From 3984adcbe817f58a4d11f79324fa19484432bee6 Mon Sep 17 00:00:00 2001 From: Yaron Schwimmer Date: Mon, 30 Jul 2018 15:49:56 +0300 Subject: [PATCH 1/9] Dev fix net cb error (#58) * removed request with no response option * fixed tests --- lib/pxapi.js | 2 +- lib/pxclient.js | 2 +- lib/pxhttpc.js | 5 +- lib/request.js | 8 - test/pxapi.test.js | 2 +- test/pxconfig.test.js | 3 +- test/pxenforcer.test.js | 20 +- test/unit.test.js | 430 ---------------------------------------- 8 files changed, 17 insertions(+), 455 deletions(-) delete mode 100644 test/unit.test.js diff --git a/lib/pxapi.js b/lib/pxapi.js index 5641cd9d..c8ad9731 100644 --- a/lib/pxapi.js +++ b/lib/pxapi.js @@ -99,7 +99,7 @@ function callServer(pxCtx, callback) { } pxCtx.hasMadeServerCall = true; - return pxHttpc.callServer(data, reqHeaders, config.SERVER_TO_SERVER_API_URI, 'query', false, callback); + return pxHttpc.callServer(data, reqHeaders, config.SERVER_TO_SERVER_API_URI, 'query', callback); } diff --git a/lib/pxclient.js b/lib/pxclient.js index f61d0362..c78281f5 100644 --- a/lib/pxclient.js +++ b/lib/pxclient.js @@ -90,7 +90,7 @@ class PxClient { } callServer(data, path, headers, cb) { - pxHttpc.callServer(data, headers, path, 'activities', true); + pxHttpc.callServer(data, headers, path, 'activities'); if (cb) { cb(); } diff --git a/lib/pxhttpc.js b/lib/pxhttpc.js index 1e8b3712..e7920282 100644 --- a/lib/pxhttpc.js +++ b/lib/pxhttpc.js @@ -16,8 +16,8 @@ module.exports = { * @param {string} callType - indication for a query or activities sending * @param {Function} callback - callback function. */ -function callServer(data, headers, uri, callType, ignoreResponse, callback) { - callback = callback || ((err) => { pxLogger.debug(`callServer callback missing. Error: ${err}`) }); +function callServer(data, headers, uri, callType, callback) { + callback = callback || ((err) => { err && pxLogger.debug(`callServer default callback. Error: ${err}`); }); const config = pxConfig.conf; const callData = { url: `https://${config.SERVER_HOST}${uri}`, @@ -26,7 +26,6 @@ function callServer(data, headers, uri, callType, ignoreResponse, callback) { }; callData.timeout = callType === 'query' ? config.API_TIMEOUT_MS : config.ACTIVITIES_TIMEOUT; - callData.ignoreResponse = ignoreResponse; try { request.post(callData, function (err, response) { diff --git a/lib/request.js b/lib/request.js index 8a5e065b..e5cfb05b 100644 --- a/lib/request.js +++ b/lib/request.js @@ -20,18 +20,10 @@ const request = { function makeRequest(options, cb) { options.agent = keepAliveAgent; try { - if (options.ignoreResponse) { - return makeRequestWithNoResponse(options); - } p(options, cb) } catch (e) { pxLogger.error(`Error making request: ${e.message}`); } } - -function makeRequestWithNoResponse(options) { - p(options); -} - module.exports = request; \ No newline at end of file diff --git a/test/pxapi.test.js b/test/pxapi.test.js index 00eb4721..f17c0436 100644 --- a/test/pxapi.test.js +++ b/test/pxapi.test.js @@ -30,7 +30,7 @@ describe('PX API - pxapi.js', () => { let pxconfig = require('../lib/pxconfig'); pxconfig.init(params, new PxClient()); config = pxconfig.mergeDefaults(params); - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback(data) }); }); diff --git a/test/pxconfig.test.js b/test/pxconfig.test.js index 6463c59f..abb3f615 100644 --- a/test/pxconfig.test.js +++ b/test/pxconfig.test.js @@ -17,7 +17,8 @@ describe('PX Configurations - pxconfig.js', () => { blockingScore: 60, debugMode: true, ipHeader: 'x-px-true-ip', - maxBufferLength: 1 + maxBufferLength: 1, + customRequestHandler: null }; pxconfig = require('../lib/pxconfig'); diff --git a/test/pxenforcer.test.js b/test/pxenforcer.test.js index 64d095bd..d2b7d4b5 100644 --- a/test/pxenforcer.test.js +++ b/test/pxenforcer.test.js @@ -43,7 +43,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('enforces a call in a disabled module', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); params.enableModule = false; @@ -56,7 +56,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('enforces a call in an enabled module', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); enforcer = new PxEnforcer(params, new PxClient()); @@ -67,8 +67,8 @@ describe('PX Enforcer - pxenforcer.js', () => { }); }); - it.only('uses first party to get client', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + it('uses first party to get client', (done) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); let reqStub = sinon.stub(request, 'get').callsFake((data, callback) => { @@ -86,7 +86,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('uses first party for xhr post request', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { @@ -106,7 +106,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('uses first party for xhr get request', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); let reqStub = sinon.stub(request, 'get').callsFake((data, callback) => { @@ -126,7 +126,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('uses first party with pxvid cookie', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { @@ -147,7 +147,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('uses first party for xhr and passed trough bodyParser', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { @@ -167,7 +167,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('uses upper case for xhr', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { return callback ? callback(null, data) : ''; }); let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { @@ -187,7 +187,7 @@ describe('PX Enforcer - pxenforcer.js', () => { }); it('should not use first party paths if originated from mobile', (done) => { - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { + stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, callback) => { data.score = 100; data.action = 'b'; return callback ? callback(null, data) : ''; diff --git a/test/unit.test.js b/test/unit.test.js deleted file mode 100644 index 31e5b40a..00000000 --- a/test/unit.test.js +++ /dev/null @@ -1,430 +0,0 @@ -'use strict'; - -const should = require('should'); -const sinon = require('sinon'); -const rewire = require("rewire"); -const pxutil = require('../lib/pxutil'); -const request = require('../lib/request'); -const pxhttpc = require('../lib/pxhttpc'); -const pxapi = rewire('../lib/pxapi'); -const PxClient = rewire('../lib/pxclient'); -const PxEnforcer = require('../lib/pxenforcer') -const originalTokenValidator = require('../lib/pxoriginaltoken'); - -describe('PX Utils - pxutils.js', () => { - let pxconfig; - let params; - - beforeEach(() => { - params = { - pxAppId: 'PX_APP_ID', - cookieSecretKey: 'PX_COOKIE_SECRET', - authToken: 'PX_AUTH_TOKEN', - sendPageActivities: true, - blockingScore: 60, - debugMode: true, - ipHeader: 'x-px-true-ip', - maxBufferLength: 1 - }; - - pxconfig = require('../lib/pxconfig'); - pxconfig.init(params, new PxClient()); - }); - - it('should generate headers array from headers object', (done) => { - const formattedHeaders = pxutil.formatHeaders({K: 'v'}); - (Object.prototype.toString.call(formattedHeaders)).should.be.exactly('[object Array]'); - formattedHeaders[0]['name'].should.be.exactly('K'); - formattedHeaders[0]['value'].should.be.exactly('v'); - return done(); - }); -}); - -describe('PX Configurations - pxconfig.js', () => { - let pxconfig; - let params; - - beforeEach(() => { - params = { - pxAppId: 'PX_APP_ID', - cookieSecretKey: 'PX_COOKIE_SECRET', - authToken: 'PX_AUTH_TOKEN', - sendPageActivities: true, - blockingScore: 60, - debugMode: true, - ipHeader: 'x-px-true-ip', - maxBufferLength: 1 - }; - - pxconfig = require('../lib/pxconfig'); - }); - - it('should set baseUrl to sapi-.perimeterx.net', (done) => { - params.pxAppId = 'PXJWbMQarF'; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.SERVER_HOST.should.be.exactly(`sapi-${params.pxAppId.toLowerCase()}.perimeterx.net`) - done(); - }); - - it('blocking score should be 80', (done) => { - params.blockingScore = 80; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.BLOCKING_SCORE.should.be.exactly(80); - done(); - }); - - it('getUserIp function should be overridden', (done) => { - params.getUserIp = function () { - return '1.2.3.4'; - }; - - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.GET_USER_IP().should.be.exactly('1.2.3.4'); - done(); - }); - - it('requestHandler function should be overridden', (done) => { - params.customRequestHandler = function () { - return 'Blocked'; - }; - - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.CUSTOM_REQUEST_HANDLER().should.be.exactly('Blocked'); - done(); - }); - - it('should set enableModule to false', () => { - params.enableModule = false; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.ENABLE_MODULE.should.be.exactly(false); - }); - - it('should set sendPageActivities to false', () => { - params.sendPageActivities = false; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.SEND_PAGE_ACTIVITIES.should.be.exactly(false); - }); - - it('should set debugMode to true', () => { - params.sendPageActivities = true; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.DEBUG_MODE.should.be.exactly(true); - }); - - it('customLogo should be overridden', () => { - params.customLogo = 'http://www.google.com/logo.jpg'; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.CUSTOM_LOGO.should.be.exactly('http://www.google.com/logo.jpg'); - }); - - it('jsRef should be overridden', () => { - params.jsRef = ['http://www.google.com/script.js']; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.JS_REF[0].should.equal('http://www.google.com/script.js'); - }); - - it('cssRef should be overridden', () => { - params.cssRef = ['http://www.google.com/stylesheet.css']; - pxconfig.init(params, new PxClient()); - const conf = pxconfig.conf; - conf.CSS_REF[0].should.equal('http://www.google.com/stylesheet.css'); - }); -}); - -describe('PX API - pxapi.js', () => { - let params; - let config; - let stub; - beforeEach(() => { - params = { - pxAppId: 'PX_APP_ID', - cookieSecretKey: 'kabum', - authToken: 'PX_AUTH_TOKEN', - sendPageActivities: true, - blockingScore: 60, - debugMode: true, - ipHeader: 'x-px-true-ip', - maxBufferLength: 1 - }; - - let pxconfig = require('../lib/pxconfig'); - config = pxconfig.mergeDefaults(params); - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { - return callback(data) - }); - }); - - afterEach(() => { - stub.restore(); - }); - it('should add px_orig_cookie to risk_api when decryption fails', (done) => { - //Stubbing the pxhttpc callServer functions - - - //Using rewire to get callServer function - const pxApiCallServerFunc = pxapi.__get__('callServer'); - - // Prepare pxCtx - const pxCtx = { - ip: '1.2.3.4', - fullUrl: 'stub', - vid: 'stub', - uuid: 'stub', - uri: 'stub', - headers: 'stub', - httpVersion: 'stub', - s2sCallReason: 'cookie_decryption_failed', - httpMethod: 'stub', - getCookie: () => { return 'abc'} - } - - pxApiCallServerFunc(pxCtx, data => { - data.additional.px_orig_cookie.should.equal('abc') - done(); - }); - }); - - it('token v3 - should add originalUuid, vid and decodedOriginalToken to pxCtx when original token decryption succeeds', (done) => { - const pxCtx = { - cookies:{ - _px3:'aaaa' - }, - originalToken: '68a1bf96ab3af2e0683a377d332b125dda3e195ee56cf3ce4d61b99cd0860dc6:xTMRZvJnzxM=:1000:0pjajaPCjssb2HjG2436zyFXIvIEbE87nFBrHEQPDRT7fqiQ5RA05+njsLUVpOtdJjLvWNNAlSG70DW2wqWM5VmF9UR420/wxPkx6Ebyz/L9q7Mxk5fcdF8p+dGcMc3uD7Qh8y3WiPSN389cXhfKfMttUABQYvRpOxo7rMC+ngpHEVYg+lfBZCliHB1PZKLy' - } - - originalTokenValidator.evalCookie(pxCtx, config); - pxCtx.originalUuid.should.equal('09ade30a-f08b-11e7-8c3f-9a214cf093ae'); - pxCtx.vid.should.equal('0290edec-f08b-11e7-8c3f-9a214cf093ae'); - JSON.stringify(pxCtx.decodedOriginalToken).should.equal('{"a":"c","s":0,"u":"09ade30a-f08b-11e7-8c3f-9a214cf093ae","t":1830515445000,"v":"0290edec-f08b-11e7-8c3f-9a214cf093ae"}'); - done(); - }) - it('token v3 - should set originalTokenError to decryption_failed on original token decryption fail', (done) => { - const pxCtx = { - cookies:{ - _px3:'aaaa' - }, - originalToken: 'aaaaa:bbbbb:cccc:ddddd' - } - - originalTokenValidator.evalCookie(pxCtx, config); - pxCtx.originalTokenError.should.equal('decryption_failed'); - done(); - }) - it('token v3 - should set originalTokenError to validation_failed on original token validation fail', (done) => { - const pxCtx = { - cookies:{ - _px3:'aaaa' - }, - originalToken: '68a1bf96ab3af2e0683a377d332b125dda3e195ee56cf3ce4d61b99cd0860dc:xTMRZvJnzxM=:1000:0pjajaPCjssb2HjG2436zyFXIvIEbE87nFBrHEQPDRT7fqiQ5RA05+njsLUVpOtdJjLvWNNAlSG70DW2wqWM5VmF9UR420/wxPkx6Ebyz/L9q7Mxk5fcdF8p+dGcMc3uD7Qh8y3WiPSN389cXhfKfMttUABQYvRpOxo7rMC+ngpHEVYg+lfBZCliHB1PZKLy' - } - - originalTokenValidator.evalCookie(pxCtx, config); - pxCtx.originalUuid.should.equal('09ade30a-f08b-11e7-8c3f-9a214cf093ae'); - pxCtx.vid.should.equal('0290edec-f08b-11e7-8c3f-9a214cf093ae'); - pxCtx.originalTokenError.should.equal('validation_failed'); - done(); - }) - it('token v1 - should add originalUuid, vid and decodedOriginalToken to pxCtx when original token decryption succeeds', (done) => { - const pxCtx = { - cookies:{ - _px:'aaaa' - }, - originalToken: 'Gy9z3mQPYNE=:1000:I7A44BXmO5IlgqhXLM5Mmuq4/jESNgse51Zj/l4bpkAaymDQzcrUMHBofVQ8Q9IYfon3bVQn7gHA124xunjlSlPMlj133wuFBzt7r/yJKpcTEex5WBxynCQAXXx8tymeO1gWXLmPchrV93ysxPl/AeV2/ofVN3YzUR/0PQbXB2fzxkPc5bMPdxLMJCrgLtR4msoMGvg9qaiufMFDWWzah1kvUq1Kvrlk3UQm0y6UU1j6GoLHkTSnDBTg3GexETotOoUkM5FYMPZm8TxK0as+mg==' - } - - originalTokenValidator.evalCookie(pxCtx, config); - pxCtx.originalUuid.should.equal('09ade30a-f08b-11e7-8c3f-9a214cf093ae'); - pxCtx.vid.should.equal('0290edec-f08b-11e7-8c3f-9a214cf093ae'); - JSON.stringify(pxCtx.decodedOriginalToken).should.equal('{"h":"aa2341380b7c67ee0ed5c2f7d4facf03847d7dcb4540aab021654361d3dcade4","s":{"a":0,"b":0},"u":"09ade30a-f08b-11e7-8c3f-9a214cf093ae","t":1830515445000,"v":"0290edec-f08b-11e7-8c3f-9a214cf093ae"}'); - done(); - }) - it('token v1 - should set originalTokenError to decryption_failed on original token decryption fail', (done) => { - const pxCtx = { - cookies:{ - _px:'aaaa' - }, - originalToken: 'aaaaa:bbbbb:cccc:ddddd' - } - - originalTokenValidator.evalCookie(pxCtx, config); - pxCtx.originalTokenError.should.equal('decryption_failed'); - done(); - }) - it('should fail with exception and set originalTokenError to decryption_failed', (done) => { - const pxCtx = { - cookies: { - _px: 'aaaaa' - }, - originalToken:'' - }; - - originalTokenValidator.evalCookie(pxCtx, config); - pxCtx.originalTokenError.should.equal('decryption_failed'); - done(); - }) -}); - -describe('PX Enforcer - pxenforcer.js', () => { - let params, enforcer, req, stub; - beforeEach(() => { - params = { - pxAppId: 'PX_APP_ID', - cookieSecretKey: 'kabum', - authToken: 'PX_AUTH_TOKEN', - sendPageActivities: true, - blockingScore: 60, - debugMode: true, - ipHeader: 'x-px-true-ip', - maxBufferLength: 1, - enableModule: true, - moduleMode: 1, - firstPartyEnabled: true - }; - - req = {}; - req.headers = {}; - req.cookies = {}; - - req.originalUrl = "/"; - req.path = req.originalUrl.substring(req.originalUrl.lastIndexOf('/')); - req.protocol = 'http'; - req.ip = '1.2.3.4'; - req.hostname = 'example.com' - req.get = (key) => { - return req.headers[key] || ''; - }; - - stub = sinon.stub(pxhttpc, 'callServer').callsFake((data, headers, uri, callType, ignore, callback) => { - return callback ? callback(data) : ''; - }); - }); - - afterEach(() => { - stub.restore(); - }); - - it ('enforces a call in a disabled module', (done) => { - params.enableModule = false; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (response) => { - - (response === undefined).should.equal(true); - done(); - }); - }); - - it ('enforces a call in an enabled module', (done) => { - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (response) => { - - (response === undefined).should.equal(true); - done(); - }); - }); - it('uses first party to get client', (done) => { - let reqStub = sinon.stub(request, 'get').callsFake((data, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:"hello buddy"}); - }) - req.originalUrl = "/_APP_ID/init.js"; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (error, response) => { - (response === undefined).should.equal(false); - response.body.should.equal("hello buddy"); - response.headers['x-px-johnny'].should.equal('1') - reqStub.restore(); - done(); - }); - }); - it('uses first party for xhr post request', (done) => { - let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:"hello buddy"}); - }) - req.originalUrl = "/_APP_ID/xhr/something"; - req.method = "POST"; - req.body = "test"; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (error, response) => { - (response === undefined).should.equal(false); - response.body.should.equal("hello buddy"); - response.headers['x-px-johnny'].should.equal('1') - reqStub.restore(); - done(); - }); - }); - it('uses first party for xhr get request', (done) => { - let reqStub = sinon.stub(request, 'get').callsFake((data, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:"hello buddy"}); - }) - req.originalUrl = "/_APP_ID/xhr/something"; - req.method = "GET"; - req.body = "test"; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (error, response) => { - (response === undefined).should.equal(false); - response.body.should.equal("hello buddy"); - response.headers['x-px-johnny'].should.equal('1') - reqStub.restore(); - done(); - }); - }); - it ('uses first party with pxvid cookie', (done) => { - let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:"hello buddy"}); - }) - req.originalUrl = "/_APP_ID/xhr/something"; - req.method = "POST"; - req.cookies['_pxvid'] = "abab-123"; - req.body = "test"; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (error, response) => { - (response === undefined).should.equal(false); - response.body.should.equal("hello buddy"); - response.headers['x-px-johnny'].should.equal('1') - reqStub.restore(); - done(); - }); - }) - it('uses first party for xhr and passed trough bodyParser', (done) => { - let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:"hello buddy"}); - }) - req.originalUrl = "/_APP_ID/xhr/something"; - req.method = "POST"; - req.body={key: 'value', anotherKey:'anotherValue'}; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (error, response) => { - (response === undefined).should.equal(false); - response.body.should.equal("hello buddy"); - response.headers['x-px-johnny'].should.equal('1') - reqStub.restore(); - done(); - }); - }) - it('uses upper case for xhr', (done) => { - let reqStub = sinon.stub(request, 'post').callsFake((data, callback) => { - callback(null, {headers: {'x-px-johnny': '1'}, body:"hello buddy"}); - }) - req.originalUrl = "/_APP_ID/XHR/something"; - req.method = "POST"; - req.body={key: 'value', anotherKey:'anotherValue'}; - enforcer = new PxEnforcer(params, new PxClient()); - enforcer.enforce(req, null, (error, response) => { - (response === undefined).should.equal(false); - response.body.should.equal("hello buddy"); - response.headers['x-px-johnny'].should.equal('1') - reqStub.restore(); - done(); - }); - }) -}); - - From 3e3380bef8750b19aeae35d8b796054b32bb45c3 Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Mon, 30 Jul 2018 16:11:55 +0300 Subject: [PATCH 2/9] Version 1.4.2 --- CHANGELOG.md | 4 ++++ README.md | 2 +- package.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6781e6b..ef5caab7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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/). +## [1.4.2] - 2018-07-30 +### Fixed +- phin callback related issue + ## [1.4.1] - 2018-07-29 ### Fixed - Various fixes regarding page_requested and pass_reason diff --git a/README.md b/README.md index fd405342..f0d4fa07 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [PerimeterX](http://www.perimeterx.com) Shared base for NodeJS enforcers ============================================================= -> Latest stable version: [v1.4.1](https://www.npmjs.com/package/perimeterx-node-core) +> Latest stable version: [v1.4.2](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.json b/package.json index 20cc8b13..cc4b2c59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "perimeterx-node-core", - "version": "1.4.1", + "version": "1.4.2", "description": "PerimeterX NodeJS shared core for various applications to monitor and block traffic according to PerimeterX risk score", "main": "index.js", "scripts": { From 59eb90faee8c7d1978750514916f745b2654c9d0 Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Tue, 31 Jul 2018 13:20:46 +0300 Subject: [PATCH 3/9] refactored the use of pxblock and pxpass (#60) --- lib/pxenforcer.js | 100 ++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/lib/pxenforcer.js b/lib/pxenforcer.js index f648ca3a..9959dbf1 100644 --- a/lib/pxenforcer.js +++ b/lib/pxenforcer.js @@ -133,6 +133,15 @@ class PxEnforcer { handleVerification(pxCtx, pxConfig, req, res, cb) { + const verified = pxCtx.score < pxConfig.BLOCKING_SCORE; + + // Handle async activities + if (verified) { + this.pxPass(pxCtx); + } else { + this.pxBlock(pxCtx, pxConfig); + } + // check for additional activity handler if (pxConfig.ADDITIONAL_ACTIVITY_HANDLER) { pxConfig.ADDITIONAL_ACTIVITY_HANDLER(pxCtx, pxConfig); @@ -150,63 +159,58 @@ class PxEnforcer { return cb(null, result); } } - } - if (pxCtx.score < pxConfig.BLOCKING_SCORE) { - this.pxPass(pxCtx); + + // If verified, pass the request here + if (verified || pxConfig.MODULE_MODE === pxConfig.MONITOR_MODE.MONITOR) { return cb(); - } else { - this.pxBlock(pxCtx, pxConfig); - if (pxConfig.MODULE_MODE === pxConfig.MONITOR_MODE.MONITOR) { - return cb(); - } + } - const acceptHeaderValue = req.headers["accept"] || req.headers["content-type"]; - const isJsonResponse = acceptHeaderValue && acceptHeaderValue.split(',').find((value) => value.toLowerCase() === "application/json") && pxCtx.cookieOrigin === "cookie" && pxCtx.blockAction !== 'r'; + const acceptHeaderValue = req.headers["accept"] || req.headers["content-type"]; + const isJsonResponse = acceptHeaderValue && acceptHeaderValue.split(',').find((value) => value.toLowerCase() === "application/json") && pxCtx.cookieOrigin === "cookie" && pxCtx.blockAction !== 'r'; - pxLogger.debug(`Enforcing action: ${pxUtil.parseAction(pxCtx.blockAction)} page is served ${isJsonResponse ? "using advanced protection mode" : ""}`); - this.generateResponse(pxCtx, pxConfig, isJsonResponse, function (responseObject) { - const response = { - status: '403', - statusDescription: "Forbidden" - }; + pxLogger.debug(`Enforcing action: ${pxUtil.parseAction(pxCtx.blockAction)} page is served ${isJsonResponse ? "using advanced protection mode" : ""}`); + this.generateResponse(pxCtx, pxConfig, isJsonResponse, function (responseObject) { + const response = { + status: '403', + statusDescription: "Forbidden" + }; - if (pxCtx.blockAction === 'r') { - response.status = '429'; - response.statusDescription = "Too Many Requests"; - } + if (pxCtx.blockAction === 'r') { + response.status = '429'; + response.statusDescription = "Too Many Requests"; + } - if (isJsonResponse) { - response.header = {key: 'Content-Type', value: 'application/json'}; - response.body = { - appId: responseObject.appId, - jsClientSrc: responseObject.jsClientSrc, - firstPartyEnabled: responseObject.firstPartyEnabled, - vid: responseObject.vid, - uuid: responseObject.uuid, - hostUrl: responseObject.hostUrl, - blockScript: responseObject.blockScript - } - return cb(null, response); + if (isJsonResponse) { + response.header = {key: 'Content-Type', value: 'application/json'}; + response.body = { + appId: responseObject.appId, + jsClientSrc: responseObject.jsClientSrc, + firstPartyEnabled: responseObject.firstPartyEnabled, + vid: responseObject.vid, + uuid: responseObject.uuid, + hostUrl: responseObject.hostUrl, + blockScript: responseObject.blockScript } + return cb(null, response); + } - response.header = {key: 'Content-Type', value: 'text/html'}; - response.body = responseObject; - - if (pxCtx.cookieOrigin !== "cookie") { - response.header = {key: 'Content-Type', value: 'application/json'}; - response.body = { - action: pxUtil.parseAction(pxCtx.blockAction), - uuid: pxCtx.uuid, - vid: pxCtx.vid, - appId: pxConfig.PX_APP_ID, - page: new Buffer(responseObject).toString('base64'), - collectorUrl: pxCtx.collectorUrl - } + response.header = {key: 'Content-Type', value: 'text/html'}; + response.body = responseObject; + + if (pxCtx.cookieOrigin !== "cookie") { + response.header = {key: 'Content-Type', value: 'application/json'}; + response.body = { + action: pxUtil.parseAction(pxCtx.blockAction), + uuid: pxCtx.uuid, + vid: pxCtx.vid, + appId: pxConfig.PX_APP_ID, + page: new Buffer(responseObject).toString('base64'), + collectorUrl: pxCtx.collectorUrl } - cb(null, response); - }); - } + } + cb(null, response); + }); } get config() { From ce55b0353f8b7c3222b983b9ae06c41d7eb8c286 Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Tue, 31 Jul 2018 17:20:27 +0300 Subject: [PATCH 4/9] updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef5caab7..e9d45d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.4.2] - 2018-07-30 ### Fixed - phin callback related issue +- no activities get sent if customRequestHandler is used ## [1.4.1] - 2018-07-29 ### Fixed From c4d998fd938ee5b51279d19bb615bd9a3d0607f7 Mon Sep 17 00:00:00 2001 From: Alex Bluvstein Date: Thu, 2 Aug 2018 15:17:54 +0300 Subject: [PATCH 5/9] APP-945 Fixed parsing of original token, removing prefix before parsing --- lib/pxoriginaltoken.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pxoriginaltoken.js b/lib/pxoriginaltoken.js index 92f96f04..04244d16 100644 --- a/lib/pxoriginaltoken.js +++ b/lib/pxoriginaltoken.js @@ -2,9 +2,11 @@ const TokenV3 = require('./cookie/tokenV3'); const TokenV1 = require('./cookie/tokenV1'); const pxLogger = require('./pxlogger'); -function evalCookie(pxCtx, pxConfig) { +function evalCookie(pxCtx, pxConfig, delimiter = ":") { try { - const cookie = (pxCtx.cookies['_px3'] ? new TokenV3(pxCtx, pxConfig, pxCtx.originalToken) : new TokenV1(pxCtx, pxConfig, pxCtx.originalToken)) + let [version, ...extractedCookie] = pxCtx.originalToken.split(delimiter); + let noVersionOriginalToken = extractedCookie.join(delimiter); + const cookie = (pxCtx.cookies['_px3'] ? new TokenV3(pxCtx, pxConfig, noVersionOriginalToken) : new TokenV1(pxCtx, pxConfig, noVersionOriginalToken)) pxLogger.debug('Original token found, Evaluating'); if (!cookie.deserialize()) { From f40cfec03db0d4e879ab589b6455e68b3a6693ef Mon Sep 17 00:00:00 2001 From: Alex Bluvstein Date: Thu, 2 Aug 2018 16:29:49 +0300 Subject: [PATCH 6/9] Revert "APP-945" This reverts commit c4d998fd938ee5b51279d19bb615bd9a3d0607f7. Changes to be committed: modified: lib/pxoriginaltoken.js Reverting a commit made by mistake --- lib/pxoriginaltoken.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/pxoriginaltoken.js b/lib/pxoriginaltoken.js index 04244d16..92f96f04 100644 --- a/lib/pxoriginaltoken.js +++ b/lib/pxoriginaltoken.js @@ -2,11 +2,9 @@ const TokenV3 = require('./cookie/tokenV3'); const TokenV1 = require('./cookie/tokenV1'); const pxLogger = require('./pxlogger'); -function evalCookie(pxCtx, pxConfig, delimiter = ":") { +function evalCookie(pxCtx, pxConfig) { try { - let [version, ...extractedCookie] = pxCtx.originalToken.split(delimiter); - let noVersionOriginalToken = extractedCookie.join(delimiter); - const cookie = (pxCtx.cookies['_px3'] ? new TokenV3(pxCtx, pxConfig, noVersionOriginalToken) : new TokenV1(pxCtx, pxConfig, noVersionOriginalToken)) + const cookie = (pxCtx.cookies['_px3'] ? new TokenV3(pxCtx, pxConfig, pxCtx.originalToken) : new TokenV1(pxCtx, pxConfig, pxCtx.originalToken)) pxLogger.debug('Original token found, Evaluating'); if (!cookie.deserialize()) { From 3106a523bb73c7fa02e4267d8224049be1a27688 Mon Sep 17 00:00:00 2001 From: alexbpx <41577203+alexbpx@users.noreply.github.com> Date: Thu, 2 Aug 2018 16:33:33 +0300 Subject: [PATCH 7/9] App 945 (#61) * APP-945 : Fixed parsing of original token, removing prefix before parsing * APP-945 : Fixed UTs to work with the latest original token parsing method --- lib/pxoriginaltoken.js | 6 ++++-- test/pxapi.test.js | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/pxoriginaltoken.js b/lib/pxoriginaltoken.js index 92f96f04..04244d16 100644 --- a/lib/pxoriginaltoken.js +++ b/lib/pxoriginaltoken.js @@ -2,9 +2,11 @@ const TokenV3 = require('./cookie/tokenV3'); const TokenV1 = require('./cookie/tokenV1'); const pxLogger = require('./pxlogger'); -function evalCookie(pxCtx, pxConfig) { +function evalCookie(pxCtx, pxConfig, delimiter = ":") { try { - const cookie = (pxCtx.cookies['_px3'] ? new TokenV3(pxCtx, pxConfig, pxCtx.originalToken) : new TokenV1(pxCtx, pxConfig, pxCtx.originalToken)) + let [version, ...extractedCookie] = pxCtx.originalToken.split(delimiter); + let noVersionOriginalToken = extractedCookie.join(delimiter); + const cookie = (pxCtx.cookies['_px3'] ? new TokenV3(pxCtx, pxConfig, noVersionOriginalToken) : new TokenV1(pxCtx, pxConfig, noVersionOriginalToken)) pxLogger.debug('Original token found, Evaluating'); if (!cookie.deserialize()) { diff --git a/test/pxapi.test.js b/test/pxapi.test.js index f17c0436..a9759a54 100644 --- a/test/pxapi.test.js +++ b/test/pxapi.test.js @@ -72,7 +72,7 @@ describe('PX API - pxapi.js', () => { cookies: { _px3: 'aaaa' }, - originalToken: '68a1bf96ab3af2e0683a377d332b125dda3e195ee56cf3ce4d61b99cd0860dc6:xTMRZvJnzxM=:1000:0pjajaPCjssb2HjG2436zyFXIvIEbE87nFBrHEQPDRT7fqiQ5RA05+njsLUVpOtdJjLvWNNAlSG70DW2wqWM5VmF9UR420/wxPkx6Ebyz/L9q7Mxk5fcdF8p+dGcMc3uD7Qh8y3WiPSN389cXhfKfMttUABQYvRpOxo7rMC+ngpHEVYg+lfBZCliHB1PZKLy' + originalToken: '3:68a1bf96ab3af2e0683a377d332b125dda3e195ee56cf3ce4d61b99cd0860dc6:xTMRZvJnzxM=:1000:0pjajaPCjssb2HjG2436zyFXIvIEbE87nFBrHEQPDRT7fqiQ5RA05+njsLUVpOtdJjLvWNNAlSG70DW2wqWM5VmF9UR420/wxPkx6Ebyz/L9q7Mxk5fcdF8p+dGcMc3uD7Qh8y3WiPSN389cXhfKfMttUABQYvRpOxo7rMC+ngpHEVYg+lfBZCliHB1PZKLy' }; originalTokenValidator.evalCookie(pxCtx, config); @@ -98,7 +98,7 @@ describe('PX API - pxapi.js', () => { cookies: { _px3: 'aaaa' }, - originalToken: '68a1bf96ab3af2e0683a377d332b125dda3e195ee56cf3ce4d61b99cd0860dc:xTMRZvJnzxM=:1000:0pjajaPCjssb2HjG2436zyFXIvIEbE87nFBrHEQPDRT7fqiQ5RA05+njsLUVpOtdJjLvWNNAlSG70DW2wqWM5VmF9UR420/wxPkx6Ebyz/L9q7Mxk5fcdF8p+dGcMc3uD7Qh8y3WiPSN389cXhfKfMttUABQYvRpOxo7rMC+ngpHEVYg+lfBZCliHB1PZKLy' + originalToken: '3:68a1bf96ab3af2e0683a377d332b125dda3e195ee56cf3ce4d61b99cd0860dc:xTMRZvJnzxM=:1000:0pjajaPCjssb2HjG2436zyFXIvIEbE87nFBrHEQPDRT7fqiQ5RA05+njsLUVpOtdJjLvWNNAlSG70DW2wqWM5VmF9UR420/wxPkx6Ebyz/L9q7Mxk5fcdF8p+dGcMc3uD7Qh8y3WiPSN389cXhfKfMttUABQYvRpOxo7rMC+ngpHEVYg+lfBZCliHB1PZKLy' }; originalTokenValidator.evalCookie(pxCtx, config); @@ -112,7 +112,7 @@ describe('PX API - pxapi.js', () => { cookies: { _px: 'aaaa' }, - originalToken: 'Gy9z3mQPYNE=:1000:I7A44BXmO5IlgqhXLM5Mmuq4/jESNgse51Zj/l4bpkAaymDQzcrUMHBofVQ8Q9IYfon3bVQn7gHA124xunjlSlPMlj133wuFBzt7r/yJKpcTEex5WBxynCQAXXx8tymeO1gWXLmPchrV93ysxPl/AeV2/ofVN3YzUR/0PQbXB2fzxkPc5bMPdxLMJCrgLtR4msoMGvg9qaiufMFDWWzah1kvUq1Kvrlk3UQm0y6UU1j6GoLHkTSnDBTg3GexETotOoUkM5FYMPZm8TxK0as+mg==' + originalToken: '3:Gy9z3mQPYNE=:1000:I7A44BXmO5IlgqhXLM5Mmuq4/jESNgse51Zj/l4bpkAaymDQzcrUMHBofVQ8Q9IYfon3bVQn7gHA124xunjlSlPMlj133wuFBzt7r/yJKpcTEex5WBxynCQAXXx8tymeO1gWXLmPchrV93ysxPl/AeV2/ofVN3YzUR/0PQbXB2fzxkPc5bMPdxLMJCrgLtR4msoMGvg9qaiufMFDWWzah1kvUq1Kvrlk3UQm0y6UU1j6GoLHkTSnDBTg3GexETotOoUkM5FYMPZm8TxK0as+mg==' }; originalTokenValidator.evalCookie(pxCtx, config); From c345318801b7e4e529e36e42b4f0ca4217cac2b1 Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Thu, 9 Aug 2018 16:33:08 +0300 Subject: [PATCH 8/9] Refactored timeout error handling --- lib/pxapi.js | 2 ++ lib/pxconfig.js | 4 +++- lib/pxhttpc.js | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/pxapi.js b/lib/pxapi.js index c8ad9731..b48a2341 100644 --- a/lib/pxapi.js +++ b/lib/pxapi.js @@ -124,6 +124,7 @@ function evalByServerCall(pxCtx, callback) { return callback(config.SCORE_EVALUATE_ACTION.S2S_TIMEOUT_PASS); } pxLogger.error(`Unexpected exception while evaluating Risk cookie. ${err}`); + pxCtx.passReason = pxConfig.conf.PASS_REASON.REQUEST_FAILED; return callback(config.SCORE_EVALUATE_ACTION.UNEXPECTED_RESULT); } let action = isBadRiskScore(res, pxCtx); @@ -163,6 +164,7 @@ function evalByServerCall(pxCtx, callback) { */ function isBadRiskScore(res, pxCtx) { if (!res || !pxUtil.verifyDefined(res.score) || !res.action) { + pxCtx.passReason = pxConfig.conf.PASS_REASON.INVALID_RESPONSE; return -1; } let score = res.score; diff --git a/lib/pxconfig.js b/lib/pxconfig.js index 108d4e5b..7e26de6d 100644 --- a/lib/pxconfig.js +++ b/lib/pxconfig.js @@ -65,7 +65,9 @@ PX_INTERNAL.PASS_REASON = { COOKIE: "cookie", S2S: "s2s", S2S_TIMEOUT: "s2s_timeout", - MONITOR_MODE: "monitor_mode" + MONITOR_MODE: "monitor_mode", + INVALID_RESPONSE: "invalid_response", + REQUEST_FAILED: "request_failed" } PX_INTERNAL.MONITOR_MODE = { diff --git a/lib/pxhttpc.js b/lib/pxhttpc.js index e7920282..2de99973 100644 --- a/lib/pxhttpc.js +++ b/lib/pxhttpc.js @@ -31,10 +31,10 @@ function callServer(data, headers, uri, callType, callback) { request.post(callData, function (err, response) { let data; if (err) { - if (err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT' || err.code === 'ECONNRESET') { + if (err == "Error: Timeout has been reached.") { return callback('timeout'); } else { - return callback('perimeterx server did not return a valid response'); + return callback(`perimeterx server did not return a valid response. Error: ${err}`); } } if (typeof(response.body) !== "undefined" && response.body !== null) { From 78c597b2e4e0739001aa6c1e7e4db89798d2a43c Mon Sep 17 00:00:00 2001 From: Johnny Tordgeman Date: Thu, 9 Aug 2018 17:45:09 +0300 Subject: [PATCH 9/9] Update CHANGELOG.md --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d45d87..2bf8db8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.4.2] - 2018-07-30 ### Fixed -- phin callback related issue -- no activities get sent if customRequestHandler is used +- Phin callback related issue +- Better handling of activities when customRequestHandler is used +- Better error messages for requests ## [1.4.1] - 2018-07-29 ### Fixed