WIP: Rewrite progress

This commit is contained in:
Holly Stubbs 2025-01-01 22:03:59 +00:00
parent 17b48c92a4
commit c4cd41c03c
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
7 changed files with 227 additions and 69 deletions

3
.gitignore vendored
View file

@ -1 +1,2 @@
node_modules/ node_modules/
config.json

View file

@ -0,0 +1,7 @@
import Controller from "./Controller";
export default class HomeController extends Controller {
public AllowAnonymous_Index() {
return this.view();
}
}

View file

@ -12,7 +12,7 @@ import HomeController from "./controllers/HomeController";
import Database from "./objects/Database"; import Database from "./objects/Database";
import { join } from "path"; import { join } from "path";
Console.customHeader(`EUS Hosting Panel server started at ${new Date()}`); Console.customHeader(`EUS server started at ${new Date()}`);
const fastify = Fastify({ const fastify = Fastify({
logger: false logger: false
@ -38,7 +38,7 @@ fastify.register(FastifyCookie, {
fastify.register(FastifyStatic, { fastify.register(FastifyStatic, {
root: join(__dirname, "wwwroot"), root: join(__dirname, "wwwroot"),
prefix: `${Config.ports.webroot}/static/` //prefix: `${Config.ports.web}/static/`
}); });
fastify.setNotFoundHandler(async (_req, res) => { fastify.setNotFoundHandler(async (_req, res) => {
@ -49,10 +49,8 @@ new Database(Config.database.address, Config.database.port, Config.database.user
Controller.FastifyInstance = fastify; Controller.FastifyInstance = fastify;
new HomeController(); new HomeController();
new AccountController();
new FileController();
fastify.listen({ port: Config.ports.http, host: "127.0.0.1" }, (err, address) => { fastify.listen({ port: Config.ports.web, host: "127.0.0.1" }, (err, address) => {
if (err) { if (err) {
Console.printError(`Error occured while spinning up fastify:\n${err}`); Console.printError(`Error occured while spinning up fastify:\n${err}`);
process.exit(1); process.exit(1);

View file

@ -1,3 +1,26 @@
export default class Config { import { readFileSync } from "fs";
const config = JSON.parse(readFileSync("./config.json").toString());
export default abstract class Config {
public static ports:IPorts = config.ports;
public static database:IDatabase = config.database;
public static session:ISession = config.session;
}
interface IPorts {
web: number
}
interface IDatabase {
address: string,
port: number,
username: string,
password: string,
name: string
}
interface ISession {
secret: string,
validity: number,
length: number
} }

View file

@ -1,67 +1,55 @@
import { FastifyReply, FastifyRequest } from "fastify"; import Config from "./Config";
import FastifyCookie from "@fastify/cookie";
import FunkyArray from "funky-array";
import SessionUser from "./SessionUser"; import SessionUser from "./SessionUser";
import UserType from "../enums/UserType"; import { FastifyReply, FastifyRequest } from "fastify";
import User from "../entities/User";
import { randomBytes } from "crypto";
export default class RequestCtx { type Cookies = { [cookieName: string]: string | undefined }
public controllerName:string;
public actionName:string;
public session?:SessionUser;
public req: FastifyRequest;
public res: FastifyReply;
public constructor(req: FastifyRequest, res: FastifyReply, controllerName:string, actionName:string, sessionUser?:SessionUser) { export default abstract class Session {
this.session = sessionUser; public static Sessions = new FunkyArray<string, SessionUser>();
this.req = req; public static SessionExpiryInterval = setInterval(() => {
this.res = res; const currentTime = Date.now();
this.controllerName = controllerName; for (const key of Session.Sessions.keys) {
this.actionName = actionName; const session = Session.Sessions.get(key);
} if (!session || (session && currentTime >= session.validityPeriod.getTime())) {
Session.Sessions.remove(key);
view(view?:string | Object, model?: Object) {
let viewName: string = this.actionName;
let viewModel: Object = {};
if (typeof(view) === "string") {
viewName = view;
} else if (typeof(view) === "object") {
viewModel = view;
}
if (typeof(model) === "object") {
viewModel = model;
}
// @ts-ignore inject session
viewModel["session"] = this.session;
// @ts-ignore inject enums
viewModel["UserLevel"] = UserLevel;
return this.res.view(`views/${this.controllerName}/${viewName}.ejs`, viewModel);
}
// TODO: query params
redirectToAction(action:string, controller?:string) {
const controllerName = controller ?? this.controllerName;
if (action === "index") {
if (controllerName === "home") {
return this.res.redirect(`/`, 302);
} else {
return this.res.redirect(`/${controllerName}`, 302);
} }
} else { }
return this.res.redirect(`/${controllerName}/${action}`, 302); }, 3600000);
public static AssignUserSession(res:FastifyReply, user:User) {
const validPeriod = new Date();
validPeriod.setTime(validPeriod.getTime() + Config.session.validity);
const key = randomBytes(Config.session.length).toString("hex");
Session.Sessions.set(key, new SessionUser(user.Id, validPeriod));
res.setCookie("EHP_SESSION", key, {
path: "/",
signed: true
});
}
public static Clear(cookies:Cookies, res:FastifyReply) {
if ("EHP_SESSION" in cookies && typeof(cookies["EHP_SESSION"]) === "string") {
const key:unknown = FastifyCookie.unsign(cookies["EHP_SESSION"], Config.session.secret);
Session.Sessions.remove(key as string);
res.clearCookie("EHP_SESSION");
} }
} }
ok(message?:string) { public static CheckValiditiy(cookies:Cookies) {
return this.res.status(200).send(message ?? ""); if ("EHP_SESSION" in cookies && typeof(cookies["EHP_SESSION"]) === "string") {
} const key = FastifyCookie.unsign(cookies["EHP_SESSION"], Config.session.secret);
if (key.valid && Session.Sessions.has(key.value ?? "badkey")) {
badRequest(message?:string) { return Session.Sessions.get(key.value ?? "badkey");
return this.res.status(400).send(message ?? ""); }
} }
unauthorised(message?:string) { return undefined;
return this.res.status(401).send(message ?? "");
}
forbidden(message?:string) {
return this.res.status(403).send(message ?? "");
} }
} }

137
package-lock.json generated
View file

@ -16,7 +16,9 @@
"@fastify/view": "^10.0.1", "@fastify/view": "^10.0.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"fastify": "^5.2.0", "fastify": "^5.2.0",
"hsconsole": "^1.0.2" "funky-array": "^1.0.0",
"hsconsole": "^1.0.2",
"mysql2": "^3.12.0"
}, },
"devDependencies": { "devDependencies": {
"@types/ejs": "^3.1.5", "@types/ejs": "^3.1.5",
@ -421,6 +423,15 @@
"fastq": "^1.17.1" "fastq": "^1.17.1"
} }
}, },
"node_modules/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
"license": "MIT",
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -622,6 +633,15 @@
} }
} }
}, },
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -882,6 +902,21 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/funky-array": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/funky-array/-/funky-array-1.0.0.tgz",
"integrity": "sha512-1oMg2rdLkvQV+RzV6IwaPw0wngQkVb/9bIfr+Twj/MqWKaBVM6KPwkq2IBSjTf0PC3GLeiMZ6weeG3jdhOlIYg==",
"license": "MIT"
},
"node_modules/generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
"license": "MIT",
"dependencies": {
"is-property": "^1.0.2"
}
},
"node_modules/glob": { "node_modules/glob": {
"version": "11.0.0", "version": "11.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz",
@ -977,6 +1012,18 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ignore-by-default": { "node_modules/ignore-by-default": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
@ -1054,6 +1101,12 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
"license": "MIT"
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -1119,6 +1172,12 @@
"set-cookie-parser": "^2.6.0" "set-cookie-parser": "^2.6.0"
} }
}, },
"node_modules/long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==",
"license": "Apache-2.0"
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "11.0.2", "version": "11.0.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz",
@ -1128,6 +1187,21 @@
"node": "20 || >=22" "node": "20 || >=22"
} }
}, },
"node_modules/lru.min": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.1.tgz",
"integrity": "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
"deno": ">=1.30.0",
"node": ">=8.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wellwelwel"
}
},
"node_modules/make-error": { "node_modules/make-error": {
"version": "1.3.6", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@ -1175,6 +1249,47 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/mysql2": {
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz",
"integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==",
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
"generate-function": "^2.3.1",
"iconv-lite": "^0.6.3",
"long": "^5.2.1",
"lru.min": "^1.0.0",
"named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5",
"sqlstring": "^2.3.2"
},
"engines": {
"node": ">= 8.0"
}
},
"node_modules/named-placeholders": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
"integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
"license": "MIT",
"dependencies": {
"lru-cache": "^7.14.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/named-placeholders/node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
"license": "ISC",
"engines": {
"node": ">=12"
}
},
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "3.1.9", "version": "3.1.9",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
@ -1440,6 +1555,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/secure-json-parse": { "node_modules/secure-json-parse": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-3.0.1.tgz", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-3.0.1.tgz",
@ -1458,6 +1579,11 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/seq-queue": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
},
"node_modules/set-cookie-parser": { "node_modules/set-cookie-parser": {
"version": "2.7.1", "version": "2.7.1",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
@ -1534,6 +1660,15 @@
"node": ">= 10.x" "node": ">= 10.x"
} }
}, },
"node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/statuses": { "node_modules/statuses": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",

View file

@ -10,7 +10,11 @@
"author": "tgpholly", "author": "tgpholly",
"license": "MIT", "license": "MIT",
"type": "commonjs", "type": "commonjs",
"scripts": {}, "scripts": {
"updateCheck": "check-outdated",
"dev": "nodemon --watch './**/*.ts' index.ts",
"build": "tsx --build --clean"
},
"devDependencies": { "devDependencies": {
"@types/ejs": "^3.1.5", "@types/ejs": "^3.1.5",
"@types/node": "^22.10.2", "@types/node": "^22.10.2",
@ -28,6 +32,8 @@
"@fastify/view": "^10.0.1", "@fastify/view": "^10.0.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"fastify": "^5.2.0", "fastify": "^5.2.0",
"hsconsole": "^1.0.2" "funky-array": "^1.0.0",
"hsconsole": "^1.0.2",
"mysql2": "^3.12.0"
} }
} }