summary refs log tree commit diff
path: root/src/api/middlewares
diff options
context:
space:
mode:
authorEmma [it/its]@Rory& <root@rory.gay>2023-12-11 01:12:54 +0100
committerEmma [it/its]@Rory& <root@rory.gay>2023-12-11 01:12:54 +0100
commit0a8ceb9e6349284e75545a01ffad608b020f78e2 (patch)
tree17a9163f963eddabf9168b0b630096b2f7535b64 /src/api/middlewares
parentPrettier: use editorconfig (diff)
downloadserver-dev/emma-refactors.tar.xz
Actually run prettier dev/emma-refactors
Diffstat (limited to 'src/api/middlewares')
-rw-r--r--src/api/middlewares/Authentication.ts9
-rw-r--r--src/api/middlewares/BodyParser.ts3
-rw-r--r--src/api/middlewares/CORS.ts12
-rw-r--r--src/api/middlewares/ErrorHandler.ts25
-rw-r--r--src/api/middlewares/RateLimit.ts49
-rw-r--r--src/api/middlewares/Translation.ts12
6 files changed, 25 insertions, 85 deletions
diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts

index 9e41b453..8451d69e 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts
@@ -71,11 +71,7 @@ declare global { } } -export async function Authentication( - req: Request, - res: Response, - next: NextFunction, -) { +export async function Authentication(req: Request, res: Response, next: NextFunction) { if (req.method === "OPTIONS") return res.sendStatus(204); const url = req.url.replace(API_PREFIX, ""); if (url.startsWith("/invites") && req.method === "GET") return next(); @@ -86,8 +82,7 @@ export async function Authentication( }) ) return next(); - if (!req.headers.authorization) - return next(new HTTPError("Missing Authorization Header", 401)); + if (!req.headers.authorization) return next(new HTTPError("Missing Authorization Header", 401)); Sentry.setUser({ id: req.user_id }); diff --git a/src/api/middlewares/BodyParser.ts b/src/api/middlewares/BodyParser.ts
index ac8e0432..31d79a51 100644 --- a/src/api/middlewares/BodyParser.ts +++ b/src/api/middlewares/BodyParser.ts
@@ -24,8 +24,7 @@ export function BodyParser(opts?: OptionsJson) { const jsonParser = bodyParser.json(opts); return (req: Request, res: Response, next: NextFunction) => { - if (!req.headers["content-type"]) - req.headers["content-type"] = "application/json"; + if (!req.headers["content-type"]) req.headers["content-type"] = "application/json"; jsonParser(req, res, (err) => { if (err) { diff --git a/src/api/middlewares/CORS.ts b/src/api/middlewares/CORS.ts
index 3e7452fc..8c9b1627 100644 --- a/src/api/middlewares/CORS.ts +++ b/src/api/middlewares/CORS.ts
@@ -25,16 +25,10 @@ export function CORS(req: Request, res: Response, next: NextFunction) { // TODO: use better CSP res.set( "Content-security-policy", - "default-src * data: blob: filesystem: about: ws: wss: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src * data: blob: ; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';", - ); - res.set( - "Access-Control-Allow-Headers", - req.header("Access-Control-Request-Headers") || "*", - ); - res.set( - "Access-Control-Allow-Methods", - req.header("Access-Control-Request-Methods") || "*", + "default-src * data: blob: filesystem: about: ws: wss: 'unsafe-inline' 'unsafe-eval'; script-src * data: blob: 'unsafe-inline' 'unsafe-eval'; connect-src * data: blob: 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src * data: blob: ; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';" ); + res.set("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers") || "*"); + res.set("Access-Control-Allow-Methods", req.header("Access-Control-Request-Methods") || "*"); next(); } diff --git a/src/api/middlewares/ErrorHandler.ts b/src/api/middlewares/ErrorHandler.ts
index c417e64f..4d61b745 100644 --- a/src/api/middlewares/ErrorHandler.ts +++ b/src/api/middlewares/ErrorHandler.ts
@@ -21,12 +21,7 @@ import { HTTPError } from "lambert-server"; import { ApiError, FieldError } from "@spacebar/util"; const EntityNotFoundErrorRegex = /"(\w+)"/; -export function ErrorHandler( - error: Error & { type?: string }, - req: Request, - res: Response, - next: NextFunction, -) { +export function ErrorHandler(error: Error & { type?: string }, req: Request, res: Response, next: NextFunction) { if (!error) return next(); try { @@ -35,16 +30,13 @@ export function ErrorHandler( let message = error?.toString(); let errors = undefined; - if (error instanceof HTTPError && error.code) - code = httpcode = error.code; + if (error instanceof HTTPError && error.code) code = httpcode = error.code; else if (error instanceof ApiError) { code = error.code; message = error.message; httpcode = error.httpStatus; } else if (error.name === "EntityNotFoundError") { - message = `${ - error.message.match(EntityNotFoundErrorRegex)?.[1] || "Item" - } could not be found`; + message = `${error.message.match(EntityNotFoundErrorRegex)?.[1] || "Item"} could not be found`; code = httpcode = 404; } else if (error instanceof FieldError) { code = Number(error.code); @@ -56,12 +48,7 @@ export function ErrorHandler( code = 50109; message = "The request body contains invalid JSON."; } else { - console.error( - `[Error] ${code} ${req.url}\n`, - errors || error, - "\nbody:", - req.body, - ); + console.error(`[Error] ${code} ${req.url}\n`, errors || error, "\nbody:", req.body); if (req.server?.options?.production) { // don't expose internal errors to the user, instead human errors should be thrown as HTTPError @@ -75,8 +62,6 @@ export function ErrorHandler( res.status(httpcode).json({ code: code, message, errors }); } catch (error) { console.error(`[Internal Server Error] 500`, error); - return res - .status(500) - .json({ code: 500, message: "Internal Server Error" }); + return res.status(500).json({ code: 500, message: "Internal Server Error" }); } } diff --git a/src/api/middlewares/RateLimit.ts b/src/api/middlewares/RateLimit.ts
index f5bfbb4f..14811a42 100644 --- a/src/api/middlewares/RateLimit.ts +++ b/src/api/middlewares/RateLimit.ts
@@ -65,21 +65,14 @@ export default function rateLimit(opts: { if (rights.has("BYPASS_RATE_LIMITS")) return next(); } - const bucket_id = - opts.bucket || - req.originalUrl.replace(API_PREFIX_TRAILING_SLASH, ""); + const bucket_id = opts.bucket || req.originalUrl.replace(API_PREFIX_TRAILING_SLASH, ""); let executor_id = getIpAdress(req); if (!opts.onlyIp && req.user_id) executor_id = req.user_id; let max_hits = opts.count; if (opts.bot && req.user_bot) max_hits = opts.bot; - if (opts.GET && ["GET", "OPTIONS", "HEAD"].includes(req.method)) - max_hits = opts.GET; - else if ( - opts.MODIFY && - ["POST", "DELETE", "PATCH", "PUT"].includes(req.method) - ) - max_hits = opts.MODIFY; + if (opts.GET && ["GET", "OPTIONS", "HEAD"].includes(req.method)) max_hits = opts.GET; + else if (opts.MODIFY && ["POST", "DELETE", "PATCH", "PUT"].includes(req.method)) max_hits = opts.MODIFY; const offender = Cache.get(executor_id + bucket_id); @@ -104,18 +97,13 @@ export default function rateLimit(opts: { } res.set("X-RateLimit-Reset", `${reset}`); - res.set( - "X-RateLimit-Reset-After", - `${Math.max(0, Math.ceil(resetAfterSec))}`, - ); + res.set("X-RateLimit-Reset-After", `${Math.max(0, Math.ceil(resetAfterSec))}`); if (offender.blocked) { const global = bucket_id === "global"; // each block violation pushes the expiry one full window further reset += opts.window * 1000; - offender.expires_at = new Date( - offender.expires_at.getTime() + opts.window * 1000, - ); + offender.expires_at = new Date(offender.expires_at.getTime() + opts.window * 1000); resetAfterMs = reset - Date.now(); resetAfterSec = Math.ceil(resetAfterMs / 1000); @@ -129,10 +117,7 @@ export default function rateLimit(opts: { res .status(429) .set("X-RateLimit-Remaining", "0") - .set( - "Retry-After", - `${Math.max(0, Math.ceil(resetAfterSec))}`, - ) + .set("Retry-After", `${Math.max(0, Math.ceil(resetAfterSec))}`) // TODO: error rate limit message translation .send({ message: "You are being rate limited.", @@ -156,11 +141,7 @@ export default function rateLimit(opts: { // check if error and increment error rate limit if (res.statusCode >= 400 && opts.error) { return hitRoute(hitRouteOpts); - } else if ( - res.statusCode >= 200 && - res.statusCode < 300 && - opts.success - ) { + } else if (res.statusCode >= 200 && res.statusCode < 300 && opts.success) { return hitRoute(hitRouteOpts); } }); @@ -198,7 +179,7 @@ export async function initRateLimits(app: Router) { bucket: "global", onlyIp: true, ...ip, - }), + }) ); app.use(rateLimit({ bucket: "global", ...global })); app.use( @@ -207,24 +188,16 @@ export async function initRateLimits(app: Router) { error: true, onlyIp: true, ...error, - }), + }) ); app.use("/guilds/:id", rateLimit(routes.guild)); app.use("/webhooks/:id", rateLimit(routes.webhook)); app.use("/channels/:id", rateLimit(routes.channel)); app.use("/auth/login", rateLimit(routes.auth.login)); - app.use( - "/auth/register", - rateLimit({ onlyIp: true, success: true, ...routes.auth.register }), - ); + app.use("/auth/register", rateLimit({ onlyIp: true, success: true, ...routes.auth.register })); } -async function hitRoute(opts: { - executor_id: string; - bucket_id: string; - max_hits: number; - window: number; -}) { +async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number }) { const id = opts.executor_id + opts.bucket_id; let limit = Cache.get(id); if (!limit) { diff --git a/src/api/middlewares/Translation.ts b/src/api/middlewares/Translation.ts
index f3a4c8df..e089407e 100644 --- a/src/api/middlewares/Translation.ts +++ b/src/api/middlewares/Translation.ts
@@ -27,12 +27,8 @@ const ASSET_FOLDER_PATH = path.join(__dirname, "..", "..", "..", "assets"); export async function initTranslation(router: Router) { const languages = fs.readdirSync(path.join(ASSET_FOLDER_PATH, "locales")); - const namespaces = fs.readdirSync( - path.join(ASSET_FOLDER_PATH, "locales", "en"), - ); - const ns = namespaces - .filter((x) => x.endsWith(".json")) - .map((x) => x.slice(0, x.length - 5)); + const namespaces = fs.readdirSync(path.join(ASSET_FOLDER_PATH, "locales", "en")); + const ns = namespaces.filter((x) => x.endsWith(".json")).map((x) => x.slice(0, x.length - 5)); await i18next .use(i18nextBackend) @@ -43,9 +39,7 @@ export async function initTranslation(router: Router) { fallbackLng: "en", ns, backend: { - loadPath: - path.join(ASSET_FOLDER_PATH, "locales") + - "/{{lng}}/{{ns}}.json", + loadPath: path.join(ASSET_FOLDER_PATH, "locales") + "/{{lng}}/{{ns}}.json", }, load: "all", });