typescript-virtual-container 1.4.8 → 1.5.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 (173) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/README.md +118 -80
  3. package/builds/self-standalone.mjs +1768 -0
  4. package/builds/standalone-wo-sftp.js +735 -268
  5. package/builds/standalone.cjs +734 -267
  6. package/builds/web-full-api.min.js +0 -1
  7. package/builds/web.min.js +0 -1
  8. package/bun.lock +3 -3
  9. package/dist/Honeypot/index.d.ts +6 -0
  10. package/dist/Honeypot/index.d.ts.map +1 -1
  11. package/dist/Honeypot/index.js +20 -0
  12. package/dist/Honeypot/index.js.map +1 -1
  13. package/dist/SSHMimic/exec.js +2 -2
  14. package/dist/SSHMimic/exec.js.map +1 -1
  15. package/dist/SSHMimic/index.d.ts +6 -5
  16. package/dist/SSHMimic/index.d.ts.map +1 -1
  17. package/dist/SSHMimic/index.js +8 -6
  18. package/dist/SSHMimic/index.js.map +1 -1
  19. package/dist/SSHMimic/sftp.d.ts +1 -0
  20. package/dist/SSHMimic/sftp.d.ts.map +1 -1
  21. package/dist/SSHMimic/sftp.js +4 -3
  22. package/dist/SSHMimic/sftp.js.map +1 -1
  23. package/dist/VirtualFileSystem/index.d.ts +14 -0
  24. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  25. package/dist/VirtualFileSystem/index.js +51 -3
  26. package/dist/VirtualFileSystem/index.js.map +1 -1
  27. package/dist/VirtualFileSystem/internalTypes.d.ts +4 -0
  28. package/dist/VirtualFileSystem/internalTypes.d.ts.map +1 -1
  29. package/dist/VirtualFileSystem/journal.d.ts +1 -0
  30. package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
  31. package/dist/VirtualFileSystem/journal.js +11 -5
  32. package/dist/VirtualFileSystem/journal.js.map +1 -1
  33. package/dist/VirtualShell/idleManager.d.ts +6 -2
  34. package/dist/VirtualShell/idleManager.d.ts.map +1 -1
  35. package/dist/VirtualShell/idleManager.js +10 -6
  36. package/dist/VirtualShell/idleManager.js.map +1 -1
  37. package/dist/VirtualShell/index.d.ts +13 -1
  38. package/dist/VirtualShell/index.d.ts.map +1 -1
  39. package/dist/VirtualShell/index.js +10 -5
  40. package/dist/VirtualShell/index.js.map +1 -1
  41. package/dist/VirtualShell/shell.js +12 -12
  42. package/dist/VirtualShell/shell.js.map +1 -1
  43. package/dist/VirtualUserManager/index.d.ts +4 -2
  44. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  45. package/dist/VirtualUserManager/index.js +8 -12
  46. package/dist/VirtualUserManager/index.js.map +1 -1
  47. package/dist/commands/apt.js +3 -3
  48. package/dist/commands/apt.js.map +1 -1
  49. package/dist/commands/cd.d.ts.map +1 -1
  50. package/dist/commands/cd.js +2 -1
  51. package/dist/commands/cd.js.map +1 -1
  52. package/dist/commands/command-helpers.d.ts +5 -2
  53. package/dist/commands/command-helpers.d.ts.map +1 -1
  54. package/dist/commands/command-helpers.js.map +1 -1
  55. package/dist/commands/helpers.d.ts +1 -1
  56. package/dist/commands/helpers.d.ts.map +1 -1
  57. package/dist/commands/helpers.js +3 -2
  58. package/dist/commands/helpers.js.map +1 -1
  59. package/dist/commands/index.d.ts +1 -1
  60. package/dist/commands/index.d.ts.map +1 -1
  61. package/dist/commands/index.js +1 -1
  62. package/dist/commands/index.js.map +1 -1
  63. package/dist/commands/lsb-release.js +1 -1
  64. package/dist/commands/lsb-release.js.map +1 -1
  65. package/dist/commands/runtime.d.ts +2 -0
  66. package/dist/commands/runtime.d.ts.map +1 -1
  67. package/dist/commands/runtime.js +5 -1
  68. package/dist/commands/runtime.js.map +1 -1
  69. package/dist/index.d.ts +5 -2
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/modules/linuxRootfs.d.ts +9 -5
  73. package/dist/modules/linuxRootfs.d.ts.map +1 -1
  74. package/dist/modules/linuxRootfs.js +1079 -148
  75. package/dist/modules/linuxRootfs.js.map +1 -1
  76. package/dist/self-standalone.js +22 -12
  77. package/dist/self-standalone.js.map +1 -1
  78. package/docs/assets/hierarchy.js +1 -1
  79. package/docs/assets/navigation.js +1 -1
  80. package/docs/assets/search.js +1 -1
  81. package/docs/classes/HoneyPot.html +9 -9
  82. package/docs/classes/IdleManager.html +12 -9
  83. package/docs/classes/SshClient.html +18 -18
  84. package/docs/classes/VirtualFileSystem.html +34 -42
  85. package/docs/classes/VirtualPackageManager.html +13 -13
  86. package/docs/classes/VirtualSftpServer.html +3 -3
  87. package/docs/classes/VirtualShell.html +33 -29
  88. package/docs/classes/VirtualSshServer.html +12 -7
  89. package/docs/classes/VirtualUserManager.html +30 -30
  90. package/docs/functions/assertDiff.html +2 -2
  91. package/docs/functions/diffSnapshots.html +2 -2
  92. package/docs/functions/formatDiff.html +2 -2
  93. package/docs/functions/getArg.html +3 -3
  94. package/docs/functions/getFlag.html +2 -2
  95. package/docs/functions/ifFlag.html +2 -2
  96. package/docs/hierarchy.html +1 -1
  97. package/docs/index.html +11 -9
  98. package/docs/interfaces/AuditLogEntry.html +3 -3
  99. package/docs/interfaces/CommandContext.html +13 -13
  100. package/docs/interfaces/CommandResult.html +13 -13
  101. package/docs/interfaces/ExecStream.html +6 -6
  102. package/docs/interfaces/HoneyPotStats.html +5 -3
  103. package/docs/interfaces/IdleManagerOptions.html +3 -3
  104. package/docs/interfaces/InstalledPackage.html +11 -11
  105. package/docs/interfaces/NanoEditorSession.html +5 -5
  106. package/docs/interfaces/PackageDefinition.html +14 -14
  107. package/docs/interfaces/PackageFile.html +5 -5
  108. package/docs/interfaces/PasswordChallenge.html +16 -0
  109. package/docs/interfaces/RemoveOptions.html +3 -3
  110. package/docs/interfaces/ShellEnv.html +4 -4
  111. package/docs/interfaces/ShellModule.html +8 -8
  112. package/docs/interfaces/ShellProperties.html +5 -5
  113. package/docs/interfaces/ShellStream.html +7 -7
  114. package/docs/interfaces/SudoChallenge.html +9 -9
  115. package/docs/interfaces/VfsBaseNode.html +7 -7
  116. package/docs/interfaces/VfsDiff.html +6 -6
  117. package/docs/interfaces/VfsDiffEntry.html +4 -4
  118. package/docs/interfaces/VfsDiffModified.html +6 -6
  119. package/docs/interfaces/VfsDirectoryNode.html +8 -8
  120. package/docs/interfaces/VfsFileNode.html +9 -9
  121. package/docs/interfaces/VfsOptions.html +6 -6
  122. package/docs/interfaces/VfsSnapshot.html +3 -3
  123. package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
  124. package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
  125. package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
  126. package/docs/interfaces/VirtualActiveSession.html +12 -0
  127. package/docs/interfaces/VirtualSftpServerOptions.html +7 -0
  128. package/docs/interfaces/VirtualShellVfsLike.html +15 -0
  129. package/docs/interfaces/VirtualShellVfsOptions.html +3 -0
  130. package/docs/interfaces/WriteFileOptions.html +4 -4
  131. package/docs/modules.html +1 -1
  132. package/docs/types/ArgParseOptions.html +4 -0
  133. package/docs/types/CommandMode.html +2 -2
  134. package/docs/types/CommandOutcome.html +2 -2
  135. package/docs/types/IdleState.html +1 -1
  136. package/docs/types/VfsNodeStats.html +2 -2
  137. package/docs/types/VfsNodeType.html +2 -2
  138. package/docs/types/VfsPersistenceMode.html +2 -2
  139. package/docs/types/VfsSnapshotNode.html +2 -2
  140. package/examples/web.min.js +0 -1
  141. package/package.json +11 -11
  142. package/scripts/generate-manuals-bundle.mjs +1 -1
  143. package/scripts/publish-package.sh +1 -1
  144. package/src/Honeypot/index.ts +24 -0
  145. package/src/SSHMimic/exec.ts +2 -2
  146. package/src/SSHMimic/index.ts +9 -6
  147. package/src/SSHMimic/sftp.ts +10 -3
  148. package/src/VirtualFileSystem/index.ts +46 -3
  149. package/src/VirtualFileSystem/internalTypes.ts +4 -0
  150. package/src/VirtualFileSystem/journal.ts +11 -5
  151. package/src/VirtualShell/idleManager.ts +10 -6
  152. package/src/VirtualShell/index.ts +18 -3
  153. package/src/VirtualShell/shell.ts +12 -12
  154. package/src/VirtualUserManager/index.ts +15 -13
  155. package/src/commands/apt.ts +3 -3
  156. package/src/commands/cd.ts +2 -1
  157. package/src/commands/command-helpers.ts +5 -1
  158. package/src/commands/helpers.ts +3 -2
  159. package/src/commands/index.ts +1 -1
  160. package/src/commands/lsb-release.ts +1 -1
  161. package/src/commands/runtime.ts +6 -1
  162. package/src/index.ts +5 -1
  163. package/src/modules/linuxRootfs.ts +1293 -207
  164. package/src/self-standalone.ts +26 -12
  165. package/tests/new-features.test.ts +2 -2
  166. package/tests/sftp.test.ts +13 -13
  167. package/typedoc.json +45 -0
  168. package/builds/self-standalone.js +0 -1300
  169. package/builds/self-standalone.js.map +0 -7
  170. package/builds/standalone-wo-sftp.js.map +0 -7
  171. package/builds/standalone.cjs.map +0 -7
  172. package/builds/web-full-api.min.js.map +0 -7
  173. package/builds/web.min.js.map +0 -7
