From c9e4154e2d76c61f7ed61e21b55d375912d481df Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Sat, 21 Oct 2023 19:38:01 +0200 Subject: [PATCH] fix: repeated headers/entries in access-control-expose-headers --- CHANGELOG.md | 6 + lib/build/framework/awsLambda/framework.js | 19 +++- lib/build/framework/custom/framework.js | 10 +- lib/build/framework/fastify/framework.js | 54 +++------ lib/build/framework/fastify/index.d.ts | 11 +- lib/build/framework/koa/framework.js | 10 +- lib/build/framework/utils.d.ts | 2 +- lib/build/framework/utils.js | 15 ++- lib/build/version.d.ts | 2 +- lib/build/version.js | 2 +- lib/ts/framework/awsLambda/framework.ts | 19 +++- lib/ts/framework/custom/framework.ts | 9 +- lib/ts/framework/fastify/framework.ts | 56 +++------- lib/ts/framework/koa/framework.ts | 10 +- lib/ts/framework/utils.ts | 15 ++- lib/ts/version.ts | 2 +- package-lock.json | 2 +- package.json | 2 +- test/framework/crossFramework.testgen.js | 19 +++- .../repeatedResponseHeader.test.js | 105 ++++++++++++++++++ test/framework/loopback-server/index.js | 20 ++++ test/framework/loopback-server/index.ts | 14 +++ 22 files changed, 297 insertions(+), 107 deletions(-) create mode 100644 test/framework/crossframework/repeatedResponseHeader.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 6317f6cf6..b9ee625bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) +## [16.3.4] - 2023-10-22 + +### Fixes + +- Fixes an issue where sometimes the `Access-Control-Expose-Headers` header value would contain duplicates + ## [16.3.3] - 2023-10-19 - Tests `null` values in `ProviderConfig` saved in core diff --git a/lib/build/framework/awsLambda/framework.js b/lib/build/framework/awsLambda/framework.js index c108e6bf1..993becc3e 100644 --- a/lib/build/framework/awsLambda/framework.js +++ b/lib/build/framework/awsLambda/framework.js @@ -142,7 +142,10 @@ class AWSResponse extends response_1.BaseResponse { path, sameSite ); - this.event.supertokens.response.cookies.push(serialisedCookie); + this.event.supertokens.response.cookies = [ + ...this.event.supertokens.response.cookies.filter((c) => !c.startsWith(key + "=")), + serialisedCookie, + ]; }; /** * @param {number} statusCode @@ -187,8 +190,18 @@ class AWSResponse extends response_1.BaseResponse { } } if (supertokensHeaders[i].allowDuplicateKey && currentValue !== undefined) { - let newValue = `${currentValue}, ${supertokensHeaders[i].value}`; - headers[supertokensHeaders[i].key] = newValue; + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if ( + typeof currentValue !== "string" || + !currentValue.includes(supertokensHeaders[i].value.toString()) + ) { + let newValue = `${currentValue}, ${supertokensHeaders[i].value}`; + headers[supertokensHeaders[i].key] = newValue; + } } else { headers[supertokensHeaders[i].key] = supertokensHeaders[i].value; } diff --git a/lib/build/framework/custom/framework.js b/lib/build/framework/custom/framework.js index 91f4ada97..b1a35d5b4 100644 --- a/lib/build/framework/custom/framework.js +++ b/lib/build/framework/custom/framework.js @@ -78,8 +78,16 @@ class CollectingResponse extends response_1.BaseResponse { this.body = html; }; this.setHeader = (key, value, allowDuplicateKey) => { + var _a; if (allowDuplicateKey) { - this.headers.append(key, value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (!((_a = this.headers.get(key)) === null || _a === void 0 ? void 0 : _a.includes(value))) { + this.headers.append(key, value); + } } else { this.headers.set(key, value); } diff --git a/lib/build/framework/fastify/framework.js b/lib/build/framework/fastify/framework.js index a3375a18c..f7099ee35 100644 --- a/lib/build/framework/fastify/framework.js +++ b/lib/build/framework/fastify/framework.js @@ -79,7 +79,14 @@ class FastifyResponse extends response_1.BaseResponse { if (existingValue === undefined) { this.response.header(key, value); } else if (allowDuplicateKey) { - this.response.header(key, existingValue + ", " + value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (typeof existingValue !== "string" || !existingValue.includes(value)) { + this.response.header(key, existingValue + ", " + value); + } } else { // we overwrite the current one with the new one this.response.header(key, value); @@ -102,43 +109,14 @@ class FastifyResponse extends response_1.BaseResponse { path, sameSite ); - /** - * lets say if current value is undefined, prev -> undefined - * - * now if add AT, - * cookieValueToSetInHeader -> AT - * response header object will be: - * - * 'set-cookie': AT - * - * now if add RT, - * - * prev -> AT - * cookieValueToSetInHeader -> AT + RT - * and response header object will be: - * - * 'set-cookie': AT + AT + RT - * - * now if add IRT, - * - * prev -> AT + AT + RT - * cookieValueToSetInHeader -> IRT + AT + AT + RT - * and response header object will be: - * - * 'set-cookie': AT + AT + RT + IRT + AT + AT + RT - * - * To avoid this, we no longer get and use the previous value - * - * Old code: - * - * let prev: string | string[] | undefined = this.response.getHeader(COOKIE_HEADER) as - * | string - * | string[] - * | undefined; - * let cookieValueToSetInHeader = getCookieValueToSetInHeader(prev, serialisedCookie, key); - * this.response.header(COOKIE_HEADER, cookieValueToSetInHeader); - */ - this.response.header(constants_1.COOKIE_HEADER, serialisedCookie); + let oldHeaders = this.response.getHeader(constants_1.COOKIE_HEADER); + if (oldHeaders === undefined) oldHeaders = []; + else if (!(oldHeaders instanceof Array)) oldHeaders = [oldHeaders]; + this.response.removeHeader(constants_1.COOKIE_HEADER); + this.response.header(constants_1.COOKIE_HEADER, [ + ...oldHeaders.filter((h) => !h.startsWith(key + "=")), + serialisedCookie, + ]); }; /** * @param {number} statusCode diff --git a/lib/build/framework/fastify/index.d.ts b/lib/build/framework/fastify/index.d.ts index 3cca3a1a2..fb2d3fe21 100644 --- a/lib/build/framework/fastify/index.d.ts +++ b/lib/build/framework/fastify/index.d.ts @@ -1,18 +1,21 @@ // @ts-nocheck /// export type { SessionRequest } from "./framework"; -export declare const plugin: import("fastify").FastifyPluginCallback, import("http").Server>; +export declare const plugin: import("fastify").FastifyPluginCallback< + Record, + import("fastify").RawServerDefault +>; export declare const errorHandler: () => ( err: any, req: import("fastify").FastifyRequest< import("fastify/types/route").RouteGenericInterface, - import("http").Server, + import("fastify").RawServerDefault, import("http").IncomingMessage >, res: import("fastify").FastifyReply< - import("http").Server, + import("fastify").RawServerDefault, import("http").IncomingMessage, - import("http").ServerResponse, + import("http").ServerResponse, import("fastify/types/route").RouteGenericInterface, unknown > diff --git a/lib/build/framework/koa/framework.js b/lib/build/framework/koa/framework.js index 5e45e9a6c..5bac1d858 100644 --- a/lib/build/framework/koa/framework.js +++ b/lib/build/framework/koa/framework.js @@ -88,7 +88,14 @@ class KoaResponse extends response_1.BaseResponse { if (existingValue === undefined) { this.ctx.set(key, value); } else if (allowDuplicateKey) { - this.ctx.set(key, existingValue + ", " + value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (typeof existingValue !== "string" || !existingValue.includes(value)) { + this.ctx.set(key, existingValue + ", " + value); + } } else { // we overwrite the current one with the new one this.ctx.set(key, value); @@ -108,6 +115,7 @@ class KoaResponse extends response_1.BaseResponse { expires: new Date(expires), domain, path, + overwrite: true, }); }; /** diff --git a/lib/build/framework/utils.d.ts b/lib/build/framework/utils.d.ts index 636a97724..123ddf23c 100644 --- a/lib/build/framework/utils.d.ts +++ b/lib/build/framework/utils.d.ts @@ -45,7 +45,7 @@ export declare function setCookieForServerResponse( expires: number, path: string, sameSite: "strict" | "lax" | "none" -): ServerResponse; +): ServerResponse; export declare function getCookieValueToSetInHeader( prev: string | string[] | undefined, val: string | string[], diff --git a/lib/build/framework/utils.js b/lib/build/framework/utils.js index 2e392b51c..76803c26c 100644 --- a/lib/build/framework/utils.js +++ b/lib/build/framework/utils.js @@ -217,10 +217,17 @@ function setHeaderForExpressLikeResponse(res, key, value, allowDuplicateKey) { res.setHeader(key, value); } } else if (allowDuplicateKey) { - if (res.header !== undefined) { - res.header(key, existingValue + ", " + value); - } else { - res.setHeader(key, existingValue + ", " + value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (typeof existingValue !== "string" || !existingValue.includes(value)) { + if (res.header !== undefined) { + res.header(key, existingValue + ", " + value); + } else { + res.setHeader(key, existingValue + ", " + value); + } } } else { // we overwrite the current one with the new one diff --git a/lib/build/version.d.ts b/lib/build/version.d.ts index 3f6fc2494..58a718bf4 100644 --- a/lib/build/version.d.ts +++ b/lib/build/version.d.ts @@ -1,4 +1,4 @@ // @ts-nocheck -export declare const version = "16.3.3"; +export declare const version = "16.3.4"; export declare const cdiSupported: string[]; export declare const dashboardVersion = "0.8"; diff --git a/lib/build/version.js b/lib/build/version.js index e39a8886d..1a39a60ae 100644 --- a/lib/build/version.js +++ b/lib/build/version.js @@ -15,7 +15,7 @@ exports.dashboardVersion = exports.cdiSupported = exports.version = void 0; * License for the specific language governing permissions and limitations * under the License. */ -exports.version = "16.3.3"; +exports.version = "16.3.4"; exports.cdiSupported = ["4.0"]; // Note: The actual script import for dashboard uses v{DASHBOARD_VERSION} exports.dashboardVersion = "0.8"; diff --git a/lib/ts/framework/awsLambda/framework.ts b/lib/ts/framework/awsLambda/framework.ts index bc01b76cb..eaf9b5167 100644 --- a/lib/ts/framework/awsLambda/framework.ts +++ b/lib/ts/framework/awsLambda/framework.ts @@ -213,7 +213,10 @@ export class AWSResponse extends BaseResponse { sameSite: "strict" | "lax" | "none" ) => { let serialisedCookie = serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite); - this.event.supertokens.response.cookies.push(serialisedCookie); + this.event.supertokens.response.cookies = [ + ...this.event.supertokens.response.cookies.filter((c) => !c.startsWith(key + "=")), + serialisedCookie, + ]; }; /** @@ -265,8 +268,18 @@ export class AWSResponse extends BaseResponse { } } if (supertokensHeaders[i].allowDuplicateKey && currentValue !== undefined) { - let newValue = `${currentValue}, ${supertokensHeaders[i].value}`; - headers[supertokensHeaders[i].key] = newValue; + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if ( + typeof currentValue !== "string" || + !currentValue.includes(supertokensHeaders[i].value.toString()) + ) { + let newValue = `${currentValue}, ${supertokensHeaders[i].value}`; + headers[supertokensHeaders[i].key] = newValue; + } } else { headers[supertokensHeaders[i].key] = supertokensHeaders[i].value; } diff --git a/lib/ts/framework/custom/framework.ts b/lib/ts/framework/custom/framework.ts index 14b48dfa1..8dd2141d4 100644 --- a/lib/ts/framework/custom/framework.ts +++ b/lib/ts/framework/custom/framework.ts @@ -118,7 +118,14 @@ export class CollectingResponse extends BaseResponse { setHeader = (key: string, value: string, allowDuplicateKey: boolean) => { if (allowDuplicateKey) { - this.headers.append(key, value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (!this.headers.get(key)?.includes(value)) { + this.headers.append(key, value); + } } else { this.headers.set(key, value); } diff --git a/lib/ts/framework/fastify/framework.ts b/lib/ts/framework/fastify/framework.ts index b2f5e1554..91bcd82ff 100644 --- a/lib/ts/framework/fastify/framework.ts +++ b/lib/ts/framework/fastify/framework.ts @@ -100,7 +100,14 @@ export class FastifyResponse extends BaseResponse { if (existingValue === undefined) { this.response.header(key, value); } else if (allowDuplicateKey) { - this.response.header(key, existingValue + ", " + value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (typeof existingValue !== "string" || !existingValue.includes(value)) { + this.response.header(key, existingValue + ", " + value); + } } else { // we overwrite the current one with the new one this.response.header(key, value); @@ -125,43 +132,16 @@ export class FastifyResponse extends BaseResponse { sameSite: "strict" | "lax" | "none" ) => { let serialisedCookie = serializeCookieValue(key, value, domain, secure, httpOnly, expires, path, sameSite); - /** - * lets say if current value is undefined, prev -> undefined - * - * now if add AT, - * cookieValueToSetInHeader -> AT - * response header object will be: - * - * 'set-cookie': AT - * - * now if add RT, - * - * prev -> AT - * cookieValueToSetInHeader -> AT + RT - * and response header object will be: - * - * 'set-cookie': AT + AT + RT - * - * now if add IRT, - * - * prev -> AT + AT + RT - * cookieValueToSetInHeader -> IRT + AT + AT + RT - * and response header object will be: - * - * 'set-cookie': AT + AT + RT + IRT + AT + AT + RT - * - * To avoid this, we no longer get and use the previous value - * - * Old code: - * - * let prev: string | string[] | undefined = this.response.getHeader(COOKIE_HEADER) as - * | string - * | string[] - * | undefined; - * let cookieValueToSetInHeader = getCookieValueToSetInHeader(prev, serialisedCookie, key); - * this.response.header(COOKIE_HEADER, cookieValueToSetInHeader); - */ - this.response.header(COOKIE_HEADER, serialisedCookie); + + let oldHeaders: string | string[] | undefined = this.response.getHeader(COOKIE_HEADER); + if (oldHeaders === undefined) oldHeaders = []; + else if (!((oldHeaders as any) instanceof Array)) oldHeaders = [oldHeaders]; + + this.response.removeHeader(COOKIE_HEADER); + this.response.header(COOKIE_HEADER, [ + ...(oldHeaders as string[]).filter((h) => !h.startsWith(key + "=")), + serialisedCookie, + ]); }; /** diff --git a/lib/ts/framework/koa/framework.ts b/lib/ts/framework/koa/framework.ts index e2dd68ff9..20cf3a82c 100644 --- a/lib/ts/framework/koa/framework.ts +++ b/lib/ts/framework/koa/framework.ts @@ -105,7 +105,14 @@ export class KoaResponse extends BaseResponse { if (existingValue === undefined) { this.ctx.set(key, value); } else if (allowDuplicateKey) { - this.ctx.set(key, existingValue + ", " + value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (typeof existingValue !== "string" || !existingValue.includes(value)) { + this.ctx.set(key, existingValue + ", " + value); + } } else { // we overwrite the current one with the new one this.ctx.set(key, value); @@ -136,6 +143,7 @@ export class KoaResponse extends BaseResponse { expires: new Date(expires), domain, path, + overwrite: true, }); }; diff --git a/lib/ts/framework/utils.ts b/lib/ts/framework/utils.ts index ffadd5294..12da0cbbe 100644 --- a/lib/ts/framework/utils.ts +++ b/lib/ts/framework/utils.ts @@ -237,10 +237,17 @@ export function setHeaderForExpressLikeResponse(res: Response, key: string, valu res.setHeader(key, value); } } else if (allowDuplicateKey) { - if (res.header !== undefined) { - res.header(key, existingValue + ", " + value); - } else { - res.setHeader(key, existingValue + ", " + value); + /** + We only want to append if it does not already exist + For example if the caller is trying to add front token to the access control exposed headers property + we do not want to append if something else had already added it + */ + if (typeof existingValue !== "string" || !existingValue.includes(value)) { + if (res.header !== undefined) { + res.header(key, existingValue + ", " + value); + } else { + res.setHeader(key, existingValue + ", " + value); + } } } else { // we overwrite the current one with the new one diff --git a/lib/ts/version.ts b/lib/ts/version.ts index 677bfe8b8..86c2c4b76 100644 --- a/lib/ts/version.ts +++ b/lib/ts/version.ts @@ -12,7 +12,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -export const version = "16.3.3"; +export const version = "16.3.4"; export const cdiSupported = ["4.0"]; diff --git a/package-lock.json b/package-lock.json index 763b33022..684022482 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "supertokens-node", - "version": "16.3.3", + "version": "16.3.4", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index d29de62e2..4227e3c5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "supertokens-node", - "version": "16.3.3", + "version": "16.3.4", "description": "NodeJS driver for SuperTokens core", "main": "index.js", "scripts": { diff --git a/test/framework/crossFramework.testgen.js b/test/framework/crossFramework.testgen.js index 451476b04..9bd3c2e0e 100644 --- a/test/framework/crossFramework.testgen.js +++ b/test/framework/crossFramework.testgen.js @@ -36,6 +36,11 @@ const loopbackRoutes = [ method: "post", verifySession: true, }, + { + path: "/session/multipleMerge", + method: "post", + verifySession: true, + }, { path: "/session/verify/optionalCSRF", method: "post", @@ -95,6 +100,7 @@ module.exports.addCrossFrameworkTests = (getTestCases, { allTokenTransferMethods route.handler( ExpressFramework.wrapRequest(req), ExpressFramework.wrapResponse(res), + req.session, next ), ]; @@ -181,6 +187,7 @@ module.exports.addCrossFrameworkTests = (getTestCases, { allTokenTransferMethods route.handler( FastifyFramework.wrapRequest(req), FastifyFramework.wrapResponse(res), + req.session, (err) => { throw err; } @@ -260,6 +267,7 @@ module.exports.addCrossFrameworkTests = (getTestCases, { allTokenTransferMethods await route.handler( HapiFramework.wrapRequest(req), HapiFramework.wrapResponse(res), + req.session, (err) => { throw err; } @@ -334,9 +342,14 @@ module.exports.addCrossFrameworkTests = (getTestCases, { allTokenTransferMethods for (const route of routes) { const handlers = [ (ctx) => - route.handler(KoaFramework.wrapRequest(ctx), KoaFramework.wrapResponse(ctx), (err) => { - throw err; - }), + route.handler( + KoaFramework.wrapRequest(ctx), + KoaFramework.wrapResponse(ctx), + ctx.session, + (err) => { + throw err; + } + ), ]; if (route.verifySession) { handlers.unshift(koaVerifySession(route.verifySessionOpts)); diff --git a/test/framework/crossframework/repeatedResponseHeader.test.js b/test/framework/crossframework/repeatedResponseHeader.test.js new file mode 100644 index 000000000..fa6702515 --- /dev/null +++ b/test/framework/crossframework/repeatedResponseHeader.test.js @@ -0,0 +1,105 @@ +const { addCrossFrameworkTests } = require("../crossFramework.testgen"); +let Session = require("../../../recipe/session"); +const { extractInfoFromResponse } = require("../../utils"); +let assert = require("assert"); +const SuperTokens = require("../../.."); + +addCrossFrameworkTests( + (setup, callServer, tokenTransferMethod) => { + describe("Updating token payload multiple times", () => { + it("should not repeat access token headers", async () => { + await setup({ + stConfig: { + appInfo: { + apiDomain: "http://api.supertokens.io", + appName: "SuperTokens", + websiteDomain: "http://supertokens.io", + apiBasePath: "/", + }, + recipeList: [Session.init()], + }, + routes: [ + { + path: "/create", + method: "post", + handler: async (req, res, next) => { + await Session.createNewSession( + req, + res, + "public", + SuperTokens.convertToRecipeUserId("id1"), + {}, + {} + ); + res.setStatusCode(200); + res.sendJSONResponse(""); + return res.response; + }, + }, + { + path: "/session/multipleMerge", + method: "post", + verifySession: true, + handler: async (req, res, session) => { + await session.mergeIntoAccessTokenPayload({ test1: Date.now() }); + await session.mergeIntoAccessTokenPayload({ test2: Date.now() }); + await session.mergeIntoAccessTokenPayload({ test3: Date.now() }); + res.setStatusCode(200); + res.sendJSONResponse(""); + }, + }, + ], + }); + + const createResp = await callServer({ + method: "post", + path: "/create", + headers: { + "st-auth-mode": tokenTransferMethod, + }, + }); + const info = extractInfoFromResponse(createResp); + + const verifyHeaders = + tokenTransferMethod === "header" + ? { authorization: `Bearer ${info.accessTokenFromAny}` } + : { + cookie: `sAccessToken=${encodeURIComponent(info.accessTokenFromAny)}`, + }; + if (info.antiCsrf) { + verifyHeaders.antiCsrf = info.antiCsrf; + } + + let resp = await callServer({ + method: "post", + path: "/session/multipleMerge", + headers: verifyHeaders, + }); + + const cookieHeader = resp.headers["set-cookie"]; + assert.strictEqual( + cookieHeader === undefined + ? 0 + : typeof cookieHeader == "string" + ? cookieHeader.startsWith("sAccessToken") + ? 1 + : 0 + : cookieHeader.filter((c) => c.startsWith("sAccessToken")).length ?? 0, + tokenTransferMethod === "cookie" ? 1 : 0 + ); + assert.strictEqual( + typeof resp.headers["st-access-token"], + tokenTransferMethod === "cookie" ? "undefined" : "string" + ); + assert.strictEqual(typeof resp.headers["front-token"], "string"); + const exposedHeaders = resp.headers["access-control-expose-headers"].split(" "); + assert.strictEqual(exposedHeaders.filter((c) => c.includes("front-token")).length, 1); + assert.strictEqual( + exposedHeaders.filter((c) => c.includes("st-access-token")).length, + tokenTransferMethod === "cookie" ? 0 : 1 + ); + }); + }); + }, + { allTokenTransferMethods: true } +); diff --git a/test/framework/loopback-server/index.js b/test/framework/loopback-server/index.js index 6b0761b28..d085b0831 100644 --- a/test/framework/loopback-server/index.js +++ b/test/framework/loopback-server/index.js @@ -87,6 +87,25 @@ __decorate( null ); Verify = __decorate([__param(0, core_1.inject(rest_1.RestBindings.Http.CONTEXT))], Verify); +let MultipleMerge = class MultipleMerge { + constructor(ctx) { + this.ctx = ctx; + } + async handler() { + const session = this.ctx.session; + await session.mergeIntoAccessTokenPayload({ test1: Date.now() }); + await session.mergeIntoAccessTokenPayload({ test2: Date.now() }); + await session.mergeIntoAccessTokenPayload({ test3: Date.now() }); + return ""; + } +}; +__decorate( + [rest_1.post("/session/multipleMerge"), core_1.intercept(loopback_2.verifySession()), rest_1.response(200)], + MultipleMerge.prototype, + "handler", + null +); +MultipleMerge = __decorate([__param(0, core_1.inject(rest_1.RestBindings.Http.CONTEXT))], MultipleMerge); let VerifyOptionalCSRF = class VerifyOptionalCSRF { constructor(ctx) { this.ctx = ctx; @@ -135,6 +154,7 @@ if (process.env.TEST_SKIP_MIDDLEWARE !== "true") { app.controller(Create); app.controller(CreateThrowing); app.controller(Verify); +app.controller(MultipleMerge); app.controller(Revoke); app.controller(VerifyOptionalCSRF); module.exports = app; diff --git a/test/framework/loopback-server/index.ts b/test/framework/loopback-server/index.ts index 01464483d..30309bacf 100644 --- a/test/framework/loopback-server/index.ts +++ b/test/framework/loopback-server/index.ts @@ -52,6 +52,19 @@ class Verify { }; } } +class MultipleMerge { + constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) {} + @post("/session/multipleMerge") + @intercept(verifySession()) + @response(200) + async handler() { + const session = (this.ctx as any).session as Session.SessionContainer; + await session.mergeIntoAccessTokenPayload({ test1: Date.now() }); + await session.mergeIntoAccessTokenPayload({ test2: Date.now() }); + await session.mergeIntoAccessTokenPayload({ test3: Date.now() }); + return ""; + } +} class VerifyOptionalCSRF { constructor(@inject(RestBindings.Http.CONTEXT) private ctx: MiddlewareContext) {} @@ -88,6 +101,7 @@ if (process.env.TEST_SKIP_MIDDLEWARE !== "true") { app.controller(Create); app.controller(CreateThrowing); app.controller(Verify); +app.controller(MultipleMerge); app.controller(Revoke); app.controller(VerifyOptionalCSRF); module.exports = app;