fixed #14 Replace BAT with WSH
This commit is contained in:
parent
2d29dc0c8a
commit
8e141597ba
5 changed files with 184 additions and 135 deletions
|
@ -1,10 +0,0 @@
|
|||
process.stdout.write(decodeDOS(process.argv[2] /*text*/ || ''),
|
||||
process.env.RLS_ENCODING || 'binary', function() {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
function decodeDOS(arg) {
|
||||
return arg.replace(/#(\d+);/g, function(str, charCode) {
|
||||
return String.fromCharCode(+charCode);
|
||||
});
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*jshint wsh:true */
|
||||
|
||||
var oExec;
|
||||
|
||||
// exit-code is not returned even if an error is thrown.
|
||||
try {
|
||||
WScript.StdOut.Write(WScript.CreateObject('ScriptPW.Password').GetPassword()
|
||||
// Bug? Illegal data may be returned when user types before initializing.
|
||||
.replace(/[\u4000-\u40FF]/g, function(chr) {
|
||||
var charCode = chr.charCodeAt(0);
|
||||
return charCode >= 0x4020 && charCode <= 0x407F ?
|
||||
String.fromCharCode(charCode - 0x4000) : '';
|
||||
}));
|
||||
} catch (e) {
|
||||
WScript.StdErr.Write(e.description);
|
||||
WScript.Quit(1);
|
||||
}
|
||||
|
||||
oExec = WScript.CreateObject('WScript.Shell').Exec('cmd /c echo; >CON');
|
||||
while (oExec.Status === 0) { WScript.Sleep(100); }
|
68
lib/read.bat
68
lib/read.bat
|
@ -1,68 +0,0 @@
|
|||
@echo off
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
|
||||
:args_loop
|
||||
if "%~1"=="" (
|
||||
goto args_end
|
||||
|
||||
) else if "%~1"=="--noechoback" (
|
||||
set noechoback=1
|
||||
|
||||
) else if "%~1"=="--keyin" (
|
||||
set keyin=1
|
||||
|
||||
) else if "%~1"=="--display" (
|
||||
set "display=%~2"
|
||||
shift /1
|
||||
|
||||
)
|
||||
shift /1
|
||||
goto args_loop
|
||||
:args_end
|
||||
|
||||
:: type tmpfile.txt >CON
|
||||
if "%display%" NEQ "" if "%NODE_EXEC_PATH%" NEQ "" (
|
||||
"%NODE_EXEC_PATH%" "%~dp0decodedos.js" "%display%" >CON
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
)
|
||||
|
||||
if "%noechoback%"=="1" (
|
||||
call :read_s
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
) else (
|
||||
set /p input=<CON >CON
|
||||
)
|
||||
set /p ="'%input%'"<NUL
|
||||
|
||||
endlocal
|
||||
exit /b 0
|
||||
|
||||
:: Silent Read
|
||||
:read_s
|
||||
|
||||
:: where /q powershell
|
||||
:: Win <Vista and <Server2008 don't have `where`.
|
||||
powershell /? >NUL 2>&1
|
||||
:: Win <7 and <Server2008R2 don't have PowerShell as default.
|
||||
:: Win XP and Server2003 have `ScriptPW` (`scriptpw.dll`).
|
||||
:: In the systems that don't have both, an error is thrown.
|
||||
if ERRORLEVEL 1 (
|
||||
set "exec_line=cscript //nologo "%~dp0read-s.cs.js""
|
||||
) else (
|
||||
set "exec_line=powershell -Command "$text = read-host -AsSecureString; ^
|
||||
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR^($text^); ^
|
||||
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto^($BSTR^)""
|
||||
)
|
||||
|
||||
:: Can't get `ERRORLEVEL` from sub-shell.
|
||||
:: 2 `%ERRCODE%` lines are returned if an error is thrown.
|
||||
set ERRCODE=ERR
|
||||
set "exec_line=%exec_line% ^& if ERRORLEVEL 1 ^(echo %ERRCODE%^& echo %ERRCODE%^)"
|
||||
:: echo %exec_line%
|
||||
|
||||
for /f "usebackq delims=" %%i in (`%exec_line%`) do (
|
||||
if "%%i"=="%ERRCODE%" if "!input!"=="%ERRCODE%" exit /b 1
|
||||
set "input=%%i"
|
||||
)
|
||||
|
||||
exit /b 0
|
148
lib/read.cs.js
Normal file
148
lib/read.cs.js
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*jshint wsh:true */
|
||||
|
||||
var
|
||||
FSO_ForReading = 1, FSO_ForWriting = 2,
|
||||
|
||||
fso, tty, shell,
|
||||
args =// Array.prototype.slice.call(WScript.Arguments),
|
||||
(function() {
|
||||
var args = [], i, iLen;
|
||||
for (i = 0, iLen = WScript.Arguments.length; i < iLen; i++) {
|
||||
args.push(WScript.Arguments(i));
|
||||
}
|
||||
return args;
|
||||
})(),
|
||||
arg, options = {};
|
||||
|
||||
while (typeof(arg = args.shift()) === 'string') {
|
||||
if (arg === '--noechoback') {
|
||||
options.noEchoBack = true;
|
||||
} else if (arg === '--keyin') {
|
||||
options.keyIn = true;
|
||||
} else if (arg === '--display') {
|
||||
options.display = args.shift();
|
||||
} else if (arg === '--encoded') {
|
||||
options.encoded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof(options.display) === 'string' && options.display !== '') {
|
||||
ttyWrite(options.encoded ? decodeDOS(options.display) : options.display);
|
||||
}
|
||||
|
||||
WScript.StdOut.Write("'" + (options.noEchoBack ? readS() : ttyRead()) + "'");
|
||||
|
||||
WScript.Quit();
|
||||
|
||||
function ttyRead() {
|
||||
var text;
|
||||
try {
|
||||
text = getFso().OpenTextFile('CONIN$', FSO_ForReading).ReadLine();
|
||||
} catch (e) {
|
||||
WScript.StdErr.WriteLine('TTY Read Error: ' + e.number +
|
||||
'\n' + e.description);
|
||||
WScript.Quit(1);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function ttyWrite(text) {
|
||||
try {
|
||||
tty = tty || getFso().OpenTextFile('CONOUT$', FSO_ForWriting, true);
|
||||
tty.Write(text);
|
||||
} catch (e) {
|
||||
WScript.StdErr.WriteLine('TTY Write Error: ' + e.number +
|
||||
'\n' + e.description);
|
||||
WScript.Quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function getFso() {
|
||||
if (!fso) { fso = new ActiveXObject('Scripting.FileSystemObject'); }
|
||||
return fso;
|
||||
}
|
||||
|
||||
function readS() {
|
||||
var pw;
|
||||
shellExec('powershell /?', function(exitCode, stdout, stderr, error) {
|
||||
if (error || exitCode !== 0) {
|
||||
pw = scriptPW();
|
||||
} else {
|
||||
shellExec('powershell -Command "$text = read-host -AsSecureString;' +
|
||||
'$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($text);' +
|
||||
'[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)"',
|
||||
function(exitCode, stdout, stderr, error) {
|
||||
if (error || exitCode !== 0) {
|
||||
WScript.StdErr.WriteLine('Windows PowerShell Error: ' + exitCode +
|
||||
(error && error.description ? '\n' + error.description : '') +
|
||||
(stderr ? '\n' + stderr : '') +
|
||||
(stdout ? '\n' + stdout : ''));
|
||||
WScript.Quit(1);
|
||||
}
|
||||
pw = stdout.replace(/[\r\n]+$/, '');
|
||||
});
|
||||
}
|
||||
});
|
||||
return pw;
|
||||
}
|
||||
|
||||
function scriptPW() {
|
||||
var pw;
|
||||
// exit-code is not returned even if an error is thrown.
|
||||
try {
|
||||
pw = WScript.CreateObject('ScriptPW.Password').GetPassword()
|
||||
// Bug? Illegal data may be returned when user types before initializing.
|
||||
.replace(/[\u4000-\u40FF]/g, function(chr) {
|
||||
var charCode = chr.charCodeAt(0);
|
||||
return charCode >= 0x4020 && charCode <= 0x407F ?
|
||||
String.fromCharCode(charCode - 0x4000) : '';
|
||||
});
|
||||
} catch (e) {
|
||||
WScript.StdErr.WriteLine('ScriptPW.Password Error: ' + e.number +
|
||||
'\n' + e.description);
|
||||
WScript.Quit(1);
|
||||
}
|
||||
ttyWrite('\n');
|
||||
return pw;
|
||||
}
|
||||
|
||||
function shellExec(cmd, callback) { // callback(exitCode, stdout, stderr, error)
|
||||
var wsExec, stdout = '', stderr = '', noOutput;
|
||||
|
||||
function getShell() {
|
||||
if (!shell) { shell = WScript.CreateObject('WScript.Shell'); }
|
||||
return shell;
|
||||
}
|
||||
|
||||
try {
|
||||
wsExec = getShell().Exec(cmd);
|
||||
} catch (e) {
|
||||
callback(e.number, stdout, stderr, e);
|
||||
return wsExec;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
noOutput = true;
|
||||
if (!wsExec.StdOut.AtEndOfStream) {
|
||||
stdout += wsExec.StdOut.ReadAll();
|
||||
noOutput = false;
|
||||
}
|
||||
if (!wsExec.StdErr.AtEndOfStream) {
|
||||
stderr += wsExec.StdErr.ReadAll();
|
||||
noOutput = false;
|
||||
}
|
||||
if (noOutput) {
|
||||
if (wsExec.Status === 1 /*WshFinished*/) { break; }
|
||||
WScript.Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
callback(wsExec.ExitCode, stdout, stderr);
|
||||
return wsExec;
|
||||
}
|
||||
|
||||
function decodeDOS(arg) {
|
||||
return arg.replace(/#(\d+);/g, function(str, charCode) {
|
||||
return String.fromCharCode(+charCode);
|
||||
});
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
var
|
||||
IS_WIN = process.platform === 'win32',
|
||||
SHELL_PATH = IS_WIN ? process.env.ComSpec || 'cmd.exe' : '/bin/sh',
|
||||
SHELL_CMD = __dirname + (IS_WIN ? '\\read.bat' : '/read.sh'),
|
||||
SHELL_PATH = IS_WIN ? 'cscript.exe' : '/bin/sh',
|
||||
SHELL_CMD = __dirname + (IS_WIN ? '\\read.cs.js' : '/read.sh'),
|
||||
ALGORITHM_CIPHER = 'aes-256-cbc',
|
||||
ALGORITHM_HASH = 'sha256',
|
||||
DEFAULT_ERR_MSG = 'The platform doesn\'t support interactive reading',
|
||||
|
@ -31,7 +31,7 @@ function _readlineSync(options) { // options.display is string
|
|||
if (options.display !== '' && typeof print === 'function')
|
||||
{ print(options.display, encoding); }
|
||||
|
||||
if (useShell || options.noEchoBack) {
|
||||
if (useShell || options.noEchoBack || options.keyIn) {
|
||||
res = _readlineShell(options);
|
||||
if (res.error) { throw res.error; }
|
||||
input = res.input;
|
||||
|
@ -129,7 +129,7 @@ function _readlineShell(options) {
|
|||
var cmdArgs = [], execArgs, res = {},
|
||||
execOptions = {
|
||||
env: process.env,
|
||||
// ScriptPW (Win XP and Server2003) for `noEchoBack` needs TTY stream.
|
||||
// ScriptPW (Win XP and Server2003) needs TTY stream as STDIN.
|
||||
// In this case, If STDIN isn't TTY, an error is thrown.
|
||||
stdio: [process.stdin],
|
||||
encoding: encoding
|
||||
|
@ -142,28 +142,15 @@ function _readlineShell(options) {
|
|||
});
|
||||
}
|
||||
|
||||
if (options.noEchoBack) { cmdArgs.push('--noechoback'); }
|
||||
if (options.keyIn) { cmdArgs.push('--keyin'); }
|
||||
else if (options.noEchoBack) { cmdArgs.push('--noechoback'); }
|
||||
if (options.display !== '') {
|
||||
if (IS_WIN) {
|
||||
cmdArgs.push('--display', encodeDOS(options.display));
|
||||
process.env.NODE_EXEC_PATH = process.execPath;
|
||||
process.env.RLS_ENCODING = encoding;
|
||||
} else {
|
||||
cmdArgs.push('--display', options.display);
|
||||
}
|
||||
cmdArgs = cmdArgs.concat('--display', IS_WIN ?
|
||||
[encodeDOS(options.display), '--encoded'] : options.display);
|
||||
}
|
||||
|
||||
if (childProc.execFileSync) {
|
||||
if (IS_WIN) {
|
||||
process.env.Q = '"'; // The quote (") that isn't escaped.
|
||||
execArgs = ['/V:ON', '/S', '/C',
|
||||
'%Q%' + SHELL_CMD + '%Q%' +
|
||||
cmdArgs.map(function(arg) { return ' %Q%' + arg + '%Q%'; }).join('') +
|
||||
' & exit !ERRORLEVEL!'];
|
||||
} else {
|
||||
execArgs = [SHELL_CMD].concat(cmdArgs);
|
||||
}
|
||||
execArgs = (IS_WIN ? ['//nologo', SHELL_CMD] : [SHELL_CMD]).concat(cmdArgs);
|
||||
try {
|
||||
res.input = childProc.execFileSync(SHELL_PATH, execArgs, execOptions);
|
||||
} catch (e) { // non-zero exit code
|
||||
|
@ -176,8 +163,10 @@ function _readlineShell(options) {
|
|||
} else {
|
||||
res = _execSyncByFile(cmdArgs, execOptions);
|
||||
}
|
||||
if (!res.error) { res.input = res.input.replace(/^'|'$/g, ''); }
|
||||
options.display = '';
|
||||
if (!res.error) {
|
||||
res.input = res.input.replace(/^'|'$/g, '');
|
||||
options.display = '';
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -207,11 +196,11 @@ function _execSyncByFile(cmdArgs, execOptions) {
|
|||
return filepath;
|
||||
}
|
||||
|
||||
var execArgs, res = {},
|
||||
pathStdout = getTempfile('readline-sync.stdout'),
|
||||
pathStderr = getTempfile('readline-sync.stderr'),
|
||||
pathStatus = getTempfile('readline-sync.status'),
|
||||
pathDone = getTempfile('readline-sync.done'),
|
||||
var execArgs, interpreter, res = {},
|
||||
pathStdout = getTempfile('readline-sync.stdout'),
|
||||
pathStderr = getTempfile('readline-sync.stderr'),
|
||||
pathExit = getTempfile('readline-sync.exit'),
|
||||
pathDone = getTempfile('readline-sync.done'),
|
||||
crypto = require('crypto'), shasum, decipher, password;
|
||||
|
||||
shasum = crypto.createHash(ALGORITHM_HASH);
|
||||
|
@ -220,32 +209,41 @@ function _execSyncByFile(cmdArgs, execOptions) {
|
|||
decipher = crypto.createDecipher(ALGORITHM_CIPHER, password);
|
||||
|
||||
if (IS_WIN) {
|
||||
interpreter = process.env.ComSpec || 'cmd.exe';
|
||||
process.env.Q = '"'; // The quote (") that isn't escaped.
|
||||
// `()` for ignore space by echo
|
||||
execArgs = ['/V:ON', '/S', '/C',
|
||||
'(%Q%' + SHELL_PATH + '%Q% /V:ON /S /C %Q%%Q%' + SHELL_CMD + '%Q%' +
|
||||
'(%Q%' + interpreter + '%Q% /V:ON /S /C %Q%' +
|
||||
'%Q%' + SHELL_PATH + '%Q% //nologo %Q%' + SHELL_CMD + '%Q%' +
|
||||
cmdArgs.map(function(arg) { return ' %Q%' + arg + '%Q%'; }).join('') +
|
||||
' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q%%Q%) 2>%Q%' + pathStderr + '%Q%' +
|
||||
' & (echo !ERRORLEVEL!)>%Q%' + pathExit + '%Q%%Q%) 2>%Q%' + pathStderr + '%Q%' +
|
||||
' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' +
|
||||
' %Q%' + ALGORITHM_CIPHER + '%Q% %Q%' + password + '%Q%' +
|
||||
' >%Q%' + pathStdout + '%Q%' +
|
||||
' & (echo 1)>%Q%' + pathDone + '%Q%'];
|
||||
} else {
|
||||
interpreter = SHELL_PATH;
|
||||
execArgs = ['-c',
|
||||
// Use `()`, not `{}` for `-c` (text param)
|
||||
'("' + SHELL_PATH + '" "' + SHELL_CMD + '"' +
|
||||
cmdArgs.map(function(arg)
|
||||
{ return ' "' + arg.replace(/[\\"`]/g, '\\\$&') + '"'; }).join('') +
|
||||
'; echo $?>"' + pathStatus + '") 2>"' + pathStderr + '"' +
|
||||
{ return " '" + arg.replace(/'/g, "'\\''") + "'"; }).join('') +
|
||||
'; echo $?>"' + pathExit + '") 2>"' + pathStderr + '"' +
|
||||
' |"' + process.execPath + '" "' + __dirname + '/encrypt.js"' +
|
||||
' "' + ALGORITHM_CIPHER + '" "' + password + '"' +
|
||||
' >"' + pathStdout + '"' +
|
||||
'; echo 1 >"' + pathDone + '"'];
|
||||
}
|
||||
childProc.spawn(SHELL_PATH, execArgs, execOptions);
|
||||
try {
|
||||
childProc.spawn(interpreter, execArgs, execOptions);
|
||||
} catch (e) {
|
||||
res.error = new Error(e.message);
|
||||
res.error.method = '_execSyncByFile - spawn';
|
||||
res.error.interpreter = interpreter;
|
||||
}
|
||||
|
||||
while (fs.readFileSync(pathDone, {encoding: encoding}).trim() !== '1') {}
|
||||
if (fs.readFileSync(pathStatus, {encoding: encoding}).trim() === '0') {
|
||||
if (fs.readFileSync(pathExit, {encoding: encoding}).trim() === '0') {
|
||||
res.input =
|
||||
decipher.update(fs.readFileSync(pathStdout, {encoding: 'binary'}), 'hex', encoding) +
|
||||
decipher.final(encoding);
|
||||
|
@ -259,7 +257,7 @@ function _execSyncByFile(cmdArgs, execOptions) {
|
|||
|
||||
fs.unlinkSync(pathStdout);
|
||||
fs.unlinkSync(pathStderr);
|
||||
fs.unlinkSync(pathStatus);
|
||||
fs.unlinkSync(pathExit);
|
||||
fs.unlinkSync(pathDone);
|
||||
|
||||
return res;
|
||||
|
@ -287,7 +285,8 @@ exports.setEncoding = function(newEncoding) {
|
|||
};
|
||||
|
||||
exports.setBufferSize = function(newBufSize) {
|
||||
if (typeof newBufSize === 'number') {
|
||||
newBufSize = parseInt(newBufSize, 10);
|
||||
if (!isNaN(newBufSize) && typeof newBufSize === 'number') {
|
||||
bufSize = newBufSize;
|
||||
}
|
||||
return bufSize;
|
||||
|
@ -320,7 +319,7 @@ exports.keyIn = function(query, options) {
|
|||
/* jshint eqnull:true */
|
||||
display: query != null ? query + '' : '',
|
||||
/* jshint eqnull:false */
|
||||
noEchoBack: false,
|
||||
noEchoBack: !!(options && options.noEchoBack),
|
||||
keyIn: true,
|
||||
noTrim: true
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue