typescript-virtual-container 1.2.7 → 1.2.9

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 (130) hide show
  1. package/README.md +457 -42
  2. package/dist/SSHMimic/executor.js +3 -5
  3. package/dist/VirtualFileSystem/binaryPack.d.ts +49 -0
  4. package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -0
  5. package/dist/VirtualFileSystem/binaryPack.js +193 -0
  6. package/dist/VirtualFileSystem/index.d.ts +7 -5
  7. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  8. package/dist/VirtualFileSystem/index.js +20 -9
  9. package/dist/VirtualPackageManager/index.d.ts +202 -0
  10. package/dist/VirtualPackageManager/index.d.ts.map +1 -0
  11. package/dist/VirtualPackageManager/index.js +676 -0
  12. package/dist/VirtualShell/index.d.ts +87 -12
  13. package/dist/VirtualShell/index.d.ts.map +1 -1
  14. package/dist/VirtualShell/index.js +83 -12
  15. package/dist/VirtualUserManager/index.d.ts +52 -20
  16. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  17. package/dist/VirtualUserManager/index.js +54 -20
  18. package/dist/commands/alias.d.ts +4 -0
  19. package/dist/commands/alias.d.ts.map +1 -0
  20. package/dist/commands/alias.js +58 -0
  21. package/dist/commands/apt.d.ts +4 -0
  22. package/dist/commands/apt.d.ts.map +1 -0
  23. package/dist/commands/apt.js +182 -0
  24. package/dist/commands/cat.d.ts.map +1 -1
  25. package/dist/commands/cat.js +27 -8
  26. package/dist/commands/chmod.d.ts.map +1 -1
  27. package/dist/commands/chmod.js +52 -3
  28. package/dist/commands/command-helpers.d.ts +78 -4
  29. package/dist/commands/command-helpers.d.ts.map +1 -1
  30. package/dist/commands/command-helpers.js +78 -4
  31. package/dist/commands/curl.d.ts.map +1 -1
  32. package/dist/commands/curl.js +81 -29
  33. package/dist/commands/dpkg.d.ts +4 -0
  34. package/dist/commands/dpkg.d.ts.map +1 -0
  35. package/dist/commands/dpkg.js +144 -0
  36. package/dist/commands/echo.d.ts.map +1 -1
  37. package/dist/commands/echo.js +24 -12
  38. package/dist/commands/free.d.ts +3 -0
  39. package/dist/commands/free.d.ts.map +1 -0
  40. package/dist/commands/free.js +38 -0
  41. package/dist/commands/helpers.d.ts +3 -0
  42. package/dist/commands/helpers.d.ts.map +1 -1
  43. package/dist/commands/helpers.js +3 -0
  44. package/dist/commands/history.d.ts +3 -0
  45. package/dist/commands/history.d.ts.map +1 -0
  46. package/dist/commands/history.js +21 -0
  47. package/dist/commands/index.d.ts +8 -1
  48. package/dist/commands/index.d.ts.map +1 -1
  49. package/dist/commands/index.js +120 -11
  50. package/dist/commands/ls.d.ts.map +1 -1
  51. package/dist/commands/ls.js +4 -3
  52. package/dist/commands/lsb-release.d.ts +3 -0
  53. package/dist/commands/lsb-release.d.ts.map +1 -0
  54. package/dist/commands/lsb-release.js +50 -0
  55. package/dist/commands/man.d.ts +3 -0
  56. package/dist/commands/man.d.ts.map +1 -0
  57. package/dist/commands/man.js +155 -0
  58. package/dist/commands/neofetch.d.ts.map +1 -1
  59. package/dist/commands/neofetch.js +5 -0
  60. package/dist/commands/ping.d.ts.map +1 -1
  61. package/dist/commands/ping.js +5 -2
  62. package/dist/commands/ps.d.ts.map +1 -1
  63. package/dist/commands/ps.js +27 -6
  64. package/dist/commands/sh.d.ts.map +1 -1
  65. package/dist/commands/sh.js +29 -11
  66. package/dist/commands/source.d.ts +3 -0
  67. package/dist/commands/source.d.ts.map +1 -0
  68. package/dist/commands/source.js +31 -0
  69. package/dist/commands/test.d.ts +3 -0
  70. package/dist/commands/test.d.ts.map +1 -0
  71. package/dist/commands/test.js +92 -0
  72. package/dist/commands/type.d.ts +3 -0
  73. package/dist/commands/type.d.ts.map +1 -0
  74. package/dist/commands/type.js +34 -0
  75. package/dist/commands/uptime.d.ts +3 -0
  76. package/dist/commands/uptime.d.ts.map +1 -0
  77. package/dist/commands/uptime.js +40 -0
  78. package/dist/commands/wget.d.ts.map +1 -1
  79. package/dist/commands/wget.js +71 -100
  80. package/dist/commands/which.d.ts +3 -0
  81. package/dist/commands/which.d.ts.map +1 -0
  82. package/dist/commands/which.js +32 -0
  83. package/dist/index.d.ts +5 -2
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +2 -1
  86. package/dist/modules/linuxRootfs.d.ts +24 -0
  87. package/dist/modules/linuxRootfs.d.ts.map +1 -0
  88. package/dist/modules/linuxRootfs.js +297 -0
  89. package/dist/modules/neofetch.d.ts.map +1 -1
  90. package/dist/modules/neofetch.js +1 -0
  91. package/dist/standalone.js +4 -1
  92. package/package.json +2 -1
  93. package/src/SSHMimic/executor.ts +3 -5
  94. package/src/VirtualFileSystem/binaryPack.ts +219 -0
  95. package/src/VirtualFileSystem/index.ts +21 -11
  96. package/src/VirtualPackageManager/index.ts +820 -0
  97. package/src/VirtualShell/index.ts +104 -13
  98. package/src/VirtualUserManager/index.ts +55 -20
  99. package/src/commands/alias.ts +60 -0
  100. package/src/commands/apt.ts +198 -0
  101. package/src/commands/cat.ts +32 -8
  102. package/src/commands/chmod.ts +48 -3
  103. package/src/commands/command-helpers.ts +78 -4
  104. package/src/commands/curl.ts +78 -37
  105. package/src/commands/dpkg.ts +158 -0
  106. package/src/commands/echo.ts +30 -14
  107. package/src/commands/free.ts +40 -0
  108. package/src/commands/helpers.ts +8 -0
  109. package/src/commands/history.ts +29 -0
  110. package/src/commands/index.ts +116 -11
  111. package/src/commands/ls.ts +5 -4
  112. package/src/commands/lsb-release.ts +52 -0
  113. package/src/commands/man.ts +166 -0
  114. package/src/commands/neofetch.ts +5 -0
  115. package/src/commands/ping.ts +5 -2
  116. package/src/commands/ps.ts +28 -6
  117. package/src/commands/sh.ts +33 -11
  118. package/src/commands/source.ts +35 -0
  119. package/src/commands/test.ts +100 -0
  120. package/src/commands/type.ts +40 -0
  121. package/src/commands/uptime.ts +46 -0
  122. package/src/commands/wget.ts +70 -123
  123. package/src/commands/which.ts +34 -0
  124. package/src/index.ts +10 -0
  125. package/src/modules/linuxRootfs.ts +439 -0
  126. package/src/modules/neofetch.ts +1 -0
  127. package/src/standalone.ts +4 -1
  128. package/standalone.js +418 -103
  129. package/standalone.js.map +4 -4
  130. package/tests/new-features.test.ts +626 -0
