typescript-virtual-container 1.1.3 → 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.
- package/dist/SSHMimic/exec.d.ts.map +1 -1
- package/dist/SSHMimic/exec.js +8 -2
- package/dist/SSHMimic/index.d.ts +1 -0
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +9 -3
- package/dist/SSHMimic/sftp.d.ts +46 -0
- package/dist/SSHMimic/sftp.d.ts.map +1 -0
- package/dist/SSHMimic/sftp.js +576 -0
- package/dist/VirtualFileSystem/index.d.ts +6 -4
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +144 -153
- package/dist/VirtualShell/index.d.ts +6 -0
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +16 -4
- package/dist/VirtualShell/shell.d.ts.map +1 -1
- package/dist/VirtualShell/shell.js +7 -0
- package/dist/VirtualUserManager/index.d.ts +1 -0
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.js +15 -0
- package/dist/commands/exit.d.ts.map +1 -1
- package/dist/commands/exit.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/standalone.js +10 -1
- package/package.json +1 -1
- package/src/SSHMimic/exec.ts +18 -12
- package/src/SSHMimic/index.ts +16 -7
- package/src/SSHMimic/sftp.ts +833 -0
- package/src/VirtualFileSystem/index.ts +158 -188
- package/src/VirtualShell/index.ts +19 -8
- package/src/VirtualShell/shell.ts +7 -0
- package/src/VirtualUserManager/index.ts +20 -0
- package/src/commands/exit.ts +1 -0
- package/src/index.ts +2 -1
- package/src/standalone.ts +11 -1
- package/tests/sftp.test.ts +319 -0
- package/tests/ssh-exec.test.ts +45 -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,
|
|
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"}
|
package/dist/SSHMimic/exec.js
CHANGED
|
@@ -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))
|
|
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
|
}
|
package/dist/SSHMimic/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/SSHMimic/index.js
CHANGED
|
@@ -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
|
|
89
|
-
|
|
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, "
|
|
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"}
|