From e0197afd23d3b919f07beea3a2388f0d722733c6 Mon Sep 17 00:00:00 2001 From: Doug Owings Date: Mon, 13 Sep 2021 09:53:46 -0700 Subject: [PATCH] do not display password on async filter/validation, fixes #1022 (#1027) --- packages/inquirer/lib/prompts/base.js | 11 +++++ packages/inquirer/lib/prompts/password.js | 26 +++++++++--- .../inquirer/test/specs/prompts/password.js | 41 +++++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/packages/inquirer/lib/prompts/base.js b/packages/inquirer/lib/prompts/base.js index 5be5b4e81..8e096f0e5 100644 --- a/packages/inquirer/lib/prompts/base.js +++ b/packages/inquirer/lib/prompts/base.js @@ -130,6 +130,7 @@ class Prompt { } startSpinner(value, bottomContent) { + value = this.getSpinningValue(value); // If the question will spin, cut off the prefix (for layout purposes) const content = bottomContent ? this.getQuestion() + value @@ -138,6 +139,16 @@ class Prompt { this.screen.renderWithSpinner(content, bottomContent); } + /** + * Allow override, e.g. for password prompts + * See: https://github.com/SBoudrias/Inquirer.js/issues/1022 + * + * @return {String} value to display while spinning + */ + getSpinningValue(value) { + return value; + } + /** * Generate the prompt question string * @return {String} prompt question string diff --git a/packages/inquirer/lib/prompts/password.js b/packages/inquirer/lib/prompts/password.js index 53cda78a0..840249d31 100644 --- a/packages/inquirer/lib/prompts/password.js +++ b/packages/inquirer/lib/prompts/password.js @@ -57,13 +57,9 @@ class PasswordPrompt extends Base { let bottomContent = ''; if (this.status === 'answered') { - message += this.opt.mask - ? chalk.cyan(mask(this.answer, this.opt.mask)) - : chalk.italic.dim('[hidden]'); - } else if (this.opt.mask) { - message += mask(this.rl.line || '', this.opt.mask); + message += this.getMaskedValue(this.answer); } else { - message += chalk.italic.dim('[input is hidden] '); + message += this.getMaskedValue(this.rl.line || ''); } if (error) { @@ -73,6 +69,24 @@ class PasswordPrompt extends Base { this.screen.render(message, bottomContent); } + getMaskedValue(value) { + if (this.status === 'answered') { + return this.opt.mask + ? chalk.cyan(mask(value, this.opt.mask)) + : chalk.italic.dim('[hidden]'); + } + return this.opt.mask + ? mask(value, this.opt.mask) + : chalk.italic.dim('[input is hidden] '); + } + + /** + * Mask value during async filter/validation. + */ + getSpinningValue(value) { + return this.getMaskedValue(value); + } + /** * When user press `enter` key */ diff --git a/packages/inquirer/test/specs/prompts/password.js b/packages/inquirer/test/specs/prompts/password.js index 53be58beb..0e7b417e6 100644 --- a/packages/inquirer/test/specs/prompts/password.js +++ b/packages/inquirer/test/specs/prompts/password.js @@ -66,4 +66,45 @@ describe('`password` prompt', () => { this.rl.emit('line', ''); return promise; }); + + // See: https://github.com/SBoudrias/Inquirer.js/issues/1022 + it('should not display input during async validation', function () { + let output = ''; + let renderCount = 0; + + this.fixture.validate = () => + new Promise((resolve) => { + const id = setInterval(() => { + // Make sure we render at least once. + if (renderCount > 1) { + clearInterval(id); + resolve(true); + } + }, 10); + }); + + const password = new Password(this.fixture, this.rl); + const input = 'wvAq82yVujm5S9pf'; + + // Override screen.render to capture all output + const { screen } = password; + const { render } = screen; + screen.render = (...args) => { + output += stripAnsi(args.join('')); + renderCount += 1; + return render.call(screen, ...args); + }; + + /* This test should fail if you uncomment this line: */ + // password.getSpinningValue = (value) => value; + + const promise = password.run().then((answer) => { + expect(output).to.not.contain(input); + expect(answer).to.equal(input); + }); + + this.rl.emit('line', input); + + return promise; + }); });