@@ -3,22 +3,66 @@ import type { CommandContext, CommandResult } from "../types/commands";
3
3
  import type { ShellStream } from "../types/streams";
4
4
  import VirtualFileSystem, { type VfsOptions } from "../VirtualFileSystem";
5
5
  import { VirtualUserManager } from "../VirtualUserManager";
6
+ import { VirtualPackageManager } from "../VirtualPackageManager";
7
+ /**
8
+ * Virtual machine identity strings surfaced by system-info commands
9
+ * (`uname`, `neofetch`, `lsb_release`, `/proc/version`, `/etc/os-release`).
10
+ *
11
+ * Pass this as the second argument to `new VirtualShell()` to customise the
12
+ * distro name, kernel version, and CPU architecture reported inside the shell.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const shell = new VirtualShell("my-vm", {
17
+ * kernel: "6.1.0+custom-amd64",
18
+ * os: "Acme GNU/Linux x64",
19
+ * arch: "x86_64",
20
+ * });
21
+ * ```
22
+ */
6
23
  export interface ShellProperties {
24
+ /** Kernel version string (e.g. `"1.0.0+itsrealfortune+1-amd64"`). */
7
25
  kernel: string;
26
+ /** Full OS description (e.g. `"Fortune GNU/Linux x64"`). */
8
27
  os: string;
28
+ /** CPU architecture label (e.g. `"x86_64"`, `"aarch64"`). */
9
29
  arch: string;
10
30
  }
11
31
  /**
12
- * Coordinates the virtual filesystem, user manager, and command runtime.
32
+ * Coordinates the virtual filesystem, user manager, package manager, and
33
+ * command runtime for a single isolated shell environment.
13
34
  *
14
- * Instances are used both by the SSH server facade and by the programmatic
15
- * client API.
35
+ * Each instance owns its own VFS tree, user database, package registry, and
36
+ * session state — multiple instances are fully independent.
37
+ *
38
+ * Instances are consumed both by the SSH/SFTP server facades and directly via
39
+ * the programmatic `SshClient` API.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const shell = new VirtualShell("my-vm");
44
+ * await shell.ensureInitialized();
45
+ * const client = new SshClient(shell, "root");
46
+ * const result = await client.exec("uname -a");
47
+ * ```
48
+ *
49
+ * @fires VirtualShell#initialized Emitted once the VFS and users are ready.
50
+ * @fires VirtualShell#command Emitted after every command execution.
51
+ * @fires VirtualShell#session:start Emitted when an interactive session opens.
16
52
  */
