mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-06 03:55:04 +02:00
organized routes and routes and added rate limiter
This commit is contained in:
parent
f1e77dfe42
commit
1a91dbb89c
45 changed files with 241 additions and 181 deletions
46
package-lock.json
generated
46
package-lock.json
generated
|
@ -12,9 +12,11 @@
|
||||||
"@node-rs/argon2": "1.8.3",
|
"@node-rs/argon2": "1.8.3",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"better-sqlite3": "11.3.0",
|
"better-sqlite3": "11.3.0",
|
||||||
|
"cookie-parser": "1.4.6",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"drizzle-orm": "0.33.0",
|
"drizzle-orm": "0.33.0",
|
||||||
"express": "4.21.0",
|
"express": "4.21.0",
|
||||||
|
"express-rate-limit": "7.4.0",
|
||||||
"helmet": "7.1.0",
|
"helmet": "7.1.0",
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"lucia": "3.2.0",
|
"lucia": "3.2.0",
|
||||||
|
@ -29,6 +31,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@dotenvx/dotenvx": "1.14.2",
|
"@dotenvx/dotenvx": "1.14.2",
|
||||||
"@types/better-sqlite3": "7.6.11",
|
"@types/better-sqlite3": "7.6.11",
|
||||||
|
"@types/cookie-parser": "1.4.7",
|
||||||
"@types/cors": "2.8.17",
|
"@types/cors": "2.8.17",
|
||||||
"@types/express": "5.0.0",
|
"@types/express": "5.0.0",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
@ -5865,6 +5868,15 @@
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/cookie-parser": {
|
||||||
|
"version": "1.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||||
|
"integrity": "sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/express": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/cors": {
|
"node_modules/@types/cors": {
|
||||||
"version": "2.8.17",
|
"version": "2.8.17",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||||
|
@ -7630,6 +7642,26 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cookie-parser": {
|
||||||
|
"version": "1.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz",
|
||||||
|
"integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "0.4.1",
|
||||||
|
"cookie-signature": "1.0.6"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cookie-parser/node_modules/cookie": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cookie-signature": {
|
"node_modules/cookie-signature": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
@ -9355,6 +9387,20 @@
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-rate-limit": {
|
||||||
|
"version": "7.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.0.tgz",
|
||||||
|
"integrity": "sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/express-rate-limit"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"express": "4 || 5 || ^5.0.0-beta.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express/node_modules/debug": {
|
"node_modules/express/node_modules/debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "dotenvx run -- tsx watch server/index.ts",
|
"dev": "dotenvx run -- tsx watch server/index.ts",
|
||||||
"db:generate": "drizzle-kit generate",
|
"db:generate": "drizzle-kit generate",
|
||||||
"db:push": "npx tsx scripts/migrate.ts",
|
"db:push": "npx tsx db/migrate.ts",
|
||||||
"db:hydrate": "npx tsx scripts/hydrate.ts",
|
"db:hydrate": "npx tsx scripts/hydrate.ts",
|
||||||
"db:studio": "drizzle-kit studio",
|
"db:studio": "drizzle-kit studio",
|
||||||
"build": "next build && tsc --project tsconfig.server.json && tsc-alias -p tsconfig.server.json",
|
"build": "next build && tsc --project tsconfig.server.json && tsc-alias -p tsconfig.server.json",
|
||||||
|
@ -16,9 +16,11 @@
|
||||||
"@node-rs/argon2": "1.8.3",
|
"@node-rs/argon2": "1.8.3",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"better-sqlite3": "11.3.0",
|
"better-sqlite3": "11.3.0",
|
||||||
|
"cookie-parser": "1.4.6",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
"drizzle-orm": "0.33.0",
|
"drizzle-orm": "0.33.0",
|
||||||
"express": "4.21.0",
|
"express": "4.21.0",
|
||||||
|
"express-rate-limit": "7.4.0",
|
||||||
"helmet": "7.1.0",
|
"helmet": "7.1.0",
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"lucia": "3.2.0",
|
"lucia": "3.2.0",
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@dotenvx/dotenvx": "1.14.2",
|
"@dotenvx/dotenvx": "1.14.2",
|
||||||
"@types/better-sqlite3": "7.6.11",
|
"@types/better-sqlite3": "7.6.11",
|
||||||
|
"@types/cookie-parser": "1.4.7",
|
||||||
"@types/cors": "2.8.17",
|
"@types/cors": "2.8.17",
|
||||||
"@types/express": "5.0.0",
|
"@types/express": "5.0.0",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
|
|
@ -9,7 +9,7 @@ const adapter = new DrizzleSQLiteAdapter(db, sessions, users);
|
||||||
export const lucia = new Lucia(adapter, {
|
export const lucia = new Lucia(adapter, {
|
||||||
getUserAttributes: (attributes) => {
|
getUserAttributes: (attributes) => {
|
||||||
return {
|
return {
|
||||||
username: attributes.username,
|
email: attributes.email,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// getSessionAttributes: (attributes) => {
|
// getSessionAttributes: (attributes) => {
|
||||||
|
@ -19,7 +19,7 @@ export const lucia = new Lucia(adapter, {
|
||||||
// },
|
// },
|
||||||
sessionCookie: {
|
sessionCookie: {
|
||||||
name: "session",
|
name: "session",
|
||||||
expires: false, // session cookies have very long lifespan (2 years)
|
expires: false,
|
||||||
attributes: {
|
attributes: {
|
||||||
secure: environment.ENVIRONMENT === "prod",
|
secure: environment.ENVIRONMENT === "prod",
|
||||||
sameSite: "strict",
|
sameSite: "strict",
|
||||||
|
@ -31,7 +31,6 @@ export const lucia = new Lucia(adapter, {
|
||||||
|
|
||||||
export default lucia;
|
export default lucia;
|
||||||
|
|
||||||
// IMPORTANT!
|
|
||||||
declare module "lucia" {
|
declare module "lucia" {
|
||||||
interface Register {
|
interface Register {
|
||||||
Lucia: typeof lucia;
|
Lucia: typeof lucia;
|
||||||
|
@ -41,7 +40,7 @@ declare module "lucia" {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DatabaseUserAttributes {
|
interface DatabaseUserAttributes {
|
||||||
username: string;
|
email: string;
|
||||||
passwordHash: string;
|
passwordHash: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,46 +5,60 @@ import environment from "@server/environment";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
|
import {
|
||||||
|
errorHandlerMiddleware,
|
||||||
|
rateLimitMiddleware,
|
||||||
|
} from "@server/middlewares";
|
||||||
import internal from "@server/routers/internal";
|
import internal from "@server/routers/internal";
|
||||||
import external from "@server/routers/external";
|
import { authenticated, unauthenticated } from "@server/routers/external";
|
||||||
import notFoundMiddleware from "./middlewares/notFound";
|
import cookieParser from "cookie-parser";
|
||||||
import { errorHandlerMiddleware } from "./middlewares/formatError";
|
|
||||||
|
|
||||||
const dev = environment.ENVIRONMENT !== "prod";
|
const dev = environment.ENVIRONMENT !== "prod";
|
||||||
|
|
||||||
const app = next({ dev });
|
const app = next({ dev });
|
||||||
const handle = app.getRequestHandler();
|
const handle = app.getRequestHandler();
|
||||||
const mainPort = environment.EXTERNAL_PORT;
|
|
||||||
|
const externalPort = environment.EXTERNAL_PORT;
|
||||||
const internalPort = environment.INTERNAL_PORT;
|
const internalPort = environment.INTERNAL_PORT;
|
||||||
|
|
||||||
app.prepare().then(() => {
|
app.prepare().then(() => {
|
||||||
// Main server
|
// External server
|
||||||
const mainServer = express();
|
const externalServer = express();
|
||||||
mainServer.use(helmet());
|
|
||||||
mainServer.use(cors());
|
externalServer.use(helmet());
|
||||||
|
externalServer.use(cors());
|
||||||
|
externalServer.use(cookieParser());
|
||||||
|
externalServer.use(express.json());
|
||||||
|
externalServer.use(rateLimitMiddleware);
|
||||||
|
|
||||||
const prefix = `/api/v1`;
|
const prefix = `/api/v1`;
|
||||||
mainServer.use(prefix, express.json(), external);
|
externalServer.use(prefix, unauthenticated);
|
||||||
|
externalServer.use(prefix, authenticated);
|
||||||
|
|
||||||
// We are using NEXT from here on
|
// We are using NEXT from here on
|
||||||
mainServer.all("*", (req: Request, res: Response) => {
|
externalServer.all("*", (req: Request, res: Response) => {
|
||||||
const parsedUrl = parse(req.url!, true);
|
const parsedUrl = parse(req.url!, true);
|
||||||
handle(req, res, parsedUrl);
|
handle(req, res, parsedUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
mainServer.listen(mainPort, (err?: any) => {
|
externalServer.listen(externalPort, (err?: any) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
logger.info(`Main server is running on http://localhost:${mainPort}`);
|
logger.info(
|
||||||
|
`Main server is running on http://localhost:${externalPort}`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
mainServer.use(notFoundMiddleware);
|
externalServer.use(errorHandlerMiddleware);
|
||||||
mainServer.use(errorHandlerMiddleware);
|
|
||||||
|
|
||||||
// Internal server
|
// Internal server
|
||||||
const internalServer = express();
|
const internalServer = express();
|
||||||
|
|
||||||
internalServer.use(helmet());
|
internalServer.use(helmet());
|
||||||
internalServer.use(cors());
|
internalServer.use(cors());
|
||||||
|
internalServer.use(cookieParser());
|
||||||
|
internalServer.use(express.json());
|
||||||
|
|
||||||
internalServer.use(prefix, express.json(), internal);
|
internalServer.use(prefix, internal);
|
||||||
|
|
||||||
internalServer.listen(internalPort, (err?: any) => {
|
internalServer.listen(internalPort, (err?: any) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
@ -53,7 +67,3 @@ app.prepare().then(() => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("SIGINT", () => {
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ export const errorHandlerMiddleware: ErrorRequestHandler = (
|
||||||
res: Response<ErrorResponse>,
|
res: Response<ErrorResponse>,
|
||||||
next: NextFunction,
|
next: NextFunction,
|
||||||
) => {
|
) => {
|
||||||
logger.error(error);
|
|
||||||
const statusCode = error.statusCode || HttpCode.INTERNAL_SERVER_ERROR;
|
const statusCode = error.statusCode || HttpCode.INTERNAL_SERVER_ERROR;
|
||||||
res?.status(statusCode).send({
|
res?.status(statusCode).send({
|
||||||
data: null,
|
data: null,
|
||||||
|
|
3
server/middlewares/index.ts
Normal file
3
server/middlewares/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export * from "./notFound";
|
||||||
|
export * from "./rateLimit";
|
||||||
|
export * from "./formatError";
|
20
server/middlewares/rateLimit.ts
Normal file
20
server/middlewares/rateLimit.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { rateLimit } from "express-rate-limit";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import { NextFunction, Request, Response } from "express";
|
||||||
|
import logger from "@server/logger";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
|
const limit = 100;
|
||||||
|
const minutes = 1;
|
||||||
|
|
||||||
|
export const rateLimitMiddleware = rateLimit({
|
||||||
|
windowMs: minutes * 60 * 1000,
|
||||||
|
limit,
|
||||||
|
handler: (req: Request, res: Response, next: NextFunction) => {
|
||||||
|
const message = `Rate limit exceeded. You can make ${limit} requests every ${minutes} minute(s).`;
|
||||||
|
logger.warn(`Rate limit exceeded for IP ${req.ip}`);
|
||||||
|
return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default rateLimitMiddleware;
|
2
server/routers/auth/index.ts
Normal file
2
server/routers/auth/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./login";
|
||||||
|
export * from "./signup";
|
|
@ -2,6 +2,7 @@ import { verify } from "@node-rs/argon2";
|
||||||
import lucia from "@server/auth";
|
import lucia from "@server/auth";
|
||||||
import db from "@server/db";
|
import db from "@server/db";
|
||||||
import { users } from "@server/db/schema";
|
import { users } from "@server/db/schema";
|
||||||
|
import logger from "@server/logger";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import response from "@server/utils/response";
|
import response from "@server/utils/response";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
@ -15,7 +16,11 @@ export const loginBodySchema = z.object({
|
||||||
password: z.string(),
|
password: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function login(req: Request, res: Response, next: NextFunction) {
|
export async function login(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
): Promise<any> {
|
||||||
const parsedBody = loginBodySchema.safeParse(req.body);
|
const parsedBody = loginBodySchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsedBody.success) {
|
if (!parsedBody.success) {
|
||||||
|
@ -29,6 +34,20 @@ export async function login(req: Request, res: Response, next: NextFunction) {
|
||||||
|
|
||||||
const { email, password } = parsedBody.data;
|
const { email, password } = parsedBody.data;
|
||||||
|
|
||||||
|
const sessionId = req.cookies[lucia.sessionCookieName];
|
||||||
|
const { session: existingSession } = await lucia.validateSession(sessionId);
|
||||||
|
if (existingSession) {
|
||||||
|
return res.status(HttpCode.OK).send(
|
||||||
|
response<null>({
|
||||||
|
data: null,
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Already logged in",
|
||||||
|
status: HttpCode.OK,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const existingUserRes = await db
|
const existingUserRes = await db
|
||||||
.select()
|
.select()
|
||||||
.from(users)
|
.from(users)
|
|
@ -28,7 +28,7 @@ export const signupBodySchema = z.object({
|
||||||
|
|
||||||
export type SignUpBody = z.infer<typeof signupBodySchema>;
|
export type SignUpBody = z.infer<typeof signupBodySchema>;
|
||||||
|
|
||||||
export async function signup(req: Request, res: Response, next: NextFunction) {
|
export async function signup(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
const parsedBody = signupBodySchema.safeParse(req.body);
|
const parsedBody = signupBodySchema.safeParse(req.body);
|
||||||
|
|
||||||
if (!parsedBody.success) {
|
if (!parsedBody.success) {
|
|
@ -1,9 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
|
|
||||||
const badger = Router();
|
|
||||||
|
|
||||||
badger.get("/", (_, res) => {
|
|
||||||
res.status(200).json({ message: "Healthy" });
|
|
||||||
});
|
|
||||||
|
|
||||||
export default badger;
|
|
|
@ -1,17 +1,48 @@
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import gerbil from "./gerbil/gerbil";
|
import * as site from "./site";
|
||||||
import pangolin from "./pangolin/pangolin";
|
import * as org from "./org";
|
||||||
import global from "./global/global";
|
import * as resource from "./resource";
|
||||||
|
import * as target from "./target";
|
||||||
|
import * as user from "./user";
|
||||||
|
import * as auth from "./auth";
|
||||||
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
const unauth = Router();
|
// Root routes
|
||||||
|
export const unauthenticated = Router();
|
||||||
|
|
||||||
unauth.get("/", (_, res) => {
|
unauthenticated.get("/", (_, res) => {
|
||||||
res.status(200).json({ message: "Healthy" });
|
res.status(HttpCode.OK).json({ message: "Healthy" });
|
||||||
});
|
});
|
||||||
|
|
||||||
unauth.use("/newt", gerbil);
|
// Authenticated Root routes
|
||||||
unauth.use("/pangolin", pangolin);
|
export const authenticated = Router();
|
||||||
|
|
||||||
unauth.use("/", global)
|
authenticated.put("/site", site.createSite);
|
||||||
|
authenticated.get("/site/:siteId", site.getSite);
|
||||||
|
authenticated.post("/site/:siteId", site.updateSite);
|
||||||
|
authenticated.delete("/site/:siteId", site.deleteSite);
|
||||||
|
|
||||||
export default unauth;
|
authenticated.put("/org", org.createOrg);
|
||||||
|
authenticated.get("/org/:orgId", org.getOrg);
|
||||||
|
authenticated.post("/org/:orgId", org.updateOrg);
|
||||||
|
authenticated.delete("/org/:orgId", org.deleteOrg);
|
||||||
|
|
||||||
|
authenticated.put("/resource", resource.createResource);
|
||||||
|
authenticated.get("/resource/:resourceId", resource.getResource);
|
||||||
|
authenticated.post("/resource/:resourceId", resource.updateResource);
|
||||||
|
authenticated.delete("/resource/:resourceId", resource.deleteResource);
|
||||||
|
|
||||||
|
authenticated.put("/target", target.createTarget);
|
||||||
|
authenticated.get("/target/:targetId", target.getTarget);
|
||||||
|
authenticated.post("/target/:targetId", target.updateTarget);
|
||||||
|
authenticated.delete("/target/:targetId", target.deleteTarget);
|
||||||
|
|
||||||
|
authenticated.get("/user/:userId", user.getUser);
|
||||||
|
authenticated.delete("/user/:userId", user.deleteUser);
|
||||||
|
|
||||||
|
// Auth routes
|
||||||
|
const authRouter = Router();
|
||||||
|
unauthenticated.use("/auth", authRouter);
|
||||||
|
|
||||||
|
authRouter.put("/signup", auth.signup);
|
||||||
|
authRouter.post("/login", auth.login);
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
import { getConfig } from "./getConfig";
|
|
||||||
import { receiveBandwidth } from "./receiveBandwidth";
|
|
||||||
|
|
||||||
const gerbil = Router();
|
|
||||||
|
|
||||||
gerbil.get("/", (_, res) => {
|
|
||||||
res.status(200).json({ message: "Healthy" });
|
|
||||||
});
|
|
||||||
|
|
||||||
gerbil.get("/get-config", getConfig);
|
|
||||||
gerbil.post("/receive-bandwidth", receiveBandwidth);
|
|
||||||
|
|
||||||
export default gerbil;
|
|
2
server/routers/gerbil/index.ts
Normal file
2
server/routers/gerbil/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./getConfig";
|
||||||
|
export * from "./receiveBandwidth";
|
|
@ -1,58 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
import { signup } from "@server/auth/signup";
|
|
||||||
import { login } from "@server/auth/login";
|
|
||||||
import { getSite } from "./site/getSite";
|
|
||||||
import { createSite } from "./site/createSite";
|
|
||||||
import { updateSite } from "./site/updateSite";
|
|
||||||
import { deleteSite } from "./site/deleteSite";
|
|
||||||
import { getOrg } from "./org/getOrg";
|
|
||||||
import { createOrg } from "./org/createOrg";
|
|
||||||
import { updateOrg } from "./org/updateOrg";
|
|
||||||
import { deleteOrg } from "./org/deleteOrg";
|
|
||||||
import { getResource } from "./resource/getResource";
|
|
||||||
import { createResource } from "./resource/createResource";
|
|
||||||
import { updateResource } from "./resource/updateResource";
|
|
||||||
import { deleteResource } from "./resource/deleteResource";
|
|
||||||
import { getTarget } from "./target/getTarget";
|
|
||||||
import { createTarget } from "./target/createTarget";
|
|
||||||
import { updateTarget } from "./target/updateTarget";
|
|
||||||
import { deleteTarget } from "./target/deleteTarget";
|
|
||||||
import { getUser } from "./user/getUser";
|
|
||||||
import { createUser } from "./user/createUser";
|
|
||||||
import { updateUser } from "./user/updateUser";
|
|
||||||
import { deleteUser } from "./user/deleteUser";
|
|
||||||
|
|
||||||
const global = Router();
|
|
||||||
|
|
||||||
global.get("/", (_, res) => {
|
|
||||||
res.status(200).json({ message: "Healthy" });
|
|
||||||
});
|
|
||||||
|
|
||||||
global.put("/site", createSite);
|
|
||||||
global.get("/site/:siteId", getSite);
|
|
||||||
global.post("/site/:siteId", updateSite);
|
|
||||||
global.delete("/site/:siteId", deleteSite);
|
|
||||||
|
|
||||||
global.put("/org", createOrg);
|
|
||||||
global.get("/org/:orgId", getOrg);
|
|
||||||
global.post("/org/:orgId", updateOrg);
|
|
||||||
global.delete("/org/:orgId", deleteOrg);
|
|
||||||
|
|
||||||
global.put("/resource", createResource);
|
|
||||||
global.get("/resource/resourceId", getResource);
|
|
||||||
global.post("/resource/resourceId", updateResource);
|
|
||||||
global.delete("/resource/resourceId", deleteResource);
|
|
||||||
|
|
||||||
global.put("/target", createTarget);
|
|
||||||
global.get("/target/:targetId", getTarget);
|
|
||||||
global.post("/target/:targetId", updateTarget);
|
|
||||||
global.delete("/target/:targetId", deleteTarget);
|
|
||||||
|
|
||||||
global.get("/user/:userId", getUser);
|
|
||||||
global.delete("/user/:userId", deleteUser);
|
|
||||||
|
|
||||||
// auth
|
|
||||||
global.post("/signup", signup);
|
|
||||||
global.post("/login", login);
|
|
||||||
|
|
||||||
export default global;
|
|
|
@ -1,17 +1,23 @@
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import gerbil from "./gerbil/gerbil";
|
import * as gerbil from "@server/routers/gerbil";
|
||||||
import badger from "./badger/badger";
|
import * as traefik from "@server/routers/traefik";
|
||||||
import { traefikConfigProvider } from "@server/traefik-config-provider";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
|
|
||||||
const unauth = Router();
|
// Root routes
|
||||||
|
const internalRouter = Router();
|
||||||
|
|
||||||
unauth.get("/", (_, res) => {
|
internalRouter.get("/", (_, res) => {
|
||||||
res.status(200).json({ message: "Healthy" });
|
res.status(HttpCode.OK).json({ message: "Healthy" });
|
||||||
});
|
});
|
||||||
|
|
||||||
unauth.use("/badger", badger);
|
internalRouter.get("/traefik-config", traefik.traefikConfigProvider);
|
||||||
unauth.use("/gerbil", gerbil);
|
|
||||||
|
|
||||||
unauth.get("/traefik-config-provider", traefikConfigProvider);
|
// Gerbil routes
|
||||||
|
const gerbilRouter = Router();
|
||||||
|
|
||||||
export default unauth;
|
gerbilRouter.get("/get-config", gerbil.getConfig);
|
||||||
|
gerbilRouter.post("/receive-bandwidth", gerbil.receiveBandwidth);
|
||||||
|
|
||||||
|
internalRouter.use("/gerbil", gerbilRouter);
|
||||||
|
|
||||||
|
export default internalRouter;
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
|
|
||||||
const newt = Router();
|
|
||||||
|
|
||||||
newt.get("/", (_, res) => {
|
|
||||||
res.status(200).json({ message: "Healthy" });
|
|
||||||
});
|
|
||||||
|
|
||||||
export default newt;
|
|
|
@ -11,7 +11,7 @@ const createOrgSchema = z.object({
|
||||||
domain: z.string().min(1).max(255),
|
domain: z.string().min(1).max(255),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function createOrg(req: Request, res: Response, next: NextFunction) {
|
export async function createOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedBody = createOrgSchema.safeParse(req.body);
|
const parsedBody = createOrgSchema.safeParse(req.body);
|
||||||
if (!parsedBody.success) {
|
if (!parsedBody.success) {
|
||||||
|
@ -42,4 +42,4 @@ export async function createOrg(req: Request, res: Response, next: NextFunction)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ const deleteOrgSchema = z.object({
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteOrg(req: Request, res: Response, next: NextFunction) {
|
export async function deleteOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = deleteOrgSchema.safeParse(req.params);
|
const parsedParams = deleteOrgSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -50,4 +50,4 @@ export async function deleteOrg(req: Request, res: Response, next: NextFunction)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ const getOrgSchema = z.object({
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getOrg(req: Request, res: Response, next: NextFunction) {
|
export async function getOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = getOrgSchema.safeParse(req.params);
|
const parsedParams = getOrgSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -51,4 +51,4 @@ export async function getOrg(req: Request, res: Response, next: NextFunction) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
4
server/routers/org/index.ts
Normal file
4
server/routers/org/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export * from "./getOrg";
|
||||||
|
export * from "./createOrg";
|
||||||
|
export * from "./deleteOrg";
|
||||||
|
export * from "./updateOrg";
|
|
@ -18,7 +18,7 @@ const updateOrgBodySchema = z.object({
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function updateOrg(req: Request, res: Response, next: NextFunction) {
|
export async function updateOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = updateOrgParamsSchema.safeParse(req.params);
|
const parsedParams = updateOrgParamsSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -69,4 +69,4 @@ export async function updateOrg(req: Request, res: Response, next: NextFunction)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
import { Router } from "express";
|
|
||||||
|
|
||||||
const pangolin = Router();
|
|
||||||
|
|
||||||
pangolin.get("/", (_, res) => {
|
|
||||||
res.status(200).json({ message: "Healthy" });
|
|
||||||
});
|
|
||||||
|
|
||||||
export default pangolin;
|
|
|
@ -13,7 +13,7 @@ const createResourceSchema = z.object({
|
||||||
subdomain: z.string().min(1).max(255).optional(),
|
subdomain: z.string().min(1).max(255).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function createResource(req: Request, res: Response, next: NextFunction) {
|
export async function createResource(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request body
|
// Validate request body
|
||||||
const parsedBody = createResourceSchema.safeParse(req.body);
|
const parsedBody = createResourceSchema.safeParse(req.body);
|
||||||
|
@ -51,4 +51,4 @@ export async function createResource(req: Request, res: Response, next: NextFunc
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@ const deleteResourceSchema = z.object({
|
||||||
resourceId: z.string().uuid()
|
resourceId: z.string().uuid()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteResource(req: Request, res: Response, next: NextFunction) {
|
export async function deleteResource(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = deleteResourceSchema.safeParse(req.params);
|
const parsedParams = deleteResourceSchema.safeParse(req.params);
|
||||||
|
@ -53,4 +53,4 @@ export async function deleteResource(req: Request, res: Response, next: NextFunc
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@ const getResourceSchema = z.object({
|
||||||
resourceId: z.string().uuid()
|
resourceId: z.string().uuid()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getResource(req: Request, res: Response, next: NextFunction) {
|
export async function getResource(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = getResourceSchema.safeParse(req.params);
|
const parsedParams = getResourceSchema.safeParse(req.params);
|
||||||
|
@ -54,4 +54,4 @@ export async function getResource(req: Request, res: Response, next: NextFunctio
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
4
server/routers/resource/index.ts
Normal file
4
server/routers/resource/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export * from "./getResource";
|
||||||
|
export * from "./createResource";
|
||||||
|
export * from "./deleteResource";
|
||||||
|
export * from "./updateResource";
|
|
@ -20,7 +20,7 @@ const updateResourceBodySchema = z.object({
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function updateResource(req: Request, res: Response, next: NextFunction) {
|
export async function updateResource(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = updateResourceParamsSchema.safeParse(req.params);
|
const parsedParams = updateResourceParamsSchema.safeParse(req.params);
|
||||||
|
@ -74,4 +74,4 @@ export async function updateResource(req: Request, res: Response, next: NextFunc
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ import HttpCode from '@server/types/HttpCode';
|
||||||
|
|
||||||
// define zod type here
|
// define zod type here
|
||||||
|
|
||||||
export async function createSite(req: Request, res: Response, next: NextFunction) {
|
export async function createSite(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
return res.status(HttpCode.OK).send(
|
return res.status(HttpCode.OK).send(
|
||||||
response<null>({
|
response<null>({
|
||||||
data: null,
|
data: null,
|
|
@ -12,7 +12,7 @@ const deleteSiteSchema = z.object({
|
||||||
siteId: z.string().transform(Number).pipe(z.number().int().positive())
|
siteId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteSite(req: Request, res: Response, next: NextFunction) {
|
export async function deleteSite(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = deleteSiteSchema.safeParse(req.params);
|
const parsedParams = deleteSiteSchema.safeParse(req.params);
|
||||||
|
@ -53,4 +53,4 @@ export async function deleteSite(req: Request, res: Response, next: NextFunction
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@ const getSiteSchema = z.object({
|
||||||
siteId: z.string().transform(Number).pipe(z.number().int().positive())
|
siteId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getSite(req: Request, res: Response, next: NextFunction) {
|
export async function getSite(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = getSiteSchema.safeParse(req.params);
|
const parsedParams = getSiteSchema.safeParse(req.params);
|
||||||
|
@ -54,4 +54,4 @@ export async function getSite(req: Request, res: Response, next: NextFunction) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
4
server/routers/site/index.ts
Normal file
4
server/routers/site/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export * from "./getSite";
|
||||||
|
export * from "./createSite";
|
||||||
|
export * from "./deleteSite";
|
||||||
|
export * from "./updateSite";
|
|
@ -25,7 +25,7 @@ const updateSiteBodySchema = z.object({
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function updateSite(req: Request, res: Response, next: NextFunction) {
|
export async function updateSite(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
// Validate request parameters
|
// Validate request parameters
|
||||||
const parsedParams = updateSiteParamsSchema.safeParse(req.params);
|
const parsedParams = updateSiteParamsSchema.safeParse(req.params);
|
||||||
|
@ -79,4 +79,4 @@ export async function updateSite(req: Request, res: Response, next: NextFunction
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ const createTargetSchema = z.object({
|
||||||
enabled: z.boolean().default(true),
|
enabled: z.boolean().default(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function createTarget(req: Request, res: Response, next: NextFunction) {
|
export async function createTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedBody = createTargetSchema.safeParse(req.body);
|
const parsedBody = createTargetSchema.safeParse(req.body);
|
||||||
if (!parsedBody.success) {
|
if (!parsedBody.success) {
|
||||||
|
@ -43,4 +43,4 @@ export async function createTarget(req: Request, res: Response, next: NextFuncti
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ const deleteTargetSchema = z.object({
|
||||||
targetId: z.string().transform(Number).pipe(z.number().int().positive())
|
targetId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteTarget(req: Request, res: Response, next: NextFunction) {
|
export async function deleteTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = deleteTargetSchema.safeParse(req.params);
|
const parsedParams = deleteTargetSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -50,4 +50,4 @@ export async function deleteTarget(req: Request, res: Response, next: NextFuncti
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ const getTargetSchema = z.object({
|
||||||
targetId: z.string().transform(Number).pipe(z.number().int().positive())
|
targetId: z.string().transform(Number).pipe(z.number().int().positive())
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getTarget(req: Request, res: Response, next: NextFunction) {
|
export async function getTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = getTargetSchema.safeParse(req.params);
|
const parsedParams = getTargetSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -51,4 +51,4 @@ export async function getTarget(req: Request, res: Response, next: NextFunction)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
4
server/routers/target/index.ts
Normal file
4
server/routers/target/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export * from "./getTarget";
|
||||||
|
export * from "./createTarget";
|
||||||
|
export * from "./deleteTarget";
|
||||||
|
export * from "./updateTarget";
|
|
@ -21,7 +21,7 @@ const updateTargetBodySchema = z.object({
|
||||||
message: "At least one field must be provided for update"
|
message: "At least one field must be provided for update"
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function updateTarget(req: Request, res: Response, next: NextFunction) {
|
export async function updateTarget(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = updateTargetParamsSchema.safeParse(req.params);
|
const parsedParams = updateTargetParamsSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -72,4 +72,4 @@ export async function updateTarget(req: Request, res: Response, next: NextFuncti
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
1
server/routers/traefik/index.ts
Normal file
1
server/routers/traefik/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./getTraefikConfig";
|
|
@ -11,7 +11,7 @@ const deleteUserSchema = z.object({
|
||||||
userId: z.string().uuid()
|
userId: z.string().uuid()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteUser(req: Request, res: Response, next: NextFunction) {
|
export async function deleteUser(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = deleteUserSchema.safeParse(req.params);
|
const parsedParams = deleteUserSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -50,4 +50,4 @@ export async function deleteUser(req: Request, res: Response, next: NextFunction
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ const getUserSchema = z.object({
|
||||||
userId: z.string().uuid()
|
userId: z.string().uuid()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getUser(req: Request, res: Response, next: NextFunction) {
|
export async function getUser(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const parsedParams = getUserSchema.safeParse(req.params);
|
const parsedParams = getUserSchema.safeParse(req.params);
|
||||||
if (!parsedParams.success) {
|
if (!parsedParams.success) {
|
||||||
|
@ -54,4 +54,4 @@ export async function getUser(req: Request, res: Response, next: NextFunction) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
2
server/routers/user/index.ts
Normal file
2
server/routers/user/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./getUser";
|
||||||
|
export * from "./deleteUser";
|
Loading…
Add table
Add a link
Reference in a new issue