diff --git a/README.md b/README.md index 24171fb..b4b469e 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,5 @@ Before Runningthis on you local machine some things have to be setup DOMAIN: THE DOMAIN NAME OF THE SERVER MAILPASSWORD: THE PASSWORD FOR THE MAIL ACCOUNT DEV: SWITCH FOR DEV MODE AFFECTS EMAIL SERVER + ALLOW_ORIGIN: ORIGIN OF THE PRODUCTION CLIENT (FOR CORS) ``` diff --git a/package.json b/package.json index 9d69e55..c615be5 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "homepage": "https://github.com/detleph/server#readme", "dependencies": { "@prisma/client": "^3.3.0", + "@types/cors": "^2.8.12", "@types/handlebars": "^4.1.0", "@types/express-fileupload": "^1.2.1", "@types/jsonwebtoken": "^8.5.5", @@ -28,13 +29,14 @@ "@types/nodemailer": "^6.4.4", "@types/redis": "^2.8.32", "argon2": "^0.28.2", + "cors": "^2.8.5", "dotenv": "^10.0.0", "express": "^4.17.1", - "handlebars": "^4.7.7", "express-async-errors": "^3.1.1", "express-fileupload": "^1.2.1", "file-type": "^16.5.3", "is-svg": "^4.3.2", + "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", "mjml": "^4.11.0", "nanoid": "^3.3.3", diff --git a/src/Middleware/error/defaultRoutes.ts b/src/Middleware/error/defaultRoutes.ts new file mode 100644 index 0000000..4a15997 --- /dev/null +++ b/src/Middleware/error/defaultRoutes.ts @@ -0,0 +1,27 @@ +import { Request, Response } from "express"; + +// Only called when no other route matches +export function notFoundHandler(req: Request, res: Response) { + return res.status(404).json({ + type: "error", + payload: { + message: `The ${req.method} HTTP method is implemented for '${req.path}'`, + _links: [ + { + rel: "root", + href: "/api", + }, + ], + }, + }); +} + +export function rootHandler(req: Request, res: Response) { + return res.status(200).json({ + type: "success", + payload: { + message: "Detleph event API", + detail: "This is the API for the Detleph event system", + }, + }); +} diff --git a/src/app.ts b/src/app.ts index ae0c0ec..5b39331 100644 --- a/src/app.ts +++ b/src/app.ts @@ -3,6 +3,7 @@ import prisma from "./lib/prisma"; import eventRouter from "./Routes/event.routes"; import adminAuthRouter from "./Routes/admin_auth.routes"; import argon2 from "argon2"; +import cors from "cors"; import adminRouter from "./Routes/admin.routes"; import organisationRouter from "./Routes/organisation.routes"; import groupRouter from "./Routes/group.routes"; @@ -12,6 +13,7 @@ import defaultErrorHandler from "./Middleware/error/handler"; import logger from "./Middleware/error/logger"; import debugLogger from "./Middleware/debug/logger"; import mediaRouter from "./Routes/media.routes"; +import { notFoundHandler, rootHandler } from "./Middleware/error/defaultRoutes"; // Set up async error handling require("express-async-errors"); @@ -20,21 +22,40 @@ require("dotenv").config(); // Load dotenv config const app = express(); -if (process.env.NODE_ENV === "development") { - logger.info("Using development mode"); -} - async function main() { - // Dev - await prisma.admin.upsert({ - where: { id: 1 }, - create: { - name: "admin", - password: await argon2.hash("test", { type: argon2.argon2id }), - permission_level: "ELEVATED", - }, - update: {}, - }); + if (process.env.NODE_ENV === "development") { + logger.info("Using development mode"); + logger.warning( + "This mode should not be used in any production-near environment as it is significantly less secure than the production mode" + ); + + // TODO: How should you login to the prod server by default? Maybe random password? + await prisma.admin.upsert({ + where: { id: 1 }, + create: { + name: "admin", + password: await argon2.hash("test", { type: argon2.argon2id }), + permission_level: "ELEVATED", + }, + update: {}, + }); + + // Allow all CORS requests + app.use(cors()); + } else { + logger.info("Using production mode"); + + // Configure cors + app.use( + cors({ + origin: process.env.ALLOW_ORIGIN, + allowedHeaders: ["Content-Type", "Authorization"], + preflightContinue: false, + methods: ["GET", "PUT", "PATCH", "POST", "DELETE"], + optionsSuccessStatus: 204, + }) + ); + } // Todo: Everything @@ -61,6 +82,9 @@ async function main() { app.use("/api/role-schemas", roleSchemaRouter); app.use("/api/media", mediaRouter); + + app.get("/", rootHandler); + app.get("/api", rootHandler); // Error handling app.use(defaultErrorHandler); // This has to be the LAST ROUTE @@ -68,6 +92,8 @@ async function main() { // Disable the media router for now // app.use("/api/media", mediaRouter); + app.use(notFoundHandler); + app.listen(process.env.PORT, () => { logger.info(`Listening on port ${process.env.PORT}`); });