@zero-transfer/sftp 0.4.7 → 0.4.8
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/dist/index.cjs +426 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +228 -24
- package/dist/index.d.ts +228 -24
- package/dist/index.mjs +423 -177
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(sftp_exports, {
|
|
|
60
60
|
copyBetween: () => copyBetween,
|
|
61
61
|
createAtomicDeployPlan: () => createAtomicDeployPlan,
|
|
62
62
|
createBandwidthThrottle: () => createBandwidthThrottle,
|
|
63
|
+
createDefaultRetryPolicy: () => createDefaultRetryPolicy,
|
|
63
64
|
createLocalProviderFactory: () => createLocalProviderFactory,
|
|
64
65
|
createMemoryProviderFactory: () => createMemoryProviderFactory,
|
|
65
66
|
createOAuthTokenSecretSource: () => createOAuthTokenSecretSource,
|
|
@@ -96,8 +97,10 @@ __export(sftp_exports, {
|
|
|
96
97
|
parseRemoteManifest: () => parseRemoteManifest,
|
|
97
98
|
redactCommand: () => redactCommand,
|
|
98
99
|
redactConnectionProfile: () => redactConnectionProfile,
|
|
100
|
+
redactErrorForLogging: () => redactErrorForLogging,
|
|
99
101
|
redactObject: () => redactObject,
|
|
100
102
|
redactSecretSource: () => redactSecretSource,
|
|
103
|
+
redactUrlForLogging: () => redactUrlForLogging,
|
|
101
104
|
redactValue: () => redactValue,
|
|
102
105
|
resolveConnectionProfileSecrets: () => resolveConnectionProfileSecrets,
|
|
103
106
|
resolveOpenSshHost: () => resolveOpenSshHost,
|
|
@@ -118,6 +121,68 @@ module.exports = __toCommonJS(sftp_exports);
|
|
|
118
121
|
// src/client/ZeroTransfer.ts
|
|
119
122
|
var import_node_events = require("events");
|
|
120
123
|
|
|
124
|
+
// src/logging/redaction.ts
|
|
125
|
+
var REDACTED = "[REDACTED]";
|
|
126
|
+
var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
|
|
127
|
+
var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
|
|
128
|
+
var URL_KEY_PATTERN = /(?:url|uri|href)$/i;
|
|
129
|
+
function isSensitiveKey(key) {
|
|
130
|
+
return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
|
|
131
|
+
}
|
|
132
|
+
function redactCommand(command) {
|
|
133
|
+
return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
|
|
134
|
+
return `${commandName.toUpperCase()} ${REDACTED}`;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function redactValue(value) {
|
|
138
|
+
if (typeof value === "string") {
|
|
139
|
+
return redactCommand(value);
|
|
140
|
+
}
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
return value.map((item) => redactValue(item));
|
|
143
|
+
}
|
|
144
|
+
if (value !== null && typeof value === "object") {
|
|
145
|
+
return redactObject(value);
|
|
146
|
+
}
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
function redactObject(input) {
|
|
150
|
+
return Object.fromEntries(
|
|
151
|
+
Object.entries(input).map(([key, value]) => {
|
|
152
|
+
if (isSensitiveKey(key)) {
|
|
153
|
+
return [key, REDACTED];
|
|
154
|
+
}
|
|
155
|
+
if (URL_KEY_PATTERN.test(key) && typeof value === "string") {
|
|
156
|
+
return [key, redactUrlForLogging(value)];
|
|
157
|
+
}
|
|
158
|
+
return [key, redactValue(value)];
|
|
159
|
+
})
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
function redactUrlForLogging(url) {
|
|
163
|
+
let parsed;
|
|
164
|
+
try {
|
|
165
|
+
parsed = typeof url === "string" ? new URL(url) : url;
|
|
166
|
+
} catch {
|
|
167
|
+
return REDACTED;
|
|
168
|
+
}
|
|
169
|
+
const origin = parsed.host.length > 0 ? `${parsed.protocol}//${parsed.host}` : parsed.protocol;
|
|
170
|
+
const query = parsed.search.length > 0 ? `?${REDACTED}` : "";
|
|
171
|
+
return `${origin}${parsed.pathname}${query}`;
|
|
172
|
+
}
|
|
173
|
+
function redactErrorForLogging(error) {
|
|
174
|
+
if (error !== null && typeof error === "object") {
|
|
175
|
+
const candidate = error;
|
|
176
|
+
if (typeof candidate.toJSON === "function") {
|
|
177
|
+
return redactObject(candidate.toJSON());
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (error instanceof Error) {
|
|
181
|
+
return redactObject({ message: error.message, name: error.name });
|
|
182
|
+
}
|
|
183
|
+
return { message: redactValue(typeof error === "string" ? error : String(error)) };
|
|
184
|
+
}
|
|
185
|
+
|
|
121
186
|
// src/errors/ZeroTransferError.ts
|
|
122
187
|
var ZeroTransferError = class extends Error {
|
|
123
188
|
/** Stable machine-readable error code. */
|
|
@@ -159,6 +224,11 @@ var ZeroTransferError = class extends Error {
|
|
|
159
224
|
/**
|
|
160
225
|
* Serializes the error into a plain object suitable for logs or API responses.
|
|
161
226
|
*
|
|
227
|
+
* `details` and `command` are passed through secret redaction so serialized
|
|
228
|
+
* errors never leak credentials, signed URLs, or raw protocol commands. The
|
|
229
|
+
* live {@link ZeroTransferError.details | details} property stays unredacted
|
|
230
|
+
* for programmatic consumers.
|
|
231
|
+
*
|
|
162
232
|
* @returns A JSON-safe object containing public structured error fields.
|
|
163
233
|
*/
|
|
164
234
|
toJSON() {
|
|
@@ -168,12 +238,12 @@ var ZeroTransferError = class extends Error {
|
|
|
168
238
|
message: this.message,
|
|
169
239
|
protocol: this.protocol,
|
|
170
240
|
host: this.host,
|
|
171
|
-
command: this.command,
|
|
241
|
+
command: this.command === void 0 ? void 0 : redactCommand(this.command),
|
|
172
242
|
ftpCode: this.ftpCode,
|
|
173
243
|
sftpCode: this.sftpCode,
|
|
174
244
|
path: this.path,
|
|
175
245
|
retryable: this.retryable,
|
|
176
|
-
details: this.details
|
|
246
|
+
details: this.details === void 0 ? void 0 : redactObject(this.details)
|
|
177
247
|
};
|
|
178
248
|
}
|
|
179
249
|
};
|
|
@@ -696,15 +766,20 @@ var ProviderRegistry = class {
|
|
|
696
766
|
var TransferClient = class {
|
|
697
767
|
/** Provider registry used by this client. */
|
|
698
768
|
registry;
|
|
769
|
+
/** Execution defaults applied when call sites omit their own values. */
|
|
770
|
+
defaults;
|
|
699
771
|
logger;
|
|
700
772
|
/**
|
|
701
773
|
* Creates a transfer client without opening any provider connections.
|
|
702
774
|
*
|
|
703
|
-
* @param options - Optional registry, provider factories, and
|
|
775
|
+
* @param options - Optional registry, provider factories, logger, and execution defaults.
|
|
704
776
|
*/
|
|
705
777
|
constructor(options = {}) {
|
|
706
778
|
this.registry = options.registry ?? new ProviderRegistry();
|
|
707
779
|
this.logger = options.logger ?? noopLogger;
|
|
780
|
+
if (options.defaults !== void 0) {
|
|
781
|
+
this.defaults = { ...options.defaults };
|
|
782
|
+
}
|
|
708
783
|
for (const provider of options.providers ?? []) {
|
|
709
784
|
this.registry.register(provider);
|
|
710
785
|
}
|
|
@@ -1277,18 +1352,25 @@ var TransferEngine = class {
|
|
|
1277
1352
|
for (let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber += 1) {
|
|
1278
1353
|
this.throwIfAborted(abortScope.signal, job);
|
|
1279
1354
|
const attemptStartedAt = this.now();
|
|
1355
|
+
const attemptScope = createAttemptScope(
|
|
1356
|
+
abortScope.signal,
|
|
1357
|
+
options.timeout,
|
|
1358
|
+
job,
|
|
1359
|
+
attemptNumber
|
|
1360
|
+
);
|
|
1280
1361
|
const context = this.createExecutionContext(
|
|
1281
1362
|
job,
|
|
1282
1363
|
attemptNumber,
|
|
1283
1364
|
attemptStartedAt,
|
|
1284
1365
|
options,
|
|
1285
|
-
|
|
1366
|
+
attemptScope.signal,
|
|
1286
1367
|
(bytesTransferred) => {
|
|
1287
1368
|
latestBytesTransferred = bytesTransferred;
|
|
1288
|
-
}
|
|
1369
|
+
},
|
|
1370
|
+
attemptScope.notifyProgress
|
|
1289
1371
|
);
|
|
1290
1372
|
try {
|
|
1291
|
-
const result = await runExecutor(executor, context,
|
|
1373
|
+
const result = await runExecutor(executor, context, attemptScope.signal, job);
|
|
1292
1374
|
context.throwIfAborted();
|
|
1293
1375
|
latestBytesTransferred = result.bytesTransferred;
|
|
1294
1376
|
const completedAt = this.now();
|
|
@@ -1306,16 +1388,27 @@ var TransferEngine = class {
|
|
|
1306
1388
|
summarizeError(error)
|
|
1307
1389
|
);
|
|
1308
1390
|
attempts.push(attempt);
|
|
1309
|
-
if (error instanceof AbortError ||
|
|
1391
|
+
if (error instanceof AbortError || abortScope.signal?.aborted === true) {
|
|
1310
1392
|
throw error;
|
|
1311
1393
|
}
|
|
1312
|
-
const retryInput = {
|
|
1394
|
+
const retryInput = {
|
|
1395
|
+
attempt: attemptNumber,
|
|
1396
|
+
elapsedMs: Math.max(0, completedAt.getTime() - startedAt.getTime()),
|
|
1397
|
+
error,
|
|
1398
|
+
job
|
|
1399
|
+
};
|
|
1313
1400
|
const shouldRetry = attemptNumber < maxAttempts && (options.retry?.shouldRetry?.(retryInput) ?? isRetryable(error));
|
|
1314
1401
|
if (shouldRetry) {
|
|
1315
1402
|
options.retry?.onRetry?.(retryInput);
|
|
1403
|
+
const delayMs = normalizeDelayMs(options.retry?.getDelayMs?.(retryInput));
|
|
1404
|
+
if (delayMs > 0) {
|
|
1405
|
+
await sleepWithAbort(delayMs, abortScope.signal, job);
|
|
1406
|
+
}
|
|
1316
1407
|
continue;
|
|
1317
1408
|
}
|
|
1318
1409
|
throw createTransferFailure(job, error, attempts);
|
|
1410
|
+
} finally {
|
|
1411
|
+
attemptScope.dispose();
|
|
1319
1412
|
}
|
|
1320
1413
|
}
|
|
1321
1414
|
throw createTransferFailure(job, void 0, attempts);
|
|
@@ -1323,12 +1416,13 @@ var TransferEngine = class {
|
|
|
1323
1416
|
abortScope.dispose();
|
|
1324
1417
|
}
|
|
1325
1418
|
}
|
|
1326
|
-
createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred) {
|
|
1419
|
+
createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred, notifyProgress) {
|
|
1327
1420
|
const context = {
|
|
1328
1421
|
attempt,
|
|
1329
1422
|
job,
|
|
1330
1423
|
reportProgress: (bytesTransferred, totalBytes) => {
|
|
1331
1424
|
this.throwIfAborted(signal, job);
|
|
1425
|
+
notifyProgress();
|
|
1332
1426
|
updateBytesTransferred(bytesTransferred);
|
|
1333
1427
|
const progressInput = {
|
|
1334
1428
|
bytesTransferred,
|
|
@@ -1397,6 +1491,96 @@ function createAbortScope(parentSignal, timeout, job) {
|
|
|
1397
1491
|
signal: controller.signal
|
|
1398
1492
|
};
|
|
1399
1493
|
}
|
|
1494
|
+
function createAttemptScope(parentSignal, timeout, job, attempt) {
|
|
1495
|
+
const attemptTimeoutMs = normalizeTimeoutMs(timeout?.attemptTimeoutMs);
|
|
1496
|
+
const stallTimeoutMs = normalizeTimeoutMs(timeout?.stallTimeoutMs);
|
|
1497
|
+
if (attemptTimeoutMs === void 0 && stallTimeoutMs === void 0) {
|
|
1498
|
+
const scope = {
|
|
1499
|
+
dispose: () => void 0,
|
|
1500
|
+
notifyProgress: () => void 0
|
|
1501
|
+
};
|
|
1502
|
+
if (parentSignal !== void 0) scope.signal = parentSignal;
|
|
1503
|
+
return scope;
|
|
1504
|
+
}
|
|
1505
|
+
const controller = new AbortController();
|
|
1506
|
+
const retryable = timeout?.retryable ?? true;
|
|
1507
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
1508
|
+
if (parentSignal?.aborted === true) {
|
|
1509
|
+
abortFromParent();
|
|
1510
|
+
} else {
|
|
1511
|
+
parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
1512
|
+
}
|
|
1513
|
+
const attemptTimer = attemptTimeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
1514
|
+
controller.abort(
|
|
1515
|
+
new TimeoutError({
|
|
1516
|
+
details: { attempt, attemptTimeoutMs, jobId: job.id, operation: job.operation },
|
|
1517
|
+
message: `Transfer attempt ${String(attempt)} timed out after ${String(attemptTimeoutMs)}ms: ${job.id}`,
|
|
1518
|
+
retryable
|
|
1519
|
+
})
|
|
1520
|
+
);
|
|
1521
|
+
}, attemptTimeoutMs);
|
|
1522
|
+
let stallTimer;
|
|
1523
|
+
const armStallWatchdog = () => {
|
|
1524
|
+
if (stallTimeoutMs === void 0 || controller.signal.aborted) return;
|
|
1525
|
+
if (stallTimer !== void 0) clearTimeout(stallTimer);
|
|
1526
|
+
stallTimer = setTimeout(() => {
|
|
1527
|
+
controller.abort(
|
|
1528
|
+
new TimeoutError({
|
|
1529
|
+
details: { attempt, jobId: job.id, operation: job.operation, stallTimeoutMs },
|
|
1530
|
+
message: `Transfer attempt ${String(attempt)} stalled (no progress for ${String(stallTimeoutMs)}ms): ${job.id}`,
|
|
1531
|
+
retryable
|
|
1532
|
+
})
|
|
1533
|
+
);
|
|
1534
|
+
}, stallTimeoutMs);
|
|
1535
|
+
};
|
|
1536
|
+
armStallWatchdog();
|
|
1537
|
+
return {
|
|
1538
|
+
dispose: () => {
|
|
1539
|
+
if (attemptTimer !== void 0) clearTimeout(attemptTimer);
|
|
1540
|
+
if (stallTimer !== void 0) clearTimeout(stallTimer);
|
|
1541
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
1542
|
+
},
|
|
1543
|
+
notifyProgress: armStallWatchdog,
|
|
1544
|
+
signal: controller.signal
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
function sleepWithAbort(delayMs, signal, job) {
|
|
1548
|
+
return new Promise((resolve, reject) => {
|
|
1549
|
+
if (signal === void 0) {
|
|
1550
|
+
setTimeout(resolve, delayMs);
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (signal.aborted) {
|
|
1554
|
+
reject(toAbortFailure(signal, job));
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
const rejectAbort = () => {
|
|
1558
|
+
clearTimeout(timer);
|
|
1559
|
+
reject(toAbortFailure(signal, job));
|
|
1560
|
+
};
|
|
1561
|
+
const timer = setTimeout(() => {
|
|
1562
|
+
signal.removeEventListener("abort", rejectAbort);
|
|
1563
|
+
resolve();
|
|
1564
|
+
}, delayMs);
|
|
1565
|
+
signal.addEventListener("abort", rejectAbort, { once: true });
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
function toAbortFailure(signal, job) {
|
|
1569
|
+
if (signal.reason instanceof ZeroTransferError) {
|
|
1570
|
+
return signal.reason;
|
|
1571
|
+
}
|
|
1572
|
+
return new AbortError({
|
|
1573
|
+
details: { jobId: job.id, operation: job.operation },
|
|
1574
|
+
message: `Transfer job aborted: ${job.id}`,
|
|
1575
|
+
retryable: false
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
function normalizeDelayMs(value) {
|
|
1579
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) {
|
|
1580
|
+
return 0;
|
|
1581
|
+
}
|
|
1582
|
+
return Math.floor(value);
|
|
1583
|
+
}
|
|
1400
1584
|
function normalizeTimeoutMs(value) {
|
|
1401
1585
|
if (value === void 0 || !Number.isFinite(value) || value <= 0) {
|
|
1402
1586
|
return void 0;
|
|
@@ -1565,7 +1749,7 @@ async function runRoute(options) {
|
|
|
1565
1749
|
const executor = createProviderTransferExecutor({
|
|
1566
1750
|
resolveSession: ({ role }) => sessions.get(role)
|
|
1567
1751
|
});
|
|
1568
|
-
return await engine.execute(job, executor, buildExecuteOptions(options));
|
|
1752
|
+
return await engine.execute(job, executor, buildExecuteOptions(options, client));
|
|
1569
1753
|
} finally {
|
|
1570
1754
|
if (destinationSession !== void 0) {
|
|
1571
1755
|
await destinationSession.disconnect();
|
|
@@ -1602,12 +1786,14 @@ function defaultJobId(route, now) {
|
|
|
1602
1786
|
const timestamp = (now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
1603
1787
|
return `route:${route.id}:${timestamp.toString(36)}`;
|
|
1604
1788
|
}
|
|
1605
|
-
function buildExecuteOptions(options) {
|
|
1789
|
+
function buildExecuteOptions(options, client) {
|
|
1606
1790
|
const execute = {};
|
|
1791
|
+
const retry = options.retry ?? client.defaults?.retry;
|
|
1792
|
+
const timeout = options.timeout ?? client.defaults?.timeout;
|
|
1607
1793
|
if (options.signal !== void 0) execute.signal = options.signal;
|
|
1608
|
-
if (
|
|
1794
|
+
if (retry !== void 0) execute.retry = retry;
|
|
1609
1795
|
if (options.onProgress !== void 0) execute.onProgress = options.onProgress;
|
|
1610
|
-
if (
|
|
1796
|
+
if (timeout !== void 0) execute.timeout = timeout;
|
|
1611
1797
|
if (options.bandwidthLimit !== void 0) execute.bandwidthLimit = options.bandwidthLimit;
|
|
1612
1798
|
return execute;
|
|
1613
1799
|
}
|
|
@@ -1664,41 +1850,6 @@ function defaultRouteSuffix(source, destination) {
|
|
|
1664
1850
|
return `${source}->${destination}`;
|
|
1665
1851
|
}
|
|
1666
1852
|
|
|
1667
|
-
// src/logging/redaction.ts
|
|
1668
|
-
var REDACTED = "[REDACTED]";
|
|
1669
|
-
var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
|
|
1670
|
-
var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
|
|
1671
|
-
function isSensitiveKey(key) {
|
|
1672
|
-
return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
|
|
1673
|
-
}
|
|
1674
|
-
function redactCommand(command) {
|
|
1675
|
-
return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
|
|
1676
|
-
return `${commandName.toUpperCase()} ${REDACTED}`;
|
|
1677
|
-
});
|
|
1678
|
-
}
|
|
1679
|
-
function redactValue(value) {
|
|
1680
|
-
if (typeof value === "string") {
|
|
1681
|
-
return redactCommand(value);
|
|
1682
|
-
}
|
|
1683
|
-
if (Array.isArray(value)) {
|
|
1684
|
-
return value.map((item) => redactValue(item));
|
|
1685
|
-
}
|
|
1686
|
-
if (value !== null && typeof value === "object") {
|
|
1687
|
-
return redactObject(value);
|
|
1688
|
-
}
|
|
1689
|
-
return value;
|
|
1690
|
-
}
|
|
1691
|
-
function redactObject(input) {
|
|
1692
|
-
return Object.fromEntries(
|
|
1693
|
-
Object.entries(input).map(([key, value]) => {
|
|
1694
|
-
if (isSensitiveKey(key)) {
|
|
1695
|
-
return [key, REDACTED];
|
|
1696
|
-
}
|
|
1697
|
-
return [key, redactValue(value)];
|
|
1698
|
-
})
|
|
1699
|
-
);
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
1853
|
// src/profiles/SecretSource.ts
|
|
1703
1854
|
var import_node_buffer2 = require("buffer");
|
|
1704
1855
|
var import_promises = require("fs/promises");
|
|
@@ -2070,11 +2221,11 @@ var import_promises2 = require("fs/promises");
|
|
|
2070
2221
|
var import_node_path2 = __toESM(require("path"));
|
|
2071
2222
|
|
|
2072
2223
|
// src/utils/path.ts
|
|
2073
|
-
var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n]/;
|
|
2224
|
+
var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n\0]/;
|
|
2074
2225
|
function assertSafeFtpArgument(value, label = "path") {
|
|
2075
2226
|
if (UNSAFE_FTP_ARGUMENT_PATTERN.test(value)) {
|
|
2076
2227
|
throw new ConfigurationError({
|
|
2077
|
-
message: `Unsafe FTP ${label}: CR and
|
|
2228
|
+
message: `Unsafe FTP ${label}: CR, LF, and NUL characters are not allowed`,
|
|
2078
2229
|
retryable: false,
|
|
2079
2230
|
details: {
|
|
2080
2231
|
label
|
|
@@ -3376,7 +3527,6 @@ function expandAlgorithms(values) {
|
|
|
3376
3527
|
}
|
|
3377
3528
|
|
|
3378
3529
|
// src/profiles/importers/FileZillaImporter.ts
|
|
3379
|
-
var import_node_buffer5 = require("buffer");
|
|
3380
3530
|
function importFileZillaSites(xml) {
|
|
3381
3531
|
const events = tokenizeXml(xml);
|
|
3382
3532
|
if (events.length === 0) {
|
|
@@ -3392,7 +3542,6 @@ function importFileZillaSites(xml) {
|
|
|
3392
3542
|
const folderNamePending = [];
|
|
3393
3543
|
let inServer = false;
|
|
3394
3544
|
let serverFields = {};
|
|
3395
|
-
let serverPasswordEncoding;
|
|
3396
3545
|
let activeTag;
|
|
3397
3546
|
let captureFolderName = false;
|
|
3398
3547
|
for (const event of events) {
|
|
@@ -3405,13 +3554,9 @@ function importFileZillaSites(xml) {
|
|
|
3405
3554
|
if (event.name === "Server") {
|
|
3406
3555
|
inServer = true;
|
|
3407
3556
|
serverFields = {};
|
|
3408
|
-
serverPasswordEncoding = void 0;
|
|
3409
3557
|
continue;
|
|
3410
3558
|
}
|
|
3411
3559
|
activeTag = event.name;
|
|
3412
|
-
if (event.name === "Pass" && inServer) {
|
|
3413
|
-
serverPasswordEncoding = event.attributes["encoding"];
|
|
3414
|
-
}
|
|
3415
3560
|
if (event.name === "Name" && !inServer && folderNamePending.length > 0) {
|
|
3416
3561
|
captureFolderName = true;
|
|
3417
3562
|
}
|
|
@@ -3437,7 +3582,7 @@ function importFileZillaSites(xml) {
|
|
|
3437
3582
|
}
|
|
3438
3583
|
if (event.name === "Server") {
|
|
3439
3584
|
const folder = folderStack.filter((segment) => segment !== "");
|
|
3440
|
-
const result = buildSiteFromFields(serverFields
|
|
3585
|
+
const result = buildSiteFromFields(serverFields);
|
|
3441
3586
|
if (result.kind === "site") {
|
|
3442
3587
|
sites.push({ ...result.site, folder });
|
|
3443
3588
|
} else {
|
|
@@ -3449,7 +3594,6 @@ function importFileZillaSites(xml) {
|
|
|
3449
3594
|
}
|
|
3450
3595
|
inServer = false;
|
|
3451
3596
|
serverFields = {};
|
|
3452
|
-
serverPasswordEncoding = void 0;
|
|
3453
3597
|
activeTag = void 0;
|
|
3454
3598
|
continue;
|
|
3455
3599
|
}
|
|
@@ -3458,7 +3602,7 @@ function importFileZillaSites(xml) {
|
|
|
3458
3602
|
}
|
|
3459
3603
|
return { sites, skipped };
|
|
3460
3604
|
}
|
|
3461
|
-
function buildSiteFromFields(fields
|
|
3605
|
+
function buildSiteFromFields(fields) {
|
|
3462
3606
|
const name = (fields["Name"] ?? fields["Host"] ?? "Untitled").trim();
|
|
3463
3607
|
const host = (fields["Host"] ?? "").trim();
|
|
3464
3608
|
if (host === "") return { kind: "skipped", name };
|
|
@@ -3477,18 +3621,9 @@ function buildSiteFromFields(fields, passwordEncoding) {
|
|
|
3477
3621
|
}
|
|
3478
3622
|
const user = fields["User"]?.trim();
|
|
3479
3623
|
if (user !== void 0 && user !== "") profile.username = { value: user };
|
|
3480
|
-
let password;
|
|
3481
3624
|
const rawPass = fields["Pass"];
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
password = import_node_buffer5.Buffer.from(rawPass, "base64").toString("utf8");
|
|
3485
|
-
} else {
|
|
3486
|
-
password = rawPass;
|
|
3487
|
-
}
|
|
3488
|
-
if (password !== void 0 && password !== "") profile.password = { value: password };
|
|
3489
|
-
}
|
|
3490
|
-
const site = { name, profile };
|
|
3491
|
-
if (password !== void 0) site.password = password;
|
|
3625
|
+
const hasStoredPassword = rawPass !== void 0 && rawPass !== "";
|
|
3626
|
+
const site = { hasStoredPassword, name, profile };
|
|
3492
3627
|
const logonText = fields["Logontype"];
|
|
3493
3628
|
if (logonText !== void 0) {
|
|
3494
3629
|
const logonType = Number.parseInt(logonText.trim(), 10);
|
|
@@ -3731,6 +3866,62 @@ function mapFtp550(details) {
|
|
|
3731
3866
|
return new PermissionDeniedError(details);
|
|
3732
3867
|
}
|
|
3733
3868
|
|
|
3869
|
+
// src/transfers/createDefaultRetryPolicy.ts
|
|
3870
|
+
var DEFAULT_MAX_ATTEMPTS = 4;
|
|
3871
|
+
var DEFAULT_BASE_DELAY_MS = 250;
|
|
3872
|
+
var DEFAULT_MAX_DELAY_MS = 3e4;
|
|
3873
|
+
var DEFAULT_MAX_ELAPSED_MS = 3e5;
|
|
3874
|
+
function createDefaultRetryPolicy(options = {}) {
|
|
3875
|
+
const maxAttempts = normalizePositiveInteger(options.maxAttempts, DEFAULT_MAX_ATTEMPTS);
|
|
3876
|
+
const baseDelayMs = normalizeNonNegative(options.baseDelayMs, DEFAULT_BASE_DELAY_MS);
|
|
3877
|
+
const maxDelayMs = normalizeNonNegative(options.maxDelayMs, DEFAULT_MAX_DELAY_MS);
|
|
3878
|
+
const maxElapsedMs = normalizeNonNegative(options.maxElapsedMs, DEFAULT_MAX_ELAPSED_MS);
|
|
3879
|
+
const random = options.random ?? Math.random;
|
|
3880
|
+
return {
|
|
3881
|
+
getDelayMs(input) {
|
|
3882
|
+
const retryAfterMs = readRetryAfterMs(input.error);
|
|
3883
|
+
if (retryAfterMs !== void 0) {
|
|
3884
|
+
return retryAfterMs;
|
|
3885
|
+
}
|
|
3886
|
+
const exponentialMs = baseDelayMs * 2 ** (input.attempt - 1);
|
|
3887
|
+
const cappedMs = Math.min(maxDelayMs, exponentialMs);
|
|
3888
|
+
return Math.floor(random() * cappedMs);
|
|
3889
|
+
},
|
|
3890
|
+
maxAttempts,
|
|
3891
|
+
shouldRetry(input) {
|
|
3892
|
+
if (!(input.error instanceof ZeroTransferError) || !input.error.retryable) {
|
|
3893
|
+
return false;
|
|
3894
|
+
}
|
|
3895
|
+
if (input.elapsedMs >= maxElapsedMs) {
|
|
3896
|
+
return false;
|
|
3897
|
+
}
|
|
3898
|
+
const retryAfterMs = readRetryAfterMs(input.error);
|
|
3899
|
+
if (retryAfterMs !== void 0 && input.elapsedMs + retryAfterMs > maxElapsedMs) {
|
|
3900
|
+
return false;
|
|
3901
|
+
}
|
|
3902
|
+
return true;
|
|
3903
|
+
}
|
|
3904
|
+
};
|
|
3905
|
+
}
|
|
3906
|
+
function readRetryAfterMs(error) {
|
|
3907
|
+
if (!(error instanceof ZeroTransferError)) return void 0;
|
|
3908
|
+
const value = error.details?.["retryAfterMs"];
|
|
3909
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
3910
|
+
return Math.floor(value);
|
|
3911
|
+
}
|
|
3912
|
+
function normalizePositiveInteger(value, fallback) {
|
|
3913
|
+
if (value === void 0 || !Number.isFinite(value) || value < 1) {
|
|
3914
|
+
return fallback;
|
|
3915
|
+
}
|
|
3916
|
+
return Math.floor(value);
|
|
3917
|
+
}
|
|
3918
|
+
function normalizeNonNegative(value, fallback) {
|
|
3919
|
+
if (value === void 0 || !Number.isFinite(value) || value < 0) {
|
|
3920
|
+
return fallback;
|
|
3921
|
+
}
|
|
3922
|
+
return Math.floor(value);
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3734
3925
|
// src/transfers/TransferPlan.ts
|
|
3735
3926
|
function createTransferPlan(input) {
|
|
3736
3927
|
const plan = {
|
|
@@ -3828,8 +4019,8 @@ var TransferQueue = class {
|
|
|
3828
4019
|
this.concurrency = normalizeConcurrency(options.concurrency);
|
|
3829
4020
|
this.defaultExecutor = options.executor;
|
|
3830
4021
|
this.resolveExecutor = options.resolveExecutor;
|
|
3831
|
-
this.retry = options.retry;
|
|
3832
|
-
this.timeout = options.timeout;
|
|
4022
|
+
this.retry = options.retry ?? options.client?.defaults?.retry;
|
|
4023
|
+
this.timeout = options.timeout ?? options.client?.defaults?.timeout;
|
|
3833
4024
|
this.bandwidthLimit = options.bandwidthLimit;
|
|
3834
4025
|
this.onProgress = options.onProgress;
|
|
3835
4026
|
this.onReceipt = options.onReceipt;
|
|
@@ -4906,12 +5097,12 @@ function isMainModule(importMetaUrl) {
|
|
|
4906
5097
|
}
|
|
4907
5098
|
|
|
4908
5099
|
// src/providers/native/sftp/NativeSftpProvider.ts
|
|
4909
|
-
var
|
|
5100
|
+
var import_node_buffer19 = require("buffer");
|
|
4910
5101
|
var import_node_crypto9 = require("crypto");
|
|
4911
5102
|
var import_node_net = require("net");
|
|
4912
5103
|
|
|
4913
5104
|
// src/protocols/ssh/binary/SshDataWriter.ts
|
|
4914
|
-
var
|
|
5105
|
+
var import_node_buffer5 = require("buffer");
|
|
4915
5106
|
var MAX_UINT32 = 4294967295;
|
|
4916
5107
|
var MAX_UINT64 = (1n << 64n) - 1n;
|
|
4917
5108
|
var SshDataWriter = class {
|
|
@@ -4919,7 +5110,7 @@ var SshDataWriter = class {
|
|
|
4919
5110
|
length = 0;
|
|
4920
5111
|
writeByte(value) {
|
|
4921
5112
|
this.assertByte(value, "byte");
|
|
4922
|
-
const chunk =
|
|
5113
|
+
const chunk = import_node_buffer5.Buffer.alloc(1);
|
|
4923
5114
|
chunk.writeUInt8(value, 0);
|
|
4924
5115
|
return this.push(chunk);
|
|
4925
5116
|
}
|
|
@@ -4927,7 +5118,7 @@ var SshDataWriter = class {
|
|
|
4927
5118
|
return this.writeByte(value ? 1 : 0);
|
|
4928
5119
|
}
|
|
4929
5120
|
writeBytes(value) {
|
|
4930
|
-
return this.push(
|
|
5121
|
+
return this.push(import_node_buffer5.Buffer.from(value));
|
|
4931
5122
|
}
|
|
4932
5123
|
writeUint32(value) {
|
|
4933
5124
|
if (!Number.isInteger(value) || value < 0 || value > MAX_UINT32) {
|
|
@@ -4937,7 +5128,7 @@ var SshDataWriter = class {
|
|
|
4937
5128
|
retryable: false
|
|
4938
5129
|
});
|
|
4939
5130
|
}
|
|
4940
|
-
const chunk =
|
|
5131
|
+
const chunk = import_node_buffer5.Buffer.alloc(4);
|
|
4941
5132
|
chunk.writeUInt32BE(value, 0);
|
|
4942
5133
|
return this.push(chunk);
|
|
4943
5134
|
}
|
|
@@ -4949,12 +5140,12 @@ var SshDataWriter = class {
|
|
|
4949
5140
|
retryable: false
|
|
4950
5141
|
});
|
|
4951
5142
|
}
|
|
4952
|
-
const chunk =
|
|
5143
|
+
const chunk = import_node_buffer5.Buffer.alloc(8);
|
|
4953
5144
|
chunk.writeBigUInt64BE(value, 0);
|
|
4954
5145
|
return this.push(chunk);
|
|
4955
5146
|
}
|
|
4956
5147
|
writeString(value, encoding = "utf8") {
|
|
4957
|
-
const payload = typeof value === "string" ?
|
|
5148
|
+
const payload = typeof value === "string" ? import_node_buffer5.Buffer.from(value, encoding) : import_node_buffer5.Buffer.from(value);
|
|
4958
5149
|
this.writeUint32(payload.length);
|
|
4959
5150
|
return this.push(payload);
|
|
4960
5151
|
}
|
|
@@ -4976,7 +5167,7 @@ var SshDataWriter = class {
|
|
|
4976
5167
|
return this.writeString(values.join(","), "ascii");
|
|
4977
5168
|
}
|
|
4978
5169
|
toBuffer() {
|
|
4979
|
-
return
|
|
5170
|
+
return import_node_buffer5.Buffer.concat(this.chunks, this.length);
|
|
4980
5171
|
}
|
|
4981
5172
|
push(chunk) {
|
|
4982
5173
|
this.chunks.push(chunk);
|
|
@@ -4994,23 +5185,23 @@ var SshDataWriter = class {
|
|
|
4994
5185
|
}
|
|
4995
5186
|
};
|
|
4996
5187
|
function normalizePositiveMpint(value) {
|
|
4997
|
-
const input =
|
|
5188
|
+
const input = import_node_buffer5.Buffer.from(value);
|
|
4998
5189
|
let offset = 0;
|
|
4999
5190
|
while (offset < input.length && input[offset] === 0) {
|
|
5000
5191
|
offset += 1;
|
|
5001
5192
|
}
|
|
5002
5193
|
if (offset >= input.length) {
|
|
5003
|
-
return
|
|
5194
|
+
return import_node_buffer5.Buffer.alloc(0);
|
|
5004
5195
|
}
|
|
5005
5196
|
const stripped = input.subarray(offset);
|
|
5006
5197
|
if ((stripped[0] & 128) === 128) {
|
|
5007
|
-
return
|
|
5198
|
+
return import_node_buffer5.Buffer.concat([import_node_buffer5.Buffer.from([0]), stripped]);
|
|
5008
5199
|
}
|
|
5009
5200
|
return stripped;
|
|
5010
5201
|
}
|
|
5011
5202
|
|
|
5012
5203
|
// src/protocols/ssh/binary/SshDataReader.ts
|
|
5013
|
-
var
|
|
5204
|
+
var import_node_buffer6 = require("buffer");
|
|
5014
5205
|
var SshDataReader = class {
|
|
5015
5206
|
constructor(source) {
|
|
5016
5207
|
this.source = source;
|
|
@@ -5036,18 +5227,18 @@ var SshDataReader = class {
|
|
|
5036
5227
|
this.ensureAvailable(length, "bytes");
|
|
5037
5228
|
const data = this.source.subarray(this.offset, this.offset + length);
|
|
5038
5229
|
this.offset += length;
|
|
5039
|
-
return
|
|
5230
|
+
return import_node_buffer6.Buffer.from(data);
|
|
5040
5231
|
}
|
|
5041
5232
|
readUint32() {
|
|
5042
5233
|
this.ensureAvailable(4, "uint32");
|
|
5043
|
-
const buffer =
|
|
5234
|
+
const buffer = import_node_buffer6.Buffer.from(this.source);
|
|
5044
5235
|
const value = buffer.readUInt32BE(this.offset);
|
|
5045
5236
|
this.offset += 4;
|
|
5046
5237
|
return value;
|
|
5047
5238
|
}
|
|
5048
5239
|
readUint64() {
|
|
5049
5240
|
this.ensureAvailable(8, "uint64");
|
|
5050
|
-
const buffer =
|
|
5241
|
+
const buffer = import_node_buffer6.Buffer.from(this.source);
|
|
5051
5242
|
const value = buffer.readBigUInt64BE(this.offset);
|
|
5052
5243
|
this.offset += 8;
|
|
5053
5244
|
return value;
|
|
@@ -5057,7 +5248,7 @@ var SshDataReader = class {
|
|
|
5057
5248
|
this.ensureAvailable(length, "string");
|
|
5058
5249
|
const data = this.source.subarray(this.offset, this.offset + length);
|
|
5059
5250
|
this.offset += length;
|
|
5060
|
-
return
|
|
5251
|
+
return import_node_buffer6.Buffer.from(data);
|
|
5061
5252
|
}
|
|
5062
5253
|
readUtf8String() {
|
|
5063
5254
|
return this.readString().toString("utf8");
|
|
@@ -5412,7 +5603,7 @@ function buildKiRequest(args) {
|
|
|
5412
5603
|
}
|
|
5413
5604
|
|
|
5414
5605
|
// src/protocols/ssh/auth/SshPublickeyCredentialBuilder.ts
|
|
5415
|
-
var
|
|
5606
|
+
var import_node_buffer7 = require("buffer");
|
|
5416
5607
|
var import_node_crypto2 = require("crypto");
|
|
5417
5608
|
var ED25519_RAW_KEY_LENGTH = 32;
|
|
5418
5609
|
var ED25519_SPKI_PREFIX_LENGTH = 12;
|
|
@@ -5430,7 +5621,7 @@ function buildPublickeyCredential(options) {
|
|
|
5430
5621
|
return {
|
|
5431
5622
|
algorithmName: "ssh-ed25519",
|
|
5432
5623
|
publicKeyBlob,
|
|
5433
|
-
sign: (data) => (0, import_node_crypto2.sign)(null,
|
|
5624
|
+
sign: (data) => (0, import_node_crypto2.sign)(null, import_node_buffer7.Buffer.from(data), privateKey),
|
|
5434
5625
|
type: "publickey",
|
|
5435
5626
|
username
|
|
5436
5627
|
};
|
|
@@ -5448,7 +5639,7 @@ function buildPublickeyCredential(options) {
|
|
|
5448
5639
|
return {
|
|
5449
5640
|
algorithmName,
|
|
5450
5641
|
publicKeyBlob,
|
|
5451
|
-
sign: (data) => (0, import_node_crypto2.sign)(hash,
|
|
5642
|
+
sign: (data) => (0, import_node_crypto2.sign)(hash, import_node_buffer7.Buffer.from(data), privateKey),
|
|
5452
5643
|
type: "publickey",
|
|
5453
5644
|
username
|
|
5454
5645
|
};
|
|
@@ -5461,7 +5652,7 @@ function buildPublickeyCredential(options) {
|
|
|
5461
5652
|
}
|
|
5462
5653
|
function base64UrlToMpint(value) {
|
|
5463
5654
|
const padded = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
5464
|
-
const buffer =
|
|
5655
|
+
const buffer = import_node_buffer7.Buffer.from(padded, "base64");
|
|
5465
5656
|
return buffer;
|
|
5466
5657
|
}
|
|
5467
5658
|
function createInvalidKeyError(message) {
|
|
@@ -5587,7 +5778,7 @@ function encodeSshChannelClose(recipientChannel) {
|
|
|
5587
5778
|
}
|
|
5588
5779
|
|
|
5589
5780
|
// src/protocols/ssh/connection/SshSessionChannel.ts
|
|
5590
|
-
var
|
|
5781
|
+
var import_node_buffer8 = require("buffer");
|
|
5591
5782
|
var INITIAL_WINDOW_SIZE = 256 * 1024;
|
|
5592
5783
|
var MAX_PACKET_SIZE = 32 * 1024;
|
|
5593
5784
|
var WINDOW_REFILL_THRESHOLD = 64 * 1024;
|
|
@@ -5745,7 +5936,7 @@ var SshSessionChannel = class {
|
|
|
5745
5936
|
this.remoteWindowRemaining,
|
|
5746
5937
|
this.remoteMaxPacketSize
|
|
5747
5938
|
);
|
|
5748
|
-
const chunk =
|
|
5939
|
+
const chunk = import_node_buffer8.Buffer.from(data.subarray(offset, offset + chunkSize));
|
|
5749
5940
|
this.transport.sendPayload(
|
|
5750
5941
|
encodeSshChannelData({ data: chunk, recipientChannel: this.remoteChannelId })
|
|
5751
5942
|
);
|
|
@@ -6007,10 +6198,10 @@ var SshConnectionManager = class {
|
|
|
6007
6198
|
};
|
|
6008
6199
|
|
|
6009
6200
|
// src/protocols/ssh/transport/SshTransportConnection.ts
|
|
6010
|
-
var
|
|
6201
|
+
var import_node_buffer16 = require("buffer");
|
|
6011
6202
|
|
|
6012
6203
|
// src/protocols/ssh/transport/SshTransportHandshake.ts
|
|
6013
|
-
var
|
|
6204
|
+
var import_node_buffer14 = require("buffer");
|
|
6014
6205
|
|
|
6015
6206
|
// src/protocols/ssh/transport/SshAlgorithmNegotiation.ts
|
|
6016
6207
|
var DEFAULT_SSH_ALGORITHM_PREFERENCES = {
|
|
@@ -6172,12 +6363,12 @@ function parseSshIdentificationLine(line) {
|
|
|
6172
6363
|
}
|
|
6173
6364
|
|
|
6174
6365
|
// src/protocols/ssh/transport/SshKexInit.ts
|
|
6175
|
-
var
|
|
6366
|
+
var import_node_buffer9 = require("buffer");
|
|
6176
6367
|
var import_node_crypto3 = require("crypto");
|
|
6177
6368
|
var SSH_MSG_KEXINIT = 20;
|
|
6178
6369
|
var KEXINIT_COOKIE_LENGTH = 16;
|
|
6179
6370
|
function encodeSshKexInitMessage(options) {
|
|
6180
|
-
const cookie = options.cookie === void 0 ? (0, import_node_crypto3.randomBytes)(KEXINIT_COOKIE_LENGTH) :
|
|
6371
|
+
const cookie = options.cookie === void 0 ? (0, import_node_crypto3.randomBytes)(KEXINIT_COOKIE_LENGTH) : import_node_buffer9.Buffer.from(options.cookie);
|
|
6181
6372
|
if (cookie.length !== KEXINIT_COOKIE_LENGTH) {
|
|
6182
6373
|
throw new ConfigurationError({
|
|
6183
6374
|
details: { actualLength: cookie.length, expectedLength: KEXINIT_COOKIE_LENGTH },
|
|
@@ -6247,12 +6438,12 @@ function decodeSshKexInitMessage(payload) {
|
|
|
6247
6438
|
}
|
|
6248
6439
|
|
|
6249
6440
|
// src/protocols/ssh/transport/SshKexCurve25519.ts
|
|
6250
|
-
var
|
|
6441
|
+
var import_node_buffer10 = require("buffer");
|
|
6251
6442
|
var import_node_crypto4 = require("crypto");
|
|
6252
6443
|
var SSH_MSG_KEX_ECDH_INIT = 30;
|
|
6253
6444
|
var SSH_MSG_KEX_ECDH_REPLY = 31;
|
|
6254
6445
|
var X25519_PUBLIC_KEY_LENGTH = 32;
|
|
6255
|
-
var X25519_SPKI_PREFIX =
|
|
6446
|
+
var X25519_SPKI_PREFIX = import_node_buffer10.Buffer.from("302a300506032b656e032100", "hex");
|
|
6256
6447
|
function createCurve25519Ephemeral() {
|
|
6257
6448
|
const { privateKey, publicKey } = (0, import_node_crypto4.generateKeyPairSync)("x25519");
|
|
6258
6449
|
const encodedPublicKey = exportX25519PublicKeyRaw(publicKey);
|
|
@@ -6297,7 +6488,7 @@ function exportX25519PublicKeyRaw(publicKey) {
|
|
|
6297
6488
|
}
|
|
6298
6489
|
function importX25519PublicKeyRaw(raw) {
|
|
6299
6490
|
const normalized = normalizeX25519PublicKey(raw, "server");
|
|
6300
|
-
const der =
|
|
6491
|
+
const der = import_node_buffer10.Buffer.concat([X25519_SPKI_PREFIX, normalized]);
|
|
6301
6492
|
return (0, import_node_crypto4.createPublicKey)({
|
|
6302
6493
|
format: "der",
|
|
6303
6494
|
key: der,
|
|
@@ -6305,7 +6496,7 @@ function importX25519PublicKeyRaw(raw) {
|
|
|
6305
6496
|
});
|
|
6306
6497
|
}
|
|
6307
6498
|
function normalizeX25519PublicKey(value, label) {
|
|
6308
|
-
const key =
|
|
6499
|
+
const key = import_node_buffer10.Buffer.from(value);
|
|
6309
6500
|
if (key.length !== X25519_PUBLIC_KEY_LENGTH) {
|
|
6310
6501
|
throw new ConfigurationError({
|
|
6311
6502
|
details: { keyLength: key.length, label },
|
|
@@ -6318,7 +6509,7 @@ function normalizeX25519PublicKey(value, label) {
|
|
|
6318
6509
|
}
|
|
6319
6510
|
|
|
6320
6511
|
// src/protocols/ssh/transport/SshKeyDerivation.ts
|
|
6321
|
-
var
|
|
6512
|
+
var import_node_buffer11 = require("buffer");
|
|
6322
6513
|
var import_node_crypto5 = require("crypto");
|
|
6323
6514
|
function deriveSshSessionKeys(input) {
|
|
6324
6515
|
const hashAlgorithm = resolveKexHashAlgorithm(input.kexAlgorithm);
|
|
@@ -6340,7 +6531,7 @@ function deriveSshSessionKeys(input) {
|
|
|
6340
6531
|
input.negotiatedAlgorithms.encryptionServerToClient,
|
|
6341
6532
|
input.negotiatedAlgorithms.macServerToClient
|
|
6342
6533
|
);
|
|
6343
|
-
const sharedSecret =
|
|
6534
|
+
const sharedSecret = import_node_buffer11.Buffer.from(input.sharedSecret);
|
|
6344
6535
|
return {
|
|
6345
6536
|
clientToServer: {
|
|
6346
6537
|
encryptionKey: deriveMaterial(
|
|
@@ -6390,21 +6581,21 @@ function computeCurve25519ExchangeHash(input, hashAlgorithm) {
|
|
|
6390
6581
|
}
|
|
6391
6582
|
function deriveMaterial(sharedSecret, exchangeHash, sessionId, letter, length, hashAlgorithm) {
|
|
6392
6583
|
if (length <= 0) {
|
|
6393
|
-
return
|
|
6584
|
+
return import_node_buffer11.Buffer.alloc(0);
|
|
6394
6585
|
}
|
|
6395
6586
|
const result = [];
|
|
6396
6587
|
const first2 = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
|
|
6397
6588
|
new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeByte(letter.charCodeAt(0)).writeBytes(sessionId).toBuffer()
|
|
6398
6589
|
).digest();
|
|
6399
6590
|
result.push(first2);
|
|
6400
|
-
while (
|
|
6401
|
-
const previous =
|
|
6591
|
+
while (import_node_buffer11.Buffer.concat(result).length < length) {
|
|
6592
|
+
const previous = import_node_buffer11.Buffer.concat(result);
|
|
6402
6593
|
const next = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
|
|
6403
6594
|
new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeBytes(previous).toBuffer()
|
|
6404
6595
|
).digest();
|
|
6405
6596
|
result.push(next);
|
|
6406
6597
|
}
|
|
6407
|
-
return
|
|
6598
|
+
return import_node_buffer11.Buffer.concat(result).subarray(0, length);
|
|
6408
6599
|
}
|
|
6409
6600
|
function resolveKexHashAlgorithm(kexAlgorithm) {
|
|
6410
6601
|
if (kexAlgorithm === "curve25519-sha256" || kexAlgorithm === "curve25519-sha256@libssh.org") {
|
|
@@ -6492,20 +6683,21 @@ function decodeSshNewKeysMessage(payload) {
|
|
|
6492
6683
|
}
|
|
6493
6684
|
|
|
6494
6685
|
// src/protocols/ssh/transport/SshTransportPacket.ts
|
|
6495
|
-
var
|
|
6686
|
+
var import_node_buffer12 = require("buffer");
|
|
6496
6687
|
var import_node_crypto6 = require("crypto");
|
|
6497
6688
|
var MIN_PADDING_LENGTH = 4;
|
|
6498
6689
|
var MIN_PACKET_LENGTH = 1 + MIN_PADDING_LENGTH;
|
|
6690
|
+
var MAX_SSH_PACKET_LENGTH = 256 * 1024;
|
|
6499
6691
|
function encodeSshTransportPacket(payload, options = {}) {
|
|
6500
|
-
const body =
|
|
6692
|
+
const body = import_node_buffer12.Buffer.from(payload);
|
|
6501
6693
|
const blockSize = normalizeBlockSize(options.blockSize ?? 8);
|
|
6502
6694
|
let paddingLength = MIN_PADDING_LENGTH;
|
|
6503
6695
|
while ((1 + body.length + paddingLength + 4) % blockSize !== 0) {
|
|
6504
6696
|
paddingLength += 1;
|
|
6505
6697
|
}
|
|
6506
|
-
const padding = options.randomPadding === false ?
|
|
6698
|
+
const padding = options.randomPadding === false ? import_node_buffer12.Buffer.alloc(paddingLength) : (0, import_node_crypto6.randomBytes)(paddingLength);
|
|
6507
6699
|
const packetLength = 1 + body.length + paddingLength;
|
|
6508
|
-
const frame =
|
|
6700
|
+
const frame = import_node_buffer12.Buffer.alloc(4 + packetLength);
|
|
6509
6701
|
frame.writeUInt32BE(packetLength, 0);
|
|
6510
6702
|
frame.writeUInt8(paddingLength, 4);
|
|
6511
6703
|
body.copy(frame, 5);
|
|
@@ -6513,7 +6705,7 @@ function encodeSshTransportPacket(payload, options = {}) {
|
|
|
6513
6705
|
return frame;
|
|
6514
6706
|
}
|
|
6515
6707
|
function decodeSshTransportPacket(frame) {
|
|
6516
|
-
const bytes =
|
|
6708
|
+
const bytes = import_node_buffer12.Buffer.from(frame);
|
|
6517
6709
|
if (bytes.length < 4 + MIN_PACKET_LENGTH) {
|
|
6518
6710
|
throw new ParseError({
|
|
6519
6711
|
details: { length: bytes.length },
|
|
@@ -6567,12 +6759,20 @@ function decodeSshTransportPacket(frame) {
|
|
|
6567
6759
|
};
|
|
6568
6760
|
}
|
|
6569
6761
|
var SshTransportPacketFramer = class {
|
|
6570
|
-
pending =
|
|
6762
|
+
pending = import_node_buffer12.Buffer.alloc(0);
|
|
6571
6763
|
push(chunk) {
|
|
6572
|
-
this.pending =
|
|
6764
|
+
this.pending = import_node_buffer12.Buffer.concat([this.pending, import_node_buffer12.Buffer.from(chunk)]);
|
|
6573
6765
|
const packets = [];
|
|
6574
6766
|
while (this.pending.length >= 4) {
|
|
6575
6767
|
const packetLength = this.pending.readUInt32BE(0);
|
|
6768
|
+
if (packetLength > MAX_SSH_PACKET_LENGTH) {
|
|
6769
|
+
throw new ParseError({
|
|
6770
|
+
details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },
|
|
6771
|
+
message: "SSH transport packet length exceeds the maximum accepted size",
|
|
6772
|
+
protocol: "sftp",
|
|
6773
|
+
retryable: false
|
|
6774
|
+
});
|
|
6775
|
+
}
|
|
6576
6776
|
const frameLength = 4 + packetLength;
|
|
6577
6777
|
if (this.pending.length < frameLength) {
|
|
6578
6778
|
break;
|
|
@@ -6588,8 +6788,8 @@ var SshTransportPacketFramer = class {
|
|
|
6588
6788
|
}
|
|
6589
6789
|
/** Returns and clears any bytes buffered but not yet part of a complete packet. */
|
|
6590
6790
|
takeRemainingBytes() {
|
|
6591
|
-
const remaining =
|
|
6592
|
-
this.pending =
|
|
6791
|
+
const remaining = import_node_buffer12.Buffer.from(this.pending);
|
|
6792
|
+
this.pending = import_node_buffer12.Buffer.alloc(0);
|
|
6593
6793
|
return remaining;
|
|
6594
6794
|
}
|
|
6595
6795
|
};
|
|
@@ -6606,10 +6806,10 @@ function normalizeBlockSize(blockSize) {
|
|
|
6606
6806
|
}
|
|
6607
6807
|
|
|
6608
6808
|
// src/protocols/ssh/transport/SshHostKeyVerification.ts
|
|
6609
|
-
var
|
|
6809
|
+
var import_node_buffer13 = require("buffer");
|
|
6610
6810
|
var import_node_crypto7 = require("crypto");
|
|
6611
6811
|
var ED25519_RAW_KEY_LENGTH2 = 32;
|
|
6612
|
-
var ED25519_SPKI_PREFIX =
|
|
6812
|
+
var ED25519_SPKI_PREFIX = import_node_buffer13.Buffer.from("302a300506032b6570032100", "hex");
|
|
6613
6813
|
function verifySshHostKeySignature(input) {
|
|
6614
6814
|
const { algorithmName, publicKey } = parseHostKey(input.hostKeyBlob);
|
|
6615
6815
|
const { signatureAlgorithm, signatureBytes } = parseSignatureBlob(input.signatureBlob);
|
|
@@ -6622,9 +6822,9 @@ function verifySshHostKeySignature(input) {
|
|
|
6622
6822
|
});
|
|
6623
6823
|
}
|
|
6624
6824
|
const verified = verifySignature({
|
|
6625
|
-
data:
|
|
6825
|
+
data: import_node_buffer13.Buffer.from(input.exchangeHash),
|
|
6626
6826
|
publicKey,
|
|
6627
|
-
signature:
|
|
6827
|
+
signature: import_node_buffer13.Buffer.from(signatureBytes),
|
|
6628
6828
|
signatureAlgorithm
|
|
6629
6829
|
});
|
|
6630
6830
|
if (!verified) {
|
|
@@ -6653,7 +6853,7 @@ function parseHostKey(blob) {
|
|
|
6653
6853
|
retryable: false
|
|
6654
6854
|
});
|
|
6655
6855
|
}
|
|
6656
|
-
const spki =
|
|
6856
|
+
const spki = import_node_buffer13.Buffer.concat([ED25519_SPKI_PREFIX, raw]);
|
|
6657
6857
|
return {
|
|
6658
6858
|
algorithmName,
|
|
6659
6859
|
publicKey: (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" })
|
|
@@ -6759,37 +6959,37 @@ function verifySignature(input) {
|
|
|
6759
6959
|
function rsaPublicKeyFromComponents(e, n) {
|
|
6760
6960
|
const eDer = encodeAsn1Integer(e);
|
|
6761
6961
|
const nDer = encodeAsn1Integer(n);
|
|
6762
|
-
const rsaPublicKeyDer = encodeAsn1Sequence(
|
|
6763
|
-
const bitStringContent =
|
|
6764
|
-
const bitString =
|
|
6765
|
-
|
|
6962
|
+
const rsaPublicKeyDer = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([nDer, eDer]));
|
|
6963
|
+
const bitStringContent = import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([0]), rsaPublicKeyDer]);
|
|
6964
|
+
const bitString = import_node_buffer13.Buffer.concat([
|
|
6965
|
+
import_node_buffer13.Buffer.from([3]),
|
|
6766
6966
|
encodeAsn1Length(bitStringContent.length),
|
|
6767
6967
|
bitStringContent
|
|
6768
6968
|
]);
|
|
6769
|
-
const algoId =
|
|
6770
|
-
const spki = encodeAsn1Sequence(
|
|
6969
|
+
const algoId = import_node_buffer13.Buffer.from("300d06092a864886f70d010101 0500".replace(/\s+/g, ""), "hex");
|
|
6970
|
+
const spki = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([algoId, bitString]));
|
|
6771
6971
|
return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
|
|
6772
6972
|
}
|
|
6773
6973
|
function encodeAsn1Integer(value) {
|
|
6774
6974
|
let body = value;
|
|
6775
6975
|
while (body.length > 1 && body[0] === 0) body = body.subarray(1);
|
|
6776
6976
|
if (body.length > 0 && (body[0] & 128) !== 0) {
|
|
6777
|
-
body =
|
|
6977
|
+
body = import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([0]), body]);
|
|
6778
6978
|
}
|
|
6779
|
-
return
|
|
6979
|
+
return import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([2]), encodeAsn1Length(body.length), body]);
|
|
6780
6980
|
}
|
|
6781
6981
|
function encodeAsn1Sequence(content) {
|
|
6782
|
-
return
|
|
6982
|
+
return import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([48]), encodeAsn1Length(content.length), content]);
|
|
6783
6983
|
}
|
|
6784
6984
|
function encodeAsn1Length(length) {
|
|
6785
|
-
if (length < 128) return
|
|
6985
|
+
if (length < 128) return import_node_buffer13.Buffer.from([length]);
|
|
6786
6986
|
const bytes = [];
|
|
6787
6987
|
let n = length;
|
|
6788
6988
|
while (n > 0) {
|
|
6789
6989
|
bytes.unshift(n & 255);
|
|
6790
6990
|
n >>>= 8;
|
|
6791
6991
|
}
|
|
6792
|
-
return
|
|
6992
|
+
return import_node_buffer13.Buffer.from([128 | bytes.length, ...bytes]);
|
|
6793
6993
|
}
|
|
6794
6994
|
var ECDSA_OID_BY_CURVE = {
|
|
6795
6995
|
nistp256: "06082a8648ce3d030107",
|
|
@@ -6810,15 +7010,15 @@ function ecdsaPublicKeyFromPoint(curveIdentifier, point) {
|
|
|
6810
7010
|
retryable: false
|
|
6811
7011
|
});
|
|
6812
7012
|
}
|
|
6813
|
-
const algoIdContent =
|
|
7013
|
+
const algoIdContent = import_node_buffer13.Buffer.from(ECDSA_ALGORITHM_OID_HEX + oidHex, "hex");
|
|
6814
7014
|
const algoId = encodeAsn1Sequence(algoIdContent);
|
|
6815
|
-
const bitStringContent =
|
|
6816
|
-
const bitString =
|
|
6817
|
-
|
|
7015
|
+
const bitStringContent = import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from([0]), point]);
|
|
7016
|
+
const bitString = import_node_buffer13.Buffer.concat([
|
|
7017
|
+
import_node_buffer13.Buffer.from([3]),
|
|
6818
7018
|
encodeAsn1Length(bitStringContent.length),
|
|
6819
7019
|
bitStringContent
|
|
6820
7020
|
]);
|
|
6821
|
-
const spki = encodeAsn1Sequence(
|
|
7021
|
+
const spki = encodeAsn1Sequence(import_node_buffer13.Buffer.concat([algoId, bitString]));
|
|
6822
7022
|
return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
|
|
6823
7023
|
}
|
|
6824
7024
|
function sshEcdsaSignatureToDer(sshSignature) {
|
|
@@ -6827,7 +7027,7 @@ function sshEcdsaSignatureToDer(sshSignature) {
|
|
|
6827
7027
|
const s = reader.readMpint();
|
|
6828
7028
|
const rDer = encodeAsn1Integer(r);
|
|
6829
7029
|
const sDer = encodeAsn1Integer(s);
|
|
6830
|
-
return encodeAsn1Sequence(
|
|
7030
|
+
return encodeAsn1Sequence(import_node_buffer13.Buffer.concat([rDer, sDer]));
|
|
6831
7031
|
}
|
|
6832
7032
|
|
|
6833
7033
|
// src/protocols/ssh/transport/SshTransportHandshake.ts
|
|
@@ -6859,7 +7059,7 @@ var SshTransportHandshake = class {
|
|
|
6859
7059
|
serverIdentification;
|
|
6860
7060
|
/** Creates the first outbound bytes (client identification line). */
|
|
6861
7061
|
createInitialClientBytes() {
|
|
6862
|
-
return
|
|
7062
|
+
return import_node_buffer14.Buffer.from(`${this.clientIdentificationLine}\r
|
|
6863
7063
|
`, "ascii");
|
|
6864
7064
|
}
|
|
6865
7065
|
/**
|
|
@@ -6883,7 +7083,7 @@ var SshTransportHandshake = class {
|
|
|
6883
7083
|
}
|
|
6884
7084
|
return { outbound };
|
|
6885
7085
|
}
|
|
6886
|
-
return this.pushServerBytesWithPhase(outbound,
|
|
7086
|
+
return this.pushServerBytesWithPhase(outbound, import_node_buffer14.Buffer.from(chunk));
|
|
6887
7087
|
}
|
|
6888
7088
|
getServerBannerLines() {
|
|
6889
7089
|
return this.identificationLines;
|
|
@@ -6937,12 +7137,12 @@ var SshTransportHandshake = class {
|
|
|
6937
7137
|
clientKexInitPayload: this.clientKexInitPayload,
|
|
6938
7138
|
clientPublicKey: this.pendingCurve25519.publicKey,
|
|
6939
7139
|
negotiatedAlgorithms,
|
|
6940
|
-
serverHostKey:
|
|
7140
|
+
serverHostKey: import_node_buffer14.Buffer.alloc(0),
|
|
6941
7141
|
serverIdentification: (this.serverIdentification ?? missingServerIdentificationError()).raw,
|
|
6942
|
-
serverKexInitPayload:
|
|
6943
|
-
serverPublicKey:
|
|
6944
|
-
serverSignature:
|
|
6945
|
-
sharedSecret:
|
|
7142
|
+
serverKexInitPayload: import_node_buffer14.Buffer.from(packet.payload),
|
|
7143
|
+
serverPublicKey: import_node_buffer14.Buffer.alloc(0),
|
|
7144
|
+
serverSignature: import_node_buffer14.Buffer.alloc(0),
|
|
7145
|
+
sharedSecret: import_node_buffer14.Buffer.alloc(0)
|
|
6946
7146
|
};
|
|
6947
7147
|
continue;
|
|
6948
7148
|
}
|
|
@@ -7050,24 +7250,54 @@ var SshTransportHandshake = class {
|
|
|
7050
7250
|
return { outbound };
|
|
7051
7251
|
}
|
|
7052
7252
|
};
|
|
7253
|
+
var MAX_IDENTIFICATION_LINE_BYTES = 8192;
|
|
7254
|
+
var MAX_PRE_IDENTIFICATION_LINES = 1024;
|
|
7053
7255
|
var SshIdentificationAccumulator = class {
|
|
7054
|
-
pending =
|
|
7256
|
+
pending = import_node_buffer14.Buffer.alloc(0);
|
|
7257
|
+
bannerLineCount = 0;
|
|
7055
7258
|
push(chunk) {
|
|
7056
|
-
this.pending =
|
|
7259
|
+
this.pending = import_node_buffer14.Buffer.concat([this.pending, import_node_buffer14.Buffer.from(chunk)]);
|
|
7057
7260
|
const bannerLines = [];
|
|
7058
7261
|
while (true) {
|
|
7059
7262
|
const lfIndex = this.pending.indexOf(10);
|
|
7060
|
-
if (lfIndex < 0)
|
|
7263
|
+
if (lfIndex < 0) {
|
|
7264
|
+
if (this.pending.length > MAX_IDENTIFICATION_LINE_BYTES) {
|
|
7265
|
+
throw new ProtocolError({
|
|
7266
|
+
details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },
|
|
7267
|
+
message: "SSH identification line exceeds the maximum accepted length",
|
|
7268
|
+
protocol: "sftp",
|
|
7269
|
+
retryable: false
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
break;
|
|
7273
|
+
}
|
|
7274
|
+
if (lfIndex > MAX_IDENTIFICATION_LINE_BYTES) {
|
|
7275
|
+
throw new ProtocolError({
|
|
7276
|
+
details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },
|
|
7277
|
+
message: "SSH identification line exceeds the maximum accepted length",
|
|
7278
|
+
protocol: "sftp",
|
|
7279
|
+
retryable: false
|
|
7280
|
+
});
|
|
7281
|
+
}
|
|
7061
7282
|
const lineText = trimLineEndings(this.pending.subarray(0, lfIndex + 1).toString("ascii"));
|
|
7062
|
-
const remainder =
|
|
7283
|
+
const remainder = import_node_buffer14.Buffer.from(this.pending.subarray(lfIndex + 1));
|
|
7063
7284
|
this.pending = remainder;
|
|
7064
7285
|
if (lineText.startsWith("SSH-")) {
|
|
7065
|
-
this.pending =
|
|
7286
|
+
this.pending = import_node_buffer14.Buffer.alloc(0);
|
|
7066
7287
|
return { bannerLines, identLine: lineText, remainder };
|
|
7067
7288
|
}
|
|
7289
|
+
this.bannerLineCount += 1;
|
|
7290
|
+
if (this.bannerLineCount > MAX_PRE_IDENTIFICATION_LINES) {
|
|
7291
|
+
throw new ProtocolError({
|
|
7292
|
+
details: { limitLines: MAX_PRE_IDENTIFICATION_LINES },
|
|
7293
|
+
message: "SSH server sent too many pre-identification banner lines",
|
|
7294
|
+
protocol: "sftp",
|
|
7295
|
+
retryable: false
|
|
7296
|
+
});
|
|
7297
|
+
}
|
|
7068
7298
|
bannerLines.push(lineText);
|
|
7069
7299
|
}
|
|
7070
|
-
return { bannerLines, remainder:
|
|
7300
|
+
return { bannerLines, remainder: import_node_buffer14.Buffer.alloc(0) };
|
|
7071
7301
|
}
|
|
7072
7302
|
};
|
|
7073
7303
|
function trimLineEndings(value) {
|
|
@@ -7095,7 +7325,7 @@ function missingPendingKeyExchangeError() {
|
|
|
7095
7325
|
}
|
|
7096
7326
|
|
|
7097
7327
|
// src/protocols/ssh/transport/SshTransportProtection.ts
|
|
7098
|
-
var
|
|
7328
|
+
var import_node_buffer15 = require("buffer");
|
|
7099
7329
|
var import_node_crypto8 = require("crypto");
|
|
7100
7330
|
function createSshTransportProtectionContext(input) {
|
|
7101
7331
|
return {
|
|
@@ -7152,7 +7382,7 @@ var SshTransportPacketProtector = class {
|
|
|
7152
7382
|
);
|
|
7153
7383
|
const encrypted = this.cipher === void 0 ? clearPacket : this.cipher.update(clearPacket);
|
|
7154
7384
|
this.sequenceNumber = this.sequenceNumber + 1 >>> 0;
|
|
7155
|
-
return
|
|
7385
|
+
return import_node_buffer15.Buffer.concat([encrypted, mac]);
|
|
7156
7386
|
}
|
|
7157
7387
|
};
|
|
7158
7388
|
var SshTransportPacketUnprotector = class {
|
|
@@ -7178,7 +7408,7 @@ var SshTransportPacketUnprotector = class {
|
|
|
7178
7408
|
sequenceNumber;
|
|
7179
7409
|
// Streaming framing state for pushBytes()
|
|
7180
7410
|
framePartialDecrypted;
|
|
7181
|
-
framePendingRaw =
|
|
7411
|
+
framePendingRaw = import_node_buffer15.Buffer.alloc(0);
|
|
7182
7412
|
frameRemainingNeeded;
|
|
7183
7413
|
getSequenceNumber() {
|
|
7184
7414
|
return this.sequenceNumber;
|
|
@@ -7188,15 +7418,23 @@ var SshTransportPacketUnprotector = class {
|
|
|
7188
7418
|
* Maintains internal framing state across calls - pass each `data` event chunk directly.
|
|
7189
7419
|
*/
|
|
7190
7420
|
pushBytes(chunk) {
|
|
7191
|
-
this.framePendingRaw =
|
|
7421
|
+
this.framePendingRaw = import_node_buffer15.Buffer.concat([this.framePendingRaw, chunk]);
|
|
7192
7422
|
const results = [];
|
|
7193
7423
|
while (true) {
|
|
7194
7424
|
if (this.framePartialDecrypted === void 0) {
|
|
7195
7425
|
if (this.framePendingRaw.length < this.blockLength) break;
|
|
7196
7426
|
const firstBlock = this.framePendingRaw.subarray(0, this.blockLength);
|
|
7197
|
-
this.framePendingRaw =
|
|
7198
|
-
this.framePartialDecrypted = this.decipher ?
|
|
7427
|
+
this.framePendingRaw = import_node_buffer15.Buffer.from(this.framePendingRaw.subarray(this.blockLength));
|
|
7428
|
+
this.framePartialDecrypted = this.decipher ? import_node_buffer15.Buffer.from(this.decipher.update(firstBlock)) : import_node_buffer15.Buffer.from(firstBlock);
|
|
7199
7429
|
const packetLength = this.framePartialDecrypted.readUInt32BE(0);
|
|
7430
|
+
if (packetLength > MAX_SSH_PACKET_LENGTH) {
|
|
7431
|
+
throw new ProtocolError({
|
|
7432
|
+
details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },
|
|
7433
|
+
message: "SSH encrypted packet length exceeds the maximum accepted size",
|
|
7434
|
+
protocol: "sftp",
|
|
7435
|
+
retryable: false
|
|
7436
|
+
});
|
|
7437
|
+
}
|
|
7200
7438
|
const remaining = 4 + packetLength - this.blockLength + this.macLength;
|
|
7201
7439
|
if (remaining < 0) {
|
|
7202
7440
|
throw new ProtocolError({
|
|
@@ -7212,9 +7450,9 @@ var SshTransportPacketUnprotector = class {
|
|
|
7212
7450
|
if (this.framePendingRaw.length < needed) break;
|
|
7213
7451
|
const encryptedRest = this.framePendingRaw.subarray(0, needed - this.macLength);
|
|
7214
7452
|
const receivedMac = this.framePendingRaw.subarray(needed - this.macLength, needed);
|
|
7215
|
-
this.framePendingRaw =
|
|
7216
|
-
const decryptedRest = encryptedRest.length > 0 ? this.decipher ?
|
|
7217
|
-
const clearPacket =
|
|
7453
|
+
this.framePendingRaw = import_node_buffer15.Buffer.from(this.framePendingRaw.subarray(needed));
|
|
7454
|
+
const decryptedRest = encryptedRest.length > 0 ? this.decipher ? import_node_buffer15.Buffer.from(this.decipher.update(encryptedRest)) : import_node_buffer15.Buffer.from(encryptedRest) : import_node_buffer15.Buffer.alloc(0);
|
|
7455
|
+
const clearPacket = import_node_buffer15.Buffer.concat([this.framePartialDecrypted, decryptedRest]);
|
|
7218
7456
|
const expectedMac = computeMac(
|
|
7219
7457
|
this.macAlgorithm,
|
|
7220
7458
|
this.options.keys.macKey,
|
|
@@ -7237,7 +7475,7 @@ var SshTransportPacketUnprotector = class {
|
|
|
7237
7475
|
return results;
|
|
7238
7476
|
}
|
|
7239
7477
|
unprotectPayload(packet) {
|
|
7240
|
-
const frame =
|
|
7478
|
+
const frame = import_node_buffer15.Buffer.from(packet);
|
|
7241
7479
|
if (frame.length < this.macLength) {
|
|
7242
7480
|
throw new ProtocolError({
|
|
7243
7481
|
details: { length: frame.length, macLength: this.macLength },
|
|
@@ -7378,10 +7616,10 @@ function resolveMacLength(encryptionAlgorithm, macAlgorithm) {
|
|
|
7378
7616
|
}
|
|
7379
7617
|
function computeMac(macAlgorithm, macKey, sequence, packet, macLength) {
|
|
7380
7618
|
if (macLength === 0) {
|
|
7381
|
-
return
|
|
7619
|
+
return import_node_buffer15.Buffer.alloc(0);
|
|
7382
7620
|
}
|
|
7383
7621
|
const hashName = macAlgorithm === "hmac-sha2-512" ? "sha512" : "sha256";
|
|
7384
|
-
const sequenceBuffer =
|
|
7622
|
+
const sequenceBuffer = import_node_buffer15.Buffer.alloc(4);
|
|
7385
7623
|
sequenceBuffer.writeUInt32BE(sequence >>> 0, 0);
|
|
7386
7624
|
return (0, import_node_crypto8.createHmac)(hashName, macKey).update(sequenceBuffer).update(packet).digest().subarray(0, macLength);
|
|
7387
7625
|
}
|
|
@@ -7588,7 +7826,7 @@ var SshTransportConnection = class {
|
|
|
7588
7826
|
*/
|
|
7589
7827
|
sendPayload(payload) {
|
|
7590
7828
|
this.assertConnected();
|
|
7591
|
-
const frame = this.protector.protectPayload(
|
|
7829
|
+
const frame = this.protector.protectPayload(import_node_buffer16.Buffer.from(payload));
|
|
7592
7830
|
this.socket.write(frame);
|
|
7593
7831
|
this.resetKeepaliveTimer();
|
|
7594
7832
|
}
|
|
@@ -7746,7 +7984,7 @@ function parseDisconnectPayload(payload) {
|
|
|
7746
7984
|
}
|
|
7747
7985
|
|
|
7748
7986
|
// src/protocols/sftp/v3/SftpSession.ts
|
|
7749
|
-
var
|
|
7987
|
+
var import_node_buffer18 = require("buffer");
|
|
7750
7988
|
|
|
7751
7989
|
// src/protocols/sftp/v3/SftpAttributes.ts
|
|
7752
7990
|
var SFTP_ATTR_FLAG = {
|
|
@@ -7819,7 +8057,8 @@ function decodeSftpAttributesFromReader(reader) {
|
|
|
7819
8057
|
}
|
|
7820
8058
|
|
|
7821
8059
|
// src/protocols/sftp/v3/SftpPacket.ts
|
|
7822
|
-
var
|
|
8060
|
+
var import_node_buffer17 = require("buffer");
|
|
8061
|
+
var MAX_SFTP_PACKET_LENGTH = 256 * 1024;
|
|
7823
8062
|
var SFTP_PACKET_TYPE = {
|
|
7824
8063
|
ATTRS: 105,
|
|
7825
8064
|
CLOSE: 4,
|
|
@@ -7850,7 +8089,7 @@ var SFTP_PACKET_TYPE = {
|
|
|
7850
8089
|
WRITE: 6
|
|
7851
8090
|
};
|
|
7852
8091
|
function decodeSftpPacket(frame) {
|
|
7853
|
-
const bytes =
|
|
8092
|
+
const bytes = import_node_buffer17.Buffer.from(frame);
|
|
7854
8093
|
if (bytes.length < 5) {
|
|
7855
8094
|
throw new ParseError({
|
|
7856
8095
|
details: { length: bytes.length },
|
|
@@ -7873,12 +8112,19 @@ function decodeSftpPacket(frame) {
|
|
|
7873
8112
|
};
|
|
7874
8113
|
}
|
|
7875
8114
|
var SftpPacketFramer = class {
|
|
7876
|
-
pending =
|
|
8115
|
+
pending = import_node_buffer17.Buffer.alloc(0);
|
|
7877
8116
|
push(chunk) {
|
|
7878
|
-
this.pending =
|
|
8117
|
+
this.pending = import_node_buffer17.Buffer.concat([this.pending, import_node_buffer17.Buffer.from(chunk)]);
|
|
7879
8118
|
const packets = [];
|
|
7880
8119
|
while (this.pending.length >= 4) {
|
|
7881
8120
|
const bodyLength = this.pending.readUInt32BE(0);
|
|
8121
|
+
if (bodyLength > MAX_SFTP_PACKET_LENGTH) {
|
|
8122
|
+
throw new ParseError({
|
|
8123
|
+
details: { bodyLength, maxPacketLength: MAX_SFTP_PACKET_LENGTH },
|
|
8124
|
+
message: "SFTP packet length exceeds the maximum accepted size",
|
|
8125
|
+
retryable: false
|
|
8126
|
+
});
|
|
8127
|
+
}
|
|
7882
8128
|
const frameLength = 4 + bodyLength;
|
|
7883
8129
|
if (this.pending.length < frameLength) {
|
|
7884
8130
|
break;
|
|
@@ -8333,7 +8579,7 @@ var SftpSession = class {
|
|
|
8333
8579
|
* serializes concurrent calls so byte ordering is preserved.
|
|
8334
8580
|
*/
|
|
8335
8581
|
sendRaw(encodedMessage, requestId) {
|
|
8336
|
-
const frame =
|
|
8582
|
+
const frame = import_node_buffer18.Buffer.alloc(4 + encodedMessage.length);
|
|
8337
8583
|
frame.writeUInt32BE(encodedMessage.length, 0);
|
|
8338
8584
|
encodedMessage.copy(frame, 4);
|
|
8339
8585
|
this.channel.sendData(frame).catch((err) => {
|
|
@@ -8876,9 +9122,9 @@ function buildNativePublickeyCredential(profile, username) {
|
|
|
8876
9122
|
const passphrase = profile.ssh?.passphrase;
|
|
8877
9123
|
try {
|
|
8878
9124
|
const privateKey = (0, import_node_crypto9.createPrivateKey)({
|
|
8879
|
-
key:
|
|
9125
|
+
key: import_node_buffer19.Buffer.isBuffer(keyMaterial) ? keyMaterial : keyMaterial,
|
|
8880
9126
|
...passphrase === void 0 ? {} : {
|
|
8881
|
-
passphrase:
|
|
9127
|
+
passphrase: import_node_buffer19.Buffer.isBuffer(passphrase) ? passphrase : passphrase
|
|
8882
9128
|
}
|
|
8883
9129
|
});
|
|
8884
9130
|
return buildPublickeyCredential({ privateKey, username });
|
|
@@ -9005,12 +9251,12 @@ function normalizeNativeHostKeyPins(value) {
|
|
|
9005
9251
|
const trimmed = pin.trim();
|
|
9006
9252
|
const hex = trimmed.replace(/:/g, "");
|
|
9007
9253
|
if (hex.length === 64 && /^[a-f0-9]+$/i.test(hex)) {
|
|
9008
|
-
normalized.add(
|
|
9254
|
+
normalized.add(import_node_buffer19.Buffer.from(hex, "hex").toString("base64").replace(/=+$/g, ""));
|
|
9009
9255
|
continue;
|
|
9010
9256
|
}
|
|
9011
9257
|
const bare = trimmed.startsWith("SHA256:") ? trimmed.slice("SHA256:".length) : trimmed;
|
|
9012
9258
|
const padded = bare.length % 4 === 0 ? bare : `${bare}${"=".repeat(4 - bare.length % 4)}`;
|
|
9013
|
-
normalized.add(
|
|
9259
|
+
normalized.add(import_node_buffer19.Buffer.from(padded, "base64").toString("base64").replace(/=+$/g, ""));
|
|
9014
9260
|
}
|
|
9015
9261
|
return normalized;
|
|
9016
9262
|
}
|
|
@@ -9020,7 +9266,7 @@ function parseNativeKnownHosts(source) {
|
|
|
9020
9266
|
const entries = [];
|
|
9021
9267
|
let sawNonEmpty = false;
|
|
9022
9268
|
for (const value of sources) {
|
|
9023
|
-
const text =
|
|
9269
|
+
const text = import_node_buffer19.Buffer.isBuffer(value) ? value.toString("utf8") : String(value);
|
|
9024
9270
|
if (text.length === 0) continue;
|
|
9025
9271
|
sawNonEmpty = true;
|
|
9026
9272
|
entries.push(...parseKnownHosts(text));
|
|
@@ -9093,7 +9339,7 @@ function requireNativeSftpUsername(profile) {
|
|
|
9093
9339
|
}
|
|
9094
9340
|
function resolveNativeSftpTextSecret(value) {
|
|
9095
9341
|
if (value === void 0) return void 0;
|
|
9096
|
-
const text =
|
|
9342
|
+
const text = import_node_buffer19.Buffer.isBuffer(value) ? value.toString("utf8") : value;
|
|
9097
9343
|
if (text.length === 0) return void 0;
|
|
9098
9344
|
return text;
|
|
9099
9345
|
}
|
|
@@ -9168,6 +9414,7 @@ function validateNativeSftpOptions(options) {
|
|
|
9168
9414
|
copyBetween,
|
|
9169
9415
|
createAtomicDeployPlan,
|
|
9170
9416
|
createBandwidthThrottle,
|
|
9417
|
+
createDefaultRetryPolicy,
|
|
9171
9418
|
createLocalProviderFactory,
|
|
9172
9419
|
createMemoryProviderFactory,
|
|
9173
9420
|
createOAuthTokenSecretSource,
|
|
@@ -9204,8 +9451,10 @@ function validateNativeSftpOptions(options) {
|
|
|
9204
9451
|
parseRemoteManifest,
|
|
9205
9452
|
redactCommand,
|
|
9206
9453
|
redactConnectionProfile,
|
|
9454
|
+
redactErrorForLogging,
|
|
9207
9455
|
redactObject,
|
|
9208
9456
|
redactSecretSource,
|
|
9457
|
+
redactUrlForLogging,
|
|
9209
9458
|
redactValue,
|
|
9210
9459
|
resolveConnectionProfileSecrets,
|
|
9211
9460
|
resolveOpenSshHost,
|