typescript-virtual-container 1.1.2 → 1.1.4

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 (49) hide show
  1. package/dist/SSHMimic/exec.d.ts.map +1 -1
  2. package/dist/SSHMimic/exec.js +8 -2
  3. package/dist/SSHMimic/index.d.ts +1 -0
  4. package/dist/SSHMimic/index.d.ts.map +1 -1
  5. package/dist/SSHMimic/index.js +9 -3
  6. package/dist/SSHMimic/sftp.d.ts +46 -0
  7. package/dist/SSHMimic/sftp.d.ts.map +1 -0
  8. package/dist/SSHMimic/sftp.js +576 -0
  9. package/dist/VirtualFileSystem/index.d.ts +6 -4
  10. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  11. package/dist/VirtualFileSystem/index.js +144 -153
  12. package/dist/VirtualShell/index.d.ts +6 -0
  13. package/dist/VirtualShell/index.d.ts.map +1 -1
  14. package/dist/VirtualShell/index.js +16 -4
  15. package/dist/VirtualShell/shell.d.ts.map +1 -1
  16. package/dist/VirtualShell/shell.js +7 -0
  17. package/dist/VirtualUserManager/index.d.ts +8 -0
  18. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  19. package/dist/VirtualUserManager/index.js +30 -0
  20. package/dist/commands/exit.d.ts.map +1 -1
  21. package/dist/commands/exit.js +1 -0
  22. package/dist/commands/index.d.ts.map +1 -1
  23. package/dist/commands/index.js +2 -0
  24. package/dist/commands/passwd.d.ts +3 -0
  25. package/dist/commands/passwd.d.ts.map +1 -0
  26. package/dist/commands/passwd.js +21 -0
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -2
  30. package/dist/modules/neofetch.d.ts.map +1 -1
  31. package/dist/modules/neofetch.js +0 -1
  32. package/dist/standalone.js +10 -1
  33. package/package.json +1 -1
  34. package/src/SSHMimic/exec.ts +18 -12
  35. package/src/SSHMimic/index.ts +16 -7
  36. package/src/SSHMimic/sftp.ts +833 -0
  37. package/src/VirtualFileSystem/index.ts +158 -188
  38. package/src/VirtualShell/index.ts +19 -8
  39. package/src/VirtualShell/shell.ts +7 -0
  40. package/src/VirtualUserManager/index.ts +38 -0
  41. package/src/commands/exit.ts +1 -0
  42. package/src/commands/index.ts +2 -0
  43. package/src/commands/passwd.ts +25 -0
  44. package/src/index.ts +2 -1
  45. package/src/modules/neofetch.ts +0 -2
  46. package/src/standalone.ts +11 -1
  47. package/tests/sftp.test.ts +319 -0
  48. package/tests/ssh-exec.test.ts +45 -0
  49. package/tests/users.test.ts +13 -0
@@ -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,CAiBN"}
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"}
@@ -6,7 +6,8 @@ function toTtyLines(text) {
6
6
  .replace(/\n/g, "\r\n");
7
7
  }