@@ -42,6 +42,10 @@ export interface ShellProperties {
42
42
  arch: string;
43
43
  }
44
44
 
45
+ /**
46
+ * Minimal VFS interface accepted by {@link VirtualShell} as a drop-in replacement
47
+ * for the built-in {@link VirtualFileSystem}.
48
+ */
45
49
  export interface VirtualShellVfsLike {
46
50
  restoreMirror(): Promise<void>;
47
51
  flushMirror(): Promise<void>;
@@ -57,6 +61,9 @@ export interface VirtualShellVfsLike {
57
61
  getUsageBytes?(targetPath?: string): number;
58
62
  }
59
63
 
64
+ /**
65
+ * Constructor options for {@link VirtualShell} when passing an existing VFS instance.
66
+ */
60
67
  export interface VirtualShellVfsOptions {
61
68
  vfsInstance?: VirtualShellVfsLike;
62
69
  }
@@ -153,7 +160,7 @@ class VirtualShell extends EventEmitter {
153
160
  *
154
161
  * @param hostname Virtual hostname used for prompts and idents.
155
162
  * @param properties Customizable properties shown in `uname -a` and similar commands.
156
- * @param vfsOptions Optional VFS persistence options (mode, snapshotPath).
163
+ * @param vfsOptionsOrInstance Optional VFS persistence options (mode, snapshotPath) or an existing VFS instance.
157
164
  */
158
165
  constructor(
159
166
  hostname: string,
@@ -239,7 +246,7 @@ class VirtualShell extends EventEmitter {
239
246
  */
240
247
  executeCommand(rawInput: string, authUser: string, cwd: string): void {
241
248
  perf.mark("executeCommand");
242
- if (this._idle) void this._idle.ping();
249
+ this._idle?.ping();
243
250
  runCommand(rawInput, authUser, this.hostname, "shell", cwd, this);
244
251
  this.emit("command", { command: rawInput, user: authUser, cwd });
245
252
  }
@@ -266,7 +273,7 @@ class VirtualShell extends EventEmitter {
266
273
  terminalSize: { cols: number; rows: number },
267
274
  ): void {
268
275
  perf.mark("startInteractiveSession");
269
- if (this._idle) void this._idle.ping();
276
+ this._idle?.ping();
270
277
  // Interactive shell logic
271
278
  this.emit("session:start", { user: authUser, sessionId, remoteAddress });
272
279
  startShell(
@@ -452,6 +459,14 @@ class VirtualShell extends EventEmitter {
452
459
  public get idleMs(): number {
453
460
  return this._idle?.idleMs ?? 0;
454
461
  }
462
+
463
+ /**
464
+ * Ping the idle manager to signal external activity (e.g. SFTP, direct VFS writes).
465
+ * No-op when idle management is disabled.
466
+ */
467
+ public pingIdle(): void {
468
+ this._idle?.ping();
469
+ }
455
470
  }
456
471
 
457
472
  export { VirtualShell };
@@ -2,7 +2,7 @@ import type { ChildProcessWithoutNullStreams } from "node:child_process";
2
2
  import { readFile, unlink, writeFile } from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import type { ShellProperties, VirtualShell } from ".";
5
- import { getCommandNames, makeDefaultEnv, runCommand } from "../commands";
5
+ import { getCommandNames, makeDefaultEnv, runCommand, userHome } from "../commands";
6
6
  import {
7
7
  spawnHtopProcess,
8
8
  spawnNanoEditorProcess,
@@ -55,12 +55,12 @@ export function startShell(
55
55
  let history = loadHistory(shell.vfs, authUser);
56
56
  let historyIndex: number | null = null;
57
57
  let historyDraft = "";
58
- let cwd = `/home/${authUser}`;
58
+ let cwd = userHome(authUser);
59
59
  const shellEnv: ShellEnv = makeDefaultEnv(authUser, hostname);
60
60
  let nanoSession: NanoSession | null = null;
61
61
  let pendingSudo: PendingSudo | null = null;
62
62
  const buildCurrentPrompt = (): string => {
63
- const homePath = `/home/${authUser}`;
63
+ const homePath = userHome(authUser);
64
64
  const cwdLabel = cwd === homePath ? "~" : path.posix.basename(cwd) || "/";
65
65
  return buildPrompt(authUser, hostname, cwdLabel);
66
66
  };
@@ -71,7 +71,7 @@ export function startShell(
71
71
 
72
72
  // Load .bashrc if it exists
73
73
  void (async () => {
74
- const bashrcPath = `/home/${authUser}/.bashrc`;
74
+ const bashrcPath = `${userHome(authUser)}/.bashrc`;
75
75
  if (shell.vfs.exists(bashrcPath)) {
76
76
  try {
77
77
  const bashrc = shell.vfs.readFile(bashrcPath);
@@ -146,7 +146,7 @@ export function startShell(
146
146
  if (!challenge.commandLine) {
147
147
  authUser = challenge.targetUser;
148
148
  if (challenge.loginShell) {
149
- cwd = `/home/${authUser}`;
149
+ cwd = userHome(authUser);
150
150
  }
151
151
  shell.users.updateSession(sessionId, authUser, remoteAddress);
152
152
  stream.write("\r\n");
@@ -154,7 +154,7 @@ export function startShell(
154
154
  return;
155
155
  }
156
156
 
157
- const runCwd = challenge.loginShell ? `/home/${challenge.targetUser}` : cwd;
157
+ const runCwd = challenge.loginShell ? userHome(challenge.targetUser) : cwd;
158
158
  const result = await Promise.resolve(
159
159
  runCommand(
160
160
  challenge.commandLine,
@@ -196,7 +196,7 @@ export function startShell(
196
196
 
197
197
  if (result.switchUser) {
198
198
  authUser = result.switchUser;
199
- cwd = result.nextCwd ?? `/home/${authUser}`;
199
+ cwd = result.nextCwd ?? userHome(authUser);
200
200
  shell.users.updateSession(sessionId, authUser, remoteAddress);
201
201
  } else if (result.nextCwd) {
202
202
  cwd = result.nextCwd;
@@ -388,11 +388,11 @@ export function startShell(
388
388
  }
389
389
 
390
390
  const data = history.length > 0 ? `${history.join("\n")}\n` : "";
391
- shell.vfs.writeFile(`/home/${authUser}/.bash_history`, data);
391
+ shell.vfs.writeFile(`${userHome(authUser)}/.bash_history`, data);
392
392
  }
393
393
 
394
394
  function readLastLogin(): { at: string; from: string } | null {
395
- const lastlogPath = `/home/${authUser}/.lastlog.json`;
395
+ const lastlogPath = `${userHome(authUser)}/.lastlog.json`;
396
396
  if (!shell.vfs.exists(lastlogPath)) {
397
397
  return null;
398
398
  }
@@ -408,7 +408,7 @@ export function startShell(
408
408
  }
409
409
 
410
410
  function writeLastLogin(nowIso: string): void {
411
- const lastlogPath = `/home/${authUser}/.lastlog`;
411
+ const lastlogPath = `${userHome(authUser)}/.lastlog`;
412
412
  shell.vfs.writeFile(
413
413
  lastlogPath,
414
414
  JSON.stringify({ at: nowIso, from: remoteAddress }),
@@ -651,7 +651,7 @@ export function startShell(
651
651
 
652
652
  if (result.switchUser) {
653
653
  authUser = result.switchUser;
654
- cwd = result.nextCwd ?? `/home/${authUser}`;
654
+ cwd = result.nextCwd ?? userHome(authUser);
655
655
  shell.users.updateSession(sessionId, authUser, remoteAddress);
656
656
  lineBuffer = "";
657
657
  cursorPos = 0;
@@ -686,7 +686,7 @@ export function startShell(
686
686
  }
687
687
 
688
688
  function loadHistory(vfs: VirtualFileSystem, authUser: string): string[] {
689
- const historyPath = `/home/${authUser}/.bash_history`;
689
+ const historyPath = `${userHome(authUser)}/.bash_history`;
690
690
  if (!vfs.exists(historyPath)) {
691
691
  vfs.writeFile(historyPath, "");
692
692
  return [];
@@ -5,7 +5,10 @@ import type { PerfLogger } from "../utils/perfLogger";
5
5
  import { createPerfLogger } from "../utils/perfLogger";
6
6
  import type VirtualFileSystem from "../VirtualFileSystem";
7
7
 
8
- /** Persisted virtual user credential record. */
8
+ /**
9
+ * Persisted virtual user credential record.
10
+ * @internal
11
+ */
9
12
  export interface VirtualUserRecord {
10
13
  /** Unique login name. */
11
14
  username: string;
@@ -61,7 +64,6 @@ export class VirtualUserManager extends EventEmitter {
61
64
  * Creates a user manager instance backed by a virtual filesystem.
62
65
  *
63
66
  * @param vfs Backing virtual filesystem used for persistence.
64
- * @param defaultRootPassword Initial root password used when root is created.
65
67
  * @param autoSudoForNewUsers Whether newly created users are added to sudoers.
66
68
  */
67
69
  constructor(
@@ -101,14 +103,14 @@ export class VirtualUserManager extends EventEmitter {
101
103
  // changed = true;
102
104
  // }
103
105
 
104
- // const homePath = `/home/root`;
105
- // if (!this.vfs.exists(homePath)) {
106
- // this.vfs.mkdir(homePath, 0o755);
107
- // this.vfs.writeFile(
108
- // `${homePath}/README.txt`,
109
- // `Welcome to the virtual environment, root`,
110
- // );
111
- // }
106
+ const homePath = "/root";
107
+ if (!this.vfs.exists(homePath)) {
108
+ this.vfs.mkdir(homePath, 0o755);
109
+ this.vfs.writeFile(
110
+ `${homePath}/README.txt`,
111
+ `Welcome to the virtual environment, root`,
112
+ );
113
+ }
112
114
 
113
115
  if (changed) {
114
116
  await this.persist();
@@ -171,7 +173,7 @@ export class VirtualUserManager extends EventEmitter {
171
173
  */
172
174
  public getUsageBytes(username: string): number {
173
175
  perf.mark("getUsageBytes");
174
- const homePath = `/home/${username}`;
176
+ const homePath = username === "root" ? "/root" : `/home/${username}`;
175
177
  if (!this.vfs.exists(homePath)) {
176
178
  return 0;
177
179
  }
@@ -200,7 +202,7 @@ export class VirtualUserManager extends EventEmitter {
200
202
  }
201
203
 
202
204
  const normalizedPath = normalizeVfsPath(targetPath);
203
- const homePath = normalizeVfsPath(`/home/${username}`);
205
+ const homePath = normalizeVfsPath(username === "root" ? "/root" : `/home/${username}`);
204
206
  const inUserHome =
205
207
  normalizedPath === homePath || normalizedPath.startsWith(`${homePath}/`);
206
208
  if (!inUserHome) {
@@ -277,7 +279,7 @@ export class VirtualUserManager extends EventEmitter {
277
279
  if (this.autoSudoForNewUsers) {
278
280
  this.sudoers.add(username);
279
281
  }
280
- const homePath = `/home/${username}`;
282
+ const homePath = username === "root" ? "/root" : `/home/${username}`;
281
283
  if (!this.vfs.exists(homePath)) {
282
284
  this.vfs.mkdir(homePath, 0o755);
283
285
  this.vfs.writeFile(
@@ -57,8 +57,8 @@ export const aptCommand: ShellModule = {
57
57
  case "update": {
58
58
  return {
59
59
  stdout: [
60
- "Hit:1 fortune://packages.fortune.local aurora InRelease",
61
- "Hit:2 fortune://security.fortune.local aurora-security InRelease",
60
+ "Hit:1 fortune://packages.fortune.local nyx InRelease",
61
+ "Hit:2 fortune://security.fortune.local nyx-security InRelease",
62
62
  "Reading package lists... Done",
63
63
  "Building dependency tree... Done",
64
64
  "Reading state information... Done",
@@ -218,7 +218,7 @@ export const aptCacheCommand: ShellModule = {
218
218
  ` Candidate: ${def.version}`,
219
219
  ` Version table:`,
220
220
  ` ${def.version} 500`,
221
- ` 500 fortune://packages.fortune.local aurora/main amd64 Packages`,
221
+ ` 500 fortune://packages.fortune.local nyx/main amd64 Packages`,
222
222
  ].join("\n"),
223
223
  exitCode: 0,
224
224
  };
@@ -1,5 +1,6 @@
1
1
  import type { ShellModule } from "../types/commands";
2
2
  import { assertPathAccess, resolvePath } from "./helpers";
3
+ import { userHome } from "./runtime";
3
4
 
4
5
  /**
5
6
  * Change current working directory.
@@ -12,7 +13,7 @@ export const cdCommand: ShellModule = {
12
13
  category: "navigation",
13
14
  params: ["[path]"],
14
15
  run: ({ authUser, shell, cwd, args }) => {
15
- const target = resolvePath(cwd, args[0] ?? `~`);
16
+ const target = resolvePath(cwd, args[0] ?? "~", userHome(authUser));
16
17
  assertPathAccess(authUser, target, "cd");
17
18
  const stats = shell.vfs.stat(target);
18
19
  if (stats.type !== "directory") {
@@ -1,4 +1,8 @@
1
- type ArgParseOptions = {
1
+ /**
2
+ * Options for argument parsing helpers.
3
+ * @public
4
+ */
5
+ export type ArgParseOptions = {
2
6
  flags?: string[];
3
7
  flagsWithValue?: string[];
4
8
  };
@@ -28,12 +28,13 @@ export function normalizeTerminalOutput(text: string): string {
28
28
  .trimEnd();
29
29
  }
30
30
 
31
- export function resolvePath(cwd: string, inputPath: string): string {
31
+ export function resolvePath(cwd: string, inputPath: string, homeDir?: string): string {
32
32
  if (!inputPath || inputPath.trim() === "") {
33
33
  return cwd;
34
34
  }
35
35
  if (inputPath.startsWith("~")) {
36
- return path.posix.normalize(`/home/${inputPath.slice(1)}`);
36
+ const home = homeDir ?? "/root";
37
+ return path.posix.normalize(`${home}${inputPath.slice(1)}`);
37
38
  }
38
39
  return inputPath.startsWith("/")
39
40
  ? path.posix.normalize(inputPath)
@@ -6,4 +6,4 @@ export {
6
6
  resolveModule
7
7
  } from "./registry";
8
8
 
9
- export { makeDefaultEnv, runCommand, runCommandDirect } from "./runtime";
9
+ export { makeDefaultEnv, runCommand, runCommandDirect, userHome } from "./runtime";
@@ -13,7 +13,7 @@ export const lsbReleaseCommand: ShellModule = {
13
13
  params: ["[-a] [-i] [-d] [-r] [-c]"],
14
14
  run: ({ args, shell }) => {
15
15
  let osName = shell.properties?.os ?? "Fortune GNU/Linux x64";
16
- let codename = "aurora";
16
+ let codename = "nyx";
17
17
  let version = "1.0";
18
18
 
19
19
  try {
@@ -11,11 +11,16 @@ import { expandAsync, expandBraces } from "../utils/expand";
11
11
  import { tokenizeCommand } from "../utils/tokenize";
12
12
  import { resolveModule } from "./registry";
13
13
 
14
+ /** Returns the home directory path for a given user. Root lives at /root. */
15
+ export function userHome(authUser: string): string {
16
+ return authUser === "root" ? "/root" : `/home/${authUser}`;
17
+ }
18
+
14
19
  export function makeDefaultEnv(authUser: string, hostname: string): ShellEnv {
15
20
  return {
16
21
  vars: {
17
22
  PATH: "/usr/local/bin:/usr/bin:/bin",
18
- HOME: `/home/${authUser}`,
23
+ HOME: userHome(authUser),
19
24
  USER: authUser,
20
25
  LOGNAME: authUser,
21
26
  SHELL: "/bin/sh",
package/src/index.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export { HoneyPot } from "./Honeypot/index";
2
2
  export { SshClient } from "./SSHClient/index";
3
3
  export { SftpMimic as VirtualSftpServer, SshMimic as VirtualSshServer } from "./SSHMimic/index";
4
+ export type { SftpMimicOptions as VirtualSftpServerOptions } from "./SSHMimic/sftp";
4
5
  export { default as VirtualFileSystem } from "./VirtualFileSystem/index";
5
6
  export { VirtualPackageManager } from "./VirtualPackageManager/index";
6
7
  export { VirtualShell } from "./VirtualShell/index";
7
8
  export { VirtualUserManager } from "./VirtualUserManager/index";
9
+ export type { VirtualActiveSession } from "./VirtualUserManager/index";
8
10
  export { IdleManager } from "./VirtualShell/idleManager";
9
11
  export type { IdleManagerOptions, IdleState } from "./VirtualShell/idleManager";
10
12
 
@@ -18,6 +20,7 @@ export type {
18
20
  CommandOutcome,
19
21
  CommandResult,
20
22
  NanoEditorSession,
23
+ PasswordChallenge,
21
24
  ShellEnv,
22
25
  ShellModule,
23
26
  SudoChallenge
@@ -38,7 +41,7 @@ export type {
38
41
  WriteFileOptions
39
42
  } from "./types/vfs";
40
43
  export type { VfsOptions, VfsPersistenceMode } from "./VirtualFileSystem/index";
41
- export type { ShellProperties } from "./VirtualShell/index";
44
+ export type { ShellProperties, VirtualShellVfsLike, VirtualShellVfsOptions } from "./VirtualShell/index";
42
45
 
43
46
  export type {
44
47
  InstalledPackage, PackageDefinition,
@@ -60,4 +63,5 @@ export {
60
63
  getFlag,
61
64
  ifFlag
62
65
  } from "./commands/command-helpers";
66
+ export type { ArgParseOptions } from "./commands/command-helpers";
63
67