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.
- package/README.md +457 -42
- package/dist/SSHMimic/executor.js +3 -5
- package/dist/VirtualFileSystem/binaryPack.d.ts +49 -0
- package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -0
- package/dist/VirtualFileSystem/binaryPack.js +193 -0
- package/dist/VirtualFileSystem/index.d.ts +7 -5
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +20 -9
- package/dist/VirtualPackageManager/index.d.ts +202 -0
- package/dist/VirtualPackageManager/index.d.ts.map +1 -0
- package/dist/VirtualPackageManager/index.js +676 -0
- package/dist/VirtualShell/index.d.ts +87 -12
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +83 -12
- package/dist/VirtualUserManager/index.d.ts +52 -20
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.js +54 -20
- package/dist/commands/alias.d.ts +4 -0
- package/dist/commands/alias.d.ts.map +1 -0
- package/dist/commands/alias.js +58 -0
- package/dist/commands/apt.d.ts +4 -0
- package/dist/commands/apt.d.ts.map +1 -0
- package/dist/commands/apt.js +182 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +27 -8
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +52 -3
- package/dist/commands/command-helpers.d.ts +78 -4
- package/dist/commands/command-helpers.d.ts.map +1 -1
- package/dist/commands/command-helpers.js +78 -4
- package/dist/commands/curl.d.ts.map +1 -1
- package/dist/commands/curl.js +81 -29
- package/dist/commands/dpkg.d.ts +4 -0
- package/dist/commands/dpkg.d.ts.map +1 -0
- package/dist/commands/dpkg.js +144 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +24 -12
- package/dist/commands/free.d.ts +3 -0
- package/dist/commands/free.d.ts.map +1 -0
- package/dist/commands/free.js +38 -0
- package/dist/commands/helpers.d.ts +3 -0
- package/dist/commands/helpers.d.ts.map +1 -1
- package/dist/commands/helpers.js +3 -0
- package/dist/commands/history.d.ts +3 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +21 -0
- package/dist/commands/index.d.ts +8 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +120 -11
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +4 -3
- package/dist/commands/lsb-release.d.ts +3 -0
- package/dist/commands/lsb-release.d.ts.map +1 -0
- package/dist/commands/lsb-release.js +50 -0
- package/dist/commands/man.d.ts +3 -0
- package/dist/commands/man.d.ts.map +1 -0
- package/dist/commands/man.js +155 -0
- package/dist/commands/neofetch.d.ts.map +1 -1
- package/dist/commands/neofetch.js +5 -0
- package/dist/commands/ping.d.ts.map +1 -1
- package/dist/commands/ping.js +5 -2
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +27 -6
- package/dist/commands/sh.d.ts.map +1 -1
- package/dist/commands/sh.js +29 -11
- package/dist/commands/source.d.ts +3 -0
- package/dist/commands/source.d.ts.map +1 -0
- package/dist/commands/source.js +31 -0
- package/dist/commands/test.d.ts +3 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +92 -0
- package/dist/commands/type.d.ts +3 -0
- package/dist/commands/type.d.ts.map +1 -0
- package/dist/commands/type.js +34 -0
- package/dist/commands/uptime.d.ts +3 -0
- package/dist/commands/uptime.d.ts.map +1 -0
- package/dist/commands/uptime.js +40 -0
- package/dist/commands/wget.d.ts.map +1 -1
- package/dist/commands/wget.js +71 -100
- package/dist/commands/which.d.ts +3 -0
- package/dist/commands/which.d.ts.map +1 -0
- package/dist/commands/which.js +32 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/modules/linuxRootfs.d.ts +24 -0
- package/dist/modules/linuxRootfs.d.ts.map +1 -0
- package/dist/modules/linuxRootfs.js +297 -0
- package/dist/modules/neofetch.d.ts.map +1 -1
- package/dist/modules/neofetch.js +1 -0
- package/dist/standalone.js +4 -1
- package/package.json +2 -1
- package/src/SSHMimic/executor.ts +3 -5
- package/src/VirtualFileSystem/binaryPack.ts +219 -0
- package/src/VirtualFileSystem/index.ts +21 -11
- package/src/VirtualPackageManager/index.ts +820 -0
- package/src/VirtualShell/index.ts +104 -13
- package/src/VirtualUserManager/index.ts +55 -20
- package/src/commands/alias.ts +60 -0
- package/src/commands/apt.ts +198 -0
- package/src/commands/cat.ts +32 -8
- package/src/commands/chmod.ts +48 -3
- package/src/commands/command-helpers.ts +78 -4
- package/src/commands/curl.ts +78 -37
- package/src/commands/dpkg.ts +158 -0
- package/src/commands/echo.ts +30 -14
- package/src/commands/free.ts +40 -0
- package/src/commands/helpers.ts +8 -0
- package/src/commands/history.ts +29 -0
- package/src/commands/index.ts +116 -11
- package/src/commands/ls.ts +5 -4
- package/src/commands/lsb-release.ts +52 -0
- package/src/commands/man.ts +166 -0
- package/src/commands/neofetch.ts +5 -0
- package/src/commands/ping.ts +5 -2
- package/src/commands/ps.ts +28 -6
- package/src/commands/sh.ts +33 -11
- package/src/commands/source.ts +35 -0
- package/src/commands/test.ts +100 -0
- package/src/commands/type.ts +40 -0
- package/src/commands/uptime.ts +46 -0
- package/src/commands/wget.ts +70 -123
- package/src/commands/which.ts +34 -0
- package/src/index.ts +10 -0
- package/src/modules/linuxRootfs.ts +439 -0
- package/src/modules/neofetch.ts +1 -0
- package/src/standalone.ts +4 -1
- package/standalone.js +418 -103
- package/standalone.js.map +4 -4
- 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,
|
|
32
|
+
* Coordinates the virtual filesystem, user manager, package manager, and
|
|
33
|
+
* command runtime for a single isolated shell environment.
|
|
13
34
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
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
|
|
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
|
-
*
|
|
102
|
+
* Attaches an interactive PTY session to this shell instance.
|
|
54
103
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
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;
|
|
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,
|
|
23
|
+
* Coordinates the virtual filesystem, user manager, package manager, and
|
|
24
|
+
* command runtime for a single isolated shell environment.
|
|
22
25
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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
|
|
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
|
-
*
|
|
132
|
+
* Attaches an interactive PTY session to this shell instance.
|
|
92
133
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
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
|
|
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
|
|
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
|
|
153
|
+
* Registers a new active session and allocates a virtual TTY identifier.
|
|
150
154
|
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
172
|
+
* Updates the username and remote address metadata for an active session.
|
|
164
173
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,iBAAiB,MAAM,sBAAsB,CAAC;AAE1D,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IACjC,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACpC,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;CAClB;AAYD;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAqBlD,OAAO,CAAC,QAAQ,CAAC,GAAG;IAGpB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAvBrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAwC;IAC3E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;IAC/D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA2B;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2C;IAC1E,OAAO,CAAC,OAAO,CAAK;IAEpB;;;;;;OAMG;gBAEe,GAAG,EAAE,iBAAiB,EAGtB,mBAAmB,GAAE,OAAc;IAMrD;;;OAGG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAsCxC;;;;;OAKG;IACU,aAAa,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC;IAehB;;;;OAIG;IACU,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxD;;;;;OAKG;IACI,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKrD;;;;;OAKG;IACI,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAU9C;;;;;;;;OAQG;IACI,sBAAsB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAAG,MAAM,GAC1B,IAAI;IAoCP;;;;;;OAMG;IACI,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAUlE;;;;;OAKG;IACU,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BvE;;;;;OAKG;IACI,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMvD
|
|
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
|
|
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
|
|
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
|
|
301
|
+
* Registers a new active session and allocates a virtual TTY identifier.
|
|
298
302
|
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
350
|
+
* Updates the username and remote address metadata for an active session.
|
|
342
351
|
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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 @@
|
|
|
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"}
|