Skip to content

Commit

Permalink
do not display password on async filter/validation, fixes #1022 (#1027)
Browse files Browse the repository at this point in the history
  • Loading branch information
owings1 authored Sep 13, 2021
1 parent 12b6934 commit e0197af
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
11 changes: 11 additions & 0 deletions packages/inquirer/lib/prompts/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
26 changes: 20 additions & 6 deletions packages/inquirer/lib/prompts/password.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
*/
Expand Down
41 changes: 41 additions & 0 deletions packages/inquirer/test/specs/prompts/password.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
});

0 comments on commit e0197af

Please sign in to comment.