From af69ef48489148fecdbe2495609a5e3e4ecbea12 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Tue, 27 Feb 2024 22:55:02 +0530 Subject: [PATCH 01/18] hidding redacted values in raw HTTP logs - html reporter --- lib/transport/selenium-webdriver/httpclient.js | 11 +++++++++++ .../selenium-webdriver/method-mappings.js | 14 ++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/transport/selenium-webdriver/httpclient.js b/lib/transport/selenium-webdriver/httpclient.js index c7c9f0129b..5979f0a47c 100644 --- a/lib/transport/selenium-webdriver/httpclient.js +++ b/lib/transport/selenium-webdriver/httpclient.js @@ -37,6 +37,16 @@ module.exports = function(settings, HttpResponse) { } + isDataRedacted(data) { + for (const value of Object.values(data)) { + if (typeof(value) === 'string' && value.includes('\uE000')) { + return true; + } + } + + return false; + } + /** @override */ send(httpRequest) { const {method, data, path} = httpRequest; @@ -52,6 +62,7 @@ module.exports = function(settings, HttpResponse) { this.options.data = data; this.options.path = path; this.options.method = method; + this.options.redact = this.isDataRedacted(data); const request = new HttpRequest(this.options); diff --git a/lib/transport/selenium-webdriver/method-mappings.js b/lib/transport/selenium-webdriver/method-mappings.js index e91462fef5..000d55bea3 100644 --- a/lib/transport/selenium-webdriver/method-mappings.js +++ b/lib/transport/selenium-webdriver/method-mappings.js @@ -1,4 +1,4 @@ -const {WebElement, WebDriver, Origin, By, until, Condition} = require('selenium-webdriver'); +const {WebElement, WebDriver, Origin, By, until, Condition, Key} = require('selenium-webdriver'); const {Locator} = require('../../element'); const NightwatchLocator = require('../../element/locator-factory.js'); const {isString} = require('../../utils'); @@ -591,11 +591,12 @@ module.exports = class MethodMappings { }, setElementValueRedacted(...args) { - // FIXME: redact password in verbose HTTP logs, it's only redacted in the command logs + args.push(true); // Passing true for readacting. + return this.methods.session.setElementValue.call(this, ...args); }, - async setElementValue(webElementOrId, value) { + async setElementValue(webElementOrId, value, redacted = false) { if (Array.isArray(value)) { value = value.join(''); } else { @@ -612,7 +613,12 @@ module.exports = class MethodMappings { throw err; } } - await element.sendKeys(value); + if (redacted) { + // Using Key.NULL as a flag for redacted values. + await element.sendKeys(value, Key.NULL); + } else { + await element.sendKeys(value); + } return null; }, From 0f6b9a7e16ada3064d38a555bab1b6e85dffbe84 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 28 Feb 2024 00:40:59 +0530 Subject: [PATCH 02/18] updated isRedacted --- lib/http/request.js | 19 ++++++++++++++++++- .../selenium-webdriver/httpclient.js | 11 ----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/http/request.js b/lib/http/request.js index 91b559943d..db49ccee6f 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -10,6 +10,7 @@ const Auth = require('./auth.js'); const Formatter = require('./formatter.js'); const HttpResponse = require('./response.js'); const Utils = require('./../utils'); +const {Key} = require('selenium-webdriver'); const {Logger, isString} = Utils; const {DEFAULT_RUNNER_EVENTS: {LogCreated}, NightwatchEventHub} = require('../runner/eventHub.js'); @@ -104,6 +105,22 @@ class HttpRequest extends EventEmitter { return this.httpResponse.res.statusCode; } + isRedacted(data, reqOptions) { + if (reqOptions?.method !== 'POST'){ + return false; + } + if (!reqOptions?.path.endsWith('/value')){ + return false; + } + for (const value of Object.values(data)) { + if (typeof(value) === 'string' && value.startsWith(Key.NULL)) { + return true; + } + } + + return false; + } + setOptions(options) { this.setPathPrefix(options); @@ -126,7 +143,7 @@ class HttpRequest extends EventEmitter { this.reqOptions = this.createHttpOptions(options); this.hostname = Formatter.formatHostname(this.reqOptions.host, this.reqOptions.port, this.use_ssl); this.retryAttempts = this.httpOpts.retry_attempts; - this.redact = options.redact || false; + this.redact = this.isRedacted(options.data, this.reqOptions); return this; } diff --git a/lib/transport/selenium-webdriver/httpclient.js b/lib/transport/selenium-webdriver/httpclient.js index 5979f0a47c..c7c9f0129b 100644 --- a/lib/transport/selenium-webdriver/httpclient.js +++ b/lib/transport/selenium-webdriver/httpclient.js @@ -37,16 +37,6 @@ module.exports = function(settings, HttpResponse) { } - isDataRedacted(data) { - for (const value of Object.values(data)) { - if (typeof(value) === 'string' && value.includes('\uE000')) { - return true; - } - } - - return false; - } - /** @override */ send(httpRequest) { const {method, data, path} = httpRequest; @@ -62,7 +52,6 @@ module.exports = function(settings, HttpResponse) { this.options.data = data; this.options.path = path; this.options.method = method; - this.options.redact = this.isDataRedacted(data); const request = new HttpRequest(this.options); From 73484d5c193ba995b390253484033a880af518b2 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 28 Feb 2024 00:41:36 +0530 Subject: [PATCH 03/18] Reverting setElementValue and updated setElementValueRedacted --- .../selenium-webdriver/method-mappings.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/transport/selenium-webdriver/method-mappings.js b/lib/transport/selenium-webdriver/method-mappings.js index 000d55bea3..9b94e25dc8 100644 --- a/lib/transport/selenium-webdriver/method-mappings.js +++ b/lib/transport/selenium-webdriver/method-mappings.js @@ -591,12 +591,14 @@ module.exports = class MethodMappings { }, setElementValueRedacted(...args) { - args.push(true); // Passing true for readacting. + const webElementOrId = args[0]; + let value = args[1]; + value = Key.NULL + value; - return this.methods.session.setElementValue.call(this, ...args); + return this.methods.session.setElementValue.call(this, webElementOrId, value); }, - async setElementValue(webElementOrId, value, redacted = false) { + async setElementValue(webElementOrId, value) { if (Array.isArray(value)) { value = value.join(''); } else { @@ -613,12 +615,7 @@ module.exports = class MethodMappings { throw err; } } - if (redacted) { - // Using Key.NULL as a flag for redacted values. - await element.sendKeys(value, Key.NULL); - } else { - await element.sendKeys(value); - } + await element.sendKeys(value); return null; }, From 961f9addb45014be9a3c44f0302e4b7833fa1e33 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 28 Feb 2024 20:35:04 +0530 Subject: [PATCH 04/18] updated args and handled additional case --- .../selenium-webdriver/method-mappings.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/transport/selenium-webdriver/method-mappings.js b/lib/transport/selenium-webdriver/method-mappings.js index 9b94e25dc8..a9ec42e628 100644 --- a/lib/transport/selenium-webdriver/method-mappings.js +++ b/lib/transport/selenium-webdriver/method-mappings.js @@ -590,12 +590,16 @@ module.exports = class MethodMappings { return null; }, - setElementValueRedacted(...args) { - const webElementOrId = args[0]; - let value = args[1]; - value = Key.NULL + value; + setElementValueRedacted(webElementOrId, value) { + let redactedValue; + if (value instanceof Array) { + redactedValue = value.unshift(Key.NULL); + } else { + // Can be String or number. + redactedValue = Key.NULL + value; + } - return this.methods.session.setElementValue.call(this, webElementOrId, value); + return this.methods.session.setElementValue.call(this, webElementOrId, redactedValue); }, async setElementValue(webElementOrId, value) { From b06c329e3fc193e1a6cb70fa78f50e40f67b0900 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 28 Feb 2024 20:37:13 +0530 Subject: [PATCH 05/18] refactored code --- lib/http/request.js | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/lib/http/request.js b/lib/http/request.js index db49ccee6f..c0f7d784fa 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -105,22 +105,6 @@ class HttpRequest extends EventEmitter { return this.httpResponse.res.statusCode; } - isRedacted(data, reqOptions) { - if (reqOptions?.method !== 'POST'){ - return false; - } - if (!reqOptions?.path.endsWith('/value')){ - return false; - } - for (const value of Object.values(data)) { - if (typeof(value) === 'string' && value.startsWith(Key.NULL)) { - return true; - } - } - - return false; - } - setOptions(options) { this.setPathPrefix(options); @@ -143,7 +127,6 @@ class HttpRequest extends EventEmitter { this.reqOptions = this.createHttpOptions(options); this.hostname = Formatter.formatHostname(this.reqOptions.host, this.reqOptions.port, this.use_ssl); this.retryAttempts = this.httpOpts.retry_attempts; - this.redact = this.isRedacted(options.data, this.reqOptions); return this; } @@ -270,6 +253,11 @@ class HttpRequest extends EventEmitter { return arg; }); + } else if (this.reqOptions.method === 'POST' && this.reqOptions.path.includes('/value')) { + if (params.text.startsWith(Key.NULL)){ + params.text = '****'; + params.value = '****'.split(''); + } } const content = ` Request ${[this.reqOptions.method, this.hostname + this.reqOptions.path, retryStr + ' '].join(' ')}`; From 84a9799a7c4cbc02c82313f1dab1fc8afb9a65b8 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 28 Feb 2024 20:43:29 +0530 Subject: [PATCH 06/18] minor fix --- lib/transport/selenium-webdriver/method-mappings.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/transport/selenium-webdriver/method-mappings.js b/lib/transport/selenium-webdriver/method-mappings.js index a9ec42e628..2f8e588d21 100644 --- a/lib/transport/selenium-webdriver/method-mappings.js +++ b/lib/transport/selenium-webdriver/method-mappings.js @@ -593,7 +593,8 @@ module.exports = class MethodMappings { setElementValueRedacted(webElementOrId, value) { let redactedValue; if (value instanceof Array) { - redactedValue = value.unshift(Key.NULL); + value.unshift(Key.NULL); + redactedValue = value; } else { // Can be String or number. redactedValue = Key.NULL + value; From ee51c76ccd5e01cadc1d6cf65735a5c44cc7a667 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Thu, 29 Feb 2024 06:35:19 +0000 Subject: [PATCH 07/18] fixed test --- test/src/api/commands/element/testSetPassword.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/api/commands/element/testSetPassword.js b/test/src/api/commands/element/testSetPassword.js index 176b27aa7f..f0c987378b 100644 --- a/test/src/api/commands/element/testSetPassword.js +++ b/test/src/api/commands/element/testSetPassword.js @@ -17,8 +17,8 @@ describe('setPassword', function() { url: '/wd/hub/session/1352110219202/element/0/value', method: 'POST', postdata: { - text: 'password', - value: ['p', 'a', 's', 's', 'w', 'o', 'r', 'd'] + text: 'password', + value: ['', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] }, response: { sessionId: '1352110219202', From bb9ad0ac7cea4b64add75f1d96f090b3a1f262c2 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Thu, 29 Feb 2024 06:59:17 +0000 Subject: [PATCH 08/18] updated test to use enum --- test/src/api/commands/element/testSetPassword.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/src/api/commands/element/testSetPassword.js b/test/src/api/commands/element/testSetPassword.js index f0c987378b..24c469b8b6 100644 --- a/test/src/api/commands/element/testSetPassword.js +++ b/test/src/api/commands/element/testSetPassword.js @@ -1,4 +1,5 @@ const assert = require('assert'); +const {Key} = require('selenium-webdriver'); const MockServer = require('../../../../lib/mockserver.js'); const CommandGlobals = require('../../../../lib/globals/commands.js'); @@ -17,8 +18,8 @@ describe('setPassword', function() { url: '/wd/hub/session/1352110219202/element/0/value', method: 'POST', postdata: { - text: 'password', - value: ['', 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] + text: Key.NULL + 'password', + value: [Key.NULL, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] }, response: { sessionId: '1352110219202', From ba8d61757d51f2dd270df5230745aa7a496d3718 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Thu, 29 Feb 2024 19:49:58 +0530 Subject: [PATCH 09/18] minor refactoring --- lib/http/request.js | 14 ++++++-------- .../selenium-webdriver/method-mappings.js | 11 ++--------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/http/request.js b/lib/http/request.js index c0f7d784fa..8625ba2dfa 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -253,18 +253,16 @@ class HttpRequest extends EventEmitter { return arg; }); - } else if (this.reqOptions.method === 'POST' && this.reqOptions.path.includes('/value')) { - if (params.text.startsWith(Key.NULL)){ - params.text = '****'; - params.value = '****'.split(''); - } + } else if (this.reqOptions.method === 'POST' && + this.reqOptions.path.includes('/value') && params.text.startsWith(Key.NULL)) { + params.text = '****'; + params.value = '****'.split(''); } const content = ` Request ${[this.reqOptions.method, this.hostname + this.reqOptions.path, retryStr + ' '].join(' ')}`; - const paramsStr = this.redact ? '' : params; - Logger.request(content, paramsStr); - Logger.info(content, paramsStr); + Logger.request(content, params); + Logger.info(content, params); this.httpRequest.on('error', err => this.onRequestError(err)); } diff --git a/lib/transport/selenium-webdriver/method-mappings.js b/lib/transport/selenium-webdriver/method-mappings.js index 2f8e588d21..bb9155735f 100644 --- a/lib/transport/selenium-webdriver/method-mappings.js +++ b/lib/transport/selenium-webdriver/method-mappings.js @@ -591,16 +591,9 @@ module.exports = class MethodMappings { }, setElementValueRedacted(webElementOrId, value) { - let redactedValue; - if (value instanceof Array) { - value.unshift(Key.NULL); - redactedValue = value; - } else { - // Can be String or number. - redactedValue = Key.NULL + value; - } + const modifiedValue = [Key.NULL].concat(value); - return this.methods.session.setElementValue.call(this, webElementOrId, redactedValue); + return this.methods.session.setElementValue.call(this, webElementOrId, modifiedValue); }, async setElementValue(webElementOrId, value) { From 2add8106a6ec16540bd8a66f0b165bd25c3d68b2 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Sat, 2 Mar 2024 15:06:19 +0530 Subject: [PATCH 10/18] added test for checking redacted values in reporter --- .../passwordValueRedacted.js | 17 ++++++++ .../api/commands/element/testSetPassword.js | 39 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 test/sampletests/checkValueRedacted/passwordValueRedacted.js diff --git a/test/sampletests/checkValueRedacted/passwordValueRedacted.js b/test/sampletests/checkValueRedacted/passwordValueRedacted.js new file mode 100644 index 0000000000..befcc2561e --- /dev/null +++ b/test/sampletests/checkValueRedacted/passwordValueRedacted.js @@ -0,0 +1,17 @@ +module.exports = { + before(client) { + client.globals.calls++; + }, + + demoTest(client) { + client + .url('http://localhost') + .setPassword('#weblogin', 'password') + .end(); + }, + + after(client, callback) { + client.globals.calls++; + callback(); + } +}; diff --git a/test/src/api/commands/element/testSetPassword.js b/test/src/api/commands/element/testSetPassword.js index 24c469b8b6..c774a8a1de 100644 --- a/test/src/api/commands/element/testSetPassword.js +++ b/test/src/api/commands/element/testSetPassword.js @@ -1,5 +1,9 @@ +const path = require('path'); const assert = require('assert'); const {Key} = require('selenium-webdriver'); +const common = require('../../../../common.js'); +const {settings} = common; +const NightwatchClient = common.require('index.js'); const MockServer = require('../../../../lib/mockserver.js'); const CommandGlobals = require('../../../../lib/globals/commands.js'); @@ -58,4 +62,39 @@ describe('setPassword', function() { this.client.start(done); }); + + it('client.setPassword() value hidden', async function() { + MockServer.addMock({ + url: '/wd/hub/session/1352110219202/element/0/value', + method: 'POST', + postdata: { + text: Key.NULL + 'password', + value: [Key.NULL, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] + }, + response: { + sessionId: '1352110219202', + status: 0 + } + }); + + const testsPath = [ + path.join(__dirname, '../../../../sampletests/checkValueRedacted/passwordValueRedacted.js') + ]; + + const globals = { + calls: 0, + waitForConditionTimeout: 10, + waitForConditionPollInterval: 10, + reporter(results) { + assert.strictEqual(globals.calls, 2); + const rawHttpOutput = results.modules.passwordValueRedacted.rawHttpOutput; + assert.strictEqual(rawHttpOutput[24][1], ' Request POST /wd/hub/session/1352110219202/element/0/value '); + assert.strictEqual(rawHttpOutput[24][2], '{ text: \'****\', value: [ \'*\', \'*\', \'*\', \'*\' ] }'); + } + }; + + await NightwatchClient.runTests(testsPath, settings({ + globals + })); + }); }); From ffcb5f8179423cbfd78502d8d10dce09d95abaf4 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Sat, 2 Mar 2024 15:09:02 +0530 Subject: [PATCH 11/18] updated test name --- test/src/api/commands/element/testSetPassword.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/api/commands/element/testSetPassword.js b/test/src/api/commands/element/testSetPassword.js index c774a8a1de..f670c8cf9e 100644 --- a/test/src/api/commands/element/testSetPassword.js +++ b/test/src/api/commands/element/testSetPassword.js @@ -63,7 +63,7 @@ describe('setPassword', function() { this.client.start(done); }); - it('client.setPassword() value hidden', async function() { + it('client.setPassword() value redacted in rawHttpOutput', async function() { MockServer.addMock({ url: '/wd/hub/session/1352110219202/element/0/value', method: 'POST', From 75382b7217dfaaf9b8b48a68a5c81b20a708d444 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Sat, 2 Mar 2024 17:58:14 +0530 Subject: [PATCH 12/18] updated tests --- .../passwordValueRedacted.js | 3 +- .../api/commands/element/testSetPassword.js | 35 ----------- .../element/testSetPasswordCheckReports.js | 62 +++++++++++++++++++ 3 files changed, 63 insertions(+), 37 deletions(-) create mode 100644 test/src/api/commands/element/testSetPasswordCheckReports.js diff --git a/test/sampletests/checkValueRedacted/passwordValueRedacted.js b/test/sampletests/checkValueRedacted/passwordValueRedacted.js index befcc2561e..e214313b9d 100644 --- a/test/sampletests/checkValueRedacted/passwordValueRedacted.js +++ b/test/sampletests/checkValueRedacted/passwordValueRedacted.js @@ -6,8 +6,7 @@ module.exports = { demoTest(client) { client .url('http://localhost') - .setPassword('#weblogin', 'password') - .end(); + .setPassword('#weblogin', 'password'); }, after(client, callback) { diff --git a/test/src/api/commands/element/testSetPassword.js b/test/src/api/commands/element/testSetPassword.js index f670c8cf9e..17036f7fdf 100644 --- a/test/src/api/commands/element/testSetPassword.js +++ b/test/src/api/commands/element/testSetPassword.js @@ -62,39 +62,4 @@ describe('setPassword', function() { this.client.start(done); }); - - it('client.setPassword() value redacted in rawHttpOutput', async function() { - MockServer.addMock({ - url: '/wd/hub/session/1352110219202/element/0/value', - method: 'POST', - postdata: { - text: Key.NULL + 'password', - value: [Key.NULL, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] - }, - response: { - sessionId: '1352110219202', - status: 0 - } - }); - - const testsPath = [ - path.join(__dirname, '../../../../sampletests/checkValueRedacted/passwordValueRedacted.js') - ]; - - const globals = { - calls: 0, - waitForConditionTimeout: 10, - waitForConditionPollInterval: 10, - reporter(results) { - assert.strictEqual(globals.calls, 2); - const rawHttpOutput = results.modules.passwordValueRedacted.rawHttpOutput; - assert.strictEqual(rawHttpOutput[24][1], ' Request POST /wd/hub/session/1352110219202/element/0/value '); - assert.strictEqual(rawHttpOutput[24][2], '{ text: \'****\', value: [ \'*\', \'*\', \'*\', \'*\' ] }'); - } - }; - - await NightwatchClient.runTests(testsPath, settings({ - globals - })); - }); }); diff --git a/test/src/api/commands/element/testSetPasswordCheckReports.js b/test/src/api/commands/element/testSetPasswordCheckReports.js new file mode 100644 index 0000000000..0f3514ea12 --- /dev/null +++ b/test/src/api/commands/element/testSetPasswordCheckReports.js @@ -0,0 +1,62 @@ +const path = require('path'); +const {Key} = require('selenium-webdriver'); +const common = require('../../../../common.js'); +const {settings} = common; +const NightwatchClient = common.require('index.js'); +const MockServer = require('../../../../lib/mockserver.js'); +const CommandGlobals = require('../../../../lib/globals/commands.js'); + +describe('setPassword', function() { + + before(function(done) { + CommandGlobals.beforeEach.call(this, done); + }); + + after(function(done) { + CommandGlobals.afterEach.call(this, done); + }); + + it('client.setPassword() value redacted in rawHttpOutput', async function() { + + MockServer.addMock({ + url: '/wd/hub/session/1352110219202/element/0/value', + method: 'POST', + postdata: { + text: Key.NULL + 'password', + value: [Key.NULL, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] + }, + response: { + sessionId: '1352110219202', + status: 0 + } + }); + + MockServer.addMock({ + url: '/wd/hub/session/1352110219202/element/0/clear', + method: 'POST', + response: { + sessionId: '1352110219202', + status: 0 + } + }); + + const testsPath = [ + path.join(__dirname, '../../../../sampletests/checkValueRedacted/passwordValueRedacted.js') + ]; + + const globals = { + calls: 0, + waitForConditionTimeout: 10, + waitForConditionPollInterval: 10, + reporter(results) { + const output = results.modules.passwordValueRedacted.rawHttpOutput; + console.log({output}); + } + }; + + await NightwatchClient.runTests(testsPath, settings({ + globals + })); + + }); +}); From 5ef08a4f7422ef31040fd0a84f2d02f3b2d2b1ad Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Sat, 2 Mar 2024 23:27:48 +0530 Subject: [PATCH 13/18] fixed tests --- .../passwordValueRedacted.js | 4 ++- .../element/testSetPasswordCheckReports.js | 30 +++++++++++++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/test/sampletests/checkValueRedacted/passwordValueRedacted.js b/test/sampletests/checkValueRedacted/passwordValueRedacted.js index e214313b9d..7bcd237409 100644 --- a/test/sampletests/checkValueRedacted/passwordValueRedacted.js +++ b/test/sampletests/checkValueRedacted/passwordValueRedacted.js @@ -6,7 +6,9 @@ module.exports = { demoTest(client) { client .url('http://localhost') - .setPassword('#weblogin', 'password'); + .setPassword('#weblogin', 'redacted_text') + .setValue('#weblogin', 'non_redacted') + .end(); }, after(client, callback) { diff --git a/test/src/api/commands/element/testSetPasswordCheckReports.js b/test/src/api/commands/element/testSetPasswordCheckReports.js index 0f3514ea12..93037e366f 100644 --- a/test/src/api/commands/element/testSetPasswordCheckReports.js +++ b/test/src/api/commands/element/testSetPasswordCheckReports.js @@ -1,3 +1,4 @@ +const assert = require('assert'); const path = require('path'); const {Key} = require('selenium-webdriver'); const common = require('../../../../common.js'); @@ -6,14 +7,17 @@ const NightwatchClient = common.require('index.js'); const MockServer = require('../../../../lib/mockserver.js'); const CommandGlobals = require('../../../../lib/globals/commands.js'); -describe('setPassword', function() { +describe('setPassword check', function() { before(function(done) { - CommandGlobals.beforeEach.call(this, done); + this.server = MockServer.init(); + this.server.on('listening', () => done()); }); after(function(done) { - CommandGlobals.afterEach.call(this, done); + this.server.close(function() { + done(); + }); }); it('client.setPassword() value redacted in rawHttpOutput', async function() { @@ -49,13 +53,27 @@ describe('setPassword', function() { waitForConditionTimeout: 10, waitForConditionPollInterval: 10, reporter(results) { - const output = results.modules.passwordValueRedacted.rawHttpOutput; - console.log({output}); + const rawHttpOutput = results.modules.passwordValueRedacted.rawHttpOutput; + const requests = rawHttpOutput.filter((req) => req[1].includes('/element/0/value') && req[1].includes('Request POST')); + let foundRedactedText = false; + let didNotFindNonRedactedText = true; + for (var request of requests) { + if (request[2].includes('redacted_text')) { + foundRedactedText = true; + } + if (request[2].includes('non_redacted')) { + didNotFindNonRedactedText = false; + } + } + assert.strictEqual(foundRedactedText, false); + assert.strictEqual(didNotFindNonRedactedText, false); + } }; await NightwatchClient.runTests(testsPath, settings({ - globals + globals, + output_folder: 'output' })); }); From 87fac0cfa216805670b78f34432d66952252fd9a Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 6 Mar 2024 21:30:48 +0530 Subject: [PATCH 14/18] removed extra imports --- test/src/api/commands/element/testSetPassword.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/src/api/commands/element/testSetPassword.js b/test/src/api/commands/element/testSetPassword.js index 17036f7fdf..24c469b8b6 100644 --- a/test/src/api/commands/element/testSetPassword.js +++ b/test/src/api/commands/element/testSetPassword.js @@ -1,9 +1,5 @@ -const path = require('path'); const assert = require('assert'); const {Key} = require('selenium-webdriver'); -const common = require('../../../../common.js'); -const {settings} = common; -const NightwatchClient = common.require('index.js'); const MockServer = require('../../../../lib/mockserver.js'); const CommandGlobals = require('../../../../lib/globals/commands.js'); From dc57b37f01a237410f05b77931e58dd0d87e1ad5 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 6 Mar 2024 21:35:53 +0530 Subject: [PATCH 15/18] imporve tests [wip] --- .../passwordValueRedacted.js | 9 ----- .../element/testSetPasswordCheckReports.js | 34 +++++++++++++------ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/test/sampletests/checkValueRedacted/passwordValueRedacted.js b/test/sampletests/checkValueRedacted/passwordValueRedacted.js index 7bcd237409..d93bb33630 100644 --- a/test/sampletests/checkValueRedacted/passwordValueRedacted.js +++ b/test/sampletests/checkValueRedacted/passwordValueRedacted.js @@ -1,18 +1,9 @@ module.exports = { - before(client) { - client.globals.calls++; - }, - demoTest(client) { client .url('http://localhost') .setPassword('#weblogin', 'redacted_text') .setValue('#weblogin', 'non_redacted') .end(); - }, - - after(client, callback) { - client.globals.calls++; - callback(); } }; diff --git a/test/src/api/commands/element/testSetPasswordCheckReports.js b/test/src/api/commands/element/testSetPasswordCheckReports.js index 93037e366f..5d2367120a 100644 --- a/test/src/api/commands/element/testSetPasswordCheckReports.js +++ b/test/src/api/commands/element/testSetPasswordCheckReports.js @@ -22,25 +22,27 @@ describe('setPassword check', function() { it('client.setPassword() value redacted in rawHttpOutput', async function() { + let sendKeysRedactedMockCalled = false; + let globalReporterCalled = false; + MockServer.addMock({ - url: '/wd/hub/session/1352110219202/element/0/value', + url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/clear', method: 'POST', - postdata: { - text: Key.NULL + 'password', - value: [Key.NULL, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'] - }, + statusCode: 200, response: { - sessionId: '1352110219202', - status: 0 + value: null } }); MockServer.addMock({ - url: '/wd/hub/session/1352110219202/element/0/clear', + url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/value', method: 'POST', + postdata: {text: 'password', value: ['p', 'a', 's', 's', 'w', 'o', 'r', 'd']}, response: { - sessionId: '1352110219202', - status: 0 + value: null + }, + onRequest: () => { + sendKeysRedactedMockCalled = true; } }); @@ -53,10 +55,17 @@ describe('setPassword check', function() { waitForConditionTimeout: 10, waitForConditionPollInterval: 10, reporter(results) { + globalReporterCalled = true; + + assert.strictEqual(sendKeysRedactedMockCalled, true); + assert.strictEqual(results.errmessages, []); + const rawHttpOutput = results.modules.passwordValueRedacted.rawHttpOutput; const requests = rawHttpOutput.filter((req) => req[1].includes('/element/0/value') && req[1].includes('Request POST')); + let foundRedactedText = false; let didNotFindNonRedactedText = true; + for (var request of requests) { if (request[2].includes('redacted_text')) { foundRedactedText = true; @@ -73,8 +82,11 @@ describe('setPassword check', function() { await NightwatchClient.runTests(testsPath, settings({ globals, - output_folder: 'output' + output_folder: 'output', + selenium_host: null, + output: true })); + assert.strictEqual(globalReporterCalled, true); }); }); From 9ad5d68ae6a1aa07a9b487d389e95de41976f225 Mon Sep 17 00:00:00 2001 From: Aniket Singh Rawat Date: Wed, 6 Mar 2024 22:44:32 +0530 Subject: [PATCH 16/18] fixed tests --- .../passwordValueRedacted.js | 16 +++--- .../element/testSetPasswordCheckReports.js | 52 +++++++++++++++---- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/test/sampletests/checkValueRedacted/passwordValueRedacted.js b/test/sampletests/checkValueRedacted/passwordValueRedacted.js index d93bb33630..ea522a1134 100644 --- a/test/sampletests/checkValueRedacted/passwordValueRedacted.js +++ b/test/sampletests/checkValueRedacted/passwordValueRedacted.js @@ -1,9 +1,7 @@ -module.exports = { - demoTest(client) { - client - .url('http://localhost') - .setPassword('#weblogin', 'redacted_text') - .setValue('#weblogin', 'non_redacted') - .end(); - } -}; +describe('Aniket', function() { + test('test setpassword', async browser => { + browser + .setPassword('#weblogin', 'password') + .setValue('#weblogin', 'simpletext'); + }); +}); \ No newline at end of file diff --git a/test/src/api/commands/element/testSetPasswordCheckReports.js b/test/src/api/commands/element/testSetPasswordCheckReports.js index 5d2367120a..3a9cf930d1 100644 --- a/test/src/api/commands/element/testSetPasswordCheckReports.js +++ b/test/src/api/commands/element/testSetPasswordCheckReports.js @@ -2,10 +2,10 @@ const assert = require('assert'); const path = require('path'); const {Key} = require('selenium-webdriver'); const common = require('../../../../common.js'); +const Mocks = require('../../../../lib/command-mocks.js'); const {settings} = common; const NightwatchClient = common.require('index.js'); const MockServer = require('../../../../lib/mockserver.js'); -const CommandGlobals = require('../../../../lib/globals/commands.js'); describe('setPassword check', function() { @@ -25,6 +25,10 @@ describe('setPassword check', function() { let sendKeysRedactedMockCalled = false; let globalReporterCalled = false; + Mocks.createNewW3CSession({ + testName: 'Actions API demo tests' + }); + MockServer.addMock({ url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/clear', method: 'POST', @@ -37,7 +41,28 @@ describe('setPassword check', function() { MockServer.addMock({ url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/value', method: 'POST', - postdata: {text: 'password', value: ['p', 'a', 's', 's', 'w', 'o', 'r', 'd']}, + postdata: {text: Key.NULL + 'password', value: [Key.NULL, 'p', 'a', 's', 's', 'w', 'o', 'r', 'd']}, + response: { + value: null + }, + onRequest: () => { + sendKeysRedactedMockCalled = true; + } + }); + + MockServer.addMock({ + url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/clear', + method: 'POST', + statusCode: 200, + response: { + value: null + } + }); + + MockServer.addMock({ + url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/value', + method: 'POST', + postdata: {text: 'simpletext', value: ['s', 'i', 'm', 'p', 'l', 'e', 't', 'e', 'x', 't']}, response: { value: null }, @@ -58,24 +83,30 @@ describe('setPassword check', function() { globalReporterCalled = true; assert.strictEqual(sendKeysRedactedMockCalled, true); - assert.strictEqual(results.errmessages, []); + assert.strictEqual(results.errmessages.length, 0); const rawHttpOutput = results.modules.passwordValueRedacted.rawHttpOutput; - const requests = rawHttpOutput.filter((req) => req[1].includes('/element/0/value') && req[1].includes('Request POST')); + const requests = rawHttpOutput.filter((req) => req[1].includes('element/5cc459b8-36a8-3042-8b4a-258883ea642b/value') && req[1].includes('Request POST')); + + // There are two calls in passwordValueRedacted.js test, setPassword('password') & setValue('simpletext') + // We first filter out the https requests that can contain these values as logs. Then we check these logs for our values. + // There are two flags: + // `foundRedactedText` which tracks if any redacted text is present in the log. So the value should be false only. + // `foundNonRedactedText` tracks that the non redacted values SHOULD be present in the logs. So the value should become true. let foundRedactedText = false; - let didNotFindNonRedactedText = true; + let foundNonRedactedText = false; for (var request of requests) { - if (request[2].includes('redacted_text')) { + if (request[2].includes('password')) { foundRedactedText = true; } - if (request[2].includes('non_redacted')) { - didNotFindNonRedactedText = false; + if (request[2].includes('simpletext')) { + foundNonRedactedText = true; } } assert.strictEqual(foundRedactedText, false); - assert.strictEqual(didNotFindNonRedactedText, false); + assert.strictEqual(foundNonRedactedText, true); } }; @@ -83,8 +114,7 @@ describe('setPassword check', function() { await NightwatchClient.runTests(testsPath, settings({ globals, output_folder: 'output', - selenium_host: null, - output: true + selenium_host: null })); assert.strictEqual(globalReporterCalled, true); From f9653216840dd6f3182c0200da9fef675e9335a6 Mon Sep 17 00:00:00 2001 From: Priyansh Garg Date: Thu, 7 Mar 2024 18:09:11 +0530 Subject: [PATCH 17/18] Some refactors. --- lib/http/request.js | 9 ++- .../passwordValueRedacted.js | 7 -- .../passwordValueRedacted.js | 7 ++ ...eckReports.js => testSetPasswordReport.js} | 72 +++++++------------ 4 files changed, 38 insertions(+), 57 deletions(-) delete mode 100644 test/sampletests/checkValueRedacted/passwordValueRedacted.js create mode 100644 test/sampletests/passwordValueRedacted/passwordValueRedacted.js rename test/src/api/commands/element/{testSetPasswordCheckReports.js => testSetPasswordReport.js} (53%) diff --git a/lib/http/request.js b/lib/http/request.js index 8625ba2dfa..37f4fb00e0 100644 --- a/lib/http/request.js +++ b/lib/http/request.js @@ -3,6 +3,7 @@ const http = require('http'); const https = require('https'); const dns = require('dns'); const path = require('path'); +const {Key} = require('selenium-webdriver'); const HttpUtil = require('./http.js'); const HttpOptions = require('./options.js'); @@ -10,7 +11,6 @@ const Auth = require('./auth.js'); const Formatter = require('./formatter.js'); const HttpResponse = require('./response.js'); const Utils = require('./../utils'); -const {Key} = require('selenium-webdriver'); const {Logger, isString} = Utils; const {DEFAULT_RUNNER_EVENTS: {LogCreated}, NightwatchEventHub} = require('../runner/eventHub.js'); @@ -253,10 +253,9 @@ class HttpRequest extends EventEmitter { return arg; }); - } else if (this.reqOptions.method === 'POST' && - this.reqOptions.path.includes('/value') && params.text.startsWith(Key.NULL)) { - params.text = '****'; - params.value = '****'.split(''); + } else if (this.reqOptions.method === 'POST' && this.reqOptions.path.endsWith('/value') && params.text.startsWith(Key.NULL)) { + params.text = '*******'; + params.value = '*******'.split(''); } const content = ` Request ${[this.reqOptions.method, this.hostname + this.reqOptions.path, retryStr + ' '].join(' ')}`; diff --git a/test/sampletests/checkValueRedacted/passwordValueRedacted.js b/test/sampletests/checkValueRedacted/passwordValueRedacted.js deleted file mode 100644 index ea522a1134..0000000000 --- a/test/sampletests/checkValueRedacted/passwordValueRedacted.js +++ /dev/null @@ -1,7 +0,0 @@ -describe('Aniket', function() { - test('test setpassword', async browser => { - browser - .setPassword('#weblogin', 'password') - .setValue('#weblogin', 'simpletext'); - }); -}); \ No newline at end of file diff --git a/test/sampletests/passwordValueRedacted/passwordValueRedacted.js b/test/sampletests/passwordValueRedacted/passwordValueRedacted.js new file mode 100644 index 0000000000..cd8d71a97c --- /dev/null +++ b/test/sampletests/passwordValueRedacted/passwordValueRedacted.js @@ -0,0 +1,7 @@ +describe('value redaction in setPassword', function() { + test('test setPassword', async browser => { + browser + .setPassword('#weblogin', 'password') + .setValue('#weblogin', 'simpletext'); + }); +}); diff --git a/test/src/api/commands/element/testSetPasswordCheckReports.js b/test/src/api/commands/element/testSetPasswordReport.js similarity index 53% rename from test/src/api/commands/element/testSetPasswordCheckReports.js rename to test/src/api/commands/element/testSetPasswordReport.js index 3a9cf930d1..c0adb73578 100644 --- a/test/src/api/commands/element/testSetPasswordCheckReports.js +++ b/test/src/api/commands/element/testSetPasswordReport.js @@ -7,8 +7,7 @@ const {settings} = common; const NightwatchClient = common.require('index.js'); const MockServer = require('../../../../lib/mockserver.js'); -describe('setPassword check', function() { - +describe('setPassword report check', function() { before(function(done) { this.server = MockServer.init(); this.server.on('listening', () => done()); @@ -21,8 +20,8 @@ describe('setPassword check', function() { }); it('client.setPassword() value redacted in rawHttpOutput', async function() { - - let sendKeysRedactedMockCalled = false; + let sendKeysPasswordMockCalled = false; + let sendKeysNormalMockCalled = false; let globalReporterCalled = false; Mocks.createNewW3CSession({ @@ -35,7 +34,8 @@ describe('setPassword check', function() { statusCode: 200, response: { value: null - } + }, + times: 2 }); MockServer.addMock({ @@ -46,18 +46,9 @@ describe('setPassword check', function() { value: null }, onRequest: () => { - sendKeysRedactedMockCalled = true; - } - }); - - MockServer.addMock({ - url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/clear', - method: 'POST', - statusCode: 200, - response: { - value: null + sendKeysPasswordMockCalled = true; } - }); + }, true); MockServer.addMock({ url: '/session/13521-10219-202/element/5cc459b8-36a8-3042-8b4a-258883ea642b/value', @@ -67,47 +58,38 @@ describe('setPassword check', function() { value: null }, onRequest: () => { - sendKeysRedactedMockCalled = true; + sendKeysNormalMockCalled = true; } - }); + }, true); const testsPath = [ - path.join(__dirname, '../../../../sampletests/checkValueRedacted/passwordValueRedacted.js') + path.join(__dirname, '../../../../sampletests/passwordvalueRedacted/passwordValueRedacted.js') ]; const globals = { - calls: 0, - waitForConditionTimeout: 10, - waitForConditionPollInterval: 10, reporter(results) { globalReporterCalled = true; - assert.strictEqual(sendKeysRedactedMockCalled, true); + assert.strictEqual(sendKeysPasswordMockCalled, true); + assert.strictEqual(sendKeysNormalMockCalled, true); assert.strictEqual(results.errmessages.length, 0); const rawHttpOutput = results.modules.passwordValueRedacted.rawHttpOutput; - const requests = rawHttpOutput.filter((req) => req[1].includes('element/5cc459b8-36a8-3042-8b4a-258883ea642b/value') && req[1].includes('Request POST')); - - // There are two calls in passwordValueRedacted.js test, setPassword('password') & setValue('simpletext') - // We first filter out the https requests that can contain these values as logs. Then we check these logs for our values. - // There are two flags: - // `foundRedactedText` which tracks if any redacted text is present in the log. So the value should be false only. - // `foundNonRedactedText` tracks that the non redacted values SHOULD be present in the logs. So the value should become true. - - let foundRedactedText = false; - let foundNonRedactedText = false; - - for (var request of requests) { - if (request[2].includes('password')) { - foundRedactedText = true; - } - if (request[2].includes('simpletext')) { - foundNonRedactedText = true; - } - } - assert.strictEqual(foundRedactedText, false); - assert.strictEqual(foundNonRedactedText, true); - + const requests = rawHttpOutput + .filter((req) => { + return req[1].includes('element/5cc459b8-36a8-3042-8b4a-258883ea642b/value') && + req[1].includes('Request POST'); + }); + + assert.strictEqual(requests.length, 2); + + // First request (setPassword) should contain redacted value + assert.strictEqual(requests[0][2].includes('password'), false); + assert.strictEqual(requests[0][2].includes('*******'), true); + + // Second request (setValue) should NOT contain redacted value + assert.strictEqual(requests[1][2].includes('simpletext'), true); + assert.strictEqual(requests[1][2].includes('*******'), false); } }; From 60eb36f0a1670b315e9e4dfd3213e01307e1957c Mon Sep 17 00:00:00 2001 From: Priyansh Garg Date: Thu, 7 Mar 2024 18:18:34 +0530 Subject: [PATCH 18/18] Fix test. --- test/src/api/commands/element/testSetPasswordReport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/api/commands/element/testSetPasswordReport.js b/test/src/api/commands/element/testSetPasswordReport.js index c0adb73578..68a95e8bea 100644 --- a/test/src/api/commands/element/testSetPasswordReport.js +++ b/test/src/api/commands/element/testSetPasswordReport.js @@ -63,7 +63,7 @@ describe('setPassword report check', function() { }, true); const testsPath = [ - path.join(__dirname, '../../../../sampletests/passwordvalueRedacted/passwordValueRedacted.js') + path.join(__dirname, '../../../../sampletests/passwordValueRedacted/passwordValueRedacted.js') ]; const globals = {