Socket
Socket
Sign inDemoInstall

node-pty

Package Overview
Dependencies
Maintainers
2
Versions
164
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-pty - npm Package Compare versions

Comparing version 0.11.0-beta30 to 0.11.0-beta31

10

lib/unixTerminal.js

@@ -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) {

148

lib/unixTerminal.test.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc