mirror of
https://github.com/Spythere/station-manager-2.0.git
synced 2026-05-03 05:28:13 +00:00
poprawki bezpieczeństwa
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
VITE_API_URL="https://stacjownik.spythere.pl"
|
VITE_API_URL="https://stacjownik.spythere.pl"
|
||||||
VITE_API_URL_DEV="http://localhost:3001"
|
VITE_API_URL_DEV="http://localhost:3001"
|
||||||
VITE_API_DEV=0
|
VITE_API_DEV=1
|
||||||
+17
-23
@@ -10,8 +10,9 @@ import PopUpCard from './components/PopUpCard.vue';
|
|||||||
import { RouterView } from 'vue-router';
|
import { RouterView } from 'vue-router';
|
||||||
import { AuthState } from './types/types';
|
import { AuthState } from './types/types';
|
||||||
import useRouteGuard from './mixins/useRouteGuard';
|
import useRouteGuard from './mixins/useRouteGuard';
|
||||||
import { useStore } from './store';
|
import { baseURL, useStore } from './store';
|
||||||
import useLocalStorage from './mixins/useLocalStorage';
|
import useLocalStorage from './mixins/useLocalStorage';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { PopUpCard },
|
components: { PopUpCard },
|
||||||
@@ -20,7 +21,7 @@ export default defineComponent({
|
|||||||
const { routeAuthGuard } = useRouteGuard();
|
const { routeAuthGuard } = useRouteGuard();
|
||||||
const { setupStorage } = useLocalStorage();
|
const { setupStorage } = useLocalStorage();
|
||||||
|
|
||||||
routeAuthGuard();
|
// routeAuthGuard();
|
||||||
setupStorage();
|
setupStorage();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -30,28 +31,21 @@ export default defineComponent({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async autoLogin() {
|
async autoLogin() {
|
||||||
const token = window.localStorage.getItem('auth-token');
|
try {
|
||||||
if (!token) {
|
const response = await axios.post(
|
||||||
this.store.authState = AuthState.UNAUTHORIZED;
|
'/auth/token',
|
||||||
return;
|
{},
|
||||||
|
{
|
||||||
|
baseURL,
|
||||||
|
withCredentials: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.store.user = response.data;
|
||||||
|
this.$router.push('/');
|
||||||
|
} catch (error) {
|
||||||
|
this.$router.push('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.store.token = token;
|
|
||||||
|
|
||||||
this.store
|
|
||||||
.fetchTokenData()
|
|
||||||
.then((res) => {
|
|
||||||
this.store.user = res.data.user;
|
|
||||||
this.store.authState = AuthState.AUTHORIZED;
|
|
||||||
this.$router.push('/');
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
this.store.isAuthorized = false;
|
|
||||||
window.localStorage.removeItem('auth-token');
|
|
||||||
|
|
||||||
this.store.authState = AuthState.UNAUTHORIZED;
|
|
||||||
this.$router.push('/login');
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -82,9 +82,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import routesMixin from '../mixins/routesMixin';
|
import routesMixin from '../mixins/routesMixin';
|
||||||
import { useStore } from '../store';
|
import { useStore, baseURL } from '../store';
|
||||||
import { AuthState, Availability, ChangeProp, HeaderTypes, SceneryRoutesInfo, SceneryRowItem } from '../types/types';
|
import { AuthState, Availability, ChangeProp, HeaderTypes, SceneryRoutesInfo, SceneryRowItem } from '../types/types';
|
||||||
import { getAvailabilityValue } from '../types/typeUitls';
|
import { getAvailabilityValue } from '../types/typeUitls';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
@@ -154,13 +155,8 @@ export default defineComponent({
|
|||||||
if (confirmed) this.updateListToDb();
|
if (confirmed) this.updateListToDb();
|
||||||
},
|
},
|
||||||
|
|
||||||
signOut() {
|
async signOut() {
|
||||||
this.store.token = null;
|
await axios.post('/auth/logout', {}, { baseURL, withCredentials: true });
|
||||||
this.store.authState = AuthState.UNAUTHORIZED;
|
|
||||||
|
|
||||||
window.localStorage.removeItem('auth-token');
|
|
||||||
window.localStorage.removeItem('user');
|
|
||||||
|
|
||||||
this.$router.push('/login');
|
this.$router.push('/login');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+18
-2
@@ -1,9 +1,25 @@
|
|||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import router from './router';
|
|
||||||
|
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
import router from './router';
|
||||||
|
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
|
import { useStore } from './store';
|
||||||
|
|
||||||
createApp(App).use(router).use(createPinia()).mount('#app');
|
const pinia = createPinia();
|
||||||
|
const app = createApp(App);
|
||||||
|
|
||||||
|
app.use(pinia).use(router);
|
||||||
|
app.mount('#app');
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
if (to.meta.protected && !store.user) {
|
||||||
|
next('/login');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -4,6 +4,9 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'ManagerView',
|
name: 'ManagerView',
|
||||||
|
meta: {
|
||||||
|
protected: true,
|
||||||
|
},
|
||||||
component: () => import('./views/ManagerView.vue'),
|
component: () => import('./views/ManagerView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -18,5 +21,4 @@ const router = createRouter({
|
|||||||
routes,
|
routes,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
+7
-33
@@ -2,7 +2,7 @@ import { defineStore } from 'pinia';
|
|||||||
import { AuthState, ILoginResponse, IStore, IUser, SceneryRowItem } from './types/types';
|
import { AuthState, ILoginResponse, IStore, IUser, SceneryRowItem } from './types/types';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const baseURL = import.meta.env[`VITE_API_URL${import.meta.env.DEV ? '_DEV' : ''}`];
|
export const baseURL = import.meta.env[`VITE_API_URL${import.meta.env.DEV ? '_DEV' : ''}`];
|
||||||
|
|
||||||
export const useStore = defineStore('store', {
|
export const useStore = defineStore('store', {
|
||||||
state: () =>
|
state: () =>
|
||||||
@@ -20,9 +20,7 @@ export const useStore = defineStore('store', {
|
|||||||
routesModalVisible: true,
|
routesModalVisible: true,
|
||||||
currentStation: null,
|
currentStation: null,
|
||||||
selectedStationName: '',
|
selectedStationName: '',
|
||||||
token: null,
|
|
||||||
user: null,
|
user: null,
|
||||||
isAuthorized: false,
|
|
||||||
notifyDiscord: true,
|
notifyDiscord: true,
|
||||||
|
|
||||||
alertMessage: '',
|
alertMessage: '',
|
||||||
@@ -37,12 +35,8 @@ export const useStore = defineStore('store', {
|
|||||||
fetchSceneriesData() {
|
fetchSceneriesData() {
|
||||||
this.dataState = 'LOADING';
|
this.dataState = 'LOADING';
|
||||||
|
|
||||||
const data = axios.get<SceneryRowItem[]>(`api/getSceneries?time=${Date.now()}`, {
|
const data = axios.get<SceneryRowItem[]>(`api/getSceneries`, {
|
||||||
baseURL,
|
baseURL,
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${this.token}`,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
data
|
data
|
||||||
@@ -55,13 +49,13 @@ export const useStore = defineStore('store', {
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
this.dataState = 'ERROR';
|
this.dataState = 'ERROR';
|
||||||
this.token = '';
|
|
||||||
this.isAuthorized = false;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateSceneriesData(mappedChangeList: any[]) {
|
async updateSceneriesData(mappedChangeList: any[]) {
|
||||||
const response = axios.post(
|
console.log(mappedChangeList);
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
'/manager/updateSceneryList',
|
'/manager/updateSceneryList',
|
||||||
{
|
{
|
||||||
changeList: mappedChangeList,
|
changeList: mappedChangeList,
|
||||||
@@ -69,32 +63,12 @@ export const useStore = defineStore('store', {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
baseURL,
|
baseURL,
|
||||||
headers: {
|
withCredentials: true,
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${this.token}`,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
login(name: string, pwd: string) {
|
|
||||||
return axios.post<ILoginResponse>(
|
|
||||||
'auth/login',
|
|
||||||
{ username: name, password: pwd },
|
|
||||||
{
|
|
||||||
baseURL,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchTokenData() {
|
|
||||||
return axios.post<{ user: IUser }>('auth/token', { token: this.token }, { baseURL });
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
+7
-8
@@ -87,6 +87,11 @@ export enum AuthState {
|
|||||||
'UNAUTHORIZED' = 2,
|
'UNAUTHORIZED' = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IUser {
|
||||||
|
name: string;
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IStore {
|
export interface IStore {
|
||||||
dataState: string;
|
dataState: string;
|
||||||
authState: AuthState;
|
authState: AuthState;
|
||||||
@@ -101,9 +106,8 @@ export interface IStore {
|
|||||||
routesModalVisible: boolean;
|
routesModalVisible: boolean;
|
||||||
currentStation: SceneryRowItem | null;
|
currentStation: SceneryRowItem | null;
|
||||||
selectedStationName: string;
|
selectedStationName: string;
|
||||||
token: string | null;
|
// token: string | null;
|
||||||
user: { name: string; id: string } | null;
|
user: IUser | null;
|
||||||
isAuthorized: boolean;
|
|
||||||
notifyDiscord: boolean;
|
notifyDiscord: boolean;
|
||||||
alertMessage: string;
|
alertMessage: string;
|
||||||
confirmMessage: string;
|
confirmMessage: string;
|
||||||
@@ -117,8 +121,3 @@ export interface ILoginResponse {
|
|||||||
token: string;
|
token: string;
|
||||||
user: IUser;
|
user: IUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUser {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|||||||
+23
-16
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login" v-if="store.authState == AuthState.UNAUTHORIZED">
|
<div class="login">
|
||||||
<div class="login-header">
|
<div class="login-header">
|
||||||
<img src="/icon-logo.svg" alt="logo" />
|
<img src="/icon-logo.svg" alt="logo" />
|
||||||
<h1>Stacjownik Station Manager</h1>
|
<h1>Stacjownik Station Manager</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form @submit="signIn">
|
<form @submit.prevent="signIn">
|
||||||
<label for="name">Nick</label>
|
<label for="name">Nick</label>
|
||||||
<br />
|
<br />
|
||||||
<input type="text" id="name" v-model="name" />
|
<input type="text" id="name" v-model="name" />
|
||||||
@@ -22,8 +22,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useStore } from '../store';
|
import { useStore, baseURL } from '../store';
|
||||||
import { AuthState } from '../types/types';
|
import { AuthState } from '../types/types';
|
||||||
|
import axios, { HttpStatusCode } from 'axios';
|
||||||
|
|
||||||
enum LoginState {
|
enum LoginState {
|
||||||
INITIALIZED = 0,
|
INITIALIZED = 0,
|
||||||
@@ -52,27 +53,33 @@ export default defineComponent({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async signIn(e: Event) {
|
async signIn(e: Event) {
|
||||||
e.preventDefault();
|
// this.loginState = LoginState.LOADING;
|
||||||
this.loginState = LoginState.LOADING;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const loginData = (await this.store.login(this.name, this.password)).data;
|
// const loginData = (await this.store.login(this.name, this.password)).data;
|
||||||
|
const response = await axios.post(
|
||||||
|
'auth/login',
|
||||||
|
{ username: this.name, password: this.password },
|
||||||
|
{
|
||||||
|
baseURL,
|
||||||
|
withCredentials: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
this.store.authState = AuthState.AUTHORIZED;
|
// this.store.authState = AuthState.AUTHORIZED;
|
||||||
this.loginState = LoginState.LOADED;
|
// this.loginState = LoginState.LOADED;
|
||||||
|
|
||||||
this.store.token = loginData.token;
|
// this.store.token = loginData.token;
|
||||||
this.store.user = loginData.user;
|
// this.store.user = loginData.user;
|
||||||
|
|
||||||
window.localStorage.setItem('auth-token', this.store.token);
|
// window.localStorage.setItem('auth-token', this.store.token);
|
||||||
window.localStorage.setItem('user', JSON.stringify(this.store.user));
|
// window.localStorage.setItem('user', JSON.stringify(this.store.user));
|
||||||
|
|
||||||
|
this.store.user = response.data;
|
||||||
this.$router.push('/');
|
this.$router.push('/');
|
||||||
|
|
||||||
this.store.fetchSceneriesData();
|
this.store.fetchSceneriesData();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.store.authState = AuthState.UNAUTHORIZED;
|
|
||||||
this.loginState = LoginState.LOADED;
|
|
||||||
|
|
||||||
if (!e.response || e.response.status === undefined) {
|
if (!e.response || e.response.status === undefined) {
|
||||||
this.errorMessage = 'Wystąpił błąd podczas łączenia z serwerem!';
|
this.errorMessage = 'Wystąpił błąd podczas łączenia z serwerem!';
|
||||||
return false;
|
return false;
|
||||||
@@ -81,7 +88,7 @@ export default defineComponent({
|
|||||||
const response = e.response;
|
const response = e.response;
|
||||||
const status: number = response.status;
|
const status: number = response.status;
|
||||||
|
|
||||||
if (status == 401) {
|
if (status == 400) {
|
||||||
this.errorMessage = 'Nieprawidłowe dane!';
|
this.errorMessage = 'Nieprawidłowe dane!';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="manager" v-if="store.authState == AuthState.AUTHORIZED">
|
<div class="manager">
|
||||||
<RoutesModal v-if="store.currentStation" />
|
<RoutesModal v-if="store.currentStation" />
|
||||||
<UpdateCard v-if="store.changesResponse.length > 0" />
|
<UpdateCard v-if="store.changesResponse.length > 0" />
|
||||||
|
|
||||||
|
|||||||
+10
-4
@@ -1,7 +1,13 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite';
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()]
|
plugins: [vue()],
|
||||||
})
|
build: {
|
||||||
|
commonjsOptions: {
|
||||||
|
esmExternals: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user