From 105d661261debcff100a9c1c867e6af2572022ba Mon Sep 17 00:00:00 2001 From: Ori Date: Tue, 15 Nov 2022 11:58:36 -0800 Subject: [PATCH 1/5] modify context configuration added --- lib/pxconfig.js | 12 ++++++++---- lib/pxenforcer.js | 12 ++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/pxconfig.js b/lib/pxconfig.js index 3939203..45c3da0 100644 --- a/lib/pxconfig.js +++ b/lib/pxconfig.js @@ -89,7 +89,8 @@ class PxConfig { ['LOGIN_SUCCESSFUL_HEADER_VALUE', 'px_login_successful_header_value'], ['LOGIN_SUCCESSFUL_STATUS', 'px_login_successful_status'], ['LOGIN_SUCCESSFUL_BODY_REGEX', 'px_login_successful_body_regex'], - ['LOGIN_SUCCESSFUL_CUSTOM_CALLBACK', 'px_login_successful_custom_callback'] + ['LOGIN_SUCCESSFUL_CUSTOM_CALLBACK', 'px_login_successful_custom_callback'], + ['MODIFY_CONTEXT', 'px_modify_context'], ]; configKeyMapping.forEach(([targetKey, sourceKey]) => { @@ -161,7 +162,8 @@ class PxConfig { userInput === 'px_additional_activity_handler' || userInput === 'px_custom_request_handler' || userInput === 'px_enrich_custom_parameters' || - userInput === 'px_login_successful_custom_callback' + userInput === 'px_login_successful_custom_callback' || + userInput === 'px_modify_context' ) { if (typeof params[userInput] === 'function') { return params[userInput]; @@ -331,7 +333,8 @@ function pxDefaultConfig() { LOGIN_SUCCESSFUL_HEADER_VALUE: '', LOGIN_SUCCESSFUL_STATUS: 200, LOGIN_SUCCESSFUL_BODY_REGEX: '', - LOGIN_SUCCESSFUL_CUSTOM_CALLBACK: null + LOGIN_SUCCESSFUL_CUSTOM_CALLBACK: null, + MODIFY_CONTEXT: null, }; } @@ -391,7 +394,8 @@ const allowedConfigKeys = [ 'px_login_successful_header_value', 'px_login_successful_status', 'px_login_successful_body_regex', - 'px_login_successful_custom_callback' + 'px_login_successful_custom_callback', + 'px_modify_context', ]; module.exports = PxConfig; diff --git a/lib/pxenforcer.js b/lib/pxenforcer.js index fb3b005..db8eeb4 100644 --- a/lib/pxenforcer.js +++ b/lib/pxenforcer.js @@ -112,8 +112,10 @@ class PxEnforcer { } const ctx = new PxContext(this._config, req, this._getAdditionalFields(req)); + this._tryModifyContext(ctx); req.locals = { ...req.locals, pxCtx: ctx }; + this.logger.debug('Request context created successfully'); ctx.collectorUrl = `https://collector-${this._config.PX_APP_ID}.perimeterx.net`; @@ -127,6 +129,16 @@ class PxEnforcer { } } + _tryModifyContext(ctx) { + if (this._config.MODIFY_CONTEXT && typeof this._config.MODIFY_CONTEXT === 'function') { + try { + this._config.MODIFY_CONTEXT(ctx); + } catch (e) { + this.logger.debug(`error modifying context: ${e}`); + } + } + } + _getAdditionalFields(req) { const additionalFields = {}; if (this.loginCredentialsExtractor) { From a6eb627149465fe582e212256310cd537bad5422 Mon Sep 17 00:00:00 2001 From: Ori Date: Tue, 15 Nov 2022 15:55:34 -0800 Subject: [PATCH 2/5] changelog + passing req --- CHANGELOG.md | 6 ++++++ lib/pxenforcer.js | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 317ae9e..ccf3fc9 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](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [3.6.0] - 2022-11-16 + +### Added + +- Support for `px_modify_context`, a custom function that allows more flexibility for changes to the request context + ## [3.5.0] - 2022-10-23 ### Added diff --git a/lib/pxenforcer.js b/lib/pxenforcer.js index db8eeb4..9133db9 100644 --- a/lib/pxenforcer.js +++ b/lib/pxenforcer.js @@ -112,7 +112,7 @@ class PxEnforcer { } const ctx = new PxContext(this._config, req, this._getAdditionalFields(req)); - this._tryModifyContext(ctx); + this._tryModifyContext(ctx, req); req.locals = { ...req.locals, pxCtx: ctx }; @@ -129,10 +129,10 @@ class PxEnforcer { } } - _tryModifyContext(ctx) { + _tryModifyContext(ctx, req) { if (this._config.MODIFY_CONTEXT && typeof this._config.MODIFY_CONTEXT === 'function') { try { - this._config.MODIFY_CONTEXT(ctx); + this._config.MODIFY_CONTEXT(ctx, req); } catch (e) { this.logger.debug(`error modifying context: ${e}`); } From 9e80a063e99fe1b4ea295c683163cab7b342912c Mon Sep 17 00:00:00 2001 From: Ori Date: Tue, 15 Nov 2022 16:09:23 -0800 Subject: [PATCH 3/5] lint fix --- lib/pxenforcer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pxenforcer.js b/lib/pxenforcer.js index 9133db9..93461c4 100644 --- a/lib/pxenforcer.js +++ b/lib/pxenforcer.js @@ -115,7 +115,6 @@ class PxEnforcer { this._tryModifyContext(ctx, req); req.locals = { ...req.locals, pxCtx: ctx }; - this.logger.debug('Request context created successfully'); ctx.collectorUrl = `https://collector-${this._config.PX_APP_ID}.perimeterx.net`; From 9bb1ada5f1340526ff3390a30766f0eef246e0a2 Mon Sep 17 00:00:00 2001 From: Ori Date: Wed, 16 Nov 2022 10:14:33 -0800 Subject: [PATCH 4/5] added unit tests --- test/pxenforcer.test.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/pxenforcer.test.js b/test/pxenforcer.test.js index 01700f1..bb5e103 100644 --- a/test/pxenforcer.test.js +++ b/test/pxenforcer.test.js @@ -842,6 +842,42 @@ describe('PX Enforcer - pxenforcer.js', () => { }); }) + it('Should call px_modify_context if set', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + return callback ? callback(null, data) : ''; + }); + + const modifyCtx = sinon.stub().callsFake((ctx) => ctx.sensitiveRoute = true); + const curParams = { + ...params, + px_modify_context: modifyCtx, + }; + + const pxenforcer = proxyquire('../lib/pxenforcer', { './pxlogger': logger }); + enforcer = new pxenforcer(curParams, pxClient); + enforcer.enforce(req, null, () => { + (modifyCtx.calledOnce).should.equal(true); + (req.locals.pxCtx.sensitiveRoute).should.equal(true); + done(); + }); + }); + + it('should not throw exception if there is an error in px_modify_context', () => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + return callback ? callback(null, data) : ''; + }); + + const curParams = { + ...params, + px_modify_context: sinon.stub().throws(), + }; + + const pxenforcer = proxyquire('../lib/pxenforcer', { './pxlogger': logger }); + enforcer = new pxenforcer(curParams, pxClient); + const enforceFunc = enforcer.enforce.bind(enforcer, req, null, () => {}); + (enforceFunc).should.not.throw(); + }); + it('Should add Nonce to CSP header (script-src directive exists)', (done) => { const nonce = 'ImN0nc3Value'; const headerWithoutNonce = 'connect-src \'self\' *.bazaarvoice.com *.google.com *.googleapis.com *.perimeterx.net *.px-cdn.net *.px-client.net; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\' *.bazaarvoice.com *.forter.com *.google-analytics.com report-uri https://csp.px-cloud.net/report?report=1&id=8a3a7c5242c0e7646bd7d86284f408f6&app_id=PXFF0j69T5&p=d767ae06-b964-4b42-96a2-6d4089aab525'; From 9f799ec25868f1dbf2fb23ac6bfe6eb9e0d110a7 Mon Sep 17 00:00:00 2001 From: Ori Date: Wed, 16 Nov 2022 10:22:07 -0800 Subject: [PATCH 5/5] release v3.6.0 --- CHANGELOG.md | 2 +- README.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccf3fc9..15ac9a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [3.6.0] - 2022-11-16 +## [3.6.0] - 2022-11-17 ### Added diff --git a/README.md b/README.md index be8faac..5e9567e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [PerimeterX](http://www.perimeterx.com) Shared base for NodeJS enforcers ============================================================= -> Latest stable version: [v3.5.0](https://www.npmjs.com/package/perimeterx-node-core) +> Latest stable version: [v3.6.0](https://www.npmjs.com/package/perimeterx-node-core) This is a shared base implementation for PerimeterX Express enforcer and future NodeJS enforcers. For a fully functioning implementation example, see the [Node-Express enforcer](https://github.com/PerimeterX/perimeterx-node-express/) implementation. diff --git a/package-lock.json b/package-lock.json index ee4921c..098c5bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "perimeterx-node-core", - "version": "3.4.3", + "version": "3.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "perimeterx-node-core", - "version": "3.4.3", + "version": "3.6.0", "license": "ISC", "dependencies": { "agent-phin": "^1.0.4", diff --git a/package.json b/package.json index 91ceff7..cb0dabe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "perimeterx-node-core", - "version": "3.5.0", + "version": "3.6.0", "description": "PerimeterX NodeJS shared core for various applications to monitor and block traffic according to PerimeterX risk score", "main": "index.js", "scripts": {