Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix session abandoned when accessing not found page #377

Merged
merged 5 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading