typescript-virtual-container 1.4.9 → 1.5.1
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/.vscode/settings.json +1 -1
- package/README.md +141 -89
- package/builds/fortune-nyx-v1.5.1-directbash-k6.1.0.mjs +1768 -0
- package/builds/fortune-nyx-v1.5.1-ssh-nosftp.js +1768 -0
- package/builds/fortune-nyx-v1.5.1-ssh.cjs +1769 -0
- package/bun.lock +3 -3
- package/dist/SSHMimic/exec.js +2 -2
- package/dist/SSHMimic/exec.js.map +1 -1
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +2 -1
- package/dist/SSHMimic/index.js.map +1 -1
- package/dist/SSHMimic/sftp.d.ts.map +1 -1
- package/dist/SSHMimic/sftp.js +4 -3
- package/dist/SSHMimic/sftp.js.map +1 -1
- package/dist/VirtualFileSystem/index.d.ts +14 -0
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +51 -3
- package/dist/VirtualFileSystem/index.js.map +1 -1
- package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
- package/dist/VirtualFileSystem/journal.js +13 -5
- package/dist/VirtualFileSystem/journal.js.map +1 -1
- package/dist/VirtualShell/shell.js +12 -12
- package/dist/VirtualShell/shell.js.map +1 -1
- package/dist/VirtualUserManager/index.js +8 -11
- package/dist/VirtualUserManager/index.js.map +1 -1
- package/dist/commands/apt.js +3 -3
- package/dist/commands/apt.js.map +1 -1
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +2 -1
- package/dist/commands/cd.js.map +1 -1
- package/dist/commands/helpers.d.ts +1 -1
- package/dist/commands/helpers.d.ts.map +1 -1
- package/dist/commands/helpers.js +3 -2
- package/dist/commands/helpers.js.map +1 -1
- package/dist/commands/index.d.ts +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/lsb-release.js +1 -1
- package/dist/commands/lsb-release.js.map +1 -1
- package/dist/commands/runtime.d.ts +2 -0
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +5 -1
- package/dist/commands/runtime.js.map +1 -1
- package/dist/modules/linuxRootfs.d.ts +9 -5
- package/dist/modules/linuxRootfs.d.ts.map +1 -1
- package/dist/modules/linuxRootfs.js +1079 -148
- package/dist/modules/linuxRootfs.js.map +1 -1
- package/dist/self-standalone.js +22 -12
- package/dist/self-standalone.js.map +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/classes/HoneyPot.html +9 -9
- package/docs/classes/IdleManager.html +8 -8
- package/docs/classes/SshClient.html +18 -18
- package/docs/classes/VirtualFileSystem.html +34 -34
- package/docs/classes/VirtualPackageManager.html +13 -13
- package/docs/classes/VirtualSftpServer.html +3 -3
- package/docs/classes/VirtualShell.html +28 -28
- package/docs/classes/VirtualSshServer.html +5 -5
- package/docs/classes/VirtualUserManager.html +27 -27
- package/docs/functions/assertDiff.html +2 -2
- package/docs/functions/diffSnapshots.html +2 -2
- package/docs/functions/formatDiff.html +2 -2
- package/docs/functions/getArg.html +2 -2
- package/docs/functions/getFlag.html +2 -2
- package/docs/functions/ifFlag.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +37 -31
- package/docs/interfaces/AuditLogEntry.html +3 -3
- package/docs/interfaces/CommandContext.html +12 -12
- package/docs/interfaces/CommandResult.html +13 -13
- package/docs/interfaces/ExecStream.html +6 -6
- package/docs/interfaces/HoneyPotStats.html +3 -3
- package/docs/interfaces/IdleManagerOptions.html +3 -3
- package/docs/interfaces/InstalledPackage.html +11 -11
- package/docs/interfaces/NanoEditorSession.html +5 -5
- package/docs/interfaces/PackageDefinition.html +14 -14
- package/docs/interfaces/PackageFile.html +5 -5
- package/docs/interfaces/PasswordChallenge.html +9 -9
- package/docs/interfaces/RemoveOptions.html +3 -3
- package/docs/interfaces/ShellEnv.html +4 -4
- package/docs/interfaces/ShellModule.html +8 -8
- package/docs/interfaces/ShellProperties.html +5 -5
- package/docs/interfaces/ShellStream.html +7 -7
- package/docs/interfaces/SudoChallenge.html +9 -9
- package/docs/interfaces/VfsBaseNode.html +7 -7
- package/docs/interfaces/VfsDiff.html +6 -6
- package/docs/interfaces/VfsDiffEntry.html +4 -4
- package/docs/interfaces/VfsDiffModified.html +6 -6
- package/docs/interfaces/VfsDirectoryNode.html +8 -8
- package/docs/interfaces/VfsFileNode.html +9 -9
- package/docs/interfaces/VfsOptions.html +6 -6
- package/docs/interfaces/VfsSnapshot.html +3 -3
- package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
- package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
- package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
- package/docs/interfaces/VirtualActiveSession.html +7 -7
- package/docs/interfaces/VirtualSftpServerOptions.html +3 -3
- package/docs/interfaces/VirtualShellVfsLike.html +3 -3
- package/docs/interfaces/VirtualShellVfsOptions.html +3 -3
- package/docs/interfaces/WriteFileOptions.html +4 -4
- package/docs/modules.html +1 -1
- package/docs/types/ArgParseOptions.html +3 -3
- package/docs/types/CommandMode.html +2 -2
- package/docs/types/CommandOutcome.html +2 -2
- package/docs/types/IdleState.html +1 -1
- package/docs/types/VfsNodeStats.html +2 -2
- package/docs/types/VfsNodeType.html +2 -2
- package/docs/types/VfsPersistenceMode.html +2 -2
- package/docs/types/VfsSnapshotNode.html +2 -2
- package/package.json +6 -5
- package/scripts/build-all.mjs +198 -0
- package/scripts/build-names.mjs +44 -0
- package/src/SSHMimic/exec.ts +2 -2
- package/src/SSHMimic/index.ts +2 -1
- package/src/SSHMimic/sftp.ts +4 -3
- package/src/VirtualFileSystem/index.ts +46 -3
- package/src/VirtualFileSystem/journal.ts +12 -5
- package/src/VirtualShell/shell.ts +12 -12
- package/src/VirtualUserManager/index.ts +11 -11
- package/src/commands/apt.ts +3 -3
- package/src/commands/cd.ts +2 -1
- package/src/commands/helpers.ts +3 -2
- package/src/commands/index.ts +1 -1
- package/src/commands/lsb-release.ts +1 -1
- package/src/commands/runtime.ts +6 -1
- package/src/modules/linuxRootfs.ts +1293 -207
- package/src/self-standalone.ts +26 -12
- package/tests/new-features.test.ts +2 -2
- package/tests/sftp.test.ts +13 -13
- package/builds/self-standalone.js +0 -1299
- package/builds/standalone-wo-sftp.js +0 -1300
- package/builds/standalone.cjs +0 -1301
- /package/builds/{web-full-api.min.js → fortune-nyx-v1.5.1-web-full.min.js} +0 -0
- /package/builds/{web.min.js → fortune-nyx-v1.5.1-web.min.js} +0 -0
|
@@ -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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ?
|
|
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 ??
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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 =
|
|
689
|
+
const historyPath = `${userHome(authUser)}/.bash_history`;
|
|
690
690
|
if (!vfs.exists(historyPath)) {
|
|
691
691
|
vfs.writeFile(historyPath, "");
|
|
692
692
|
return [];
|
|
@@ -103,14 +103,14 @@ export class VirtualUserManager extends EventEmitter {
|
|
|
103
103
|
// changed = true;
|
|
104
104
|
// }
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
}
|
|
114
114
|
|
|
115
115
|
if (changed) {
|
|
116
116
|
await this.persist();
|
|
@@ -173,7 +173,7 @@ export class VirtualUserManager extends EventEmitter {
|
|
|
173
173
|
*/
|
|
174
174
|
public getUsageBytes(username: string): number {
|
|
175
175
|
perf.mark("getUsageBytes");
|
|
176
|
-
const homePath = `/home/${username}`;
|
|
176
|
+
const homePath = username === "root" ? "/root" : `/home/${username}`;
|
|
177
177
|
if (!this.vfs.exists(homePath)) {
|
|
178
178
|
return 0;
|
|
179
179
|
}
|
|
@@ -202,7 +202,7 @@ export class VirtualUserManager extends EventEmitter {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
const normalizedPath = normalizeVfsPath(targetPath);
|
|
205
|
-
const homePath = normalizeVfsPath(`/home/${username}`);
|
|
205
|
+
const homePath = normalizeVfsPath(username === "root" ? "/root" : `/home/${username}`);
|
|
206
206
|
const inUserHome =
|
|
207
207
|
normalizedPath === homePath || normalizedPath.startsWith(`${homePath}/`);
|
|
208
208
|
if (!inUserHome) {
|
|
@@ -279,7 +279,7 @@ export class VirtualUserManager extends EventEmitter {
|
|
|
279
279
|
if (this.autoSudoForNewUsers) {
|
|
280
280
|
this.sudoers.add(username);
|
|
281
281
|
}
|
|
282
|
-
const homePath = `/home/${username}`;
|
|
282
|
+
const homePath = username === "root" ? "/root" : `/home/${username}`;
|
|
283
283
|
if (!this.vfs.exists(homePath)) {
|
|
284
284
|
this.vfs.mkdir(homePath, 0o755);
|
|
285
285
|
this.vfs.writeFile(
|
package/src/commands/apt.ts
CHANGED
|
@@ -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
|
|
61
|
-
"Hit:2 fortune://security.fortune.local
|
|
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
|
|
221
|
+
` 500 fortune://packages.fortune.local nyx/main amd64 Packages`,
|
|
222
222
|
].join("\n"),
|
|
223
223
|
exitCode: 0,
|
|
224
224
|
};
|
package/src/commands/cd.ts
CHANGED
|
@@ -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") {
|
package/src/commands/helpers.ts
CHANGED
|
@@ -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
|
-
|
|
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)
|
package/src/commands/index.ts
CHANGED
|
@@ -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 = "
|
|
16
|
+
let codename = "nyx";
|
|
17
17
|
let version = "1.0";
|
|
18
18
|
|
|
19
19
|
try {
|
package/src/commands/runtime.ts
CHANGED
|
@@ -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:
|
|
23
|
+
HOME: userHome(authUser),
|
|
19
24
|
USER: authUser,
|
|
20
25
|
LOGNAME: authUser,
|
|
21
26
|
SHELL: "/bin/sh",
|