typescript-virtual-container 1.1.4 → 1.1.5
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/CHANGELOG.md +42 -0
- package/HONEYPOT.md +358 -0
- package/README.md +471 -16
- package/dist/SSHMimic/index.d.ts +2 -1
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +12 -1
- package/dist/SSHMimic/sftp.d.ts +3 -1
- package/dist/SSHMimic/sftp.d.ts.map +1 -1
- package/dist/SSHMimic/sftp.js +20 -1
- package/dist/VirtualFileSystem/index.d.ts +2 -1
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +8 -1
- package/dist/VirtualShell/index.d.ts +2 -1
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +6 -1
- package/dist/VirtualUserManager/index.d.ts +2 -1
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.js +19 -1
- package/dist/honeypot.d.ts +132 -0
- package/dist/honeypot.d.ts.map +1 -0
- package/dist/honeypot.js +289 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/examples/README.md +210 -0
- package/examples/honeypot-audit.ts +180 -0
- package/examples/honeypot-export.ts +253 -0
- package/examples/honeypot-quickstart.ts +110 -0
- package/package.json +1 -1
- package/src/Honeypot/index.ts +422 -0
- package/src/SSHMimic/index.ts +13 -1
- package/src/SSHMimic/sftp.ts +21 -1
- package/src/VirtualFileSystem/index.ts +8 -1
- package/src/VirtualShell/index.ts +6 -1
- package/src/VirtualUserManager/index.ts +21 -3
- package/src/index.ts +6 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `typescript-virtual-container`
|
|
2
2
|
|
|
3
|
-
> In-memory SSH server with a virtual filesystem and typed programmatic API for testing, automation, and interactive shell scripting in TypeScript/JavaScript.
|
|
3
|
+
> In-memory SSH/SFTP server with a virtual filesystem and typed programmatic API for testing, automation, and interactive shell scripting in TypeScript/JavaScript.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/typescript-virtual-container)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -34,12 +34,14 @@
|
|
|
34
34
|
|
|
35
35
|
## Overview
|
|
36
36
|
|
|
37
|
-
`typescript-virtual-container` is a lightweight, fully-typed SSH
|
|
37
|
+
`typescript-virtual-container` is a lightweight, fully-typed SSH/SFTP runtime written in TypeScript that provides:
|
|
38
38
|
|
|
39
|
-
- **SSH Protocol Support**: Serve SSH
|
|
40
|
-
- **Virtual Filesystem**: In-memory
|
|
39
|
+
- **SSH + SFTP Protocol Support**: Serve SSH shell/exec sessions and SFTP file operations on configurable ports.
|
|
40
|
+
- **Virtual Filesystem**: In-memory-like developer workflow backed by a mirror directory under `.vfs/mirror`, with optional gzip compression and programmatic access.
|
|
41
41
|
- **User Management**: Create, authenticate, and manage virtual users with strict password hashing (scrypt) and sudo-like privilege elevation.
|
|
42
42
|
- **Programmatic Shell API**: Execute shell commands and query filesystem state directly from TypeScript without SSH overhead.
|
|
43
|
+
- **Event-Driven Architecture**: All core classes extend `EventEmitter` for lifecycle and operation tracking. Listen to auth events, filesystem operations, session lifecycle, and command execution for auditing and integration.
|
|
44
|
+
- **Security Auditing**: Built-in `HoneyPot` utility for comprehensive activity logging, event tracking, statistics collection, and anomaly detection across all components.
|
|
43
45
|
- **Built-in Commands**: `ls`, `cd`, `pwd`, `cat`, `mkdir`, `touch`, `rm`, `tree`, `whoami`, `hostname`, `who`, `sudo`, `su`, `adduser`, `deluser`, `nano` (text editor), `curl`, `wget`, and a growing set of additional commands. Not everything is implemented yet, and shell compatibility is still being expanded.
|
|
44
46
|
- **Full TypeScript Support**: Complete JSDoc coverage, exported types, and first-class async/await for all operations.
|
|
45
47
|
|
|
@@ -126,6 +128,31 @@ process.on("SIGTERM", () => {
|
|
|
126
128
|
});
|
|
127
129
|
```
|
|
128
130
|
|
|
131
|
+
### Running SSH + SFTP with Shared State
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import { VirtualSftpServer, VirtualShell, VirtualSshServer } from "typescript-virtual-container";
|
|
135
|
+
|
|
136
|
+
const shell = new VirtualShell("my-container");
|
|
137
|
+
|
|
138
|
+
const ssh = new VirtualSshServer({
|
|
139
|
+
port: 2222,
|
|
140
|
+
hostname: "my-container",
|
|
141
|
+
shell,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const sftp = new VirtualSftpServer({
|
|
145
|
+
port: 2223,
|
|
146
|
+
hostname: "my-container",
|
|
147
|
+
shell,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
await ssh.start();
|
|
151
|
+
await sftp.start();
|
|
152
|
+
|
|
153
|
+
console.log("SSH on :2222, SFTP on :2223");
|
|
154
|
+
```
|
|
155
|
+
|
|
129
156
|
### Using the Programmatic Client API
|
|
130
157
|
|
|
131
158
|
```typescript
|
|
@@ -174,7 +201,7 @@ ssh.stop();
|
|
|
174
201
|
└──────────────┘ └──────────┘ └──────────┘
|
|
175
202
|
▲
|
|
176
203
|
│ Backed by disk
|
|
177
|
-
│ .vfs/mirror
|
|
204
|
+
│ .vfs/mirror
|
|
178
205
|
└──────────────────────────────────┘
|
|
179
206
|
``` -->
|
|
180
207
|
|
|
@@ -182,13 +209,14 @@ ssh.stop();
|
|
|
182
209
|
|
|
183
210
|
1. **SSH Shell Mode**: Interactive terminal session over SSH with readline, prompt, TTY resizing.
|
|
184
211
|
2. **SSH Exec Mode**: Non-interactive command execution (e.g., `ssh user@host "ls -la"`).
|
|
185
|
-
3. **
|
|
212
|
+
3. **SFTP Mode**: Remote file operations (`readdir`, `stat`, `readFile`, `writeFile`, `mkdir`, `rename`, etc.) with home-directory confinement.
|
|
213
|
+
4. **Programmatic Mode**: Direct TypeScript API via `SshClient`, no SSH protocol overhead.
|
|
186
214
|
|
|
187
215
|
### Persistence
|
|
188
216
|
|
|
189
|
-
- Filesystem state
|
|
217
|
+
- Filesystem state is stored under `.vfs/mirror` inside the configured `basePath`
|
|
190
218
|
- Users/passwords stored in virtual paths `/virtual-env-js/.auth/htpasswd` and `/virtual-env-js/.auth/sudoers`
|
|
191
|
-
-
|
|
219
|
+
- `restoreMirror()` and `flushMirror()` are lightweight compatibility hooks for initialization boundaries
|
|
192
220
|
|
|
193
221
|
---
|
|
194
222
|
|
|
@@ -248,6 +276,31 @@ Cleanly closes server and all active connections.
|
|
|
248
276
|
ssh.stop();
|
|
249
277
|
```
|
|
250
278
|
|
|
279
|
+
#### Events
|
|
280
|
+
|
|
281
|
+
`SshMimic` extends `EventEmitter` and emits the following events:
|
|
282
|
+
|
|
283
|
+
| Event | Data | Description |
|
|
284
|
+
|-------|------|-------------|
|
|
285
|
+
| `start` | `{ port: number }` | Server started and listening |
|
|
286
|
+
| `stop` | — | Server stopped |
|
|
287
|
+
| `auth:success` | `{ username: string; remoteAddress: string }` | User authenticated |
|
|
288
|
+
| `auth:failure` | `{ username: string; remoteAddress: string }` | Auth failed for user |
|
|
289
|
+
| `client:connect` | — | New SSH client connected |
|
|
290
|
+
| `client:disconnect` | `{ user: string }` | SSH client disconnected |
|
|
291
|
+
|
|
292
|
+
**Example:**
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
ssh.on("auth:success", ({ username, remoteAddress }) => {
|
|
296
|
+
console.log(`[SSH] User ${username} authenticated from ${remoteAddress}`);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
ssh.on("auth:failure", ({ username }) => {
|
|
300
|
+
console.log(`[SSH] Auth failed for user ${username}`);
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
251
304
|
##### `getVfs(): VirtualFileSystem | null`
|
|
252
305
|
|
|
253
306
|
Returns the virtual filesystem instance. Null if server not started.
|
|
@@ -278,6 +331,75 @@ console.log(`Server name: ${ssh.getHostname()}`);
|
|
|
278
331
|
|
|
279
332
|
---
|
|
280
333
|
|
|
334
|
+
### SftpMimic (SFTP Server)
|
|
335
|
+
|
|
336
|
+
SFTP server class, exported as `VirtualSftpServer` in the package entrypoint. It can run with a shared `VirtualShell` (recommended) or with explicit `vfs + users` dependencies.
|
|
337
|
+
|
|
338
|
+
#### Constructor
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
new SftpMimic(options: {
|
|
342
|
+
port: number;
|
|
343
|
+
hostname?: string;
|
|
344
|
+
shell?: VirtualShell;
|
|
345
|
+
vfs?: VirtualFileSystem;
|
|
346
|
+
users?: VirtualUserManager;
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
- If `shell` is provided, SFTP reuses the same users/filesystem state as SSH.
|
|
351
|
+
- If `shell` is omitted, pass `vfs` and `users` explicitly.
|
|
352
|
+
|
|
353
|
+
#### Methods
|
|
354
|
+
|
|
355
|
+
##### `async start(): Promise<number>`
|
|
356
|
+
|
|
357
|
+
Starts the SFTP server and returns the bound port (useful with `port: 0`).
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
const sftp = new SftpMimic({ port: 0, shell });
|
|
361
|
+
const boundPort = await sftp.start();
|
|
362
|
+
console.log(`SFTP listening on ${boundPort}`);
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
##### `stop(): void`
|
|
366
|
+
|
|
367
|
+
Stops the SFTP server.
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
sftp.stop();
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### Behavior Notes
|
|
374
|
+
|
|
375
|
+
- Supports `password` and `keyboard-interactive` authentication.
|
|
376
|
+
- Resolves relative SFTP paths from `/home/<user>`.
|
|
377
|
+
- Confines all SFTP operations to `/home/<user>` and blocks traversal attempts outside the user home.
|
|
378
|
+
- Unsupported operations (`READLINK`, `SYMLINK`) return `OP_UNSUPPORTED`.
|
|
379
|
+
|
|
380
|
+
#### Events
|
|
381
|
+
|
|
382
|
+
`SftpMimic` extends `EventEmitter` and emits the following events:
|
|
383
|
+
|
|
384
|
+
| Event | Data | Description |
|
|
385
|
+
|-------|------|-------------|
|
|
386
|
+
| `start` | `{ port: number }` | SFTP server started and listening |
|
|
387
|
+
| `stop` | — | SFTP server stopped |
|
|
388
|
+
| `auth:success` | `{ username: string; remoteAddress: string }` | User authenticated for SFTP |
|
|
389
|
+
| `auth:failure` | `{ username: string; remoteAddress: string }` | SFTP auth failed for user |
|
|
390
|
+
| `client:connect` | — | New SFTP client connected |
|
|
391
|
+
| `client:disconnect` | `{ user: string }` | SFTP client disconnected |
|
|
392
|
+
|
|
393
|
+
**Example:**
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
sftp.on("auth:success", ({ username }) => {
|
|
397
|
+
console.log(`[SFTP] User ${username} authenticated`);
|
|
398
|
+
});
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
281
403
|
### SshClient (Programmatic Shell API)
|
|
282
404
|
|
|
283
405
|
Execute shell commands against a `VirtualShell` instance without SSH overhead. Maintains connection state (current working directory) across calls.
|
|
@@ -475,7 +597,7 @@ new VirtualShell(
|
|
|
475
597
|
|
|
476
598
|
- **hostname**: Hostname injected into command context and prompt behavior.
|
|
477
599
|
- **properties**: Optional shell metadata. Defaults to `defaultShellProperties`.
|
|
478
|
-
- **basePath**: Optional directory used to resolve `.vfs/mirror
|
|
600
|
+
- **basePath**: Optional directory used to resolve `.vfs/mirror` and auth storage (defaults to `.`).
|
|
479
601
|
|
|
480
602
|
**Example:**
|
|
481
603
|
|
|
@@ -519,11 +641,33 @@ shell.startInteractiveSession(
|
|
|
519
641
|
);
|
|
520
642
|
```
|
|
521
643
|
|
|
644
|
+
#### Events
|
|
645
|
+
|
|
646
|
+
`VirtualShell` extends `EventEmitter` and emits the following events:
|
|
647
|
+
|
|
648
|
+
| Event | Data | Description |
|
|
649
|
+
|-------|------|-------------|
|
|
650
|
+
| `initialized` | — | Shell initialization complete |
|
|
651
|
+
| `command` | `{ command: string; user: string; cwd: string }` | Command executed |
|
|
652
|
+
| `session:start` | `{ user: string; sessionId: string \| null; remoteAddress: string }` | Interactive session started |
|
|
653
|
+
|
|
654
|
+
**Example:**
|
|
655
|
+
|
|
656
|
+
```typescript
|
|
657
|
+
shell.on("command", ({ command, user, cwd }) => {
|
|
658
|
+
console.log(`[SHELL] User ${user} executed: ${command} (cwd: ${cwd})`);
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
shell.on("session:start", ({ user, remoteAddress }) => {
|
|
662
|
+
console.log(`[SHELL] Session started for ${user} from ${remoteAddress}`);
|
|
663
|
+
});
|
|
664
|
+
```
|
|
665
|
+
|
|
522
666
|
---
|
|
523
667
|
|
|
524
668
|
### VirtualFileSystem
|
|
525
669
|
|
|
526
|
-
|
|
670
|
+
Virtual filesystem abstraction backed by a mirror directory on disk, with optional gzip compression per file.
|
|
527
671
|
|
|
528
672
|
#### Constructor
|
|
529
673
|
|
|
@@ -531,18 +675,41 @@ In-memory filesystem with optional gzip compression and tar.gz persistence.
|
|
|
531
675
|
new VirtualFileSystem(baseDir?: string)
|
|
532
676
|
```
|
|
533
677
|
|
|
534
|
-
- **baseDir**: Directory
|
|
678
|
+
- **baseDir**: Directory used for the `.vfs/mirror` root (default: current working directory)
|
|
535
679
|
|
|
536
680
|
```typescript
|
|
537
681
|
const vfs = new VirtualFileSystem("./container-data");
|
|
538
|
-
//
|
|
682
|
+
// Mirror root at ./container-data/.vfs/mirror
|
|
539
683
|
```
|
|
540
684
|
|
|
541
685
|
#### Methods
|
|
542
686
|
|
|
687
|
+
#### Events
|
|
688
|
+
|
|
689
|
+
`VirtualFileSystem` extends `EventEmitter` and emits the following events:
|
|
690
|
+
|
|
691
|
+
| Event | Data | Description |
|
|
692
|
+
|-------|------|-------------|
|
|
693
|
+
| `file:read` | `{ path: string; size: number }` | File read |
|
|
694
|
+
| `file:write` | `{ path: string; size: number }` | File written |
|
|
695
|
+
| `dir:create` | `{ path: string; mode: number }` | Directory created |
|
|
696
|
+
| `mirror:flush` | — | Mirror persisted to disk |
|
|
697
|
+
|
|
698
|
+
**Example:**
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
vfs.on("file:write", ({ path, size }) => {
|
|
702
|
+
console.log(`[VFS] File written: ${path} (${size} bytes)`);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
vfs.on("dir:create", ({ path, mode }) => {
|
|
706
|
+
console.log(`[VFS] Directory created: ${path} (mode: ${mode.toString(8)})`);
|
|
707
|
+
});
|
|
708
|
+
```
|
|
709
|
+
|
|
543
710
|
##### `async restoreMirror(): Promise<void>`
|
|
544
711
|
|
|
545
|
-
|
|
712
|
+
Ensures mirror directory structure exists and is ready for operations.
|
|
546
713
|
|
|
547
714
|
```typescript
|
|
548
715
|
await vfs.restoreMirror();
|
|
@@ -550,7 +717,7 @@ await vfs.restoreMirror();
|
|
|
550
717
|
|
|
551
718
|
##### `async flushMirror(): Promise<void>`
|
|
552
719
|
|
|
553
|
-
|
|
720
|
+
Compatibility hook to finalize mirror boundary operations.
|
|
554
721
|
|
|
555
722
|
```typescript
|
|
556
723
|
// After file modifications...
|
|
@@ -662,6 +829,18 @@ Decompresses file content (inverse of `compressFile`).
|
|
|
662
829
|
vfs.decompressFile("/var/log/app.log");
|
|
663
830
|
```
|
|
664
831
|
|
|
832
|
+
**Example:**
|
|
833
|
+
|
|
834
|
+
```typescript
|
|
835
|
+
vfs.on("file:write", ({ path, size }) => {
|
|
836
|
+
console.log(`[VFS] File written: ${path} (${size} bytes)`);
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
vfs.on("dir:create", ({ path, mode }) => {
|
|
840
|
+
console.log(`[VFS] Directory created: ${path} (mode: ${mode.toString(8)})`);
|
|
841
|
+
});
|
|
842
|
+
```
|
|
843
|
+
|
|
665
844
|
---
|
|
666
845
|
|
|
667
846
|
### VirtualUserManager
|
|
@@ -723,6 +902,7 @@ await users.deleteUser("bob");
|
|
|
723
902
|
|
|
724
903
|
Checks sudo access.
|
|
725
904
|
|
|
905
|
+
|
|
726
906
|
```typescript
|
|
727
907
|
if (users.isSudoer("alice")) {
|
|
728
908
|
console.log("alice can use sudo");
|
|
@@ -821,6 +1001,154 @@ sessions.forEach(s => {
|
|
|
821
1001
|
});
|
|
822
1002
|
```
|
|
823
1003
|
|
|
1004
|
+
#### Events
|
|
1005
|
+
|
|
1006
|
+
`VirtualUserManager` extends `EventEmitter` and emits the following events:
|
|
1007
|
+
|
|
1008
|
+
| Event | Data | Description |
|
|
1009
|
+
|-------|------|-------------|
|
|
1010
|
+
| `initialized` | — | User manager initialization complete, root user ready |
|
|
1011
|
+
| `user:add` | `{ username: string }` | New user created |
|
|
1012
|
+
| `user:delete` | `{ username: string }` | User deleted |
|
|
1013
|
+
| `session:register` | `{ sessionId: string; username: string; remoteAddress: string }` | Session registered (user logged in) |
|
|
1014
|
+
| `session:unregister` | `{ sessionId: string; username: string }` | Session unregistered (user logged out) |
|
|
1015
|
+
|
|
1016
|
+
**Example:**
|
|
1017
|
+
|
|
1018
|
+
```typescript
|
|
1019
|
+
users.on("user:add", ({ username }) => {
|
|
1020
|
+
console.log(`[USERS] User created: ${username}`);
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
users.on("session:register", ({ sessionId, username, remoteAddress }) => {
|
|
1024
|
+
console.log(`[USERS] Session ${sessionId}: ${username} from ${remoteAddress}`);
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
users.on("session:unregister", ({ sessionId, username }) => {
|
|
1028
|
+
console.log(`[USERS] Session ${sessionId} (${username}) closed`);
|
|
1029
|
+
});
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
---
|
|
1033
|
+
|
|
1034
|
+
### HoneyPot (Auditing & Event Tracking)
|
|
1035
|
+
|
|
1036
|
+
Comprehensive security auditing and event tracking utility. Attaches to all core components (VirtualShell, VirtualFileSystem, VirtualUserManager, SshMimic, SftpMimic) to log activity, track statistics, and detect anomalies.
|
|
1037
|
+
|
|
1038
|
+
#### Constructor
|
|
1039
|
+
|
|
1040
|
+
```typescript
|
|
1041
|
+
new HoneyPot(maxLogSize?: number)
|
|
1042
|
+
```
|
|
1043
|
+
|
|
1044
|
+
- **maxLogSize**: Maximum audit log entries to retain (default: 10000)
|
|
1045
|
+
|
|
1046
|
+
```typescript
|
|
1047
|
+
const honeypot = new HoneyPot(5000); // Keep last 5000 audit entries
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
#### Methods
|
|
1051
|
+
|
|
1052
|
+
##### `attach(shell: VirtualShell, vfs: VirtualFileSystem, users: VirtualUserManager, ssh?: SshMimic, sftp?: SftpMimic): void`
|
|
1053
|
+
|
|
1054
|
+
Attaches honeypot listeners to all provided event emitters. This wires up all audit tracking across the entire virtual environment.
|
|
1055
|
+
|
|
1056
|
+
```typescript
|
|
1057
|
+
honeypot.attach(shell, vfs, users, ssh, sftp);
|
|
1058
|
+
// All components now emit events to honeypot
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
##### `getAuditLog(type?: string, source?: string): AuditLogEntry[]`
|
|
1062
|
+
|
|
1063
|
+
Returns audit log entries with optional filtering by event type or source component.
|
|
1064
|
+
|
|
1065
|
+
```typescript
|
|
1066
|
+
// All entries
|
|
1067
|
+
const allLogs = honeypot.getAuditLog();
|
|
1068
|
+
|
|
1069
|
+
// Only auth events
|
|
1070
|
+
const authLogs = honeypot.getAuditLog("auth:failure");
|
|
1071
|
+
|
|
1072
|
+
// Only SshMimic events
|
|
1073
|
+
const sshLogs = honeypot.getAuditLog(undefined, "SshMimic");
|
|
1074
|
+
|
|
1075
|
+
// Combine filters
|
|
1076
|
+
const sshAuthLogs = honeypot.getAuditLog("auth:success", "SshMimic");
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
##### `getStats(): Readonly<HoneyPotStats>`
|
|
1080
|
+
|
|
1081
|
+
Returns current activity statistics snapshot.
|
|
1082
|
+
|
|
1083
|
+
```typescript
|
|
1084
|
+
const stats = honeypot.getStats();
|
|
1085
|
+
console.log(`Auth attempts: ${stats.authAttempts}`);
|
|
1086
|
+
console.log(`Auth successes: ${stats.authSuccesses}`);
|
|
1087
|
+
console.log(`Auth failures: ${stats.authFailures}`);
|
|
1088
|
+
console.log(`Commands executed: ${stats.commands}`);
|
|
1089
|
+
console.log(`File writes: ${stats.fileWrites}`);
|
|
1090
|
+
console.log(`File reads: ${stats.fileReads}`);
|
|
1091
|
+
console.log(`Sessions started: ${stats.sessionStarts}`);
|
|
1092
|
+
console.log(`Sessions ended: ${stats.sessionEnds}`);
|
|
1093
|
+
console.log(`Users created: ${stats.userCreated}`);
|
|
1094
|
+
console.log(`Users deleted: ${stats.userDeleted}`);
|
|
1095
|
+
console.log(`Client connects: ${stats.clientConnects}`);
|
|
1096
|
+
console.log(`Client disconnects: ${stats.clientDisconnects}`);
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
##### `getRecent(limit?: number): AuditLogEntry[]`
|
|
1100
|
+
|
|
1101
|
+
Returns most recent audit entries in reverse chronological order.
|
|
1102
|
+
|
|
1103
|
+
```typescript
|
|
1104
|
+
const last50 = honeypot.getRecent(50);
|
|
1105
|
+
last50.forEach(entry => {
|
|
1106
|
+
console.log(`${entry.timestamp} | ${entry.source} | ${entry.type}`);
|
|
1107
|
+
console.log(`Details:`, entry.details);
|
|
1108
|
+
});
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
##### `detectAnomalies(): Array<{ type: string; severity: "low" | "medium" | "high"; message: string }>`
|
|
1112
|
+
|
|
1113
|
+
Analyzes activity patterns and detects potential security issues.
|
|
1114
|
+
|
|
1115
|
+
```typescript
|
|
1116
|
+
const anomalies = honeypot.detectAnomalies();
|
|
1117
|
+
anomalies.forEach(anomaly => {
|
|
1118
|
+
console.log(`[${anomaly.severity.toUpperCase()}] ${anomaly.type}`);
|
|
1119
|
+
console.log(` ${anomaly.message}`);
|
|
1120
|
+
});
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
Detects:
|
|
1124
|
+
- High authentication failure rates
|
|
1125
|
+
- Excessive authentication failures
|
|
1126
|
+
- Unusual command execution volume
|
|
1127
|
+
- Unusual file write volume
|
|
1128
|
+
|
|
1129
|
+
##### `reset(): void`
|
|
1130
|
+
|
|
1131
|
+
Clears audit log and resets all statistics counters.
|
|
1132
|
+
|
|
1133
|
+
```typescript
|
|
1134
|
+
honeypot.reset(); // Fresh start
|
|
1135
|
+
```
|
|
1136
|
+
|
|
1137
|
+
#### Audit Log Entry Structure
|
|
1138
|
+
|
|
1139
|
+
```typescript
|
|
1140
|
+
interface AuditLogEntry {
|
|
1141
|
+
timestamp: string; // ISO-8601 timestamp
|
|
1142
|
+
type: string; // Event type (e.g., "auth:success", "file:write")
|
|
1143
|
+
source: string; // Event source component
|
|
1144
|
+
details: Record<string, unknown>; // Event-specific data
|
|
1145
|
+
}
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
#### Example Usage
|
|
1149
|
+
|
|
1150
|
+
See [Example 8: Security Auditing with HoneyPot](#example-8-security-auditing-with-honeypot) in Usage Examples.
|
|
1151
|
+
|
|
824
1152
|
---
|
|
825
1153
|
|
|
826
1154
|
### Key Types
|
|
@@ -1022,7 +1350,7 @@ vfs1.writeFile("/data/report.txt", "Baseline data");
|
|
|
1022
1350
|
await vfs1.flushMirror();
|
|
1023
1351
|
ssh1.stop();
|
|
1024
1352
|
|
|
1025
|
-
console.log("State
|
|
1353
|
+
console.log("State available under ./container/.vfs/mirror");
|
|
1026
1354
|
|
|
1027
1355
|
// Later: Reload and continue
|
|
1028
1356
|
const shell2 = new VirtualShell("typescript-vm", undefined, "./container");
|
|
@@ -1156,6 +1484,133 @@ ssh.stop();
|
|
|
1156
1484
|
|
|
1157
1485
|
---
|
|
1158
1486
|
|
|
1487
|
+
### Example 8: Security Auditing with HoneyPot
|
|
1488
|
+
|
|
1489
|
+
Track all system activity, detect anomalies, and maintain security audit logs:
|
|
1490
|
+
|
|
1491
|
+
```typescript
|
|
1492
|
+
import {
|
|
1493
|
+
VirtualSshServer,
|
|
1494
|
+
VirtualShell,
|
|
1495
|
+
SshClient,
|
|
1496
|
+
HoneyPot,
|
|
1497
|
+
} from "typescript-virtual-container";
|
|
1498
|
+
|
|
1499
|
+
const shell = new VirtualShell("typescript-vm");
|
|
1500
|
+
const ssh = new VirtualSshServer({ port: 2222, shell });
|
|
1501
|
+
await ssh.start();
|
|
1502
|
+
|
|
1503
|
+
const users = ssh.getUsers()!;
|
|
1504
|
+
const vfs = ssh.getVfs()!;
|
|
1505
|
+
|
|
1506
|
+
// Initialize honeypot with 5000-entry log limit
|
|
1507
|
+
const honeypot = new HoneyPot(5000);
|
|
1508
|
+
honeypot.attach(shell, vfs, users, ssh);
|
|
1509
|
+
|
|
1510
|
+
// Create users
|
|
1511
|
+
await users.addUser("alice", "alice123");
|
|
1512
|
+
await users.addUser("bob", "bob456");
|
|
1513
|
+
|
|
1514
|
+
// Simulate activity
|
|
1515
|
+
const alice = new SshClient(shell, "alice");
|
|
1516
|
+
await alice.mkdir("/home/alice/projects", true);
|
|
1517
|
+
await alice.writeFile("/home/alice/projects/app.txt", "My application");
|
|
1518
|
+
await alice.ls("/home/alice/projects");
|
|
1519
|
+
|
|
1520
|
+
const bob = new SshClient(shell, "bob");
|
|
1521
|
+
// Bob tries invalid operations
|
|
1522
|
+
await bob.readFile("/etc/shadow"); // Will fail
|
|
1523
|
+
await bob.writeFile("/etc/passwd", "hacked"); // Will fail
|
|
1524
|
+
|
|
1525
|
+
// Collect stats
|
|
1526
|
+
const stats = honeypot.getStats();
|
|
1527
|
+
console.log("\n=== Activity Summary ===");
|
|
1528
|
+
console.log(`Auth attempts: ${stats.authAttempts}`);
|
|
1529
|
+
console.log(`Auth successes: ${stats.authSuccesses}`);
|
|
1530
|
+
console.log(`Auth failures: ${stats.authFailures}`);
|
|
1531
|
+
console.log(`Commands executed: ${stats.commands}`);
|
|
1532
|
+
console.log(`File writes: ${stats.fileWrites}`);
|
|
1533
|
+
console.log(`File reads: ${stats.fileReads}`);
|
|
1534
|
+
console.log(`Sessions active: ${stats.sessionStarts}`);
|
|
1535
|
+
console.log(`Users created: ${stats.userCreated}`);
|
|
1536
|
+
|
|
1537
|
+
// Get recent events
|
|
1538
|
+
console.log("\n=== Last 5 Events ===");
|
|
1539
|
+
honeypot.getRecent(5).forEach((entry) => {
|
|
1540
|
+
console.log(`[${entry.timestamp}] ${entry.source} -> ${entry.type}`);
|
|
1541
|
+
console.log(` Details: ${JSON.stringify(entry.details, null, 2)}`);
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
// Detect anomalies
|
|
1545
|
+
console.log("\n=== Security Analysis ===");
|
|
1546
|
+
const anomalies = honeypot.detectAnomalies();
|
|
1547
|
+
if (anomalies.length > 0) {
|
|
1548
|
+
anomalies.forEach((anomaly) => {
|
|
1549
|
+
console.log(
|
|
1550
|
+
`[${anomaly.severity.toUpperCase()}] ${anomaly.type}: ${anomaly.message}`,
|
|
1551
|
+
);
|
|
1552
|
+
});
|
|
1553
|
+
} else {
|
|
1554
|
+
console.log("No anomalies detected");
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// Filter audit log by event type
|
|
1558
|
+
console.log("\n=== Auth Failures ===");
|
|
1559
|
+
const authFailures = honeypot.getAuditLog("auth:failure");
|
|
1560
|
+
authFailures.forEach((entry) => {
|
|
1561
|
+
console.log(
|
|
1562
|
+
` ${entry.details.username} from ${entry.details.remoteAddress}`,
|
|
1563
|
+
);
|
|
1564
|
+
});
|
|
1565
|
+
|
|
1566
|
+
// Filter by source component
|
|
1567
|
+
console.log("\n=== All SSH Events ===");
|
|
1568
|
+
const sshEvents = honeypot.getAuditLog(undefined, "SshMimic");
|
|
1569
|
+
console.log(` Total SSH events: ${sshEvents.length}`);
|
|
1570
|
+
|
|
1571
|
+
// Export full audit log (for external storage/analysis)
|
|
1572
|
+
const fullAuditLog = honeypot.getAuditLog();
|
|
1573
|
+
console.log(`\nTotal audit entries: ${fullAuditLog.length}`);
|
|
1574
|
+
|
|
1575
|
+
// Optional: Reset for next test phase
|
|
1576
|
+
// honeypot.reset();
|
|
1577
|
+
|
|
1578
|
+
ssh.stop();
|
|
1579
|
+
```
|
|
1580
|
+
|
|
1581
|
+
**Output example:**
|
|
1582
|
+
|
|
1583
|
+
```
|
|
1584
|
+
[AUDIT] 2026-04-16T10:30:45.123Z | SshMimic | start { port: 2222 }
|
|
1585
|
+
[AUDIT] 2026-04-16T10:30:46.234Z | VirtualUserManager | user:add { username: 'alice' }
|
|
1586
|
+
[AUDIT] 2026-04-16T10:30:47.345Z | VirtualUserManager | user:add { username: 'bob' }
|
|
1587
|
+
[AUDIT] 2026-04-16T10:30:48.456Z | VirtualShell | command { command: 'mkdir /home/alice/projects', user: 'alice', cwd: '/home/alice' }
|
|
1588
|
+
[AUDIT] 2026-04-16T10:30:49.567Z | VirtualFileSystem | dir:create { path: '/home/alice/projects', mode: 16877 }
|
|
1589
|
+
[AUDIT] 2026-04-16T10:30:50.678Z | VirtualShell | command { command: 'writeFile /home/alice/projects/app.txt', user: 'alice', cwd: '/home/alice' }
|
|
1590
|
+
|
|
1591
|
+
=== Activity Summary ===
|
|
1592
|
+
Auth attempts: 2
|
|
1593
|
+
Auth successes: 2
|
|
1594
|
+
Auth failures: 0
|
|
1595
|
+
Commands executed: 8
|
|
1596
|
+
File writes: 1
|
|
1597
|
+
File reads: 2
|
|
1598
|
+
Sessions active: 2
|
|
1599
|
+
Users created: 2
|
|
1600
|
+
|
|
1601
|
+
=== Last 5 Events ===
|
|
1602
|
+
[2026-04-16T10:30:50.678Z] VirtualShell -> command
|
|
1603
|
+
Details: { command: 'ls /home/alice/projects', user: 'alice', cwd: '/home/alice/projects' }
|
|
1604
|
+
|
|
1605
|
+
=== Security Analysis ===
|
|
1606
|
+
No anomalies detected
|
|
1607
|
+
|
|
1608
|
+
=== All SSH Events ===
|
|
1609
|
+
Total SSH events: 4
|
|
1610
|
+
```
|
|
1611
|
+
|
|
1612
|
+
---
|
|
1613
|
+
|
|
1159
1614
|
## Built-in Commands
|
|
1160
1615
|
|
|
1161
1616
|
The following commands are currently registered and available in both SSH shell mode and via `SshClient.exec()`. Some flags and edge-case behavior are still being expanded for shell compatibility.
|
|
@@ -1293,7 +1748,7 @@ You can use it in production-like automation contexts (sandboxed command runners
|
|
|
1293
1748
|
|
|
1294
1749
|
### Does data persist between restarts?
|
|
1295
1750
|
|
|
1296
|
-
Yes,
|
|
1751
|
+
Yes, when using a stable `basePath`. Files are stored under `.vfs/mirror`.
|
|
1297
1752
|
|
|
1298
1753
|
### Is networking fully implemented for curl/wget?
|
|
1299
1754
|
|
package/dist/SSHMimic/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
1
2
|
import { Server as SshServer } from "ssh2";
|
|
2
3
|
import { VirtualShell } from "../VirtualShell";
|
|
3
4
|
/**
|
|
@@ -7,7 +8,7 @@ import { VirtualShell } from "../VirtualShell";
|
|
|
7
8
|
* Create an instance, call {@link SshMimic.start}, and stop it with
|
|
8
9
|
* {@link SshMimic.stop} when your process exits.
|
|
9
10
|
*/
|
|
10
|
-
declare class SshMimic {
|
|
11
|
+
declare class SshMimic extends EventEmitter {
|
|
11
12
|
port: number;
|
|
12
13
|
server: SshServer | null;
|
|
13
14
|
private shell;
|
|
@@ -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;AAI/C;;;;;;GAMG;AACH,cAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SSHMimic/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAI/C;;;;;;GAMG;AACH,cAAM,QAAS,SAAQ,YAAY;IAClC,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;IAQD;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAwHrC;;OAEG;IACI,IAAI,IAAI,IAAI;CAQnB;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|