galvanic corrosion rewrite

commit this before something goes horribly wrong
This commit is contained in:
2025-08-12 21:04:52 -04:00
parent 941c8400c0
commit f19552929e
40 changed files with 28149 additions and 73212 deletions

View File

@@ -4,7 +4,7 @@ import Logging from "@proxnet/undead-logging";
import z from "zod";
import { verify } from "@hono/hono/jwt";
import Server from "../server/server.ts";
import { ProfileToken } from "../server/profiles/types/profile.ts";
import { TokenFormat } from "../server/platforms/types.ts";
const log = new Logging("APIUtils");
@@ -34,8 +34,8 @@ export async function authenticate(c: Context<HonoEnv>, nxt: Next) {
if (authHeader.success) {
try {
const payload = await verify(authHeader.data ? authHeader.data : 'not a valid token', secret);
const profile = await Server.Profiles.get((payload as ProfileToken).sub);
const payload = JSON.parse(JSON.stringify(await verify(authHeader.data ? authHeader.data : 'not a valid token', secret)));
const profile = await Server.Profiles.get((payload as TokenFormat).sub);
if (!profile) return c.json(genericResponse(false, "Internal Server Error"), 500);
c.set('profile', profile);
@@ -46,4 +46,86 @@ export async function authenticate(c: Context<HonoEnv>, nxt: Next) {
}
} else return c.json(genericResponse(false, "Authorization required"), 401);
}
export enum GalvanicErrors {
jex = "jex", // Error in account creation, check platform
sploot = "sploot", // Error in account creation, steamid was not valid or profile could not be created
}
export function galvanicError(code: GalvanicErrors) {
return {success: false, error:`Galvanic Error (code: ${code})`};
}
export function recNetError(err: string) {
return {success:false, error: err};
}
export function generateRandomString(length: number) {
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let randomString = "";
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * characters.length);
randomString += characters.charAt(randomIndex);
}
return randomString;
}
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 = 60, limit: number = 10) {
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 (
c: Context<HonoEnv>,
next: Next
) => {
const address = c.get('srcAddr');
if (address == '127.0.0.1' || address == '::1') return next();
this.#addressIncrement(address);
const hits = this.#getAddressHits(address);
if (hits && hits > this.#hitLimit) return c.json(recNetError("Rate Limited. Please try again later."), 429);
else return next();
};
}
#close() {
clearInterval(this.#intervalId);
}
}