User stuff, config structure changes, web panel start, versioncheck fix, api start, recaptcha support for web panel

This commit is contained in:
2025-02-08 21:19:25 -05:00
parent bc3443b1dc
commit 73e9b72ad4
36 changed files with 5526 additions and 87 deletions

View File

@@ -4,7 +4,7 @@ import Logging from "@proxnet/undead-logging";
const log = new Logging('APIUtils');
interface AppRouter {
type AppRouter = {
path: string,
router: express.Router
}
@@ -57,10 +57,10 @@ export function checkBodyTypes<T>(typeDef: T) {
};
}
export function genericResponseFormat(failure: boolean, msg: string | null = null, data = null) {
export function genericResponseFormat(failure: boolean, msg: string | null = null, data: object | null = null) {
return { failed: failure, instance: instanceId, message: msg, data: data };
}
export function genericResponse(failure: boolean, msg: string | null = null, data = null) {
export function genericResponse(failure: boolean, msg: string | null = null, data: object | null = null) {
return (_rq: express.Request, rs: express.Response) => {
rs.json({ failed: failure, instance: instanceId, message: msg, data: data });
};
@@ -102,4 +102,67 @@ export function statusResponse(code: number) {
}
}
export class RateLimiter {
#intervalId: number
#hitLimit: number
#addressHits: Map<string, number> = new Map();
/**
* @param interval In seconds: rate at which hit counts will be cleared
* @param limit Number of hits (inclusive) before requests are blocked
*/
constructor(interval: number, limit: number) {
this.#hitLimit = limit;
this.#intervalId = setInterval(() => {
this.#addressHits.clear();
}, interval * 1000);
Deno.addSignalListener('SIGINT', () => {
this.#close();
});
}
#addressIncrement(address: string) {
const hits = this.#addressHits.get(address);
if (hits) this.#addressHits.set(address, hits + 1);
else this.#addressHits.set(address, 1);
}
#getAddressHits(address: string) {
const hits = this.#addressHits.get(address);
if (hits) return hits;
else {
this.#addressHits.set(address, 1);
return 1;
}
}
middle() {
return (rq: express.Request, rs: express.Response, nxt: express.NextFunction) => {
const address = getSrcIpDefault(rq);
this.#addressIncrement(address);
const hits = this.#getAddressHits(address);
if (hits && hits > this.#hitLimit) {
rs.statusCode = 429;
rs.json(genericResponseFormat(true, `Rate limit for address ${address} reached. Try again in a moment.`));
return;
} else nxt();
}
}
#close() {
clearInterval(this.#intervalId);
}
}
export * as APIUtils from "./apiutils.ts"