diff --git a/app.js b/app.js index c7995842..d6efee3c 100644 --- a/app.js +++ b/app.js @@ -24,6 +24,7 @@ import { version } from "./version.js"; import * as databaseInitializer from "./helpers/initializer.database.js"; import debug from "debug"; import { apiGetHandler } from "./handlers/permissions.js"; +import { getSafeRedirectURL } from "./helpers/functions.authentication.js"; const debugApp = debug("lot-occupancy-system:app"); databaseInitializer.initializeDatabase(); const __dirname = "."; @@ -91,7 +92,8 @@ const sessionChecker = (request, response, next) => { if (request.session.user && request.cookies[sessionCookieName]) { return next(); } - return response.redirect(`${urlPrefix}/login?redirect=${request.originalUrl}`); + const redirectUrl = getSafeRedirectURL(request.originalUrl); + return response.redirect(`${urlPrefix}/login?redirect=${redirectUrl}`); }; app.use((request, response, next) => { response.locals.buildNumber = version; diff --git a/app.ts b/app.ts index 0e89064e..55b118b6 100644 --- a/app.ts +++ b/app.ts @@ -31,6 +31,7 @@ import * as databaseInitializer from "./helpers/initializer.database.js"; import debug from "debug"; import { apiGetHandler } from "./handlers/permissions.js"; +import { getSafeRedirectURL } from "./helpers/functions.authentication.js"; const debugApp = debug("lot-occupancy-system:app"); /* @@ -177,8 +178,10 @@ const sessionChecker = ( return next(); } + const redirectUrl = getSafeRedirectURL(request.originalUrl); + return response.redirect( - `${urlPrefix}/login?redirect=${request.originalUrl}` + `${urlPrefix}/login?redirect=${redirectUrl}` ); }; diff --git a/helpers/functions.authentication.d.ts b/helpers/functions.authentication.d.ts index 349dce34..4ac59785 100644 --- a/helpers/functions.authentication.d.ts +++ b/helpers/functions.authentication.d.ts @@ -1 +1,2 @@ export declare const authenticate: (userName: string, password: string) => Promise; +export declare const getSafeRedirectURL: (possibleRedirectURL?: string) => string; diff --git a/helpers/functions.authentication.js b/helpers/functions.authentication.js index 80ebeb32..713c92a4 100644 --- a/helpers/functions.authentication.js +++ b/helpers/functions.authentication.js @@ -24,3 +24,36 @@ export const authenticate = async (userName, password) => { } return await authenticateViaActiveDirectory(userName, password); }; +const safeRedirects = new Set([ + "/admin/cleanup", + "/admin/fees", + "/admin/occupancytypes", + "/admin/tables", + "/lotoccupancies", + "/lotoccupancies/new", + "/lots", + "/lots/new", + "/maps", + "/maps/new", + "/workorders", + "/workorders/new", + "/workorders/milestonecalendar", + "/workorders/outlook", + "/reports" +]); +export const getSafeRedirectURL = (possibleRedirectURL = "") => { + const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix"); + if (typeof possibleRedirectURL === "string") { + const urlToCheck = (possibleRedirectURL.startsWith(urlPrefix) + ? possibleRedirectURL.slice(urlPrefix.length) + : possibleRedirectURL).toLowerCase(); + if (safeRedirects.has(urlToCheck) || + /^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) || + /^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) || + /^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) || + /^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck)) { + return urlPrefix + urlToCheck; + } + } + return urlPrefix + "/dashboard"; +}; diff --git a/helpers/functions.authentication.ts b/helpers/functions.authentication.ts index 199c00a7..ee1136c7 100644 --- a/helpers/functions.authentication.ts +++ b/helpers/functions.authentication.ts @@ -41,3 +41,46 @@ export const authenticate = async ( return await authenticateViaActiveDirectory(userName, password); }; + + +const safeRedirects = new Set([ + "/admin/cleanup", + "/admin/fees", + "/admin/occupancytypes", + "/admin/tables", + "/lotoccupancies", + "/lotoccupancies/new", + "/lots", + "/lots/new", + "/maps", + "/maps/new", + "/workorders", + "/workorders/new", + "/workorders/milestonecalendar", + "/workorders/outlook", + "/reports" +]); + +export const getSafeRedirectURL = (possibleRedirectURL = "") => { + const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix"); + + if (typeof possibleRedirectURL === "string") { + const urlToCheck = ( + possibleRedirectURL.startsWith(urlPrefix) + ? possibleRedirectURL.slice(urlPrefix.length) + : possibleRedirectURL + ).toLowerCase(); + + if ( + safeRedirects.has(urlToCheck) || + /^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) || + /^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) || + /^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) || + /^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck) + ) { + return urlPrefix + urlToCheck; + } + } + + return urlPrefix + "/dashboard"; +}; diff --git a/routes/login.js b/routes/login.js index 7ba77d3f..c690c7cb 100644 --- a/routes/login.js +++ b/routes/login.js @@ -6,42 +6,12 @@ import { getApiKey } from "../helpers/functions.api.js"; import Debug from "debug"; const debug = Debug("lot-occupancy-system:login"); export const router = Router(); -const safeRedirects = new Set([ - "/admin/fees", - "/admin/occupancytypes", - "/admin/tables", - "/lotoccupancies", - "/lotoccupancies/new", - "/lots", - "/lots/new", - "/maps", - "/maps/new", - "/workorders", - "/workorders/new", - "/reports" -]); -const getSafeRedirectURL = (possibleRedirectURL = "") => { - const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix"); - if (typeof possibleRedirectURL === "string") { - const urlToCheck = (possibleRedirectURL.startsWith(urlPrefix) - ? possibleRedirectURL.slice(urlPrefix.length) - : possibleRedirectURL).toLowerCase(); - if (safeRedirects.has(urlToCheck) || - /^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) || - /^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) || - /^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) || - /^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck)) { - return urlPrefix + urlToCheck; - } - } - return urlPrefix + "/dashboard"; -}; router .route("/") .get((request, response) => { const sessionCookieName = configFunctions.getProperty("session.cookieName"); if (request.session.user && request.cookies[sessionCookieName]) { - const redirectURL = getSafeRedirectURL((request.query.redirect || "")); + const redirectURL = authenticationFunctions.getSafeRedirectURL((request.query.redirect || "")); response.redirect(redirectURL); } else { @@ -57,7 +27,7 @@ router const userName = request.body.userName; const passwordPlain = request.body.password; const unsafeRedirectURL = request.body.redirect; - const redirectURL = getSafeRedirectURL(typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : ""); + const redirectURL = authenticationFunctions.getSafeRedirectURL(typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : ""); let isAuthenticated = false; if (userName.charAt(0) === "*") { if (useTestDatabases && userName === passwordPlain) { diff --git a/routes/login.ts b/routes/login.ts index e37b1dbc..e33436ce 100644 --- a/routes/login.ts +++ b/routes/login.ts @@ -16,45 +16,6 @@ const debug = Debug("lot-occupancy-system:login"); export const router = Router(); -const safeRedirects = new Set([ - "/admin/fees", - "/admin/occupancytypes", - "/admin/tables", - "/lotoccupancies", - "/lotoccupancies/new", - "/lots", - "/lots/new", - "/maps", - "/maps/new", - "/workorders", - "/workorders/new", - "/reports" -]); - -const getSafeRedirectURL = (possibleRedirectURL = "") => { - const urlPrefix = configFunctions.getProperty("reverseProxy.urlPrefix"); - - if (typeof possibleRedirectURL === "string") { - const urlToCheck = ( - possibleRedirectURL.startsWith(urlPrefix) - ? possibleRedirectURL.slice(urlPrefix.length) - : possibleRedirectURL - ).toLowerCase(); - - if ( - safeRedirects.has(urlToCheck) || - /^(\/maps\/)\d+(\/edit)?$/.test(urlToCheck) || - /^(\/lots\/)\d+(\/edit)?$/.test(urlToCheck) || - /^(\/lotoccupancies\/)\d+(\/edit)?$/.test(urlToCheck) || - /^(\/workorders\/)\d+(\/edit)?$/.test(urlToCheck) - ) { - return urlPrefix + urlToCheck; - } - } - - return urlPrefix + "/dashboard"; -}; - router .route("/") .get((request, response) => { @@ -62,7 +23,7 @@ router configFunctions.getProperty("session.cookieName"); if (request.session.user && request.cookies[sessionCookieName]) { - const redirectURL = getSafeRedirectURL( + const redirectURL = authenticationFunctions.getSafeRedirectURL( (request.query.redirect || "") as string ); @@ -82,7 +43,7 @@ router const unsafeRedirectURL = request.body.redirect; - const redirectURL = getSafeRedirectURL( + const redirectURL = authenticationFunctions.getSafeRedirectURL( typeof unsafeRedirectURL === "string" ? unsafeRedirectURL : "" );