@zero-transfer/classic 0.4.6 → 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/README.md +0 -2
- package/dist/index.cjs +511 -204
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +233 -29
- package/dist/index.d.ts +233 -29
- package/dist/index.mjs +508 -204
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,7 @@ __export(classic_exports, {
|
|
|
61
61
|
copyBetween: () => copyBetween,
|
|
62
62
|
createAtomicDeployPlan: () => createAtomicDeployPlan,
|
|
63
63
|
createBandwidthThrottle: () => createBandwidthThrottle,
|
|
64
|
+
createDefaultRetryPolicy: () => createDefaultRetryPolicy,
|
|
64
65
|
createFtpProviderFactory: () => createFtpProviderFactory,
|
|
65
66
|
createFtpsProviderFactory: () => createFtpsProviderFactory,
|
|
66
67
|
createLocalProviderFactory: () => createLocalProviderFactory,
|
|
@@ -71,7 +72,7 @@ __export(classic_exports, {
|
|
|
71
72
|
createProviderTransferExecutor: () => createProviderTransferExecutor,
|
|
72
73
|
createRemoteBrowser: () => createRemoteBrowser,
|
|
73
74
|
createRemoteManifest: () => createRemoteManifest,
|
|
74
|
-
createSftpProviderFactory: () =>
|
|
75
|
+
createSftpProviderFactory: () => createSftpProviderFactory,
|
|
75
76
|
createSyncPlan: () => createSyncPlan,
|
|
76
77
|
createTransferClient: () => createTransferClient,
|
|
77
78
|
createTransferJobsFromPlan: () => createTransferJobsFromPlan,
|
|
@@ -106,8 +107,10 @@ __export(classic_exports, {
|
|
|
106
107
|
parseUnixListLine: () => parseUnixListLine,
|
|
107
108
|
redactCommand: () => redactCommand,
|
|
108
109
|
redactConnectionProfile: () => redactConnectionProfile,
|
|
110
|
+
redactErrorForLogging: () => redactErrorForLogging,
|
|
109
111
|
redactObject: () => redactObject,
|
|
110
112
|
redactSecretSource: () => redactSecretSource,
|
|
113
|
+
redactUrlForLogging: () => redactUrlForLogging,
|
|
111
114
|
redactValue: () => redactValue,
|
|
112
115
|
resolveConnectionProfileSecrets: () => resolveConnectionProfileSecrets,
|
|
113
116
|
resolveOpenSshHost: () => resolveOpenSshHost,
|
|
@@ -128,6 +131,68 @@ module.exports = __toCommonJS(classic_exports);
|
|
|
128
131
|
// src/client/ZeroTransfer.ts
|
|
129
132
|
var import_node_events = require("events");
|
|
130
133
|
|
|
134
|
+
// src/logging/redaction.ts
|
|
135
|
+
var REDACTED = "[REDACTED]";
|
|
136
|
+
var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
|
|
137
|
+
var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
|
|
138
|
+
var URL_KEY_PATTERN = /(?:url|uri|href)$/i;
|
|
139
|
+
function isSensitiveKey(key) {
|
|
140
|
+
return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
|
|
141
|
+
}
|
|
142
|
+
function redactCommand(command) {
|
|
143
|
+
return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
|
|
144
|
+
return `${commandName.toUpperCase()} ${REDACTED}`;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function redactValue(value) {
|
|
148
|
+
if (typeof value === "string") {
|
|
149
|
+
return redactCommand(value);
|
|
150
|
+
}
|
|
151
|
+
if (Array.isArray(value)) {
|
|
152
|
+
return value.map((item) => redactValue(item));
|
|
153
|
+
}
|
|
154
|
+
if (value !== null && typeof value === "object") {
|
|
155
|
+
return redactObject(value);
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
function redactObject(input) {
|
|
160
|
+
return Object.fromEntries(
|
|
161
|
+
Object.entries(input).map(([key, value]) => {
|
|
162
|
+
if (isSensitiveKey(key)) {
|
|
163
|
+
return [key, REDACTED];
|
|
164
|
+
}
|
|
165
|
+
if (URL_KEY_PATTERN.test(key) && typeof value === "string") {
|
|
166
|
+
return [key, redactUrlForLogging(value)];
|
|
167
|
+
}
|
|
168
|
+
return [key, redactValue(value)];
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
function redactUrlForLogging(url) {
|
|
173
|
+
let parsed;
|
|
174
|
+
try {
|
|
175
|
+
parsed = typeof url === "string" ? new URL(url) : url;
|
|
176
|
+
} catch {
|
|
177
|
+
return REDACTED;
|
|
178
|
+
}
|
|
179
|
+
const origin = parsed.host.length > 0 ? `${parsed.protocol}//${parsed.host}` : parsed.protocol;
|
|
180
|
+
const query = parsed.search.length > 0 ? `?${REDACTED}` : "";
|
|
181
|
+
return `${origin}${parsed.pathname}${query}`;
|
|
182
|
+
}
|
|
183
|
+
function redactErrorForLogging(error) {
|
|
184
|
+
if (error !== null && typeof error === "object") {
|
|
185
|
+
const candidate = error;
|
|
186
|
+
if (typeof candidate.toJSON === "function") {
|
|
187
|
+
return redactObject(candidate.toJSON());
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (error instanceof Error) {
|
|
191
|
+
return redactObject({ message: error.message, name: error.name });
|
|
192
|
+
}
|
|
193
|
+
return { message: redactValue(typeof error === "string" ? error : String(error)) };
|
|
194
|
+
}
|
|
195
|
+
|
|
131
196
|
// src/errors/ZeroTransferError.ts
|
|
132
197
|
var ZeroTransferError = class extends Error {
|
|
133
198
|
/** Stable machine-readable error code. */
|
|
@@ -169,6 +234,11 @@ var ZeroTransferError = class extends Error {
|
|
|
169
234
|
/**
|
|
170
235
|
* Serializes the error into a plain object suitable for logs or API responses.
|
|
171
236
|
*
|
|
237
|
+
* `details` and `command` are passed through secret redaction so serialized
|
|
238
|
+
* errors never leak credentials, signed URLs, or raw protocol commands. The
|
|
239
|
+
* live {@link ZeroTransferError.details | details} property stays unredacted
|
|
240
|
+
* for programmatic consumers.
|
|
241
|
+
*
|
|
172
242
|
* @returns A JSON-safe object containing public structured error fields.
|
|
173
243
|
*/
|
|
174
244
|
toJSON() {
|
|
@@ -178,12 +248,12 @@ var ZeroTransferError = class extends Error {
|
|
|
178
248
|
message: this.message,
|
|
179
249
|
protocol: this.protocol,
|
|
180
250
|
host: this.host,
|
|
181
|
-
command: this.command,
|
|
251
|
+
command: this.command === void 0 ? void 0 : redactCommand(this.command),
|
|
182
252
|
ftpCode: this.ftpCode,
|
|
183
253
|
sftpCode: this.sftpCode,
|
|
184
254
|
path: this.path,
|
|
185
255
|
retryable: this.retryable,
|
|
186
|
-
details: this.details
|
|
256
|
+
details: this.details === void 0 ? void 0 : redactObject(this.details)
|
|
187
257
|
};
|
|
188
258
|
}
|
|
189
259
|
};
|
|
@@ -706,15 +776,20 @@ var ProviderRegistry = class {
|
|
|
706
776
|
var TransferClient = class {
|
|
707
777
|
/** Provider registry used by this client. */
|
|
708
778
|
registry;
|
|
779
|
+
/** Execution defaults applied when call sites omit their own values. */
|
|
780
|
+
defaults;
|
|
709
781
|
logger;
|
|
710
782
|
/**
|
|
711
783
|
* Creates a transfer client without opening any provider connections.
|
|
712
784
|
*
|
|
713
|
-
* @param options - Optional registry, provider factories, and
|
|
785
|
+
* @param options - Optional registry, provider factories, logger, and execution defaults.
|
|
714
786
|
*/
|
|
715
787
|
constructor(options = {}) {
|
|
716
788
|
this.registry = options.registry ?? new ProviderRegistry();
|
|
717
789
|
this.logger = options.logger ?? noopLogger;
|
|
790
|
+
if (options.defaults !== void 0) {
|
|
791
|
+
this.defaults = { ...options.defaults };
|
|
792
|
+
}
|
|
718
793
|
for (const provider of options.providers ?? []) {
|
|
719
794
|
this.registry.register(provider);
|
|
720
795
|
}
|
|
@@ -1287,18 +1362,25 @@ var TransferEngine = class {
|
|
|
1287
1362
|
for (let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber += 1) {
|
|
1288
1363
|
this.throwIfAborted(abortScope.signal, job);
|
|
1289
1364
|
const attemptStartedAt = this.now();
|
|
1365
|
+
const attemptScope = createAttemptScope(
|
|
1366
|
+
abortScope.signal,
|
|
1367
|
+
options.timeout,
|
|
1368
|
+
job,
|
|
1369
|
+
attemptNumber
|
|
1370
|
+
);
|
|
1290
1371
|
const context = this.createExecutionContext(
|
|
1291
1372
|
job,
|
|
1292
1373
|
attemptNumber,
|
|
1293
1374
|
attemptStartedAt,
|
|
1294
1375
|
options,
|
|
1295
|
-
|
|
1376
|
+
attemptScope.signal,
|
|
1296
1377
|
(bytesTransferred) => {
|
|
1297
1378
|
latestBytesTransferred = bytesTransferred;
|
|
1298
|
-
}
|
|
1379
|
+
},
|
|
1380
|
+
attemptScope.notifyProgress
|
|
1299
1381
|
);
|
|
1300
1382
|
try {
|
|
1301
|
-
const result = await runExecutor(executor, context,
|
|
1383
|
+
const result = await runExecutor(executor, context, attemptScope.signal, job);
|
|
1302
1384
|
context.throwIfAborted();
|
|
1303
1385
|
latestBytesTransferred = result.bytesTransferred;
|
|
1304
1386
|
const completedAt = this.now();
|
|
@@ -1316,16 +1398,27 @@ var TransferEngine = class {
|
|
|
1316
1398
|
summarizeError(error)
|
|
1317
1399
|
);
|
|
1318
1400
|
attempts.push(attempt);
|
|
1319
|
-
if (error instanceof AbortError ||
|
|
1401
|
+
if (error instanceof AbortError || abortScope.signal?.aborted === true) {
|
|
1320
1402
|
throw error;
|
|
1321
1403
|
}
|
|
1322
|
-
const retryInput = {
|
|
1404
|
+
const retryInput = {
|
|
1405
|
+
attempt: attemptNumber,
|
|
1406
|
+
elapsedMs: Math.max(0, completedAt.getTime() - startedAt.getTime()),
|
|
1407
|
+
error,
|
|
1408
|
+
job
|
|
1409
|
+
};
|
|
1323
1410
|
const shouldRetry = attemptNumber < maxAttempts && (options.retry?.shouldRetry?.(retryInput) ?? isRetryable(error));
|
|
1324
1411
|
if (shouldRetry) {
|
|
1325
1412
|
options.retry?.onRetry?.(retryInput);
|
|
1413
|
+
const delayMs = normalizeDelayMs(options.retry?.getDelayMs?.(retryInput));
|
|
1414
|
+
if (delayMs > 0) {
|
|
1415
|
+
await sleepWithAbort(delayMs, abortScope.signal, job);
|
|
1416
|
+
}
|
|
1326
1417
|
continue;
|
|
1327
1418
|
}
|
|
1328
1419
|
throw createTransferFailure(job, error, attempts);
|
|
1420
|
+
} finally {
|
|
1421
|
+
attemptScope.dispose();
|
|
1329
1422
|
}
|
|
1330
1423
|
}
|
|
1331
1424
|
throw createTransferFailure(job, void 0, attempts);
|
|
@@ -1333,12 +1426,13 @@ var TransferEngine = class {
|
|
|
1333
1426
|
abortScope.dispose();
|
|
1334
1427
|
}
|
|
1335
1428
|
}
|
|
1336
|
-
createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred) {
|
|
1429
|
+
createExecutionContext(job, attempt, startedAt, options, signal, updateBytesTransferred, notifyProgress) {
|
|
1337
1430
|
const context = {
|
|
1338
1431
|
attempt,
|
|
1339
1432
|
job,
|
|
1340
1433
|
reportProgress: (bytesTransferred, totalBytes) => {
|
|
1341
1434
|
this.throwIfAborted(signal, job);
|
|
1435
|
+
notifyProgress();
|
|
1342
1436
|
updateBytesTransferred(bytesTransferred);
|
|
1343
1437
|
const progressInput = {
|
|
1344
1438
|
bytesTransferred,
|
|
@@ -1407,6 +1501,96 @@ function createAbortScope(parentSignal, timeout, job) {
|
|
|
1407
1501
|
signal: controller.signal
|
|
1408
1502
|
};
|
|
1409
1503
|
}
|
|
1504
|
+
function createAttemptScope(parentSignal, timeout, job, attempt) {
|
|
1505
|
+
const attemptTimeoutMs = normalizeTimeoutMs(timeout?.attemptTimeoutMs);
|
|
1506
|
+
const stallTimeoutMs = normalizeTimeoutMs(timeout?.stallTimeoutMs);
|
|
1507
|
+
if (attemptTimeoutMs === void 0 && stallTimeoutMs === void 0) {
|
|
1508
|
+
const scope = {
|
|
1509
|
+
dispose: () => void 0,
|
|
1510
|
+
notifyProgress: () => void 0
|
|
1511
|
+
};
|
|
1512
|
+
if (parentSignal !== void 0) scope.signal = parentSignal;
|
|
1513
|
+
return scope;
|
|
1514
|
+
}
|
|
1515
|
+
const controller = new AbortController();
|
|
1516
|
+
const retryable = timeout?.retryable ?? true;
|
|
1517
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
1518
|
+
if (parentSignal?.aborted === true) {
|
|
1519
|
+
abortFromParent();
|
|
1520
|
+
} else {
|
|
1521
|
+
parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
1522
|
+
}
|
|
1523
|
+
const attemptTimer = attemptTimeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
1524
|
+
controller.abort(
|
|
1525
|
+
new TimeoutError({
|
|
1526
|
+
details: { attempt, attemptTimeoutMs, jobId: job.id, operation: job.operation },
|
|
1527
|
+
message: `Transfer attempt ${String(attempt)} timed out after ${String(attemptTimeoutMs)}ms: ${job.id}`,
|
|
1528
|
+
retryable
|
|
1529
|
+
})
|
|
1530
|
+
);
|
|
1531
|
+
}, attemptTimeoutMs);
|
|
1532
|
+
let stallTimer;
|
|
1533
|
+
const armStallWatchdog = () => {
|
|
1534
|
+
if (stallTimeoutMs === void 0 || controller.signal.aborted) return;
|
|
1535
|
+
if (stallTimer !== void 0) clearTimeout(stallTimer);
|
|
1536
|
+
stallTimer = setTimeout(() => {
|
|
1537
|
+
controller.abort(
|
|
1538
|
+
new TimeoutError({
|
|
1539
|
+
details: { attempt, jobId: job.id, operation: job.operation, stallTimeoutMs },
|
|
1540
|
+
message: `Transfer attempt ${String(attempt)} stalled (no progress for ${String(stallTimeoutMs)}ms): ${job.id}`,
|
|
1541
|
+
retryable
|
|
1542
|
+
})
|
|
1543
|
+
);
|
|
1544
|
+
}, stallTimeoutMs);
|
|
1545
|
+
};
|
|
1546
|
+
armStallWatchdog();
|
|
1547
|
+
return {
|
|
1548
|
+
dispose: () => {
|
|
1549
|
+
if (attemptTimer !== void 0) clearTimeout(attemptTimer);
|
|
1550
|
+
if (stallTimer !== void 0) clearTimeout(stallTimer);
|
|
1551
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
1552
|
+
},
|
|
1553
|
+
notifyProgress: armStallWatchdog,
|
|
1554
|
+
signal: controller.signal
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
function sleepWithAbort(delayMs, signal, job) {
|
|
1558
|
+
return new Promise((resolve, reject) => {
|
|
1559
|
+
if (signal === void 0) {
|
|
1560
|
+
setTimeout(resolve, delayMs);
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
if (signal.aborted) {
|
|
1564
|
+
reject(toAbortFailure(signal, job));
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const rejectAbort = () => {
|
|
1568
|
+
clearTimeout(timer);
|
|
1569
|
+
reject(toAbortFailure(signal, job));
|
|
1570
|
+
};
|
|
1571
|
+
const timer = setTimeout(() => {
|
|
1572
|
+
signal.removeEventListener("abort", rejectAbort);
|
|
1573
|
+
resolve();
|
|
1574
|
+
}, delayMs);
|
|
1575
|
+
signal.addEventListener("abort", rejectAbort, { once: true });
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
function toAbortFailure(signal, job) {
|
|
1579
|
+
if (signal.reason instanceof ZeroTransferError) {
|
|
1580
|
+
return signal.reason;
|
|
1581
|
+
}
|
|
1582
|
+
return new AbortError({
|
|
1583
|
+
details: { jobId: job.id, operation: job.operation },
|
|
1584
|
+
message: `Transfer job aborted: ${job.id}`,
|
|
1585
|
+
retryable: false
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
function normalizeDelayMs(value) {
|
|
1589
|
+
if (value === void 0 || !Number.isFinite(value) || value <= 0) {
|
|
1590
|
+
return 0;
|
|
1591
|
+
}
|
|
1592
|
+
return Math.floor(value);
|
|
1593
|
+
}
|
|
1410
1594
|
function normalizeTimeoutMs(value) {
|
|
1411
1595
|
if (value === void 0 || !Number.isFinite(value) || value <= 0) {
|
|
1412
1596
|
return void 0;
|
|
@@ -1575,7 +1759,7 @@ async function runRoute(options) {
|
|
|
1575
1759
|
const executor = createProviderTransferExecutor({
|
|
1576
1760
|
resolveSession: ({ role }) => sessions.get(role)
|
|
1577
1761
|
});
|
|
1578
|
-
return await engine.execute(job, executor, buildExecuteOptions(options));
|
|
1762
|
+
return await engine.execute(job, executor, buildExecuteOptions(options, client));
|
|
1579
1763
|
} finally {
|
|
1580
1764
|
if (destinationSession !== void 0) {
|
|
1581
1765
|
await destinationSession.disconnect();
|
|
@@ -1612,12 +1796,14 @@ function defaultJobId(route, now) {
|
|
|
1612
1796
|
const timestamp = (now?.() ?? /* @__PURE__ */ new Date()).getTime();
|
|
1613
1797
|
return `route:${route.id}:${timestamp.toString(36)}`;
|
|
1614
1798
|
}
|
|
1615
|
-
function buildExecuteOptions(options) {
|
|
1799
|
+
function buildExecuteOptions(options, client) {
|
|
1616
1800
|
const execute = {};
|
|
1801
|
+
const retry = options.retry ?? client.defaults?.retry;
|
|
1802
|
+
const timeout = options.timeout ?? client.defaults?.timeout;
|
|
1617
1803
|
if (options.signal !== void 0) execute.signal = options.signal;
|
|
1618
|
-
if (
|
|
1804
|
+
if (retry !== void 0) execute.retry = retry;
|
|
1619
1805
|
if (options.onProgress !== void 0) execute.onProgress = options.onProgress;
|
|
1620
|
-
if (
|
|
1806
|
+
if (timeout !== void 0) execute.timeout = timeout;
|
|
1621
1807
|
if (options.bandwidthLimit !== void 0) execute.bandwidthLimit = options.bandwidthLimit;
|
|
1622
1808
|
return execute;
|
|
1623
1809
|
}
|
|
@@ -1674,41 +1860,6 @@ function defaultRouteSuffix(source, destination) {
|
|
|
1674
1860
|
return `${source}->${destination}`;
|
|
1675
1861
|
}
|
|
1676
1862
|
|
|
1677
|
-
// src/logging/redaction.ts
|
|
1678
|
-
var REDACTED = "[REDACTED]";
|
|
1679
|
-
var SENSITIVE_KEY_PATTERN = /(?:password|passphrase|privatekey|token|secret|username|user)$/i;
|
|
1680
|
-
var SECRET_COMMAND_PATTERN = /^(PASS|USER|ACCT)\s+(.+)$/i;
|
|
1681
|
-
function isSensitiveKey(key) {
|
|
1682
|
-
return SENSITIVE_KEY_PATTERN.test(key.replace(/[_-]/g, ""));
|
|
1683
|
-
}
|
|
1684
|
-
function redactCommand(command) {
|
|
1685
|
-
return command.replace(SECRET_COMMAND_PATTERN, (_fullMatch, commandName) => {
|
|
1686
|
-
return `${commandName.toUpperCase()} ${REDACTED}`;
|
|
1687
|
-
});
|
|
1688
|
-
}
|
|
1689
|
-
function redactValue(value) {
|
|
1690
|
-
if (typeof value === "string") {
|
|
1691
|
-
return redactCommand(value);
|
|
1692
|
-
}
|
|
1693
|
-
if (Array.isArray(value)) {
|
|
1694
|
-
return value.map((item) => redactValue(item));
|
|
1695
|
-
}
|
|
1696
|
-
if (value !== null && typeof value === "object") {
|
|
1697
|
-
return redactObject(value);
|
|
1698
|
-
}
|
|
1699
|
-
return value;
|
|
1700
|
-
}
|
|
1701
|
-
function redactObject(input) {
|
|
1702
|
-
return Object.fromEntries(
|
|
1703
|
-
Object.entries(input).map(([key, value]) => {
|
|
1704
|
-
if (isSensitiveKey(key)) {
|
|
1705
|
-
return [key, REDACTED];
|
|
1706
|
-
}
|
|
1707
|
-
return [key, redactValue(value)];
|
|
1708
|
-
})
|
|
1709
|
-
);
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
1863
|
// src/profiles/SecretSource.ts
|
|
1713
1864
|
var import_node_buffer2 = require("buffer");
|
|
1714
1865
|
var import_promises = require("fs/promises");
|
|
@@ -2080,11 +2231,11 @@ var import_promises2 = require("fs/promises");
|
|
|
2080
2231
|
var import_node_path2 = __toESM(require("path"));
|
|
2081
2232
|
|
|
2082
2233
|
// src/utils/path.ts
|
|
2083
|
-
var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n]/;
|
|
2234
|
+
var UNSAFE_FTP_ARGUMENT_PATTERN = /[\r\n\0]/;
|
|
2084
2235
|
function assertSafeFtpArgument(value, label = "path") {
|
|
2085
2236
|
if (UNSAFE_FTP_ARGUMENT_PATTERN.test(value)) {
|
|
2086
2237
|
throw new ConfigurationError({
|
|
2087
|
-
message: `Unsafe FTP ${label}: CR and
|
|
2238
|
+
message: `Unsafe FTP ${label}: CR, LF, and NUL characters are not allowed`,
|
|
2088
2239
|
retryable: false,
|
|
2089
2240
|
details: {
|
|
2090
2241
|
label
|
|
@@ -3386,7 +3537,6 @@ function expandAlgorithms(values) {
|
|
|
3386
3537
|
}
|
|
3387
3538
|
|
|
3388
3539
|
// src/profiles/importers/FileZillaImporter.ts
|
|
3389
|
-
var import_node_buffer5 = require("buffer");
|
|
3390
3540
|
function importFileZillaSites(xml) {
|
|
3391
3541
|
const events = tokenizeXml(xml);
|
|
3392
3542
|
if (events.length === 0) {
|
|
@@ -3402,7 +3552,6 @@ function importFileZillaSites(xml) {
|
|
|
3402
3552
|
const folderNamePending = [];
|
|
3403
3553
|
let inServer = false;
|
|
3404
3554
|
let serverFields = {};
|
|
3405
|
-
let serverPasswordEncoding;
|
|
3406
3555
|
let activeTag;
|
|
3407
3556
|
let captureFolderName = false;
|
|
3408
3557
|
for (const event of events) {
|
|
@@ -3415,13 +3564,9 @@ function importFileZillaSites(xml) {
|
|
|
3415
3564
|
if (event.name === "Server") {
|
|
3416
3565
|
inServer = true;
|
|
3417
3566
|
serverFields = {};
|
|
3418
|
-
serverPasswordEncoding = void 0;
|
|
3419
3567
|
continue;
|
|
3420
3568
|
}
|
|
3421
3569
|
activeTag = event.name;
|
|
3422
|
-
if (event.name === "Pass" && inServer) {
|
|
3423
|
-
serverPasswordEncoding = event.attributes["encoding"];
|
|
3424
|
-
}
|
|
3425
3570
|
if (event.name === "Name" && !inServer && folderNamePending.length > 0) {
|
|
3426
3571
|
captureFolderName = true;
|
|
3427
3572
|
}
|
|
@@ -3447,7 +3592,7 @@ function importFileZillaSites(xml) {
|
|
|
3447
3592
|
}
|
|
3448
3593
|
if (event.name === "Server") {
|
|
3449
3594
|
const folder = folderStack.filter((segment) => segment !== "");
|
|
3450
|
-
const result = buildSiteFromFields(serverFields
|
|
3595
|
+
const result = buildSiteFromFields(serverFields);
|
|
3451
3596
|
if (result.kind === "site") {
|
|
3452
3597
|
sites.push({ ...result.site, folder });
|
|
3453
3598
|
} else {
|
|
@@ -3459,7 +3604,6 @@ function importFileZillaSites(xml) {
|
|
|
3459
3604
|
}
|
|
3460
3605
|
inServer = false;
|
|
3461
3606
|
serverFields = {};
|
|
3462
|
-
serverPasswordEncoding = void 0;
|
|
3463
3607
|
activeTag = void 0;
|
|
3464
3608
|
continue;
|
|
3465
3609
|
}
|
|
@@ -3468,7 +3612,7 @@ function importFileZillaSites(xml) {
|
|
|
3468
3612
|
}
|
|
3469
3613
|
return { sites, skipped };
|
|
3470
3614
|
}
|
|
3471
|
-
function buildSiteFromFields(fields
|
|
3615
|
+
function buildSiteFromFields(fields) {
|
|
3472
3616
|
const name = (fields["Name"] ?? fields["Host"] ?? "Untitled").trim();
|
|
3473
3617
|
const host = (fields["Host"] ?? "").trim();
|
|
3474
3618
|
if (host === "") return { kind: "skipped", name };
|
|
@@ -3487,18 +3631,9 @@ function buildSiteFromFields(fields, passwordEncoding) {
|
|
|
3487
3631
|
}
|
|
3488
3632
|
const user = fields["User"]?.trim();
|
|
3489
3633
|
if (user !== void 0 && user !== "") profile.username = { value: user };
|
|
3490
|
-
let password;
|
|
3491
3634
|
const rawPass = fields["Pass"];
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
password = import_node_buffer5.Buffer.from(rawPass, "base64").toString("utf8");
|
|
3495
|
-
} else {
|
|
3496
|
-
password = rawPass;
|
|
3497
|
-
}
|
|
3498
|
-
if (password !== void 0 && password !== "") profile.password = { value: password };
|
|
3499
|
-
}
|
|
3500
|
-
const site = { name, profile };
|
|
3501
|
-
if (password !== void 0) site.password = password;
|
|
3635
|
+
const hasStoredPassword = rawPass !== void 0 && rawPass !== "";
|
|
3636
|
+
const site = { hasStoredPassword, name, profile };
|
|
3502
3637
|
const logonText = fields["Logontype"];
|
|
3503
3638
|
if (logonText !== void 0) {
|
|
3504
3639
|
const logonType = Number.parseInt(logonText.trim(), 10);
|
|
@@ -3741,6 +3876,62 @@ function mapFtp550(details) {
|
|
|
3741
3876
|
return new PermissionDeniedError(details);
|
|
3742
3877
|
}
|
|
3743
3878
|
|
|
3879
|
+
// src/transfers/createDefaultRetryPolicy.ts
|
|
3880
|
+
var DEFAULT_MAX_ATTEMPTS = 4;
|
|
3881
|
+
var DEFAULT_BASE_DELAY_MS = 250;
|
|
3882
|
+
var DEFAULT_MAX_DELAY_MS = 3e4;
|
|
3883
|
+
var DEFAULT_MAX_ELAPSED_MS = 3e5;
|
|
3884
|
+
function createDefaultRetryPolicy(options = {}) {
|
|
3885
|
+
const maxAttempts = normalizePositiveInteger(options.maxAttempts, DEFAULT_MAX_ATTEMPTS);
|
|
3886
|
+
const baseDelayMs = normalizeNonNegative(options.baseDelayMs, DEFAULT_BASE_DELAY_MS);
|
|
3887
|
+
const maxDelayMs = normalizeNonNegative(options.maxDelayMs, DEFAULT_MAX_DELAY_MS);
|
|
3888
|
+
const maxElapsedMs = normalizeNonNegative(options.maxElapsedMs, DEFAULT_MAX_ELAPSED_MS);
|
|
3889
|
+
const random = options.random ?? Math.random;
|
|
3890
|
+
return {
|
|
3891
|
+
getDelayMs(input) {
|
|
3892
|
+
const retryAfterMs = readRetryAfterMs(input.error);
|
|
3893
|
+
if (retryAfterMs !== void 0) {
|
|
3894
|
+
return retryAfterMs;
|
|
3895
|
+
}
|
|
3896
|
+
const exponentialMs = baseDelayMs * 2 ** (input.attempt - 1);
|
|
3897
|
+
const cappedMs = Math.min(maxDelayMs, exponentialMs);
|
|
3898
|
+
return Math.floor(random() * cappedMs);
|
|
3899
|
+
},
|
|
3900
|
+
maxAttempts,
|
|
3901
|
+
shouldRetry(input) {
|
|
3902
|
+
if (!(input.error instanceof ZeroTransferError) || !input.error.retryable) {
|
|
3903
|
+
return false;
|
|
3904
|
+
}
|
|
3905
|
+
if (input.elapsedMs >= maxElapsedMs) {
|
|
3906
|
+
return false;
|
|
3907
|
+
}
|
|
3908
|
+
const retryAfterMs = readRetryAfterMs(input.error);
|
|
3909
|
+
if (retryAfterMs !== void 0 && input.elapsedMs + retryAfterMs > maxElapsedMs) {
|
|
3910
|
+
return false;
|
|
3911
|
+
}
|
|
3912
|
+
return true;
|
|
3913
|
+
}
|
|
3914
|
+
};
|
|
3915
|
+
}
|
|
3916
|
+
function readRetryAfterMs(error) {
|
|
3917
|
+
if (!(error instanceof ZeroTransferError)) return void 0;
|
|
3918
|
+
const value = error.details?.["retryAfterMs"];
|
|
3919
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return void 0;
|
|
3920
|
+
return Math.floor(value);
|
|
3921
|
+
}
|
|
3922
|
+
function normalizePositiveInteger(value, fallback) {
|
|
3923
|
+
if (value === void 0 || !Number.isFinite(value) || value < 1) {
|
|
3924
|
+
return fallback;
|
|
3925
|
+
}
|
|
3926
|
+
return Math.floor(value);
|
|
3927
|
+
}
|
|
3928
|
+
function normalizeNonNegative(value, fallback) {
|
|
3929
|
+
if (value === void 0 || !Number.isFinite(value) || value < 0) {
|
|
3930
|
+
return fallback;
|
|
3931
|
+
}
|
|
3932
|
+
return Math.floor(value);
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3744
3935
|
// src/transfers/TransferPlan.ts
|
|
3745
3936
|
function createTransferPlan(input) {
|
|
3746
3937
|
const plan = {
|
|
@@ -3838,8 +4029,8 @@ var TransferQueue = class {
|
|
|
3838
4029
|
this.concurrency = normalizeConcurrency(options.concurrency);
|
|
3839
4030
|
this.defaultExecutor = options.executor;
|
|
3840
4031
|
this.resolveExecutor = options.resolveExecutor;
|
|
3841
|
-
this.retry = options.retry;
|
|
3842
|
-
this.timeout = options.timeout;
|
|
4032
|
+
this.retry = options.retry ?? options.client?.defaults?.retry;
|
|
4033
|
+
this.timeout = options.timeout ?? options.client?.defaults?.timeout;
|
|
3843
4034
|
this.bandwidthLimit = options.bandwidthLimit;
|
|
3844
4035
|
this.onProgress = options.onProgress;
|
|
3845
4036
|
this.onReceipt = options.onReceipt;
|
|
@@ -4916,7 +5107,7 @@ function isMainModule(importMetaUrl) {
|
|
|
4916
5107
|
}
|
|
4917
5108
|
|
|
4918
5109
|
// src/providers/classic/ftp/FtpProvider.ts
|
|
4919
|
-
var
|
|
5110
|
+
var import_node_buffer5 = require("buffer");
|
|
4920
5111
|
var import_node_net = require("net");
|
|
4921
5112
|
var import_node_tls = require("tls");
|
|
4922
5113
|
|
|
@@ -5834,38 +6025,53 @@ async function expectCompletion(control, command, path2) {
|
|
|
5834
6025
|
const response = await control.sendCommand(command);
|
|
5835
6026
|
assertPathCommandSucceeded(response, command, path2, control.providerId);
|
|
5836
6027
|
}
|
|
5837
|
-
async function
|
|
5838
|
-
const dataConnection = await openPassiveDataCommand(control, command, path2
|
|
6028
|
+
async function readPassiveLinesCommand(control, command, path2, onLine) {
|
|
6029
|
+
const dataConnection = await openPassiveDataCommand(control, command, path2);
|
|
5839
6030
|
try {
|
|
5840
|
-
const
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
path2,
|
|
5844
|
-
control.providerId
|
|
5845
|
-
);
|
|
6031
|
+
const failure = await consumePassiveLines(dataConnection, control.operationTimeoutMs, {
|
|
6032
|
+
command,
|
|
6033
|
+
onLine,
|
|
6034
|
+
path: path2,
|
|
6035
|
+
providerId: control.providerId
|
|
6036
|
+
});
|
|
5846
6037
|
const finalResponse = await control.readFinalResponse({
|
|
5847
6038
|
command,
|
|
5848
6039
|
operation: "data command completion",
|
|
5849
6040
|
path: path2
|
|
5850
6041
|
});
|
|
5851
6042
|
assertPathCommandSucceeded(finalResponse, command, path2, control.providerId);
|
|
5852
|
-
|
|
6043
|
+
if (failure !== void 0) throw failure;
|
|
5853
6044
|
} catch (error) {
|
|
5854
6045
|
dataConnection.close();
|
|
5855
6046
|
throw error;
|
|
5856
6047
|
}
|
|
5857
6048
|
}
|
|
5858
6049
|
async function readDirectoryEntries(control, path2) {
|
|
6050
|
+
const entries = [];
|
|
6051
|
+
const collectEntry = (entry) => {
|
|
6052
|
+
if (entry.name === "." || entry.name === "..") return;
|
|
6053
|
+
entries.push(entry);
|
|
6054
|
+
};
|
|
5859
6055
|
try {
|
|
5860
|
-
|
|
5861
|
-
|
|
6056
|
+
await readPassiveLinesCommand(control, `MLSD ${path2}`, path2, (rawLine) => {
|
|
6057
|
+
const line = rawLine.trimEnd();
|
|
6058
|
+
if (line.length === 0) return;
|
|
6059
|
+
collectEntry(parseMlsdLine(line, path2));
|
|
6060
|
+
});
|
|
6061
|
+
return entries;
|
|
5862
6062
|
} catch (error) {
|
|
5863
6063
|
if (!isUnsupportedFtpCommandError(error, "MLSD")) {
|
|
5864
6064
|
throw error;
|
|
5865
6065
|
}
|
|
5866
6066
|
}
|
|
5867
|
-
|
|
5868
|
-
|
|
6067
|
+
entries.length = 0;
|
|
6068
|
+
const now = /* @__PURE__ */ new Date();
|
|
6069
|
+
await readPassiveLinesCommand(control, `LIST ${path2}`, path2, (rawLine) => {
|
|
6070
|
+
const line = rawLine.trimEnd();
|
|
6071
|
+
if (line.length === 0 || line.toLowerCase().startsWith("total ")) return;
|
|
6072
|
+
collectEntry(parseUnixListLine(line, path2, now));
|
|
6073
|
+
});
|
|
6074
|
+
return entries;
|
|
5869
6075
|
}
|
|
5870
6076
|
async function openPassiveDataCommand(control, command, path2, options = {}) {
|
|
5871
6077
|
const offset = normalizeOptionalByteCount3(options.offset, "offset", path2);
|
|
@@ -6038,22 +6244,58 @@ function openPassiveDataConnection(endpoint, timeoutMs, path2, control) {
|
|
|
6038
6244
|
}
|
|
6039
6245
|
};
|
|
6040
6246
|
}
|
|
6041
|
-
|
|
6042
|
-
|
|
6247
|
+
var MAX_LIST_LINE_BYTES = 64 * 1024;
|
|
6248
|
+
async function consumePassiveLines(dataConnection, timeoutMs, input) {
|
|
6249
|
+
let carry = import_node_buffer5.Buffer.alloc(0);
|
|
6250
|
+
let failure;
|
|
6043
6251
|
const clearIdleTimeout = setSocketTimeout(dataConnection.socket, timeoutMs, {
|
|
6044
6252
|
host: dataConnection.endpoint.host,
|
|
6045
6253
|
operation: "passive data transfer",
|
|
6046
|
-
path:
|
|
6047
|
-
providerId
|
|
6254
|
+
path: input.path,
|
|
6255
|
+
providerId: input.providerId
|
|
6256
|
+
});
|
|
6257
|
+
const overlongLineFailure = () => new ParseError({
|
|
6258
|
+
details: { command: input.command, limitBytes: MAX_LIST_LINE_BYTES, path: input.path },
|
|
6259
|
+
message: `FTP listing line exceeded ${String(MAX_LIST_LINE_BYTES)} bytes for ${input.command}`,
|
|
6260
|
+
retryable: false
|
|
6048
6261
|
});
|
|
6262
|
+
const emit = (lineBytes) => {
|
|
6263
|
+
if (failure !== void 0) return;
|
|
6264
|
+
let end = lineBytes.length;
|
|
6265
|
+
if (end > 0 && lineBytes[end - 1] === 13) end -= 1;
|
|
6266
|
+
if (end === 0) return;
|
|
6267
|
+
if (end > MAX_LIST_LINE_BYTES) {
|
|
6268
|
+
failure = overlongLineFailure();
|
|
6269
|
+
return;
|
|
6270
|
+
}
|
|
6271
|
+
try {
|
|
6272
|
+
input.onLine(lineBytes.toString("utf8", 0, end));
|
|
6273
|
+
} catch (error) {
|
|
6274
|
+
failure = error instanceof Error ? error : new Error(String(error));
|
|
6275
|
+
}
|
|
6276
|
+
};
|
|
6049
6277
|
try {
|
|
6050
6278
|
for await (const chunk of dataConnection.socket) {
|
|
6051
|
-
|
|
6052
|
-
|
|
6279
|
+
if (failure !== void 0) continue;
|
|
6280
|
+
const data = carry.length > 0 ? import_node_buffer5.Buffer.concat([carry, chunk]) : chunk;
|
|
6281
|
+
let start = 0;
|
|
6282
|
+
let newline = data.indexOf(10, start);
|
|
6283
|
+
while (newline !== -1) {
|
|
6284
|
+
emit(data.subarray(start, newline));
|
|
6285
|
+
start = newline + 1;
|
|
6286
|
+
newline = data.indexOf(10, start);
|
|
6287
|
+
}
|
|
6288
|
+
carry = import_node_buffer5.Buffer.from(data.subarray(start));
|
|
6289
|
+
if (carry.length > MAX_LIST_LINE_BYTES && failure === void 0) {
|
|
6290
|
+
failure = overlongLineFailure();
|
|
6291
|
+
}
|
|
6292
|
+
if (failure !== void 0) carry = import_node_buffer5.Buffer.alloc(0);
|
|
6293
|
+
}
|
|
6294
|
+
if (carry.length > 0) emit(carry);
|
|
6053
6295
|
} finally {
|
|
6054
6296
|
clearIdleTimeout();
|
|
6055
6297
|
}
|
|
6056
|
-
return
|
|
6298
|
+
return failure;
|
|
6057
6299
|
}
|
|
6058
6300
|
async function* createPassiveReadSource(control, dataConnection, command, path2, range, request) {
|
|
6059
6301
|
let bytesEmitted = 0;
|
|
@@ -6070,7 +6312,7 @@ async function* createPassiveReadSource(control, dataConnection, command, path2,
|
|
|
6070
6312
|
});
|
|
6071
6313
|
for await (const chunk of dataConnection.socket) {
|
|
6072
6314
|
request.throwIfAborted();
|
|
6073
|
-
const buffer =
|
|
6315
|
+
const buffer = import_node_buffer5.Buffer.from(chunk);
|
|
6074
6316
|
if (range.length === void 0) {
|
|
6075
6317
|
bytesEmitted += buffer.byteLength;
|
|
6076
6318
|
yield new Uint8Array(buffer);
|
|
@@ -6302,6 +6544,13 @@ function createTlsPinnedFingerprints(profile) {
|
|
|
6302
6544
|
if (pinnedFingerprint256 === void 0) {
|
|
6303
6545
|
return void 0;
|
|
6304
6546
|
}
|
|
6547
|
+
if (profile.tls?.rejectUnauthorized === false) {
|
|
6548
|
+
throw new ConfigurationError({
|
|
6549
|
+
message: "FTPS tls.pinnedFingerprint256 cannot be combined with rejectUnauthorized: false; pin verification runs after the TLS handshake, so chain validation must stay enabled. For self-signed certificates supply tls.ca instead of disabling validation.",
|
|
6550
|
+
protocol: FTPS_PROVIDER_ID,
|
|
6551
|
+
retryable: false
|
|
6552
|
+
});
|
|
6553
|
+
}
|
|
6305
6554
|
const fingerprints = Array.isArray(pinnedFingerprint256) ? pinnedFingerprint256 : [pinnedFingerprint256];
|
|
6306
6555
|
if (fingerprints.length === 0) {
|
|
6307
6556
|
throw new ConfigurationError({
|
|
@@ -6356,9 +6605,9 @@ function normalizeCertificateFingerprint256(certificate) {
|
|
|
6356
6605
|
}
|
|
6357
6606
|
function normalizeTlsSecretValue(value) {
|
|
6358
6607
|
if (Array.isArray(value)) {
|
|
6359
|
-
return value.map((item) =>
|
|
6608
|
+
return value.map((item) => import_node_buffer5.Buffer.isBuffer(item) ? import_node_buffer5.Buffer.from(item) : item);
|
|
6360
6609
|
}
|
|
6361
|
-
return
|
|
6610
|
+
return import_node_buffer5.Buffer.isBuffer(value) ? import_node_buffer5.Buffer.from(value) : value;
|
|
6362
6611
|
}
|
|
6363
6612
|
async function authenticateFtpSession(control, username, password, host) {
|
|
6364
6613
|
const safeUsername = assertSafeFtpArgument(username, "username");
|
|
@@ -6537,7 +6786,7 @@ function compareEntries5(left, right) {
|
|
|
6537
6786
|
return left.path.localeCompare(right.path);
|
|
6538
6787
|
}
|
|
6539
6788
|
function secretToString(value) {
|
|
6540
|
-
return
|
|
6789
|
+
return import_node_buffer5.Buffer.isBuffer(value) ? value.toString("utf8") : value;
|
|
6541
6790
|
}
|
|
6542
6791
|
|
|
6543
6792
|
// src/providers/classic/ftp/FtpFeatureParser.ts
|
|
@@ -6582,12 +6831,12 @@ function normalizeFeatureLines(input) {
|
|
|
6582
6831
|
}
|
|
6583
6832
|
|
|
6584
6833
|
// src/providers/native/sftp/NativeSftpProvider.ts
|
|
6585
|
-
var
|
|
6834
|
+
var import_node_buffer20 = require("buffer");
|
|
6586
6835
|
var import_node_crypto9 = require("crypto");
|
|
6587
6836
|
var import_node_net2 = require("net");
|
|
6588
6837
|
|
|
6589
6838
|
// src/protocols/ssh/binary/SshDataWriter.ts
|
|
6590
|
-
var
|
|
6839
|
+
var import_node_buffer6 = require("buffer");
|
|
6591
6840
|
var MAX_UINT32 = 4294967295;
|
|
6592
6841
|
var MAX_UINT64 = (1n << 64n) - 1n;
|
|
6593
6842
|
var SshDataWriter = class {
|
|
@@ -6595,7 +6844,7 @@ var SshDataWriter = class {
|
|
|
6595
6844
|
length = 0;
|
|
6596
6845
|
writeByte(value) {
|
|
6597
6846
|
this.assertByte(value, "byte");
|
|
6598
|
-
const chunk =
|
|
6847
|
+
const chunk = import_node_buffer6.Buffer.alloc(1);
|
|
6599
6848
|
chunk.writeUInt8(value, 0);
|
|
6600
6849
|
return this.push(chunk);
|
|
6601
6850
|
}
|
|
@@ -6603,7 +6852,7 @@ var SshDataWriter = class {
|
|
|
6603
6852
|
return this.writeByte(value ? 1 : 0);
|
|
6604
6853
|
}
|
|
6605
6854
|
writeBytes(value) {
|
|
6606
|
-
return this.push(
|
|
6855
|
+
return this.push(import_node_buffer6.Buffer.from(value));
|
|
6607
6856
|
}
|
|
6608
6857
|
writeUint32(value) {
|
|
6609
6858
|
if (!Number.isInteger(value) || value < 0 || value > MAX_UINT32) {
|
|
@@ -6613,7 +6862,7 @@ var SshDataWriter = class {
|
|
|
6613
6862
|
retryable: false
|
|
6614
6863
|
});
|
|
6615
6864
|
}
|
|
6616
|
-
const chunk =
|
|
6865
|
+
const chunk = import_node_buffer6.Buffer.alloc(4);
|
|
6617
6866
|
chunk.writeUInt32BE(value, 0);
|
|
6618
6867
|
return this.push(chunk);
|
|
6619
6868
|
}
|
|
@@ -6625,12 +6874,12 @@ var SshDataWriter = class {
|
|
|
6625
6874
|
retryable: false
|
|
6626
6875
|
});
|
|
6627
6876
|
}
|
|
6628
|
-
const chunk =
|
|
6877
|
+
const chunk = import_node_buffer6.Buffer.alloc(8);
|
|
6629
6878
|
chunk.writeBigUInt64BE(value, 0);
|
|
6630
6879
|
return this.push(chunk);
|
|
6631
6880
|
}
|
|
6632
6881
|
writeString(value, encoding = "utf8") {
|
|
6633
|
-
const payload = typeof value === "string" ?
|
|
6882
|
+
const payload = typeof value === "string" ? import_node_buffer6.Buffer.from(value, encoding) : import_node_buffer6.Buffer.from(value);
|
|
6634
6883
|
this.writeUint32(payload.length);
|
|
6635
6884
|
return this.push(payload);
|
|
6636
6885
|
}
|
|
@@ -6652,7 +6901,7 @@ var SshDataWriter = class {
|
|
|
6652
6901
|
return this.writeString(values.join(","), "ascii");
|
|
6653
6902
|
}
|
|
6654
6903
|
toBuffer() {
|
|
6655
|
-
return
|
|
6904
|
+
return import_node_buffer6.Buffer.concat(this.chunks, this.length);
|
|
6656
6905
|
}
|
|
6657
6906
|
push(chunk) {
|
|
6658
6907
|
this.chunks.push(chunk);
|
|
@@ -6670,23 +6919,23 @@ var SshDataWriter = class {
|
|
|
6670
6919
|
}
|
|
6671
6920
|
};
|
|
6672
6921
|
function normalizePositiveMpint(value) {
|
|
6673
|
-
const input =
|
|
6922
|
+
const input = import_node_buffer6.Buffer.from(value);
|
|
6674
6923
|
let offset = 0;
|
|
6675
6924
|
while (offset < input.length && input[offset] === 0) {
|
|
6676
6925
|
offset += 1;
|
|
6677
6926
|
}
|
|
6678
6927
|
if (offset >= input.length) {
|
|
6679
|
-
return
|
|
6928
|
+
return import_node_buffer6.Buffer.alloc(0);
|
|
6680
6929
|
}
|
|
6681
6930
|
const stripped = input.subarray(offset);
|
|
6682
6931
|
if ((stripped[0] & 128) === 128) {
|
|
6683
|
-
return
|
|
6932
|
+
return import_node_buffer6.Buffer.concat([import_node_buffer6.Buffer.from([0]), stripped]);
|
|
6684
6933
|
}
|
|
6685
6934
|
return stripped;
|
|
6686
6935
|
}
|
|
6687
6936
|
|
|
6688
6937
|
// src/protocols/ssh/binary/SshDataReader.ts
|
|
6689
|
-
var
|
|
6938
|
+
var import_node_buffer7 = require("buffer");
|
|
6690
6939
|
var SshDataReader = class {
|
|
6691
6940
|
constructor(source) {
|
|
6692
6941
|
this.source = source;
|
|
@@ -6712,18 +6961,18 @@ var SshDataReader = class {
|
|
|
6712
6961
|
this.ensureAvailable(length, "bytes");
|
|
6713
6962
|
const data = this.source.subarray(this.offset, this.offset + length);
|
|
6714
6963
|
this.offset += length;
|
|
6715
|
-
return
|
|
6964
|
+
return import_node_buffer7.Buffer.from(data);
|
|
6716
6965
|
}
|
|
6717
6966
|
readUint32() {
|
|
6718
6967
|
this.ensureAvailable(4, "uint32");
|
|
6719
|
-
const buffer =
|
|
6968
|
+
const buffer = import_node_buffer7.Buffer.from(this.source);
|
|
6720
6969
|
const value = buffer.readUInt32BE(this.offset);
|
|
6721
6970
|
this.offset += 4;
|
|
6722
6971
|
return value;
|
|
6723
6972
|
}
|
|
6724
6973
|
readUint64() {
|
|
6725
6974
|
this.ensureAvailable(8, "uint64");
|
|
6726
|
-
const buffer =
|
|
6975
|
+
const buffer = import_node_buffer7.Buffer.from(this.source);
|
|
6727
6976
|
const value = buffer.readBigUInt64BE(this.offset);
|
|
6728
6977
|
this.offset += 8;
|
|
6729
6978
|
return value;
|
|
@@ -6733,7 +6982,7 @@ var SshDataReader = class {
|
|
|
6733
6982
|
this.ensureAvailable(length, "string");
|
|
6734
6983
|
const data = this.source.subarray(this.offset, this.offset + length);
|
|
6735
6984
|
this.offset += length;
|
|
6736
|
-
return
|
|
6985
|
+
return import_node_buffer7.Buffer.from(data);
|
|
6737
6986
|
}
|
|
6738
6987
|
readUtf8String() {
|
|
6739
6988
|
return this.readString().toString("utf8");
|
|
@@ -7088,7 +7337,7 @@ function buildKiRequest(args) {
|
|
|
7088
7337
|
}
|
|
7089
7338
|
|
|
7090
7339
|
// src/protocols/ssh/auth/SshPublickeyCredentialBuilder.ts
|
|
7091
|
-
var
|
|
7340
|
+
var import_node_buffer8 = require("buffer");
|
|
7092
7341
|
var import_node_crypto2 = require("crypto");
|
|
7093
7342
|
var ED25519_RAW_KEY_LENGTH = 32;
|
|
7094
7343
|
var ED25519_SPKI_PREFIX_LENGTH = 12;
|
|
@@ -7106,7 +7355,7 @@ function buildPublickeyCredential(options) {
|
|
|
7106
7355
|
return {
|
|
7107
7356
|
algorithmName: "ssh-ed25519",
|
|
7108
7357
|
publicKeyBlob,
|
|
7109
|
-
sign: (data) => (0, import_node_crypto2.sign)(null,
|
|
7358
|
+
sign: (data) => (0, import_node_crypto2.sign)(null, import_node_buffer8.Buffer.from(data), privateKey),
|
|
7110
7359
|
type: "publickey",
|
|
7111
7360
|
username
|
|
7112
7361
|
};
|
|
@@ -7124,7 +7373,7 @@ function buildPublickeyCredential(options) {
|
|
|
7124
7373
|
return {
|
|
7125
7374
|
algorithmName,
|
|
7126
7375
|
publicKeyBlob,
|
|
7127
|
-
sign: (data) => (0, import_node_crypto2.sign)(hash,
|
|
7376
|
+
sign: (data) => (0, import_node_crypto2.sign)(hash, import_node_buffer8.Buffer.from(data), privateKey),
|
|
7128
7377
|
type: "publickey",
|
|
7129
7378
|
username
|
|
7130
7379
|
};
|
|
@@ -7137,7 +7386,7 @@ function buildPublickeyCredential(options) {
|
|
|
7137
7386
|
}
|
|
7138
7387
|
function base64UrlToMpint(value) {
|
|
7139
7388
|
const padded = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
7140
|
-
const buffer =
|
|
7389
|
+
const buffer = import_node_buffer8.Buffer.from(padded, "base64");
|
|
7141
7390
|
return buffer;
|
|
7142
7391
|
}
|
|
7143
7392
|
function createInvalidKeyError(message) {
|
|
@@ -7263,7 +7512,7 @@ function encodeSshChannelClose(recipientChannel) {
|
|
|
7263
7512
|
}
|
|
7264
7513
|
|
|
7265
7514
|
// src/protocols/ssh/connection/SshSessionChannel.ts
|
|
7266
|
-
var
|
|
7515
|
+
var import_node_buffer9 = require("buffer");
|
|
7267
7516
|
var INITIAL_WINDOW_SIZE = 256 * 1024;
|
|
7268
7517
|
var MAX_PACKET_SIZE = 32 * 1024;
|
|
7269
7518
|
var WINDOW_REFILL_THRESHOLD = 64 * 1024;
|
|
@@ -7421,7 +7670,7 @@ var SshSessionChannel = class {
|
|
|
7421
7670
|
this.remoteWindowRemaining,
|
|
7422
7671
|
this.remoteMaxPacketSize
|
|
7423
7672
|
);
|
|
7424
|
-
const chunk =
|
|
7673
|
+
const chunk = import_node_buffer9.Buffer.from(data.subarray(offset, offset + chunkSize));
|
|
7425
7674
|
this.transport.sendPayload(
|
|
7426
7675
|
encodeSshChannelData({ data: chunk, recipientChannel: this.remoteChannelId })
|
|
7427
7676
|
);
|
|
@@ -7683,10 +7932,10 @@ var SshConnectionManager = class {
|
|
|
7683
7932
|
};
|
|
7684
7933
|
|
|
7685
7934
|
// src/protocols/ssh/transport/SshTransportConnection.ts
|
|
7686
|
-
var
|
|
7935
|
+
var import_node_buffer17 = require("buffer");
|
|
7687
7936
|
|
|
7688
7937
|
// src/protocols/ssh/transport/SshTransportHandshake.ts
|
|
7689
|
-
var
|
|
7938
|
+
var import_node_buffer15 = require("buffer");
|
|
7690
7939
|
|
|
7691
7940
|
// src/protocols/ssh/transport/SshAlgorithmNegotiation.ts
|
|
7692
7941
|
var DEFAULT_SSH_ALGORITHM_PREFERENCES = {
|
|
@@ -7848,12 +8097,12 @@ function parseSshIdentificationLine(line) {
|
|
|
7848
8097
|
}
|
|
7849
8098
|
|
|
7850
8099
|
// src/protocols/ssh/transport/SshKexInit.ts
|
|
7851
|
-
var
|
|
8100
|
+
var import_node_buffer10 = require("buffer");
|
|
7852
8101
|
var import_node_crypto3 = require("crypto");
|
|
7853
8102
|
var SSH_MSG_KEXINIT = 20;
|
|
7854
8103
|
var KEXINIT_COOKIE_LENGTH = 16;
|
|
7855
8104
|
function encodeSshKexInitMessage(options) {
|
|
7856
|
-
const cookie = options.cookie === void 0 ? (0, import_node_crypto3.randomBytes)(KEXINIT_COOKIE_LENGTH) :
|
|
8105
|
+
const cookie = options.cookie === void 0 ? (0, import_node_crypto3.randomBytes)(KEXINIT_COOKIE_LENGTH) : import_node_buffer10.Buffer.from(options.cookie);
|
|
7857
8106
|
if (cookie.length !== KEXINIT_COOKIE_LENGTH) {
|
|
7858
8107
|
throw new ConfigurationError({
|
|
7859
8108
|
details: { actualLength: cookie.length, expectedLength: KEXINIT_COOKIE_LENGTH },
|
|
@@ -7923,12 +8172,12 @@ function decodeSshKexInitMessage(payload) {
|
|
|
7923
8172
|
}
|
|
7924
8173
|
|
|
7925
8174
|
// src/protocols/ssh/transport/SshKexCurve25519.ts
|
|
7926
|
-
var
|
|
8175
|
+
var import_node_buffer11 = require("buffer");
|
|
7927
8176
|
var import_node_crypto4 = require("crypto");
|
|
7928
8177
|
var SSH_MSG_KEX_ECDH_INIT = 30;
|
|
7929
8178
|
var SSH_MSG_KEX_ECDH_REPLY = 31;
|
|
7930
8179
|
var X25519_PUBLIC_KEY_LENGTH = 32;
|
|
7931
|
-
var X25519_SPKI_PREFIX =
|
|
8180
|
+
var X25519_SPKI_PREFIX = import_node_buffer11.Buffer.from("302a300506032b656e032100", "hex");
|
|
7932
8181
|
function createCurve25519Ephemeral() {
|
|
7933
8182
|
const { privateKey, publicKey } = (0, import_node_crypto4.generateKeyPairSync)("x25519");
|
|
7934
8183
|
const encodedPublicKey = exportX25519PublicKeyRaw(publicKey);
|
|
@@ -7973,7 +8222,7 @@ function exportX25519PublicKeyRaw(publicKey) {
|
|
|
7973
8222
|
}
|
|
7974
8223
|
function importX25519PublicKeyRaw(raw) {
|
|
7975
8224
|
const normalized = normalizeX25519PublicKey(raw, "server");
|
|
7976
|
-
const der =
|
|
8225
|
+
const der = import_node_buffer11.Buffer.concat([X25519_SPKI_PREFIX, normalized]);
|
|
7977
8226
|
return (0, import_node_crypto4.createPublicKey)({
|
|
7978
8227
|
format: "der",
|
|
7979
8228
|
key: der,
|
|
@@ -7981,7 +8230,7 @@ function importX25519PublicKeyRaw(raw) {
|
|
|
7981
8230
|
});
|
|
7982
8231
|
}
|
|
7983
8232
|
function normalizeX25519PublicKey(value, label) {
|
|
7984
|
-
const key =
|
|
8233
|
+
const key = import_node_buffer11.Buffer.from(value);
|
|
7985
8234
|
if (key.length !== X25519_PUBLIC_KEY_LENGTH) {
|
|
7986
8235
|
throw new ConfigurationError({
|
|
7987
8236
|
details: { keyLength: key.length, label },
|
|
@@ -7994,7 +8243,7 @@ function normalizeX25519PublicKey(value, label) {
|
|
|
7994
8243
|
}
|
|
7995
8244
|
|
|
7996
8245
|
// src/protocols/ssh/transport/SshKeyDerivation.ts
|
|
7997
|
-
var
|
|
8246
|
+
var import_node_buffer12 = require("buffer");
|
|
7998
8247
|
var import_node_crypto5 = require("crypto");
|
|
7999
8248
|
function deriveSshSessionKeys(input) {
|
|
8000
8249
|
const hashAlgorithm = resolveKexHashAlgorithm(input.kexAlgorithm);
|
|
@@ -8016,7 +8265,7 @@ function deriveSshSessionKeys(input) {
|
|
|
8016
8265
|
input.negotiatedAlgorithms.encryptionServerToClient,
|
|
8017
8266
|
input.negotiatedAlgorithms.macServerToClient
|
|
8018
8267
|
);
|
|
8019
|
-
const sharedSecret =
|
|
8268
|
+
const sharedSecret = import_node_buffer12.Buffer.from(input.sharedSecret);
|
|
8020
8269
|
return {
|
|
8021
8270
|
clientToServer: {
|
|
8022
8271
|
encryptionKey: deriveMaterial(
|
|
@@ -8066,21 +8315,21 @@ function computeCurve25519ExchangeHash(input, hashAlgorithm) {
|
|
|
8066
8315
|
}
|
|
8067
8316
|
function deriveMaterial(sharedSecret, exchangeHash, sessionId, letter, length, hashAlgorithm) {
|
|
8068
8317
|
if (length <= 0) {
|
|
8069
|
-
return
|
|
8318
|
+
return import_node_buffer12.Buffer.alloc(0);
|
|
8070
8319
|
}
|
|
8071
8320
|
const result = [];
|
|
8072
8321
|
const first2 = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
|
|
8073
8322
|
new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeByte(letter.charCodeAt(0)).writeBytes(sessionId).toBuffer()
|
|
8074
8323
|
).digest();
|
|
8075
8324
|
result.push(first2);
|
|
8076
|
-
while (
|
|
8077
|
-
const previous =
|
|
8325
|
+
while (import_node_buffer12.Buffer.concat(result).length < length) {
|
|
8326
|
+
const previous = import_node_buffer12.Buffer.concat(result);
|
|
8078
8327
|
const next = (0, import_node_crypto5.createHash)(hashAlgorithm).update(
|
|
8079
8328
|
new SshDataWriter().writeMpint(sharedSecret).writeBytes(exchangeHash).writeBytes(previous).toBuffer()
|
|
8080
8329
|
).digest();
|
|
8081
8330
|
result.push(next);
|
|
8082
8331
|
}
|
|
8083
|
-
return
|
|
8332
|
+
return import_node_buffer12.Buffer.concat(result).subarray(0, length);
|
|
8084
8333
|
}
|
|
8085
8334
|
function resolveKexHashAlgorithm(kexAlgorithm) {
|
|
8086
8335
|
if (kexAlgorithm === "curve25519-sha256" || kexAlgorithm === "curve25519-sha256@libssh.org") {
|
|
@@ -8168,20 +8417,21 @@ function decodeSshNewKeysMessage(payload) {
|
|
|
8168
8417
|
}
|
|
8169
8418
|
|
|
8170
8419
|
// src/protocols/ssh/transport/SshTransportPacket.ts
|
|
8171
|
-
var
|
|
8420
|
+
var import_node_buffer13 = require("buffer");
|
|
8172
8421
|
var import_node_crypto6 = require("crypto");
|
|
8173
8422
|
var MIN_PADDING_LENGTH = 4;
|
|
8174
8423
|
var MIN_PACKET_LENGTH = 1 + MIN_PADDING_LENGTH;
|
|
8424
|
+
var MAX_SSH_PACKET_LENGTH = 256 * 1024;
|
|
8175
8425
|
function encodeSshTransportPacket(payload, options = {}) {
|
|
8176
|
-
const body =
|
|
8426
|
+
const body = import_node_buffer13.Buffer.from(payload);
|
|
8177
8427
|
const blockSize = normalizeBlockSize(options.blockSize ?? 8);
|
|
8178
8428
|
let paddingLength = MIN_PADDING_LENGTH;
|
|
8179
8429
|
while ((1 + body.length + paddingLength + 4) % blockSize !== 0) {
|
|
8180
8430
|
paddingLength += 1;
|
|
8181
8431
|
}
|
|
8182
|
-
const padding = options.randomPadding === false ?
|
|
8432
|
+
const padding = options.randomPadding === false ? import_node_buffer13.Buffer.alloc(paddingLength) : (0, import_node_crypto6.randomBytes)(paddingLength);
|
|
8183
8433
|
const packetLength = 1 + body.length + paddingLength;
|
|
8184
|
-
const frame =
|
|
8434
|
+
const frame = import_node_buffer13.Buffer.alloc(4 + packetLength);
|
|
8185
8435
|
frame.writeUInt32BE(packetLength, 0);
|
|
8186
8436
|
frame.writeUInt8(paddingLength, 4);
|
|
8187
8437
|
body.copy(frame, 5);
|
|
@@ -8189,7 +8439,7 @@ function encodeSshTransportPacket(payload, options = {}) {
|
|
|
8189
8439
|
return frame;
|
|
8190
8440
|
}
|
|
8191
8441
|
function decodeSshTransportPacket(frame) {
|
|
8192
|
-
const bytes =
|
|
8442
|
+
const bytes = import_node_buffer13.Buffer.from(frame);
|
|
8193
8443
|
if (bytes.length < 4 + MIN_PACKET_LENGTH) {
|
|
8194
8444
|
throw new ParseError({
|
|
8195
8445
|
details: { length: bytes.length },
|
|
@@ -8243,12 +8493,20 @@ function decodeSshTransportPacket(frame) {
|
|
|
8243
8493
|
};
|
|
8244
8494
|
}
|
|
8245
8495
|
var SshTransportPacketFramer = class {
|
|
8246
|
-
pending =
|
|
8496
|
+
pending = import_node_buffer13.Buffer.alloc(0);
|
|
8247
8497
|
push(chunk) {
|
|
8248
|
-
this.pending =
|
|
8498
|
+
this.pending = import_node_buffer13.Buffer.concat([this.pending, import_node_buffer13.Buffer.from(chunk)]);
|
|
8249
8499
|
const packets = [];
|
|
8250
8500
|
while (this.pending.length >= 4) {
|
|
8251
8501
|
const packetLength = this.pending.readUInt32BE(0);
|
|
8502
|
+
if (packetLength > MAX_SSH_PACKET_LENGTH) {
|
|
8503
|
+
throw new ParseError({
|
|
8504
|
+
details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },
|
|
8505
|
+
message: "SSH transport packet length exceeds the maximum accepted size",
|
|
8506
|
+
protocol: "sftp",
|
|
8507
|
+
retryable: false
|
|
8508
|
+
});
|
|
8509
|
+
}
|
|
8252
8510
|
const frameLength = 4 + packetLength;
|
|
8253
8511
|
if (this.pending.length < frameLength) {
|
|
8254
8512
|
break;
|
|
@@ -8264,8 +8522,8 @@ var SshTransportPacketFramer = class {
|
|
|
8264
8522
|
}
|
|
8265
8523
|
/** Returns and clears any bytes buffered but not yet part of a complete packet. */
|
|
8266
8524
|
takeRemainingBytes() {
|
|
8267
|
-
const remaining =
|
|
8268
|
-
this.pending =
|
|
8525
|
+
const remaining = import_node_buffer13.Buffer.from(this.pending);
|
|
8526
|
+
this.pending = import_node_buffer13.Buffer.alloc(0);
|
|
8269
8527
|
return remaining;
|
|
8270
8528
|
}
|
|
8271
8529
|
};
|
|
@@ -8282,10 +8540,10 @@ function normalizeBlockSize(blockSize) {
|
|
|
8282
8540
|
}
|
|
8283
8541
|
|
|
8284
8542
|
// src/protocols/ssh/transport/SshHostKeyVerification.ts
|
|
8285
|
-
var
|
|
8543
|
+
var import_node_buffer14 = require("buffer");
|
|
8286
8544
|
var import_node_crypto7 = require("crypto");
|
|
8287
8545
|
var ED25519_RAW_KEY_LENGTH2 = 32;
|
|
8288
|
-
var ED25519_SPKI_PREFIX =
|
|
8546
|
+
var ED25519_SPKI_PREFIX = import_node_buffer14.Buffer.from("302a300506032b6570032100", "hex");
|
|
8289
8547
|
function verifySshHostKeySignature(input) {
|
|
8290
8548
|
const { algorithmName, publicKey } = parseHostKey(input.hostKeyBlob);
|
|
8291
8549
|
const { signatureAlgorithm, signatureBytes } = parseSignatureBlob(input.signatureBlob);
|
|
@@ -8298,9 +8556,9 @@ function verifySshHostKeySignature(input) {
|
|
|
8298
8556
|
});
|
|
8299
8557
|
}
|
|
8300
8558
|
const verified = verifySignature({
|
|
8301
|
-
data:
|
|
8559
|
+
data: import_node_buffer14.Buffer.from(input.exchangeHash),
|
|
8302
8560
|
publicKey,
|
|
8303
|
-
signature:
|
|
8561
|
+
signature: import_node_buffer14.Buffer.from(signatureBytes),
|
|
8304
8562
|
signatureAlgorithm
|
|
8305
8563
|
});
|
|
8306
8564
|
if (!verified) {
|
|
@@ -8329,7 +8587,7 @@ function parseHostKey(blob) {
|
|
|
8329
8587
|
retryable: false
|
|
8330
8588
|
});
|
|
8331
8589
|
}
|
|
8332
|
-
const spki =
|
|
8590
|
+
const spki = import_node_buffer14.Buffer.concat([ED25519_SPKI_PREFIX, raw]);
|
|
8333
8591
|
return {
|
|
8334
8592
|
algorithmName,
|
|
8335
8593
|
publicKey: (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" })
|
|
@@ -8435,37 +8693,37 @@ function verifySignature(input) {
|
|
|
8435
8693
|
function rsaPublicKeyFromComponents(e, n) {
|
|
8436
8694
|
const eDer = encodeAsn1Integer(e);
|
|
8437
8695
|
const nDer = encodeAsn1Integer(n);
|
|
8438
|
-
const rsaPublicKeyDer = encodeAsn1Sequence(
|
|
8439
|
-
const bitStringContent =
|
|
8440
|
-
const bitString =
|
|
8441
|
-
|
|
8696
|
+
const rsaPublicKeyDer = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([nDer, eDer]));
|
|
8697
|
+
const bitStringContent = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), rsaPublicKeyDer]);
|
|
8698
|
+
const bitString = import_node_buffer14.Buffer.concat([
|
|
8699
|
+
import_node_buffer14.Buffer.from([3]),
|
|
8442
8700
|
encodeAsn1Length(bitStringContent.length),
|
|
8443
8701
|
bitStringContent
|
|
8444
8702
|
]);
|
|
8445
|
-
const algoId =
|
|
8446
|
-
const spki = encodeAsn1Sequence(
|
|
8703
|
+
const algoId = import_node_buffer14.Buffer.from("300d06092a864886f70d010101 0500".replace(/\s+/g, ""), "hex");
|
|
8704
|
+
const spki = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([algoId, bitString]));
|
|
8447
8705
|
return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
|
|
8448
8706
|
}
|
|
8449
8707
|
function encodeAsn1Integer(value) {
|
|
8450
8708
|
let body = value;
|
|
8451
8709
|
while (body.length > 1 && body[0] === 0) body = body.subarray(1);
|
|
8452
8710
|
if (body.length > 0 && (body[0] & 128) !== 0) {
|
|
8453
|
-
body =
|
|
8711
|
+
body = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), body]);
|
|
8454
8712
|
}
|
|
8455
|
-
return
|
|
8713
|
+
return import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([2]), encodeAsn1Length(body.length), body]);
|
|
8456
8714
|
}
|
|
8457
8715
|
function encodeAsn1Sequence(content) {
|
|
8458
|
-
return
|
|
8716
|
+
return import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([48]), encodeAsn1Length(content.length), content]);
|
|
8459
8717
|
}
|
|
8460
8718
|
function encodeAsn1Length(length) {
|
|
8461
|
-
if (length < 128) return
|
|
8719
|
+
if (length < 128) return import_node_buffer14.Buffer.from([length]);
|
|
8462
8720
|
const bytes = [];
|
|
8463
8721
|
let n = length;
|
|
8464
8722
|
while (n > 0) {
|
|
8465
8723
|
bytes.unshift(n & 255);
|
|
8466
8724
|
n >>>= 8;
|
|
8467
8725
|
}
|
|
8468
|
-
return
|
|
8726
|
+
return import_node_buffer14.Buffer.from([128 | bytes.length, ...bytes]);
|
|
8469
8727
|
}
|
|
8470
8728
|
var ECDSA_OID_BY_CURVE = {
|
|
8471
8729
|
nistp256: "06082a8648ce3d030107",
|
|
@@ -8486,15 +8744,15 @@ function ecdsaPublicKeyFromPoint(curveIdentifier, point) {
|
|
|
8486
8744
|
retryable: false
|
|
8487
8745
|
});
|
|
8488
8746
|
}
|
|
8489
|
-
const algoIdContent =
|
|
8747
|
+
const algoIdContent = import_node_buffer14.Buffer.from(ECDSA_ALGORITHM_OID_HEX + oidHex, "hex");
|
|
8490
8748
|
const algoId = encodeAsn1Sequence(algoIdContent);
|
|
8491
|
-
const bitStringContent =
|
|
8492
|
-
const bitString =
|
|
8493
|
-
|
|
8749
|
+
const bitStringContent = import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from([0]), point]);
|
|
8750
|
+
const bitString = import_node_buffer14.Buffer.concat([
|
|
8751
|
+
import_node_buffer14.Buffer.from([3]),
|
|
8494
8752
|
encodeAsn1Length(bitStringContent.length),
|
|
8495
8753
|
bitStringContent
|
|
8496
8754
|
]);
|
|
8497
|
-
const spki = encodeAsn1Sequence(
|
|
8755
|
+
const spki = encodeAsn1Sequence(import_node_buffer14.Buffer.concat([algoId, bitString]));
|
|
8498
8756
|
return (0, import_node_crypto7.createPublicKey)({ format: "der", key: spki, type: "spki" });
|
|
8499
8757
|
}
|
|
8500
8758
|
function sshEcdsaSignatureToDer(sshSignature) {
|
|
@@ -8503,7 +8761,7 @@ function sshEcdsaSignatureToDer(sshSignature) {
|
|
|
8503
8761
|
const s = reader.readMpint();
|
|
8504
8762
|
const rDer = encodeAsn1Integer(r);
|
|
8505
8763
|
const sDer = encodeAsn1Integer(s);
|
|
8506
|
-
return encodeAsn1Sequence(
|
|
8764
|
+
return encodeAsn1Sequence(import_node_buffer14.Buffer.concat([rDer, sDer]));
|
|
8507
8765
|
}
|
|
8508
8766
|
|
|
8509
8767
|
// src/protocols/ssh/transport/SshTransportHandshake.ts
|
|
@@ -8535,7 +8793,7 @@ var SshTransportHandshake = class {
|
|
|
8535
8793
|
serverIdentification;
|
|
8536
8794
|
/** Creates the first outbound bytes (client identification line). */
|
|
8537
8795
|
createInitialClientBytes() {
|
|
8538
|
-
return
|
|
8796
|
+
return import_node_buffer15.Buffer.from(`${this.clientIdentificationLine}\r
|
|
8539
8797
|
`, "ascii");
|
|
8540
8798
|
}
|
|
8541
8799
|
/**
|
|
@@ -8559,7 +8817,7 @@ var SshTransportHandshake = class {
|
|
|
8559
8817
|
}
|
|
8560
8818
|
return { outbound };
|
|
8561
8819
|
}
|
|
8562
|
-
return this.pushServerBytesWithPhase(outbound,
|
|
8820
|
+
return this.pushServerBytesWithPhase(outbound, import_node_buffer15.Buffer.from(chunk));
|
|
8563
8821
|
}
|
|
8564
8822
|
getServerBannerLines() {
|
|
8565
8823
|
return this.identificationLines;
|
|
@@ -8613,12 +8871,12 @@ var SshTransportHandshake = class {
|
|
|
8613
8871
|
clientKexInitPayload: this.clientKexInitPayload,
|
|
8614
8872
|
clientPublicKey: this.pendingCurve25519.publicKey,
|
|
8615
8873
|
negotiatedAlgorithms,
|
|
8616
|
-
serverHostKey:
|
|
8874
|
+
serverHostKey: import_node_buffer15.Buffer.alloc(0),
|
|
8617
8875
|
serverIdentification: (this.serverIdentification ?? missingServerIdentificationError()).raw,
|
|
8618
|
-
serverKexInitPayload:
|
|
8619
|
-
serverPublicKey:
|
|
8620
|
-
serverSignature:
|
|
8621
|
-
sharedSecret:
|
|
8876
|
+
serverKexInitPayload: import_node_buffer15.Buffer.from(packet.payload),
|
|
8877
|
+
serverPublicKey: import_node_buffer15.Buffer.alloc(0),
|
|
8878
|
+
serverSignature: import_node_buffer15.Buffer.alloc(0),
|
|
8879
|
+
sharedSecret: import_node_buffer15.Buffer.alloc(0)
|
|
8622
8880
|
};
|
|
8623
8881
|
continue;
|
|
8624
8882
|
}
|
|
@@ -8726,24 +8984,54 @@ var SshTransportHandshake = class {
|
|
|
8726
8984
|
return { outbound };
|
|
8727
8985
|
}
|
|
8728
8986
|
};
|
|
8987
|
+
var MAX_IDENTIFICATION_LINE_BYTES = 8192;
|
|
8988
|
+
var MAX_PRE_IDENTIFICATION_LINES = 1024;
|
|
8729
8989
|
var SshIdentificationAccumulator = class {
|
|
8730
|
-
pending =
|
|
8990
|
+
pending = import_node_buffer15.Buffer.alloc(0);
|
|
8991
|
+
bannerLineCount = 0;
|
|
8731
8992
|
push(chunk) {
|
|
8732
|
-
this.pending =
|
|
8993
|
+
this.pending = import_node_buffer15.Buffer.concat([this.pending, import_node_buffer15.Buffer.from(chunk)]);
|
|
8733
8994
|
const bannerLines = [];
|
|
8734
8995
|
while (true) {
|
|
8735
8996
|
const lfIndex = this.pending.indexOf(10);
|
|
8736
|
-
if (lfIndex < 0)
|
|
8997
|
+
if (lfIndex < 0) {
|
|
8998
|
+
if (this.pending.length > MAX_IDENTIFICATION_LINE_BYTES) {
|
|
8999
|
+
throw new ProtocolError({
|
|
9000
|
+
details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },
|
|
9001
|
+
message: "SSH identification line exceeds the maximum accepted length",
|
|
9002
|
+
protocol: "sftp",
|
|
9003
|
+
retryable: false
|
|
9004
|
+
});
|
|
9005
|
+
}
|
|
9006
|
+
break;
|
|
9007
|
+
}
|
|
9008
|
+
if (lfIndex > MAX_IDENTIFICATION_LINE_BYTES) {
|
|
9009
|
+
throw new ProtocolError({
|
|
9010
|
+
details: { limitBytes: MAX_IDENTIFICATION_LINE_BYTES },
|
|
9011
|
+
message: "SSH identification line exceeds the maximum accepted length",
|
|
9012
|
+
protocol: "sftp",
|
|
9013
|
+
retryable: false
|
|
9014
|
+
});
|
|
9015
|
+
}
|
|
8737
9016
|
const lineText = trimLineEndings(this.pending.subarray(0, lfIndex + 1).toString("ascii"));
|
|
8738
|
-
const remainder =
|
|
9017
|
+
const remainder = import_node_buffer15.Buffer.from(this.pending.subarray(lfIndex + 1));
|
|
8739
9018
|
this.pending = remainder;
|
|
8740
9019
|
if (lineText.startsWith("SSH-")) {
|
|
8741
|
-
this.pending =
|
|
9020
|
+
this.pending = import_node_buffer15.Buffer.alloc(0);
|
|
8742
9021
|
return { bannerLines, identLine: lineText, remainder };
|
|
8743
9022
|
}
|
|
9023
|
+
this.bannerLineCount += 1;
|
|
9024
|
+
if (this.bannerLineCount > MAX_PRE_IDENTIFICATION_LINES) {
|
|
9025
|
+
throw new ProtocolError({
|
|
9026
|
+
details: { limitLines: MAX_PRE_IDENTIFICATION_LINES },
|
|
9027
|
+
message: "SSH server sent too many pre-identification banner lines",
|
|
9028
|
+
protocol: "sftp",
|
|
9029
|
+
retryable: false
|
|
9030
|
+
});
|
|
9031
|
+
}
|
|
8744
9032
|
bannerLines.push(lineText);
|
|
8745
9033
|
}
|
|
8746
|
-
return { bannerLines, remainder:
|
|
9034
|
+
return { bannerLines, remainder: import_node_buffer15.Buffer.alloc(0) };
|
|
8747
9035
|
}
|
|
8748
9036
|
};
|
|
8749
9037
|
function trimLineEndings(value) {
|
|
@@ -8771,7 +9059,7 @@ function missingPendingKeyExchangeError() {
|
|
|
8771
9059
|
}
|
|
8772
9060
|
|
|
8773
9061
|
// src/protocols/ssh/transport/SshTransportProtection.ts
|
|
8774
|
-
var
|
|
9062
|
+
var import_node_buffer16 = require("buffer");
|
|
8775
9063
|
var import_node_crypto8 = require("crypto");
|
|
8776
9064
|
function createSshTransportProtectionContext(input) {
|
|
8777
9065
|
return {
|
|
@@ -8828,7 +9116,7 @@ var SshTransportPacketProtector = class {
|
|
|
8828
9116
|
);
|
|
8829
9117
|
const encrypted = this.cipher === void 0 ? clearPacket : this.cipher.update(clearPacket);
|
|
8830
9118
|
this.sequenceNumber = this.sequenceNumber + 1 >>> 0;
|
|
8831
|
-
return
|
|
9119
|
+
return import_node_buffer16.Buffer.concat([encrypted, mac]);
|
|
8832
9120
|
}
|
|
8833
9121
|
};
|
|
8834
9122
|
var SshTransportPacketUnprotector = class {
|
|
@@ -8854,7 +9142,7 @@ var SshTransportPacketUnprotector = class {
|
|
|
8854
9142
|
sequenceNumber;
|
|
8855
9143
|
// Streaming framing state for pushBytes()
|
|
8856
9144
|
framePartialDecrypted;
|
|
8857
|
-
framePendingRaw =
|
|
9145
|
+
framePendingRaw = import_node_buffer16.Buffer.alloc(0);
|
|
8858
9146
|
frameRemainingNeeded;
|
|
8859
9147
|
getSequenceNumber() {
|
|
8860
9148
|
return this.sequenceNumber;
|
|
@@ -8864,15 +9152,23 @@ var SshTransportPacketUnprotector = class {
|
|
|
8864
9152
|
* Maintains internal framing state across calls - pass each `data` event chunk directly.
|
|
8865
9153
|
*/
|
|
8866
9154
|
pushBytes(chunk) {
|
|
8867
|
-
this.framePendingRaw =
|
|
9155
|
+
this.framePendingRaw = import_node_buffer16.Buffer.concat([this.framePendingRaw, chunk]);
|
|
8868
9156
|
const results = [];
|
|
8869
9157
|
while (true) {
|
|
8870
9158
|
if (this.framePartialDecrypted === void 0) {
|
|
8871
9159
|
if (this.framePendingRaw.length < this.blockLength) break;
|
|
8872
9160
|
const firstBlock = this.framePendingRaw.subarray(0, this.blockLength);
|
|
8873
|
-
this.framePendingRaw =
|
|
8874
|
-
this.framePartialDecrypted = this.decipher ?
|
|
9161
|
+
this.framePendingRaw = import_node_buffer16.Buffer.from(this.framePendingRaw.subarray(this.blockLength));
|
|
9162
|
+
this.framePartialDecrypted = this.decipher ? import_node_buffer16.Buffer.from(this.decipher.update(firstBlock)) : import_node_buffer16.Buffer.from(firstBlock);
|
|
8875
9163
|
const packetLength = this.framePartialDecrypted.readUInt32BE(0);
|
|
9164
|
+
if (packetLength > MAX_SSH_PACKET_LENGTH) {
|
|
9165
|
+
throw new ProtocolError({
|
|
9166
|
+
details: { maxPacketLength: MAX_SSH_PACKET_LENGTH, packetLength },
|
|
9167
|
+
message: "SSH encrypted packet length exceeds the maximum accepted size",
|
|
9168
|
+
protocol: "sftp",
|
|
9169
|
+
retryable: false
|
|
9170
|
+
});
|
|
9171
|
+
}
|
|
8876
9172
|
const remaining = 4 + packetLength - this.blockLength + this.macLength;
|
|
8877
9173
|
if (remaining < 0) {
|
|
8878
9174
|
throw new ProtocolError({
|
|
@@ -8888,9 +9184,9 @@ var SshTransportPacketUnprotector = class {
|
|
|
8888
9184
|
if (this.framePendingRaw.length < needed) break;
|
|
8889
9185
|
const encryptedRest = this.framePendingRaw.subarray(0, needed - this.macLength);
|
|
8890
9186
|
const receivedMac = this.framePendingRaw.subarray(needed - this.macLength, needed);
|
|
8891
|
-
this.framePendingRaw =
|
|
8892
|
-
const decryptedRest = encryptedRest.length > 0 ? this.decipher ?
|
|
8893
|
-
const clearPacket =
|
|
9187
|
+
this.framePendingRaw = import_node_buffer16.Buffer.from(this.framePendingRaw.subarray(needed));
|
|
9188
|
+
const decryptedRest = encryptedRest.length > 0 ? this.decipher ? import_node_buffer16.Buffer.from(this.decipher.update(encryptedRest)) : import_node_buffer16.Buffer.from(encryptedRest) : import_node_buffer16.Buffer.alloc(0);
|
|
9189
|
+
const clearPacket = import_node_buffer16.Buffer.concat([this.framePartialDecrypted, decryptedRest]);
|
|
8894
9190
|
const expectedMac = computeMac(
|
|
8895
9191
|
this.macAlgorithm,
|
|
8896
9192
|
this.options.keys.macKey,
|
|
@@ -8913,7 +9209,7 @@ var SshTransportPacketUnprotector = class {
|
|
|
8913
9209
|
return results;
|
|
8914
9210
|
}
|
|
8915
9211
|
unprotectPayload(packet) {
|
|
8916
|
-
const frame =
|
|
9212
|
+
const frame = import_node_buffer16.Buffer.from(packet);
|
|
8917
9213
|
if (frame.length < this.macLength) {
|
|
8918
9214
|
throw new ProtocolError({
|
|
8919
9215
|
details: { length: frame.length, macLength: this.macLength },
|
|
@@ -9054,10 +9350,10 @@ function resolveMacLength(encryptionAlgorithm, macAlgorithm) {
|
|
|
9054
9350
|
}
|
|
9055
9351
|
function computeMac(macAlgorithm, macKey, sequence, packet, macLength) {
|
|
9056
9352
|
if (macLength === 0) {
|
|
9057
|
-
return
|
|
9353
|
+
return import_node_buffer16.Buffer.alloc(0);
|
|
9058
9354
|
}
|
|
9059
9355
|
const hashName = macAlgorithm === "hmac-sha2-512" ? "sha512" : "sha256";
|
|
9060
|
-
const sequenceBuffer =
|
|
9356
|
+
const sequenceBuffer = import_node_buffer16.Buffer.alloc(4);
|
|
9061
9357
|
sequenceBuffer.writeUInt32BE(sequence >>> 0, 0);
|
|
9062
9358
|
return (0, import_node_crypto8.createHmac)(hashName, macKey).update(sequenceBuffer).update(packet).digest().subarray(0, macLength);
|
|
9063
9359
|
}
|
|
@@ -9264,7 +9560,7 @@ var SshTransportConnection = class {
|
|
|
9264
9560
|
*/
|
|
9265
9561
|
sendPayload(payload) {
|
|
9266
9562
|
this.assertConnected();
|
|
9267
|
-
const frame = this.protector.protectPayload(
|
|
9563
|
+
const frame = this.protector.protectPayload(import_node_buffer17.Buffer.from(payload));
|
|
9268
9564
|
this.socket.write(frame);
|
|
9269
9565
|
this.resetKeepaliveTimer();
|
|
9270
9566
|
}
|
|
@@ -9422,7 +9718,7 @@ function parseDisconnectPayload(payload) {
|
|
|
9422
9718
|
}
|
|
9423
9719
|
|
|
9424
9720
|
// src/protocols/sftp/v3/SftpSession.ts
|
|
9425
|
-
var
|
|
9721
|
+
var import_node_buffer19 = require("buffer");
|
|
9426
9722
|
|
|
9427
9723
|
// src/protocols/sftp/v3/SftpAttributes.ts
|
|
9428
9724
|
var SFTP_ATTR_FLAG = {
|
|
@@ -9495,7 +9791,8 @@ function decodeSftpAttributesFromReader(reader) {
|
|
|
9495
9791
|
}
|
|
9496
9792
|
|
|
9497
9793
|
// src/protocols/sftp/v3/SftpPacket.ts
|
|
9498
|
-
var
|
|
9794
|
+
var import_node_buffer18 = require("buffer");
|
|
9795
|
+
var MAX_SFTP_PACKET_LENGTH = 256 * 1024;
|
|
9499
9796
|
var SFTP_PACKET_TYPE = {
|
|
9500
9797
|
ATTRS: 105,
|
|
9501
9798
|
CLOSE: 4,
|
|
@@ -9526,7 +9823,7 @@ var SFTP_PACKET_TYPE = {
|
|
|
9526
9823
|
WRITE: 6
|
|
9527
9824
|
};
|
|
9528
9825
|
function decodeSftpPacket(frame) {
|
|
9529
|
-
const bytes =
|
|
9826
|
+
const bytes = import_node_buffer18.Buffer.from(frame);
|
|
9530
9827
|
if (bytes.length < 5) {
|
|
9531
9828
|
throw new ParseError({
|
|
9532
9829
|
details: { length: bytes.length },
|
|
@@ -9549,12 +9846,19 @@ function decodeSftpPacket(frame) {
|
|
|
9549
9846
|
};
|
|
9550
9847
|
}
|
|
9551
9848
|
var SftpPacketFramer = class {
|
|
9552
|
-
pending =
|
|
9849
|
+
pending = import_node_buffer18.Buffer.alloc(0);
|
|
9553
9850
|
push(chunk) {
|
|
9554
|
-
this.pending =
|
|
9851
|
+
this.pending = import_node_buffer18.Buffer.concat([this.pending, import_node_buffer18.Buffer.from(chunk)]);
|
|
9555
9852
|
const packets = [];
|
|
9556
9853
|
while (this.pending.length >= 4) {
|
|
9557
9854
|
const bodyLength = this.pending.readUInt32BE(0);
|
|
9855
|
+
if (bodyLength > MAX_SFTP_PACKET_LENGTH) {
|
|
9856
|
+
throw new ParseError({
|
|
9857
|
+
details: { bodyLength, maxPacketLength: MAX_SFTP_PACKET_LENGTH },
|
|
9858
|
+
message: "SFTP packet length exceeds the maximum accepted size",
|
|
9859
|
+
retryable: false
|
|
9860
|
+
});
|
|
9861
|
+
}
|
|
9558
9862
|
const frameLength = 4 + bodyLength;
|
|
9559
9863
|
if (this.pending.length < frameLength) {
|
|
9560
9864
|
break;
|
|
@@ -10009,7 +10313,7 @@ var SftpSession = class {
|
|
|
10009
10313
|
* serializes concurrent calls so byte ordering is preserved.
|
|
10010
10314
|
*/
|
|
10011
10315
|
sendRaw(encodedMessage, requestId) {
|
|
10012
|
-
const frame =
|
|
10316
|
+
const frame = import_node_buffer19.Buffer.alloc(4 + encodedMessage.length);
|
|
10013
10317
|
frame.writeUInt32BE(encodedMessage.length, 0);
|
|
10014
10318
|
encodedMessage.copy(frame, 4);
|
|
10015
10319
|
this.channel.sendData(frame).catch((err) => {
|
|
@@ -10156,7 +10460,7 @@ function buildNativeSftpCapabilities(maxConcurrency) {
|
|
|
10156
10460
|
var NATIVE_SFTP_PROVIDER_CAPABILITIES = buildNativeSftpCapabilities(
|
|
10157
10461
|
NATIVE_SFTP_DEFAULT_MAX_CONCURRENCY
|
|
10158
10462
|
);
|
|
10159
|
-
function
|
|
10463
|
+
function createSftpProviderFactory(options = {}) {
|
|
10160
10464
|
validateNativeSftpOptions(options);
|
|
10161
10465
|
const capabilities = buildNativeSftpCapabilities(
|
|
10162
10466
|
options.maxConcurrency ?? NATIVE_SFTP_DEFAULT_MAX_CONCURRENCY
|
|
@@ -10552,9 +10856,9 @@ function buildNativePublickeyCredential(profile, username) {
|
|
|
10552
10856
|
const passphrase = profile.ssh?.passphrase;
|
|
10553
10857
|
try {
|
|
10554
10858
|
const privateKey = (0, import_node_crypto9.createPrivateKey)({
|
|
10555
|
-
key:
|
|
10859
|
+
key: import_node_buffer20.Buffer.isBuffer(keyMaterial) ? keyMaterial : keyMaterial,
|
|
10556
10860
|
...passphrase === void 0 ? {} : {
|
|
10557
|
-
passphrase:
|
|
10861
|
+
passphrase: import_node_buffer20.Buffer.isBuffer(passphrase) ? passphrase : passphrase
|
|
10558
10862
|
}
|
|
10559
10863
|
});
|
|
10560
10864
|
return buildPublickeyCredential({ privateKey, username });
|
|
@@ -10681,12 +10985,12 @@ function normalizeNativeHostKeyPins(value) {
|
|
|
10681
10985
|
const trimmed = pin.trim();
|
|
10682
10986
|
const hex = trimmed.replace(/:/g, "");
|
|
10683
10987
|
if (hex.length === 64 && /^[a-f0-9]+$/i.test(hex)) {
|
|
10684
|
-
normalized.add(
|
|
10988
|
+
normalized.add(import_node_buffer20.Buffer.from(hex, "hex").toString("base64").replace(/=+$/g, ""));
|
|
10685
10989
|
continue;
|
|
10686
10990
|
}
|
|
10687
10991
|
const bare = trimmed.startsWith("SHA256:") ? trimmed.slice("SHA256:".length) : trimmed;
|
|
10688
10992
|
const padded = bare.length % 4 === 0 ? bare : `${bare}${"=".repeat(4 - bare.length % 4)}`;
|
|
10689
|
-
normalized.add(
|
|
10993
|
+
normalized.add(import_node_buffer20.Buffer.from(padded, "base64").toString("base64").replace(/=+$/g, ""));
|
|
10690
10994
|
}
|
|
10691
10995
|
return normalized;
|
|
10692
10996
|
}
|
|
@@ -10696,7 +11000,7 @@ function parseNativeKnownHosts(source) {
|
|
|
10696
11000
|
const entries = [];
|
|
10697
11001
|
let sawNonEmpty = false;
|
|
10698
11002
|
for (const value of sources) {
|
|
10699
|
-
const text =
|
|
11003
|
+
const text = import_node_buffer20.Buffer.isBuffer(value) ? value.toString("utf8") : String(value);
|
|
10700
11004
|
if (text.length === 0) continue;
|
|
10701
11005
|
sawNonEmpty = true;
|
|
10702
11006
|
entries.push(...parseKnownHosts(text));
|
|
@@ -10769,7 +11073,7 @@ function requireNativeSftpUsername(profile) {
|
|
|
10769
11073
|
}
|
|
10770
11074
|
function resolveNativeSftpTextSecret(value) {
|
|
10771
11075
|
if (value === void 0) return void 0;
|
|
10772
|
-
const text =
|
|
11076
|
+
const text = import_node_buffer20.Buffer.isBuffer(value) ? value.toString("utf8") : value;
|
|
10773
11077
|
if (text.length === 0) return void 0;
|
|
10774
11078
|
return text;
|
|
10775
11079
|
}
|
|
@@ -10845,6 +11149,7 @@ function validateNativeSftpOptions(options) {
|
|
|
10845
11149
|
copyBetween,
|
|
10846
11150
|
createAtomicDeployPlan,
|
|
10847
11151
|
createBandwidthThrottle,
|
|
11152
|
+
createDefaultRetryPolicy,
|
|
10848
11153
|
createFtpProviderFactory,
|
|
10849
11154
|
createFtpsProviderFactory,
|
|
10850
11155
|
createLocalProviderFactory,
|
|
@@ -10890,8 +11195,10 @@ function validateNativeSftpOptions(options) {
|
|
|
10890
11195
|
parseUnixListLine,
|
|
10891
11196
|
redactCommand,
|
|
10892
11197
|
redactConnectionProfile,
|
|
11198
|
+
redactErrorForLogging,
|
|
10893
11199
|
redactObject,
|
|
10894
11200
|
redactSecretSource,
|
|
11201
|
+
redactUrlForLogging,
|
|
10895
11202
|
redactValue,
|
|
10896
11203
|
resolveConnectionProfileSecrets,
|
|
10897
11204
|
resolveOpenSshHost,
|