@zero-transfer/ssh 0.4.2 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/index.cjs +97 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +111 -40
- package/dist/index.d.ts +111 -40
- package/dist/index.mjs +95 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npm install @zero-transfer/ssh
|
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
Standalone, zero-dependency SSH 2.0 stack
|
|
13
|
+
Standalone, zero-dependency SSH 2.0 stack - RFC 4253 transport (curve25519-sha256 KEX, AES-CTR + HMAC-SHA2), RFC 4252 user authentication (password, keyboard-interactive, publickey for Ed25519 / RSA-SHA2-256/512), RFC 5656 ECDSA host keys (P-256/384/521), RFC 4254 channels, OpenSSH `known_hosts` parsing, and host-key pinning. The same protocol stack that powers the SFTP provider, exposed for callers that need direct SSH features (custom subsystems, exec channels, port forwarding, custom RPC) - capabilities the Node.js ecosystem otherwise lacks a maintained pure-JS solution for.
|
|
14
14
|
|
|
15
15
|
## Usage
|
|
16
16
|
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
|
|
25
25
|
## Public surface
|
|
26
26
|
|
|
27
|
-
This package publishes a narrowed surface of **
|
|
27
|
+
This package publishes a narrowed surface of **26** exports. These symbols are also available from [`@zero-transfer/sdk`](https://www.npmjs.com/package/@zero-transfer/sdk); the table below links into the full API reference:
|
|
28
28
|
|
|
29
29
|
| Symbol | Kind | Notes |
|
|
30
30
|
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ------------------ |
|
|
@@ -51,6 +51,9 @@ This package publishes a narrowed surface of **23** exports. These symbols are a
|
|
|
51
51
|
| [`matchKnownHostsEntry`](https://github.com/tonywied17/zero-transfer/blob/main/docs/api-md/functions/matchKnownHostsEntry.md) | Function | See API reference. |
|
|
52
52
|
| [`KnownHostsEntry`](https://github.com/tonywied17/zero-transfer/blob/main/docs/api-md/interfaces/KnownHostsEntry.md) | Interface | See API reference. |
|
|
53
53
|
| [`KnownHostsMarker`](https://github.com/tonywied17/zero-transfer/blob/main/docs/api-md/type-aliases/KnownHostsMarker.md) | Type | See API reference. |
|
|
54
|
+
| [`runSshCommand`](https://github.com/tonywied17/zero-transfer/blob/main/docs/api-md/functions/runSshCommand.md) | Function | See API reference. |
|
|
55
|
+
| [`RunSshCommandOptions`](https://github.com/tonywied17/zero-transfer/blob/main/docs/api-md/interfaces/RunSshCommandOptions.md) | Interface | See API reference. |
|
|
56
|
+
| [`RunSshCommandResult`](https://github.com/tonywied17/zero-transfer/blob/main/docs/api-md/interfaces/RunSshCommandResult.md) | Interface | See API reference. |
|
|
54
57
|
|
|
55
58
|
## Examples
|
|
56
59
|
|
package/dist/index.cjs
CHANGED
|
@@ -92,6 +92,7 @@ __export(ssh_exports, {
|
|
|
92
92
|
importOpenSshConfig: () => importOpenSshConfig,
|
|
93
93
|
importWinScpSessions: () => importWinScpSessions,
|
|
94
94
|
isClassicProviderId: () => isClassicProviderId,
|
|
95
|
+
isMainModule: () => isMainModule,
|
|
95
96
|
isSensitiveKey: () => isSensitiveKey,
|
|
96
97
|
joinRemotePath: () => joinRemotePath,
|
|
97
98
|
matchKnownHosts: () => matchKnownHosts,
|
|
@@ -113,6 +114,7 @@ __export(ssh_exports, {
|
|
|
113
114
|
resolveProviderId: () => resolveProviderId,
|
|
114
115
|
resolveSecret: () => resolveSecret,
|
|
115
116
|
runConnectionDiagnostics: () => runConnectionDiagnostics,
|
|
117
|
+
runSshCommand: () => runSshCommand,
|
|
116
118
|
serializeRemoteManifest: () => serializeRemoteManifest,
|
|
117
119
|
sortRemoteEntries: () => sortRemoteEntries,
|
|
118
120
|
summarizeClientDiagnostics: () => summarizeClientDiagnostics,
|
|
@@ -4901,6 +4903,19 @@ function isModifiedAtDifferent2(source, destination, toleranceMs) {
|
|
|
4901
4903
|
return Math.abs(sourceTime - destinationTime) > toleranceMs;
|
|
4902
4904
|
}
|
|
4903
4905
|
|
|
4906
|
+
// src/utils/mainModule.ts
|
|
4907
|
+
var import_node_url = require("url");
|
|
4908
|
+
function isMainModule(importMetaUrl) {
|
|
4909
|
+
if (typeof process === "undefined" || !process.argv || process.argv.length < 2) {
|
|
4910
|
+
return false;
|
|
4911
|
+
}
|
|
4912
|
+
try {
|
|
4913
|
+
return process.argv[1] === (0, import_node_url.fileURLToPath)(importMetaUrl);
|
|
4914
|
+
} catch {
|
|
4915
|
+
return false;
|
|
4916
|
+
}
|
|
4917
|
+
}
|
|
4918
|
+
|
|
4904
4919
|
// src/protocols/ssh/transport/SshTransportConnection.ts
|
|
4905
4920
|
var import_node_buffer15 = require("buffer");
|
|
4906
4921
|
|
|
@@ -6271,7 +6286,7 @@ var SshTransportPacketUnprotector = class {
|
|
|
6271
6286
|
}
|
|
6272
6287
|
/**
|
|
6273
6288
|
* Feeds raw encrypted bytes from the socket and returns any fully decoded payloads.
|
|
6274
|
-
* Maintains internal framing state across calls
|
|
6289
|
+
* Maintains internal framing state across calls - pass each `data` event chunk directly.
|
|
6275
6290
|
*/
|
|
6276
6291
|
pushBytes(chunk) {
|
|
6277
6292
|
this.framePendingRaw = import_node_buffer14.Buffer.concat([this.framePendingRaw, chunk]);
|
|
@@ -6779,7 +6794,7 @@ var SshTransportConnection = class {
|
|
|
6779
6794
|
assertConnected() {
|
|
6780
6795
|
if (!this.connected) {
|
|
6781
6796
|
throw new ProtocolError({
|
|
6782
|
-
message: "SshTransportConnection is not yet connected
|
|
6797
|
+
message: "SshTransportConnection is not yet connected - call connect() first",
|
|
6783
6798
|
protocol: "sftp",
|
|
6784
6799
|
retryable: false
|
|
6785
6800
|
});
|
|
@@ -7735,6 +7750,84 @@ var SshConnectionManager = class {
|
|
|
7735
7750
|
}
|
|
7736
7751
|
}
|
|
7737
7752
|
};
|
|
7753
|
+
|
|
7754
|
+
// src/protocols/ssh/runSshCommand.ts
|
|
7755
|
+
var import_node_net = require("net");
|
|
7756
|
+
var DEFAULT_PORT = 22;
|
|
7757
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
7758
|
+
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 1e4;
|
|
7759
|
+
var DEFAULT_MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
|
|
7760
|
+
async function runSshCommand(options) {
|
|
7761
|
+
const {
|
|
7762
|
+
host,
|
|
7763
|
+
port = DEFAULT_PORT,
|
|
7764
|
+
command,
|
|
7765
|
+
auth,
|
|
7766
|
+
transport: transportOptions,
|
|
7767
|
+
connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS,
|
|
7768
|
+
maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES
|
|
7769
|
+
} = options;
|
|
7770
|
+
const socket = await openTcpSocket(host, port, connectTimeoutMs);
|
|
7771
|
+
const transport = new SshTransportConnection({
|
|
7772
|
+
handshakeTimeoutMs: DEFAULT_HANDSHAKE_TIMEOUT_MS,
|
|
7773
|
+
...transportOptions
|
|
7774
|
+
});
|
|
7775
|
+
try {
|
|
7776
|
+
const handshake = await transport.connect(socket);
|
|
7777
|
+
const authSession = new SshAuthSession(transport);
|
|
7778
|
+
await authSession.authenticate({
|
|
7779
|
+
credential: auth,
|
|
7780
|
+
sessionId: handshake.keyExchange.sessionId
|
|
7781
|
+
});
|
|
7782
|
+
const conn = new SshConnectionManager(transport);
|
|
7783
|
+
const channel = await conn.openExecChannel(command);
|
|
7784
|
+
const pump = conn.start();
|
|
7785
|
+
pump.catch(() => {
|
|
7786
|
+
});
|
|
7787
|
+
const chunks = [];
|
|
7788
|
+
let bytesReceived = 0;
|
|
7789
|
+
try {
|
|
7790
|
+
for await (const chunk of channel.receiveData()) {
|
|
7791
|
+
bytesReceived += chunk.length;
|
|
7792
|
+
if (bytesReceived > maxOutputBytes) {
|
|
7793
|
+
throw new Error(
|
|
7794
|
+
`runSshCommand: stdout exceeded ${maxOutputBytes} bytes (set maxOutputBytes to allow more)`
|
|
7795
|
+
);
|
|
7796
|
+
}
|
|
7797
|
+
chunks.push(chunk);
|
|
7798
|
+
}
|
|
7799
|
+
} finally {
|
|
7800
|
+
channel.close();
|
|
7801
|
+
}
|
|
7802
|
+
const stdout = Buffer.concat(chunks);
|
|
7803
|
+
return {
|
|
7804
|
+
stdout,
|
|
7805
|
+
stdoutText: stdout.toString("utf8"),
|
|
7806
|
+
bytesReceived
|
|
7807
|
+
};
|
|
7808
|
+
} finally {
|
|
7809
|
+
transport.disconnect();
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7812
|
+
function openTcpSocket(host, port, timeoutMs) {
|
|
7813
|
+
return new Promise((resolve, reject) => {
|
|
7814
|
+
const socket = (0, import_node_net.connect)({ host, port });
|
|
7815
|
+
const timer = setTimeout(() => {
|
|
7816
|
+
socket.destroy();
|
|
7817
|
+
reject(
|
|
7818
|
+
new Error(`runSshCommand: TCP connect to ${host}:${port} timed out after ${timeoutMs}ms`)
|
|
7819
|
+
);
|
|
7820
|
+
}, timeoutMs);
|
|
7821
|
+
socket.once("connect", () => {
|
|
7822
|
+
clearTimeout(timer);
|
|
7823
|
+
resolve(socket);
|
|
7824
|
+
});
|
|
7825
|
+
socket.once("error", (error) => {
|
|
7826
|
+
clearTimeout(timer);
|
|
7827
|
+
reject(error);
|
|
7828
|
+
});
|
|
7829
|
+
});
|
|
7830
|
+
}
|
|
7738
7831
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7739
7832
|
0 && (module.exports = {
|
|
7740
7833
|
AbortError,
|
|
@@ -7799,6 +7892,7 @@ var SshConnectionManager = class {
|
|
|
7799
7892
|
importOpenSshConfig,
|
|
7800
7893
|
importWinScpSessions,
|
|
7801
7894
|
isClassicProviderId,
|
|
7895
|
+
isMainModule,
|
|
7802
7896
|
isSensitiveKey,
|
|
7803
7897
|
joinRemotePath,
|
|
7804
7898
|
matchKnownHosts,
|
|
@@ -7820,6 +7914,7 @@ var SshConnectionManager = class {
|
|
|
7820
7914
|
resolveProviderId,
|
|
7821
7915
|
resolveSecret,
|
|
7822
7916
|
runConnectionDiagnostics,
|
|
7917
|
+
runSshCommand,
|
|
7823
7918
|
serializeRemoteManifest,
|
|
7824
7919
|
sortRemoteEntries,
|
|
7825
7920
|
summarizeClientDiagnostics,
|