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.
Files changed (281) hide show
  1. package/.vscode/settings.json +0 -1
  2. package/README.md +141 -50
  3. package/biome.json +7 -0
  4. package/dist/SSHMimic/exec.d.ts.map +1 -1
  5. package/dist/SSHMimic/executor.d.ts.map +1 -1
  6. package/dist/SSHMimic/executor.js +32 -16
  7. package/dist/SSHMimic/index.d.ts.map +1 -1
  8. package/dist/SSHMimic/index.js +20 -6
  9. package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -1
  10. package/dist/VirtualFileSystem/binaryPack.js +29 -6
  11. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  12. package/dist/VirtualFileSystem/index.js +36 -13
  13. package/dist/VirtualPackageManager/index.d.ts.map +1 -1
  14. package/dist/VirtualPackageManager/index.js +192 -43
  15. package/dist/VirtualShell/index.d.ts +10 -4
  16. package/dist/VirtualShell/index.d.ts.map +1 -1
  17. package/dist/VirtualShell/index.js +18 -7
  18. package/dist/VirtualShell/shell.d.ts.map +1 -1
  19. package/dist/VirtualShell/shell.js +3 -1
  20. package/dist/VirtualShell/shellParser.d.ts.map +1 -1
  21. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  22. package/dist/commands/adduser.d.ts +6 -0
  23. package/dist/commands/adduser.d.ts.map +1 -1
  24. package/dist/commands/adduser.js +6 -0
  25. package/dist/commands/alias.d.ts +5 -0
  26. package/dist/commands/alias.d.ts.map +1 -1
  27. package/dist/commands/alias.js +5 -0
  28. package/dist/commands/apt.d.ts +5 -0
  29. package/dist/commands/apt.d.ts.map +1 -1
  30. package/dist/commands/apt.js +32 -9
  31. package/dist/commands/awk.d.ts +11 -0
  32. package/dist/commands/awk.d.ts.map +1 -1
  33. package/dist/commands/awk.js +15 -2
  34. package/dist/commands/base64.d.ts +5 -0
  35. package/dist/commands/base64.d.ts.map +1 -1
  36. package/dist/commands/base64.js +9 -1
  37. package/dist/commands/cat.d.ts +5 -0
  38. package/dist/commands/cat.d.ts.map +1 -1
  39. package/dist/commands/cat.js +10 -2
  40. package/dist/commands/cd.d.ts +5 -0
  41. package/dist/commands/cd.d.ts.map +1 -1
  42. package/dist/commands/cd.js +5 -0
  43. package/dist/commands/chmod.d.ts +5 -0
  44. package/dist/commands/chmod.d.ts.map +1 -1
  45. package/dist/commands/chmod.js +5 -0
  46. package/dist/commands/cp.d.ts +5 -0
  47. package/dist/commands/cp.d.ts.map +1 -1
  48. package/dist/commands/cp.js +5 -0
  49. package/dist/commands/curl.d.ts +5 -0
  50. package/dist/commands/curl.d.ts.map +1 -1
  51. package/dist/commands/curl.js +34 -6
  52. package/dist/commands/cut.d.ts +5 -0
  53. package/dist/commands/cut.d.ts.map +1 -1
  54. package/dist/commands/cut.js +8 -1
  55. package/dist/commands/date.d.ts +5 -0
  56. package/dist/commands/date.d.ts.map +1 -1
  57. package/dist/commands/date.js +7 -1
  58. package/dist/commands/declare.d.ts +3 -0
  59. package/dist/commands/declare.d.ts.map +1 -0
  60. package/dist/commands/declare.js +39 -0
  61. package/dist/commands/diff.d.ts +5 -0
  62. package/dist/commands/diff.d.ts.map +1 -1
  63. package/dist/commands/diff.js +5 -0
  64. package/dist/commands/dpkg.d.ts +5 -0
  65. package/dist/commands/dpkg.d.ts.map +1 -1
  66. package/dist/commands/dpkg.js +24 -7
  67. package/dist/commands/du.d.ts.map +1 -1
  68. package/dist/commands/du.js +8 -2
  69. package/dist/commands/echo.d.ts +5 -0
  70. package/dist/commands/echo.d.ts.map +1 -1
  71. package/dist/commands/echo.js +13 -4
  72. package/dist/commands/env.d.ts +5 -0
  73. package/dist/commands/env.d.ts.map +1 -1
  74. package/dist/commands/env.js +11 -1
  75. package/dist/commands/exit.d.ts +5 -0
  76. package/dist/commands/exit.d.ts.map +1 -1
  77. package/dist/commands/exit.js +12 -2
  78. package/dist/commands/export.d.ts.map +1 -1
  79. package/dist/commands/export.js +3 -1
  80. package/dist/commands/find.d.ts +5 -0
  81. package/dist/commands/find.d.ts.map +1 -1
  82. package/dist/commands/find.js +5 -0
  83. package/dist/commands/free.d.ts +5 -0
  84. package/dist/commands/free.d.ts.map +1 -1
  85. package/dist/commands/free.js +5 -0
  86. package/dist/commands/grep.d.ts +5 -0
  87. package/dist/commands/grep.d.ts.map +1 -1
  88. package/dist/commands/grep.js +12 -2
  89. package/dist/commands/gzip.d.ts +5 -0
  90. package/dist/commands/gzip.d.ts.map +1 -1
  91. package/dist/commands/gzip.js +18 -2
  92. package/dist/commands/head.d.ts +5 -0
  93. package/dist/commands/head.d.ts.map +1 -1
  94. package/dist/commands/head.js +5 -0
  95. package/dist/commands/help.d.ts.map +1 -1
  96. package/dist/commands/help.js +98 -45
  97. package/dist/commands/history.d.ts +5 -0
  98. package/dist/commands/history.d.ts.map +1 -1
  99. package/dist/commands/history.js +5 -0
  100. package/dist/commands/hostname.d.ts +5 -0
  101. package/dist/commands/hostname.d.ts.map +1 -1
  102. package/dist/commands/hostname.js +5 -0
  103. package/dist/commands/id.d.ts.map +1 -1
  104. package/dist/commands/id.js +4 -1
  105. package/dist/commands/index.d.ts +2 -17
  106. package/dist/commands/index.d.ts.map +1 -1
  107. package/dist/commands/index.js +2 -340
  108. package/dist/commands/ls.d.ts.map +1 -1
  109. package/dist/commands/ls.js +3 -1
  110. package/dist/commands/lsb-release.d.ts.map +1 -1
  111. package/dist/commands/lsb-release.js +8 -2
  112. package/dist/commands/nano.js +1 -1
  113. package/dist/commands/neofetch.js +1 -1
  114. package/dist/commands/node.d.ts +9 -0
  115. package/dist/commands/node.d.ts.map +1 -0
  116. package/dist/commands/node.js +316 -0
  117. package/dist/commands/npm.d.ts +19 -0
  118. package/dist/commands/npm.d.ts.map +1 -0
  119. package/dist/commands/npm.js +109 -0
  120. package/dist/commands/ping.d.ts.map +1 -1
  121. package/dist/commands/ping.js +3 -1
  122. package/dist/commands/printf.d.ts +3 -0
  123. package/dist/commands/printf.d.ts.map +1 -0
  124. package/dist/commands/printf.js +113 -0
  125. package/dist/commands/ps.d.ts.map +1 -1
  126. package/dist/commands/ps.js +4 -1
  127. package/dist/commands/python.d.ts +30 -0
  128. package/dist/commands/python.d.ts.map +1 -0
  129. package/dist/commands/python.js +2058 -0
  130. package/dist/commands/read.d.ts +3 -0
  131. package/dist/commands/read.d.ts.map +1 -0
  132. package/dist/commands/read.js +34 -0
  133. package/dist/commands/registry.d.ts +8 -0
  134. package/dist/commands/registry.d.ts.map +1 -0
  135. package/dist/commands/registry.js +229 -0
  136. package/dist/commands/runtime.d.ts +6 -0
  137. package/dist/commands/runtime.d.ts.map +1 -0
  138. package/dist/commands/runtime.js +280 -0
  139. package/dist/commands/sed.d.ts.map +1 -1
  140. package/dist/commands/sed.js +11 -3
  141. package/dist/commands/set.d.ts.map +1 -1
  142. package/dist/commands/set.js +9 -3
  143. package/dist/commands/sh.d.ts.map +1 -1
  144. package/dist/commands/sh.js +57 -36
  145. package/dist/commands/shift.d.ts +5 -0
  146. package/dist/commands/shift.d.ts.map +1 -0
  147. package/dist/commands/shift.js +52 -0
  148. package/dist/commands/sleep.d.ts.map +1 -1
  149. package/dist/commands/sort.d.ts.map +1 -1
  150. package/dist/commands/sort.js +4 -2
  151. package/dist/commands/source.d.ts.map +1 -1
  152. package/dist/commands/source.js +5 -2
  153. package/dist/commands/sudo.js +1 -1
  154. package/dist/commands/tar.d.ts.map +1 -1
  155. package/dist/commands/tar.js +11 -3
  156. package/dist/commands/tee.d.ts.map +1 -1
  157. package/dist/commands/tee.js +8 -6
  158. package/dist/commands/test.d.ts.map +1 -1
  159. package/dist/commands/test.js +46 -24
  160. package/dist/commands/tr.d.ts.map +1 -1
  161. package/dist/commands/tr.js +3 -1
  162. package/dist/commands/true.d.ts +4 -0
  163. package/dist/commands/true.d.ts.map +1 -0
  164. package/dist/commands/true.js +14 -0
  165. package/dist/commands/type.d.ts.map +1 -1
  166. package/dist/commands/type.js +1 -1
  167. package/dist/commands/uname.d.ts.map +1 -1
  168. package/dist/commands/uname.js +4 -1
  169. package/dist/commands/uniq.d.ts.map +1 -1
  170. package/dist/commands/uptime.d.ts.map +1 -1
  171. package/dist/commands/uptime.js +4 -1
  172. package/dist/commands/wget.d.ts.map +1 -1
  173. package/dist/commands/wget.js +32 -7
  174. package/dist/commands/which.d.ts.map +1 -1
  175. package/dist/commands/xargs.d.ts.map +1 -1
  176. package/dist/commands/xargs.js +1 -1
  177. package/dist/index.d.ts +15 -14
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +9 -9
  180. package/dist/modules/linuxRootfs.d.ts +18 -1
  181. package/dist/modules/linuxRootfs.d.ts.map +1 -1
  182. package/dist/modules/linuxRootfs.js +160 -17
  183. package/dist/standalone-wo-sftp.d.ts +2 -0
  184. package/dist/standalone-wo-sftp.d.ts.map +1 -0
  185. package/dist/standalone-wo-sftp.js +30 -0
  186. package/dist/utils/expand.d.ts +50 -0
  187. package/dist/utils/expand.d.ts.map +1 -0
  188. package/dist/utils/expand.js +183 -0
  189. package/dist/utils/vfsDiff.d.ts +90 -0
  190. package/dist/utils/vfsDiff.d.ts.map +1 -0
  191. package/dist/utils/vfsDiff.js +177 -0
  192. package/package.json +2 -1
  193. package/src/SSHMimic/exec.ts +10 -1
  194. package/src/SSHMimic/executor.ts +104 -18
  195. package/src/SSHMimic/index.ts +49 -15
  196. package/src/VirtualFileSystem/binaryPack.ts +35 -8
  197. package/src/VirtualFileSystem/index.ts +78 -28
  198. package/src/VirtualPackageManager/index.ts +208 -49
  199. package/src/VirtualShell/index.ts +35 -7
  200. package/src/VirtualShell/shell.ts +23 -3
  201. package/src/VirtualShell/shellParser.ts +134 -36
  202. package/src/VirtualUserManager/index.ts +7 -2
  203. package/src/commands/adduser.ts +6 -0
  204. package/src/commands/alias.ts +5 -1
  205. package/src/commands/apt.ts +47 -17
  206. package/src/commands/awk.ts +20 -6
  207. package/src/commands/base64.ts +13 -2
  208. package/src/commands/cat.ts +13 -5
  209. package/src/commands/cd.ts +5 -0
  210. package/src/commands/chmod.ts +5 -0
  211. package/src/commands/cp.ts +5 -0
  212. package/src/commands/curl.ts +56 -12
  213. package/src/commands/cut.ts +8 -1
  214. package/src/commands/date.ts +7 -1
  215. package/src/commands/declare.ts +44 -0
  216. package/src/commands/diff.ts +17 -3
  217. package/src/commands/dpkg.ts +33 -11
  218. package/src/commands/du.ts +17 -5
  219. package/src/commands/echo.ts +22 -9
  220. package/src/commands/env.ts +11 -1
  221. package/src/commands/exit.ts +12 -2
  222. package/src/commands/export.ts +3 -1
  223. package/src/commands/find.ts +5 -0
  224. package/src/commands/free.ts +9 -2
  225. package/src/commands/grep.ts +12 -2
  226. package/src/commands/gzip.ts +28 -4
  227. package/src/commands/head.ts +5 -0
  228. package/src/commands/help.ts +121 -47
  229. package/src/commands/history.ts +7 -2
  230. package/src/commands/hostname.ts +5 -0
  231. package/src/commands/id.ts +4 -1
  232. package/src/commands/index.ts +9 -360
  233. package/src/commands/ls.ts +5 -3
  234. package/src/commands/lsb-release.ts +8 -2
  235. package/src/commands/nano.ts +1 -1
  236. package/src/commands/neofetch.ts +1 -1
  237. package/src/commands/node.ts +341 -0
  238. package/src/commands/npm.ts +132 -0
  239. package/src/commands/ping.ts +6 -2
  240. package/src/commands/printf.ts +112 -0
  241. package/src/commands/ps.ts +21 -9
  242. package/src/commands/python.ts +2229 -0
  243. package/src/commands/read.ts +41 -0
  244. package/src/commands/registry.ts +244 -0
  245. package/src/commands/runtime.ts +353 -0
  246. package/src/commands/sed.ts +27 -9
  247. package/src/commands/set.ts +9 -3
  248. package/src/commands/sh.ts +159 -55
  249. package/src/commands/shift.ts +53 -0
  250. package/src/commands/sleep.ts +2 -1
  251. package/src/commands/sort.ts +10 -6
  252. package/src/commands/source.ts +15 -3
  253. package/src/commands/sudo.ts +1 -1
  254. package/src/commands/tar.ts +28 -7
  255. package/src/commands/tee.ts +7 -1
  256. package/src/commands/test.ts +61 -26
  257. package/src/commands/tr.ts +3 -1
  258. package/src/commands/true.ts +17 -0
  259. package/src/commands/type.ts +6 -3
  260. package/src/commands/uname.ts +5 -1
  261. package/src/commands/uniq.ts +8 -2
  262. package/src/commands/uptime.ts +4 -1
  263. package/src/commands/wget.ts +51 -12
  264. package/src/commands/which.ts +5 -2
  265. package/src/commands/xargs.ts +11 -2
  266. package/src/index.ts +23 -24
  267. package/src/modules/linuxRootfs.ts +233 -30
  268. package/src/standalone-wo-sftp.ts +38 -0
  269. package/src/utils/expand.ts +238 -0
  270. package/src/utils/vfsDiff.ts +275 -0
  271. package/standalone-wo-sftp.js +507 -0
  272. package/standalone-wo-sftp.js.map +7 -0
  273. package/standalone.js +253 -191
  274. package/standalone.js.map +4 -4
  275. package/tests/bun-test-shim.ts +9 -1
  276. package/tests/command-helpers.test.ts +1 -5
  277. package/tests/new-features.test.ts +415 -5
  278. package/tests/parser-executor.test.ts +27 -27
  279. package/tests/sftp.test.ts +122 -42
  280. package/tests/users.test.ts +23 -5
  281. package/CHANGELOG.md +0 -150
