middleware works as it should! With recursion, which I hate :)
This commit is contained in:
4928
client/Cargo.lock
generated
Normal file
4928
client/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,12 +7,14 @@ import { ok, ResultFromJSON } from "@shared/utils/result.ts";
|
|||||||
import { ResultResponseFromJSON } from "@src/lib/context.ts";
|
import { ResultResponseFromJSON } from "@src/lib/context.ts";
|
||||||
import admin from "@src/lib/admin.ts";
|
import admin from "@src/lib/admin.ts";
|
||||||
import UsbipManager from "@shared/utils/usbip.ts";
|
import UsbipManager from "@shared/utils/usbip.ts";
|
||||||
|
import loggerMiddleware from "@src/middleware/logger.ts";
|
||||||
|
|
||||||
const router = new HttpRouter();
|
const router = new HttpRouter();
|
||||||
|
|
||||||
const views = Deno.cwd() + "/views/";
|
const views = Deno.cwd() + "/views/";
|
||||||
const eta = new Eta({ views });
|
const eta = new Eta({ views });
|
||||||
|
|
||||||
|
router.use(loggerMiddleware);
|
||||||
router.use(rateLimitMiddleware);
|
router.use(rateLimitMiddleware);
|
||||||
router.use(authMiddleware);
|
router.use(authMiddleware);
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ type RequestHandler<S extends string> = (
|
|||||||
export type Middleware = (
|
export type Middleware = (
|
||||||
c: Context<string>,
|
c: Context<string>,
|
||||||
next: () => Promise<void>,
|
next: () => Promise<void>,
|
||||||
) => Promise<Response | undefined> | Response | undefined;
|
) => Promise<Response | void> | Response | void;
|
||||||
|
|
||||||
type MethodHandlers<S extends string> = Partial<
|
type MethodHandlers<S extends string> = Partial<
|
||||||
Record<string, RequestHandler<S>>
|
Record<string, RequestHandler<S>>
|
||||||
@ -19,7 +19,7 @@ const DEFAULT_NOT_FOUND_HANDLER = () => new Response("404 Not found");
|
|||||||
class HttpRouter {
|
class HttpRouter {
|
||||||
routerTree = new RouterTree<MethodHandlers<any>>();
|
routerTree = new RouterTree<MethodHandlers<any>>();
|
||||||
pathPreprocessor?: (path: string) => string;
|
pathPreprocessor?: (path: string) => string;
|
||||||
middlewareChain: Middleware[] = [];
|
middlewares: Middleware[] = [];
|
||||||
defaultNotFoundHandler: RequestHandler<string> = DEFAULT_NOT_FOUND_HANDLER;
|
defaultNotFoundHandler: RequestHandler<string> = DEFAULT_NOT_FOUND_HANDLER;
|
||||||
|
|
||||||
setPathProcessor(processor: (path: string) => string) {
|
setPathProcessor(processor: (path: string) => string) {
|
||||||
@ -27,7 +27,7 @@ class HttpRouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use(mw: Middleware): HttpRouter {
|
use(mw: Middleware): HttpRouter {
|
||||||
this.middlewareChain.push(mw);
|
this.middlewares.push(mw);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,23 +99,58 @@ class HttpRouter {
|
|||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const c = new Context(req, connInfo, {});
|
const c = new Context(req, connInfo, {});
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
const mw = this.middlewareChain[i++];
|
|
||||||
|
|
||||||
const path = this.pathPreprocessor
|
const path = this.pathPreprocessor
|
||||||
? this.pathPreprocessor(c.path)
|
? this.pathPreprocessor(c.path)
|
||||||
: c.path;
|
: c.path;
|
||||||
|
|
||||||
return await this.routerTree
|
let params: Params<string> = {};
|
||||||
|
|
||||||
|
const handler = this.routerTree
|
||||||
.find(path)
|
.find(path)
|
||||||
.andThen((routeMatch) => {
|
.andThen((routeMatch) => {
|
||||||
const { value, params } = routeMatch;
|
const { value: handlers, params: paramsMatched } = routeMatch;
|
||||||
const handler = value[req.method];
|
params = paramsMatched;
|
||||||
return handler
|
const handler = handlers[req.method];
|
||||||
? some(handler(Context.setParams(c, params)))
|
return handler ? some(handler) : none;
|
||||||
: none;
|
|
||||||
})
|
})
|
||||||
.unwrapOrElse(() => this.defaultNotFoundHandler(c));
|
.unwrapOrElse(() => this.defaultNotFoundHandler);
|
||||||
|
|
||||||
|
const cf = await this.executeMiddlewareChain(
|
||||||
|
this.middlewares,
|
||||||
|
handler,
|
||||||
|
Context.setParams(c, params),
|
||||||
|
);
|
||||||
|
|
||||||
|
return cf.res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async executeMiddlewareChain<S extends string>(
|
||||||
|
middlewares: Middleware[],
|
||||||
|
handler: RequestHandler<S>,
|
||||||
|
c: Context<S>,
|
||||||
|
) {
|
||||||
|
let currentIndex = -1;
|
||||||
|
|
||||||
|
const dispatch = async (index: number): Promise<void> => {
|
||||||
|
currentIndex = index;
|
||||||
|
|
||||||
|
if (index < middlewares.length) {
|
||||||
|
const middleware = middlewares[index];
|
||||||
|
|
||||||
|
const result = await middleware(c, () => dispatch(index + 1));
|
||||||
|
|
||||||
|
if (result !== undefined) {
|
||||||
|
c.res = await Promise.resolve(result);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const res = await handler(c);
|
||||||
|
c.res = res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await dispatch(0);
|
||||||
|
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import admin from "@lib/admin.ts";
|
|||||||
|
|
||||||
const LOGIN_PATH = "/login";
|
const LOGIN_PATH = "/login";
|
||||||
|
|
||||||
const authMiddleware: Middleware = (c) => {
|
const authMiddleware: Middleware = async (c, next) => {
|
||||||
const token = c.cookies.get("token");
|
const token = c.cookies.get("token");
|
||||||
const isValid = token
|
const isValid = token
|
||||||
.map((token) => admin.sessions.verifyToken(token))
|
.map((token) => admin.sessions.verifyToken(token))
|
||||||
@ -11,15 +11,17 @@ const authMiddleware: Middleware = (c) => {
|
|||||||
const path = c.path;
|
const path = c.path;
|
||||||
|
|
||||||
if (path.startsWith("/public")) {
|
if (path.startsWith("/public")) {
|
||||||
return;
|
await next();
|
||||||
}
|
} else {
|
||||||
|
if (path !== LOGIN_PATH && !isValid) {
|
||||||
|
return c.redirect("/login");
|
||||||
|
}
|
||||||
|
|
||||||
if (path !== LOGIN_PATH && !isValid) {
|
if (path === LOGIN_PATH && isValid) {
|
||||||
return c.redirect("/login");
|
return c.redirect("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path === LOGIN_PATH && isValid) {
|
await next();
|
||||||
return c.redirect("");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
9
server/src/middleware/logger.ts
Normal file
9
server/src/middleware/logger.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Middleware } from "@lib/router.ts";
|
||||||
|
|
||||||
|
const loggerMiddleware: Middleware = async (c, next) => {
|
||||||
|
console.log(c.req.method, c.path);
|
||||||
|
await next();
|
||||||
|
console.log(c.res.status);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default loggerMiddleware;
|
||||||
@ -8,7 +8,7 @@ const requestCounts: Partial<
|
|||||||
const MAX_REQUESTS_PER_WINDOW = 300;
|
const MAX_REQUESTS_PER_WINDOW = 300;
|
||||||
const RATE_LIMIT_WINDOW = 60000;
|
const RATE_LIMIT_WINDOW = 60000;
|
||||||
|
|
||||||
const rateLimitMiddleware: Middleware = (c) => {
|
const rateLimitMiddleware: Middleware = async (c, next) => {
|
||||||
const hostnameOpt = c.hostname;
|
const hostnameOpt = c.hostname;
|
||||||
|
|
||||||
if (hostnameOpt.isSome()) {
|
if (hostnameOpt.isSome()) {
|
||||||
@ -19,15 +19,9 @@ const rateLimitMiddleware: Middleware = (c) => {
|
|||||||
|
|
||||||
if (!clientCount || now - clientCount.lastReset > RATE_LIMIT_WINDOW) {
|
if (!clientCount || now - clientCount.lastReset > RATE_LIMIT_WINDOW) {
|
||||||
requestCounts[hostname] = { count: 1, lastReset: now };
|
requestCounts[hostname] = { count: 1, lastReset: now };
|
||||||
return;
|
} else if (clientCount.count < MAX_REQUESTS_PER_WINDOW) {
|
||||||
}
|
|
||||||
|
|
||||||
if (clientCount.count < MAX_REQUESTS_PER_WINDOW) {
|
|
||||||
clientCount.count++;
|
clientCount.count++;
|
||||||
return;
|
} else if (c.preferredType.isSome()) {
|
||||||
}
|
|
||||||
|
|
||||||
if (c.preferredType.isSome()) {
|
|
||||||
log.info(`client ${hostname} is rate limeted`);
|
log.info(`client ${hostname} is rate limeted`);
|
||||||
switch (c.preferredType.value) {
|
switch (c.preferredType.value) {
|
||||||
case "html": {
|
case "html": {
|
||||||
@ -46,11 +40,13 @@ const rateLimitMiddleware: Middleware = (c) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return new Response("429 Too Many Request", {
|
||||||
|
status: 429,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return new Response("429 Too Many Request", {
|
|
||||||
status: 429,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
await next();
|
||||||
};
|
};
|
||||||
|
|
||||||
export default rateLimitMiddleware;
|
export default rateLimitMiddleware;
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
quantile
|
|
||||||
|
|
||||||
quntile
|
|
||||||
Reference in New Issue
Block a user