server/index.ts

158 lines
3.7 KiB
TypeScript
Raw Normal View History

2023-09-11 05:54:14 +02:00
import { getConfig } from "@config";
2023-10-02 02:07:29 +02:00
import { jsonResponse } from "@response";
import { MatchedRoute } from "bun";
2023-10-23 02:32:17 +02:00
import chalk from "chalk";
2023-09-15 05:21:38 +02:00
import { appendFile } from "fs/promises";
import { matches } from "ip-matching";
2023-09-12 22:48:10 +02:00
import "reflect-metadata";
2023-09-14 04:25:45 +02:00
import { AppDataSource } from "~database/datasource";
import { User } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
2023-09-11 05:54:14 +02:00
2023-09-11 05:31:08 +02:00
const router = new Bun.FileSystemRouter({
style: "nextjs",
dir: process.cwd() + "/server/api",
2023-09-13 02:29:13 +02:00
});
2023-09-11 05:31:08 +02:00
2023-10-23 02:32:17 +02:00
console.log(`${chalk.green(`>`)} ${chalk.bold("Starting Lysand...")}`);
2023-09-11 05:46:20 +02:00
2023-09-11 05:54:14 +02:00
const config = getConfig();
2023-09-15 05:21:38 +02:00
const requests_log = Bun.file(process.cwd() + "/logs/requests.log");
if (!(await requests_log.exists())) {
2023-10-23 02:32:17 +02:00
console.log(`${chalk.green(``)} ${chalk.bold("Creating logs folder...")}`);
2023-09-15 05:21:38 +02:00
await Bun.write(process.cwd() + "/logs/requests.log", "");
}
2023-09-11 05:54:14 +02:00
2023-09-14 04:25:45 +02:00
if (!AppDataSource.isInitialized) await AppDataSource.initialize();
2023-09-11 05:31:08 +02:00
Bun.serve({
port: config.http.bind_port,
hostname: config.http.bind || "0.0.0.0", // defaults to "0.0.0.0"
2023-09-11 05:31:08 +02:00
async fetch(req) {
/* Check for banned IPs */
const request_ip = this.requestIP(req)?.address ?? "";
2023-09-15 05:21:38 +02:00
for (const ip of config.http.banned_ips) {
try {
if (matches(ip, request_ip)) {
return new Response(undefined, {
status: 403,
statusText: "Forbidden",
});
}
} catch (e) {
console.error(`[-] Error while parsing banned IP "${ip}" `);
throw e;
2023-09-15 05:21:38 +02:00
}
}
await logRequest(req);
2023-10-02 02:07:29 +02:00
if (req.method === "OPTIONS") {
return jsonResponse({});
}
2023-09-11 05:31:08 +02:00
const matchedRoute = router.match(req);
if (matchedRoute) {
const file: {
meta: APIRouteMeta;
default: (
req: Request,
matchedRoute: MatchedRoute
) => Response | Promise<Response>;
} = await import(matchedRoute.filePath);
const meta = file.meta;
// Check for allowed requests
if (!meta.allowedMethods.includes(req.method as any)) {
return new Response(undefined, {
status: 405,
statusText: `Method not allowed: allowed methods are: ${meta.allowedMethods.join(
", "
)}`,
});
}
// TODO: Check for ratelimits
// Check for authentication if required
if (meta.auth.required) {
const { user } = await User.getFromRequest(req);
if (!user) {
return new Response(undefined, {
status: 401,
statusText: "Unauthorized",
});
}
} else if (
(meta.auth.requiredOnMethods ?? []).includes(req.method as any)
) {
const { user } = await User.getFromRequest(req);
if (!user) {
return new Response(undefined, {
status: 401,
statusText: "Unauthorized",
});
}
}
return file.default(req, matchedRoute);
2023-09-11 05:31:08 +02:00
} else {
2023-09-11 05:46:20 +02:00
return new Response(undefined, {
2023-09-11 05:31:08 +02:00
status: 404,
statusText: "Route not found",
});
}
},
});
2023-09-11 05:46:20 +02:00
const logRequest = async (req: Request) => {
if (config.logging.log_requests_verbose) {
await appendFile(
`${process.cwd()}/logs/requests.log`,
`[${new Date().toISOString()}] ${req.method} ${
req.url
}\n\tHeaders:\n`
);
// Add headers
const headers = req.headers.entries();
for (const [key, value] of headers) {
await appendFile(
`${process.cwd()}/logs/requests.log`,
`\t\t${key}: ${value}\n`
);
}
const body = await req.clone().text();
await appendFile(
`${process.cwd()}/logs/requests.log`,
`\tBody:\n\t${body}\n`
);
} else if (config.logging.log_requests) {
await appendFile(
process.cwd() + "/logs/requests.log",
`[${new Date().toISOString()}] ${req.method} ${req.url}\n`
);
}
};
2023-10-23 02:32:17 +02:00
// Remove previous console.log
console.clear();
console.log(
`${chalk.green(``)} ${chalk.bold(
`Lysand started at ${chalk.blue(
`${config.http.bind}:${config.http.bind_port}`
)}`
)}`
);