typescript-virtual-container 1.2.9 → 1.3.0
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/.vscode/settings.json +0 -1
- package/README.md +141 -50
- package/biome.json +7 -0
- package/dist/SSHMimic/exec.d.ts.map +1 -1
- package/dist/SSHMimic/executor.d.ts.map +1 -1
- package/dist/SSHMimic/executor.js +32 -16
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +20 -6
- package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -1
- package/dist/VirtualFileSystem/binaryPack.js +29 -6
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +36 -13
- package/dist/VirtualPackageManager/index.d.ts.map +1 -1
- package/dist/VirtualPackageManager/index.js +192 -43
- package/dist/VirtualShell/index.d.ts +10 -4
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +18 -7
- package/dist/VirtualShell/shell.d.ts.map +1 -1
- package/dist/VirtualShell/shell.js +3 -1
- package/dist/VirtualShell/shellParser.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/commands/adduser.d.ts +6 -0
- package/dist/commands/adduser.d.ts.map +1 -1
- package/dist/commands/adduser.js +6 -0
- package/dist/commands/alias.d.ts +5 -0
- package/dist/commands/alias.d.ts.map +1 -1
- package/dist/commands/alias.js +5 -0
- package/dist/commands/apt.d.ts +5 -0
- package/dist/commands/apt.d.ts.map +1 -1
- package/dist/commands/apt.js +32 -9
- package/dist/commands/awk.d.ts +11 -0
- package/dist/commands/awk.d.ts.map +1 -1
- package/dist/commands/awk.js +15 -2
- package/dist/commands/base64.d.ts +5 -0
- package/dist/commands/base64.d.ts.map +1 -1
- package/dist/commands/base64.js +9 -1
- package/dist/commands/cat.d.ts +5 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +10 -2
- package/dist/commands/cd.d.ts +5 -0
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +5 -0
- package/dist/commands/chmod.d.ts +5 -0
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +5 -0
- package/dist/commands/cp.d.ts +5 -0
- package/dist/commands/cp.d.ts.map +1 -1
- package/dist/commands/cp.js +5 -0
- package/dist/commands/curl.d.ts +5 -0
- package/dist/commands/curl.d.ts.map +1 -1
- package/dist/commands/curl.js +34 -6
- package/dist/commands/cut.d.ts +5 -0
- package/dist/commands/cut.d.ts.map +1 -1
- package/dist/commands/cut.js +8 -1
- package/dist/commands/date.d.ts +5 -0
- package/dist/commands/date.d.ts.map +1 -1
- package/dist/commands/date.js +7 -1
- package/dist/commands/declare.d.ts +3 -0
- package/dist/commands/declare.d.ts.map +1 -0
- package/dist/commands/declare.js +39 -0
- package/dist/commands/diff.d.ts +5 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +5 -0
- package/dist/commands/dpkg.d.ts +5 -0
- package/dist/commands/dpkg.d.ts.map +1 -1
- package/dist/commands/dpkg.js +24 -7
- package/dist/commands/du.d.ts.map +1 -1
- package/dist/commands/du.js +8 -2
- package/dist/commands/echo.d.ts +5 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +13 -4
- package/dist/commands/env.d.ts +5 -0
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +11 -1
- package/dist/commands/exit.d.ts +5 -0
- package/dist/commands/exit.d.ts.map +1 -1
- package/dist/commands/exit.js +12 -2
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +3 -1
- package/dist/commands/find.d.ts +5 -0
- package/dist/commands/find.d.ts.map +1 -1
- package/dist/commands/find.js +5 -0
- package/dist/commands/free.d.ts +5 -0
- package/dist/commands/free.d.ts.map +1 -1
- package/dist/commands/free.js +5 -0
- package/dist/commands/grep.d.ts +5 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +12 -2
- package/dist/commands/gzip.d.ts +5 -0
- package/dist/commands/gzip.d.ts.map +1 -1
- package/dist/commands/gzip.js +18 -2
- package/dist/commands/head.d.ts +5 -0
- package/dist/commands/head.d.ts.map +1 -1
- package/dist/commands/head.js +5 -0
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +98 -45
- package/dist/commands/history.d.ts +5 -0
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +5 -0
- package/dist/commands/hostname.d.ts +5 -0
- package/dist/commands/hostname.d.ts.map +1 -1
- package/dist/commands/hostname.js +5 -0
- package/dist/commands/id.d.ts.map +1 -1
- package/dist/commands/id.js +4 -1
- package/dist/commands/index.d.ts +2 -17
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -340
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +3 -1
- package/dist/commands/lsb-release.d.ts.map +1 -1
- package/dist/commands/lsb-release.js +8 -2
- package/dist/commands/nano.js +1 -1
- package/dist/commands/neofetch.js +1 -1
- package/dist/commands/node.d.ts +9 -0
- package/dist/commands/node.d.ts.map +1 -0
- package/dist/commands/node.js +316 -0
- package/dist/commands/npm.d.ts +19 -0
- package/dist/commands/npm.d.ts.map +1 -0
- package/dist/commands/npm.js +109 -0
- package/dist/commands/ping.d.ts.map +1 -1
- package/dist/commands/ping.js +3 -1
- package/dist/commands/printf.d.ts +3 -0
- package/dist/commands/printf.d.ts.map +1 -0
- package/dist/commands/printf.js +113 -0
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +4 -1
- package/dist/commands/python.d.ts +30 -0
- package/dist/commands/python.d.ts.map +1 -0
- package/dist/commands/python.js +2058 -0
- package/dist/commands/read.d.ts +3 -0
- package/dist/commands/read.d.ts.map +1 -0
- package/dist/commands/read.js +34 -0
- package/dist/commands/registry.d.ts +8 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +229 -0
- package/dist/commands/runtime.d.ts +6 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +280 -0
- package/dist/commands/sed.d.ts.map +1 -1
- package/dist/commands/sed.js +11 -3
- package/dist/commands/set.d.ts.map +1 -1
- package/dist/commands/set.js +9 -3
- package/dist/commands/sh.d.ts.map +1 -1
- package/dist/commands/sh.js +57 -36
- package/dist/commands/shift.d.ts +5 -0
- package/dist/commands/shift.d.ts.map +1 -0
- package/dist/commands/shift.js +52 -0
- package/dist/commands/sleep.d.ts.map +1 -1
- package/dist/commands/sort.d.ts.map +1 -1
- package/dist/commands/sort.js +4 -2
- package/dist/commands/source.d.ts.map +1 -1
- package/dist/commands/source.js +5 -2
- package/dist/commands/sudo.js +1 -1
- package/dist/commands/tar.d.ts.map +1 -1
- package/dist/commands/tar.js +11 -3
- package/dist/commands/tee.d.ts.map +1 -1
- package/dist/commands/tee.js +8 -6
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +46 -24
- package/dist/commands/tr.d.ts.map +1 -1
- package/dist/commands/tr.js +3 -1
- package/dist/commands/true.d.ts +4 -0
- package/dist/commands/true.d.ts.map +1 -0
- package/dist/commands/true.js +14 -0
- package/dist/commands/type.d.ts.map +1 -1
- package/dist/commands/type.js +1 -1
- package/dist/commands/uname.d.ts.map +1 -1
- package/dist/commands/uname.js +4 -1
- package/dist/commands/uniq.d.ts.map +1 -1
- package/dist/commands/uptime.d.ts.map +1 -1
- package/dist/commands/uptime.js +4 -1
- package/dist/commands/wget.d.ts.map +1 -1
- package/dist/commands/wget.js +32 -7
- package/dist/commands/which.d.ts.map +1 -1
- package/dist/commands/xargs.d.ts.map +1 -1
- package/dist/commands/xargs.js +1 -1
- package/dist/index.d.ts +15 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/modules/linuxRootfs.d.ts +18 -1
- package/dist/modules/linuxRootfs.d.ts.map +1 -1
- package/dist/modules/linuxRootfs.js +160 -17
- package/dist/standalone-wo-sftp.d.ts +2 -0
- package/dist/standalone-wo-sftp.d.ts.map +1 -0
- package/dist/standalone-wo-sftp.js +30 -0
- package/dist/utils/expand.d.ts +50 -0
- package/dist/utils/expand.d.ts.map +1 -0
- package/dist/utils/expand.js +183 -0
- package/dist/utils/vfsDiff.d.ts +90 -0
- package/dist/utils/vfsDiff.d.ts.map +1 -0
- package/dist/utils/vfsDiff.js +177 -0
- package/package.json +2 -1
- package/src/SSHMimic/exec.ts +10 -1
- package/src/SSHMimic/executor.ts +104 -18
- package/src/SSHMimic/index.ts +49 -15
- package/src/VirtualFileSystem/binaryPack.ts +35 -8
- package/src/VirtualFileSystem/index.ts +78 -28
- package/src/VirtualPackageManager/index.ts +208 -49
- package/src/VirtualShell/index.ts +35 -7
- package/src/VirtualShell/shell.ts +23 -3
- package/src/VirtualShell/shellParser.ts +134 -36
- package/src/VirtualUserManager/index.ts +7 -2
- package/src/commands/adduser.ts +6 -0
- package/src/commands/alias.ts +5 -1
- package/src/commands/apt.ts +47 -17
- package/src/commands/awk.ts +20 -6
- package/src/commands/base64.ts +13 -2
- package/src/commands/cat.ts +13 -5
- package/src/commands/cd.ts +5 -0
- package/src/commands/chmod.ts +5 -0
- package/src/commands/cp.ts +5 -0
- package/src/commands/curl.ts +56 -12
- package/src/commands/cut.ts +8 -1
- package/src/commands/date.ts +7 -1
- package/src/commands/declare.ts +44 -0
- package/src/commands/diff.ts +17 -3
- package/src/commands/dpkg.ts +33 -11
- package/src/commands/du.ts +17 -5
- package/src/commands/echo.ts +22 -9
- package/src/commands/env.ts +11 -1
- package/src/commands/exit.ts +12 -2
- package/src/commands/export.ts +3 -1
- package/src/commands/find.ts +5 -0
- package/src/commands/free.ts +9 -2
- package/src/commands/grep.ts +12 -2
- package/src/commands/gzip.ts +28 -4
- package/src/commands/head.ts +5 -0
- package/src/commands/help.ts +121 -47
- package/src/commands/history.ts +7 -2
- package/src/commands/hostname.ts +5 -0
- package/src/commands/id.ts +4 -1
- package/src/commands/index.ts +9 -360
- package/src/commands/ls.ts +5 -3
- package/src/commands/lsb-release.ts +8 -2
- package/src/commands/nano.ts +1 -1
- package/src/commands/neofetch.ts +1 -1
- package/src/commands/node.ts +341 -0
- package/src/commands/npm.ts +132 -0
- package/src/commands/ping.ts +6 -2
- package/src/commands/printf.ts +112 -0
- package/src/commands/ps.ts +21 -9
- package/src/commands/python.ts +2229 -0
- package/src/commands/read.ts +41 -0
- package/src/commands/registry.ts +244 -0
- package/src/commands/runtime.ts +353 -0
- package/src/commands/sed.ts +27 -9
- package/src/commands/set.ts +9 -3
- package/src/commands/sh.ts +159 -55
- package/src/commands/shift.ts +53 -0
- package/src/commands/sleep.ts +2 -1
- package/src/commands/sort.ts +10 -6
- package/src/commands/source.ts +15 -3
- package/src/commands/sudo.ts +1 -1
- package/src/commands/tar.ts +28 -7
- package/src/commands/tee.ts +7 -1
- package/src/commands/test.ts +61 -26
- package/src/commands/tr.ts +3 -1
- package/src/commands/true.ts +17 -0
- package/src/commands/type.ts +6 -3
- package/src/commands/uname.ts +5 -1
- package/src/commands/uniq.ts +8 -2
- package/src/commands/uptime.ts +4 -1
- package/src/commands/wget.ts +51 -12
- package/src/commands/which.ts +5 -2
- package/src/commands/xargs.ts +11 -2
- package/src/index.ts +23 -24
- package/src/modules/linuxRootfs.ts +233 -30
- package/src/standalone-wo-sftp.ts +38 -0
- package/src/utils/expand.ts +238 -0
- package/src/utils/vfsDiff.ts +275 -0
- package/standalone-wo-sftp.js +507 -0
- package/standalone-wo-sftp.js.map +7 -0
- package/standalone.js +253 -191
- package/standalone.js.map +4 -4
- package/tests/bun-test-shim.ts +9 -1
- package/tests/command-helpers.test.ts +1 -5
- package/tests/new-features.test.ts +415 -5
- package/tests/parser-executor.test.ts +27 -27
- package/tests/sftp.test.ts +122 -42
- package/tests/users.test.ts +23 -5
- package/CHANGELOG.md +0 -150
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vfsDiff.ts
|
|
3
|
+
*
|
|
4
|
+
* Snapshot diff tooling for `VirtualFileSystem`.
|
|
5
|
+
*
|
|
6
|
+
* Compares two VFS snapshots and returns structured diff results suitable
|
|
7
|
+
* for test assertions, audit logging, and deployment verification.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { diffSnapshots, formatDiff } from "typescript-virtual-container/utils/vfsDiff";
|
|
12
|
+
*
|
|
13
|
+
* const before = shell.vfs.toSnapshot();
|
|
14
|
+
* await client.exec("npm install && mkdir -p /app");
|
|
15
|
+
* const after = shell.vfs.toSnapshot();
|
|
16
|
+
*
|
|
17
|
+
* const diff = diffSnapshots(before, after);
|
|
18
|
+
* console.log(formatDiff(diff));
|
|
19
|
+
*
|
|
20
|
+
* // Test assertions
|
|
21
|
+
* expect(diff.added).toContain("/app");
|
|
22
|
+
* expect(diff.modified).toContain("/etc/hosts");
|
|
23
|
+
* expect(diff.removed).not.toContain("/tmp/needed-file");
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import type { VfsSnapshot } from "../types/vfs";
|
|
27
|
+
/** A single changed file entry in a diff result. */
|
|
28
|
+
export interface VfsDiffEntry {
|
|
29
|
+
/** Absolute VFS path of the changed node. */
|
|
30
|
+
path: string;
|
|
31
|
+
/** Node type — `"file"` or `"directory"`. */
|
|
32
|
+
type: "file" | "directory";
|
|
33
|
+
}
|
|
34
|
+
/** A modified file entry — includes before/after content for files. */
|
|
35
|
+
export interface VfsDiffModified extends VfsDiffEntry {
|
|
36
|
+
type: "file";
|
|
37
|
+
/** Content before the change (decoded from base64). */
|
|
38
|
+
before: string;
|
|
39
|
+
/** Content after the change (decoded from base64). */
|
|
40
|
+
after: string;
|
|
41
|
+
}
|
|
42
|
+
/** Full result of a snapshot diff operation. */
|
|
43
|
+
export interface VfsDiff {
|
|
44
|
+
/** Paths present in `after` but not in `before`. */
|
|
45
|
+
added: VfsDiffEntry[];
|
|
46
|
+
/** Paths present in `before` but not in `after`. */
|
|
47
|
+
removed: VfsDiffEntry[];
|
|
48
|
+
/** Files whose content or mode changed between snapshots. */
|
|
49
|
+
modified: VfsDiffModified[];
|
|
50
|
+
/** True when there are no differences. */
|
|
51
|
+
clean: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compute the diff between two VFS snapshots.
|
|
55
|
+
*
|
|
56
|
+
* @param before Snapshot taken before the operation.
|
|
57
|
+
* @param after Snapshot taken after the operation.
|
|
58
|
+
* @param options Optional filtering options.
|
|
59
|
+
* @returns A structured `VfsDiff` result.
|
|
60
|
+
*/
|
|
61
|
+
export declare function diffSnapshots(before: VfsSnapshot, after: VfsSnapshot, options?: {
|
|
62
|
+
/** Glob-style path prefixes to ignore (e.g. `["/proc", "/var/log"]`). */
|
|
63
|
+
ignore?: string[];
|
|
64
|
+
}): VfsDiff;
|
|
65
|
+
/**
|
|
66
|
+
* Format a `VfsDiff` as a human-readable string similar to `git diff --stat`.
|
|
67
|
+
*
|
|
68
|
+
* @param diff Result from `diffSnapshots`.
|
|
69
|
+
* @param options Formatting options.
|
|
70
|
+
*/
|
|
71
|
+
export declare function formatDiff(diff: VfsDiff, options?: {
|
|
72
|
+
/** Show file content changes inline. Default: false. */
|
|
73
|
+
showContent?: boolean;
|
|
74
|
+
/** Max chars of content to show per change. Default: 120. */
|
|
75
|
+
maxContentChars?: number;
|
|
76
|
+
}): string;
|
|
77
|
+
/**
|
|
78
|
+
* Assert that a diff contains specific paths, throwing on mismatch.
|
|
79
|
+
* Designed for use in test suites.
|
|
80
|
+
*
|
|
81
|
+
* @param diff Result from `diffSnapshots`.
|
|
82
|
+
* @param expect Expected paths in each category.
|
|
83
|
+
* @throws When any expectation is not met.
|
|
84
|
+
*/
|
|
85
|
+
export declare function assertDiff(diff: VfsDiff, expect: {
|
|
86
|
+
added?: string[];
|
|
87
|
+
removed?: string[];
|
|
88
|
+
modified?: string[];
|
|
89
|
+
}): void;
|
|
90
|
+
//# sourceMappingURL=vfsDiff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfsDiff.d.ts","sourceRoot":"","sources":["../../src/utils/vfsDiff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EACX,WAAW,EAIX,MAAM,cAAc,CAAC;AAItB,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC5B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;CACd;AAED,gDAAgD;AAChD,MAAM,WAAW,OAAO;IACvB,oDAAoD;IACpD,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,oDAAoD;IACpD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,0CAA0C;IAC1C,KAAK,EAAE,OAAO,CAAC;CACf;AA4BD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC5B,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE;IACR,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACb,GACJ,OAAO,CAsET;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE;IACR,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;CACpB,GACJ,MAAM,CAsCR;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACzB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE;IACP,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,GACC,IAAI,CA4BN"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vfsDiff.ts
|
|
3
|
+
*
|
|
4
|
+
* Snapshot diff tooling for `VirtualFileSystem`.
|
|
5
|
+
*
|
|
6
|
+
* Compares two VFS snapshots and returns structured diff results suitable
|
|
7
|
+
* for test assertions, audit logging, and deployment verification.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { diffSnapshots, formatDiff } from "typescript-virtual-container/utils/vfsDiff";
|
|
12
|
+
*
|
|
13
|
+
* const before = shell.vfs.toSnapshot();
|
|
14
|
+
* await client.exec("npm install && mkdir -p /app");
|
|
15
|
+
* const after = shell.vfs.toSnapshot();
|
|
16
|
+
*
|
|
17
|
+
* const diff = diffSnapshots(before, after);
|
|
18
|
+
* console.log(formatDiff(diff));
|
|
19
|
+
*
|
|
20
|
+
* // Test assertions
|
|
21
|
+
* expect(diff.added).toContain("/app");
|
|
22
|
+
* expect(diff.modified).toContain("/etc/hosts");
|
|
23
|
+
* expect(diff.removed).not.toContain("/tmp/needed-file");
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
// ─── internal helpers ─────────────────────────────────────────────────────────
|
|
27
|
+
function flattenSnapshot(node, prefix, out) {
|
|
28
|
+
const path = prefix === "" ? "/" : prefix;
|
|
29
|
+
out.set(path, node);
|
|
30
|
+
if (node.type === "directory") {
|
|
31
|
+
for (const child of node.children ?? []) {
|
|
32
|
+
flattenSnapshot(child, `${prefix}/${child.name}`, out);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function decodeContent(node) {
|
|
37
|
+
try {
|
|
38
|
+
return Buffer.from(node.contentBase64, "base64").toString("utf8");
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return node.contentBase64;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ─── public API ───────────────────────────────────────────────────────────────
|
|
45
|
+
/**
|
|
46
|
+
* Compute the diff between two VFS snapshots.
|
|
47
|
+
*
|
|
48
|
+
* @param before Snapshot taken before the operation.
|
|
49
|
+
* @param after Snapshot taken after the operation.
|
|
50
|
+
* @param options Optional filtering options.
|
|
51
|
+
* @returns A structured `VfsDiff` result.
|
|
52
|
+
*/
|
|
53
|
+
export function diffSnapshots(before, after, options = {}) {
|
|
54
|
+
const ignorePrefixes = options.ignore ?? [];
|
|
55
|
+
const shouldIgnore = (path) => ignorePrefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
|
|
56
|
+
const beforeMap = new Map();
|
|
57
|
+
const afterMap = new Map();
|
|
58
|
+
flattenSnapshot(before.root, "", beforeMap);
|
|
59
|
+
flattenSnapshot(after.root, "", afterMap);
|
|
60
|
+
const added = [];
|
|
61
|
+
const removed = [];
|
|
62
|
+
const modified = [];
|
|
63
|
+
// Added — in after, not in before
|
|
64
|
+
for (const [path, node] of afterMap) {
|
|
65
|
+
if (shouldIgnore(path))
|
|
66
|
+
continue;
|
|
67
|
+
if (!beforeMap.has(path)) {
|
|
68
|
+
added.push({ path, type: node.type });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Removed — in before, not in after
|
|
72
|
+
for (const [path, node] of beforeMap) {
|
|
73
|
+
if (shouldIgnore(path))
|
|
74
|
+
continue;
|
|
75
|
+
if (!afterMap.has(path)) {
|
|
76
|
+
removed.push({ path, type: node.type });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Modified — in both, but content or mode changed
|
|
80
|
+
for (const [path, afterNode] of afterMap) {
|
|
81
|
+
if (shouldIgnore(path))
|
|
82
|
+
continue;
|
|
83
|
+
const beforeNode = beforeMap.get(path);
|
|
84
|
+
if (!beforeNode)
|
|
85
|
+
continue; // already in added
|
|
86
|
+
if (afterNode.type !== beforeNode.type)
|
|
87
|
+
continue; // type change = add+remove
|
|
88
|
+
if (afterNode.type === "file" && beforeNode.type === "file") {
|
|
89
|
+
const beforeContent = decodeContent(beforeNode);
|
|
90
|
+
const afterContent = decodeContent(afterNode);
|
|
91
|
+
const modeChanged = afterNode.mode !== beforeNode.mode;
|
|
92
|
+
if (beforeContent !== afterContent || modeChanged) {
|
|
93
|
+
modified.push({
|
|
94
|
+
path,
|
|
95
|
+
type: "file",
|
|
96
|
+
before: beforeContent,
|
|
97
|
+
after: afterContent,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Sort all arrays for determinism
|
|
103
|
+
const sortByPath = (a, b) => a.path.localeCompare(b.path);
|
|
104
|
+
added.sort(sortByPath);
|
|
105
|
+
removed.sort(sortByPath);
|
|
106
|
+
modified.sort(sortByPath);
|
|
107
|
+
return {
|
|
108
|
+
added,
|
|
109
|
+
removed,
|
|
110
|
+
modified,
|
|
111
|
+
clean: added.length === 0 && removed.length === 0 && modified.length === 0,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Format a `VfsDiff` as a human-readable string similar to `git diff --stat`.
|
|
116
|
+
*
|
|
117
|
+
* @param diff Result from `diffSnapshots`.
|
|
118
|
+
* @param options Formatting options.
|
|
119
|
+
*/
|
|
120
|
+
export function formatDiff(diff, options = {}) {
|
|
121
|
+
if (diff.clean)
|
|
122
|
+
return "(no changes)";
|
|
123
|
+
const { showContent = false, maxContentChars = 120 } = options;
|
|
124
|
+
const lines = [];
|
|
125
|
+
for (const entry of diff.added) {
|
|
126
|
+
lines.push(`+ ${entry.path} [${entry.type}]`);
|
|
127
|
+
}
|
|
128
|
+
for (const entry of diff.removed) {
|
|
129
|
+
lines.push(`- ${entry.path} [${entry.type}]`);
|
|
130
|
+
}
|
|
131
|
+
for (const entry of diff.modified) {
|
|
132
|
+
lines.push(`~ ${entry.path} [modified]`);
|
|
133
|
+
if (showContent) {
|
|
134
|
+
const before = entry.before.slice(0, maxContentChars);
|
|
135
|
+
const after = entry.after.slice(0, maxContentChars);
|
|
136
|
+
lines.push(` before: ${JSON.stringify(before)}${entry.before.length > maxContentChars ? "…" : ""}`);
|
|
137
|
+
lines.push(` after: ${JSON.stringify(after)}${entry.after.length > maxContentChars ? "…" : ""}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const summary = [
|
|
141
|
+
diff.added.length > 0 ? `${diff.added.length} added` : "",
|
|
142
|
+
diff.removed.length > 0 ? `${diff.removed.length} removed` : "",
|
|
143
|
+
diff.modified.length > 0 ? `${diff.modified.length} modified` : "",
|
|
144
|
+
]
|
|
145
|
+
.filter(Boolean)
|
|
146
|
+
.join(", ");
|
|
147
|
+
lines.push(`\n${summary}`);
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Assert that a diff contains specific paths, throwing on mismatch.
|
|
152
|
+
* Designed for use in test suites.
|
|
153
|
+
*
|
|
154
|
+
* @param diff Result from `diffSnapshots`.
|
|
155
|
+
* @param expect Expected paths in each category.
|
|
156
|
+
* @throws When any expectation is not met.
|
|
157
|
+
*/
|
|
158
|
+
export function assertDiff(diff, expect) {
|
|
159
|
+
const addedPaths = diff.added.map((e) => e.path);
|
|
160
|
+
const removedPaths = diff.removed.map((e) => e.path);
|
|
161
|
+
const modifiedPaths = diff.modified.map((e) => e.path);
|
|
162
|
+
for (const path of expect.added ?? []) {
|
|
163
|
+
if (!addedPaths.includes(path)) {
|
|
164
|
+
throw new Error(`assertDiff: expected "${path}" to be added, but it was not.\nAdded: ${JSON.stringify(addedPaths)}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
for (const path of expect.removed ?? []) {
|
|
168
|
+
if (!removedPaths.includes(path)) {
|
|
169
|
+
throw new Error(`assertDiff: expected "${path}" to be removed, but it was not.\nRemoved: ${JSON.stringify(removedPaths)}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
for (const path of expect.modified ?? []) {
|
|
173
|
+
if (!modifiedPaths.includes(path)) {
|
|
174
|
+
throw new Error(`assertDiff: expected "${path}" to be modified, but it was not.\nModified: ${JSON.stringify(modifiedPaths)}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.3.0",
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"build": "tsc --project tsconfig.json",
|
|
30
30
|
"deploy:npm": "npm publish --access public",
|
|
31
31
|
"bench": "rm -rf .benchmark-shells/ && bun benchmark-virtualshell.ts",
|
|
32
|
+
"standalone-build:wo-sftp": "bunx esbuild src/standalone-wo-sftp.ts --bundle --platform=node --target=node18 --outfile=standalone-wo-sftp.js --tree-shaking=true --minify --sourcemap",
|
|
32
33
|
"publish-package": "bash ./scripts/publish-package.sh",
|
|
33
34
|
"standalone-build": "bunx esbuild src/standalone.ts --bundle --platform=node --target=node18 --outfile=standalone.js --tree-shaking=true --minify --sourcemap"
|
|
34
35
|
},
|
package/src/SSHMimic/exec.ts
CHANGED
|
@@ -17,7 +17,16 @@ export function runExec(
|
|
|
17
17
|
shell: VirtualShell,
|
|
18
18
|
): void {
|
|
19
19
|
Promise.resolve(
|
|
20
|
-
runCommand(
|
|
20
|
+
runCommand(
|
|
21
|
+
cmd,
|
|
22
|
+
authUser,
|
|
23
|
+
hostname,
|
|
24
|
+
"exec",
|
|
25
|
+
`/home/${authUser}`,
|
|
26
|
+
shell,
|
|
27
|
+
undefined,
|
|
28
|
+
makeDefaultEnv(authUser, hostname),
|
|
29
|
+
),
|
|
21
30
|
)
|
|
22
31
|
.then((result) => {
|
|
23
32
|
if (result.stdout) {
|
package/src/SSHMimic/executor.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { runCommandDirect } from "../commands";
|
|
2
2
|
import { resolvePath } from "../commands/helpers";
|
|
3
3
|
import type { CommandMode, CommandResult, ShellEnv } from "../types/commands";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
Pipeline,
|
|
6
|
+
PipelineCommand,
|
|
7
|
+
Script,
|
|
8
|
+
Statement,
|
|
9
|
+
} from "../types/pipeline";
|
|
5
10
|
import type { VirtualShell } from "../VirtualShell";
|
|
6
11
|
|
|
7
12
|
// ── Script executor (handles &&/||/;) ────────────────────────────────────────
|
|
@@ -15,17 +20,30 @@ export async function executeScript(
|
|
|
15
20
|
shell: VirtualShell,
|
|
16
21
|
env: ShellEnv,
|
|
17
22
|
): Promise<CommandResult> {
|
|
18
|
-
if (!script.isValid)
|
|
23
|
+
if (!script.isValid)
|
|
24
|
+
return { stderr: script.error || "Syntax error", exitCode: 1 };
|
|
19
25
|
|
|
20
26
|
let lastResult: CommandResult = { exitCode: 0 };
|
|
21
27
|
|
|
22
28
|
for (const stmt of script.statements) {
|
|
23
29
|
// Decide whether to run this statement based on previous op
|
|
24
|
-
lastResult = await executePipeline(
|
|
30
|
+
lastResult = await executePipeline(
|
|
31
|
+
stmt.pipeline,
|
|
32
|
+
authUser,
|
|
33
|
+
hostname,
|
|
34
|
+
mode,
|
|
35
|
+
cwd,
|
|
36
|
+
shell,
|
|
37
|
+
env,
|
|
38
|
+
);
|
|
25
39
|
env.lastExitCode = lastResult.exitCode ?? 0;
|
|
26
40
|
|
|
27
41
|
// Propagate session-control signals
|
|
28
|
-
if (
|
|
42
|
+
if (
|
|
43
|
+
lastResult.closeSession ||
|
|
44
|
+
lastResult.switchUser ||
|
|
45
|
+
lastResult.nextCwd
|
|
46
|
+
) {
|
|
29
47
|
break;
|
|
30
48
|
}
|
|
31
49
|
}
|
|
@@ -48,7 +66,15 @@ export async function executeStatements(
|
|
|
48
66
|
|
|
49
67
|
while (i < statements.length) {
|
|
50
68
|
const stmt = statements[i]!;
|
|
51
|
-
last = await executePipeline(
|
|
69
|
+
last = await executePipeline(
|
|
70
|
+
stmt.pipeline,
|
|
71
|
+
authUser,
|
|
72
|
+
hostname,
|
|
73
|
+
mode,
|
|
74
|
+
cwd,
|
|
75
|
+
shell,
|
|
76
|
+
env,
|
|
77
|
+
);
|
|
52
78
|
env.lastExitCode = last.exitCode ?? 0;
|
|
53
79
|
|
|
54
80
|
if (last.closeSession || last.switchUser) return last;
|
|
@@ -83,7 +109,8 @@ export async function executePipeline(
|
|
|
83
109
|
shell: VirtualShell,
|
|
84
110
|
env?: ShellEnv,
|
|
85
111
|
): Promise<CommandResult> {
|
|
86
|
-
if (!pipeline.isValid)
|
|
112
|
+
if (!pipeline.isValid)
|
|
113
|
+
return { stderr: pipeline.error || "Syntax error", exitCode: 1 };
|
|
87
114
|
if (pipeline.commands.length === 0) return { exitCode: 0 };
|
|
88
115
|
|
|
89
116
|
const shellEnv: ShellEnv = env ?? { vars: {}, lastExitCode: 0 };
|
|
@@ -91,13 +118,23 @@ export async function executePipeline(
|
|
|
91
118
|
if (pipeline.commands.length === 1) {
|
|
92
119
|
return executeSingleCommandWithRedirections(
|
|
93
120
|
pipeline.commands[0] as PipelineCommand,
|
|
94
|
-
authUser,
|
|
121
|
+
authUser,
|
|
122
|
+
hostname,
|
|
123
|
+
mode,
|
|
124
|
+
cwd,
|
|
125
|
+
shell,
|
|
126
|
+
shellEnv,
|
|
95
127
|
);
|
|
96
128
|
}
|
|
97
129
|
|
|
98
130
|
return executePipelineChain(
|
|
99
131
|
pipeline.commands as PipelineCommand[],
|
|
100
|
-
authUser,
|
|
132
|
+
authUser,
|
|
133
|
+
hostname,
|
|
134
|
+
mode,
|
|
135
|
+
cwd,
|
|
136
|
+
shell,
|
|
137
|
+
shellEnv,
|
|
101
138
|
);
|
|
102
139
|
}
|
|
103
140
|
|
|
@@ -113,25 +150,51 @@ async function executeSingleCommandWithRedirections(
|
|
|
113
150
|
let stdin: string | undefined;
|
|
114
151
|
if (cmd.inputFile) {
|
|
115
152
|
const inputPath = resolvePath(cwd, cmd.inputFile);
|
|
116
|
-
try {
|
|
117
|
-
|
|
153
|
+
try {
|
|
154
|
+
stdin = shell.vfs.readFile(inputPath);
|
|
155
|
+
} catch {
|
|
156
|
+
return {
|
|
157
|
+
stderr: `${cmd.inputFile}: No such file or directory`,
|
|
158
|
+
exitCode: 1,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
118
161
|
}
|
|
119
162
|
|
|
120
|
-
const result = await runCommandDirect(
|
|
163
|
+
const result = await runCommandDirect(
|
|
164
|
+
cmd.name,
|
|
165
|
+
cmd.args,
|
|
166
|
+
authUser,
|
|
167
|
+
hostname,
|
|
168
|
+
mode,
|
|
169
|
+
cwd,
|
|
170
|
+
shell,
|
|
171
|
+
stdin,
|
|
172
|
+
env,
|
|
173
|
+
);
|
|
121
174
|
|
|
122
175
|
if (cmd.outputFile) {
|
|
123
176
|
const outputPath = resolvePath(cwd, cmd.outputFile);
|
|
124
177
|
const output = result.stdout || "";
|
|
125
178
|
try {
|
|
126
179
|
if (cmd.appendOutput) {
|
|
127
|
-
const existing = (() => {
|
|
180
|
+
const existing = (() => {
|
|
181
|
+
try {
|
|
182
|
+
return shell.vfs.readFile(outputPath);
|
|
183
|
+
} catch {
|
|
184
|
+
return "";
|
|
185
|
+
}
|
|
186
|
+
})();
|
|
128
187
|
shell.writeFileAsUser(authUser, outputPath, existing + output);
|
|
129
188
|
} else {
|
|
130
189
|
shell.writeFileAsUser(authUser, outputPath, output);
|
|
131
190
|
}
|
|
132
191
|
return { ...result, stdout: "" };
|
|
133
192
|
} catch {
|
|
134
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
...result,
|
|
195
|
+
stderr: `Failed to write to ${cmd.outputFile}`,
|
|
196
|
+
exitCode: 1,
|
|
197
|
+
};
|
|
135
198
|
}
|
|
136
199
|
}
|
|
137
200
|
|
|
@@ -155,11 +218,27 @@ async function executePipelineChain(
|
|
|
155
218
|
|
|
156
219
|
if (i === 0 && cmd.inputFile) {
|
|
157
220
|
const inputPath = resolvePath(cwd, cmd.inputFile);
|
|
158
|
-
try {
|
|
159
|
-
|
|
221
|
+
try {
|
|
222
|
+
currentOutput = shell.vfs.readFile(inputPath);
|
|
223
|
+
} catch {
|
|
224
|
+
return {
|
|
225
|
+
stderr: `${cmd.inputFile}: No such file or directory`,
|
|
226
|
+
exitCode: 1,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
160
229
|
}
|
|
161
230
|
|
|
162
|
-
const result = await runCommandDirect(
|
|
231
|
+
const result = await runCommandDirect(
|
|
232
|
+
cmd.name,
|
|
233
|
+
cmd.args,
|
|
234
|
+
authUser,
|
|
235
|
+
hostname,
|
|
236
|
+
mode,
|
|
237
|
+
cwd,
|
|
238
|
+
shell,
|
|
239
|
+
currentOutput,
|
|
240
|
+
env,
|
|
241
|
+
);
|
|
163
242
|
exitCode = result.exitCode ?? 0;
|
|
164
243
|
|
|
165
244
|
if (i === commands.length - 1 && cmd.outputFile) {
|
|
@@ -167,7 +246,13 @@ async function executePipelineChain(
|
|
|
167
246
|
const output = result.stdout || "";
|
|
168
247
|
try {
|
|
169
248
|
if (cmd.appendOutput) {
|
|
170
|
-
const existing = (() => {
|
|
249
|
+
const existing = (() => {
|
|
250
|
+
try {
|
|
251
|
+
return shell.vfs.readFile(outputPath);
|
|
252
|
+
} catch {
|
|
253
|
+
return "";
|
|
254
|
+
}
|
|
255
|
+
})();
|
|
171
256
|
shell.writeFileAsUser(authUser, outputPath, existing + output);
|
|
172
257
|
} else {
|
|
173
258
|
shell.writeFileAsUser(authUser, outputPath, output);
|
|
@@ -180,7 +265,8 @@ async function executePipelineChain(
|
|
|
180
265
|
currentOutput = result.stdout || "";
|
|
181
266
|
}
|
|
182
267
|
|
|
183
|
-
if (result.stderr && exitCode !== 0)
|
|
268
|
+
if (result.stderr && exitCode !== 0)
|
|
269
|
+
return { stderr: result.stderr, exitCode };
|
|
184
270
|
if (result.closeSession || result.switchUser) return result;
|
|
185
271
|
}
|
|
186
272
|
|
package/src/SSHMimic/index.ts
CHANGED
|
@@ -140,7 +140,11 @@ class SshMimic extends EventEmitter {
|
|
|
140
140
|
|
|
141
141
|
// Rate-limit check
|
|
142
142
|
if (this.isLockedOut(remoteAddress)) {
|
|
143
|
-
this.emit("auth:failure", {
|
|
143
|
+
this.emit("auth:failure", {
|
|
144
|
+
username: candidateUser,
|
|
145
|
+
remoteAddress,
|
|
146
|
+
reason: "lockout",
|
|
147
|
+
});
|
|
144
148
|
ctx.reject();
|
|
145
149
|
return;
|
|
146
150
|
}
|
|
@@ -152,7 +156,10 @@ class SshMimic extends EventEmitter {
|
|
|
152
156
|
`User ${candidateUser} has no password set, allowing login without verification`,
|
|
153
157
|
);
|
|
154
158
|
authUser = candidateUser;
|
|
155
|
-
sessionId = shell.users.registerSession(
|
|
159
|
+
sessionId = shell.users.registerSession(
|
|
160
|
+
authUser,
|
|
161
|
+
remoteAddress,
|
|
162
|
+
).id;
|
|
156
163
|
this.recordSuccess(remoteAddress);
|
|
157
164
|
this.emit("auth:success", { username: authUser, remoteAddress });
|
|
158
165
|
this.ensureHomeDir(authUser);
|
|
@@ -166,7 +173,10 @@ class SshMimic extends EventEmitter {
|
|
|
166
173
|
!shell.users.verifyPassword(candidateUser, ctx.password)
|
|
167
174
|
) {
|
|
168
175
|
this.recordFailure(remoteAddress);
|
|
169
|
-
this.emit("auth:failure", {
|
|
176
|
+
this.emit("auth:failure", {
|
|
177
|
+
username: candidateUser,
|
|
178
|
+
remoteAddress,
|
|
179
|
+
});
|
|
170
180
|
ctx.reject();
|
|
171
181
|
return;
|
|
172
182
|
}
|
|
@@ -192,13 +202,16 @@ class SshMimic extends EventEmitter {
|
|
|
192
202
|
const incomingKey = ctx.key;
|
|
193
203
|
const keyMatches = authorizedKeys.some(
|
|
194
204
|
(k) =>
|
|
195
|
-
k.algo === incomingKey.algo &&
|
|
196
|
-
k.data.equals(incomingKey.data),
|
|
205
|
+
k.algo === incomingKey.algo && k.data.equals(incomingKey.data),
|
|
197
206
|
);
|
|
198
207
|
|
|
199
208
|
if (!keyMatches) {
|
|
200
209
|
this.recordFailure(remoteAddress);
|
|
201
|
-
this.emit("auth:failure", {
|
|
210
|
+
this.emit("auth:failure", {
|
|
211
|
+
username: candidateUser,
|
|
212
|
+
remoteAddress,
|
|
213
|
+
method: "publickey",
|
|
214
|
+
});
|
|
202
215
|
ctx.reject();
|
|
203
216
|
return;
|
|
204
217
|
}
|
|
@@ -206,9 +219,16 @@ class SshMimic extends EventEmitter {
|
|
|
206
219
|
// Key matched — if this is a signature check step, accept
|
|
207
220
|
if (ctx.signature) {
|
|
208
221
|
authUser = candidateUser;
|
|
209
|
-
sessionId = shell.users.registerSession(
|
|
222
|
+
sessionId = shell.users.registerSession(
|
|
223
|
+
authUser,
|
|
224
|
+
remoteAddress,
|
|
225
|
+
).id;
|
|
210
226
|
this.recordSuccess(remoteAddress);
|
|
211
|
-
this.emit("auth:success", {
|
|
227
|
+
this.emit("auth:success", {
|
|
228
|
+
username: authUser,
|
|
229
|
+
remoteAddress,
|
|
230
|
+
method: "publickey",
|
|
231
|
+
});
|
|
212
232
|
this.ensureHomeDir(authUser);
|
|
213
233
|
ctx.accept();
|
|
214
234
|
} else {
|
|
@@ -238,20 +258,35 @@ class SshMimic extends EventEmitter {
|
|
|
238
258
|
acceptPty();
|
|
239
259
|
});
|
|
240
260
|
|
|
241
|
-
session.on(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
261
|
+
session.on(
|
|
262
|
+
"window-change",
|
|
263
|
+
(_acceptChange, _rejectChange, info) => {
|
|
264
|
+
terminalSize.cols = info?.cols ?? terminalSize.cols;
|
|
265
|
+
terminalSize.rows = info?.rows ?? terminalSize.rows;
|
|
266
|
+
},
|
|
267
|
+
);
|
|
245
268
|
|
|
246
269
|
session.on("shell", (acceptShell) => {
|
|
247
270
|
const stream = acceptShell();
|
|
248
|
-
shell?.startInteractiveSession(
|
|
271
|
+
shell?.startInteractiveSession(
|
|
272
|
+
stream,
|
|
273
|
+
authUser,
|
|
274
|
+
sessionId,
|
|
275
|
+
remoteAddress,
|
|
276
|
+
terminalSize,
|
|
277
|
+
);
|
|
249
278
|
});
|
|
250
279
|
|
|
251
280
|
session.on("exec", (acceptExec, _rejectExec, info) => {
|
|
252
281
|
const stream = acceptExec();
|
|
253
282
|
if (stream) {
|
|
254
|
-
runExec(
|
|
283
|
+
runExec(
|
|
284
|
+
stream,
|
|
285
|
+
info.command.trim(),
|
|
286
|
+
authUser,
|
|
287
|
+
shell.hostname,
|
|
288
|
+
shell,
|
|
289
|
+
);
|
|
255
290
|
}
|
|
256
291
|
});
|
|
257
292
|
});
|
|
@@ -293,4 +328,3 @@ class SshMimic extends EventEmitter {
|
|
|
293
328
|
|
|
294
329
|
export { SftpMimic } from "./sftp";
|
|
295
330
|
export { SshMimic };
|
|
296
|
-
|