UNPKG

@opengis/fastify-table

Version:

core-plugins

137 lines (136 loc) 5.81 kB
import { existsSync } from "node:fs"; import cookie from "@fastify/cookie"; import session from "@fastify/session"; import { Authenticator } from "@fastify/passport"; import RedisStore from "fastify-session-redis-store"; import config from "../../../config.js"; import getRedis from "../redis/funcs/getRedis.js"; const fastifyPassport = new Authenticator(); const { prefix = "/api" } = config; export async function onRequest(req, reply) { const { hostname, headers, routeOptions } = req; const { config: routeConfig, method, handler, url } = routeOptions || {}; const { policy } = routeConfig || {}; const isApi = method && url && typeof handler === "function" && url !== "*"; // handle non-api at vite/vike if (!isApi) { return null; } // proxy from old apps to editor, bi etc. const validToken = (req.ip === "193.239.152.181" || req.ip === "127.0.0.1" || req.ip?.startsWith?.("192.168.") || config.debug) && req.headers?.token && config.auth?.tokens?.includes?.(headers.token); if (validToken && !req?.user?.uid) { req.user = { uid: req.headers?.uid?.toString?.(), user_type: req.headers?.user_type?.toString?.() || "regular", }; } const isAdmin = process.env.NODE_ENV === "admin" || hostname?.split?.(":")?.shift?.() === config.adminDomain || config.admin || hostname?.startsWith?.("admin"); const isPublic = Array.isArray(policy) ? policy.includes("public") : policy === "L0"; if (req.cookies?.["session_auth"] && !req.session?.passport?.user?.uid && (config.auth?.disable || config.auth?.user)) { req.session = req.session || {}; req.session.passport = req.session.passport || {}; // ensure passport session exists req.session.passport.user = { ...(config.auth?.user || {}), uid: config.auth?.user?.uid?.toString?.() || "1", user_rnokpp: config.auth?.user?.rnokpp, user_type: config.auth?.user?.type || "regular", }; req.user = req.session.passport.user; } // ! intentional: null || undefined > undefined req.user = req.user || req.session?.passport?.user || undefined; // fix for user.uid errors, by default user is null, while with express passport it was {}, unauthorized user does not trigger serializer // currently 2factor + auth with passwd file not supported const ispasswd = (existsSync("passwd") && !config.auth?.["2factor"]) || config.auth?.passwd; const loginPageUrl = config.auth?.link?.core?.login || config?.auth?.redirect || "/login"; if (!req.user?.uid && !config.auth?.disable && isAdmin && !isPublic && !config.auth?.disableRedirect && !req.url.startsWith(prefix) && !req.url.startsWith("/api") && !req.url.includes(loginPageUrl) && !req.url.includes(".") && !req.url.includes("@")) { if (isApi) { return reply.status(401).send({ error: "unauthorized", code: 401 }); } return reply.redirect(`${loginPageUrl}` + `?redirect=${req.url}`); } // by default, disable 2factor for id.gov.ua auth const check = req.user?.auth_type === "govid" ? config.auth?.["2factor"]?.govid : true; const login2faPage = config.auth?.link?.["2fa"]?.login || "/2factor"; // example: 2factor for admin env only, while public env does not require it const checkEnv = () => { if (!config.auth?.["2factorEnv"]) return true; if ((config.auth?.["2factorEnv"] && process.env.NODE_ENV === config.auth?.["2factorEnv"]) || (config.auth?.["2factorEnv"] === "admin" && isAdmin)) { return true; } return false; }; // if 2factor is enabled globally + for user and secondFactorPassed not true => redirect to 2factor login page if (req.user?.uid && req.user?.twofa && // config.auth?.["2factor"] && // !isPublic && (routeOptions?.method || "GET") === "GET" && !req.session?.secondFactorPassed && !ispasswd && !config.auth?.disableRedirect && !config.auth?.disable && check && checkEnv() && !req.url.startsWith(login2faPage) && !routeOptions.url?.includes?.("/logout") && !routeOptions.url?.includes?.("/2fa") && !routeOptions.url?.includes?.("/assets")) { if (isApi) { return reply .status(403) .send({ error: "access restricted: twofa", code: 403 }); } return reply.redirect(login2faPage); } return null; } function plugin(fastify) { if (!config.redis) { return; } fastify.register(cookie, { parseOptions: config?.auth?.cookieOptions || { secure: false }, }); fastify.register(session, { secret: config?.auth?.secret || "61b820e12858570a4b0633020d4394a17903d9a9", cookieName: "session_auth", cookie: config?.auth?.cookieOptions || { secure: false }, store: new RedisStore({ prefix: `session_auth:${config.pg?.database || "db"}:`, client: getRedis({ db: 2 }), }), }); // register passport AFTER session is ready fastify.register(fastifyPassport.initialize()); fastify.register(fastifyPassport.secureSession()); // serialize user used to store user info in session store fastifyPassport.registerUserSerializer(async (user) => ({ user })); // deserialize user used to add user info from session store to req fastifyPassport.registerUserDeserializer(async (passport) => passport?.user || passport); fastify.addHook("onRequest", onRequest); } export default plugin;