-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.ts
More file actions
131 lines (112 loc) · 4.8 KB
/
Copy pathapp.ts
File metadata and controls
131 lines (112 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import type { ErrorRequestHandler, Express, NextFunction, Request, Response } from "express";
import express from "express";
import { requireAdmin } from "./middleware/admin.ts";
import { globalLimiter } from "./middleware/rateLimit.ts";
import { requestLogger } from "./middleware/requestLogger.ts";
import { requireLogin } from "./middleware/requireLogin.ts";
import { applySecurity } from "./middleware/security.ts";
import { applySession } from "./middleware/session.ts";
import { requireFreshToken } from "./middleware/tokenRefresh.ts";
import * as commandService from "./modules/commandService.ts";
import { generateCsrfToken, verifyCsrfToken } from "./modules/csrf.ts";
import { connectDB } from "./modules/db.ts";
import { env } from "./modules/env.ts";
import { getCachedUserGuilds } from "./modules/guildHelpers.ts";
import logger from "./modules/logger.ts";
import { ARENA_OFFSETS, formatPayoutTimes, getTimeLeft } from "./modules/payout.ts";
import { loadPlugins } from "./modules/pluginLoader.ts";
import authRoutes from "./routes/auth.ts";
import guildConfigRoutes from "./routes/guildConfig.ts";
import guildEventRoutes from "./routes/guildEvents.ts";
import guildSelectRoutes from "./routes/guildSelect.ts";
import healthRoutes from "./routes/health.ts";
import publicRoutes from "./routes/public.ts";
import userConfigRoutes from "./routes/userConfig.ts";
import type { PluginContext } from "./types/plugin.ts";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export async function createApp(): Promise<Express> {
const app = express();
app.set("trust proxy", "loopback, linklocal, uniquelocal");
applySecurity(app);
app.use(requestLogger);
app.use(express.static(join(__dirname, "public")));
applySession(app);
app.use(express.urlencoded({ extended: false }));
app.use((req: Request, res: Response, next: NextFunction) => {
res.locals.user = req.session.user ?? null;
res.locals.isAdmin = req.session.user?.id === env.ADMIN_DISCORD_ID;
res.locals.currentPath = req.path;
res.locals.logoutCsrfToken = req.session.user ? (req.session.csrfToken ?? null) : null;
res.locals.logoutReturnTo = "/";
next();
});
app.use("/", healthRoutes);
app.use(globalLimiter);
app.locals.formatPayoutTimes = formatPayoutTimes;
app.locals.getTimeLeft = getTimeLeft;
app.locals.ARENA_OFFSETS = ARENA_OFFSETS;
app.locals.partialsPath = join(__dirname, "partials");
app.locals.escapeAttr = (str: string): string => {
return String(str)
.replace(/&/g, "&")
.replace(/"/g, """)
.replace(/'/g, "'")
.replace(/</g, "<")
.replace(/>/g, ">");
};
logger.log("Loading bot command data...");
commandService.initialize();
await connectDB();
logger.log("Connected to bot database.");
const pluginCtx: PluginContext = {
env: process.env,
logger,
requireAdmin,
generateCsrfToken,
verifyCsrfToken,
getCachedUserGuilds,
partialsPath: join(__dirname, "partials"),
};
const plugins = await loadPlugins(pluginCtx);
const viewPaths: string[] = [__dirname, ...plugins.flatMap((p) => p.viewPaths ?? [])];
app.set("views", viewPaths);
app.set("view engine", "ejs");
for (const plugin of plugins) {
if (plugin.staticDir && plugin.staticMountPath) {
app.use(plugin.staticMountPath, express.static(plugin.staticDir));
}
}
app.use("/", publicRoutes);
app.use("/", authRoutes);
app.use("/", requireLogin, userConfigRoutes);
app.use("/", requireLogin, requireFreshToken, guildSelectRoutes);
app.use("/", requireLogin, requireFreshToken, guildConfigRoutes);
app.use("/", requireLogin, requireFreshToken, guildEventRoutes);
app.locals.pluginNavItems = plugins.flatMap((p) => p.navItems ?? []);
for (const plugin of plugins) {
app.use(plugin.mountPath, plugin.router);
logger.log(`Mounted plugin: ${plugin.name} at ${plugin.mountPath}`);
}
app.use((_req: Request, res: Response) => {
res.status(404).render("pages/404", {
title: "Page Not Found - SWGoHBot",
description: "The page you're looking for doesn't exist.",
});
});
const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => {
if (env.NODE_ENV !== "production") {
logger.error(err.stack);
} else {
logger.error(`Error: ${err.message}`);
}
res.status(500).render("pages/500", {
title: "Server Error - SWGoHBot",
description: "Something went wrong on our end.",
});
};
app.use(errorHandler);
return app;
}