This commit is contained in:
anseki 2014-07-13 13:55:17 +09:00
parent 8d9aca03f8
commit eeb0770459
4 changed files with 46 additions and 14 deletions

View file

@ -40,7 +40,7 @@ line = readlineSync.prompt([options])
```
Readies readline for input from the user, putting the current `setPrompt` options on a new line, giving the user a new spot to write.
If `{noEchoBack: true}` is specified to `options`, echo back is avoided. It is used to hide the password which is typed by user on screen. *See [Note](#note) for security.*
If `{noEchoBack: true}` is specified to `options`, echo back is avoided. It is used to hide the password which is typed by user on screen.
### question
@ -50,7 +50,7 @@ line = readlineSync.question([query[, options]])
Displays the `query` to the user, and then returns the user's response after it has been typed.
`query` is converted to string (i.e. `toString` method is called) before it is displayed every time.
If `{noEchoBack: true}` is specified to `options`, echo back is avoided. It is used to hide the password which is typed by user on screen. *See [Note](#note) for security.*
If `{noEchoBack: true}` is specified to `options`, echo back is avoided. It is used to hide the password which is typed by user on screen.
### setEncoding
@ -104,9 +104,8 @@ try {
}
```
+ If `options.noEchoBack` is used, the text that input by user is saved to temporary file (e.g. `/tmp/readline-sync.stdout`). This file is removed immediately after reading is done, but you have to be careful about it because this text is *plain*. Removing the file might fail, or the file might be peeped before it is removed.
## Release History
* 2014-07-13 v0.4.3 fixed #6: Crypto input data.
* 2014-07-12 v0.4.2 `setPrompt()` and `setEncoding()` return current value.
* 2014-07-12 v0.4.1 `setPrompt()` and `question()` accept the value which is not string too (e.g. number, Date, Object, etc.).
* 2014-07-12 v0.4.0 Add `options.noEchoBack`.

16
lib/encrypt.js Normal file
View file

@ -0,0 +1,16 @@
var algorithmCipher = 'aes-256-cbc',
cipher = require('crypto').createCipher(algorithmCipher, process.argv[2]),
stdin = process.stdin,
stdout = process.stdout,
crypted = '';
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', function(d) {
crypted += cipher.update(d, 'utf8', 'hex');
});
stdin.on('end', function() {
stdout.write(crypted + cipher.final('hex'), 'binary', function() {
process.exit(0);
});
});

View file

@ -8,14 +8,18 @@
'use strict';
var promptText = '> ',
encoding = 'utf8',
var
BUF_SIZE = 256,
ALGORITHM_CIPHER = 'aes-256-cbc',
ALGORITHM_HASH = 'sha256',
promptText = '> ',
encoding = 'utf8',
fs = require('fs'),
stdin = process.stdin,
stdout = process.stdout,
buffer = new Buffer(BUF_SIZE),
useShell = true, print, tempdir;
useShell = true, print, tempdir, salt = 0;
function _readlineSync(display, options) {
var input = '', rsize, err;
@ -78,18 +82,29 @@ function _readlineShell(noEchoBack) {
pathStdout = getTempfile('readline-sync.stdout'),
pathStatus = getTempfile('readline-sync.status'),
pathDone = getTempfile('readline-sync.done'),
optEchoBack = noEchoBack ? ' noechoback' : '';
optEchoBack = noEchoBack ? ' noechoback' : '',
crypto = require('crypto'), shasum, decipher, password;
shasum = crypto.createHash(ALGORITHM_HASH);
shasum.update('' + process.pid + (salt++) + Math.random());
password = shasum.digest('hex');
decipher = crypto.createDecipher(ALGORITHM_CIPHER, password);
if (process.platform === 'win32') {
// The quote (") is escaped by node before parsed by shell. Then use ENV{Q}.
shellPath = 'cmd.exe';
args = ['/V:ON', '/S', '/C',
'%Q%' + __dirname + '\\read.bat%Q%' + optEchoBack + ' >%Q%' + pathStdout +
'%Q% & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q% & (echo 1)>%Q%' + pathDone + '%Q%'];
'%Q%' + __dirname + '\\read.bat%Q%' + optEchoBack +
' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q% %Q%' + password + '%Q%' +
' >%Q%' + pathStdout + '%Q%' +
' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q% & (echo 1)>%Q%' + pathDone + '%Q%'];
} else {
shellPath = '/bin/sh';
args = ['-c', '(' + shellPath + ' "' + __dirname + '/read.sh"' + optEchoBack + ') >"' + pathStdout +
'"; echo $? >"' + pathStatus + '"; echo 1 >"' + pathDone + '"'];
args = ['-c',
'(' + shellPath + ' "' + __dirname + '/read.sh"' + optEchoBack + ')' +
' |"' + process.execPath + '" "' + __dirname + '/encrypt.js" "' + password + '"' +
' >"' + pathStdout + '";' +
' echo $? >"' + pathStatus + '"; echo 1 >"' + pathDone + '"'];
}
stdin.pause(); // re-start in child process
@ -99,7 +114,9 @@ function _readlineShell(noEchoBack) {
if (fs.readFileSync(pathDone, {encoding: encoding}).trim() === '1') { break; }
}
if (fs.readFileSync(pathStatus, {encoding: encoding}).trim() === '0') {
shellStdout = fs.readFileSync(pathStdout, {encoding: encoding});
shellStdout =
decipher.update(fs.readFileSync(pathStdout, {encoding: 'binary'}), 'hex', encoding) +
decipher.final(encoding);
}
fs.unlinkSync(pathStdout);

View file

@ -1,7 +1,7 @@
{
"name": "readline-sync",
"description": "Synchronous Readline",
"version": "0.4.2",
"version": "0.4.3",
"homepage": "https://github.com/anseki/readline-sync",
"author": {
"name": "anseki"