server/server.ts

191 lines
6.9 KiB
TypeScript
Raw Normal View History

import { dualLogger } from "@loggers";
import { errorResponse, response } from "@response";
import type { MatchedRoute } from "bun";
2024-04-07 07:30:49 +02:00
import type { Config } from "config-manager";
import { matches } from "ip-matching";
import type { LogManager, MultiLogManager } from "log-manager";
import { LogLevel } from "log-manager";
2024-04-14 10:16:03 +02:00
import { processRoute } from "server-handler";
import { handleGlitchRequest } from "~packages/glitch-server/main";
2024-03-13 09:10:32 +01:00
import { matchRoute } from "~routes";
export const createServer = (
2024-04-07 07:30:49 +02:00
config: Config,
logger: LogManager | MultiLogManager,
isProd: boolean,
) =>
2024-04-07 07:30:49 +02:00
Bun.serve({
port: config.http.bind_port,
tls: config.http.tls.enabled
? {
key: Bun.file(config.http.tls.key),
cert: Bun.file(config.http.tls.cert),
passphrase: config.http.tls.passphrase,
ca: config.http.tls.ca
? Bun.file(config.http.tls.ca)
: undefined,
}
: undefined,
2024-04-07 07:30:49 +02:00
hostname: config.http.bind || "0.0.0.0", // defaults to "0.0.0.0"
async fetch(req) {
// Check for banned IPs
const request_ip = this.requestIP(req)?.address ?? "";
for (const ip of config.http.banned_ips) {
try {
if (matches(ip, request_ip)) {
2024-04-08 05:28:18 +02:00
return errorResponse("Forbidden", 403);
2024-04-07 07:30:49 +02:00
}
} catch (e) {
2024-04-14 13:20:55 +02:00
logger.log(
LogLevel.ERROR,
"Server.IPCheck",
`Error while parsing banned IP "${ip}" `,
);
logger.logError(
LogLevel.ERROR,
"Server.IPCheck",
e as Error,
);
return errorResponse(
`A server error occured: ${(e as Error).message}`,
500,
);
2024-04-07 07:30:49 +02:00
}
}
// Check for banned user agents (regex)
const ua = req.headers.get("User-Agent") ?? "";
for (const agent of config.http.banned_user_agents) {
if (new RegExp(agent).test(ua)) {
2024-04-08 05:28:18 +02:00
return errorResponse("Forbidden", 403);
2024-04-07 07:30:49 +02:00
}
}
if (config.http.bait.enabled) {
// Check for bait IPs
for (const ip of config.http.bait.bait_ips) {
try {
if (matches(ip, request_ip)) {
const file = Bun.file(
2024-04-09 13:14:53 +02:00
config.http.bait.send_file || "./beemovie.txt",
2024-04-07 07:30:49 +02:00
);
if (await file.exists()) {
2024-04-08 05:28:18 +02:00
return response(file);
2024-04-07 07:30:49 +02:00
}
await logger.log(
LogLevel.ERROR,
"Server.Bait",
`Bait file not found: ${config.http.bait.send_file}`,
);
}
} catch (e) {
2024-04-14 13:20:55 +02:00
logger.log(
LogLevel.ERROR,
"Server.IPCheck",
`Error while parsing bait IP "${ip}" `,
);
logger.logError(
LogLevel.ERROR,
"Server.IPCheck",
e as Error,
);
return errorResponse(
`A server error occured: ${(e as Error).message}`,
500,
2024-04-07 07:30:49 +02:00
);
}
}
// Check for bait user agents (regex)
for (const agent of config.http.bait.bait_user_agents) {
if (new RegExp(agent).test(ua)) {
const file = Bun.file(
2024-04-09 13:14:53 +02:00
config.http.bait.send_file || "./beemovie.txt",
2024-04-07 07:30:49 +02:00
);
if (await file.exists()) {
2024-04-08 05:28:18 +02:00
return response(file);
2024-04-07 07:30:49 +02:00
}
await logger.log(
LogLevel.ERROR,
"Server.Bait",
`Bait file not found: ${config.http.bait.send_file}`,
);
}
}
}
if (config.logging.log_requests) {
await logger.logRequest(
2024-04-07 14:26:19 +02:00
req.clone(),
2024-04-07 07:30:49 +02:00
config.logging.log_ip ? request_ip : undefined,
config.logging.log_requests_verbose,
);
}
2024-04-10 05:45:19 +02:00
// If route is .well-known, remove dot because the filesystem router can't handle dots for some reason
2024-04-14 13:57:26 +02:00
const matchedRoute = matchRoute(
new Request(req.url.replace(".well-known", "well-known"), {
method: req.method,
}),
2024-04-07 07:30:49 +02:00
);
if (
matchedRoute?.filePath &&
matchedRoute.name !== "/[...404]" &&
!(
new URL(req.url).pathname.startsWith("/oauth/authorize") &&
req.method === "GET"
)
) {
return await processRoute(matchedRoute, req, logger);
}
2024-04-09 13:42:53 +02:00
const base_url_with_http = config.http.base_url.replace(
"https://",
"http://",
);
const replacedUrl = req.url
.replace(config.http.base_url, config.frontend.url)
.replace(base_url_with_http, config.frontend.url);
2024-04-09 13:42:53 +02:00
2024-04-14 07:26:29 +02:00
const proxy = await fetch(replacedUrl, {
headers: {
// Include for SSR
"X-Forwarded-Host": `${config.http.bind}:${config.http.bind_port}`,
},
}).catch(async (e) => {
await logger.logError(
LogLevel.ERROR,
"Server.Proxy",
e as Error,
);
await logger.log(
LogLevel.ERROR,
"Server.Proxy",
`The Frontend is not running or the route is not found: ${replacedUrl}`,
);
return null;
});
if (!proxy || proxy.status === 404) {
if (config.frontend.glitch.enabled) {
return (
(await handleGlitchRequest(req, dualLogger)) ??
errorResponse("Route not found", 404)
);
}
} else {
return proxy;
2024-04-07 07:30:49 +02:00
}
2024-04-07 07:30:49 +02:00
return errorResponse("Route not found", 404);
},
});