@@ -12,7 +12,6 @@
12
12
 
13
13
  "LICENSE": true,
14
14
  "*.md": true,
15
- "biome.json": true,
16
15
  "tsconfig.tsbuildinfo": true
17
16
  }
18
17
  }
package/README.md CHANGED
@@ -2,26 +2,6 @@
2
2
 
3
3
  > Pure in-memory SSH/SFTP server with a realistic Linux rootfs, a virtual package manager, a real shell interpreter, and a typed programmatic API for testing, automation, honeypots, and interactive shell scripting in TypeScript/JavaScript.
4
4
 
5
- ---
6
-
7
- > **Release notes — what changed in this drop**
8
- >
9
- > **Linux rootfs** — full `/etc`, `/proc`, `/sys`, `/dev`, `/usr`, `/var` hierarchy bootstrapped at init. `neofetch` now shows real uptime and package count. `/proc/meminfo`, `/proc/cpuinfo`, `/proc/version` populated from live system data. `/etc/passwd`, `/etc/group`, `/etc/shadow` synced from `VirtualUserManager`.
10
- >
11
- > **Virtual package manager** — `apt install vim git nodejs python3` works. 25 packages in the built-in registry. Dependency resolution, file installation into VFS, `/var/lib/dpkg/status` persistence, `dpkg -l|-s|-L`, `apt-cache search|show|policy`. `neofetch` reflects installed count.
12
- >
13
- > **`curl` / `wget` — pure `fetch()`** — host binary no longer spawned. Full flag support (`-o`, `-X`, `-d`, `-H`, `-s`, `-I`, `-L`, `-v` for curl; `-O`, `-P`, `-q` for wget). Zero host filesystem access.
14
- >
15
- > **New commands** — `which`, `type`, `man` (with built-in pages), `uptime`, `free`, `lsb_release`, `alias`, `unalias`.
16
- >
17
- > **`$(cmd)` command substitution** — `echo $(whoami)`, `mkdir /tmp/$(date +%s)`, nested subs, all work.
18
- >
19
- > **Alias expansion** — `alias ll='ls -la'` then `ll /etc` resolves transparently in the dispatcher.
20
- >
21
- > *— written by Claude because explaining every change manually is a waste of everyone's time*
22
-
23
- ---
24
-
25
5
  [![npm version](https://badge.fury.io/js/typescript-virtual-container.svg)](https://www.npmjs.com/package/typescript-virtual-container)
26
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
27
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
@@ -82,7 +62,7 @@
82
62
  - **Security Auditing**: Built-in `HoneyPot` utility for comprehensive activity logging, event tracking, statistics collection, and anomaly detection across all components.
83
63
  - **Linux rootfs on boot**: Realistic `/etc`, `/proc`, `/sys`, `/dev`, `/usr`, `/var` hierarchy populated at startup — `os-release`, `passwd`, `hosts`, `resolv.conf`, `/proc/meminfo`, `/proc/cpuinfo`, and more.
84
64
  - **Virtual package manager**: `apt install`, `apt remove`, `apt search`, `dpkg -l`, `dpkg -s` — 25 packages in the built-in registry (vim, git, nodejs, python3, curl, openssh, gcc…). Writes files into VFS, tracks state in `/var/lib/dpkg/status`.
85
- - **90+ Built-in Commands**: Full navigation, text processing, archiving, system info, package management, and user management commands — grouped and documented in the interactive `help` system.
65
+ - **87 Built-in Commands**: Full navigation, text processing, archiving, system info, package management, and user management commands — grouped and documented in the interactive `help` system.
86
66
  - **`$(cmd)` command substitution**: Nested command execution in any argument position.
87
67
  - **Alias support**: `alias`, `unalias` — persisted in session environment.
88
68
  - **Full TypeScript Support**: Complete JSDoc coverage, exported types, and first-class async/await for all operations.
@@ -804,6 +784,77 @@ interface InstalledPackage {
804
784
 
805
785
  ---
806
786
 
787
+ ### Snapshot Diff Tooling
788
+
789
+ Three utility functions for comparing VFS snapshots in tests and deployment verification.
790
+
791
+ ```typescript
792
+ import {
793
+ diffSnapshots,
794
+ formatDiff,
795
+ assertDiff,
796
+ } from "typescript-virtual-container";
797
+ ```
798
+
799
+ #### `diffSnapshots(before, after, options?): VfsDiff`
800
+
801
+ Compares two snapshots and returns structured diff results.
802
+
803
+ ```ts
804
+ const before = shell.vfs.toSnapshot();
805
+ await client.exec("apt install vim && mkdir -p /app");
806
+ const after = shell.vfs.toSnapshot();
807
+
808
+ const diff = diffSnapshots(before, after, {
809
+ ignore: ["/proc", "/var/log"], // skip volatile paths
810
+ });
811
+
812
+ diff.clean; // false
813
+ diff.added; // [{ path: "/usr/bin/vim", type: "file" }, ...]
814
+ diff.removed; // []
815
+ diff.modified; // [{ path: "/var/lib/dpkg/status", before: "...", after: "..." }]
816
+ ```
817
+
818
+ #### `formatDiff(diff, options?): string`
819
+
820
+ Human-readable output similar to `git diff --stat`.
821
+
822
+ ```ts
823
+ console.log(formatDiff(diff));
824
+ // + /app [directory]
825
+ // + /usr/bin/vim [file]
826
+ // ~ /var/lib/dpkg/status [modified]
827
+ //
828
+ // 2 added, 1 modified
829
+
830
+ console.log(formatDiff(diff, { showContent: true, maxContentChars: 80 }));
831
+ ```
832
+
833
+ #### `assertDiff(diff, expected): void`
834
+
835
+ Throws on mismatch — designed for test suites.
836
+
837
+ ```ts
838
+ assertDiff(diff, {
839
+ added: ["/app", "/usr/bin/vim"],
840
+ modified: ["/var/lib/dpkg/status"],
841
+ });
842
+ // throws if any expected path is not in the diff
843
+ ```
844
+
845
+ #### Types
846
+
847
+ ```ts
848
+ interface VfsDiff {
849
+ added: VfsDiffEntry[]; // { path, type }
850
+ removed: VfsDiffEntry[]; // { path, type }
851
+ modified: VfsDiffModified[]; // { path, type, before, after }
852
+ clean: boolean;
853
+ }
854
+ ```
855
+
856
+ ---
857
+
807
858
  ### `HoneyPot`
808
859
 
809
860
  Comprehensive security auditing and event tracking utility. Attaches listeners to all core components to log activity, track statistics, and detect anomalies.
@@ -1475,6 +1526,9 @@ On every `VirtualShell` init, a realistic Linux directory hierarchy is bootstrap
1475
1526
  │ ├── resolv.conf 1.1.1.1 + 8.8.8.8
1476
1527
  │ └── shadow (mode 0o640)
1477
1528
  ├── proc/
1529
+ │ ├── 1/ init process (cmdline, status, comm, environ, fd/)
1530
+ │ ├── <pid>/ one entry per active session (based on pts/* TTY)
1531
+ │ ├── self/ mirrors the most recent session's /proc/<pid>/
1478
1532
  │ ├── cpuinfo real host CPU info
1479
1533
  │ ├── loadavg
1480
1534
  │ ├── meminfo real host memory
@@ -1617,6 +1671,7 @@ All commands are available in SSH shell mode and via `SshClient.exec()`. Type `h
1617
1671
  | `mkdir <path>` | `-p` | Create directory |
1618
1672
  | `mv <src> <dest>` | | Move or rename |
1619
1673
  | `rm <path>` | `-r` | Remove file or directory |
1674
+ | `nano <path>` | | Interactive text editor |
1620
1675
  | `touch <path>` | | Create or update file |
1621
1676
 
1622
1677
  ### Text Processing
@@ -1661,6 +1716,8 @@ All commands are available in SSH shell mode and via `SshClient.exec()`. Type `h
1661
1716
  | `free` | `-h` `-m` `-g` | Display free and used memory |
1662
1717
  | `lsb_release` | `-a` `-i` `-d` `-r` `-c` | Print distribution information |
1663
1718
  | `neofetch` | | System info display (shows real packages/uptime) |
1719
+ | `node` | `--version` `-e` `-p` | JavaScript runtime (virtual REPL — evaluates expressions and VFS `.js` files) |
1720
+ | `python3` | `--version` `-c` `-V` | Python 3 interpreter (virtual REPL — evaluates expressions and VFS `.py` files); alias `python` |
1664
1721
  | `uptime` | `-p` `-s` | Tell how long the system has been running |
1665
1722
  | `ping [-c <n>] <host>` | | Send ICMP ECHO_REQUEST (mock) |
1666
1723
  | `ps` | `-a` `-u` `-x` `aux` | Report process status; `-u` / `aux` shows USER/PID/%CPU/%MEM columns |
@@ -1682,20 +1739,31 @@ All commands are available in SSH shell mode and via `SshClient.exec()`. Type `h
1682
1739
  |---------|-------|-------------|
1683
1740
  | `alias [name=value]` | | Define or display aliases |
1684
1741
  | `clear` | | Clear terminal screen (full ANSI reset) |
1685
- | `echo <text>` | `-n` `-e` | Display text; `-n` suppresses newline, `-e` interprets escape sequences (`\n`, `\t`, `\r`, `\\`) |
1742
+ | `declare [name=value]` | `-i` `-r` `-x` | Declare variables with attributes; aliases `local`, `typeset` |
1743
+ | `echo <text>` | `-n` `-e` | Display text; `-n` suppresses newline, `-e` interprets `\n` `\t` `\r` `\\` |
1686
1744
  | `env` | | Print session environment variables |
1687
- | `exit [code]` | | Exit session |
1745
+ | `exit [code]` | | Exit session with optional exit code |
1688
1746
  | `export NAME=VALUE` | | Set shell variable in current session |
1689
- | `help [command]` | | List commands (grouped) or show command details |
1690
- | `set [VAR=val]` | | Display or set shell variables |
1691
- | `sh` | `-c <script>` `[file]` | Execute shell script (supports if/for/while/do/done); `$(cmd)` substitution inside single-quoted args is preserved |
1747
+ | `help [command]` | | List commands grouped by category, or show usage for a specific command |
1692
1748
  | `history [n]` | | Display command history (last N entries) |
1693
- | `source <file>` | | Execute file in current shell environment (aliases and exports persist) |
1749
+ | `man <command>` | | Display command reference manual |
1750
+ | `printf <fmt> [args...]` | | Format and print data (`%s` `%d` `%f` `%x` `\n` `\t`) |
1751
+ | `read [-r] <var...>` | `-r` `-p` | Read a line from stdin into variable(s) |
1752
+ | `return [n]` | | Return from a shell function with optional exit code |
1753
+ | `set [VAR=val]` | | Display or set shell variables |
1754
+ | `sh` | `-c <script>` `[file]` | Execute shell script — supports `if`/`for`/`while`/`case`/functions, bare `VAR=val` assignments, `$((expr))` arithmetic; single-quoted args are never expanded |
1755
+ | `shift [n]` | | Shift positional parameters left by n (default 1) |
1756
+ | `source <file>` | | Execute file in current shell environment; aliases and exports persist |
1694
1757
  | `. <file>` | | Alias for `source` |
1695
- | `test <expr>` | | Evaluate conditional expression |
1696
- | `[ <expr> ]` | | Alias for `test` supports `-f`, `-d`, `-e`, `-z`, `-n`, `=`, `!=`, `-eq`, `-lt`, `-gt`, etc. |
1758
+ | `test <expr>` | | Evaluate POSIX conditional expression |
1759
+ | `[ <expr> ]` | | Alias for `test`; supports `-f` `-d` `-e` `-z` `-n` `-x` `-s` `=` `!=` `-eq` `-lt` `-gt` `-le` `-ge` `!` `-a` `-o` |
1760
+ | `trap [action] [signal]` | | Register handler for shell signals; supports `EXIT` |
1761
+ | `true` | | Return success exit code (0) |
1762
+ | `false` | | Return failure exit code (1) |
1763
+ | `type <command>` | | Describe how a command would be interpreted (builtin vs PATH) |
1697
1764
  | `unalias <name>` | `-a` | Remove alias definitions |
1698
1765
  | `unset <VAR>` | | Remove shell variable |
1766
+ | `which <command>` | | Locate a command in the session PATH |
1699
1767
 
1700
1768
  ### Package Management
1701
1769
 
@@ -1707,15 +1775,6 @@ All commands are available in SSH shell mode and via `SshClient.exec()`. Type `h
1707
1775
  | `dpkg` | `-l` `-s` `-L` `-r` `-P` | Debian package manager low-level tool |
1708
1776
  | `dpkg-query` | `-W` `-l` | Show information about installed packages |
1709
1777
 
1710
- ### Shell (extended)
1711
-
1712
- | Command | Flags | Description |
1713
- |---------|-------|-------------|
1714
- | `alias [name=value]` | | Define or display aliases |
1715
- | `man <command>` | | Display command manual page |
1716
- | `type <command>` | | Describe how command is interpreted |
1717
- | `unalias <name>` | `-a` | Remove alias definitions |
1718
- | `which <command>` | | Locate command in PATH |
1719
1778
 
1720
1779
  ### Users & Permissions
1721
1780
 
@@ -1723,7 +1782,6 @@ All commands are available in SSH shell mode and via `SshClient.exec()`. Type `h
1723
1782
  |---------|-------|-------------|
1724
1783
  | `adduser <name> <pass>` | | Create user (root only) |
1725
1784
  | `deluser <name>` | | Delete user (root only) |
1726
- | `nano <path>` | | Interactive text editor |
1727
1785
  | `passwd [user]` | | Change password |
1728
1786
  | `su [user]` | | Switch user |
1729
1787
  | `sudo <cmd>` | `-i` | Run as root |
@@ -1758,11 +1816,34 @@ cat /tmp/out.txt >> /tmp/log.txt
1758
1816
  ```bash
1759
1817
  export NAME=world
1760
1818
  echo "Hello $NAME" # Hello world
1819
+ echo "${NAME}" # world (braced form)
1761
1820
  echo "${NAME:-fallback}" # world (or fallback if unset)
1762
- echo "${UNSET:-default}" # default
1763
- echo "Exit: $?" # last exit code
1821
+ echo "${UNSET:-default}" # default (assign-on-read: use ${UNSET:=default})
1822
+ echo "${NAME:+alternate}" # alternate (only if NAME is set)
1823
+ echo "${#NAME}" # 5 (string length)
1824
+ echo "$?" # last exit code
1825
+ echo "~" # /home/<user> (tilde expansion)
1826
+ ```
1827
+
1828
+ ### Arithmetic Expansion
1829
+
1830
+ ```bash
1831
+ echo $((2 + 3)) # 5
1832
+ echo $((10 % 3)) # 1
1833
+ X=4; echo $((X * 2)) # 8
1834
+ i=0; i=$((i + 1)); echo $i # 1
1835
+
1836
+ # In loops (via sh):
1837
+ sh -c 'i=0
1838
+ while [ $i -lt 5 ]; do
1839
+ echo $i
1840
+ i=$((i + 1))
1841
+ done'
1764
1842
  ```
1765
1843
 
1844
+ > **Single-quote isolation** — variable and arithmetic expansion never occurs inside single quotes.
1845
+ > `echo '$NAME'` always outputs the literal string `$NAME`.
1846
+
1766
1847
  ### Conditionals
1767
1848
 
1768
1849
  ```bash
@@ -2115,13 +2196,23 @@ MIT — see [LICENSE](./LICENSE).
2115
2196
  - [x] `>>` append redirect fixed — was broken because `echo` lacked terminal newline
2116
2197
  - [x] `export A=1 && echo $A` — env vars visible to subsequent commands in same pipeline
2117
2198
  - [x] `echo` uses session `env.vars` (not stale global store)
2118
- - [ ] Snapshot diff tooling for test assertions
2199
+ - [x] `printf` format string with `%s` `%d` `%f` `%x` `\n` `\t`
2200
+ - [x] `read` — read stdin into variables (supports multiple vars, splits on whitespace)
2201
+ - [x] `declare` / `local` / `typeset` — variable declaration with `-i` integer, `-r` readonly, `-x` export
2202
+ - [x] `shift [n]` — shift positional parameters
2203
+ - [x] `trap [action] [signal]` — signal handlers with `EXIT` support
2204
+ - [x] `return [n]` — return from shell functions
2205
+ - [x] `exit [code]` — optional exit code
2206
+ - [x] `help` rewrite — Package Management category, aliases shown inline, `help <cmd>` shows category
2207
+ - [x] Category corrections — `neofetch`→system, `nano`→files, `apt`/`dpkg`→package
2208
+ - [x] `src/utils/expand.ts` — centralised expansion module used by `runCommand`, `echo`, and `sh.ts`
2209
+ - [x] `${#VAR}` string length, `$((expr))` arithmetic, `~` tilde expansion
2210
+ - [x] `${VAR:=assign}` assign-on-read, `${VAR:+alternate}` alternate-if-set
2211
+ - [x] Single-quote isolation in expansion — `$VAR` never expanded inside `'...'`
2212
+ - [x] `true` / `false` builtins
2213
+ - [x] Bare `VAR=val` assignments in `sh` scripts (`i=0`, `i=$((i+1))`)
2214
+ - [x] `$?` reflects last command exit code correctly across `&&` / `;` chains
2215
+ - [x] `node` / `python3` virtual REPL stubs — `node -e`, `node <file>`, `python3 -c`, `python3 <file>`, `--version` flags
2216
+ - [x] `/proc/self` and `/proc/<pid>` per-session process entries — `comm`, `status`, `cmdline`, `environ`, `cwd`, `exe`, `fd/`
2217
+ - [x] Snapshot diff tooling — `diffSnapshots()`, `formatDiff()`, `assertDiff()` exported from `typescript-virtual-container`
2119
2218
  - [ ] WebSocket-based remote shell client (experimental)
2120
- - [ ] Package stubs that simulate REPL behavior (node, python3)
2121
- - [ ] `/proc/self` and `/proc/<pid>` per-session process entries
2122
-
2123
- ---
2124
-
2125
- ## Changelog
2126
-
2127
- See [CHANGELOG.md](./CHANGELOG.md).
package/biome.json CHANGED
@@ -26,5 +26,12 @@
26
26
  "indentWidth": 2,
27
27
  "lineWidth": 80,
28
28
  "lineEnding": "lf"
29
+ },
30
+ "files": {
31
+ "ignoreUnknown": true,
32
+ "includes": [
33
+ "**/*.ts",
34
+ "**/*.tsx"
35
+ ]
29
36
  }
30
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/exec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AASpD,wBAAgB,OAAO,CACtB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,GACjB,IAAI,CAuBN"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/exec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AASpD,wBAAgB,OAAO,CACtB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,GACjB,IAAI,CAgCN"}
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD,wBAAsB,aAAa,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,aAAa,CAAC,CAiBxB;AAED,8CAA8C;AAC9C,wBAAsB,iBAAiB,CACtC,UAAU,EAAE,SAAS,EAAE,EACvB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,aAAa,CAAC,CA4BxB;AAID,wBAAsB,eAAe,CACpC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,GAAG,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,aAAa,CAAC,CAiBxB"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EACX,QAAQ,EAER,MAAM,EACN,SAAS,EACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAIpD,wBAAsB,aAAa,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,aAAa,CAAC,CA8BxB;AAED,8CAA8C;AAC9C,wBAAsB,iBAAiB,CACtC,UAAU,EAAE,SAAS,EAAE,EACvB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,QAAQ,GACX,OAAO,CAAC,aAAa,CAAC,CAoCxB;AAID,wBAAsB,eAAe,CACpC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,GAAG,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,aAAa,CAAC,CA4BxB"}
@@ -10,7 +10,9 @@ export async function executeScript(script, authUser, hostname, mode, cwd, shell
10
10
  lastResult = await executePipeline(stmt.pipeline, authUser, hostname, mode, cwd, shell, env);
11
11
  env.lastExitCode = lastResult.exitCode ?? 0;
12
12
  // Propagate session-control signals
13
- if (lastResult.closeSession || lastResult.switchUser || lastResult.nextCwd) {
13
+ if (lastResult.closeSession ||
14
+ lastResult.switchUser ||
15
+ lastResult.nextCwd) {
14
16
  break;
15
17
  }
16
18
  }
@@ -68,7 +70,10 @@ async function executeSingleCommandWithRedirections(cmd, authUser, hostname, mod
68
70
  stdin = shell.vfs.readFile(inputPath);
69
71
  }
70
72
  catch {
71
- return { stderr: `${cmd.inputFile}: No such file or directory`, exitCode: 1 };
73
+ return {
74
+ stderr: `${cmd.inputFile}: No such file or directory`,
75
+ exitCode: 1,
76
+ };
72
77
  }
73
78
  }
