added auth

This commit is contained in:
WeeXnes 2025-02-27 02:56:21 +01:00
parent f6b3c35b70
commit 42a77072e1
10 changed files with 145 additions and 45 deletions

6
core/globals.ts Normal file
View file

@ -0,0 +1,6 @@
import {reactive} from "vue";
export const jwt_globals = reactive({
secret: "",
});

View file

@ -4,10 +4,10 @@ import { reactive, ref } from 'vue';
import axios from 'axios';
import type {networkInterface} from "~/types/networkInterface";
import type {serviceInterface} from "~/types/serviceInterface";
import {checkAuth} from "~/util/auth";
const ignoreCache = true;
const startVm = async (vm: any) => {
@ -195,20 +195,21 @@ const fetchSettings = async () => {
}
onMounted(async () => {
await fetchSettings()
if(settings.enable_qemu_controls) await fetchVMs()
await fetchOsInfo()
await fetchCpuTemp()
cpuInfo.isLoaded = true
await fetchMemoryInfo()
await fetchNetworkInfo()
if(settings.enable_services) await fetchServiceInfo()
const intervalId = setInterval(fetchCpuTemp, 7000);
onUnmounted(() => {
clearInterval(intervalId);
});
let isAuthed = await checkAuth(useRouter())
if(isAuthed){
await fetchSettings()
if(settings.enable_qemu_controls) await fetchVMs()
await fetchOsInfo()
await fetchCpuTemp()
cpuInfo.isLoaded = true
await fetchMemoryInfo()
await fetchNetworkInfo()
if(settings.enable_services) await fetchServiceInfo()
const intervalId = setInterval(fetchCpuTemp, 7000);
onUnmounted(() => {
clearInterval(intervalId);
});
}
})

View file

@ -4,19 +4,6 @@
<h2 class="text-2xl font-bold text-center">Login</h2>
<form @submit.prevent="handleLogin" class="mt-4">
<div class="form-control">
<label class="label">
<span class="label-text">E-Mail</span>
</label>
<input
v-model="email"
type="email"
placeholder="Enter your email"
class="input input-bordered"
required
/>
</div>
<div class="form-control mt-2">
<label class="label">
<span class="label-text">Password</span>
@ -34,10 +21,6 @@
<button type="submit" class="btn btn-primary w-full">Login</button>
</div>
</form>
<div class="mt-4 text-center text-sm">
<p>Don't have an account? <a href="/register" class="text-blue-500 hover:underline">Register here</a></p>
</div>
</div>
</div>
</template>
@ -57,7 +40,24 @@ export default {
},
methods: {
async handleLogin() {
try {
const response = await axios.post('/api/login', {
password: this.password,
});
console.log(response.data);
if (response?.data?.message == 'Login successful!') {
const token = response.data.token;
const cookie = useCookie('token');
cookie.value = token;
this.$router.push('/');
} else {
console.error('Login failed');
}
} catch (error) {
console.error('Login error:', error);
}
}
}
};

View file

@ -1,9 +1,9 @@
<script setup lang="ts">
import type { VM } from '../types/VM';
import axios from 'axios';
import {checkAuth} from "~/util/auth";
onMounted(async () => {
let isAuthed = await checkAuth(useRouter())
})
</script>

View file

@ -5,7 +5,7 @@ export const settings = reactive({
//Leave empty to scan all interfaces
//or change item to "disabled" to disable interface scanning
interfaces_to_scan:[
"eth0"
"enp4s0"
],
enable_qemu_controls: true,
qemu_vms: [
@ -22,5 +22,9 @@ export const settings = reactive({
systemctl_services:[
"libvirt",
"frp"
]
],
password:{
hash: "$2y$10$04HVBBemPypGbaMhTmUxX.DUMir1HA4hT6cst.dGabot1ZWR5IQ.6",
salt_rounds: 10
},
});

30
server/api/auth.ts Normal file
View file

@ -0,0 +1,30 @@
import { defineEventHandler, getCookie, createError } from 'h3';
import jwt from 'jsonwebtoken';
import {jwt_globals} from "~/core/globals";
export default defineEventHandler(async (event) => {
try {
const token = getCookie(event, 'token');
console.log("Checking token " + token);
if (!token) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' });
}
const secret = jwt_globals.secret;
if (!secret) {
throw createError({ statusCode: 500, statusMessage: 'JWT secret not set' });
}
const decoded = jwt.verify(token, secret) as { userId: string };
if (!decoded?.userId) {
throw createError({ statusCode: 401, statusMessage: 'Invalid token' });
}
console.log("user has been authed, hash: " + decoded.userId);
return { success: true };
} catch (error: any) {
return createError({
statusCode: error.statusCode || 500,
statusMessage: error.statusMessage || 'Invalid or expired token',
});
}
});

View file

@ -45,10 +45,6 @@ export default defineEventHandler(async () => {
state: network.operstate as "up" | "down" | "unknown"
})
}
interfaces.forEach(obj => {
console.log(obj.name + " is " + obj.state);
})
return interfaces;
} catch (error) {

36
server/api/login.ts Normal file
View file

@ -0,0 +1,36 @@
import bcrypt from 'bcryptjs';
import { sendError, createError } from 'h3';
import jwt from 'jsonwebtoken';
import {settings} from "~/panel.config";
import {jwt_globals} from "~/core/globals";
export default defineEventHandler(async (event) => {
try {
const { password } = await readBody(event);
if (!password) {
console.log("password is required");
return sendError(event, createError({ statusCode: 400, message: 'password is required' }));
}
const isMatch = await bcrypt.compare(password, settings.password.hash);
if (!isMatch) {
console.log("Invalid credentials! password");
return sendError(event, createError({ statusCode: 400, message: 'Invalid credentials!' }));
}
const token = jwt.sign({ userId: password }, jwt_globals.secret!, {
expiresIn: '1h',
});
return {
message: 'Login successful!',
token
};
} catch (error) {
console.error("Login error: ", error);
return sendError(event, createError({ statusCode: 500, message: 'Internal server error' }));
}
});

View file

@ -1,7 +1,13 @@
import { defineNitroPlugin } from "#imports";
import { reactive } from "vue";
import * as crypto from 'crypto';
import {jwt_globals} from "~/core/globals";
export default defineNitroPlugin((nitroApp) => {
console.log("Loading Server Settings");
console.log("Running init...");
console.log("Generating jwt secret...")
jwt_globals.secret = crypto.randomBytes(32).toString('base64');
console.log("secret: " + jwt_globals.secret)
});

21
util/auth.ts Normal file
View file

@ -0,0 +1,21 @@
// util/auth.ts
import axios from 'axios';
import { useRouter } from 'vue-router'; // Import useRouter
export async function checkAuth(router: any) {
try {
const response = await axios.get('/api/auth', {
withCredentials: true, // Ensure cookies are sent with the request
});
if (!response.data.success) {
router.push('/login');
}
return response.data.success;
} catch (error) {
console.log("Not authenticated, redirecting to /login");
router.push('/login');
return false;
}
}