Comparing version 0.11.0-beta30 to 0.11.0-beta31
@@ -23,10 +23,7 @@ "use strict"; | ||
var net = require("net"); | ||
var path = require("path"); | ||
var terminal_1 = require("./terminal"); | ||
var utils_1 = require("./utils"); | ||
var pty; | ||
var helperPath; | ||
try { | ||
pty = require('../build/Release/pty.node'); | ||
helperPath = '../build/Release/spawn-helper'; | ||
} | ||
@@ -36,3 +33,2 @@ catch (outerError) { | ||
pty = require('../build/Debug/pty.node'); | ||
helperPath = '../build/Debug/spawn-helper'; | ||
} | ||
@@ -45,5 +41,2 @@ catch (innerError) { | ||
} | ||
helperPath = path.resolve(__dirname, helperPath); | ||
helperPath = helperPath.replace('app.asar', 'app.asar.unpacked'); | ||
helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked'); | ||
var DEFAULT_FILE = 'sh'; | ||
@@ -71,3 +64,2 @@ var DEFAULT_NAME = 'xterm'; | ||
var gid = (_b = opt.gid) !== null && _b !== void 0 ? _b : -1; | ||
var closeFDs = opt.closeFDs || false; | ||
var env = utils_1.assign({}, opt.env); | ||
@@ -110,3 +102,3 @@ if (opt.env === process.env) { | ||
// fork | ||
var term = pty.fork(file, args, parsedEnv, cwd, _this._cols, _this._rows, uid, gid, (encoding === 'utf8'), closeFDs, onexit, helperPath); | ||
var term = pty.fork(file, args, parsedEnv, cwd, _this._cols, _this._rows, uid, gid, (encoding === 'utf8'), onexit); | ||
_this._socket = new PipeSocket(term.fd); | ||
@@ -113,0 +105,0 @@ if (encoding !== null) { |
@@ -6,2 +6,38 @@ "use strict"; | ||
*/ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -216,64 +252,39 @@ var unixTerminal_1 = require("./unixTerminal"); | ||
describe('spawn', function () { | ||
it('should handle exec() errors', function (done) { | ||
try { | ||
new unixTerminal_1.UnixTerminal('/bin/bogus.exe', []); | ||
done(new Error('should have failed')); | ||
} | ||
catch (_a) { | ||
done(); | ||
} | ||
}); | ||
it('should handle chdir() errors', function (done) { | ||
try { | ||
new unixTerminal_1.UnixTerminal('/bin/echo', [], { cwd: '/nowhere' }); | ||
done(new Error('should have failed')); | ||
} | ||
catch (e) { | ||
assert.strictEqual(e.toString(), 'Error: chdir() failed: No such file or directory'); | ||
done(); | ||
} | ||
}); | ||
it('should handle setuid() errors', function (done) { | ||
try { | ||
new unixTerminal_1.UnixTerminal('/bin/echo', [], { uid: 999999 }); | ||
done(new Error('should have failed')); | ||
} | ||
catch (e) { | ||
assert.strictEqual(e.toString(), 'Error: setuid() failed: Operation not permitted'); | ||
done(); | ||
} | ||
}); | ||
if (process.platform === 'linux') { | ||
it('should not close on exec when closeFDs is not defined', function (done) { | ||
var data = "\n var pty = require('./lib/index');\n var ptyProcess = pty.spawn('node', ['-e', 'setTimeout(() => console.log(\"hello from terminal\"), 300);']);\n ptyProcess.on('data', function (data) {\n console.log(data);\n });\n setTimeout(() => null, 500);\n console.log('ready', ptyProcess.pid);\n "; | ||
var buffer = []; | ||
var readFd = fs.openSync(FIXTURES_PATH, 'r'); | ||
var p = cp.spawn('node', ['-e', data], { | ||
stdio: ['ignore', 'pipe', 'pipe', readFd] | ||
it('should handle exec() errors', function (done) { | ||
var term = new unixTerminal_1.UnixTerminal('/bin/bogus.exe', []); | ||
term.on('exit', function (code, signal) { | ||
assert.strictEqual(code, 1); | ||
done(); | ||
}); | ||
var sub = ''; | ||
p.stdout.on('data', function (data) { | ||
if (!data.toString().indexOf('ready')) { | ||
sub = data.toString().split(' ')[1].slice(0, -1); | ||
try { | ||
fs.statSync("/proc/" + sub + "/fd/" + readFd); | ||
} | ||
catch (_) { | ||
done('not reachable'); | ||
} | ||
setTimeout(function () { | ||
process.kill(parseInt(sub), 'SIGINT'); // SIGINT to child | ||
p.kill('SIGINT'); // SIGINT to parent | ||
}, 200); | ||
} | ||
else { | ||
buffer.push(data.toString().replace(/^\s+|\s+$/g, '')); | ||
} | ||
}); | ||
p.on('close', function () { | ||
}); | ||
it('should handle chdir() errors', function (done) { | ||
var term = new unixTerminal_1.UnixTerminal('/bin/echo', [], { cwd: '/nowhere' }); | ||
term.on('exit', function (code, signal) { | ||
assert.strictEqual(code, 1); | ||
done(); | ||
}); | ||
}); | ||
it('should close on exec when closeFDs is true', function (done) { | ||
var data = "\n var pty = require('./lib/index');\n var ptyProcess = pty.spawn('node', ['-e', 'setTimeout(() => console.log(\"hello from terminal\"), 300);'], {\n closeFDs: true\n });\n ptyProcess.on('data', function (data) {\n console.log(data);\n });\n setTimeout(() => null, 500);\n console.log('ready', ptyProcess.pid);\n "; | ||
} | ||
else if (process.platform === 'darwin') { | ||
it('should handle exec() errors', function (done) { | ||
try { | ||
new unixTerminal_1.UnixTerminal('/bin/bogus.exe', []); | ||
done(new Error('should have failed')); | ||
} | ||
catch (_a) { | ||
done(); | ||
} | ||
}); | ||
it('should handle chdir() errors', function (done) { | ||
try { | ||
new unixTerminal_1.UnixTerminal('/bin/echo', [], { cwd: '/nowhere' }); | ||
done(new Error('should have failed')); | ||
} | ||
catch (e) { | ||
done(); | ||
} | ||
}); | ||
it('should close on exec', function (done) { | ||
var data = "\n var pty = require('./lib/index');\n var ptyProcess = pty.spawn('node', ['-e', 'setTimeout(() => console.log(\"hello from terminal\"), 300);']);\n ptyProcess.on('data', function (data) {\n console.log(data);\n });\n setTimeout(() => null, 500);\n console.log('ready', ptyProcess.pid);\n "; | ||
var buffer = []; | ||
@@ -309,2 +320,25 @@ var readFd = fs.openSync(FIXTURES_PATH, 'r'); | ||
} | ||
it('should not leak child process', function (done) { | ||
var count = cp.execSync('ps -ax | grep node | wc -l'); | ||
var term = new unixTerminal_1.UnixTerminal('node', ['-e', "\n console.log('ready');\n setTimeout(()=>console.log('timeout'), 200);" | ||
]); | ||
term.on('data', function (data) { return __awaiter(void 0, void 0, void 0, function () { | ||
var newCount; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!(data === 'ready\r\n')) return [3 /*break*/, 2]; | ||
process.kill(term.pid, 'SIGINT'); | ||
return [4 /*yield*/, setTimeout(function () { return null; }, 1000)]; | ||
case 1: | ||
_a.sent(); | ||
newCount = cp.execSync('ps -ax | grep node | wc -l'); | ||
assert.strictEqual(count.toString(), newCount.toString()); | ||
done(); | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
}); }); | ||
}); | ||
}); | ||
@@ -311,0 +345,0 @@ }); |
@@ -7,3 +7,3 @@ { | ||
}, | ||
"version": "0.11.0-beta30", | ||
"version": "0.11.0-beta31", | ||
"license": "MIT", | ||
@@ -10,0 +10,0 @@ "main": "./lib/index.js", |
@@ -12,3 +12,2 @@ var fs = require('fs'); | ||
path.join(RELEASE_DIR, 'pty.pdb'), | ||
path.join(RELEASE_DIR, 'spawn-helper'), | ||
path.join(RELEASE_DIR, 'winpty-agent.exe'), | ||
@@ -15,0 +14,0 @@ path.join(RELEASE_DIR, 'winpty-agent.pdb'), |
@@ -112,3 +112,2 @@ /** | ||
gid?: number; | ||
closeFDs?: boolean; | ||
} | ||
@@ -115,0 +114,0 @@ |
@@ -21,3 +21,3 @@ /** | ||
interface IUnixNative { | ||
fork(file: string, args: string[], parsedEnv: string[], cwd: string, cols: number, rows: number, uid: number, gid: number, closeFDs: boolean, useUtf8: boolean, onExitCallback: (code: number, signal: number) => void, helperPath: string): IUnixProcess; | ||
fork(file: string, args: string[], parsedEnv: string[], cwd: string, cols: number, rows: number, uid: number, gid: number, useUtf8: boolean, onExitCallback: (code: number, signal: number) => void): IUnixProcess; | ||
open(cols: number, rows: number): IUnixOpenProcess; | ||
@@ -24,0 +24,0 @@ process(fd: number, pty: string): string; |
@@ -258,71 +258,38 @@ /** | ||
describe('spawn', () => { | ||
it('should handle exec() errors', (done) => { | ||
try { | ||
new UnixTerminal('/bin/bogus.exe', []); | ||
done(new Error('should have failed')); | ||
} catch { | ||
done(); | ||
} | ||
}); | ||
it('should handle chdir() errors', (done) => { | ||
try { | ||
new UnixTerminal('/bin/echo', [], { cwd: '/nowhere' }); | ||
done(new Error('should have failed')); | ||
} catch (e) { | ||
assert.strictEqual((e as any).toString(), 'Error: chdir() failed: No such file or directory'); | ||
done(); | ||
} | ||
}); | ||
it('should handle setuid() errors', (done) => { | ||
try { | ||
new UnixTerminal('/bin/echo', [], { uid: 999999 }); | ||
done(new Error('should have failed')); | ||
} catch (e) { | ||
assert.strictEqual((e as any).toString(), 'Error: setuid() failed: Operation not permitted'); | ||
done(); | ||
} | ||
}); | ||
if (process.platform === 'linux') { | ||
it('should not close on exec when closeFDs is not defined', (done) => { | ||
const data = ` | ||
var pty = require('./lib/index'); | ||
var ptyProcess = pty.spawn('node', ['-e', 'setTimeout(() => console.log("hello from terminal"), 300);']); | ||
ptyProcess.on('data', function (data) { | ||
console.log(data); | ||
it('should handle exec() errors', (done) => { | ||
const term = new UnixTerminal('/bin/bogus.exe', []); | ||
term.on('exit', (code, signal) => { | ||
assert.strictEqual(code, 1); | ||
done(); | ||
}); | ||
setTimeout(() => null, 500); | ||
console.log('ready', ptyProcess.pid); | ||
`; | ||
const buffer: string[] = []; | ||
const readFd = fs.openSync(FIXTURES_PATH, 'r'); | ||
const p = cp.spawn('node', ['-e', data], { | ||
stdio: ['ignore', 'pipe', 'pipe', readFd] | ||
}); | ||
let sub = ''; | ||
p.stdout!.on('data', (data) => { | ||
if (!data.toString().indexOf('ready')) { | ||
sub = data.toString().split(' ')[1].slice(0, -1); | ||
try { | ||
fs.statSync(`/proc/${sub}/fd/${readFd}`); | ||
} catch (_) { | ||
done('not reachable'); | ||
} | ||
setTimeout(() => { | ||
process.kill(parseInt(sub), 'SIGINT'); // SIGINT to child | ||
p.kill('SIGINT'); // SIGINT to parent | ||
}, 200); | ||
} else { | ||
buffer.push(data.toString().replace(/^\s+|\s+$/g, '')); | ||
} | ||
}); | ||
p.on('close', () => { | ||
}); | ||
it('should handle chdir() errors', (done) => { | ||
const term = new UnixTerminal('/bin/echo', [], { cwd: '/nowhere' }); | ||
term.on('exit', (code, signal) => { | ||
assert.strictEqual(code, 1); | ||
done(); | ||
}); | ||
}); | ||
it('should close on exec when closeFDs is true', (done) => { | ||
} else if (process.platform === 'darwin') { | ||
it('should handle exec() errors', (done) => { | ||
try { | ||
new UnixTerminal('/bin/bogus.exe', []); | ||
done(new Error('should have failed')); | ||
} catch { | ||
done(); | ||
} | ||
}); | ||
it('should handle chdir() errors', (done) => { | ||
try { | ||
new UnixTerminal('/bin/echo', [], { cwd: '/nowhere' }); | ||
done(new Error('should have failed')); | ||
} catch (e) { | ||
done(); | ||
} | ||
}); | ||
it('should close on exec', (done) => { | ||
const data = ` | ||
var pty = require('./lib/index'); | ||
var ptyProcess = pty.spawn('node', ['-e', 'setTimeout(() => console.log("hello from terminal"), 300);'], { | ||
closeFDs: true | ||
}); | ||
var ptyProcess = pty.spawn('node', ['-e', 'setTimeout(() => console.log("hello from terminal"), 300);']); | ||
ptyProcess.on('data', function (data) { | ||
@@ -362,4 +329,20 @@ console.log(data); | ||
} | ||
it('should not leak child process', (done) => { | ||
const count = cp.execSync('ps -ax | grep node | wc -l'); | ||
const term = new UnixTerminal('node', [ '-e', ` | ||
console.log('ready'); | ||
setTimeout(()=>console.log('timeout'), 200);` | ||
]); | ||
term.on('data', async (data) => { | ||
if (data === 'ready\r\n') { | ||
process.kill(term.pid, 'SIGINT'); | ||
await setTimeout(() => null, 1000); | ||
const newCount = cp.execSync('ps -ax | grep node | wc -l'); | ||
assert.strictEqual(count.toString(), newCount.toString()); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
} |
@@ -14,10 +14,7 @@ /** | ||
let pty: IUnixNative; | ||
let helperPath: string; | ||
try { | ||
pty = require('../build/Release/pty.node'); | ||
helperPath = '../build/Release/spawn-helper'; | ||
} catch (outerError) { | ||
try { | ||
pty = require('../build/Debug/pty.node'); | ||
helperPath = '../build/Debug/spawn-helper'; | ||
} catch (innerError) { | ||
@@ -30,6 +27,2 @@ console.error('innerError', innerError); | ||
helperPath = path.resolve(__dirname, helperPath); | ||
helperPath = helperPath.replace('app.asar', 'app.asar.unpacked'); | ||
helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked'); | ||
const DEFAULT_FILE = 'sh'; | ||
@@ -74,3 +67,2 @@ const DEFAULT_NAME = 'xterm'; | ||
const gid = opt.gid ?? -1; | ||
const closeFDs = opt.closeFDs || false; | ||
const env: IProcessEnv = assign({}, opt.env); | ||
@@ -118,3 +110,3 @@ | ||
// fork | ||
const term = pty.fork(file, args, parsedEnv, cwd, this._cols, this._rows, uid, gid, (encoding === 'utf8'), closeFDs, onexit, helperPath); | ||
const term = pty.fork(file, args, parsedEnv, cwd, this._cols, this._rows, uid, gid, (encoding === 'utf8'), onexit); | ||
@@ -121,0 +113,0 @@ this._socket = new PipeSocket(term.fd); |
@@ -81,3 +81,3 @@ /** | ||
/** | ||
* Security warning: use this option with great caution unless `closeFDs` is also set, | ||
* Security warning: use this option with great caution, | ||
* as opened file descriptors with higher privileges might leak to the child program. | ||
@@ -87,8 +87,2 @@ */ | ||
gid?: number; | ||
/** | ||
* Close all open file after spawning the child process (UNIX only). | ||
* Carries a performance penalty on Linux. | ||
*/ | ||
closeFDs?: boolean; | ||
} | ||
@@ -95,0 +89,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1143716
250
4440