diff --git a/CHANGELOG.md b/CHANGELOG.md index db5f9d35..1aec447c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ 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/). +## [2.4.0] - 2019-10-15 +### Added +- Send HTTP method on async activities +- Support for specific enforced routes and specific monitored routes + +### Fixed +- Upgraded dependency + ## [2.3.2] - 2019-10-02 ### Fixed - Upgraded dependency diff --git a/README.md b/README.md index 2e6158ea..19c4df4b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [PerimeterX](http://www.perimeterx.com) Shared base for NodeJS enforcers ============================================================= -> Latest stable version: [v2.3.2](https://www.npmjs.com/package/perimeterx-node-core) +> Latest stable version: [v2.4.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/lib/pxapi.js b/lib/pxapi.js index b07a85e0..0f24ed13 100644 --- a/lib/pxapi.js +++ b/lib/pxapi.js @@ -20,7 +20,7 @@ function callServer(ctx, config, callback) { const uri = ctx.uri || '/'; const headers = pxUtil.formatHeaders(ctx.headers, config.SENSITIVE_HEADERS); const httpVersion = ctx.httpVersion; - const riskMode = config.MODULE_MODE === config.MONITOR_MODE.MONITOR ? 'monitor' : 'active_blocking'; + const riskMode = (config.MODULE_MODE === config.MONITOR_MODE.MONITOR || ctx.monitoredRoute) ? 'monitor' : 'active_blocking'; const data = { request: { diff --git a/lib/pxclient.js b/lib/pxclient.js index 0c456026..1645d27f 100644 --- a/lib/pxclient.js +++ b/lib/pxclient.js @@ -26,6 +26,7 @@ class PxClient { details['cookie_origin'] = ctx.cookieOrigin; details['module_version'] = config.MODULE_VERSION; + details['http_method'] = ctx.httpMethod; if (ctx.blockAction && activityType === 'block') { details['block_action'] = ctx.blockAction; } diff --git a/lib/pxconfig.js b/lib/pxconfig.js index 988c36bc..673b15a5 100644 --- a/lib/pxconfig.js +++ b/lib/pxconfig.js @@ -26,12 +26,12 @@ class PxConfig { mergeParams(params) { params = this.mergeConfigFileParams(params); - - const configKeyMapping = [['ENABLE_MODULE', 'enableModule'], ['PX_APP_ID', 'pxAppId'], ['COOKIE_SECRET_KEY', 'cookieSecretKey'], ['AUTH_TOKEN', 'authToken'], ['PROXY_URL', 'proxy'], - ['API_TIMEOUT_MS', 'apiTimeoutMS'], ['CUSTOM_REQUEST_HANDLER', 'customRequestHandler'], ['GET_USER_IP', 'getUserIp'], ['BLOCKING_SCORE', 'blockingScore'], ['IP_HEADERS', 'ipHeaders'], - ['SEND_PAGE_ACTIVITIES', 'sendPageActivities'], ['SENSITIVE_HEADERS', 'sensitiveHeaders'], ['DEBUG_MODE', 'debugMode'], ['MAX_BUFFER_LEN', 'maxBufferLength'], ['JS_REF', 'jsRef'], - ['CSS_REF', 'cssRef'], ['CUSTOM_LOGO', 'customLogo'], ['SENSITIVE_ROUTES', 'sensitiveRoutes'], ['WHITELIST_ROUTES', 'whitelistRoutes'], ['DYNAMIC_CONFIGURATIONS', 'dynamicConfigurations'], - ['MODULE_MODE', 'moduleMode'], ['FIRST_PARTY_ENABLED', 'firstPartyEnabled'], ['ADDITIONAL_ACTIVITY_HANDLER', 'additionalActivityHandler'], ['ENRICH_CUSTOM_PARAMETERS', 'enrichCustomParameters'], + + const configKeyMapping = [['ENABLE_MODULE', 'enableModule'], ['PX_APP_ID', 'pxAppId'], ['COOKIE_SECRET_KEY', 'cookieSecretKey'], ['AUTH_TOKEN', 'authToken'], ['PROXY_URL', 'proxy'], + ['API_TIMEOUT_MS', 'apiTimeoutMS'], ['CUSTOM_REQUEST_HANDLER', 'customRequestHandler'], ['GET_USER_IP', 'getUserIp'], ['BLOCKING_SCORE', 'blockingScore'], ['IP_HEADERS', 'ipHeaders'], + ['SEND_PAGE_ACTIVITIES', 'sendPageActivities'], ['SENSITIVE_HEADERS', 'sensitiveHeaders'], ['DEBUG_MODE', 'debugMode'], ['MAX_BUFFER_LEN', 'maxBufferLength'], ['JS_REF', 'jsRef'], + ['CSS_REF', 'cssRef'], ['CUSTOM_LOGO', 'customLogo'], ['SENSITIVE_ROUTES', 'sensitiveRoutes'], ['WHITELIST_ROUTES', 'whitelistRoutes'], ['ENFORCED_ROUTES', 'enforcedRoutes'], ['MONITORED_ROUTES', 'monitoredRoutes'], ['DYNAMIC_CONFIGURATIONS', 'dynamicConfigurations'], + ['MODULE_MODE', 'moduleMode'], ['FIRST_PARTY_ENABLED', 'firstPartyEnabled'], ['ADDITIONAL_ACTIVITY_HANDLER', 'additionalActivityHandler'], ['ENRICH_CUSTOM_PARAMETERS', 'enrichCustomParameters'], ['TESTING_MODE', 'testingMode'], ['WHITELIST_EXT', 'whitelistExt'], ['BYPASS_MONITOR_HEADER', 'bypassMonitorHeader'], ['ADVANCED_BLOCKING_RESPONSE', 'advancedBlockingResponse'], ['TELEMETRY_COMMAND_HEADER', 'telemetryCommandHeader'], ['CUSTOM_TEMPLATE_ROOT', 'customTemplateRoot'], ['CUSTOM_TEMPLATE_DATA', 'customTemplateData']]; @@ -128,9 +128,9 @@ function pxInternalConfig() { CE_ITERATIONS: 1000, CE_DIGEST: 'sha256', CE_ALGO: 'aes-256-cbc', - + STATIC_FILES_EXT: ['.css', '.bmp', '.tif', '.ttf', '.docx', '.woff2', '.js', '.pict', '.tiff', '.eot', '.xlsx', '.jpg', '.csv', '.eps', '.woff', '.xls', '.jpeg', '.doc', '.ejs', '.otf', '.pptx', '.gif', '.pdf', '.swf', '.svg', '.ps', '.ico', '.pls', '.midi', '.svgz', '.class', '.png', '.ppt', '.mid', 'webp', '.jar'], - + /* actions */ SCORE_EVALUATE_ACTION: { SPECIAL_TOKEN: -6, @@ -139,7 +139,7 @@ function pxInternalConfig() { NO_COOKIE: -3, COOKIE_INVALID: -2, COOKIE_EXPIRED: -1, - + S2S_PASS_TRAFFIC: 11, COOKIE_PASS_TRAFFIC: 10, S2S_TIMEOUT_PASS: 9, @@ -147,14 +147,14 @@ function pxInternalConfig() { S2S_BLOCK_TRAFFIC: -11, CAPTCHA_BLOCK_TRAFFIC: -12, CHALLENGE_BLOCK_TRAFFIC: -13, - + CAPTCHA_PASS: 0, CAPTCHA_BLOCK: 1, - + GOOD_SCORE: 1, BAD_SCORE: 0 }, - + PASS_REASON: { CAPTCHA_TIMEOUT: 'captcha_timeout', CAPTCHA: 'captcha', @@ -165,7 +165,7 @@ function pxInternalConfig() { INVALID_RESPONSE: 'invalid_response', REQUEST_FAILED: 'request_failed' }, - + MONITOR_MODE: { MONITOR: 0, BLOCK: 1 @@ -197,6 +197,8 @@ function pxDefaultConfig(PX_INTERNAL) { LOGO_VISIBILITY: 'hidden', SENSITIVE_ROUTES: [], WHITELIST_ROUTES: [], + MONITORED_ROUTES: [], + ENFORCED_ROUTES: [], DYNAMIC_CONFIGURATIONS: false, CONFIGURATION_LOAD_INTERVAL: 5000, MODULE_MODE: PX_INTERNAL.MONITOR_MODE.MONITOR, @@ -215,32 +217,32 @@ function pxDefaultConfig(PX_INTERNAL) { } const configSchemaMapper = { - px_enable_module: 'enableModule', - px_app_id: 'pxAppId', - px_cookie_secret: 'cookieSecretKey', - px_auth_token: 'authToken', - px_proxy_url: 'proxy', + px_enable_module: 'enableModule', + px_app_id: 'pxAppId', + px_cookie_secret: 'cookieSecretKey', + px_auth_token: 'authToken', + px_proxy_url: 'proxy', px_sync_request_timeout_ms: 'apiTimeoutMS', - px_custom_request_handler: 'customRequestHandler', - px_get_user_ip: 'getUserIp', - px_blocking_score: 'blockingScore', - px_ip_headers: 'ipHeaders', + px_custom_request_handler: 'customRequestHandler', + px_get_user_ip: 'getUserIp', + px_blocking_score: 'blockingScore', + px_ip_headers: 'ipHeaders', px_send_async_activities: 'sendPageActivities', - px_sensitive_headers: 'sensitiveHeaders', + px_sensitive_headers: 'sensitiveHeaders', px_debug_mode: 'debugMode', px_max_buffer_length: 'maxBufferLength', - px_js_ref: 'jsRef', - px_css_ref: 'cssRef', - px_custom_logo: 'customLogo', - px_sensitive_routes: 'sensitiveRoutes', - px_whitelist_uri_full: 'whitelistRoutes', - px_dynamic_configurations: 'dynamicConfigurations', - px_module_mode: 'moduleMode', - px_first_party_enabled: 'firstPartyEnabled', - px_additional_activity_handler: 'additionalActivityHandler', - px_enrich_custom_parameters: 'enrichCustomParameters', - px_test_mode: 'testingMode', - px_whitelist_extensions: 'whitelistExt', + px_js_ref: 'jsRef', + px_css_ref: 'cssRef', + px_custom_logo: 'customLogo', + px_sensitive_routes: 'sensitiveRoutes', + px_whitelist_uri_full: 'whitelistRoutes', + px_dynamic_configurations: 'dynamicConfigurations', + px_module_mode: 'moduleMode', + px_first_party_enabled: 'firstPartyEnabled', + px_additional_activity_handler: 'additionalActivityHandler', + px_enrich_custom_parameters: 'enrichCustomParameters', + px_test_mode: 'testingMode', + px_whitelist_extensions: 'whitelistExt', px_bypass_monitor_header: 'bypassMonitorHeader', px_advanced_blocking_response: 'advancedBlockingResponse', px_telemetry_command: 'telemetryCommandHeader' diff --git a/lib/pxcontext.js b/lib/pxcontext.js index 5b417bc3..c57dbebf 100644 --- a/lib/pxcontext.js +++ b/lib/pxcontext.js @@ -20,7 +20,9 @@ class PxContext { this.httpVersion = req.httpVersion || ''; this.httpMethod = req.method || ''; this.sensitiveRoute = this.isSpecialRoute(config.SENSITIVE_ROUTES, this.uri); + this.enforcedRoute = this.isSpecialRoute(config.ENFORCED_ROUTES, this.uri); this.whitelistRoute = this.isSpecialRoute(config.WHITELIST_ROUTES, this.uri); + this.monitoredRoute = !this.enforcedRoute && this.isSpecialRoute(config.MONITORED_ROUTES, this.uri); this.cookieOrigin = 'cookie'; const mobileHeader = this.headers[mobileSdkHeader]; if (mobileHeader !== undefined) { diff --git a/lib/pxenforcer.js b/lib/pxenforcer.js index 608e5ebb..5299cd0f 100644 --- a/lib/pxenforcer.js +++ b/lib/pxenforcer.js @@ -65,6 +65,7 @@ class PxEnforcer { try { const ctx = new PxContext(this._config, req, this.logger); + this.logger.debug('Request context created successfully'); ctx.collectorUrl = `https://collector-${this._config.PX_APP_ID}.perimeterx.net`; @@ -184,7 +185,7 @@ class PxEnforcer { // If verified, pass the request here const shouldBypassMonitor = this._config.BYPASS_MONITOR_HEADER && req.headers[this._config.BYPASS_MONITOR_HEADER] === '1'; - if (verified || (this._config.MODULE_MODE === this._config.MONITOR_MODE.MONITOR && !shouldBypassMonitor)) { + if (verified || ctx.monitoredRoute || (this._config.MODULE_MODE === this._config.MONITOR_MODE.MONITOR && !shouldBypassMonitor)) { return cb(); } @@ -273,7 +274,7 @@ class PxEnforcer { block_module: 'px-node-express', block_score: ctx.score, module_version: this.pxConfig.conf.MODULE_VERSION, - simulated_block: this._config.MODULE_MODE === this._config.MONITOR_MODE.MONITOR + simulated_block: this._config.MODULE_MODE === this._config.MONITOR_MODE.MONITOR || ctx.monitoredRoute }; this.logger.debug(`Sending block activity`); diff --git a/package-lock.json b/package-lock.json index b7015729..0e7f7b05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "perimeterx-node-core", - "version": "2.3.2", + "version": "2.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -463,6 +463,16 @@ "flat-cache": "^2.0.1" } }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -561,9 +571,9 @@ } }, "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.0.tgz", + "integrity": "sha512-y4jAxNEihqvBI5F3SaO2rtsjIOnnNA8sEbuiP+UhJZJHeM2NRm6c09ax2tgqme+SgUUvjao2fJXF4h3D6Cb2HQ==", "requires": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -656,6 +666,12 @@ "is-extglob": "^2.1.1" } }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -724,6 +740,12 @@ "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", "dev": true }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", @@ -813,6 +835,12 @@ } } }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -906,6 +934,12 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -927,6 +961,17 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "proxyquire": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", + "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.1", + "resolve": "^1.11.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -950,6 +995,15 @@ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", diff --git a/package.json b/package.json index 2d1b0f41..89d7e864 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "perimeterx-node-core", - "version": "2.3.2", + "version": "2.4.0", "description": "PerimeterX NodeJS shared core for various applications to monitor and block traffic according to PerimeterX risk score", "main": "index.js", "scripts": { @@ -21,7 +21,7 @@ "dependencies": { "agent-phin": "^1.0.4", "content-type": "^1.0.4", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^3.0.0", "mu2": "^0.5.21", "raw-body": "^2.3.2" }, @@ -29,6 +29,7 @@ "eslint": "^6.3.0", "eslint-config-perimeterx": "^0.3.0", "mocha": "^5.2.0", + "proxyquire": "^2.1.3", "rewire": "^2.5.2", "should": "^8.3.0", "sinon": "^2.1.0" diff --git a/test/pxenforcer.test.js b/test/pxenforcer.test.js index c739d106..547096db 100644 --- a/test/pxenforcer.test.js +++ b/test/pxenforcer.test.js @@ -7,9 +7,10 @@ const request = require('../lib/request'); const pxhttpc = require('../lib/pxhttpc'); const PxClient = rewire('../lib/pxclient'); const PxEnforcer = require('../lib/pxenforcer'); +const proxyquire = require('proxyquire'); describe('PX Enforcer - pxenforcer.js', () => { - let params, enforcer, req, stub, pxClient; + let params, enforcer, req, stub, pxClient, pxLoggerSpy, logger; beforeEach(() => { params = { @@ -37,6 +38,17 @@ describe('PX Enforcer - pxenforcer.js', () => { return req.headers[key] || ''; }; + pxLoggerSpy = { + debug: sinon.spy(), + error: sinon.spy(), + init: () => {}, + '@global': true + }; + + logger = function () { + return pxLoggerSpy; + }; + pxClient = new PxClient(); }); @@ -49,9 +61,15 @@ describe('PX Enforcer - pxenforcer.js', () => { return callback ? callback(null, data) : ''; }); params.enableModule = false; - enforcer = new PxEnforcer(params, pxClient); + const curParams = Object.assign({ + enableModule: false + }, params); + + const pxenforcer = proxyquire('../lib/pxenforcer', {'./pxlogger': logger}); + enforcer = new pxenforcer(curParams, pxClient); enforcer.enforce(req, null, (response) => { + pxLoggerSpy.debug.calledWith('Request will not be verified, module is disabled').should.equal(true); (response === undefined).should.equal(true); done(); }); @@ -74,7 +92,7 @@ describe('PX Enforcer - pxenforcer.js', () => { return callback ? callback(null, data) : ''; }); const reqStub = sinon.stub(request, 'get').callsFake((data, config, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body: 'hello buddy', proxy:''}); + callback(null, {headers: {'x-px-johnny': '1'}, body: 'hello buddy', proxy: ''}); }); req.originalUrl = '/_APP_ID/init.js'; enforcer = new PxEnforcer(params, pxClient); @@ -92,7 +110,7 @@ describe('PX Enforcer - pxenforcer.js', () => { return callback ? callback(null, data) : ''; }); const reqStub = sinon.stub(request, 'post').callsFake((data, config, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:'hello buddy'}); + callback(null, {headers: {'x-px-johnny': '1'}, body: 'hello buddy'}); }); req.originalUrl = '/_APP_ID/xhr/something'; req.method = 'POST'; @@ -132,7 +150,7 @@ describe('PX Enforcer - pxenforcer.js', () => { return callback ? callback(null, data) : ''; }); const reqStub = sinon.stub(request, 'post').callsFake((data, config, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:'hello buddy'}); + callback(null, {headers: {'x-px-johnny': '1'}, body: 'hello buddy'}); }); req.originalUrl = '/_APP_ID/xhr/something'; req.method = 'POST'; @@ -153,7 +171,7 @@ describe('PX Enforcer - pxenforcer.js', () => { return callback ? callback(null, data) : ''; }); const reqStub = sinon.stub(request, 'post').callsFake((data, config, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:'hello buddy'}); + callback(null, {headers: {'x-px-johnny': '1'}, body: 'hello buddy'}); }); req.originalUrl = '/_APP_ID/xhr/something'; req.method = 'POST'; @@ -179,7 +197,7 @@ describe('PX Enforcer - pxenforcer.js', () => { firstPartyEnabled: true }, params); const reqStub = sinon.stub(request, 'post').callsFake((data, config, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:'hello buddy'}); + callback(null, {headers: {'x-px-johnny': '1'}, body: 'hello buddy'}); }); req.headers = {'x-px-authorization': '3:some-fake-cookie'}; req.method = 'POST'; @@ -203,10 +221,10 @@ describe('PX Enforcer - pxenforcer.js', () => { bypassMonitorHeader: 'x-px-block' }, params); req.headers = { - 'x-px-block':'1' + 'x-px-block': '1' }; const reqStub = sinon.stub(req, 'post').callsFake((data, callback) => { - callback(null, {body:'hello buddy'}); + callback(null, {body: 'hello buddy'}); }); req.method = 'POST'; req.body = {key: 'value', anotherKey: 'anotherValue'}; @@ -229,10 +247,10 @@ describe('PX Enforcer - pxenforcer.js', () => { bypassMonitorHeader: 'x-px-block' }, params); req.headers = { - 'x-px-block':'0' + 'x-px-block': '0' }; const reqStub = sinon.stub(req, 'post').callsFake((data, callback) => { - callback(null, {body:'hello buddy'}); + callback(null, {body: 'hello buddy'}); }); req.method = 'POST'; req.body = {key: 'value', anotherKey: 'anotherValue'}; @@ -254,7 +272,7 @@ describe('PX Enforcer - pxenforcer.js', () => { bypassMonitorHeader: 'x-px-block' }, params); const reqStub = sinon.stub(req, 'post').callsFake((data, callback) => { - callback(null, { body:'hello buddy'}); + callback(null, {body: 'hello buddy'}); }); req.method = 'POST'; req.body = {key: 'value', anotherKey: 'anotherValue'}; @@ -276,10 +294,10 @@ describe('PX Enforcer - pxenforcer.js', () => { bypassMonitorHeader: 'x-px-block' }, params); req.headers = { - 'x-px-block':'1' + 'x-px-block': '1' }; const reqStub = sinon.stub(req, 'post').callsFake((data, callback) => { - callback(null, { body:'hello buddy'}); + callback(null, {body: 'hello buddy'}); }); req.method = 'POST'; req.body = {key: 'value', anotherKey: 'anotherValue'}; @@ -301,7 +319,7 @@ describe('PX Enforcer - pxenforcer.js', () => { advancedBlockingResponse: false }, params); const reqStub = sinon.stub(req, 'post').callsFake((data, callback) => { - callback(null, { body:'hello buddy'}); + callback(null, {body: 'hello buddy'}); }); req.method = 'POST'; req.body = {key: 'value', anotherKey: 'anotherValue'}; @@ -324,7 +342,7 @@ describe('PX Enforcer - pxenforcer.js', () => { moduleMode: 1 }, params); const reqStub = sinon.stub(req, 'post').callsFake((data, callback) => { - callback(null, { body:'hello buddy'}); + callback(null, {body: 'hello buddy'}); }); req.method = 'POST'; req.body = {key: 'value', anotherKey: 'anotherValue'}; @@ -337,4 +355,128 @@ describe('PX Enforcer - pxenforcer.js', () => { done(); }); }); + + it('should not monitor specific route when enforcer is disabled', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + return callback ? callback(null, data) : ''; + }); + + params.monitoredRoutes = ['/profile']; + params.enableModule = false; + req.originalUrl = '/profile'; + enforcer = new PxEnforcer(params, pxClient); + enforcer.enforce(req, null, (response) => { + (response === undefined).should.equal(true); + done(); + }); + }); + + it('should whitelist specific routes in blocking mode', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + data.score = 100; + data.action = 'c'; + return callback ? callback(null, data) : ''; + }); + + const curParams = Object.assign({ + moduleMode: 1, + whitelistRoutes: ['/profile'] + }, params); + + req.originalUrl = '/profile'; + const pxenforcer = proxyquire('../lib/pxenforcer', {'./pxlogger': logger}); + enforcer = new pxenforcer(curParams, pxClient); + enforcer.enforce(req, null, (error, response) => { + should(error).not.be.ok(); + pxLoggerSpy.debug.calledWith('Whitelist route match: /profile').should.equal(true); + (response === undefined).should.equal(true); + done(); + }); + }); + it('should monitor specific routes in blocking mode', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + data.score = 100; + data.action = 'c'; + return callback ? callback(null, data) : ''; + }); + + const curParams = Object.assign({ + moduleMode: 1, + monitoredRoutes: ['/profile'] + }, params); + + req.originalUrl = '/profile'; + const pxenforcer = proxyquire('../lib/pxenforcer', {'./pxlogger': logger}); + enforcer = new pxenforcer(curParams, pxClient); + enforcer.enforce(req, null, (error, response) => { + should(error).not.be.ok(); + (response === undefined).should.equal(true); + done(); + }); + }); + it('should enforce routes in blocking mode that are not specified in monitoredRoutes', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + data.score = 100; + data.action = 'c'; + return callback ? callback(null, data) : ''; + }); + + const curParams = Object.assign({ + moduleMode: 1, + monitoredRoutes: ['/profile'] + }, params); + + req.originalUrl = '/admin'; + const pxenforcer = proxyquire('../lib/pxenforcer', {'./pxlogger': logger}); + enforcer = new pxenforcer(curParams, pxClient); + enforcer.enforce(req, null, (error, response) => { + should(error).not.be.ok(); + (response === undefined).should.equal(false); + done(); + }); + }); + it('should monitor specific routes with enforced specific routes not in monitor', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + data.score = 100; + data.action = 'c'; + return callback ? callback(null, data) : ''; + }); + + const curParams = Object.assign({ + moduleMode: 1, + enforcedRoutes: ['/profile', '/login'], + monitoredRoutes: ['/'] + }, params); + + req.originalUrl = '/'; + const pxenforcer = proxyquire('../lib/pxenforcer', {'./pxlogger': logger}); + enforcer = new pxenforcer(curParams, pxClient); + enforcer.enforce(req, null, (error, response) => { + should(error).not.be.ok(); + (response === undefined).should.equal(true); + done(); + }); + }); + it('should enforce specific routes with enforced specific routes not in monitor', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, config, callback) => { + data.score = 100; + data.action = 'c'; + return callback ? callback(null, data) : ''; + }); + + const curParams = Object.assign({ + moduleMode: 1, + enforcedRoutes: ['/profile', '/login'], + monitoredRoutes: ['/'] + }, params); + + req.originalUrl = '/login'; + const pxenforcer = proxyquire('../lib/pxenforcer', {'./pxlogger': logger}); + enforcer = new pxenforcer(curParams, pxClient); + enforcer.enforce(req, null, (error, response) => { + should(error).not.be.ok(); + (response === undefined).should.equal(false); + done(); + }); + }); });