From 4ebe4e6b1cd7e7f25a2f4141a23adef26bdc9808 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 16 Nov 2023 18:37:25 +0100 Subject: [PATCH] Fixes #26 - [Feature Request] Support of phasing out third-party cookies Added support for cookie attributes: Domain, Path, Max-Age, Partitioned. Signed-off-by: Simone Bordet --- cometd-nodejs-server.d.ts | 4 ++++ cometd-nodejs-server.js | 15 +++++++++++++++ package.json | 6 +++--- test/server.test.ts | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/cometd-nodejs-server.d.ts b/cometd-nodejs-server.d.ts index 1421656..d4d8be9 100644 --- a/cometd-nodejs-server.d.ts +++ b/cometd-nodejs-server.d.ts @@ -139,8 +139,12 @@ export interface Options { sweepPeriod?: number; timeout?: number; // HTTP options. + browserCookieDomain?: string; browserCookieHttpOnly?: boolean; + browserCookieMaxAge?: number; browserCookieName?: string; + browserCookiePartitioned?: boolean; + browserCookiePath?: string; browserCookieSameSite?: 'Strict' | 'Lax' | 'None'; browserCookieSecure?: boolean; duplicateMetaConnectHttpResponseCode?: number; diff --git a/cometd-nodejs-server.js b/cometd-nodejs-server.js index 48d92d7..4b558c8 100644 --- a/cometd-nodejs-server.js +++ b/cometd-nodejs-server.js @@ -358,6 +358,18 @@ module.exports = (() => { function _generateCookie(cookieName, cookieValue) { let result = cookieName + '=' + cookieValue; + const domain = _self.option('browserCookieDomain'); + if (domain) { + result += '; Domain=' + domain; + } + const path = _self.option('browserCookiePath'); + if (path) { + result += '; Path=' + path; + } + const maxAge = _self.option('browserCookieMaxAge'); + if (maxAge) { + result += '; Max-Age=' + maxAge; + } if (_self.option('browserCookieHttpOnly') === true) { result += '; HttpOnly'; } @@ -368,6 +380,9 @@ module.exports = (() => { if (sameSite) { result += '; SameSite=' + sameSite; } + if (_self.option('browserCookiePartitioned') === true) { + result += '; Partitioned'; + } return result; } diff --git a/package.json b/package.json index 05f1b67..de09331 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,12 @@ "test": "mocha --exit --require ts-node/register --extension ts" }, "devDependencies": { + "@types/mocha": ">=10.0.0", + "@types/node": ">=16.0.0", "cometd": "^7.0.6", "cometd-nodejs-client": "^1.4.0", "mocha": ">=10.2.0", - "typescript": ">=5.0.0", "ts-node": ">=10.9.0", - "@types/node": ">=16.0.0", - "@types/mocha": ">=10.0.0" + "typescript": ">=5.0.0" } } diff --git a/test/server.test.ts b/test/server.test.ts index eff3e9a..e6874de 100644 --- a/test/server.test.ts +++ b/test/server.test.ts @@ -730,6 +730,41 @@ describe('server', () => { '}]'); }); + it('supports Partitioned cookie attribute', done => { + _server.options.browserCookiePath = '/'; + _server.options.browserCookieSecure = true; + _server.options.browserCookiePartitioned = true; + + http.request(newRequest(), r => { + receiveResponse(r, replies => { + const reply = replies[0]; + assert.strictEqual(reply.successful, true); + const headers = r.headers; + for (let name in headers) { + if (headers.hasOwnProperty(name)) { + if (/^set-cookie$/i.test(name)) { + const values = headers[name] || []; + for (let i = 0; i < values.length; ++i) { + let value = values[i]; + if (value.indexOf('Partitioned') >= 0 && + value.indexOf('Path=/') >= 0 && + value.indexOf('Secure') >= 0) { + done(); + return; + } + } + } + } + } + done(new Error('missing Partitioned cookie attribute')); + }); + }).end('[{' + + '"channel": "/meta/handshake",' + + '"version": "1.0",' + + '"supportedConnectionTypes": ["long-polling"]' + + '}]'); + }); + it('resends messages when connection is broken', done => { const serverAck = require('../ack-extension'); _server.addExtension(new serverAck.AcknowledgedMessagesExtension());