1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | const chalk = require('chalk');
|
7 | const { map, takeUntil } = require('rxjs/operators');
|
8 | const Base = require('./base');
|
9 | const observe = require('../utils/events');
|
10 |
|
11 | function mask(input, maskChar) {
|
12 | input = String(input);
|
13 | maskChar = typeof maskChar === 'string' ? maskChar : '*';
|
14 | if (input.length === 0) {
|
15 | return '';
|
16 | }
|
17 |
|
18 | return new Array(input.length + 1).join(maskChar);
|
19 | }
|
20 |
|
21 | class PasswordPrompt extends Base {
|
22 | |
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | _run(cb) {
|
29 | this.done = cb;
|
30 |
|
31 | const events = observe(this.rl);
|
32 |
|
33 |
|
34 | const submit = events.line.pipe(map(this.filterInput.bind(this)));
|
35 |
|
36 | const validation = this.handleSubmitEvents(submit);
|
37 | validation.success.forEach(this.onEnd.bind(this));
|
38 | validation.error.forEach(this.onError.bind(this));
|
39 |
|
40 | events.keypress
|
41 | .pipe(takeUntil(validation.success))
|
42 | .forEach(this.onKeypress.bind(this));
|
43 |
|
44 |
|
45 | this.render();
|
46 |
|
47 | return this;
|
48 | }
|
49 |
|
50 | |
51 |
|
52 |
|
53 |
|
54 |
|
55 | render(error) {
|
56 | let message = this.getQuestion();
|
57 | let bottomContent = '';
|
58 |
|
59 | if (this.status === 'answered') {
|
60 | message += this.getMaskedValue(this.answer);
|
61 | } else {
|
62 | message += this.getMaskedValue(this.rl.line || '');
|
63 | }
|
64 |
|
65 | if (error) {
|
66 | bottomContent = '\n' + chalk.red('>> ') + error;
|
67 | }
|
68 |
|
69 | this.screen.render(message, bottomContent);
|
70 | }
|
71 |
|
72 | getMaskedValue(value) {
|
73 | if (this.status === 'answered') {
|
74 | return this.opt.mask
|
75 | ? chalk.cyan(mask(value, this.opt.mask))
|
76 | : chalk.italic.dim('[hidden]');
|
77 | }
|
78 | return this.opt.mask
|
79 | ? mask(value, this.opt.mask)
|
80 | : chalk.italic.dim('[input is hidden] ');
|
81 | }
|
82 |
|
83 | |
84 |
|
85 |
|
86 | getSpinningValue(value) {
|
87 | return this.getMaskedValue(value);
|
88 | }
|
89 |
|
90 | |
91 |
|
92 |
|
93 |
|
94 | filterInput(input) {
|
95 | if (!input) {
|
96 | return this.opt.default == null ? '' : this.opt.default;
|
97 | }
|
98 |
|
99 | return input;
|
100 | }
|
101 |
|
102 | onEnd(state) {
|
103 | this.status = 'answered';
|
104 | this.answer = state.value;
|
105 |
|
106 |
|
107 | this.render();
|
108 |
|
109 | this.screen.done();
|
110 | this.done(state.value);
|
111 | }
|
112 |
|
113 | onError(state) {
|
114 | this.render(state.isValid);
|
115 | }
|
116 |
|
117 | onKeypress() {
|
118 |
|
119 | if (this.opt.default) {
|
120 | this.opt.default = undefined;
|
121 | }
|
122 |
|
123 | this.render();
|
124 | }
|
125 | }
|
126 |
|
127 | module.exports = PasswordPrompt;
|