UNPKG

supertokens-node

Version:
184 lines (183 loc) 8.44 kB
"use strict"; /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * * This software is licensed under the Apache License, Version 2.0 (the * "License") as published by the Apache Software Foundation. * * You may not use this file except in compliance with the License. You may * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); const types_1 = require("./types"); const cookieAndHeaders_1 = require("./cookieAndHeaders"); const url_1 = require("url"); const middleware_1 = require("./api/middleware"); const constants_1 = require("./constants"); const normalisedURLPath_1 = require("../../normalisedURLPath"); const psl = require("psl"); const utils_1 = require("../../utils"); function normaliseSessionScopeOrThrowError(sessionScope) { function helper(sessionScope) { sessionScope = sessionScope.trim().toLowerCase(); // first we convert it to a URL so that we can use the URL class if (sessionScope.startsWith(".")) { sessionScope = sessionScope.substr(1); } if (!sessionScope.startsWith("http://") && !sessionScope.startsWith("https://")) { sessionScope = "http://" + sessionScope; } try { let urlObj = new url_1.URL(sessionScope); sessionScope = urlObj.hostname; // remove leading dot if (sessionScope.startsWith(".")) { sessionScope = sessionScope.substr(1); } return sessionScope; } catch (err) { throw new Error("Please provide a valid sessionScope"); } } let noDotNormalised = helper(sessionScope); if (noDotNormalised === "localhost" || utils_1.isAnIpAddress(noDotNormalised)) { return noDotNormalised; } if (sessionScope.startsWith(".")) { return "." + noDotNormalised; } return noDotNormalised; } exports.normaliseSessionScopeOrThrowError = normaliseSessionScopeOrThrowError; function getTopLevelDomainForSameSiteResolution(url) { let urlObj = new url_1.URL(url); let hostname = urlObj.hostname; if (hostname.startsWith("localhost") || hostname.startsWith("localhost.org") || utils_1.isAnIpAddress(hostname)) { // we treat these as the same TLDs since we can use sameSite lax for all of them. return "localhost"; } let parsedURL = psl.parse(hostname); if (parsedURL.domain === null) { throw new Error("Please make sure that the apiDomain and websiteDomain have correct values"); } return parsedURL.domain; } exports.getTopLevelDomainForSameSiteResolution = getTopLevelDomainForSameSiteResolution; function validateAndNormaliseUserInput(recipeInstance, appInfo, config) { utils_1.validateTheStructureOfUserInput(config, types_1.InputSchema, "session recipe"); let cookieDomain = config === undefined || config.cookieDomain === undefined ? undefined : normaliseSessionScopeOrThrowError(config.cookieDomain); let topLevelAPIDomain = getTopLevelDomainForSameSiteResolution(appInfo.apiDomain.getAsStringDangerous()); let topLevelWebsiteDomain = getTopLevelDomainForSameSiteResolution(appInfo.websiteDomain.getAsStringDangerous()); let cookieSameSite = topLevelAPIDomain !== topLevelWebsiteDomain ? "none" : "lax"; cookieSameSite = config === undefined || config.cookieSameSite === undefined ? cookieSameSite : normaliseSameSiteOrThrowError(config.cookieSameSite); let cookieSecure = config === undefined || config.cookieSecure === undefined ? appInfo.apiDomain.getAsStringDangerous().startsWith("https") : config.cookieSecure; let sessionExpiredStatusCode = config === undefined || config.sessionExpiredStatusCode === undefined ? 401 : config.sessionExpiredStatusCode; if (config !== undefined && config.antiCsrf !== undefined) { if (config.antiCsrf !== "NONE" && config.antiCsrf !== "VIA_CUSTOM_HEADER" && config.antiCsrf !== "VIA_TOKEN") { throw new Error("antiCsrf config must be one of 'NONE' or 'VIA_CUSTOM_HEADER' or 'VIA_TOKEN'"); } } let antiCsrf = config === undefined || config.antiCsrf === undefined ? cookieSameSite === "none" ? "VIA_CUSTOM_HEADER" : "NONE" : config.antiCsrf; let errorHandlers = { onTokenTheftDetected: (sessionHandle, userId, request, response, next) => { return middleware_1.sendTokenTheftDetectedResponse( recipeInstance, sessionHandle, userId, request, response, next ); }, onTryRefreshToken: (message, request, response, next) => { return middleware_1.sendTryRefreshTokenResponse(recipeInstance, message, request, response, next); }, onUnauthorised: (message, request, response, next) => { return middleware_1.sendUnauthorisedResponse(recipeInstance, message, request, response, next); }, }; if (config !== undefined && config.errorHandlers !== undefined) { if (config.errorHandlers.onTokenTheftDetected !== undefined) { errorHandlers.onTokenTheftDetected = config.errorHandlers.onTokenTheftDetected; } if (config.errorHandlers.onUnauthorised !== undefined) { errorHandlers.onUnauthorised = config.errorHandlers.onUnauthorised; } } if ( cookieSameSite === "none" && !cookieSecure && !(topLevelAPIDomain === "localhost" || utils_1.isAnIpAddress(topLevelAPIDomain)) && !(topLevelWebsiteDomain === "localhost" || utils_1.isAnIpAddress(topLevelWebsiteDomain)) ) { throw new Error( "Since your API and website domain are different, for sessions to work, please use https on your apiDomain and dont set cookieSecure to false." ); } let override = Object.assign( { functions: (originalImplementation) => originalImplementation, apis: (originalImplementation) => originalImplementation, }, config === null || config === void 0 ? void 0 : config.override ); return { refreshTokenPath: appInfo.apiBasePath.appendPath(new normalisedURLPath_1.default(constants_1.REFRESH_API_PATH)), cookieDomain, cookieSameSite, cookieSecure, sessionExpiredStatusCode, errorHandlers, antiCsrf, override, }; } exports.validateAndNormaliseUserInput = validateAndNormaliseUserInput; function normaliseSameSiteOrThrowError(sameSite) { sameSite = sameSite.trim(); sameSite = sameSite.toLocaleLowerCase(); if (sameSite !== "strict" && sameSite !== "lax" && sameSite !== "none") { throw new Error('cookie same site must be one of "strict", "lax", or "none"'); } return sameSite; } exports.normaliseSameSiteOrThrowError = normaliseSameSiteOrThrowError; function attachCreateOrRefreshSessionResponseToExpressRes(config, res, response) { let accessToken = response.accessToken; let refreshToken = response.refreshToken; let idRefreshToken = response.idRefreshToken; cookieAndHeaders_1.setFrontTokenInHeaders( res, response.session.userId, response.accessToken.expiry, response.session.userDataInJWT ); cookieAndHeaders_1.attachAccessTokenToCookie(config, res, accessToken.token, accessToken.expiry); cookieAndHeaders_1.attachRefreshTokenToCookie(config, res, refreshToken.token, refreshToken.expiry); cookieAndHeaders_1.setIdRefreshTokenInHeaderAndCookie(config, res, idRefreshToken.token, idRefreshToken.expiry); if (response.antiCsrfToken !== undefined) { cookieAndHeaders_1.setAntiCsrfTokenInHeaders(res, response.antiCsrfToken); } } exports.attachCreateOrRefreshSessionResponseToExpressRes = attachCreateOrRefreshSessionResponseToExpressRes; //# sourceMappingURL=utils.js.map