Skip to content

Commit

Permalink
Fix session abandoned when accessing not found page (#377)
Browse files Browse the repository at this point in the history
  • Loading branch information
frontegg-david authored Oct 28, 2024
1 parent 5066dec commit 3ca3e67
Show file tree
Hide file tree
Showing 9 changed files with 2,920 additions and 3,089 deletions.
230 changes: 0 additions & 230 deletions dangerfile.ts

This file was deleted.

28 changes: 15 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,20 @@
"update-version": "node scripts/update-entry.js"
},
"devDependencies": {
"@babel/cli": "^7.21.0 ",
"@babel/core": "^7.21.3",
"@babel/node": "^7.20.7",
"@babel/cli": "^7.25.9",
"@babel/core": "^7.25.9",
"@babel/node": "^7.25.9",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
"@babel/plugin-transform-object-assign": "^7.18.6",
"@babel/plugin-transform-react-constant-elements": "^7.21.3",
"@babel/plugin-transform-runtime": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@babel/register": "^7.21.0",
"@babel/plugin-transform-object-assign": "^7.25.9",
"@babel/plugin-transform-react-constant-elements": "^7.25.9",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/plugin-transform-runtime": "^7.25.9",
"@babel/preset-env": "^7.25.9",
"@babel/preset-react": "^7.25.9",
"@babel/preset-typescript": "^7.25.9",
"@babel/register": "^7.25.9",
"@playwright/test": "^1.48.1",
"@types/jest": "^29.5.0",
"@types/node": "^16.18.16",
Expand All @@ -48,9 +50,9 @@
"danger": "11.2.4",
"danger-plugin-yarn": "1.6.0",
"eslint": "^8.36.0",
"express": "^4.18.2",
"express": "^4.21.1",
"jest": "^29.3.1",
"lerna": "6.2.0",
"lerna": "8.1.8",
"pre-commit": "^1.2.2",
"prettier": "2.8.4",
"pretty-quick": "^3.1.3",
Expand All @@ -59,7 +61,7 @@
"tslib": "^2.3.0",
"tslint": "^6.1.3",
"typescript": "^4.9.4",
"webpack": "^5.76.2"
"webpack": "^5.95.0"
},
"nyc": {
"reporter": [
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/src/utils/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ export const FRONTEGG_AFTER_AUTH_REDIRECT_URL = 'FRONTEGG_AFTER_AUTH_REDIRECT_UR
*/
export const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
export const cookieContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;

export const FRONTEGG_FORWARDED_SESSION_KEY = '__frontegg_forwarded_session__';
18 changes: 18 additions & 0 deletions packages/nextjs/src/utils/cookies/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { COOKIE_MAX_LENGTH } from './constants';
import { chunkString } from '../common';
import config from '../../config';
import { CookieSerializeOptions, RequestType } from './types';
import { ServerResponse } from 'http';

/**
* Return a cookieName with index, used for divided cookies.
Expand Down Expand Up @@ -55,6 +56,23 @@ export const getCookieHeader = (request: RequestType): string => {
return cookieHeader;
};

/**
* Receive http response, and extract the set-cookie header.
* @return cookie as string if exists, else empty string
*
* @param {ResponseType} response - HTTP Response
*/
export const getSetCookieHeader = (response: ServerResponse): string => {
let cookieHeader = response.getHeader('set-cookie');
const cookies: string[] = [];
if (!Array.isArray(cookieHeader)) {
cookies.push(`${cookieHeader}`);
} else {
cookies.push(...cookieHeader);
}
return cookies.map((cookie) => cookie.split(';')[0]).join(';');
};

export const getRefreshTokenCookieNameVariants = () => {
if (config.rewriteCookieByAppId && config.appId) {
return [
Expand Down
47 changes: 46 additions & 1 deletion packages/nextjs/src/utils/cookies/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import cookieSerializer from './serializer';
import type { RequestCookie } from 'next/dist/server/web/spec-extension/cookies';
import config from '../../config';
import { CookieSerializeOptions, CreateCookieOptions, RemoveCookiesOptions, RequestType } from './types';
import { CookieSerializeOptions, CreateCookieOptions, RemoveCookiesOptions, RequestType, ResponseType } from './types';
import { COOKIE_MAX_LENGTH } from './constants';

import {
getCookieHeader,
getIndexedCookieName,
getRefreshTokenCookieNameVariants,
getSetCookieHeader,
splitValueToChunks,
} from './helpers';
import fronteggLogger from '../fronteggLogger';
Expand Down Expand Up @@ -147,6 +148,50 @@ class CookieManager {
return sessionCookies;
}

/**
* Loop over cookie headers, extract, parse cookies and merged divided cookies from redirected http response,
* @return full session cookie headers if exists, else return undefined
* @param {ResponseType} response - Outgoing HTTP response
*/
getSessionCookieFromRedirectedResponse(response?: ResponseType): string | undefined {
const logger = fronteggLogger.child({ tag: 'CookieManager.getSessionCookieFromRedirectedResponse' });
logger.info('Going to extract session from set-cookie header from response');

if (!response) {
logger.info(`'response' argument is null, Cookie header not found`);
return undefined;
}

logger.debug('Getting set-cookie header');
const cookieStr = getSetCookieHeader(response);

logger.debug('Parsing set-cookie header string');
const cookies = cookieSerializer.parse(cookieStr);

logger.debug('Loop over session set-cookie header');
let i = 1;
let sessionCookies = '';
let sessionCookieChunk: string | undefined = cookies[this.getCookieName()];
if (sessionCookieChunk === undefined) {
do {
sessionCookieChunk = cookies[getIndexedCookieName(i++)];
if (sessionCookieChunk) {
sessionCookies += sessionCookieChunk;
}
} while (sessionCookieChunk);
} else {
sessionCookies = sessionCookieChunk;
}

if (sessionCookies.length === 0) {
logger.info('Session set-cookie NOT found');
return undefined;
}

logger.info(`Session set-cookie found, (count: ${sessionCookies.length})`);
return sessionCookies;
}

parseCookieFromArray(cookies: RequestCookie[]): string | undefined {
const logger = fronteggLogger.child({ tag: 'CookieManager.parseCookieFromArray' });
const cookieChunks = cookies.filter((c) => c.name.includes(this.getCookieName()));
Expand Down
Loading

0 comments on commit 3ca3e67

Please sign in to comment.