From bdc1cb07947df00e010635c310c307bcaebf2756 Mon Sep 17 00:00:00 2001 From: journey-ad Date: Fri, 25 Oct 2024 13:36:32 +0800 Subject: [PATCH] refactor: Add cors middleware --- index.js | 3 +- utils/middleware.js | 83 +++++++++++++++++++++++++++++++++++++++++++++ utils/zod.js | 50 --------------------------- 3 files changed, 85 insertions(+), 51 deletions(-) create mode 100644 utils/middleware.js delete mode 100644 utils/zod.js diff --git a/index.js b/index.js index 749b733..55c5d34 100644 --- a/index.js +++ b/index.js @@ -7,13 +7,14 @@ const { z } = require("zod"); const db = require("./db"); const { themeList, getCountImage } = require("./utils/themify"); -const { ZodValid } = require("./utils/zod"); +const { cors, ZodValid } = require("./utils/middleware"); const { randomArray } = require("./utils"); const app = express(); app.use(express.static("assets")); app.use(compression()); +app.use(cors()); app.set("view engine", "pug"); app.get('/', (req, res) => { diff --git a/utils/middleware.js b/utils/middleware.js new file mode 100644 index 0000000..dc352e0 --- /dev/null +++ b/utils/middleware.js @@ -0,0 +1,83 @@ +function parseError(error) { + const err = JSON.parse(error)[0]; + + return { + code: 400, + message: `The field \`${err.path[0]}\` is invalid. ${err.message}`, + } +} +function validateInput(parseFn, input) { + const result = parseFn(input); + if (!result.success) { + return parseError(result.error); + } + return null; +} + +module.exports = { + ZodValid: ({ headers, params, query, body }) => { + const handler = (req, res, next) => { + const validations = [ + { input: req.headers, parseFn: headers?.safeParse }, + { input: req.params, parseFn: params?.safeParse }, + { input: req.query, parseFn: query?.safeParse }, + { input: req.body, parseFn: body?.safeParse }, + ]; + + for (const { input, parseFn } of validations) { + if (parseFn) { + const error = validateInput(parseFn, input); + if (error) { + return res.status(400).send(error); + } + } + } + + next(); + } + + return handler + }, + cors: ({ allowOrigins = '*', allowMethods = 'GET, POST, PUT, DELETE' } = {}) => { + const isOriginAllowed = (origin) => { + if (Array.isArray(allowOrigins)) { + return allowOrigins.includes(origin); + } + if (typeof allowOrigins === 'string') { + return allowOrigins === '*' || allowOrigins === origin; + } + return false; + }; + + const handler = (req, res, next) => { + const origin = req.headers.origin; + + if (origin && isOriginAllowed(origin)) { + res.header("Access-Control-Allow-Origin", origin); + res.header("Access-Control-Allow-Credentials", "true"); + } else { + return next(); + } + + if (req.method === "OPTIONS") { + const requestMethod = req.headers['access-control-request-method']; + if (requestMethod) { + res.header("Access-Control-Allow-Methods", requestMethod); + } else { + res.header("Access-Control-Allow-Methods", allowMethods); + } + + const requestHeaders = req.headers['access-control-request-headers']; + if (requestHeaders) { + res.header("Access-Control-Allow-Headers", requestHeaders); + } + + return res.sendStatus(204); + } + + next(); + }; + + return handler; + } +} diff --git a/utils/zod.js b/utils/zod.js deleted file mode 100644 index f5bcc89..0000000 --- a/utils/zod.js +++ /dev/null @@ -1,50 +0,0 @@ -function parseError(error) { - const err = JSON.parse(error)[0]; - - return { - code: 400, - message: `The field \`${err.path[0]}\` is invalid. ${err.message}`, - } -} - -module.exports = { - ZodValid: ({ headers, params, query, body }) => { - const handler = (req, res, next) => { - if (headers) { - const result = headers.safeParse(req.headers); - if (!result.success) { - res.status(400).send(parseError(result.error)); - return; - } - } - - if (params) { - const result = params.safeParse(req.params); - if (!result.success) { - res.status(400).send(parseError(result.error)); - return; - } - } - - if (query) { - const result = query.safeParse(req.query); - if (!result.success) { - res.status(400).send(parseError(result.error)); - return; - } - } - - if (body) { - const result = body.safeParse(req.body); - if (!result.success) { - res.status(400).send(parseError(result.error)); - return; - } - } - - next(); - } - - return handler - } -} \ No newline at end of file