74
79
  const result = await runCommandDirect(cmd.name, cmd.args, authUser, hostname, mode, cwd, shell, stdin, env);
@@ -77,12 +82,14 @@ async function executeSingleCommandWithRedirections(cmd, authUser, hostname, mod
77
82
  const output = result.stdout || "";
78
83
  try {
79
84
  if (cmd.appendOutput) {
80
- const existing = (() => { try {
81
- return shell.vfs.readFile(outputPath);
82
- }
83
- catch {
84
- return "";
85
- } })();
85
+ const existing = (() => {
86
+ try {
87
+ return shell.vfs.readFile(outputPath);
88
+ }
89
+ catch {
90
+ return "";
91
+ }
92
+ })();
86
93
  shell.writeFileAsUser(authUser, outputPath, existing + output);
87
94
  }
88
95
  else {
@@ -91,7 +98,11 @@ async function executeSingleCommandWithRedirections(cmd, authUser, hostname, mod
91
98
  return { ...result, stdout: "" };
92
99
  }
93
100
  catch {
94
- return { ...result, stderr: `Failed to write to ${cmd.outputFile}`, exitCode: 1 };
101
+ return {
102
+ ...result,
103
+ stderr: `Failed to write to ${cmd.outputFile}`,
104
+ exitCode: 1,
105
+ };
95
106
  }
96
107
  }
97
108
  return result;
@@ -107,7 +118,10 @@ async function executePipelineChain(commands, authUser, hostname, mode, cwd, she
107
118
  currentOutput = shell.vfs.readFile(inputPath);
108
119
  }
109
120
  catch {
110
- return { stderr: `${cmd.inputFile}: No such file or directory`, exitCode: 1 };
121
+ return {
122
+ stderr: `${cmd.inputFile}: No such file or directory`,
123
+ exitCode: 1,
124
+ };
111
125
  }
112
126
  }
113
127
  const result = await runCommandDirect(cmd.name, cmd.args, authUser, hostname, mode, cwd, shell, currentOutput, env);
@@ -117,12 +131,14 @@ async function executePipelineChain(commands, authUser, hostname, mode, cwd, she
117
131
  const output = result.stdout || "";
118
132
  try {
119
133
  if (cmd.appendOutput) {
120
- const existing = (() => { try {
121
- return shell.vfs.readFile(outputPath);
122
- }
123
- catch {
124
- return "";
125
- } })();
134
+ const existing = (() => {
135
+ try {
136
+ return shell.vfs.readFile(outputPath);
137
+ }
138
+ catch {
139
+ return "";
140
+ }
141
+ })();
126
142
  shell.writeFileAsUser(authUser, outputPath, existing + output);
127
143
  }
128
144
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA0B/C,cAAM,QAAS,SAAQ,YAAY;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,KAAK,CAAe;IAE5B,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqC;IAElE;;;;;;;;OAQG;gBACS,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAkC,EAClC,eAAmB,EACnB,iBAA0B,GAC1B,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,YAAY,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC3B;IAYD,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,aAAa;IAcrB;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA0JrC;;OAEG;IACI,IAAI,IAAI,IAAI;IAUnB;;;OAGG;IACI,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAGrC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA0B/C,cAAM,QAAS,SAAQ,YAAY;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,KAAK,CAAe;IAE5B,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqC;IAElE;;;;;;;;OAQG;gBACS,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAkC,EAClC,eAAmB,EACnB,iBAA0B,GAC1B,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,YAAY,CAAC;QACrB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC3B;IAYD,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,aAAa;IAcrB;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA6LrC;;OAEG;IACI,IAAI,IAAI,IAAI;IAUnB;;;OAGG;IACI,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;CAGrC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -103,7 +103,11 @@ class SshMimic extends EventEmitter {
103
103
  remoteAddress = ctx.ip ?? remoteAddress;
104
104
  // Rate-limit check
105
105
  if (this.isLockedOut(remoteAddress)) {
106
- this.emit("auth:failure", { username: candidateUser, remoteAddress, reason: "lockout" });
106
+ this.emit("auth:failure", {
107
+ username: candidateUser,
108
+ remoteAddress,
109
+ reason: "lockout",
110
+ });
107
111
  ctx.reject();
108
112
  return;
109
113
  }
@@ -123,7 +127,10 @@ class SshMimic extends EventEmitter {
123
127
  ctx.password === "" ||
124
128
  !shell.users.verifyPassword(candidateUser, ctx.password)) {
125
129
  this.recordFailure(remoteAddress);
126
- this.emit("auth:failure", { username: candidateUser, remoteAddress });
130
+ this.emit("auth:failure", {
131
+ username: candidateUser,
132
+ remoteAddress,
133
+ });
127
134
  ctx.reject();
128
135
  return;
129
136
  }
@@ -144,11 +151,14 @@ class SshMimic extends EventEmitter {
144
151
  return;
145
152
  }
146
153
  const incomingKey = ctx.key;
147
- const keyMatches = authorizedKeys.some((k) => k.algo === incomingKey.algo &&
148
- k.data.equals(incomingKey.data));
154
+ const keyMatches = authorizedKeys.some((k) => k.algo === incomingKey.algo && k.data.equals(incomingKey.data));
149
155
  if (!keyMatches) {
150
156
  this.recordFailure(remoteAddress);
151
- this.emit("auth:failure", { username: candidateUser, remoteAddress, method: "publickey" });
157
+ this.emit("auth:failure", {
158
+ username: candidateUser,
159
+ remoteAddress,
160
+ method: "publickey",
161
+ });
152
162
  ctx.reject();
153
163
  return;
154
164
  }
@@ -157,7 +167,11 @@ class SshMimic extends EventEmitter {
157
167
  authUser = candidateUser;
158
168
  sessionId = shell.users.registerSession(authUser, remoteAddress).id;
159
169
  this.recordSuccess(remoteAddress);
160
- this.emit("auth:success", { username: authUser, remoteAddress, method: "publickey" });
170
+ this.emit("auth:success", {
171
+ username: authUser,
172
+ remoteAddress,
173
+ method: "publickey",
174
+ });
161
175
  this.ensureHomeDir(authUser);
162
176
  ctx.accept();
163
177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"binaryPack.d.ts","sourceRoot":"","sources":["../../src/VirtualFileSystem/binaryPack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAkC,MAAM,iBAAiB,CAAC;AA2E7F;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAM7D;AAuED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,qBAAqB,CAiB5D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD"}
1
+ {"version":3,"file":"binaryPack.d.ts","sourceRoot":"","sources":["../../src/VirtualFileSystem/binaryPack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EACX,qBAAqB,EAGrB,MAAM,iBAAiB,CAAC;AA+EzB;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAM7D;AA0FD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,qBAAqB,CAiB5D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD"}
@@ -37,7 +37,9 @@ const TYPE_DIR = 0x02;
37
37
  // ── Encoder ───────────────────────────────────────────────────────────────────
38
38
  class Encoder {
39
39
  chunks = [];
40
- write(buf) { this.chunks.push(buf); }
40
+ write(buf) {
41
+ this.chunks.push(buf);
42
+ }
41
43
  writeUint8(n) {
42
44
  const b = Buffer.allocUnsafe(1);
43
45
  b.writeUInt8(n, 0);
@@ -67,7 +69,9 @@ class Encoder {
67
69
  this.writeUint32(bytes.length);
68
70
  this.chunks.push(bytes);
69
71
  }
70
- toBuffer() { return Buffer.concat(this.chunks); }
72
+ toBuffer() {
73
+ return Buffer.concat(this.chunks);
74
+ }
71
75
  }
72
76
  function encodeNode(enc, node) {
73
77
  if (node.type === "file") {
@@ -111,7 +115,9 @@ class Decoder {
111
115
  constructor(buf) {
112
116
  this.buf = buf;
113
117
  }
114
- readUint8() { return this.buf.readUInt8(this.pos++); }
118
+ readUint8() {
119
+ return this.buf.readUInt8(this.pos++);
120
+ }
115
121
  readUint16() {
116
122
  const v = this.buf.readUInt16LE(this.pos);
117
123
  this.pos += 2;
@@ -139,7 +145,9 @@ class Decoder {
139
145
  this.pos += len;
140
146
  return b;
141
147
  }
142
- remaining() { return this.buf.length - this.pos; }
148
+ remaining() {
149
+ return this.buf.length - this.pos;
150
+ }
143
151
  }
144
152
  function decodeNode(dec) {
145
153
  const type = dec.readUint8();
@@ -150,7 +158,15 @@ function decodeNode(dec) {
150
158
  if (type === TYPE_FILE) {
151
159
  const compressed = dec.readUint8() === 0x01;
152
160
  const content = dec.readBytes();
153
- return { type: "file", name, mode, createdAt, updatedAt, compressed, content };
161
+ return {
162
+ type: "file",
163
+ name,
164
+ mode,
165
+ createdAt,
166
+ updatedAt,
167
+ compressed,
168
+ content,
169
+ };
154
170
  }
155
171
  if (type === TYPE_DIR) {
156
172
  const count = dec.readUint32();
@@ -159,7 +175,14 @@ function decodeNode(dec) {
159
175
  const child = decodeNode(dec);
160
176
  children.set(child.name, child);
161
177
  }
162
- return { type: "directory", name, mode, createdAt, updatedAt, children };
178
+ return {
179
+ type: "directory",
180
+ name,
181
+ mode,
182
+ createdAt,
183
+ updatedAt,
184
+ children,
185
+ };
163
186
  }
164
187
  throw new Error(`[VFS binary] Unknown node type: 0x${type.toString(16)}`);
165
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualFileSystem/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EAIX,gBAAgB,EAChB,MAAM,cAAc,CAAC;AAItB;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,IAAI,CAAC;AAEjD,MAAM,WAAW,UAAU;IAC1B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAM,iBAAkB,SAAQ,YAAY;IAC3C,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;gBAEjC,OAAO,GAAE,UAAe;IAqBpC,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,cAAc;IAwBtB;;;;;;OAMG;IACU,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B3C;;;;;;OAMG;IACU,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAazC,4CAA4C;IACrC,OAAO,IAAI,kBAAkB;IAIpC,qEAAqE;IAC9D,eAAe,IAAI,MAAM,GAAG,IAAI;IAMvC,qDAAqD;IAC9C,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAc,GAAG,IAAI;IAa5D;;;OAGG;IACI,SAAS,CACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,gBAAqB,GAC5B,IAAI;IAuCP;;;OAGG;IACI,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAY3C,+DAA+D;IACxD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAY9C,4DAA4D;IACrD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAO1C,mCAAmC;IAC5B,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpD,gDAAgD;IACzC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY;IAoB7C,2DAA2D;IACpD,IAAI,CAAC,OAAO,GAAE,MAAY,GAAG,MAAM,EAAE;IAS5C,wDAAwD;IACjD,IAAI,CAAC,OAAO,GAAE,MAAY,GAAG,MAAM;IAY1C,OAAO,CAAC,eAAe;IAoBvB,gDAAgD;IACzC,aAAa,CAAC,UAAU,GAAE,MAAY,GAAG,MAAM;IAItD,OAAO,CAAC,YAAY;IASpB,sDAAsD;IAC/C,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAW7C,oDAAoD;IAC7C,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAW/C;;;OAGG;IACI,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAoB1D,0DAA0D;IACnD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAO7C;;;OAGG;IACI,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM;IAkB7D,wCAAwC;IACjC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI;IAiBpE,+BAA+B;IACxB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAwBnD;;;;;OAKG;IACI,UAAU,IAAI,WAAW;IAIhC,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,aAAa;IAUrB;;;;;;;OAOG;WACW,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,iBAAiB;IAMpE;;;;;;;;OAQG;IACI,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAKlD,OAAO,CAAC,cAAc;CA8BtB;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualFileSystem/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EAIX,gBAAgB,EAChB,MAAM,cAAc,CAAC;AAItB;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,IAAI,CAAC;AAEjD,MAAM,WAAW,UAAU;IAC1B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAM,iBAAkB,SAAQ,YAAY;IAC3C,OAAO,CAAC,IAAI,CAAwB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;gBAEjC,OAAO,GAAE,UAAe;IAqBpC,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,cAAc;IAwBtB;;;;;;OAMG;IACU,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3C;;;;;;OAMG;IACU,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAazC,4CAA4C;IACrC,OAAO,IAAI,kBAAkB;IAIpC,qEAAqE;IAC9D,eAAe,IAAI,MAAM,GAAG,IAAI;IAMvC,qDAAqD;IAC9C,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAc,GAAG,IAAI;IAiB5D;;;OAGG;IACI,SAAS,CACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,gBAAqB,GAC5B,IAAI;IAuCP;;;OAGG;IACI,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAY3C,+DAA+D;IACxD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAY9C,4DAA4D;IACrD,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAS1C,mCAAmC;IAC5B,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpD,gDAAgD;IACzC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY;IA6B7C,2DAA2D;IACpD,IAAI,CAAC,OAAO,GAAE,MAAY,GAAG,MAAM,EAAE;IAS5C,wDAAwD;IACjD,IAAI,CAAC,OAAO,GAAE,MAAY,GAAG,MAAM;IAU1C,OAAO,CAAC,eAAe;IAqBvB,gDAAgD;IACzC,aAAa,CAAC,UAAU,GAAE,MAAY,GAAG,MAAM;IAItD,OAAO,CAAC,YAAY;IASpB,sDAAsD;IAC/C,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAY7C,oDAAoD;IAC7C,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAY/C;;;OAGG;IACI,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IA2B1D,0DAA0D;IACnD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAS7C;;;OAGG;IACI,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM;IAsB7D,wCAAwC;IACjC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI;IAsBpE,+BAA+B;IACxB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IA8BnD;;;;;OAKG;IACI,UAAU,IAAI,WAAW;IAIhC,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,aAAa;IAYrB;;;;;;;OAOG;WACW,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,iBAAiB;IAMpE;;;;;;;;OAQG;IACI,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAKlD,OAAO,CAAC,cAAc;CAkCtB;AAED,eAAe,iBAAiB,CAAC"}