17
53
  declare class VirtualShell extends EventEmitter {
54
+ /** Backing virtual filesystem — use for direct path operations. */
18
55
  vfs: VirtualFileSystem;
56
+ /** Virtual user database — use for auth, quotas, and session tracking. */
19
57
  users: VirtualUserManager;
58
+ /** APT/dpkg package manager backed by the built-in package registry. */
59
+ packageManager: VirtualPackageManager;
60
+ /** Hostname shown in the shell prompt and SSH ident string. */
20
61
  hostname: string;
62
+ /** Distro identity strings surfaced by `uname`, `neofetch`, etc. */
21
63
  properties: ShellProperties;
64
+ /** Unix ms timestamp of shell creation — used by `uptime` and `/proc/uptime`. */
65
+ startTime: number;
22
66
  private initialized;
23
67
  /**
24
68
  * Creates a new virtual shell instance.
@@ -42,25 +86,56 @@ declare class VirtualShell extends EventEmitter {
42
86
  */
43
87
  addCommand(name: string, params: string[], callback: (ctx: CommandContext) => CommandResult | Promise<CommandResult>): void;
44
88
  /**
45
- * Executes a command line string in the context of this shell instance.
89
+ * Executes a raw command line string programmatically.
90
+ *
91
+ * Supports the full shell operator set (`&&`, `||`, `;`, `|`, `>`, `<`,
92
+ * `$(cmd)`) and alias expansion. The result is emitted via the
93
+ * `"command"` event but not returned — use `SshClient.exec()` for a
94
+ * result-returning wrapper.
46
95
  *
47
- * @param rawInput
48
- * @param authUser
49
- * @param cwd
96
+ * @param rawInput Unparsed command line (e.g. `"ls -la /tmp"`).
97
+ * @param authUser Username to run the command as.
98
+ * @param cwd Current working directory for path resolution.
50
99
  */
51
100
  executeCommand(rawInput: string, authUser: string, cwd: string): void;
52
101
  /**
53
- * Starts an interactive session with the shell.
102
+ * Attaches an interactive PTY session to this shell instance.
54
103
  *
55
- * @param stream The stream for the interactive session.
56
- * @param authUser The authenticated user for the session.
57
- * @param sessionId The ID of the session.
58
- * @param remoteAddress The address of the remote client.
104
+ * Called internally by `SshMimic` when a client opens a shell channel.
105
+ * The session reads from `stream` (user keystrokes) and writes back ANSI
106
+ * output. History, `.bashrc` sourcing, and Ctrl+W/Ctrl+U line editing are
107
+ * handled automatically.
108
+ *
109
+ * @param stream Bidirectional SSH channel stream.
110
+ * @param authUser Authenticated username bound to this session.
111
+ * @param sessionId Stable session UUID (used for `who` output), or `null`.
112
+ * @param remoteAddress IP or hostname of the connecting client.
113
+ * @param terminalSize Initial terminal dimensions in columns and rows.
59
114
  */
60
115
  startInteractiveSession(stream: ShellStream, authUser: string, sessionId: string | null, remoteAddress: string, terminalSize: {
61
116
  cols: number;
62
117
  rows: number;
63
118
  }): void;
119
+ /**
120
+ * Refreshes the `/proc` virtual filesystem with current system state.
121
+ *
122
+ * Updates `/proc/uptime`, `/proc/meminfo`, `/proc/cpuinfo`,
123
+ * `/proc/version`, and `/proc/loadavg` from live host data.
124
+ *
125
+ * Called automatically during `bootstrapLinuxRootfs`. Call again before
126
+ * reading `/proc` files for up-to-date values (e.g. before `neofetch`
127
+ * or `free` in long-running processes).
128
+ */
129
+ refreshProcFs(): void;
130
+ /**
131
+ * Syncs `/etc/passwd`, `/etc/group`, and `/etc/shadow` from the current
132
+ * `VirtualUserManager` state.
133
+ *
134
+ * Called automatically during `bootstrapLinuxRootfs`. Call again after
135
+ * `users.addUser()`, `users.deleteUser()`, or `users.addSudoer()` to keep
136
+ * the classic Unix credential files in sync with the user manager.
137
+ */
138
+ syncPasswd(): void;
64
139
  /**
65
140
  * Returns virtual filesystem instance after server started.
66
141
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualShell/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,iBAAiB,EAAE,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG3D,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACb;AAmBD;;;;;GAKG;AACH,cAAM,YAAa,SAAQ,YAAY;IACtC,GAAG,EAAE,iBAAiB,CAAC;IACvB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,WAAW,CAAgB;IAEnC;;;;;;OAMG;gBAEF,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,eAAe,EAC5B,UAAU,CAAC,EAAE,UAAU;IAqBxB;;;OAGG;IACU,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/C;;;;;;OAMG;IACH,UAAU,CACT,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,GACvE,IAAI;IASP;;;;;;OAMG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAMrE;;;;;;;OAOG;IAEH,uBAAuB,CACtB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC1C,IAAI;IAgBP;;;;OAIG;IACI,MAAM,IAAI,iBAAiB,GAAG,IAAI;IAIzC;;;;OAIG;IACI,QAAQ,IAAI,kBAAkB,GAAG,IAAI;IAI5C;;;;OAIG;IACI,WAAW,IAAI,MAAM;IAI5B;;;;;;OAMG;IACI,eAAe,CACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,GACtB,IAAI;CAKP;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualShell/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,OAAO,iBAAiB,EAAE,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAIjE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,eAAe;IAC/B,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACb;AAmBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,cAAM,YAAa,SAAQ,YAAY;IACtC,mEAAmE;IACnE,GAAG,EAAE,iBAAiB,CAAC;IACvB,0EAA0E;IAC1E,KAAK,EAAE,kBAAkB,CAAC;IAC1B,wEAAwE;IACxE,cAAc,EAAE,qBAAqB,CAAC;IACtC,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,UAAU,EAAE,eAAe,CAAC;IAC5B,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,WAAW,CAAgB;IAEnC;;;;;;OAMG;gBAEF,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,eAAe,EAC5B,UAAU,CAAC,EAAE,UAAU;IA+BxB;;;OAGG;IACU,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAK/C;;;;;;OAMG;IACH,UAAU,CACT,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,GACvE,IAAI;IASP;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAMrE;;;;;;;;;;;;;OAaG;IACH,uBAAuB,CACtB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC1C,IAAI;IAgBP;;;;;;;;;OASG;IACI,aAAa,IAAI,IAAI;IAI5B;;;;;;;OAOG;IACI,UAAU,IAAI,IAAI;IAIzB;;;;OAIG;IACI,MAAM,IAAI,iBAAiB,GAAG,IAAI;IAIzC;;;;OAIG;IACI,QAAQ,IAAI,kBAAkB,GAAG,IAAI;IAI5C;;;;OAIG;IACI,WAAW,IAAI,MAAM;IAI5B;;;;;;OAMG;IACI,eAAe,CACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,MAAM,GACtB,IAAI;CAKP;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -3,6 +3,8 @@ import { createCustomCommand, registerCommand, runCommand } from "../commands";
3
3
  import { createPerfLogger } from "../utils/perfLogger";
4
4
  import VirtualFileSystem, {} from "../VirtualFileSystem";
5
5
  import { VirtualUserManager } from "../VirtualUserManager";
6
+ import { VirtualPackageManager } from "../VirtualPackageManager";
7
+ import { bootstrapLinuxRootfs, refreshProc, syncEtcPasswd } from "../modules/linuxRootfs";
6
8
  import { startShell } from "./shell";
7
9
  const defaultShellProperties = {
8
10
  kernel: "1.0.0+itsrealfortune+1-amd64",
@@ -18,16 +20,40 @@ function resolveAutoSudoForNewUsers() {
18
20
  return !["0", "false", "no", "off"].includes(configured.toLowerCase());
19
21
  }
20
22
  /**
21
- * Coordinates the virtual filesystem, user manager, and command runtime.
23
+ * Coordinates the virtual filesystem, user manager, package manager, and
24
+ * command runtime for a single isolated shell environment.
22
25
  *
23
- * Instances are used both by the SSH server facade and by the programmatic
24
- * client API.
26
+ * Each instance owns its own VFS tree, user database, package registry, and
27
+ * session state — multiple instances are fully independent.
28
+ *
29
+ * Instances are consumed both by the SSH/SFTP server facades and directly via
30
+ * the programmatic `SshClient` API.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * const shell = new VirtualShell("my-vm");
35
+ * await shell.ensureInitialized();
36
+ * const client = new SshClient(shell, "root");
37
+ * const result = await client.exec("uname -a");
38
+ * ```
39
+ *
40
+ * @fires VirtualShell#initialized Emitted once the VFS and users are ready.
41
+ * @fires VirtualShell#command Emitted after every command execution.
42
+ * @fires VirtualShell#session:start Emitted when an interactive session opens.
25
43
  */
26
44
  class VirtualShell extends EventEmitter {
45
+ /** Backing virtual filesystem — use for direct path operations. */
27
46
  vfs;
47
+ /** Virtual user database — use for auth, quotas, and session tracking. */
28
48
  users;
49
+ /** APT/dpkg package manager backed by the built-in package registry. */
50
+ packageManager;
51
+ /** Hostname shown in the shell prompt and SSH ident string. */
29
52
  hostname;
53
+ /** Distro identity strings surfaced by `uname`, `neofetch`, etc. */
30
54
  properties;
55
+ /** Unix ms timestamp of shell creation — used by `uptime` and `/proc/uptime`. */
56
+ startTime;
31
57
  initialized;
32
58
  /**
33
59
  * Creates a new virtual shell instance.
@@ -41,15 +67,25 @@ class VirtualShell extends EventEmitter {
41
67
  perf.mark("constructor");
42
68
  this.hostname = hostname;
43
69
  this.properties = properties || defaultShellProperties;
70
+ this.startTime = Date.now();
44
71
  this.vfs = new VirtualFileSystem(vfsOptions ?? {});
45
72
  this.users = new VirtualUserManager(this.vfs, resolveAutoSudoForNewUsers());
73
+ this.packageManager = new VirtualPackageManager(this.vfs, this.users);
46
74
  // Store references to avoid TypeScript "used before assigned" errors
47
75
  const vfs = this.vfs;
48
76
  const users = this.users;
77
+ const pm = this.packageManager;
78
+ const shellProps = this.properties;
79
+ const shellHostname = this.hostname;
80
+ const startTime = this.startTime;
49
81
  // Initialize both VFS mirror and users, ensuring all is ready before auth
50
82
  this.initialized = (async () => {
51
83
  await vfs.restoreMirror();
52
84
  await users.initialize();
85
+ // Bootstrap Linux rootfs (idempotent)
86
+ bootstrapLinuxRootfs(vfs, users, shellHostname, shellProps, startTime);
87
+ // Load installed packages from dpkg status
88
+ pm.load();
53
89
  this.emit("initialized");
54
90
  })();
55
91
  }
@@ -76,11 +112,16 @@ class VirtualShell extends EventEmitter {
76
112
  registerCommand(createCustomCommand(normalized, params, callback));
77
113
  }
78
114
  /**
79
- * Executes a command line string in the context of this shell instance.
115
+ * Executes a raw command line string programmatically.
116
+ *
117
+ * Supports the full shell operator set (`&&`, `||`, `;`, `|`, `>`, `<`,
118
+ * `$(cmd)`) and alias expansion. The result is emitted via the
119
+ * `"command"` event but not returned — use `SshClient.exec()` for a
120
+ * result-returning wrapper.
80
121
  *
81
- * @param rawInput
82
- * @param authUser
83
- * @param cwd
122
+ * @param rawInput Unparsed command line (e.g. `"ls -la /tmp"`).
123
+ * @param authUser Username to run the command as.
124
+ * @param cwd Current working directory for path resolution.
84
125
  */
85
126
  executeCommand(rawInput, authUser, cwd) {
86
127
  perf.mark("executeCommand");
@@ -88,12 +129,18 @@ class VirtualShell extends EventEmitter {
88
129
  this.emit("command", { command: rawInput, user: authUser, cwd });
89
130
  }
90
131
  /**
91
- * Starts an interactive session with the shell.
132
+ * Attaches an interactive PTY session to this shell instance.
92
133
  *
93
- * @param stream The stream for the interactive session.
94
- * @param authUser The authenticated user for the session.
95
- * @param sessionId The ID of the session.
96
- * @param remoteAddress The address of the remote client.
134
+ * Called internally by `SshMimic` when a client opens a shell channel.
135
+ * The session reads from `stream` (user keystrokes) and writes back ANSI
136
+ * output. History, `.bashrc` sourcing, and Ctrl+W/Ctrl+U line editing are
137
+ * handled automatically.
138
+ *
139
+ * @param stream Bidirectional SSH channel stream.
140
+ * @param authUser Authenticated username bound to this session.
141
+ * @param sessionId Stable session UUID (used for `who` output), or `null`.
142
+ * @param remoteAddress IP or hostname of the connecting client.
143
+ * @param terminalSize Initial terminal dimensions in columns and rows.
97
144
  */
98
145
  startInteractiveSession(stream, authUser, sessionId, remoteAddress, terminalSize) {
99
146
  perf.mark("startInteractiveSession");
@@ -101,6 +148,30 @@ class VirtualShell extends EventEmitter {
101
148
  this.emit("session:start", { user: authUser, sessionId, remoteAddress });
102
149
  startShell(this.properties, stream, authUser, this.hostname, sessionId, remoteAddress, terminalSize, this);
103
150
  }
151
+ /**
152
+ * Refreshes the `/proc` virtual filesystem with current system state.
153
+ *
154
+ * Updates `/proc/uptime`, `/proc/meminfo`, `/proc/cpuinfo`,
155
+ * `/proc/version`, and `/proc/loadavg` from live host data.
156
+ *
157
+ * Called automatically during `bootstrapLinuxRootfs`. Call again before
158
+ * reading `/proc` files for up-to-date values (e.g. before `neofetch`
159
+ * or `free` in long-running processes).
160
+ */
161
+ refreshProcFs() {
162
+ refreshProc(this.vfs, this.properties, this.hostname, this.startTime);
163
+ }
164
+ /**
165
+ * Syncs `/etc/passwd`, `/etc/group`, and `/etc/shadow` from the current
166
+ * `VirtualUserManager` state.
167
+ *
168
+ * Called automatically during `bootstrapLinuxRootfs`. Call again after
169
+ * `users.addUser()`, `users.deleteUser()`, or `users.addSudoer()` to keep
170
+ * the classic Unix credential files in sync with the user manager.
171
+ */
172
+ syncPasswd() {
173
+ syncEtcPasswd(this.vfs, this.users);
174
+ }
104
175
  /**
105
176
  * Returns virtual filesystem instance after server started.
106
177
  *
@@ -114,16 +114,18 @@ export declare class VirtualUserManager extends EventEmitter {
114
114
  */
115
115
  getPasswordHash(username: string): string | null;
116
116
  /**
117
- * Updates password for an existing user account.
117
+ * Updates the password for an existing user account.
118
118
  *
119
119
  * @param username Username to update.
120
- * @param password New plaintext password.
120
+ * @param password New plaintext password (must be non-empty).
121
+ * @throws When the user does not exist or the password is empty.
121
122
  */
122
123
  setPassword(username: string, password: string): Promise<void>;
123
124
  /**
124
- * Deletes existing non-root user account.
125
+ * Deletes an existing non-root user account and revokes sudo access.
125
126
  *
126
127
  * @param username Username to remove.
128
+ * @throws When `username` is `"root"` or the user does not exist.
127
129
  */
128
130
  deleteUser(username: string): Promise<void>;
129
131
  /**
@@ -134,57 +136,87 @@ export declare class VirtualUserManager extends EventEmitter {
134
136
  */
135
137
  isSudoer(username: string): boolean;
136
138
  /**
137
- * Grants sudo access to existing user.
139
+ * Grants sudo privileges to an existing user.
138
140
  *
139
141
  * @param username Username to promote.
142
+ * @throws When the user does not exist.
140
143
  */
141
144
  addSudoer(username: string): Promise<void>;
142
145
  /**
143
- * Revokes sudo access from user.
146
+ * Revokes sudo privileges from a user. Root cannot be demoted.
144
147
  *
145
148
  * @param username Username to demote.
149
+ * @throws When `username` is `"root"`.
146
150
  */
147
151
  removeSudoer(username: string): Promise<void>;
148
152
  /**
149
- * Registers active session and allocates tty id.
153
+ * Registers a new active session and allocates a virtual TTY identifier.
150
154
  *
151
- * @param username Session username.
152
- * @param remoteAddress Session source address.
153
- * @returns Registered session descriptor.
155
+ * Called by the SSH server when a client is authenticated. The returned
156
+ * descriptor is visible in `who` output and `listActiveSessions()`.
157
+ *
158
+ * @param username Authenticated username bound to the session.
159
+ * @param remoteAddress IP address or hostname of the connecting client.
160
+ * @returns The newly created `VirtualActiveSession` descriptor.
154
161
  */
155
162
  registerSession(username: string, remoteAddress: string): VirtualActiveSession;
156
163
  /**
157
- * Unregisters active session when connection closes.
164
+ * Removes an active session record when the connection closes.
165
+ *
166
+ * Safe to call with a `null` or `undefined` session ID — it will be a no-op.
158
167
  *
159
- * @param sessionId Session identifier; ignored when nullish.
168
+ * @param sessionId Session UUID returned by `registerSession()`, or nullish.
160
169
  */
161
170
  unregisterSession(sessionId: string | null | undefined): void;
162
171
  /**
163
- * Updates username/address metadata for existing session.
172
+ * Updates the username and remote address metadata for an active session.
164
173
  *
165
- * @param sessionId Session identifier; ignored when nullish.
166
- * @param username New username value.
167
- * @param remoteAddress New remote address value.
174
+ * Called internally by `su` and `sudo` when the effective user changes
175
+ * within a session. Silently ignored when the session ID is nullish or
176
+ * unknown.
177
+ *
178
+ * @param sessionId Session UUID to update, or nullish for no-op.
179
+ * @param username New effective username.
180
+ * @param remoteAddress New remote address (usually unchanged).
168
181
  */
169
182
  updateSession(sessionId: string | null | undefined, username: string, remoteAddress: string): void;
170
183
  /**
171
- * Lists active sessions sorted by start time.
184
+ * Returns a snapshot of all currently active sessions, sorted by start time.
185
+ *
186
+ * Used by `who`, `ps`, `uptime`, and the `HoneyPot` auditor.
172
187
  *
173
- * @returns Snapshot of active session descriptors.
188
+ * @returns Array of `VirtualActiveSession` descriptors.
174
189
  */
175
190
  listActiveSessions(): VirtualActiveSession[];
191
+ /**
192
+ * Returns a sorted list of all registered usernames.
193
+ *
194
+ * @returns Array of username strings sorted alphabetically.
195
+ */
196
+ listUsers(): string[];
176
197
  private loadFromVfs;
177
198
  private loadSudoersFromVfs;
178
199
  private loadQuotasFromVfs;
179
200
  private persist;
180
201
  private writeIfChanged;
181
202
  private createRecord;
203
+ /**
204
+ * Returns `true` when the user has a non-empty password set.
205
+ *
206
+ * A user with no password (or whose password hash matches the empty-string
207
+ * hash) is allowed to authenticate without a credential check.
208
+ *
209
+ * @param username Target username.
210
+ */
182
211
  hasPassword(username: string): boolean;
183
212
  /**
184
- * Hashes plaintext password with per-user salt using scrypt.
213
+ * Hashes a plaintext password using scrypt (or SHA-256 in fast-hash mode).
214
+ *
215
+ * Set `SSH_MIMIC_FAST_PASSWORD_HASH=1` to switch to SHA-256 for test
216
+ * environments where scrypt latency is undesirable.
185
217
  *
186
- * @param password Plaintext password.
187
- * @returns Hex-encoded password hash.
218
+ * @param password Plaintext password string.
219
+ * @returns Hex-encoded hash string.
188
220
  */
189
221
  hashPassword(password: string): string;
190
222
  private validateUsername;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualUserManager/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/VirtualUserManager/index.ts"],"names":[],"mappings":"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"}
@@ -222,10 +222,11 @@ export class VirtualUserManager extends EventEmitter {
222
222
  return record ? record.passwordHash : null;
223
223
  }
224
224
  /**
225
- * Updates password for an existing user account.
225
+ * Updates the password for an existing user account.
226
226
  *
227
227
  * @param username Username to update.
228
- * @param password New plaintext password.
228
+ * @param password New plaintext password (must be non-empty).
229
+ * @throws When the user does not exist or the password is empty.
229
230
  */
230
231
  async setPassword(username, password) {
231
232
  perf.mark("setPassword");
@@ -238,9 +239,10 @@ export class VirtualUserManager extends EventEmitter {
238
239
  await this.persist();
239
240
  }
240
241
  /**
241
- * Deletes existing non-root user account.
242
+ * Deletes an existing non-root user account and revokes sudo access.
242
243
  *
243
244
  * @param username Username to remove.
245
+ * @throws When `username` is `"root"` or the user does not exist.
244
246
  */
245
247
  async deleteUser(username) {
246
248
  perf.mark("deleteUser");
@@ -266,9 +268,10 @@ export class VirtualUserManager extends EventEmitter {
266
268
  return this.sudoers.has(username);
267
269
  }
268
270
  /**
269
- * Grants sudo access to existing user.
271
+ * Grants sudo privileges to an existing user.
270
272
  *
271
273
  * @param username Username to promote.
274
+ * @throws When the user does not exist.
272
275
  */
273
276
  async addSudoer(username) {
274
277
  perf.mark("addSudoer");
@@ -280,9 +283,10 @@ export class VirtualUserManager extends EventEmitter {
280
283
  await this.persist();
281
284
  }
282
285
  /**
283
- * Revokes sudo access from user.
286
+ * Revokes sudo privileges from a user. Root cannot be demoted.
284
287
  *
285
288
  * @param username Username to demote.
289
+ * @throws When `username` is `"root"`.
286
290
  */
287
291
  async removeSudoer(username) {
288
292
  perf.mark("removeSudoer");
@@ -294,11 +298,14 @@ export class VirtualUserManager extends EventEmitter {
294
298
  await this.persist();
295
299
  }
296
300
  /**
297
- * Registers active session and allocates tty id.
301
+ * Registers a new active session and allocates a virtual TTY identifier.
298
302
  *
299
- * @param username Session username.
300
- * @param remoteAddress Session source address.
301
- * @returns Registered session descriptor.
303
+ * Called by the SSH server when a client is authenticated. The returned
304
+ * descriptor is visible in `who` output and `listActiveSessions()`.
305
+ *
306
+ * @param username Authenticated username bound to the session.
307
+ * @param remoteAddress IP address or hostname of the connecting client.
308
+ * @returns The newly created `VirtualActiveSession` descriptor.
302
309
  */
303
310
  registerSession(username, remoteAddress) {
304
311
  perf.mark("registerSession");
@@ -318,9 +325,11 @@ export class VirtualUserManager extends EventEmitter {
318
325
  return session;
319
326
  }
320
327
  /**
321
- * Unregisters active session when connection closes.
328
+ * Removes an active session record when the connection closes.
329
+ *
330
+ * Safe to call with a `null` or `undefined` session ID — it will be a no-op.
322
331
  *
323
- * @param sessionId Session identifier; ignored when nullish.
332
+ * @param sessionId Session UUID returned by `registerSession()`, or nullish.
324
333
  */
325
334
  unregisterSession(sessionId) {
326
335
  perf.mark("unregisterSession");
@@ -338,11 +347,15 @@ export class VirtualUserManager extends EventEmitter {
338
347
  this.activeSessions.delete(sessionId);
339
348
  }
340
349
  /**
341
- * Updates username/address metadata for existing session.
350
+ * Updates the username and remote address metadata for an active session.
342
351
  *
343
- * @param sessionId Session identifier; ignored when nullish.
344
- * @param username New username value.
345
- * @param remoteAddress New remote address value.
352
+ * Called internally by `su` and `sudo` when the effective user changes
353
+ * within a session. Silently ignored when the session ID is nullish or
354
+ * unknown.
355
+ *
356
+ * @param sessionId Session UUID to update, or nullish for no-op.
357
+ * @param username New effective username.
358
+ * @param remoteAddress New remote address (usually unchanged).
346
359
  */
347
360
  updateSession(sessionId, username, remoteAddress) {
348
361
  perf.mark("updateSession");
@@ -360,14 +373,24 @@ export class VirtualUserManager extends EventEmitter {
360
373
  });
361
374
  }
362
375
  /**
363
- * Lists active sessions sorted by start time.
376
+ * Returns a snapshot of all currently active sessions, sorted by start time.
377
+ *
378
+ * Used by `who`, `ps`, `uptime`, and the `HoneyPot` auditor.
364
379
  *
365
- * @returns Snapshot of active session descriptors.
380
+ * @returns Array of `VirtualActiveSession` descriptors.
366
381
  */
367
382
  listActiveSessions() {
368
383
  perf.mark("listActiveSessions");
369
384
  return Array.from(this.activeSessions.values()).sort((left, right) => left.startedAt.localeCompare(right.startedAt));
370
385
  }
386
+ /**
387
+ * Returns a sorted list of all registered usernames.
388
+ *
389
+ * @returns Array of username strings sorted alphabetically.
390
+ */
391
+ listUsers() {
392
+ return Array.from(this.users.keys()).sort();
393
+ }
371
394
  loadFromVfs() {
372
395
  this.users.clear();
373
396
  if (!this.vfs.exists(this.usersPath)) {
@@ -472,6 +495,14 @@ export class VirtualUserManager extends EventEmitter {
472
495
  VirtualUserManager.recordCache.set(cacheKey, record);
473
496
  return record;
474
497
  }
498
+ /**
499
+ * Returns `true` when the user has a non-empty password set.
500
+ *
501
+ * A user with no password (or whose password hash matches the empty-string
502
+ * hash) is allowed to authenticate without a credential check.
503
+ *
504
+ * @param username Target username.
505
+ */
475
506
  hasPassword(username) {
476
507
  perf.mark("hasPassword");
477
508
  if (this.getPasswordHash(username) === this.hashPassword("")) {
@@ -481,10 +512,13 @@ export class VirtualUserManager extends EventEmitter {
481
512
  return !!record && !!record.passwordHash;
482
513
  }
483
514
  /**
484
- * Hashes plaintext password with per-user salt using scrypt.
515
+ * Hashes a plaintext password using scrypt (or SHA-256 in fast-hash mode).
516
+ *
517
+ * Set `SSH_MIMIC_FAST_PASSWORD_HASH=1` to switch to SHA-256 for test
518
+ * environments where scrypt latency is undesirable.
485
519
  *
486
- * @param password Plaintext password.
487
- * @returns Hex-encoded password hash.
520
+ * @param password Plaintext password string.
521
+ * @returns Hex-encoded hash string.
488
522
  */
489
523
  hashPassword(password) {
490
524
  if (VirtualUserManager.fastPasswordHash) {
@@ -0,0 +1,4 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const aliasCommand: ShellModule;
3
+ export declare const unaliasCommand: ShellModule;
4
+ //# sourceMappingURL=alias.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias.d.ts","sourceRoot":"","sources":["../../src/commands/alias.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WAkC1B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAoB5B,CAAC"}