Initial commit
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+295
@@ -0,0 +1,295 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
Duplex: DuplexStream,
|
||||
Readable: ReadableStream,
|
||||
Writable: WritableStream,
|
||||
} = require('stream');
|
||||
|
||||
const {
|
||||
CHANNEL_EXTENDED_DATATYPE: { STDERR },
|
||||
} = require('./protocol/constants.js');
|
||||
const { bufferSlice } = require('./protocol/utils.js');
|
||||
|
||||
const PACKET_SIZE = 32 * 1024;
|
||||
const MAX_WINDOW = 2 * 1024 * 1024;
|
||||
const WINDOW_THRESHOLD = MAX_WINDOW / 2;
|
||||
|
||||
class ClientStderr extends ReadableStream {
|
||||
constructor(channel, streamOpts) {
|
||||
super(streamOpts);
|
||||
|
||||
this._channel = channel;
|
||||
}
|
||||
_read(n) {
|
||||
if (this._channel._waitChanDrain) {
|
||||
this._channel._waitChanDrain = false;
|
||||
if (this._channel.incoming.window <= WINDOW_THRESHOLD)
|
||||
windowAdjust(this._channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ServerStderr extends WritableStream {
|
||||
constructor(channel) {
|
||||
super({ highWaterMark: MAX_WINDOW });
|
||||
|
||||
this._channel = channel;
|
||||
}
|
||||
|
||||
_write(data, encoding, cb) {
|
||||
const channel = this._channel;
|
||||
const protocol = channel._client._protocol;
|
||||
const outgoing = channel.outgoing;
|
||||
const packetSize = outgoing.packetSize;
|
||||
const id = outgoing.id;
|
||||
let window = outgoing.window;
|
||||
const len = data.length;
|
||||
let p = 0;
|
||||
|
||||
if (outgoing.state !== 'open')
|
||||
return;
|
||||
|
||||
while (len - p > 0 && window > 0) {
|
||||
let sliceLen = len - p;
|
||||
if (sliceLen > window)
|
||||
sliceLen = window;
|
||||
if (sliceLen > packetSize)
|
||||
sliceLen = packetSize;
|
||||
|
||||
if (p === 0 && sliceLen === len)
|
||||
protocol.channelExtData(id, data, STDERR);
|
||||
else
|
||||
protocol.channelExtData(id, bufferSlice(data, p, p + sliceLen), STDERR);
|
||||
|
||||
p += sliceLen;
|
||||
window -= sliceLen;
|
||||
}
|
||||
|
||||
outgoing.window = window;
|
||||
|
||||
if (len - p > 0) {
|
||||
if (window === 0)
|
||||
channel._waitWindow = true;
|
||||
if (p > 0)
|
||||
channel._chunkErr = bufferSlice(data, p, len);
|
||||
else
|
||||
channel._chunkErr = data;
|
||||
channel._chunkcbErr = cb;
|
||||
return;
|
||||
}
|
||||
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
class Channel extends DuplexStream {
|
||||
constructor(client, info, opts) {
|
||||
const streamOpts = {
|
||||
highWaterMark: MAX_WINDOW,
|
||||
allowHalfOpen: (!opts || (opts && opts.allowHalfOpen !== false)),
|
||||
emitClose: false,
|
||||
};
|
||||
super(streamOpts);
|
||||
this.allowHalfOpen = streamOpts.allowHalfOpen;
|
||||
|
||||
const server = !!(opts && opts.server);
|
||||
|
||||
this.server = server;
|
||||
this.type = info.type;
|
||||
this.subtype = undefined;
|
||||
|
||||
/*
|
||||
incoming and outgoing contain these properties:
|
||||
{
|
||||
id: undefined,
|
||||
window: undefined,
|
||||
packetSize: undefined,
|
||||
state: 'closed'
|
||||
}
|
||||
*/
|
||||
this.incoming = info.incoming;
|
||||
this.outgoing = info.outgoing;
|
||||
this._callbacks = [];
|
||||
|
||||
this._client = client;
|
||||
this._hasX11 = false;
|
||||
this._exit = {
|
||||
code: undefined,
|
||||
signal: undefined,
|
||||
dump: undefined,
|
||||
desc: undefined,
|
||||
};
|
||||
|
||||
this.stdin = this.stdout = this;
|
||||
|
||||
if (server)
|
||||
this.stderr = new ServerStderr(this);
|
||||
else
|
||||
this.stderr = new ClientStderr(this, streamOpts);
|
||||
|
||||
// Outgoing data
|
||||
this._waitWindow = false; // SSH-level backpressure
|
||||
|
||||
// Incoming data
|
||||
this._waitChanDrain = false; // Channel Readable side backpressure
|
||||
|
||||
this._chunk = undefined;
|
||||
this._chunkcb = undefined;
|
||||
this._chunkErr = undefined;
|
||||
this._chunkcbErr = undefined;
|
||||
|
||||
this.on('finish', onFinish)
|
||||
.on('prefinish', onFinish); // For node v0.11+
|
||||
|
||||
this.on('end', onEnd).on('close', onEnd);
|
||||
}
|
||||
|
||||
_read(n) {
|
||||
if (this._waitChanDrain) {
|
||||
this._waitChanDrain = false;
|
||||
if (this.incoming.window <= WINDOW_THRESHOLD)
|
||||
windowAdjust(this);
|
||||
}
|
||||
}
|
||||
|
||||
_write(data, encoding, cb) {
|
||||
const protocol = this._client._protocol;
|
||||
const outgoing = this.outgoing;
|
||||
const packetSize = outgoing.packetSize;
|
||||
const id = outgoing.id;
|
||||
let window = outgoing.window;
|
||||
const len = data.length;
|
||||
let p = 0;
|
||||
|
||||
if (outgoing.state !== 'open')
|
||||
return;
|
||||
|
||||
while (len - p > 0 && window > 0) {
|
||||
let sliceLen = len - p;
|
||||
if (sliceLen > window)
|
||||
sliceLen = window;
|
||||
if (sliceLen > packetSize)
|
||||
sliceLen = packetSize;
|
||||
|
||||
if (p === 0 && sliceLen === len)
|
||||
protocol.channelData(id, data);
|
||||
else
|
||||
protocol.channelData(id, bufferSlice(data, p, p + sliceLen));
|
||||
|
||||
p += sliceLen;
|
||||
window -= sliceLen;
|
||||
}
|
||||
|
||||
outgoing.window = window;
|
||||
|
||||
if (len - p > 0) {
|
||||
if (window === 0)
|
||||
this._waitWindow = true;
|
||||
if (p > 0)
|
||||
this._chunk = bufferSlice(data, p, len);
|
||||
else
|
||||
this._chunk = data;
|
||||
this._chunkcb = cb;
|
||||
return;
|
||||
}
|
||||
|
||||
cb();
|
||||
}
|
||||
|
||||
eof() {
|
||||
if (this.outgoing.state === 'open') {
|
||||
this.outgoing.state = 'eof';
|
||||
this._client._protocol.channelEOF(this.outgoing.id);
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.outgoing.state === 'open' || this.outgoing.state === 'eof') {
|
||||
this.outgoing.state = 'closing';
|
||||
this._client._protocol.channelClose(this.outgoing.id);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.end();
|
||||
this.close();
|
||||
return this;
|
||||
}
|
||||
|
||||
// Session type-specific methods =============================================
|
||||
setWindow(rows, cols, height, width) {
|
||||
if (this.server)
|
||||
throw new Error('Client-only method called in server mode');
|
||||
|
||||
if (this.type === 'session'
|
||||
&& (this.subtype === 'shell' || this.subtype === 'exec')
|
||||
&& this.writable
|
||||
&& this.outgoing.state === 'open') {
|
||||
this._client._protocol.windowChange(this.outgoing.id,
|
||||
rows,
|
||||
cols,
|
||||
height,
|
||||
width);
|
||||
}
|
||||
}
|
||||
|
||||
signal(signalName) {
|
||||
if (this.server)
|
||||
throw new Error('Client-only method called in server mode');
|
||||
|
||||
if (this.type === 'session'
|
||||
&& this.writable
|
||||
&& this.outgoing.state === 'open') {
|
||||
this._client._protocol.signal(this.outgoing.id, signalName);
|
||||
}
|
||||
}
|
||||
|
||||
exit(statusOrSignal, coreDumped, msg) {
|
||||
if (!this.server)
|
||||
throw new Error('Server-only method called in client mode');
|
||||
|
||||
if (this.type === 'session'
|
||||
&& this.writable
|
||||
&& this.outgoing.state === 'open') {
|
||||
if (typeof statusOrSignal === 'number') {
|
||||
this._client._protocol.exitStatus(this.outgoing.id, statusOrSignal);
|
||||
} else {
|
||||
this._client._protocol.exitSignal(this.outgoing.id,
|
||||
statusOrSignal,
|
||||
coreDumped,
|
||||
msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onFinish() {
|
||||
this.eof();
|
||||
if (this.server || !this.allowHalfOpen)
|
||||
this.close();
|
||||
this.writable = false;
|
||||
}
|
||||
|
||||
function onEnd() {
|
||||
this.readable = false;
|
||||
}
|
||||
|
||||
function windowAdjust(self) {
|
||||
if (self.outgoing.state === 'closed')
|
||||
return;
|
||||
const amt = MAX_WINDOW - self.incoming.window;
|
||||
if (amt <= 0)
|
||||
return;
|
||||
self.incoming.window += amt;
|
||||
self._client._protocol.channelWindowAdjust(self.outgoing.id, amt);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Channel,
|
||||
MAX_WINDOW,
|
||||
PACKET_SIZE,
|
||||
windowAdjust,
|
||||
WINDOW_THRESHOLD,
|
||||
};
|
||||
+1123
File diff suppressed because it is too large
Load Diff
+2176
File diff suppressed because it is too large
Load Diff
+84
@@ -0,0 +1,84 @@
|
||||
'use strict';
|
||||
|
||||
const { Agent: HttpAgent } = require('http');
|
||||
const { Agent: HttpsAgent } = require('https');
|
||||
const { connect: tlsConnect } = require('tls');
|
||||
|
||||
let Client;
|
||||
|
||||
for (const ctor of [HttpAgent, HttpsAgent]) {
|
||||
class SSHAgent extends ctor {
|
||||
constructor(connectCfg, agentOptions) {
|
||||
super(agentOptions);
|
||||
|
||||
this._connectCfg = connectCfg;
|
||||
this._defaultSrcIP = (agentOptions && agentOptions.srcIP) || 'localhost';
|
||||
}
|
||||
|
||||
createConnection(options, cb) {
|
||||
const srcIP = (options && options.localAddress) || this._defaultSrcIP;
|
||||
const srcPort = (options && options.localPort) || 0;
|
||||
const dstIP = options.host;
|
||||
const dstPort = options.port;
|
||||
|
||||
if (Client === undefined)
|
||||
Client = require('./client.js');
|
||||
|
||||
const client = new Client();
|
||||
let triedForward = false;
|
||||
client.on('ready', () => {
|
||||
client.forwardOut(srcIP, srcPort, dstIP, dstPort, (err, stream) => {
|
||||
triedForward = true;
|
||||
if (err) {
|
||||
client.end();
|
||||
return cb(err);
|
||||
}
|
||||
stream.once('close', () => client.end());
|
||||
cb(null, decorateStream(stream, ctor, options));
|
||||
});
|
||||
}).on('error', cb).on('close', () => {
|
||||
if (!triedForward)
|
||||
cb(new Error('Unexpected connection close'));
|
||||
}).connect(this._connectCfg);
|
||||
}
|
||||
}
|
||||
|
||||
exports[ctor === HttpAgent ? 'SSHTTPAgent' : 'SSHTTPSAgent'] = SSHAgent;
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
function decorateStream(stream, ctor, options) {
|
||||
if (ctor === HttpAgent) {
|
||||
// HTTP
|
||||
stream.setKeepAlive = noop;
|
||||
stream.setNoDelay = noop;
|
||||
stream.setTimeout = noop;
|
||||
stream.ref = noop;
|
||||
stream.unref = noop;
|
||||
stream.destroySoon = stream.destroy;
|
||||
return stream;
|
||||
}
|
||||
|
||||
// HTTPS
|
||||
options.socket = stream;
|
||||
const wrapped = tlsConnect(options);
|
||||
|
||||
// This is a workaround for a regression in node v12.16.3+
|
||||
// https://github.com/nodejs/node/issues/35904
|
||||
const onClose = (() => {
|
||||
let called = false;
|
||||
return () => {
|
||||
if (called)
|
||||
return;
|
||||
called = true;
|
||||
if (stream.isPaused())
|
||||
stream.resume();
|
||||
};
|
||||
})();
|
||||
// 'end' listener is needed because 'close' is not emitted in some scenarios
|
||||
// in node v12.x for some unknown reason
|
||||
wrapped.on('end', onClose).on('close', onClose);
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
AgentProtocol,
|
||||
BaseAgent,
|
||||
createAgent,
|
||||
CygwinAgent,
|
||||
OpenSSHAgent,
|
||||
PageantAgent,
|
||||
} = require('./agent.js');
|
||||
const {
|
||||
SSHTTPAgent: HTTPAgent,
|
||||
SSHTTPSAgent: HTTPSAgent,
|
||||
} = require('./http-agents.js');
|
||||
const { parseKey } = require('./protocol/keyParser.js');
|
||||
const {
|
||||
flagsToString,
|
||||
OPEN_MODE,
|
||||
STATUS_CODE,
|
||||
stringToFlags,
|
||||
} = require('./protocol/SFTP.js');
|
||||
|
||||
module.exports = {
|
||||
AgentProtocol,
|
||||
BaseAgent,
|
||||
createAgent,
|
||||
Client: require('./client.js'),
|
||||
CygwinAgent,
|
||||
HTTPAgent,
|
||||
HTTPSAgent,
|
||||
OpenSSHAgent,
|
||||
PageantAgent,
|
||||
Server: require('./server.js'),
|
||||
utils: {
|
||||
parseKey,
|
||||
...require('./keygen.js'),
|
||||
sftp: {
|
||||
flagsToString,
|
||||
OPEN_MODE,
|
||||
STATUS_CODE,
|
||||
stringToFlags,
|
||||
},
|
||||
},
|
||||
};
|
||||
+582
@@ -0,0 +1,582 @@
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
createCipheriv,
|
||||
generateKeyPair: generateKeyPair_,
|
||||
generateKeyPairSync: generateKeyPairSync_,
|
||||
getCurves,
|
||||
randomBytes,
|
||||
} = require('crypto');
|
||||
|
||||
const { Ber } = require('asn1');
|
||||
const bcrypt_pbkdf = require('bcrypt-pbkdf').pbkdf;
|
||||
|
||||
const { CIPHER_INFO } = require('./protocol/crypto.js');
|
||||
|
||||
const SALT_LEN = 16;
|
||||
const DEFAULT_ROUNDS = 16;
|
||||
|
||||
const curves = getCurves();
|
||||
const ciphers = new Map(Object.entries(CIPHER_INFO));
|
||||
|
||||
function makeArgs(type, opts) {
|
||||
if (typeof type !== 'string')
|
||||
throw new TypeError('Key type must be a string');
|
||||
|
||||
const publicKeyEncoding = { type: 'spki', format: 'der' };
|
||||
const privateKeyEncoding = { type: 'pkcs8', format: 'der' };
|
||||
|
||||
switch (type.toLowerCase()) {
|
||||
case 'rsa': {
|
||||
if (typeof opts !== 'object' || opts === null)
|
||||
throw new TypeError('Missing options object for RSA key');
|
||||
const modulusLength = opts.bits;
|
||||
if (!Number.isInteger(modulusLength))
|
||||
throw new TypeError('RSA bits must be an integer');
|
||||
if (modulusLength <= 0 || modulusLength > 16384)
|
||||
throw new RangeError('RSA bits must be non-zero and <= 16384');
|
||||
return ['rsa', { modulusLength, publicKeyEncoding, privateKeyEncoding }];
|
||||
}
|
||||
case 'ecdsa': {
|
||||
if (typeof opts !== 'object' || opts === null)
|
||||
throw new TypeError('Missing options object for ECDSA key');
|
||||
if (!Number.isInteger(opts.bits))
|
||||
throw new TypeError('ECDSA bits must be an integer');
|
||||
let namedCurve;
|
||||
switch (opts.bits) {
|
||||
case 256:
|
||||
namedCurve = 'prime256v1';
|
||||
break;
|
||||
case 384:
|
||||
namedCurve = 'secp384r1';
|
||||
break;
|
||||
case 521:
|
||||
namedCurve = 'secp521r1';
|
||||
break;
|
||||
default:
|
||||
throw new Error('ECDSA bits must be 256, 384, or 521');
|
||||
}
|
||||
if (!curves.includes(namedCurve))
|
||||
throw new Error('Unsupported ECDSA bits value');
|
||||
return ['ec', { namedCurve, publicKeyEncoding, privateKeyEncoding }];
|
||||
}
|
||||
case 'ed25519':
|
||||
return ['ed25519', { publicKeyEncoding, privateKeyEncoding }];
|
||||
default:
|
||||
throw new Error(`Unsupported key type: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
function parseDERs(keyType, pub, priv) {
|
||||
switch (keyType) {
|
||||
case 'rsa': {
|
||||
// Note: we don't need to parse the public key since the PKCS8 private key
|
||||
// already includes the public key parameters
|
||||
|
||||
// Parse private key
|
||||
let reader = new Ber.Reader(priv);
|
||||
reader.readSequence();
|
||||
|
||||
// - Version
|
||||
if (reader.readInt() !== 0)
|
||||
throw new Error('Unsupported version in RSA private key');
|
||||
|
||||
// - Algorithm
|
||||
reader.readSequence();
|
||||
if (reader.readOID() !== '1.2.840.113549.1.1.1')
|
||||
throw new Error('Bad RSA private OID');
|
||||
// - Algorithm parameters (RSA has none)
|
||||
if (reader.readByte() !== Ber.Null)
|
||||
throw new Error('Malformed RSA private key (expected null)');
|
||||
if (reader.readByte() !== 0x00) {
|
||||
throw new Error(
|
||||
'Malformed RSA private key (expected zero-length null)'
|
||||
);
|
||||
}
|
||||
|
||||
reader = new Ber.Reader(reader.readString(Ber.OctetString, true));
|
||||
reader.readSequence();
|
||||
if (reader.readInt() !== 0)
|
||||
throw new Error('Unsupported version in RSA private key');
|
||||
const n = reader.readString(Ber.Integer, true);
|
||||
const e = reader.readString(Ber.Integer, true);
|
||||
const d = reader.readString(Ber.Integer, true);
|
||||
const p = reader.readString(Ber.Integer, true);
|
||||
const q = reader.readString(Ber.Integer, true);
|
||||
reader.readString(Ber.Integer, true); // dmp1
|
||||
reader.readString(Ber.Integer, true); // dmq1
|
||||
const iqmp = reader.readString(Ber.Integer, true);
|
||||
|
||||
/*
|
||||
OpenSSH RSA private key:
|
||||
string "ssh-rsa"
|
||||
string n -- public
|
||||
string e -- public
|
||||
string d -- private
|
||||
string iqmp -- private
|
||||
string p -- private
|
||||
string q -- private
|
||||
*/
|
||||
const keyName = Buffer.from('ssh-rsa');
|
||||
const privBuf = Buffer.allocUnsafe(
|
||||
4 + keyName.length
|
||||
+ 4 + n.length
|
||||
+ 4 + e.length
|
||||
+ 4 + d.length
|
||||
+ 4 + iqmp.length
|
||||
+ 4 + p.length
|
||||
+ 4 + q.length
|
||||
);
|
||||
let pos = 0;
|
||||
|
||||
privBuf.writeUInt32BE(keyName.length, pos += 0);
|
||||
privBuf.set(keyName, pos += 4);
|
||||
privBuf.writeUInt32BE(n.length, pos += keyName.length);
|
||||
privBuf.set(n, pos += 4);
|
||||
privBuf.writeUInt32BE(e.length, pos += n.length);
|
||||
privBuf.set(e, pos += 4);
|
||||
privBuf.writeUInt32BE(d.length, pos += e.length);
|
||||
privBuf.set(d, pos += 4);
|
||||
privBuf.writeUInt32BE(iqmp.length, pos += d.length);
|
||||
privBuf.set(iqmp, pos += 4);
|
||||
privBuf.writeUInt32BE(p.length, pos += iqmp.length);
|
||||
privBuf.set(p, pos += 4);
|
||||
privBuf.writeUInt32BE(q.length, pos += p.length);
|
||||
privBuf.set(q, pos += 4);
|
||||
|
||||
/*
|
||||
OpenSSH RSA public key:
|
||||
string "ssh-rsa"
|
||||
string e -- public
|
||||
string n -- public
|
||||
*/
|
||||
const pubBuf = Buffer.allocUnsafe(
|
||||
4 + keyName.length
|
||||
+ 4 + e.length
|
||||
+ 4 + n.length
|
||||
);
|
||||
pos = 0;
|
||||
|
||||
pubBuf.writeUInt32BE(keyName.length, pos += 0);
|
||||
pubBuf.set(keyName, pos += 4);
|
||||
pubBuf.writeUInt32BE(e.length, pos += keyName.length);
|
||||
pubBuf.set(e, pos += 4);
|
||||
pubBuf.writeUInt32BE(n.length, pos += e.length);
|
||||
pubBuf.set(n, pos += 4);
|
||||
|
||||
return { sshName: keyName.toString(), priv: privBuf, pub: pubBuf };
|
||||
}
|
||||
case 'ec': {
|
||||
// Parse public key
|
||||
let reader = new Ber.Reader(pub);
|
||||
reader.readSequence();
|
||||
|
||||
reader.readSequence();
|
||||
if (reader.readOID() !== '1.2.840.10045.2.1')
|
||||
throw new Error('Bad ECDSA public OID');
|
||||
// Skip curve OID, we'll get it from the private key
|
||||
reader.readOID();
|
||||
let pubBin = reader.readString(Ber.BitString, true);
|
||||
{
|
||||
// Remove leading zero bytes
|
||||
let i = 0;
|
||||
for (; i < pubBin.length && pubBin[i] === 0x00; ++i);
|
||||
if (i > 0)
|
||||
pubBin = pubBin.slice(i);
|
||||
}
|
||||
|
||||
// Parse private key
|
||||
reader = new Ber.Reader(priv);
|
||||
reader.readSequence();
|
||||
|
||||
// - Version
|
||||
if (reader.readInt() !== 0)
|
||||
throw new Error('Unsupported version in ECDSA private key');
|
||||
|
||||
reader.readSequence();
|
||||
if (reader.readOID() !== '1.2.840.10045.2.1')
|
||||
throw new Error('Bad ECDSA private OID');
|
||||
const curveOID = reader.readOID();
|
||||
let sshCurveName;
|
||||
switch (curveOID) {
|
||||
case '1.2.840.10045.3.1.7':
|
||||
// prime256v1/secp256r1
|
||||
sshCurveName = 'nistp256';
|
||||
break;
|
||||
case '1.3.132.0.34':
|
||||
// secp384r1
|
||||
sshCurveName = 'nistp384';
|
||||
break;
|
||||
case '1.3.132.0.35':
|
||||
// secp521r1
|
||||
sshCurveName = 'nistp521';
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unsupported curve in ECDSA private key');
|
||||
}
|
||||
|
||||
reader = new Ber.Reader(reader.readString(Ber.OctetString, true));
|
||||
reader.readSequence();
|
||||
|
||||
// - Version
|
||||
if (reader.readInt() !== 1)
|
||||
throw new Error('Unsupported version in ECDSA private key');
|
||||
|
||||
// Add leading zero byte to prevent negative bignum in private key
|
||||
const privBin = Buffer.concat([
|
||||
Buffer.from([0x00]),
|
||||
reader.readString(Ber.OctetString, true)
|
||||
]);
|
||||
|
||||
/*
|
||||
OpenSSH ECDSA private key:
|
||||
string "ecdsa-sha2-<sshCurveName>"
|
||||
string curve name
|
||||
string Q -- public
|
||||
string d -- private
|
||||
*/
|
||||
const keyName = Buffer.from(`ecdsa-sha2-${sshCurveName}`);
|
||||
sshCurveName = Buffer.from(sshCurveName);
|
||||
const privBuf = Buffer.allocUnsafe(
|
||||
4 + keyName.length
|
||||
+ 4 + sshCurveName.length
|
||||
+ 4 + pubBin.length
|
||||
+ 4 + privBin.length
|
||||
);
|
||||
let pos = 0;
|
||||
|
||||
privBuf.writeUInt32BE(keyName.length, pos += 0);
|
||||
privBuf.set(keyName, pos += 4);
|
||||
privBuf.writeUInt32BE(sshCurveName.length, pos += keyName.length);
|
||||
privBuf.set(sshCurveName, pos += 4);
|
||||
privBuf.writeUInt32BE(pubBin.length, pos += sshCurveName.length);
|
||||
privBuf.set(pubBin, pos += 4);
|
||||
privBuf.writeUInt32BE(privBin.length, pos += pubBin.length);
|
||||
privBuf.set(privBin, pos += 4);
|
||||
|
||||
/*
|
||||
OpenSSH ECDSA public key:
|
||||
string "ecdsa-sha2-<sshCurveName>"
|
||||
string curve name
|
||||
string Q -- public
|
||||
*/
|
||||
const pubBuf = Buffer.allocUnsafe(
|
||||
4 + keyName.length
|
||||
+ 4 + sshCurveName.length
|
||||
+ 4 + pubBin.length
|
||||
);
|
||||
pos = 0;
|
||||
|
||||
pubBuf.writeUInt32BE(keyName.length, pos += 0);
|
||||
pubBuf.set(keyName, pos += 4);
|
||||
pubBuf.writeUInt32BE(sshCurveName.length, pos += keyName.length);
|
||||
pubBuf.set(sshCurveName, pos += 4);
|
||||
pubBuf.writeUInt32BE(pubBin.length, pos += sshCurveName.length);
|
||||
pubBuf.set(pubBin, pos += 4);
|
||||
|
||||
return { sshName: keyName.toString(), priv: privBuf, pub: pubBuf };
|
||||
}
|
||||
case 'ed25519': {
|
||||
// Parse public key
|
||||
let reader = new Ber.Reader(pub);
|
||||
reader.readSequence();
|
||||
|
||||
// - Algorithm
|
||||
reader.readSequence();
|
||||
if (reader.readOID() !== '1.3.101.112')
|
||||
throw new Error('Bad ED25519 public OID');
|
||||
// - Attributes (absent for ED25519)
|
||||
|
||||
let pubBin = reader.readString(Ber.BitString, true);
|
||||
{
|
||||
// Remove leading zero bytes
|
||||
let i = 0;
|
||||
for (; i < pubBin.length && pubBin[i] === 0x00; ++i);
|
||||
if (i > 0)
|
||||
pubBin = pubBin.slice(i);
|
||||
}
|
||||
|
||||
// Parse private key
|
||||
reader = new Ber.Reader(priv);
|
||||
reader.readSequence();
|
||||
|
||||
// - Version
|
||||
if (reader.readInt() !== 0)
|
||||
throw new Error('Unsupported version in ED25519 private key');
|
||||
|
||||
// - Algorithm
|
||||
reader.readSequence();
|
||||
if (reader.readOID() !== '1.3.101.112')
|
||||
throw new Error('Bad ED25519 private OID');
|
||||
// - Attributes (absent)
|
||||
|
||||
reader = new Ber.Reader(reader.readString(Ber.OctetString, true));
|
||||
const privBin = reader.readString(Ber.OctetString, true);
|
||||
|
||||
/*
|
||||
OpenSSH ed25519 private key:
|
||||
string "ssh-ed25519"
|
||||
string public key
|
||||
string private key + public key
|
||||
*/
|
||||
const keyName = Buffer.from('ssh-ed25519');
|
||||
const privBuf = Buffer.allocUnsafe(
|
||||
4 + keyName.length
|
||||
+ 4 + pubBin.length
|
||||
+ 4 + (privBin.length + pubBin.length)
|
||||
);
|
||||
let pos = 0;
|
||||
|
||||
privBuf.writeUInt32BE(keyName.length, pos += 0);
|
||||
privBuf.set(keyName, pos += 4);
|
||||
privBuf.writeUInt32BE(pubBin.length, pos += keyName.length);
|
||||
privBuf.set(pubBin, pos += 4);
|
||||
privBuf.writeUInt32BE(
|
||||
privBin.length + pubBin.length,
|
||||
pos += pubBin.length
|
||||
);
|
||||
privBuf.set(privBin, pos += 4);
|
||||
privBuf.set(pubBin, pos += privBin.length);
|
||||
|
||||
/*
|
||||
OpenSSH ed25519 public key:
|
||||
string "ssh-ed25519"
|
||||
string public key
|
||||
*/
|
||||
const pubBuf = Buffer.allocUnsafe(
|
||||
4 + keyName.length
|
||||
+ 4 + pubBin.length
|
||||
);
|
||||
pos = 0;
|
||||
|
||||
pubBuf.writeUInt32BE(keyName.length, pos += 0);
|
||||
pubBuf.set(keyName, pos += 4);
|
||||
pubBuf.writeUInt32BE(pubBin.length, pos += keyName.length);
|
||||
pubBuf.set(pubBin, pos += 4);
|
||||
|
||||
return { sshName: keyName.toString(), priv: privBuf, pub: pubBuf };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertKeys(keyType, pub, priv, opts) {
|
||||
let format = 'new';
|
||||
let encrypted;
|
||||
let comment = '';
|
||||
if (typeof opts === 'object' && opts !== null) {
|
||||
if (typeof opts.comment === 'string' && opts.comment)
|
||||
comment = opts.comment;
|
||||
if (typeof opts.format === 'string' && opts.format)
|
||||
format = opts.format;
|
||||
if (opts.passphrase) {
|
||||
let passphrase;
|
||||
if (typeof opts.passphrase === 'string')
|
||||
passphrase = Buffer.from(opts.passphrase);
|
||||
else if (Buffer.isBuffer(opts.passphrase))
|
||||
passphrase = opts.passphrase;
|
||||
else
|
||||
throw new Error('Invalid passphrase');
|
||||
|
||||
if (opts.cipher === undefined)
|
||||
throw new Error('Missing cipher name');
|
||||
const cipher = ciphers.get(opts.cipher);
|
||||
if (cipher === undefined)
|
||||
throw new Error('Invalid cipher name');
|
||||
|
||||
if (format === 'new') {
|
||||
let rounds = DEFAULT_ROUNDS;
|
||||
if (opts.rounds !== undefined) {
|
||||
if (!Number.isInteger(opts.rounds))
|
||||
throw new TypeError('rounds must be an integer');
|
||||
if (opts.rounds > 0)
|
||||
rounds = opts.rounds;
|
||||
}
|
||||
|
||||
const gen = Buffer.allocUnsafe(cipher.keyLen + cipher.ivLen);
|
||||
const salt = randomBytes(SALT_LEN);
|
||||
const r = bcrypt_pbkdf(
|
||||
passphrase,
|
||||
passphrase.length,
|
||||
salt,
|
||||
salt.length,
|
||||
gen,
|
||||
gen.length,
|
||||
rounds
|
||||
);
|
||||
if (r !== 0)
|
||||
return new Error('Failed to generate information to encrypt key');
|
||||
|
||||
/*
|
||||
string salt
|
||||
uint32 rounds
|
||||
*/
|
||||
const kdfOptions = Buffer.allocUnsafe(4 + salt.length + 4);
|
||||
{
|
||||
let pos = 0;
|
||||
kdfOptions.writeUInt32BE(salt.length, pos += 0);
|
||||
kdfOptions.set(salt, pos += 4);
|
||||
kdfOptions.writeUInt32BE(rounds, pos += salt.length);
|
||||
}
|
||||
|
||||
encrypted = {
|
||||
cipher,
|
||||
cipherName: opts.cipher,
|
||||
kdfName: 'bcrypt',
|
||||
kdfOptions,
|
||||
key: gen.slice(0, cipher.keyLen),
|
||||
iv: gen.slice(cipher.keyLen),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case 'new': {
|
||||
let privateB64 = '-----BEGIN OPENSSH PRIVATE KEY-----\n';
|
||||
let publicB64;
|
||||
/*
|
||||
byte[] "openssh-key-v1\0"
|
||||
string ciphername
|
||||
string kdfname
|
||||
string kdfoptions
|
||||
uint32 number of keys N
|
||||
string publickey1
|
||||
string encrypted, padded list of private keys
|
||||
uint32 checkint
|
||||
uint32 checkint
|
||||
byte[] privatekey1
|
||||
string comment1
|
||||
byte 1
|
||||
byte 2
|
||||
byte 3
|
||||
...
|
||||
byte padlen % 255
|
||||
*/
|
||||
const cipherName = Buffer.from(encrypted ? encrypted.cipherName : 'none');
|
||||
const kdfName = Buffer.from(encrypted ? encrypted.kdfName : 'none');
|
||||
const kdfOptions = (encrypted ? encrypted.kdfOptions : Buffer.alloc(0));
|
||||
const blockLen = (encrypted ? encrypted.cipher.blockLen : 8);
|
||||
|
||||
const parsed = parseDERs(keyType, pub, priv);
|
||||
|
||||
const checkInt = randomBytes(4);
|
||||
const commentBin = Buffer.from(comment);
|
||||
const privBlobLen = (4 + 4 + parsed.priv.length + 4 + commentBin.length);
|
||||
let padding = [];
|
||||
for (let i = 1; ((privBlobLen + padding.length) % blockLen); ++i)
|
||||
padding.push(i & 0xFF);
|
||||
padding = Buffer.from(padding);
|
||||
|
||||
let privBlob = Buffer.allocUnsafe(privBlobLen + padding.length);
|
||||
let extra;
|
||||
{
|
||||
let pos = 0;
|
||||
privBlob.set(checkInt, pos += 0);
|
||||
privBlob.set(checkInt, pos += 4);
|
||||
privBlob.set(parsed.priv, pos += 4);
|
||||
privBlob.writeUInt32BE(commentBin.length, pos += parsed.priv.length);
|
||||
privBlob.set(commentBin, pos += 4);
|
||||
privBlob.set(padding, pos += commentBin.length);
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
const options = { authTagLength: encrypted.cipher.authLen };
|
||||
const cipher = createCipheriv(
|
||||
encrypted.cipher.sslName,
|
||||
encrypted.key,
|
||||
encrypted.iv,
|
||||
options
|
||||
);
|
||||
cipher.setAutoPadding(false);
|
||||
privBlob = Buffer.concat([ cipher.update(privBlob), cipher.final() ]);
|
||||
if (encrypted.cipher.authLen > 0)
|
||||
extra = cipher.getAuthTag();
|
||||
else
|
||||
extra = Buffer.alloc(0);
|
||||
encrypted.key.fill(0);
|
||||
encrypted.iv.fill(0);
|
||||
} else {
|
||||
extra = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
const magicBytes = Buffer.from('openssh-key-v1\0');
|
||||
const privBin = Buffer.allocUnsafe(
|
||||
magicBytes.length
|
||||
+ 4 + cipherName.length
|
||||
+ 4 + kdfName.length
|
||||
+ 4 + kdfOptions.length
|
||||
+ 4
|
||||
+ 4 + parsed.pub.length
|
||||
+ 4 + privBlob.length
|
||||
+ extra.length
|
||||
);
|
||||
{
|
||||
let pos = 0;
|
||||
privBin.set(magicBytes, pos += 0);
|
||||
privBin.writeUInt32BE(cipherName.length, pos += magicBytes.length);
|
||||
privBin.set(cipherName, pos += 4);
|
||||
privBin.writeUInt32BE(kdfName.length, pos += cipherName.length);
|
||||
privBin.set(kdfName, pos += 4);
|
||||
privBin.writeUInt32BE(kdfOptions.length, pos += kdfName.length);
|
||||
privBin.set(kdfOptions, pos += 4);
|
||||
privBin.writeUInt32BE(1, pos += kdfOptions.length);
|
||||
privBin.writeUInt32BE(parsed.pub.length, pos += 4);
|
||||
privBin.set(parsed.pub, pos += 4);
|
||||
privBin.writeUInt32BE(privBlob.length, pos += parsed.pub.length);
|
||||
privBin.set(privBlob, pos += 4);
|
||||
privBin.set(extra, pos += privBlob.length);
|
||||
}
|
||||
|
||||
{
|
||||
const b64 = privBin.base64Slice(0, privBin.length);
|
||||
let formatted = b64.replace(/.{64}/g, '$&\n');
|
||||
if (b64.length & 63)
|
||||
formatted += '\n';
|
||||
privateB64 += formatted;
|
||||
}
|
||||
|
||||
{
|
||||
const b64 = parsed.pub.base64Slice(0, parsed.pub.length);
|
||||
publicB64 = `${parsed.sshName} ${b64}${comment ? ` ${comment}` : ''}`;
|
||||
}
|
||||
|
||||
privateB64 += '-----END OPENSSH PRIVATE KEY-----\n';
|
||||
return {
|
||||
private: privateB64,
|
||||
public: publicB64,
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error('Invalid output key format');
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
module.exports = {
|
||||
generateKeyPair: (keyType, opts, cb) => {
|
||||
if (typeof opts === 'function') {
|
||||
cb = opts;
|
||||
opts = undefined;
|
||||
}
|
||||
if (typeof cb !== 'function')
|
||||
cb = noop;
|
||||
const args = makeArgs(keyType, opts);
|
||||
generateKeyPair_(...args, (err, pub, priv) => {
|
||||
if (err)
|
||||
return cb(err);
|
||||
let ret;
|
||||
try {
|
||||
ret = convertKeys(args[0], pub, priv, opts);
|
||||
} catch (ex) {
|
||||
return cb(ex);
|
||||
}
|
||||
cb(null, ret);
|
||||
});
|
||||
},
|
||||
generateKeyPairSync: (keyType, opts) => {
|
||||
const args = makeArgs(keyType, opts);
|
||||
const { publicKey: pub, privateKey: priv } = generateKeyPairSync_(...args);
|
||||
return convertKeys(args[0], pub, priv, opts);
|
||||
}
|
||||
};
|
||||
+2136
File diff suppressed because it is too large
Load Diff
+4052
File diff suppressed because it is too large
Load Diff
+356
@@ -0,0 +1,356 @@
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
let cpuInfo;
|
||||
try {
|
||||
cpuInfo = require('cpu-features')();
|
||||
} catch {}
|
||||
|
||||
const { bindingAvailable, CIPHER_INFO, MAC_INFO } = require('./crypto.js');
|
||||
|
||||
const eddsaSupported = (() => {
|
||||
if (typeof crypto.sign === 'function'
|
||||
&& typeof crypto.verify === 'function') {
|
||||
const key =
|
||||
'-----BEGIN PRIVATE KEY-----\r\nMC4CAQAwBQYDK2VwBCIEIHKj+sVa9WcD'
|
||||
+ '/q2DJUJaf43Kptc8xYuUQA4bOFj9vC8T\r\n-----END PRIVATE KEY-----';
|
||||
const data = Buffer.from('a');
|
||||
let sig;
|
||||
let verified;
|
||||
try {
|
||||
sig = crypto.sign(null, data, key);
|
||||
verified = crypto.verify(null, data, key, sig);
|
||||
} catch {}
|
||||
return (Buffer.isBuffer(sig) && sig.length === 64 && verified === true);
|
||||
}
|
||||
|
||||
return false;
|
||||
})();
|
||||
|
||||
const curve25519Supported = (typeof crypto.diffieHellman === 'function'
|
||||
&& typeof crypto.generateKeyPairSync === 'function'
|
||||
&& typeof crypto.createPublicKey === 'function');
|
||||
|
||||
const DEFAULT_KEX = [
|
||||
// https://tools.ietf.org/html/rfc5656#section-10.1
|
||||
'ecdh-sha2-nistp256',
|
||||
'ecdh-sha2-nistp384',
|
||||
'ecdh-sha2-nistp521',
|
||||
|
||||
// https://tools.ietf.org/html/rfc4419#section-4
|
||||
'diffie-hellman-group-exchange-sha256',
|
||||
|
||||
// https://tools.ietf.org/html/rfc8268
|
||||
'diffie-hellman-group14-sha256',
|
||||
'diffie-hellman-group15-sha512',
|
||||
'diffie-hellman-group16-sha512',
|
||||
'diffie-hellman-group17-sha512',
|
||||
'diffie-hellman-group18-sha512',
|
||||
];
|
||||
if (curve25519Supported) {
|
||||
DEFAULT_KEX.unshift('curve25519-sha256');
|
||||
DEFAULT_KEX.unshift('curve25519-sha256@libssh.org');
|
||||
}
|
||||
const SUPPORTED_KEX = DEFAULT_KEX.concat([
|
||||
// https://tools.ietf.org/html/rfc4419#section-4
|
||||
'diffie-hellman-group-exchange-sha1',
|
||||
|
||||
'diffie-hellman-group14-sha1', // REQUIRED
|
||||
'diffie-hellman-group1-sha1', // REQUIRED
|
||||
]);
|
||||
|
||||
|
||||
const DEFAULT_SERVER_HOST_KEY = [
|
||||
'ecdsa-sha2-nistp256',
|
||||
'ecdsa-sha2-nistp384',
|
||||
'ecdsa-sha2-nistp521',
|
||||
'rsa-sha2-512', // RFC 8332
|
||||
'rsa-sha2-256', // RFC 8332
|
||||
'ssh-rsa',
|
||||
];
|
||||
if (eddsaSupported)
|
||||
DEFAULT_SERVER_HOST_KEY.unshift('ssh-ed25519');
|
||||
const SUPPORTED_SERVER_HOST_KEY = DEFAULT_SERVER_HOST_KEY.concat([
|
||||
'ssh-dss',
|
||||
]);
|
||||
|
||||
|
||||
const canUseCipher = (() => {
|
||||
const ciphers = crypto.getCiphers();
|
||||
return (name) => ciphers.includes(CIPHER_INFO[name].sslName);
|
||||
})();
|
||||
let DEFAULT_CIPHER = [
|
||||
// http://tools.ietf.org/html/rfc5647
|
||||
'aes128-gcm@openssh.com',
|
||||
'aes256-gcm@openssh.com',
|
||||
|
||||
// http://tools.ietf.org/html/rfc4344#section-4
|
||||
'aes128-ctr',
|
||||
'aes192-ctr',
|
||||
'aes256-ctr',
|
||||
];
|
||||
if (cpuInfo && cpuInfo.flags && !cpuInfo.flags.aes) {
|
||||
// We know for sure the CPU does not support AES acceleration
|
||||
if (bindingAvailable)
|
||||
DEFAULT_CIPHER.unshift('chacha20-poly1305@openssh.com');
|
||||
else
|
||||
DEFAULT_CIPHER.push('chacha20-poly1305@openssh.com');
|
||||
} else if (bindingAvailable && cpuInfo && cpuInfo.arch === 'x86') {
|
||||
// Places chacha20-poly1305 immediately after GCM ciphers since GCM ciphers
|
||||
// seem to outperform it on x86, but it seems to be faster than CTR ciphers
|
||||
DEFAULT_CIPHER.splice(4, 0, 'chacha20-poly1305@openssh.com');
|
||||
} else {
|
||||
DEFAULT_CIPHER.push('chacha20-poly1305@openssh.com');
|
||||
}
|
||||
DEFAULT_CIPHER = DEFAULT_CIPHER.filter(canUseCipher);
|
||||
const SUPPORTED_CIPHER = DEFAULT_CIPHER.concat([
|
||||
'aes256-cbc',
|
||||
'aes192-cbc',
|
||||
'aes128-cbc',
|
||||
'blowfish-cbc',
|
||||
'3des-cbc',
|
||||
'aes128-gcm',
|
||||
'aes256-gcm',
|
||||
|
||||
// http://tools.ietf.org/html/rfc4345#section-4:
|
||||
'arcfour256',
|
||||
'arcfour128',
|
||||
|
||||
'cast128-cbc',
|
||||
'arcfour',
|
||||
].filter(canUseCipher));
|
||||
|
||||
|
||||
const canUseMAC = (() => {
|
||||
const hashes = crypto.getHashes();
|
||||
return (name) => hashes.includes(MAC_INFO[name].sslName);
|
||||
})();
|
||||
const DEFAULT_MAC = [
|
||||
'hmac-sha2-256-etm@openssh.com',
|
||||
'hmac-sha2-512-etm@openssh.com',
|
||||
'hmac-sha1-etm@openssh.com',
|
||||
'hmac-sha2-256',
|
||||
'hmac-sha2-512',
|
||||
'hmac-sha1',
|
||||
].filter(canUseMAC);
|
||||
const SUPPORTED_MAC = DEFAULT_MAC.concat([
|
||||
'hmac-md5',
|
||||
'hmac-sha2-256-96', // first 96 bits of HMAC-SHA256
|
||||
'hmac-sha2-512-96', // first 96 bits of HMAC-SHA512
|
||||
'hmac-ripemd160',
|
||||
'hmac-sha1-96', // first 96 bits of HMAC-SHA1
|
||||
'hmac-md5-96', // first 96 bits of HMAC-MD5
|
||||
].filter(canUseMAC));
|
||||
|
||||
const DEFAULT_COMPRESSION = [
|
||||
'none',
|
||||
'zlib@openssh.com', // ZLIB (LZ77) compression, except
|
||||
// compression/decompression does not start until after
|
||||
// successful user authentication
|
||||
'zlib', // ZLIB (LZ77) compression
|
||||
];
|
||||
const SUPPORTED_COMPRESSION = DEFAULT_COMPRESSION.concat([
|
||||
]);
|
||||
|
||||
|
||||
const COMPAT = {
|
||||
BAD_DHGEX: 1 << 0,
|
||||
OLD_EXIT: 1 << 1,
|
||||
DYN_RPORT_BUG: 1 << 2,
|
||||
BUG_DHGEX_LARGE: 1 << 3,
|
||||
IMPLY_RSA_SHA2_SIGALGS: 1 << 4,
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
MESSAGE: {
|
||||
// Transport layer protocol -- generic (1-19)
|
||||
DISCONNECT: 1,
|
||||
IGNORE: 2,
|
||||
UNIMPLEMENTED: 3,
|
||||
DEBUG: 4,
|
||||
SERVICE_REQUEST: 5,
|
||||
SERVICE_ACCEPT: 6,
|
||||
EXT_INFO: 7, // RFC 8308
|
||||
|
||||
// Transport layer protocol -- algorithm negotiation (20-29)
|
||||
KEXINIT: 20,
|
||||
NEWKEYS: 21,
|
||||
|
||||
// Transport layer protocol -- key exchange method-specific (30-49)
|
||||
KEXDH_INIT: 30,
|
||||
KEXDH_REPLY: 31,
|
||||
|
||||
KEXDH_GEX_GROUP: 31,
|
||||
KEXDH_GEX_INIT: 32,
|
||||
KEXDH_GEX_REPLY: 33,
|
||||
KEXDH_GEX_REQUEST: 34,
|
||||
|
||||
KEXECDH_INIT: 30,
|
||||
KEXECDH_REPLY: 31,
|
||||
|
||||
// User auth protocol -- generic (50-59)
|
||||
USERAUTH_REQUEST: 50,
|
||||
USERAUTH_FAILURE: 51,
|
||||
USERAUTH_SUCCESS: 52,
|
||||
USERAUTH_BANNER: 53,
|
||||
|
||||
// User auth protocol -- user auth method-specific (60-79)
|
||||
USERAUTH_PASSWD_CHANGEREQ: 60,
|
||||
|
||||
USERAUTH_PK_OK: 60,
|
||||
|
||||
USERAUTH_INFO_REQUEST: 60,
|
||||
USERAUTH_INFO_RESPONSE: 61,
|
||||
|
||||
// Connection protocol -- generic (80-89)
|
||||
GLOBAL_REQUEST: 80,
|
||||
REQUEST_SUCCESS: 81,
|
||||
REQUEST_FAILURE: 82,
|
||||
|
||||
// Connection protocol -- channel-related (90-127)
|
||||
CHANNEL_OPEN: 90,
|
||||
CHANNEL_OPEN_CONFIRMATION: 91,
|
||||
CHANNEL_OPEN_FAILURE: 92,
|
||||
CHANNEL_WINDOW_ADJUST: 93,
|
||||
CHANNEL_DATA: 94,
|
||||
CHANNEL_EXTENDED_DATA: 95,
|
||||
CHANNEL_EOF: 96,
|
||||
CHANNEL_CLOSE: 97,
|
||||
CHANNEL_REQUEST: 98,
|
||||
CHANNEL_SUCCESS: 99,
|
||||
CHANNEL_FAILURE: 100
|
||||
|
||||
// Reserved for client protocols (128-191)
|
||||
|
||||
// Local extensions (192-155)
|
||||
},
|
||||
DISCONNECT_REASON: {
|
||||
HOST_NOT_ALLOWED_TO_CONNECT: 1,
|
||||
PROTOCOL_ERROR: 2,
|
||||
KEY_EXCHANGE_FAILED: 3,
|
||||
RESERVED: 4,
|
||||
MAC_ERROR: 5,
|
||||
COMPRESSION_ERROR: 6,
|
||||
SERVICE_NOT_AVAILABLE: 7,
|
||||
PROTOCOL_VERSION_NOT_SUPPORTED: 8,
|
||||
HOST_KEY_NOT_VERIFIABLE: 9,
|
||||
CONNECTION_LOST: 10,
|
||||
BY_APPLICATION: 11,
|
||||
TOO_MANY_CONNECTIONS: 12,
|
||||
AUTH_CANCELED_BY_USER: 13,
|
||||
NO_MORE_AUTH_METHODS_AVAILABLE: 14,
|
||||
ILLEGAL_USER_NAME: 15,
|
||||
},
|
||||
DISCONNECT_REASON_STR: undefined,
|
||||
CHANNEL_OPEN_FAILURE: {
|
||||
ADMINISTRATIVELY_PROHIBITED: 1,
|
||||
CONNECT_FAILED: 2,
|
||||
UNKNOWN_CHANNEL_TYPE: 3,
|
||||
RESOURCE_SHORTAGE: 4
|
||||
},
|
||||
TERMINAL_MODE: {
|
||||
TTY_OP_END: 0, // Indicates end of options.
|
||||
VINTR: 1, // Interrupt character; 255 if none. Similarly for the
|
||||
// other characters. Not all of these characters are
|
||||
// supported on all systems.
|
||||
VQUIT: 2, // The quit character (sends SIGQUIT signal on POSIX
|
||||
// systems).
|
||||
VERASE: 3, // Erase the character to left of the cursor.
|
||||
VKILL: 4, // Kill the current input line.
|
||||
VEOF: 5, // End-of-file character (sends EOF from the
|
||||
// terminal).
|
||||
VEOL: 6, // End-of-line character in addition to carriage
|
||||
// return and/or linefeed.
|
||||
VEOL2: 7, // Additional end-of-line character.
|
||||
VSTART: 8, // Continues paused output (normally control-Q).
|
||||
VSTOP: 9, // Pauses output (normally control-S).
|
||||
VSUSP: 10, // Suspends the current program.
|
||||
VDSUSP: 11, // Another suspend character.
|
||||
VREPRINT: 12, // Reprints the current input line.
|
||||
VWERASE: 13, // Erases a word left of cursor.
|
||||
VLNEXT: 14, // Enter the next character typed literally, even if
|
||||
// it is a special character
|
||||
VFLUSH: 15, // Character to flush output.
|
||||
VSWTCH: 16, // Switch to a different shell layer.
|
||||
VSTATUS: 17, // Prints system status line (load, command, pid,
|
||||
// etc).
|
||||
VDISCARD: 18, // Toggles the flushing of terminal output.
|
||||
IGNPAR: 30, // The ignore parity flag. The parameter SHOULD be 0
|
||||
// if this flag is FALSE, and 1 if it is TRUE.
|
||||
PARMRK: 31, // Mark parity and framing errors.
|
||||
INPCK: 32, // Enable checking of parity errors.
|
||||
ISTRIP: 33, // Strip 8th bit off characters.
|
||||
INLCR: 34, // Map NL into CR on input.
|
||||
IGNCR: 35, // Ignore CR on input.
|
||||
ICRNL: 36, // Map CR to NL on input.
|
||||
IUCLC: 37, // Translate uppercase characters to lowercase.
|
||||
IXON: 38, // Enable output flow control.
|
||||
IXANY: 39, // Any char will restart after stop.
|
||||
IXOFF: 40, // Enable input flow control.
|
||||
IMAXBEL: 41, // Ring bell on input queue full.
|
||||
ISIG: 50, // Enable signals INTR, QUIT, [D]SUSP.
|
||||
ICANON: 51, // Canonicalize input lines.
|
||||
XCASE: 52, // Enable input and output of uppercase characters by
|
||||
// preceding their lowercase equivalents with "\".
|
||||
ECHO: 53, // Enable echoing.
|
||||
ECHOE: 54, // Visually erase chars.
|
||||
ECHOK: 55, // Kill character discards current line.
|
||||
ECHONL: 56, // Echo NL even if ECHO is off.
|
||||
NOFLSH: 57, // Don't flush after interrupt.
|
||||
TOSTOP: 58, // Stop background jobs from output.
|
||||
IEXTEN: 59, // Enable extensions.
|
||||
ECHOCTL: 60, // Echo control characters as ^(Char).
|
||||
ECHOKE: 61, // Visual erase for line kill.
|
||||
PENDIN: 62, // Retype pending input.
|
||||
OPOST: 70, // Enable output processing.
|
||||
OLCUC: 71, // Convert lowercase to uppercase.
|
||||
ONLCR: 72, // Map NL to CR-NL.
|
||||
OCRNL: 73, // Translate carriage return to newline (output).
|
||||
ONOCR: 74, // Translate newline to carriage return-newline
|
||||
// (output).
|
||||
ONLRET: 75, // Newline performs a carriage return (output).
|
||||
CS7: 90, // 7 bit mode.
|
||||
CS8: 91, // 8 bit mode.
|
||||
PARENB: 92, // Parity enable.
|
||||
PARODD: 93, // Odd parity, else even.
|
||||
TTY_OP_ISPEED: 128, // Specifies the input baud rate in bits per second.
|
||||
TTY_OP_OSPEED: 129, // Specifies the output baud rate in bits per second.
|
||||
},
|
||||
CHANNEL_EXTENDED_DATATYPE: {
|
||||
STDERR: 1,
|
||||
},
|
||||
|
||||
SIGNALS: [
|
||||
'ABRT', 'ALRM', 'FPE', 'HUP', 'ILL', 'INT', 'QUIT', 'SEGV', 'TERM', 'USR1',
|
||||
'USR2', 'KILL', 'PIPE'
|
||||
].reduce((cur, val) => ({ ...cur, [val]: 1 }), {}),
|
||||
|
||||
COMPAT,
|
||||
COMPAT_CHECKS: [
|
||||
[ 'Cisco-1.25', COMPAT.BAD_DHGEX ],
|
||||
[ /^Cisco-1[.]/, COMPAT.BUG_DHGEX_LARGE ],
|
||||
[ /^[0-9.]+$/, COMPAT.OLD_EXIT ], // old SSH.com implementations
|
||||
[ /^OpenSSH_5[.][0-9]+/, COMPAT.DYN_RPORT_BUG ],
|
||||
[ /^OpenSSH_7[.]4/, COMPAT.IMPLY_RSA_SHA2_SIGALGS ],
|
||||
],
|
||||
|
||||
// KEX proposal-related
|
||||
DEFAULT_KEX,
|
||||
SUPPORTED_KEX,
|
||||
DEFAULT_SERVER_HOST_KEY,
|
||||
SUPPORTED_SERVER_HOST_KEY,
|
||||
DEFAULT_CIPHER,
|
||||
SUPPORTED_CIPHER,
|
||||
DEFAULT_MAC,
|
||||
SUPPORTED_MAC,
|
||||
DEFAULT_COMPRESSION,
|
||||
SUPPORTED_COMPRESSION,
|
||||
|
||||
curve25519Supported,
|
||||
eddsaSupported,
|
||||
};
|
||||
|
||||
module.exports.DISCONNECT_REASON_BY_VALUE =
|
||||
Array.from(Object.entries(module.exports.DISCONNECT_REASON))
|
||||
.reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {});
|
||||
+1602
File diff suppressed because it is too large
Load Diff
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
'variables': {
|
||||
'real_openssl_major%': '0',
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'sshcrypto',
|
||||
'include_dirs': [
|
||||
"<!(node -e \"require('nan')\")",
|
||||
],
|
||||
'sources': [
|
||||
'src/binding.cc'
|
||||
],
|
||||
'cflags': [ '-O3' ],
|
||||
|
||||
# Needed for OpenSSL 3.x/node.js v17.x+
|
||||
'defines': [
|
||||
'OPENSSL_API_COMPAT=0x10100000L',
|
||||
'REAL_OPENSSL_MAJOR=<(real_openssl_major)',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project>
|
||||
<ProjectOutputs>
|
||||
<ProjectOutput>
|
||||
<FullPath>C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\sshcrypto.node</FullPath>
|
||||
</ProjectOutput>
|
||||
</ProjectOutputs>
|
||||
<ContentFiles />
|
||||
<SatelliteDlls />
|
||||
<NonRecipeFileRefs />
|
||||
</Project>
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\src\binding.cc;C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\obj\sshcrypto\src\binding.obj
|
||||
C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\src\win_delay_load_hook.cc;C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\obj\sshcrypto\win_delay_load_hook.obj
|
||||
node_modules/ssh2/lib/protocol/crypto/build/Release/obj/sshcrypto/sshcrypto.tlog/link.command.1.tlog
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
^C:\USERS\DIMIR\SSH-UPDATER\NODE_MODULES\SSH2\LIB\PROTOCOL\CRYPTO\BUILD\RELEASE\OBJ\SSHCRYPTO\SRC\BINDING.OBJ|C:\USERS\DIMIR\SSH-UPDATER\NODE_MODULES\SSH2\LIB\PROTOCOL\CRYPTO\BUILD\RELEASE\OBJ\SSHCRYPTO\WIN_DELAY_LOAD_HOOK.OBJ
|
||||
C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\sshcrypto.LIB
|
||||
C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\sshcrypto.EXP
|
||||
C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\sshcrypto.IPDB
|
||||
C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\Release\sshcrypto.IOBJ
|
||||
Generated
Vendored
BIN
Binary file not shown.
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.44.35207:TargetPlatformVersion=10.0.26100.0:
|
||||
Release|x64|C:\Users\dimir\ssh-updater\node_modules\ssh2\lib\protocol\crypto\build\|
|
||||
Generated
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+19
@@ -0,0 +1,19 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2015
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sshcrypto", "sshcrypto.vcxproj", "{529648C8-47C1-F1B5-2925-8170DD79C9A4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{529648C8-47C1-F1B5-2925-8170DD79C9A4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{529648C8-47C1-F1B5-2925-8170DD79C9A4}.Debug|x64.Build.0 = Debug|x64
|
||||
{529648C8-47C1-F1B5-2925-8170DD79C9A4}.Release|x64.ActiveCfg = Release|x64
|
||||
{529648C8-47C1-F1B5-2925-8170DD79C9A4}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+528
@@ -0,0 +1,528 @@
|
||||
# Do not edit. File was generated by node-gyp's "configure" step
|
||||
{
|
||||
"target_defaults": {
|
||||
"cflags": [],
|
||||
"configurations": {
|
||||
"Debug": {
|
||||
"v8_enable_v8_checks": 0,
|
||||
"variables": {}
|
||||
},
|
||||
"Release": {
|
||||
"v8_enable_v8_checks": 1,
|
||||
"variables": {}
|
||||
}
|
||||
},
|
||||
"default_configuration": "Release",
|
||||
"defines": [],
|
||||
"include_dirs": [],
|
||||
"libraries": [],
|
||||
"msbuild_toolset": "v143",
|
||||
"msvs_windows_target_platform_version": "10.0.26100.0"
|
||||
},
|
||||
"variables": {
|
||||
"asan": 0,
|
||||
"clang": 0,
|
||||
"control_flow_guard": "false",
|
||||
"coverage": "false",
|
||||
"dcheck_always_on": 0,
|
||||
"debug_nghttp2": "false",
|
||||
"debug_node": "false",
|
||||
"enable_lto": "false",
|
||||
"enable_pgo_generate": "false",
|
||||
"enable_pgo_use": "false",
|
||||
"error_on_warn": "false",
|
||||
"force_dynamic_crt": 0,
|
||||
"host_arch": "x64",
|
||||
"icu_data_in": "..\\..\\deps\\icu-tmp\\icudt77l.dat",
|
||||
"icu_endianness": "l",
|
||||
"icu_gyp_path": "tools/icu/icu-generic.gyp",
|
||||
"icu_path": "deps/icu-small",
|
||||
"icu_small": "false",
|
||||
"icu_ver_major": "77",
|
||||
"libdir": "lib",
|
||||
"llvm_version": "19.1.5",
|
||||
"napi_build_version": "10",
|
||||
"nasm_version": "3.01",
|
||||
"node_builtin_shareable_builtins": [
|
||||
"deps/cjs-module-lexer/lexer.js",
|
||||
"deps/cjs-module-lexer/dist/lexer.js",
|
||||
"deps/undici/undici.js",
|
||||
"deps/amaro/dist/index.js"
|
||||
],
|
||||
"node_byteorder": "little",
|
||||
"node_cctest_sources": [
|
||||
"src/node_snapshot_stub.cc",
|
||||
"test/cctest/inspector/test_network_requests_buffer.cc",
|
||||
"test/cctest/inspector/test_node_protocol.cc",
|
||||
"test/cctest/node_test_fixture.cc",
|
||||
"test/cctest/test_aliased_buffer.cc",
|
||||
"test/cctest/test_base64.cc",
|
||||
"test/cctest/test_base_object_ptr.cc",
|
||||
"test/cctest/test_cppgc.cc",
|
||||
"test/cctest/test_crypto_clienthello.cc",
|
||||
"test/cctest/test_dataqueue.cc",
|
||||
"test/cctest/test_environment.cc",
|
||||
"test/cctest/test_inspector_socket.cc",
|
||||
"test/cctest/test_inspector_socket_server.cc",
|
||||
"test/cctest/test_json_utils.cc",
|
||||
"test/cctest/test_linked_binding.cc",
|
||||
"test/cctest/test_lru_cache.cc",
|
||||
"test/cctest/test_node_api.cc",
|
||||
"test/cctest/test_node_crypto.cc",
|
||||
"test/cctest/test_node_crypto_env.cc",
|
||||
"test/cctest/test_node_postmortem_metadata.cc",
|
||||
"test/cctest/test_node_task_runner.cc",
|
||||
"test/cctest/test_path.cc",
|
||||
"test/cctest/test_per_process.cc",
|
||||
"test/cctest/test_platform.cc",
|
||||
"test/cctest/test_quic_cid.cc",
|
||||
"test/cctest/test_quic_error.cc",
|
||||
"test/cctest/test_quic_tokens.cc",
|
||||
"test/cctest/test_report.cc",
|
||||
"test/cctest/test_sockaddr.cc",
|
||||
"test/cctest/test_string_bytes.cc",
|
||||
"test/cctest/test_traced_value.cc",
|
||||
"test/cctest/test_util.cc",
|
||||
"test/cctest/node_test_fixture.h"
|
||||
],
|
||||
"node_debug_lib": "false",
|
||||
"node_enable_d8": "false",
|
||||
"node_enable_v8_vtunejit": "false",
|
||||
"node_enable_v8windbg": "false",
|
||||
"node_fipsinstall": "false",
|
||||
"node_install_corepack": "true",
|
||||
"node_install_npm": "true",
|
||||
"node_library_files": [
|
||||
"lib/_http_agent.js",
|
||||
"lib/_http_client.js",
|
||||
"lib/_http_common.js",
|
||||
"lib/_http_incoming.js",
|
||||
"lib/_http_outgoing.js",
|
||||
"lib/_http_server.js",
|
||||
"lib/_stream_duplex.js",
|
||||
"lib/_stream_passthrough.js",
|
||||
"lib/_stream_readable.js",
|
||||
"lib/_stream_transform.js",
|
||||
"lib/_stream_wrap.js",
|
||||
"lib/_stream_writable.js",
|
||||
"lib/_tls_common.js",
|
||||
"lib/_tls_wrap.js",
|
||||
"lib/assert.js",
|
||||
"lib/assert/strict.js",
|
||||
"lib/async_hooks.js",
|
||||
"lib/buffer.js",
|
||||
"lib/child_process.js",
|
||||
"lib/cluster.js",
|
||||
"lib/console.js",
|
||||
"lib/constants.js",
|
||||
"lib/crypto.js",
|
||||
"lib/dgram.js",
|
||||
"lib/diagnostics_channel.js",
|
||||
"lib/dns.js",
|
||||
"lib/dns/promises.js",
|
||||
"lib/domain.js",
|
||||
"lib/events.js",
|
||||
"lib/fs.js",
|
||||
"lib/fs/promises.js",
|
||||
"lib/http.js",
|
||||
"lib/http2.js",
|
||||
"lib/https.js",
|
||||
"lib/inspector.js",
|
||||
"lib/inspector/promises.js",
|
||||
"lib/internal/abort_controller.js",
|
||||
"lib/internal/assert.js",
|
||||
"lib/internal/assert/assertion_error.js",
|
||||
"lib/internal/assert/calltracker.js",
|
||||
"lib/internal/assert/myers_diff.js",
|
||||
"lib/internal/assert/utils.js",
|
||||
"lib/internal/async_context_frame.js",
|
||||
"lib/internal/async_hooks.js",
|
||||
"lib/internal/async_local_storage/async_context_frame.js",
|
||||
"lib/internal/async_local_storage/async_hooks.js",
|
||||
"lib/internal/blob.js",
|
||||
"lib/internal/blocklist.js",
|
||||
"lib/internal/bootstrap/node.js",
|
||||
"lib/internal/bootstrap/realm.js",
|
||||
"lib/internal/bootstrap/shadow_realm.js",
|
||||
"lib/internal/bootstrap/switches/does_not_own_process_state.js",
|
||||
"lib/internal/bootstrap/switches/does_own_process_state.js",
|
||||
"lib/internal/bootstrap/switches/is_main_thread.js",
|
||||
"lib/internal/bootstrap/switches/is_not_main_thread.js",
|
||||
"lib/internal/bootstrap/web/exposed-wildcard.js",
|
||||
"lib/internal/bootstrap/web/exposed-window-or-worker.js",
|
||||
"lib/internal/buffer.js",
|
||||
"lib/internal/child_process.js",
|
||||
"lib/internal/child_process/serialization.js",
|
||||
"lib/internal/cli_table.js",
|
||||
"lib/internal/cluster/child.js",
|
||||
"lib/internal/cluster/primary.js",
|
||||
"lib/internal/cluster/round_robin_handle.js",
|
||||
"lib/internal/cluster/shared_handle.js",
|
||||
"lib/internal/cluster/utils.js",
|
||||
"lib/internal/cluster/worker.js",
|
||||
"lib/internal/console/constructor.js",
|
||||
"lib/internal/console/global.js",
|
||||
"lib/internal/constants.js",
|
||||
"lib/internal/crypto/aes.js",
|
||||
"lib/internal/crypto/argon2.js",
|
||||
"lib/internal/crypto/certificate.js",
|
||||
"lib/internal/crypto/cfrg.js",
|
||||
"lib/internal/crypto/chacha20_poly1305.js",
|
||||
"lib/internal/crypto/cipher.js",
|
||||
"lib/internal/crypto/diffiehellman.js",
|
||||
"lib/internal/crypto/ec.js",
|
||||
"lib/internal/crypto/hash.js",
|
||||
"lib/internal/crypto/hashnames.js",
|
||||
"lib/internal/crypto/hkdf.js",
|
||||
"lib/internal/crypto/kem.js",
|
||||
"lib/internal/crypto/keygen.js",
|
||||
"lib/internal/crypto/keys.js",
|
||||
"lib/internal/crypto/mac.js",
|
||||
"lib/internal/crypto/ml_dsa.js",
|
||||
"lib/internal/crypto/ml_kem.js",
|
||||
"lib/internal/crypto/pbkdf2.js",
|
||||
"lib/internal/crypto/random.js",
|
||||
"lib/internal/crypto/rsa.js",
|
||||
"lib/internal/crypto/scrypt.js",
|
||||
"lib/internal/crypto/sig.js",
|
||||
"lib/internal/crypto/util.js",
|
||||
"lib/internal/crypto/webcrypto.js",
|
||||
"lib/internal/crypto/webidl.js",
|
||||
"lib/internal/crypto/x509.js",
|
||||
"lib/internal/data_url.js",
|
||||
"lib/internal/debugger/inspect.js",
|
||||
"lib/internal/debugger/inspect_client.js",
|
||||
"lib/internal/debugger/inspect_repl.js",
|
||||
"lib/internal/dgram.js",
|
||||
"lib/internal/dns/callback_resolver.js",
|
||||
"lib/internal/dns/promises.js",
|
||||
"lib/internal/dns/utils.js",
|
||||
"lib/internal/encoding.js",
|
||||
"lib/internal/error_serdes.js",
|
||||
"lib/internal/errors.js",
|
||||
"lib/internal/errors/error_source.js",
|
||||
"lib/internal/event_target.js",
|
||||
"lib/internal/events/abort_listener.js",
|
||||
"lib/internal/events/symbols.js",
|
||||
"lib/internal/file.js",
|
||||
"lib/internal/fixed_queue.js",
|
||||
"lib/internal/freelist.js",
|
||||
"lib/internal/freeze_intrinsics.js",
|
||||
"lib/internal/fs/cp/cp-sync.js",
|
||||
"lib/internal/fs/cp/cp.js",
|
||||
"lib/internal/fs/dir.js",
|
||||
"lib/internal/fs/glob.js",
|
||||
"lib/internal/fs/promises.js",
|
||||
"lib/internal/fs/read/context.js",
|
||||
"lib/internal/fs/recursive_watch.js",
|
||||
"lib/internal/fs/rimraf.js",
|
||||
"lib/internal/fs/streams.js",
|
||||
"lib/internal/fs/sync_write_stream.js",
|
||||
"lib/internal/fs/utils.js",
|
||||
"lib/internal/fs/watchers.js",
|
||||
"lib/internal/heap_utils.js",
|
||||
"lib/internal/histogram.js",
|
||||
"lib/internal/http.js",
|
||||
"lib/internal/http2/compat.js",
|
||||
"lib/internal/http2/core.js",
|
||||
"lib/internal/http2/util.js",
|
||||
"lib/internal/inspector/network.js",
|
||||
"lib/internal/inspector/network_http.js",
|
||||
"lib/internal/inspector/network_http2.js",
|
||||
"lib/internal/inspector/network_resources.js",
|
||||
"lib/internal/inspector/network_undici.js",
|
||||
"lib/internal/inspector_async_hook.js",
|
||||
"lib/internal/inspector_network_tracking.js",
|
||||
"lib/internal/js_stream_socket.js",
|
||||
"lib/internal/legacy/processbinding.js",
|
||||
"lib/internal/linkedlist.js",
|
||||
"lib/internal/locks.js",
|
||||
"lib/internal/main/check_syntax.js",
|
||||
"lib/internal/main/embedding.js",
|
||||
"lib/internal/main/eval_stdin.js",
|
||||
"lib/internal/main/eval_string.js",
|
||||
"lib/internal/main/inspect.js",
|
||||
"lib/internal/main/mksnapshot.js",
|
||||
"lib/internal/main/print_help.js",
|
||||
"lib/internal/main/prof_process.js",
|
||||
"lib/internal/main/repl.js",
|
||||
"lib/internal/main/run_main_module.js",
|
||||
"lib/internal/main/test_runner.js",
|
||||
"lib/internal/main/watch_mode.js",
|
||||
"lib/internal/main/worker_thread.js",
|
||||
"lib/internal/mime.js",
|
||||
"lib/internal/modules/cjs/loader.js",
|
||||
"lib/internal/modules/customization_hooks.js",
|
||||
"lib/internal/modules/esm/assert.js",
|
||||
"lib/internal/modules/esm/create_dynamic_module.js",
|
||||
"lib/internal/modules/esm/formats.js",
|
||||
"lib/internal/modules/esm/get_format.js",
|
||||
"lib/internal/modules/esm/hooks.js",
|
||||
"lib/internal/modules/esm/initialize_import_meta.js",
|
||||
"lib/internal/modules/esm/load.js",
|
||||
"lib/internal/modules/esm/loader.js",
|
||||
"lib/internal/modules/esm/module_job.js",
|
||||
"lib/internal/modules/esm/module_map.js",
|
||||
"lib/internal/modules/esm/resolve.js",
|
||||
"lib/internal/modules/esm/shared_constants.js",
|
||||
"lib/internal/modules/esm/translators.js",
|
||||
"lib/internal/modules/esm/utils.js",
|
||||
"lib/internal/modules/esm/worker.js",
|
||||
"lib/internal/modules/helpers.js",
|
||||
"lib/internal/modules/package_json_reader.js",
|
||||
"lib/internal/modules/run_main.js",
|
||||
"lib/internal/modules/typescript.js",
|
||||
"lib/internal/navigator.js",
|
||||
"lib/internal/net.js",
|
||||
"lib/internal/options.js",
|
||||
"lib/internal/per_context/domexception.js",
|
||||
"lib/internal/per_context/messageport.js",
|
||||
"lib/internal/per_context/primordials.js",
|
||||
"lib/internal/perf/event_loop_delay.js",
|
||||
"lib/internal/perf/event_loop_utilization.js",
|
||||
"lib/internal/perf/nodetiming.js",
|
||||
"lib/internal/perf/observe.js",
|
||||
"lib/internal/perf/performance.js",
|
||||
"lib/internal/perf/performance_entry.js",
|
||||
"lib/internal/perf/resource_timing.js",
|
||||
"lib/internal/perf/timerify.js",
|
||||
"lib/internal/perf/usertiming.js",
|
||||
"lib/internal/perf/utils.js",
|
||||
"lib/internal/priority_queue.js",
|
||||
"lib/internal/process/execution.js",
|
||||
"lib/internal/process/finalization.js",
|
||||
"lib/internal/process/per_thread.js",
|
||||
"lib/internal/process/permission.js",
|
||||
"lib/internal/process/pre_execution.js",
|
||||
"lib/internal/process/promises.js",
|
||||
"lib/internal/process/report.js",
|
||||
"lib/internal/process/signal.js",
|
||||
"lib/internal/process/task_queues.js",
|
||||
"lib/internal/process/warning.js",
|
||||
"lib/internal/process/worker_thread_only.js",
|
||||
"lib/internal/promise_hooks.js",
|
||||
"lib/internal/querystring.js",
|
||||
"lib/internal/quic/quic.js",
|
||||
"lib/internal/quic/state.js",
|
||||
"lib/internal/quic/stats.js",
|
||||
"lib/internal/quic/symbols.js",
|
||||
"lib/internal/readline/callbacks.js",
|
||||
"lib/internal/readline/emitKeypressEvents.js",
|
||||
"lib/internal/readline/interface.js",
|
||||
"lib/internal/readline/promises.js",
|
||||
"lib/internal/readline/utils.js",
|
||||
"lib/internal/repl.js",
|
||||
"lib/internal/repl/await.js",
|
||||
"lib/internal/repl/history.js",
|
||||
"lib/internal/repl/utils.js",
|
||||
"lib/internal/socket_list.js",
|
||||
"lib/internal/socketaddress.js",
|
||||
"lib/internal/source_map/prepare_stack_trace.js",
|
||||
"lib/internal/source_map/source_map.js",
|
||||
"lib/internal/source_map/source_map_cache.js",
|
||||
"lib/internal/source_map/source_map_cache_map.js",
|
||||
"lib/internal/stream_base_commons.js",
|
||||
"lib/internal/streams/add-abort-signal.js",
|
||||
"lib/internal/streams/compose.js",
|
||||
"lib/internal/streams/destroy.js",
|
||||
"lib/internal/streams/duplex.js",
|
||||
"lib/internal/streams/duplexify.js",
|
||||
"lib/internal/streams/duplexpair.js",
|
||||
"lib/internal/streams/end-of-stream.js",
|
||||
"lib/internal/streams/fast-utf8-stream.js",
|
||||
"lib/internal/streams/from.js",
|
||||
"lib/internal/streams/lazy_transform.js",
|
||||
"lib/internal/streams/legacy.js",
|
||||
"lib/internal/streams/operators.js",
|
||||
"lib/internal/streams/passthrough.js",
|
||||
"lib/internal/streams/pipeline.js",
|
||||
"lib/internal/streams/readable.js",
|
||||
"lib/internal/streams/state.js",
|
||||
"lib/internal/streams/transform.js",
|
||||
"lib/internal/streams/utils.js",
|
||||
"lib/internal/streams/writable.js",
|
||||
"lib/internal/test/binding.js",
|
||||
"lib/internal/test/transfer.js",
|
||||
"lib/internal/test_runner/assert.js",
|
||||
"lib/internal/test_runner/coverage.js",
|
||||
"lib/internal/test_runner/harness.js",
|
||||
"lib/internal/test_runner/mock/loader.js",
|
||||
"lib/internal/test_runner/mock/mock.js",
|
||||
"lib/internal/test_runner/mock/mock_timers.js",
|
||||
"lib/internal/test_runner/reporter/dot.js",
|
||||
"lib/internal/test_runner/reporter/junit.js",
|
||||
"lib/internal/test_runner/reporter/lcov.js",
|
||||
"lib/internal/test_runner/reporter/rerun.js",
|
||||
"lib/internal/test_runner/reporter/spec.js",
|
||||
"lib/internal/test_runner/reporter/tap.js",
|
||||
"lib/internal/test_runner/reporter/utils.js",
|
||||
"lib/internal/test_runner/reporter/v8-serializer.js",
|
||||
"lib/internal/test_runner/runner.js",
|
||||
"lib/internal/test_runner/snapshot.js",
|
||||
"lib/internal/test_runner/test.js",
|
||||
"lib/internal/test_runner/tests_stream.js",
|
||||
"lib/internal/test_runner/utils.js",
|
||||
"lib/internal/timers.js",
|
||||
"lib/internal/tls/secure-context.js",
|
||||
"lib/internal/trace_events_async_hooks.js",
|
||||
"lib/internal/tty.js",
|
||||
"lib/internal/url.js",
|
||||
"lib/internal/util.js",
|
||||
"lib/internal/util/colors.js",
|
||||
"lib/internal/util/comparisons.js",
|
||||
"lib/internal/util/debuglog.js",
|
||||
"lib/internal/util/diff.js",
|
||||
"lib/internal/util/inspect.js",
|
||||
"lib/internal/util/inspector.js",
|
||||
"lib/internal/util/parse_args/parse_args.js",
|
||||
"lib/internal/util/parse_args/utils.js",
|
||||
"lib/internal/util/trace_sigint.js",
|
||||
"lib/internal/util/types.js",
|
||||
"lib/internal/v8/startup_snapshot.js",
|
||||
"lib/internal/v8_prof_polyfill.js",
|
||||
"lib/internal/v8_prof_processor.js",
|
||||
"lib/internal/validators.js",
|
||||
"lib/internal/vm.js",
|
||||
"lib/internal/vm/module.js",
|
||||
"lib/internal/wasm_web_api.js",
|
||||
"lib/internal/watch_mode/files_watcher.js",
|
||||
"lib/internal/watchdog.js",
|
||||
"lib/internal/webidl.js",
|
||||
"lib/internal/webstorage.js",
|
||||
"lib/internal/webstreams/adapters.js",
|
||||
"lib/internal/webstreams/compression.js",
|
||||
"lib/internal/webstreams/encoding.js",
|
||||
"lib/internal/webstreams/queuingstrategies.js",
|
||||
"lib/internal/webstreams/readablestream.js",
|
||||
"lib/internal/webstreams/transfer.js",
|
||||
"lib/internal/webstreams/transformstream.js",
|
||||
"lib/internal/webstreams/util.js",
|
||||
"lib/internal/webstreams/writablestream.js",
|
||||
"lib/internal/worker.js",
|
||||
"lib/internal/worker/clone_dom_exception.js",
|
||||
"lib/internal/worker/io.js",
|
||||
"lib/internal/worker/js_transferable.js",
|
||||
"lib/internal/worker/messaging.js",
|
||||
"lib/module.js",
|
||||
"lib/net.js",
|
||||
"lib/os.js",
|
||||
"lib/path.js",
|
||||
"lib/path/posix.js",
|
||||
"lib/path/win32.js",
|
||||
"lib/perf_hooks.js",
|
||||
"lib/process.js",
|
||||
"lib/punycode.js",
|
||||
"lib/querystring.js",
|
||||
"lib/quic.js",
|
||||
"lib/readline.js",
|
||||
"lib/readline/promises.js",
|
||||
"lib/repl.js",
|
||||
"lib/sea.js",
|
||||
"lib/sqlite.js",
|
||||
"lib/stream.js",
|
||||
"lib/stream/consumers.js",
|
||||
"lib/stream/promises.js",
|
||||
"lib/stream/web.js",
|
||||
"lib/string_decoder.js",
|
||||
"lib/sys.js",
|
||||
"lib/test.js",
|
||||
"lib/test/reporters.js",
|
||||
"lib/timers.js",
|
||||
"lib/timers/promises.js",
|
||||
"lib/tls.js",
|
||||
"lib/trace_events.js",
|
||||
"lib/tty.js",
|
||||
"lib/url.js",
|
||||
"lib/util.js",
|
||||
"lib/util/types.js",
|
||||
"lib/v8.js",
|
||||
"lib/vm.js",
|
||||
"lib/wasi.js",
|
||||
"lib/worker_threads.js",
|
||||
"lib/zlib.js"
|
||||
],
|
||||
"node_module_version": 137,
|
||||
"node_no_browser_globals": "false",
|
||||
"node_prefix": "\\usr\\local",
|
||||
"node_quic": "false",
|
||||
"node_release_urlbase": "https://nodejs.org/download/release/",
|
||||
"node_shared": "false",
|
||||
"node_shared_ada": "false",
|
||||
"node_shared_brotli": "false",
|
||||
"node_shared_cares": "false",
|
||||
"node_shared_http_parser": "false",
|
||||
"node_shared_libuv": "false",
|
||||
"node_shared_nghttp2": "false",
|
||||
"node_shared_nghttp3": "false",
|
||||
"node_shared_ngtcp2": "false",
|
||||
"node_shared_openssl": "false",
|
||||
"node_shared_simdjson": "false",
|
||||
"node_shared_simdutf": "false",
|
||||
"node_shared_sqlite": "false",
|
||||
"node_shared_uvwasi": "false",
|
||||
"node_shared_zlib": "false",
|
||||
"node_shared_zstd": "false",
|
||||
"node_tag": "",
|
||||
"node_target_type": "executable",
|
||||
"node_use_amaro": "true",
|
||||
"node_use_bundled_v8": "true",
|
||||
"node_use_node_code_cache": "true",
|
||||
"node_use_node_snapshot": "true",
|
||||
"node_use_openssl": "true",
|
||||
"node_use_sqlite": "true",
|
||||
"node_use_v8_platform": "true",
|
||||
"node_with_ltcg": "true",
|
||||
"node_without_node_options": "false",
|
||||
"node_write_snapshot_as_array_literals": "true",
|
||||
"openssl_is_fips": "false",
|
||||
"openssl_quic": "false",
|
||||
"ossfuzz": "false",
|
||||
"shlib_suffix": "so.137",
|
||||
"single_executable_application": "true",
|
||||
"suppress_all_error_on_warn": "false",
|
||||
"target_arch": "x64",
|
||||
"ubsan": 0,
|
||||
"use_ccache_win": 0,
|
||||
"use_prefix_to_find_headers": "false",
|
||||
"v8_enable_31bit_smis_on_64bit_arch": 0,
|
||||
"v8_enable_extensible_ro_snapshot": 0,
|
||||
"v8_enable_external_code_space": 0,
|
||||
"v8_enable_gdbjit": 0,
|
||||
"v8_enable_hugepage": 0,
|
||||
"v8_enable_i18n_support": 1,
|
||||
"v8_enable_inspector": 1,
|
||||
"v8_enable_javascript_promise_hooks": 1,
|
||||
"v8_enable_lite_mode": 0,
|
||||
"v8_enable_maglev": 1,
|
||||
"v8_enable_object_print": 1,
|
||||
"v8_enable_pointer_compression": 0,
|
||||
"v8_enable_pointer_compression_shared_cage": 0,
|
||||
"v8_enable_sandbox": 0,
|
||||
"v8_enable_short_builtin_calls": 1,
|
||||
"v8_enable_wasm_simd256_revec": 1,
|
||||
"v8_enable_webassembly": 1,
|
||||
"v8_optimized_debug": 1,
|
||||
"v8_promise_internal_field_count": 1,
|
||||
"v8_random_seed": 0,
|
||||
"v8_trace_maps": 0,
|
||||
"v8_use_siphash": 1,
|
||||
"want_separate_host_toolset": 0,
|
||||
"nodedir": "C:\\Users\\dimir\\AppData\\Local\\node-gyp\\Cache\\24.11.1",
|
||||
"python": "C:\\Users\\dimir\\AppData\\Local\\Programs\\Python\\Python312\\python.exe",
|
||||
"standalone_static_library": 1,
|
||||
"msbuild_path": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe",
|
||||
"target": "v24.11.1",
|
||||
"real_openssl_major": "3",
|
||||
"user_agent": "npm/11.12.0 node/v24.11.1 win32 x64 workspaces/false",
|
||||
"userconfig": "C:\\Users\\dimir\\.npmrc",
|
||||
"save_dev": "true",
|
||||
"prefix": "C:\\Users\\dimir\\AppData\\Roaming\\npm",
|
||||
"npm_version": "11.12.0",
|
||||
"node_gyp": "C:\\Users\\dimir\\AppData\\Roaming\\npm\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js",
|
||||
"local_prefix": "C:\\Users\\dimir\\ssh-updater",
|
||||
"init_module": "C:\\Users\\dimir\\.npm-init.js",
|
||||
"global_prefix": "C:\\Users\\dimir\\AppData\\Roaming\\npm",
|
||||
"globalconfig": "C:\\Users\\dimir\\AppData\\Roaming\\npm\\etc\\npmrc",
|
||||
"cache": "C:\\Users\\dimir\\AppData\\Local\\npm-cache"
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{529648C8-47C1-F1B5-2925-8170DD79C9A4}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>sshcrypto</RootNamespace>
|
||||
<IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
|
||||
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||
<WindowsTargetPlatformVersion>10.0.26100.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Locals">
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props"/>
|
||||
<ImportGroup Label="ExtensionSettings"/>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/>
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros"/>
|
||||
<PropertyGroup>
|
||||
<ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\..\bin\;$(MSBuildProjectDirectory)\..\bin\</ExecutablePath>
|
||||
<IgnoreImportLibrary>true</IgnoreImportLibrary>
|
||||
<IntDir>$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
|
||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.node</TargetExt>
|
||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
|
||||
<TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.node</TargetExt>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<TargetPath>$(OutDir)\$(ProjectName).node</TargetPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\include\node;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\src;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\config;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\openssl\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\uv\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\zlib;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\v8\include;..\..\..\..\..\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/Zc:__cplusplus -std:c++20 /Zm2000 %(AdditionalOptions)</AdditionalOptions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=sshcrypto;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;OPENSSL_API_COMPAT=0x10100000L;REAL_OPENSSL_MAJOR=3;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";DEBUG;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
|
||||
</Lib>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;delayimp.lib;"C:\\Users\\dimir\\AppData\\Local\\node-gyp\\Cache\\24.11.1\\x64\\node.lib"</AdditionalDependencies>
|
||||
<AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
|
||||
<DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TargetExt>.node</TargetExt>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\include\node;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\src;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\config;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\openssl\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\uv\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\zlib;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\v8\include;..\..\..\..\..\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=sshcrypto;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;OPENSSL_API_COMPAT=0x10100000L;REAL_OPENSSL_MAJOR=3;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";DEBUG;_DEBUG;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\include\node;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\src;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\config;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\openssl\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\uv\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\zlib;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\v8\include;..\..\..\..\..\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalOptions>/Zc:__cplusplus -std:c++20 /Zm2000 %(AdditionalOptions)</AdditionalOptions>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<DebugInformationFormat>OldStyle</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4351;4355;4800;4251;4275;4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ExceptionHandling>false</ExceptionHandling>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<Optimization>Full</Optimization>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=sshcrypto;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;OPENSSL_API_COMPAT=0x10100000L;REAL_OPENSSL_MAJOR=3;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<StringPooling>true</StringPooling>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<AdditionalOptions>/LTCG:INCREMENTAL %(AdditionalOptions)</AdditionalOptions>
|
||||
</Lib>
|
||||
<Link>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;delayimp.lib;"C:\\Users\\dimir\\AppData\\Local\\node-gyp\\Cache\\24.11.1\\x64\\node.lib"</AdditionalDependencies>
|
||||
<AdditionalOptions>/LTCG:INCREMENTAL /ignore:4199 %(AdditionalOptions)</AdditionalOptions>
|
||||
<DelayLoadDLLs>node.exe;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<OutputFile>$(OutDir)$(ProjectName).node</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<TargetExt>.node</TargetExt>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\include\node;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\src;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\config;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\openssl\openssl\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\uv\include;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\zlib;C:\Users\dimir\AppData\Local\node-gyp\Cache\24.11.1\deps\v8\include;..\..\..\..\..\nan;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NODE_GYP_MODULE_NAME=sshcrypto;USING_UV_SHARED=1;USING_V8_SHARED=1;V8_DEPRECATION_WARNINGS=1;_GLIBCXX_USE_CXX11_ABI=1;_FILE_OFFSET_BITS=64;WIN32;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;_HAS_EXCEPTIONS=0;NOMINMAX;OPENSSL_NO_PINSHARED;OPENSSL_THREADS;OPENSSL_API_COMPAT=0x10100000L;REAL_OPENSSL_MAJOR=3;BUILDING_NODE_EXTENSION;HOST_BINARY="node.exe";%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\binding.gyp"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\binding.cc">
|
||||
<ObjectFileName>$(IntDir)\src\binding.obj</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\src\win_delay_load_hook.cc"/>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets"/>
|
||||
<ImportGroup Label="ExtensionTargets"/>
|
||||
</Project>
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="..">
|
||||
<UniqueIdentifier>{13ED4249-1F9C-5F0F-2651-29A73F3A7059}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="..\src">
|
||||
<UniqueIdentifier>{F1003AD6-4B6D-45DF-3F56-5CAC869BF55E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:">
|
||||
<UniqueIdentifier>{F87FD356-0FEB-9BC5-D1FA-368C81420008}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users">
|
||||
<UniqueIdentifier>{707347A1-1ABA-A9B2-9AF4-DE122F5D7F08}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir">
|
||||
<UniqueIdentifier>{9110070F-34CE-9DE2-A12E-05D95C34015C}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData">
|
||||
<UniqueIdentifier>{DABCEBCE-33D1-4D68-EC67-0BC19A2A0901}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming">
|
||||
<UniqueIdentifier>{06897101-0A2C-F34A-36C2-4D0BE8BF5EB9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming\npm">
|
||||
<UniqueIdentifier>{E6F3EBE6-A3A6-AA7E-34C1-5CE4364854E4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming\npm\node_modules">
|
||||
<UniqueIdentifier>{126A39EA-1D28-5689-C126-0DA0AB5837A0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming\npm\node_modules\npm">
|
||||
<UniqueIdentifier>{E6F3EBE6-A3A6-AA7E-34C1-5CE4364854E4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules">
|
||||
<UniqueIdentifier>{126A39EA-1D28-5689-C126-0DA0AB5837A0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp">
|
||||
<UniqueIdentifier>{49558BB4-6D34-CA91-A65D-85A65792DC11}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\src">
|
||||
<UniqueIdentifier>{F1003AD6-4B6D-45DF-3F56-5CAC869BF55E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="..">
|
||||
<UniqueIdentifier>{13ED4249-1F9C-5F0F-2651-29A73F3A7059}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\binding.cc">
|
||||
<Filter>..\src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\src\win_delay_load_hook.cc">
|
||||
<Filter>C:\Users\dimir\AppData\Roaming\npm\node_modules\npm\node_modules\node-gyp\src</Filter>
|
||||
</ClCompile>
|
||||
<None Include="..\binding.gyp">
|
||||
<Filter>..</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+43
File diff suppressed because one or more lines are too long
+2300
File diff suppressed because it is too large
Load Diff
+16
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
const MESSAGE_HANDLERS = new Array(256);
|
||||
[
|
||||
require('./kex.js').HANDLERS,
|
||||
require('./handlers.misc.js'),
|
||||
].forEach((handlers) => {
|
||||
// eslint-disable-next-line prefer-const
|
||||
for (let [type, handler] of Object.entries(handlers)) {
|
||||
type = +type;
|
||||
if (isFinite(type) && type >= 0 && type < MESSAGE_HANDLERS.length)
|
||||
MESSAGE_HANDLERS[type] = handler;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = MESSAGE_HANDLERS;
|
||||
+1285
File diff suppressed because it is too large
Load Diff
+1908
File diff suppressed because it is too large
Load Diff
+1484
File diff suppressed because it is too large
Load Diff
+115
@@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('assert');
|
||||
const { inspect } = require('util');
|
||||
|
||||
// Only use this for integers! Decimal numbers do not work with this function.
|
||||
function addNumericalSeparator(val) {
|
||||
let res = '';
|
||||
let i = val.length;
|
||||
const start = val[0] === '-' ? 1 : 0;
|
||||
for (; i >= start + 4; i -= 3)
|
||||
res = `_${val.slice(i - 3, i)}${res}`;
|
||||
return `${val.slice(0, i)}${res}`;
|
||||
}
|
||||
|
||||
function oneOf(expected, thing) {
|
||||
assert(typeof thing === 'string', '`thing` has to be of type string');
|
||||
if (Array.isArray(expected)) {
|
||||
const len = expected.length;
|
||||
assert(len > 0, 'At least one expected value needs to be specified');
|
||||
expected = expected.map((i) => String(i));
|
||||
if (len > 2) {
|
||||
return `one of ${thing} ${expected.slice(0, len - 1).join(', ')}, or `
|
||||
+ expected[len - 1];
|
||||
} else if (len === 2) {
|
||||
return `one of ${thing} ${expected[0]} or ${expected[1]}`;
|
||||
}
|
||||
return `of ${thing} ${expected[0]}`;
|
||||
}
|
||||
return `of ${thing} ${String(expected)}`;
|
||||
}
|
||||
|
||||
|
||||
exports.ERR_INTERNAL_ASSERTION = class ERR_INTERNAL_ASSERTION extends Error {
|
||||
constructor(message) {
|
||||
super();
|
||||
Error.captureStackTrace(this, ERR_INTERNAL_ASSERTION);
|
||||
|
||||
const suffix = 'This is caused by either a bug in ssh2 '
|
||||
+ 'or incorrect usage of ssh2 internals.\n'
|
||||
+ 'Please open an issue with this stack trace at '
|
||||
+ 'https://github.com/mscdex/ssh2/issues\n';
|
||||
|
||||
this.message = (message === undefined ? suffix : `${message}\n${suffix}`);
|
||||
}
|
||||
};
|
||||
|
||||
const MAX_32BIT_INT = 2 ** 32;
|
||||
const MAX_32BIT_BIGINT = (() => {
|
||||
try {
|
||||
return new Function('return 2n ** 32n')();
|
||||
} catch {}
|
||||
})();
|
||||
exports.ERR_OUT_OF_RANGE = class ERR_OUT_OF_RANGE extends RangeError {
|
||||
constructor(str, range, input, replaceDefaultBoolean) {
|
||||
super();
|
||||
Error.captureStackTrace(this, ERR_OUT_OF_RANGE);
|
||||
|
||||
assert(range, 'Missing "range" argument');
|
||||
let msg = (replaceDefaultBoolean
|
||||
? str
|
||||
: `The value of "${str}" is out of range.`);
|
||||
let received;
|
||||
if (Number.isInteger(input) && Math.abs(input) > MAX_32BIT_INT) {
|
||||
received = addNumericalSeparator(String(input));
|
||||
} else if (typeof input === 'bigint') {
|
||||
received = String(input);
|
||||
if (input > MAX_32BIT_BIGINT || input < -MAX_32BIT_BIGINT)
|
||||
received = addNumericalSeparator(received);
|
||||
received += 'n';
|
||||
} else {
|
||||
received = inspect(input);
|
||||
}
|
||||
msg += ` It must be ${range}. Received ${received}`;
|
||||
|
||||
this.message = msg;
|
||||
}
|
||||
};
|
||||
|
||||
class ERR_INVALID_ARG_TYPE extends TypeError {
|
||||
constructor(name, expected, actual) {
|
||||
super();
|
||||
Error.captureStackTrace(this, ERR_INVALID_ARG_TYPE);
|
||||
|
||||
assert(typeof name === 'string', `'name' must be a string`);
|
||||
|
||||
// determiner: 'must be' or 'must not be'
|
||||
let determiner;
|
||||
if (typeof expected === 'string' && expected.startsWith('not ')) {
|
||||
determiner = 'must not be';
|
||||
expected = expected.replace(/^not /, '');
|
||||
} else {
|
||||
determiner = 'must be';
|
||||
}
|
||||
|
||||
let msg;
|
||||
if (name.endsWith(' argument')) {
|
||||
// For cases like 'first argument'
|
||||
msg = `The ${name} ${determiner} ${oneOf(expected, 'type')}`;
|
||||
} else {
|
||||
const type = (name.includes('.') ? 'property' : 'argument');
|
||||
msg = `The "${name}" ${type} ${determiner} ${oneOf(expected, 'type')}`;
|
||||
}
|
||||
|
||||
msg += `. Received type ${typeof actual}`;
|
||||
|
||||
this.message = msg;
|
||||
}
|
||||
}
|
||||
exports.ERR_INVALID_ARG_TYPE = ERR_INVALID_ARG_TYPE;
|
||||
|
||||
exports.validateNumber = function validateNumber(value, name) {
|
||||
if (typeof value !== 'number')
|
||||
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
|
||||
};
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
'use strict';
|
||||
|
||||
const Ber = require('asn1').Ber;
|
||||
|
||||
let DISCONNECT_REASON;
|
||||
|
||||
const FastBuffer = Buffer[Symbol.species];
|
||||
const TypedArrayFill = Object.getPrototypeOf(Uint8Array.prototype).fill;
|
||||
|
||||
function readUInt32BE(buf, offset) {
|
||||
return (buf[offset++] * 16777216)
|
||||
+ (buf[offset++] * 65536)
|
||||
+ (buf[offset++] * 256)
|
||||
+ buf[offset];
|
||||
}
|
||||
|
||||
function bufferCopy(src, dest, srcStart, srcEnd, destStart) {
|
||||
if (!destStart)
|
||||
destStart = 0;
|
||||
if (srcEnd > src.length)
|
||||
srcEnd = src.length;
|
||||
let nb = srcEnd - srcStart;
|
||||
const destLeft = (dest.length - destStart);
|
||||
if (nb > destLeft)
|
||||
nb = destLeft;
|
||||
dest.set(new Uint8Array(src.buffer, src.byteOffset + srcStart, nb),
|
||||
destStart);
|
||||
return nb;
|
||||
}
|
||||
|
||||
function bufferSlice(buf, start, end) {
|
||||
if (end === undefined)
|
||||
end = buf.length;
|
||||
return new FastBuffer(buf.buffer, buf.byteOffset + start, end - start);
|
||||
}
|
||||
|
||||
function makeBufferParser() {
|
||||
let pos = 0;
|
||||
let buffer;
|
||||
|
||||
const self = {
|
||||
init: (buf, start) => {
|
||||
buffer = buf;
|
||||
pos = (typeof start === 'number' ? start : 0);
|
||||
},
|
||||
pos: () => pos,
|
||||
length: () => (buffer ? buffer.length : 0),
|
||||
avail: () => (buffer && pos < buffer.length ? buffer.length - pos : 0),
|
||||
clear: () => {
|
||||
buffer = undefined;
|
||||
},
|
||||
readUInt32BE: () => {
|
||||
if (!buffer || pos + 3 >= buffer.length)
|
||||
return;
|
||||
return (buffer[pos++] * 16777216)
|
||||
+ (buffer[pos++] * 65536)
|
||||
+ (buffer[pos++] * 256)
|
||||
+ buffer[pos++];
|
||||
},
|
||||
readUInt64BE: (behavior) => {
|
||||
if (!buffer || pos + 7 >= buffer.length)
|
||||
return;
|
||||
switch (behavior) {
|
||||
case 'always':
|
||||
return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`);
|
||||
case 'maybe':
|
||||
if (buffer[pos] > 0x1F)
|
||||
return BigInt(`0x${buffer.hexSlice(pos, pos += 8)}`);
|
||||
// FALLTHROUGH
|
||||
default:
|
||||
return (buffer[pos++] * 72057594037927940)
|
||||
+ (buffer[pos++] * 281474976710656)
|
||||
+ (buffer[pos++] * 1099511627776)
|
||||
+ (buffer[pos++] * 4294967296)
|
||||
+ (buffer[pos++] * 16777216)
|
||||
+ (buffer[pos++] * 65536)
|
||||
+ (buffer[pos++] * 256)
|
||||
+ buffer[pos++];
|
||||
}
|
||||
},
|
||||
skip: (n) => {
|
||||
if (buffer && n > 0)
|
||||
pos += n;
|
||||
},
|
||||
skipString: () => {
|
||||
const len = self.readUInt32BE();
|
||||
if (len === undefined)
|
||||
return;
|
||||
pos += len;
|
||||
return (pos <= buffer.length ? len : undefined);
|
||||
},
|
||||
readByte: () => {
|
||||
if (buffer && pos < buffer.length)
|
||||
return buffer[pos++];
|
||||
},
|
||||
readBool: () => {
|
||||
if (buffer && pos < buffer.length)
|
||||
return !!buffer[pos++];
|
||||
},
|
||||
readList: () => {
|
||||
const list = self.readString(true);
|
||||
if (list === undefined)
|
||||
return;
|
||||
return (list ? list.split(',') : []);
|
||||
},
|
||||
readString: (dest, maxLen) => {
|
||||
if (typeof dest === 'number') {
|
||||
maxLen = dest;
|
||||
dest = undefined;
|
||||
}
|
||||
|
||||
const len = self.readUInt32BE();
|
||||
if (len === undefined)
|
||||
return;
|
||||
|
||||
if ((buffer.length - pos) < len
|
||||
|| (typeof maxLen === 'number' && len > maxLen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dest) {
|
||||
if (Buffer.isBuffer(dest))
|
||||
return bufferCopy(buffer, dest, pos, pos += len);
|
||||
return buffer.utf8Slice(pos, pos += len);
|
||||
}
|
||||
return bufferSlice(buffer, pos, pos += len);
|
||||
},
|
||||
readRaw: (len) => {
|
||||
if (!buffer)
|
||||
return;
|
||||
if (typeof len !== 'number')
|
||||
return bufferSlice(buffer, pos, pos += (buffer.length - pos));
|
||||
if ((buffer.length - pos) >= len)
|
||||
return bufferSlice(buffer, pos, pos += len);
|
||||
},
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
function makeError(msg, level, fatal) {
|
||||
const err = new Error(msg);
|
||||
if (typeof level === 'boolean') {
|
||||
fatal = level;
|
||||
err.level = 'protocol';
|
||||
} else {
|
||||
err.level = level || 'protocol';
|
||||
}
|
||||
err.fatal = !!fatal;
|
||||
return err;
|
||||
}
|
||||
|
||||
function writeUInt32BE(buf, value, offset) {
|
||||
buf[offset++] = (value >>> 24);
|
||||
buf[offset++] = (value >>> 16);
|
||||
buf[offset++] = (value >>> 8);
|
||||
buf[offset++] = value;
|
||||
return offset;
|
||||
}
|
||||
|
||||
const utilBufferParser = makeBufferParser();
|
||||
|
||||
module.exports = {
|
||||
bufferCopy,
|
||||
bufferSlice,
|
||||
FastBuffer,
|
||||
bufferFill: (buf, value, start, end) => {
|
||||
return TypedArrayFill.call(buf, value, start, end);
|
||||
},
|
||||
makeError,
|
||||
doFatalError: (protocol, msg, level, reason) => {
|
||||
let err;
|
||||
if (DISCONNECT_REASON === undefined)
|
||||
({ DISCONNECT_REASON } = require('./constants.js'));
|
||||
if (msg instanceof Error) {
|
||||
// doFatalError(protocol, err[, reason])
|
||||
err = msg;
|
||||
if (typeof level !== 'number')
|
||||
reason = DISCONNECT_REASON.PROTOCOL_ERROR;
|
||||
else
|
||||
reason = level;
|
||||
} else {
|
||||
// doFatalError(protocol, msg[, level[, reason]])
|
||||
err = makeError(msg, level, true);
|
||||
}
|
||||
if (typeof reason !== 'number')
|
||||
reason = DISCONNECT_REASON.PROTOCOL_ERROR;
|
||||
protocol.disconnect(reason);
|
||||
protocol._destruct();
|
||||
protocol._onError(err);
|
||||
return Infinity;
|
||||
},
|
||||
readUInt32BE,
|
||||
writeUInt32BE,
|
||||
writeUInt32LE: (buf, value, offset) => {
|
||||
buf[offset++] = value;
|
||||
buf[offset++] = (value >>> 8);
|
||||
buf[offset++] = (value >>> 16);
|
||||
buf[offset++] = (value >>> 24);
|
||||
return offset;
|
||||
},
|
||||
makeBufferParser,
|
||||
bufferParser: makeBufferParser(),
|
||||
readString: (buffer, start, dest, maxLen) => {
|
||||
if (typeof dest === 'number') {
|
||||
maxLen = dest;
|
||||
dest = undefined;
|
||||
}
|
||||
|
||||
if (start === undefined)
|
||||
start = 0;
|
||||
|
||||
const left = (buffer.length - start);
|
||||
if (start < 0 || start >= buffer.length || left < 4)
|
||||
return;
|
||||
|
||||
const len = readUInt32BE(buffer, start);
|
||||
if (left < (4 + len) || (typeof maxLen === 'number' && len > maxLen))
|
||||
return;
|
||||
|
||||
start += 4;
|
||||
const end = start + len;
|
||||
buffer._pos = end;
|
||||
|
||||
if (dest) {
|
||||
if (Buffer.isBuffer(dest))
|
||||
return bufferCopy(buffer, dest, start, end);
|
||||
return buffer.utf8Slice(start, end);
|
||||
}
|
||||
return bufferSlice(buffer, start, end);
|
||||
},
|
||||
sigSSHToASN1: (sig, type) => {
|
||||
switch (type) {
|
||||
case 'ssh-dss': {
|
||||
if (sig.length > 40)
|
||||
return sig;
|
||||
// Change bare signature r and s values to ASN.1 BER values for OpenSSL
|
||||
const asnWriter = new Ber.Writer();
|
||||
asnWriter.startSequence();
|
||||
let r = sig.slice(0, 20);
|
||||
let s = sig.slice(20);
|
||||
if (r[0] & 0x80) {
|
||||
const rNew = Buffer.allocUnsafe(21);
|
||||
rNew[0] = 0x00;
|
||||
r.copy(rNew, 1);
|
||||
r = rNew;
|
||||
} else if (r[0] === 0x00 && !(r[1] & 0x80)) {
|
||||
r = r.slice(1);
|
||||
}
|
||||
if (s[0] & 0x80) {
|
||||
const sNew = Buffer.allocUnsafe(21);
|
||||
sNew[0] = 0x00;
|
||||
s.copy(sNew, 1);
|
||||
s = sNew;
|
||||
} else if (s[0] === 0x00 && !(s[1] & 0x80)) {
|
||||
s = s.slice(1);
|
||||
}
|
||||
asnWriter.writeBuffer(r, Ber.Integer);
|
||||
asnWriter.writeBuffer(s, Ber.Integer);
|
||||
asnWriter.endSequence();
|
||||
return asnWriter.buffer;
|
||||
}
|
||||
case 'ecdsa-sha2-nistp256':
|
||||
case 'ecdsa-sha2-nistp384':
|
||||
case 'ecdsa-sha2-nistp521': {
|
||||
utilBufferParser.init(sig, 0);
|
||||
const r = utilBufferParser.readString();
|
||||
const s = utilBufferParser.readString();
|
||||
utilBufferParser.clear();
|
||||
if (r === undefined || s === undefined)
|
||||
return;
|
||||
|
||||
const asnWriter = new Ber.Writer();
|
||||
asnWriter.startSequence();
|
||||
asnWriter.writeBuffer(r, Ber.Integer);
|
||||
asnWriter.writeBuffer(s, Ber.Integer);
|
||||
asnWriter.endSequence();
|
||||
return asnWriter.buffer;
|
||||
}
|
||||
default:
|
||||
return sig;
|
||||
}
|
||||
},
|
||||
convertSignature: (signature, keyType) => {
|
||||
switch (keyType) {
|
||||
case 'ssh-dss': {
|
||||
if (signature.length <= 40)
|
||||
return signature;
|
||||
// This is a quick and dirty way to get from BER encoded r and s that
|
||||
// OpenSSL gives us, to just the bare values back to back (40 bytes
|
||||
// total) like OpenSSH (and possibly others) are expecting
|
||||
const asnReader = new Ber.Reader(signature);
|
||||
asnReader.readSequence();
|
||||
let r = asnReader.readString(Ber.Integer, true);
|
||||
let s = asnReader.readString(Ber.Integer, true);
|
||||
let rOffset = 0;
|
||||
let sOffset = 0;
|
||||
if (r.length < 20) {
|
||||
const rNew = Buffer.allocUnsafe(20);
|
||||
rNew.set(r, 1);
|
||||
r = rNew;
|
||||
r[0] = 0;
|
||||
}
|
||||
if (s.length < 20) {
|
||||
const sNew = Buffer.allocUnsafe(20);
|
||||
sNew.set(s, 1);
|
||||
s = sNew;
|
||||
s[0] = 0;
|
||||
}
|
||||
if (r.length > 20 && r[0] === 0)
|
||||
rOffset = 1;
|
||||
if (s.length > 20 && s[0] === 0)
|
||||
sOffset = 1;
|
||||
const newSig =
|
||||
Buffer.allocUnsafe((r.length - rOffset) + (s.length - sOffset));
|
||||
bufferCopy(r, newSig, rOffset, r.length, 0);
|
||||
bufferCopy(s, newSig, sOffset, s.length, r.length - rOffset);
|
||||
return newSig;
|
||||
}
|
||||
case 'ecdsa-sha2-nistp256':
|
||||
case 'ecdsa-sha2-nistp384':
|
||||
case 'ecdsa-sha2-nistp521': {
|
||||
if (signature[0] === 0)
|
||||
return signature;
|
||||
// Convert SSH signature parameters to ASN.1 BER values for OpenSSL
|
||||
const asnReader = new Ber.Reader(signature);
|
||||
asnReader.readSequence();
|
||||
const r = asnReader.readString(Ber.Integer, true);
|
||||
const s = asnReader.readString(Ber.Integer, true);
|
||||
if (r === null || s === null)
|
||||
return;
|
||||
const newSig = Buffer.allocUnsafe(4 + r.length + 4 + s.length);
|
||||
writeUInt32BE(newSig, r.length, 0);
|
||||
newSig.set(r, 4);
|
||||
writeUInt32BE(newSig, s.length, 4 + r.length);
|
||||
newSig.set(s, 4 + 4 + r.length);
|
||||
return newSig;
|
||||
}
|
||||
}
|
||||
|
||||
return signature;
|
||||
},
|
||||
sendPacket: (proto, packet, bypass) => {
|
||||
if (!bypass && proto._kexinit !== undefined) {
|
||||
// We're currently in the middle of a handshake
|
||||
|
||||
if (proto._queue === undefined)
|
||||
proto._queue = [];
|
||||
proto._queue.push(packet);
|
||||
proto._debug && proto._debug('Outbound: ... packet queued');
|
||||
return false;
|
||||
}
|
||||
proto._cipher.encrypt(packet);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
'use strict';
|
||||
|
||||
const { kMaxLength } = require('buffer');
|
||||
const {
|
||||
createInflate,
|
||||
constants: {
|
||||
DEFLATE,
|
||||
INFLATE,
|
||||
Z_DEFAULT_CHUNK,
|
||||
Z_DEFAULT_COMPRESSION,
|
||||
Z_DEFAULT_MEMLEVEL,
|
||||
Z_DEFAULT_STRATEGY,
|
||||
Z_DEFAULT_WINDOWBITS,
|
||||
Z_PARTIAL_FLUSH,
|
||||
}
|
||||
} = require('zlib');
|
||||
const ZlibHandle = createInflate()._handle.constructor;
|
||||
|
||||
function processCallback() {
|
||||
throw new Error('Should not get here');
|
||||
}
|
||||
|
||||
function zlibOnError(message, errno, code) {
|
||||
const self = this._owner;
|
||||
// There is no way to cleanly recover.
|
||||
// Continuing only obscures problems.
|
||||
|
||||
const error = new Error(message);
|
||||
error.errno = errno;
|
||||
error.code = code;
|
||||
self._err = error;
|
||||
}
|
||||
|
||||
function _close(engine) {
|
||||
// Caller may invoke .close after a zlib error (which will null _handle).
|
||||
if (!engine._handle)
|
||||
return;
|
||||
|
||||
engine._handle.close();
|
||||
engine._handle = null;
|
||||
}
|
||||
|
||||
class Zlib {
|
||||
constructor(mode) {
|
||||
const windowBits = Z_DEFAULT_WINDOWBITS;
|
||||
const level = Z_DEFAULT_COMPRESSION;
|
||||
const memLevel = Z_DEFAULT_MEMLEVEL;
|
||||
const strategy = Z_DEFAULT_STRATEGY;
|
||||
const dictionary = undefined;
|
||||
|
||||
this._err = undefined;
|
||||
this._writeState = new Uint32Array(2);
|
||||
this._chunkSize = Z_DEFAULT_CHUNK;
|
||||
this._maxOutputLength = kMaxLength;
|
||||
this._outBuffer = Buffer.allocUnsafe(this._chunkSize);
|
||||
this._outOffset = 0;
|
||||
|
||||
this._handle = new ZlibHandle(mode);
|
||||
this._handle._owner = this;
|
||||
this._handle.onerror = zlibOnError;
|
||||
this._handle.init(windowBits,
|
||||
level,
|
||||
memLevel,
|
||||
strategy,
|
||||
this._writeState,
|
||||
processCallback,
|
||||
dictionary);
|
||||
}
|
||||
|
||||
writeSync(chunk, retChunks) {
|
||||
const handle = this._handle;
|
||||
if (!handle)
|
||||
throw new Error('Invalid Zlib instance');
|
||||
|
||||
let availInBefore = chunk.length;
|
||||
let availOutBefore = this._chunkSize - this._outOffset;
|
||||
let inOff = 0;
|
||||
let availOutAfter;
|
||||
let availInAfter;
|
||||
|
||||
let buffers;
|
||||
let nread = 0;
|
||||
const state = this._writeState;
|
||||
let buffer = this._outBuffer;
|
||||
let offset = this._outOffset;
|
||||
const chunkSize = this._chunkSize;
|
||||
|
||||
while (true) {
|
||||
handle.writeSync(Z_PARTIAL_FLUSH,
|
||||
chunk, // in
|
||||
inOff, // in_off
|
||||
availInBefore, // in_len
|
||||
buffer, // out
|
||||
offset, // out_off
|
||||
availOutBefore); // out_len
|
||||
if (this._err)
|
||||
throw this._err;
|
||||
|
||||
availOutAfter = state[0];
|
||||
availInAfter = state[1];
|
||||
|
||||
const inDelta = availInBefore - availInAfter;
|
||||
const have = availOutBefore - availOutAfter;
|
||||
|
||||
if (have > 0) {
|
||||
const out = (offset === 0 && have === buffer.length
|
||||
? buffer
|
||||
: buffer.slice(offset, offset + have));
|
||||
offset += have;
|
||||
if (!buffers)
|
||||
buffers = out;
|
||||
else if (buffers.push === undefined)
|
||||
buffers = [buffers, out];
|
||||
else
|
||||
buffers.push(out);
|
||||
nread += out.byteLength;
|
||||
|
||||
if (nread > this._maxOutputLength) {
|
||||
_close(this);
|
||||
throw new Error(
|
||||
`Output length exceeded maximum of ${this._maxOutputLength}`
|
||||
);
|
||||
}
|
||||
} else if (have !== 0) {
|
||||
throw new Error('have should not go down');
|
||||
}
|
||||
|
||||
// Exhausted the output buffer, or used all the input create a new one.
|
||||
if (availOutAfter === 0 || offset >= chunkSize) {
|
||||
availOutBefore = chunkSize;
|
||||
offset = 0;
|
||||
buffer = Buffer.allocUnsafe(chunkSize);
|
||||
}
|
||||
|
||||
if (availOutAfter === 0) {
|
||||
// Not actually done. Need to reprocess.
|
||||
// Also, update the availInBefore to the availInAfter value,
|
||||
// so that if we have to hit it a third (fourth, etc.) time,
|
||||
// it'll have the correct byte counts.
|
||||
inOff += inDelta;
|
||||
availInBefore = availInAfter;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._outBuffer = buffer;
|
||||
this._outOffset = offset;
|
||||
|
||||
if (nread === 0)
|
||||
buffers = Buffer.alloc(0);
|
||||
|
||||
if (retChunks) {
|
||||
buffers.totalLen = nread;
|
||||
return buffers;
|
||||
}
|
||||
|
||||
if (buffers.push === undefined)
|
||||
return buffers;
|
||||
|
||||
const output = Buffer.allocUnsafe(nread);
|
||||
for (let i = 0, p = 0; i < buffers.length; ++i) {
|
||||
const buf = buffers[i];
|
||||
output.set(buf, p);
|
||||
p += buf.length;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
class ZlibPacketWriter {
|
||||
constructor(protocol) {
|
||||
this.allocStart = 0;
|
||||
this.allocStartKEX = 0;
|
||||
this._protocol = protocol;
|
||||
this._zlib = new Zlib(DEFLATE);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if (this._zlib)
|
||||
_close(this._zlib);
|
||||
}
|
||||
|
||||
alloc(payloadSize, force) {
|
||||
return Buffer.allocUnsafe(payloadSize);
|
||||
}
|
||||
|
||||
finalize(payload, force) {
|
||||
if (this._protocol._kexinit === undefined || force) {
|
||||
const output = this._zlib.writeSync(payload, true);
|
||||
const packet = this._protocol._cipher.allocPacket(output.totalLen);
|
||||
if (output.push === undefined) {
|
||||
packet.set(output, 5);
|
||||
} else {
|
||||
for (let i = 0, p = 5; i < output.length; ++i) {
|
||||
const chunk = output[i];
|
||||
packet.set(chunk, p);
|
||||
p += chunk.length;
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
|
||||
class PacketWriter {
|
||||
constructor(protocol) {
|
||||
this.allocStart = 5;
|
||||
this.allocStartKEX = 5;
|
||||
this._protocol = protocol;
|
||||
}
|
||||
|
||||
cleanup() {}
|
||||
|
||||
alloc(payloadSize, force) {
|
||||
if (this._protocol._kexinit === undefined || force)
|
||||
return this._protocol._cipher.allocPacket(payloadSize);
|
||||
return Buffer.allocUnsafe(payloadSize);
|
||||
}
|
||||
|
||||
finalize(packet, force) {
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
class ZlibPacketReader {
|
||||
constructor() {
|
||||
this._zlib = new Zlib(INFLATE);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if (this._zlib)
|
||||
_close(this._zlib);
|
||||
}
|
||||
|
||||
read(data) {
|
||||
return this._zlib.writeSync(data, false);
|
||||
}
|
||||
}
|
||||
|
||||
class PacketReader {
|
||||
cleanup() {}
|
||||
|
||||
read(data) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PacketReader,
|
||||
PacketWriter,
|
||||
ZlibPacketReader,
|
||||
ZlibPacketWriter,
|
||||
};
|
||||
+1380
File diff suppressed because it is too large
Load Diff
+336
@@ -0,0 +1,336 @@
|
||||
'use strict';
|
||||
|
||||
const { SFTP } = require('./protocol/SFTP.js');
|
||||
|
||||
const MAX_CHANNEL = 2 ** 32 - 1;
|
||||
|
||||
function onChannelOpenFailure(self, recipient, info, cb) {
|
||||
self._chanMgr.remove(recipient);
|
||||
if (typeof cb !== 'function')
|
||||
return;
|
||||
|
||||
let err;
|
||||
if (info instanceof Error) {
|
||||
err = info;
|
||||
} else if (typeof info === 'object' && info !== null) {
|
||||
err = new Error(`(SSH) Channel open failure: ${info.description}`);
|
||||
err.reason = info.reason;
|
||||
} else {
|
||||
err = new Error(
|
||||
'(SSH) Channel open failure: server closed channel unexpectedly'
|
||||
);
|
||||
err.reason = '';
|
||||
}
|
||||
|
||||
cb(err);
|
||||
}
|
||||
|
||||
function onCHANNEL_CLOSE(self, recipient, channel, err, dead) {
|
||||
if (typeof channel === 'function') {
|
||||
// We got CHANNEL_CLOSE instead of CHANNEL_OPEN_FAILURE when
|
||||
// requesting to open a channel
|
||||
onChannelOpenFailure(self, recipient, err, channel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof channel !== 'object' || channel === null)
|
||||
return;
|
||||
|
||||
if (channel.incoming && channel.incoming.state === 'closed')
|
||||
return;
|
||||
|
||||
self._chanMgr.remove(recipient);
|
||||
|
||||
if (channel.server && channel.constructor.name === 'Session')
|
||||
return;
|
||||
|
||||
channel.incoming.state = 'closed';
|
||||
|
||||
if (channel.readable)
|
||||
channel.push(null);
|
||||
if (channel.server) {
|
||||
if (channel.stderr.writable)
|
||||
channel.stderr.end();
|
||||
} else if (channel.stderr.readable) {
|
||||
channel.stderr.push(null);
|
||||
}
|
||||
|
||||
if (channel.constructor !== SFTP
|
||||
&& (channel.outgoing.state === 'open'
|
||||
|| channel.outgoing.state === 'eof')
|
||||
&& !dead) {
|
||||
channel.close();
|
||||
}
|
||||
if (channel.outgoing.state === 'closing')
|
||||
channel.outgoing.state = 'closed';
|
||||
|
||||
const readState = channel._readableState;
|
||||
const writeState = channel._writableState;
|
||||
if (writeState && !writeState.ending && !writeState.finished && !dead)
|
||||
channel.end();
|
||||
|
||||
// Take care of any outstanding channel requests
|
||||
const chanCallbacks = channel._callbacks;
|
||||
channel._callbacks = [];
|
||||
for (let i = 0; i < chanCallbacks.length; ++i)
|
||||
chanCallbacks[i](true);
|
||||
|
||||
if (channel.server) {
|
||||
if (!channel.readable
|
||||
|| channel.destroyed
|
||||
|| (readState && readState.endEmitted)) {
|
||||
channel.emit('close');
|
||||
} else {
|
||||
channel.once('end', () => channel.emit('close'));
|
||||
}
|
||||
} else {
|
||||
let doClose;
|
||||
switch (channel.type) {
|
||||
case 'direct-streamlocal@openssh.com':
|
||||
case 'direct-tcpip':
|
||||
doClose = () => channel.emit('close');
|
||||
break;
|
||||
default: {
|
||||
// Align more with node child processes, where the close event gets
|
||||
// the same arguments as the exit event
|
||||
const exit = channel._exit;
|
||||
doClose = () => {
|
||||
if (exit.code === null)
|
||||
channel.emit('close', exit.code, exit.signal, exit.dump, exit.desc);
|
||||
else
|
||||
channel.emit('close', exit.code);
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!channel.readable
|
||||
|| channel.destroyed
|
||||
|| (readState && readState.endEmitted)) {
|
||||
doClose();
|
||||
} else {
|
||||
channel.once('end', doClose);
|
||||
}
|
||||
|
||||
const errReadState = channel.stderr._readableState;
|
||||
if (!channel.stderr.readable
|
||||
|| channel.stderr.destroyed
|
||||
|| (errReadState && errReadState.endEmitted)) {
|
||||
channel.stderr.emit('close');
|
||||
} else {
|
||||
channel.stderr.once('end', () => channel.stderr.emit('close'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelManager {
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
this._channels = {};
|
||||
this._cur = -1;
|
||||
this._count = 0;
|
||||
}
|
||||
add(val) {
|
||||
// Attempt to reserve an id
|
||||
|
||||
let id;
|
||||
// Optimized paths
|
||||
if (this._cur < MAX_CHANNEL) {
|
||||
id = ++this._cur;
|
||||
} else if (this._count === 0) {
|
||||
// Revert and reset back to fast path once we no longer have any channels
|
||||
// open
|
||||
this._cur = 0;
|
||||
id = 0;
|
||||
} else {
|
||||
// Slower lookup path
|
||||
|
||||
// This path is triggered we have opened at least MAX_CHANNEL channels
|
||||
// while having at least one channel open at any given time, so we have
|
||||
// to search for a free id.
|
||||
const channels = this._channels;
|
||||
for (let i = 0; i < MAX_CHANNEL; ++i) {
|
||||
if (channels[i] === undefined) {
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (id === undefined)
|
||||
return -1;
|
||||
|
||||
this._channels[id] = (val || true);
|
||||
++this._count;
|
||||
|
||||
return id;
|
||||
}
|
||||
update(id, val) {
|
||||
if (typeof id !== 'number' || id < 0 || id >= MAX_CHANNEL || !isFinite(id))
|
||||
throw new Error(`Invalid channel id: ${id}`);
|
||||
|
||||
if (val && this._channels[id])
|
||||
this._channels[id] = val;
|
||||
}
|
||||
get(id) {
|
||||
if (typeof id !== 'number' || id < 0 || id >= MAX_CHANNEL || !isFinite(id))
|
||||
throw new Error(`Invalid channel id: ${id}`);
|
||||
|
||||
return this._channels[id];
|
||||
}
|
||||
remove(id) {
|
||||
if (typeof id !== 'number' || id < 0 || id >= MAX_CHANNEL || !isFinite(id))
|
||||
throw new Error(`Invalid channel id: ${id}`);
|
||||
|
||||
if (this._channels[id]) {
|
||||
delete this._channels[id];
|
||||
if (this._count)
|
||||
--this._count;
|
||||
}
|
||||
}
|
||||
cleanup(err) {
|
||||
const channels = this._channels;
|
||||
this._channels = {};
|
||||
this._cur = -1;
|
||||
this._count = 0;
|
||||
|
||||
const chanIDs = Object.keys(channels);
|
||||
const client = this._client;
|
||||
for (let i = 0; i < chanIDs.length; ++i) {
|
||||
const id = +chanIDs[i];
|
||||
const channel = channels[id];
|
||||
onCHANNEL_CLOSE(client, id, channel._channel || channel, err, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isRegExp = (() => {
|
||||
const toString = Object.prototype.toString;
|
||||
return (val) => toString.call(val) === '[object RegExp]';
|
||||
})();
|
||||
|
||||
function generateAlgorithmList(algoList, defaultList, supportedList) {
|
||||
if (Array.isArray(algoList) && algoList.length > 0) {
|
||||
// Exact list
|
||||
for (let i = 0; i < algoList.length; ++i) {
|
||||
if (supportedList.indexOf(algoList[i]) === -1)
|
||||
throw new Error(`Unsupported algorithm: ${algoList[i]}`);
|
||||
}
|
||||
return algoList;
|
||||
}
|
||||
|
||||
if (typeof algoList === 'object' && algoList !== null) {
|
||||
// Operations based on the default list
|
||||
const keys = Object.keys(algoList);
|
||||
let list = defaultList;
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
let val = algoList[key];
|
||||
switch (key) {
|
||||
case 'append':
|
||||
if (!Array.isArray(val))
|
||||
val = [val];
|
||||
if (Array.isArray(val)) {
|
||||
for (let j = 0; j < val.length; ++j) {
|
||||
const append = val[j];
|
||||
if (typeof append === 'string') {
|
||||
if (!append || list.indexOf(append) !== -1)
|
||||
continue;
|
||||
if (supportedList.indexOf(append) === -1)
|
||||
throw new Error(`Unsupported algorithm: ${append}`);
|
||||
if (list === defaultList)
|
||||
list = list.slice();
|
||||
list.push(append);
|
||||
} else if (isRegExp(append)) {
|
||||
for (let k = 0; k < supportedList.length; ++k) {
|
||||
const algo = supportedList[k];
|
||||
if (append.test(algo)) {
|
||||
if (list.indexOf(algo) !== -1)
|
||||
continue;
|
||||
if (list === defaultList)
|
||||
list = list.slice();
|
||||
list.push(algo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'prepend':
|
||||
if (!Array.isArray(val))
|
||||
val = [val];
|
||||
if (Array.isArray(val)) {
|
||||
for (let j = val.length; j >= 0; --j) {
|
||||
const prepend = val[j];
|
||||
if (typeof prepend === 'string') {
|
||||
if (!prepend || list.indexOf(prepend) !== -1)
|
||||
continue;
|
||||
if (supportedList.indexOf(prepend) === -1)
|
||||
throw new Error(`Unsupported algorithm: ${prepend}`);
|
||||
if (list === defaultList)
|
||||
list = list.slice();
|
||||
list.unshift(prepend);
|
||||
} else if (isRegExp(prepend)) {
|
||||
for (let k = supportedList.length; k >= 0; --k) {
|
||||
const algo = supportedList[k];
|
||||
if (prepend.test(algo)) {
|
||||
if (list.indexOf(algo) !== -1)
|
||||
continue;
|
||||
if (list === defaultList)
|
||||
list = list.slice();
|
||||
list.unshift(algo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'remove':
|
||||
if (!Array.isArray(val))
|
||||
val = [val];
|
||||
if (Array.isArray(val)) {
|
||||
for (let j = 0; j < val.length; ++j) {
|
||||
const search = val[j];
|
||||
if (typeof search === 'string') {
|
||||
if (!search)
|
||||
continue;
|
||||
const idx = list.indexOf(search);
|
||||
if (idx === -1)
|
||||
continue;
|
||||
if (list === defaultList)
|
||||
list = list.slice();
|
||||
list.splice(idx, 1);
|
||||
} else if (isRegExp(search)) {
|
||||
for (let k = 0; k < list.length; ++k) {
|
||||
if (search.test(list[k])) {
|
||||
if (list === defaultList)
|
||||
list = list.slice();
|
||||
list.splice(k, 1);
|
||||
--k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return defaultList;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ChannelManager,
|
||||
generateAlgorithmList,
|
||||
onChannelOpenFailure,
|
||||
onCHANNEL_CLOSE,
|
||||
isWritable: (stream) => {
|
||||
// XXX: hack to workaround regression in node
|
||||
// See: https://github.com/nodejs/node/issues/36029
|
||||
return (stream
|
||||
&& stream.writable
|
||||
&& stream._readableState
|
||||
&& stream._readableState.ended === false);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user