8
8
  export function runExec(stream, cmd, authUser, hostname, shell) {
9
- Promise.resolve(runCommand(cmd, authUser, hostname, "exec", `/home/${authUser}`, shell)).then((result) => {
9
+ Promise.resolve(runCommand(cmd, authUser, hostname, "exec", `/home/${authUser}`, shell))
10
+ .then((result) => {
10
11
  if (result.stdout) {
11
12
  stream.write(`${toTtyLines(result.stdout)}\r\n`);
12
13
  }
@@ -14,8 +15,13 @@ export function runExec(stream, cmd, authUser, hostname, shell) {
14
15
  stream.stderr.write(`${toTtyLines(result.stderr)}\r\n`);
15
16
  }
16
17
  stream.exit(result.exitCode ?? 0);
17
- console.log(shell.vfs);
18
18
  void shell.vfs.flushMirror();
19
19
  stream.end();
20
+ })
21
+ .catch((error) => {
22
+ console.error("Exec error:", error);
23
+ stream.stderr.write(`Error: ${String(error)}\r\n`);
24
+ stream.exit(1);
25
+ stream.end();
20
26
  });
21
27
  }
@@ -35,5 +35,6 @@ declare class SshMimic {
35
35
  */
36
36
  stop(): void;
37
37
  }
38
+ export { SftpMimic } from "./sftp";
38
39
  export { SshMimic };
39
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C;;;;;;GAMG;AACH,cAAM,QAAQ;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,aAAa,CAAS;IAE9B;;;;;;OAMG;gBACS,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAkC,GAClC,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,YAAY,CAAC;KACrB;IAOD;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAwGrC;;OAEG;IACI,IAAI,IAAI,IAAI;CAOnB;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI/C;;;;;;GAMG;AACH,cAAM,QAAQ;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,aAAa,CAAS;IAE9B;;;;;;OAMG;gBACS,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAkC,GAClC,EAAE;QACF,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,YAAY,CAAC;KACrB;IAOD;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IA+GrC;;OAEG;IACI,IAAI,IAAI,IAAI;CAOnB;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { Server as SshServer } from "ssh2";
2
2
  import { VirtualShell } from "../VirtualShell";
3
+ import { runExec } from "./exec";
3
4
  import { loadOrCreateHostKey } from "./hostKey";
4
5
  /**
5
6
  * SSH server facade that wires the virtual shell runtime into ssh2 sessions.
@@ -34,6 +35,8 @@ class SshMimic {
34
35
  async start() {
35
36
  const shell = this.shell;
36
37
  const privateKey = loadOrCreateHostKey();
38
+ // Ensure VirtualShell is fully initialized before accepting connections
39
+ await shell.ensureInitialized();
37
40
  this.server = new SshServer({
38
41
  hostKeys: [privateKey],
39
42
  ident: `SSH-2.0-${shell.hostname}`,
@@ -85,15 +88,17 @@ class SshMimic {
85
88
  shell?.startInteractiveSession(stream, authUser, sessionId, remoteAddress, terminalSize);
86
89
  });
87
90
  session.on("exec", (acceptExec, _rejectExec, info) => {
88
- const _stream = acceptExec();
89
- shell?.executeCommand(info.command.trim(), authUser, `/home/${authUser}`);
91
+ const stream = acceptExec();
92
+ if (stream) {
93
+ runExec(stream, info.command.trim(), authUser, shell.hostname, shell);
94
+ }
90
95
  });
91
96
  });
92
97
  });
93
98
  });
94
99
  return new Promise((resolve, reject) => {
95
100
  this.server?.once("error", (err) => reject(err));
96
- this.server?.listen(this.port, "127.0.0.1", () => {
101
+ this.server?.listen(this.port, "0.0.0.0", () => {
97
102
  console.log(`SSH Mimic listening on port ${this.port}`);
98
103
  resolve(this.port);
99
104
  });
@@ -110,4 +115,5 @@ class SshMimic {
110
115
  }
111
116
  }
112
117
  }
118
+ export { SftpMimic } from "./sftp";
113
119
  export { SshMimic };
@@ -0,0 +1,46 @@
1
+ import { Server as SshServer } from "ssh2";
2
+ import type VirtualFileSystem from "../VirtualFileSystem";
3
+ import { VirtualShell } from "../VirtualShell";
4
+ import type { VirtualUserManager } from "../VirtualUserManager";
5
+ export interface SftpMimicOptions {
6
+ port: number;
7
+ hostname?: string;
8
+ shell?: VirtualShell;
9
+ vfs?: VirtualFileSystem;
10
+ users?: VirtualUserManager;
11
+ }
12
+ export declare class SftpMimic {
13
+ port: number;
14
+ server: SshServer | null;
15
+ private readonly hostname;
16
+ private readonly shell;
17
+ private readonly vfs;
18
+ private readonly users;
19
+ private nextHandleId;
20
+ private handles;
21
+ constructor({ port, hostname, shell, vfs, users, }: SftpMimicOptions);
22
+ private getVfs;
23
+ private getUsers;
24
+ start(): Promise<number>;
25
+ stop(): void;
26
+ /**
27
+ * Resolves SFTP request paths with proper handling of relative paths.
28
+ * Relative paths (including ".") are resolved relative to the user's home directory.
29
+ * This is standard SFTP behavior where the "working directory" is always the home.
30
+ */
31
+ private resolveRequestPath;
32
+ /**
33
+ * Verifies that a target path is confined within the user's home directory.
34
+ * This implements chroot-like behavior for security.
35
+ * @param targetPath - The normalized target path
36
+ * @param authUser - The authenticated username
37
+ * @returns true if path is within home, false if traversal attempt detected
38
+ */
39
+ private isPathWithinHome;
40
+ private createAttrs;
41
+ private openHandle;
42
+ private getHandle;
43
+ private closeHandle;
44
+ private attachSftpHandlers;
45
+ }
46
+ //# sourceMappingURL=sftp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sftp.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/sftp.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,KAAK,iBAAiB,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA2HhE,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AAED,qBAAa,SAAS;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,OAAO,CAAiC;gBAEpC,EACX,IAAI,EACJ,QAA0B,EAC1B,KAAK,EACL,GAAG,EACH,KAAK,GACL,EAAE,gBAAgB;IAsBnB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,QAAQ;IAIH,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAuI9B,IAAI,IAAI,IAAI;IAQnB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;CA6a1B"}