diff --git a/.password_hash_gen/generator.js b/.password_hash_gen/generator.js
new file mode 100644
index 0000000..18624e8
--- /dev/null
+++ b/.password_hash_gen/generator.js
@@ -0,0 +1,42 @@
+const bcrypt = require('bcryptjs');
+const fs = require('fs');
+const path = require('path');
+
+const password = process.argv[2];
+
+if (!password) {
+ console.log('Please provide a password as a command-line argument.');
+ process.exit(1);
+}
+
+const saltRounds = 10;
+
+const configFilePath = path.join(__dirname, '../panel.config.ts');
+
+bcrypt.hash(password, saltRounds)
+ .then(hash => {
+ console.log('Generated bcrypt hash:', hash);
+
+ fs.readFile(configFilePath, 'utf8', (err, data) => {
+ if (err) {
+ console.error('Error reading the config file:', err);
+ process.exit(1);
+ }
+
+ const passwordHashRegex = /password_hash:\s*"[^"]*"/;
+
+ const updatedData = data.replace(passwordHashRegex, `password_hash: "${hash}"`) || data.replace(/(password_hash:\s*".*")/, `password_hash: "${hash}"`);
+
+ fs.writeFile(configFilePath, updatedData, 'utf8', (err) => {
+ if (err) {
+ console.error('Error writing the config file:', err);
+ process.exit(1);
+ }
+
+ console.log('Updated the password hash in panel.config.ts');
+ });
+ });
+ })
+ .catch(err => {
+ console.error('Error generating hash:', err);
+ });
diff --git a/.password_hash_gen/package.json b/.password_hash_gen/package.json
new file mode 100644
index 0000000..868ee04
--- /dev/null
+++ b/.password_hash_gen/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "password_hash_gen",
+ "version": "1.0.0",
+ "main": "generator.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "description": ""
+}
diff --git a/core/globals.ts b/core/globals.ts
index 646c532..696b2f6 100644
--- a/core/globals.ts
+++ b/core/globals.ts
@@ -1,20 +1,20 @@
import type {MinecraftServer} from "~/types/MinecraftServer";
import type {SettingsJsonFile} from "~/types/SettingsJsonFile";
import * as os from 'os';
+import { reactive } from "vue";
import {saveJsonFile} from "~/util/jsonLoader";
export namespace environment{
+ export const jwt_globals = reactive({
+ secret: "tH5kunVlY4rDIv10Y6Hy0NoLKpH1uYtW",
+ });
export namespace paths{
export let data: string = `${os.homedir()}/.mcservermanager`;
export let servers: string = `${os.homedir()}/.mcservermanager/servers`;
}
-
-
export namespace files{
export let settings: string = paths.data + "/settings.json";
}
-
-
export let settings: SettingsJsonFile;
}
diff --git a/middleware/auth.ts b/middleware/auth.ts
new file mode 100644
index 0000000..c8b6cf6
--- /dev/null
+++ b/middleware/auth.ts
@@ -0,0 +1,9 @@
+import axios from "axios";
+
+
+export default defineNuxtRouteMiddleware(async (to, from) => {
+ const user = useCookie('token')
+ if (!user.value) {
+ return navigateTo('/login')
+ }
+})
diff --git a/package.json b/package.json
index ca55278..6a4a0e6 100644
--- a/package.json
+++ b/package.json
@@ -7,20 +7,24 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
- "postinstall": "nuxt prepare"
+ "postinstall": "nuxt prepare",
+ "password_gen": "node .password_hash_gen/generator.js"
},
"dependencies": {
"@nuxt/icon": "^1.10.3",
"@nuxtjs/tailwindcss": "^6.13.1",
"axios": "^1.7.9",
+ "bcryptjs": "^3.0.2",
"daisyui": "^4.12.23",
"execa": "^9.5.2",
"ini": "^5.0.0",
+ "jsonwebtoken": "^9.0.2",
"nuxt": "^3.15.4",
"vue": "latest",
"vue-router": "latest"
},
"devDependencies": {
- "@types/ini": "^4.1.1"
+ "@types/ini": "^4.1.1",
+ "@types/jsonwebtoken": "^9.0.9"
}
}
diff --git a/pages/index.vue b/pages/index.vue
index 415016d..7f08812 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -462,6 +462,11 @@ onBeforeUnmount(()=>{
})
+definePageMeta({
+ middleware: 'auth'
+})
+
+
diff --git a/pages/login.vue b/pages/login.vue
new file mode 100644
index 0000000..646dd50
--- /dev/null
+++ b/pages/login.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/panel.config.ts b/panel.config.ts
new file mode 100644
index 0000000..21ee369
--- /dev/null
+++ b/panel.config.ts
@@ -0,0 +1,5 @@
+import { reactive } from "vue";
+
+export const settings = reactive({
+ password_hash: ""
+});
\ No newline at end of file
diff --git a/server/api/login.ts b/server/api/login.ts
new file mode 100644
index 0000000..6c21fa0
--- /dev/null
+++ b/server/api/login.ts
@@ -0,0 +1,32 @@
+import bcrypt from 'bcryptjs';
+import { sendError, createError } from 'h3';
+import jwt from 'jsonwebtoken';
+import { settings } from '~/panel.config'
+import { environment } from "~/core/globals";
+
+export default defineEventHandler(async (event) => {
+ try {
+ const { password } = await readBody(event);
+
+ if (!password) {
+ return sendError(event, createError({ statusCode: 400, message: 'password is required' }));
+ }
+
+ const isMatch = await bcrypt.compare(password, settings.password_hash);
+ if (!isMatch) {
+ return sendError(event, createError({ statusCode: 400, message: 'Invalid credentials!' }));
+ }
+
+ const token = jwt.sign({ userId: password }, environment.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' }));
+ }
+});
diff --git a/util/jsonLoader.ts b/util/jsonLoader.ts
index 028047e..710b380 100644
--- a/util/jsonLoader.ts
+++ b/util/jsonLoader.ts
@@ -41,7 +41,7 @@ function createEmptySettingsIfNotExists() {
} catch (error) {
console.log('Settings does not exist, creating an empty Settings-file...');
let emptySettings: SettingsJsonFile = ({
- eula: false,
+ eula: true,
servers:[]
});
const jsonSettings = JSON.stringify(emptySettings, null, 2);