typescript-virtual-container 1.1.3 → 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.
Files changed (49) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/HONEYPOT.md +358 -0
  3. package/README.md +471 -16
  4. package/dist/SSHMimic/exec.d.ts.map +1 -1
  5. package/dist/SSHMimic/exec.js +8 -2
  6. package/dist/SSHMimic/index.d.ts +3 -1
  7. package/dist/SSHMimic/index.d.ts.map +1 -1
  8. package/dist/SSHMimic/index.js +21 -4
  9. package/dist/SSHMimic/sftp.d.ts +48 -0
  10. package/dist/SSHMimic/sftp.d.ts.map +1 -0
  11. package/dist/SSHMimic/sftp.js +595 -0
  12. package/dist/VirtualFileSystem/index.d.ts +8 -5
  13. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  14. package/dist/VirtualFileSystem/index.js +152 -154
  15. package/dist/VirtualShell/index.d.ts +8 -1
  16. package/dist/VirtualShell/index.d.ts.map +1 -1
  17. package/dist/VirtualShell/index.js +22 -5
  18. package/dist/VirtualShell/shell.d.ts.map +1 -1
  19. package/dist/VirtualShell/shell.js +7 -0
  20. package/dist/VirtualUserManager/index.d.ts +3 -1
  21. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  22. package/dist/VirtualUserManager/index.js +34 -1
  23. package/dist/commands/exit.d.ts.map +1 -1
  24. package/dist/commands/exit.js +1 -0
  25. package/dist/honeypot.d.ts +132 -0
  26. package/dist/honeypot.d.ts.map +1 -0
  27. package/dist/honeypot.js +289 -0
  28. package/dist/index.d.ts +4 -2
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +3 -2
  31. package/dist/standalone.js +10 -1
  32. package/examples/README.md +210 -0
  33. package/examples/honeypot-audit.ts +180 -0
  34. package/examples/honeypot-export.ts +253 -0
  35. package/examples/honeypot-quickstart.ts +110 -0
  36. package/package.json +1 -1
  37. package/src/Honeypot/index.ts +422 -0
  38. package/src/SSHMimic/exec.ts +18 -12
  39. package/src/SSHMimic/index.ts +29 -8
  40. package/src/SSHMimic/sftp.ts +853 -0
  41. package/src/VirtualFileSystem/index.ts +167 -190
  42. package/src/VirtualShell/index.ts +25 -9
  43. package/src/VirtualShell/shell.ts +7 -0
  44. package/src/VirtualUserManager/index.ts +41 -3
  45. package/src/commands/exit.ts +1 -0
  46. package/src/index.ts +8 -1
  47. package/src/standalone.ts +11 -1
  48. package/tests/sftp.test.ts +319 -0
  49. package/tests/ssh-exec.test.ts +45 -0
@@ -1,11 +1,12 @@
1
1
  import { randomBytes, randomUUID, scryptSync } from "node:crypto";
2
+ import { EventEmitter } from "node:events";
2
3
  import * as path from "node:path";
3
4
  /**
4
5
  * Persistent user, sudoers, and active-session manager for the shell runtime.
5
6
  *
6
7
  * Passwords are hashed with scrypt and stored in the backing virtual filesystem.
7
8
  */
8
- export class VirtualUserManager {
9
+ export class VirtualUserManager extends EventEmitter {
9
10
  vfs;
10
11
  defaultRootPassword;
11
12
  autoSudoForNewUsers;
@@ -26,12 +27,14 @@ export class VirtualUserManager {
26
27
  * @param autoSudoForNewUsers Whether newly created users are added to sudoers.
27
28
  */
28
29
  constructor(vfs, defaultRootPassword = "root", autoSudoForNewUsers = true) {
30
+ super();
29
31
  this.vfs = vfs;
30
32
  this.defaultRootPassword = defaultRootPassword;
31
33
  this.autoSudoForNewUsers = autoSudoForNewUsers;
32
34
  }
33
35
  /**
34
36
  * Loads users/sudoers from disk and ensures root account exists.
37
+ * Also creates the current system user if not already present.
35
38
  */
36
39
  async initialize() {
37
40
  this.loadFromVfs();
@@ -39,7 +42,22 @@ export class VirtualUserManager {
39
42
  this.loadQuotasFromVfs();
40
43
  this.users.set("root", this.createRecord("root", this.defaultRootPassword));
41
44
  this.sudoers.add("root");
45
+ // Auto-create current system user for easier authentication
46
+ const currentUser = process.env.USER || process.env.USERNAME;
47
+ if (currentUser && currentUser !== "root" && !this.users.has(currentUser)) {
48
+ // Use same password as root for convenience, or a generic default
49
+ const userPassword = this.defaultRootPassword;
50
+ this.users.set(currentUser, this.createRecord(currentUser, userPassword));
51
+ this.sudoers.add(currentUser);
52
+ // Create home directory for the system user
53
+ const homePath = `/home/${currentUser}`;
54
+ if (!this.vfs.exists(homePath)) {
55
+ this.vfs.mkdir(homePath, 0o755);
56
+ this.vfs.writeFile(`${homePath}/README.txt`, `Welcome to the virtual environment, ${currentUser}`);
57
+ }
58
+ }
42
59
  await this.persist();
60
+ this.emit("initialized");
43
61
  }
44
62
  /**
45
63
  * Sets max allowed bytes under /home/<username>.
@@ -162,6 +180,7 @@ export class VirtualUserManager {
162
180
  this.vfs.writeFile(`${homePath}/README.txt`, `Welcome to the virtual environment, ${username}`);
163
181
  }
164
182
  await this.persist();
183
+ this.emit("user:add", { username });
165
184
  }
166
185
  /**
167
186
  * Updates password for an existing user account.
@@ -192,6 +211,7 @@ export class VirtualUserManager {
192
211
  throw new Error(`deluser: user '${username}' does not exist`);
193
212
  }
194
213
  this.sudoers.delete(username);
214
+ this.emit("user:delete", { username });
195
215
  await this.persist();
196
216
  }
197
217
  /**
@@ -245,6 +265,11 @@ export class VirtualUserManager {
245
265
  startedAt: new Date().toISOString(),
246
266
  };
247
267
  this.activeSessions.set(session.id, session);
268
+ this.emit("session:register", {
269
+ sessionId: session.id,
270
+ username,
271
+ remoteAddress,
272
+ });
248
273
  return session;
249
274
  }
250
275
  /**
@@ -256,6 +281,14 @@ export class VirtualUserManager {
256
281
  if (!sessionId) {
257
282
  return;
258
283
  }
284
+ const session = this.activeSessions.get(sessionId);
285
+ this.activeSessions.delete(sessionId);
286
+ if (session) {
287
+ this.emit("session:unregister", {
288
+ sessionId,
289
+ username: session.username,
290
+ });
291
+ }
259
292
  this.activeSessions.delete(sessionId);
260
293
  }
261
294
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"exit.d.ts","sourceRoot":"","sources":["../../src/commands/exit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,WAIzB,CAAC"}
1
+ {"version":3,"file":"exit.d.ts","sourceRoot":"","sources":["../../src/commands/exit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,WAAW,EAAE,WAKzB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export const exitCommand = {
2
2
  name: "exit",
3
+ aliases: ["bye"],
3
4
  params: [],
4
5
  run: () => ({ closeSession: true, exitCode: 0 }),
5
6
  };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Honeypot tracking and auditing module for virtual shell events.
3
+ *
4
+ * Attaches listeners to VirtualShell, VirtualFileSystem, VirtualUserManager,
5
+ * SshMimic, and SftpMimic instances to log all activity for security auditing,
6
+ * anomaly detection, and forensic analysis.
7
+ *
8
+ * @module honeypot
9
+ */
10
+ import type { VirtualShell } from "./VirtualShell";
11
+ import type VirtualFileSystem from "./VirtualFileSystem";
12
+ import type { VirtualUserManager } from "./VirtualUserManager";
13
+ import type { SshMimic } from "./SSHMimic";
14
+ import type { SftpMimic } from "./SSHMimic/sftp";
15
+ /**
16
+ * Audit log entry recorded for each event.
17
+ */
18
+ export interface AuditLogEntry {
19
+ timestamp: string;
20
+ type: string;
21
+ source: string;
22
+ details: Record<string, unknown>;
23
+ }
24
+ /**
25
+ * Statistics tracker for honeypot activity.
26
+ */
27
+ export interface HoneyPotStats {
28
+ authAttempts: number;
29
+ authSuccesses: number;
30
+ authFailures: number;
31
+ commands: number;
32
+ fileWrites: number;
33
+ fileReads: number;
34
+ sessionStarts: number;
35
+ sessionEnds: number;
36
+ userCreated: number;
37
+ userDeleted: number;
38
+ clientConnects: number;
39
+ clientDisconnects: number;
40
+ }
41
+ /**
42
+ * HoneyPot audit and event tracking utility.
43
+ *
44
+ * Singleton-like helper that attaches listeners to virtual shell components
45
+ * and maintains an audit log of all activity.
46
+ */
47
+ export declare class HoneyPot {
48
+ private auditLog;
49
+ private stats;
50
+ private maxLogSize;
51
+ /**
52
+ * Creates a new HoneyPot instance.
53
+ *
54
+ * @param maxLogSize Maximum audit log entries to retain (default: 10000).
55
+ */
56
+ constructor(maxLogSize?: number);
57
+ /**
58
+ * Attaches honeypot listeners to all provided event emitters.
59
+ *
60
+ * @param shell VirtualShell instance.
61
+ * @param vfs VirtualFileSystem instance.
62
+ * @param users VirtualUserManager instance.
63
+ * @param ssh SshMimic instance (optional).
64
+ * @param sftp SftpMimic instance (optional).
65
+ */
66
+ attach(shell: VirtualShell, vfs: VirtualFileSystem, users: VirtualUserManager, ssh?: SshMimic, sftp?: SftpMimic): void;
67
+ /**
68
+ * Attaches to VirtualShell events.
69
+ */
70
+ private attachVirtualShell;
71
+ /**
72
+ * Attaches to VirtualFileSystem events.
73
+ */
74
+ private attachVirtualFileSystem;
75
+ /**
76
+ * Attaches to VirtualUserManager events.
77
+ */
78
+ private attachVirtualUserManager;
79
+ /**
80
+ * Attaches to SshMimic events.
81
+ */
82
+ private attachSshMimic;
83
+ /**
84
+ * Attaches to SftpMimic events.
85
+ */
86
+ private attachSftpMimic;
87
+ /**
88
+ * Records an audit log entry.
89
+ *
90
+ * @param source Event source (e.g., "SshMimic", "VirtualFileSystem").
91
+ * @param type Event type.
92
+ * @param details Event-specific data.
93
+ */
94
+ private log;
95
+ /**
96
+ * Returns audit log entries matching optional filters.
97
+ *
98
+ * @param type Optional event type filter.
99
+ * @param source Optional source filter.
100
+ * @returns Filtered audit log entries.
101
+ */
102
+ getAuditLog(type?: string, source?: string): AuditLogEntry[];
103
+ /**
104
+ * Returns current activity statistics.
105
+ *
106
+ * @returns Snapshot of honeypot stats.
107
+ */
108
+ getStats(): Readonly<HoneyPotStats>;
109
+ /**
110
+ * Clears audit log and resets statistics.
111
+ */
112
+ reset(): void;
113
+ /**
114
+ * Returns recent log entries in reverse chronological order.
115
+ *
116
+ * @param limit Number of recent entries to return (default: 100).
117
+ * @returns Recent audit log entries.
118
+ */
119
+ getRecent(limit?: number): AuditLogEntry[];
120
+ /**
121
+ * Detects potential security issues based on activity patterns.
122
+ *
123
+ * @returns Array of anomalies detected.
124
+ */
125
+ detectAnomalies(): Array<{
126
+ type: string;
127
+ severity: "low" | "medium" | "high";
128
+ message: string;
129
+ }>;
130
+ }
131
+ export default HoneyPot;
132
+ //# sourceMappingURL=honeypot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"honeypot.d.ts","sourceRoot":"","sources":["../src/honeypot.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,iBAAiB,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,qBAAa,QAAQ;IACpB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,KAAK,CAaX;IAEF,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;OAIG;gBACS,UAAU,GAAE,MAAc;IAItC;;;;;;;;OAQG;IACI,MAAM,CACZ,KAAK,EAAE,YAAY,EACnB,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,kBAAkB,EACzB,GAAG,CAAC,EAAE,QAAQ,EACd,IAAI,CAAC,EAAE,SAAS,GACd,IAAI;IAYP;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAkChC;;OAEG;IACH,OAAO,CAAC,cAAc;IAyCtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAyCvB;;;;;;OAMG;IACH,OAAO,CAAC,GAAG;IAuBX;;;;;;OAMG;IACI,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE;IAOnE;;;;OAIG;IACI,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC;IAI1C;;OAEG;IACI,KAAK,IAAI,IAAI;IAkBpB;;;;;OAKG;IACI,SAAS,CAAC,KAAK,GAAE,MAAY,GAAG,aAAa,EAAE;IAItD;;;;OAIG;IACI,eAAe,IAAI,KAAK,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;QACpC,OAAO,EAAE,MAAM,CAAC;KAChB,CAAC;CAkDF;AAED,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Honeypot tracking and auditing module for virtual shell events.
3
+ *
4
+ * Attaches listeners to VirtualShell, VirtualFileSystem, VirtualUserManager,
5
+ * SshMimic, and SftpMimic instances to log all activity for security auditing,
6
+ * anomaly detection, and forensic analysis.
7
+ *
8
+ * @module honeypot
9
+ */
10
+ /**
11
+ * HoneyPot audit and event tracking utility.
12
+ *
13
+ * Singleton-like helper that attaches listeners to virtual shell components
14
+ * and maintains an audit log of all activity.
15
+ */
16
+ export class HoneyPot {
17
+ auditLog = [];
18
+ stats = {
19
+ authAttempts: 0,
20
+ authSuccesses: 0,
21
+ authFailures: 0,
22
+ commands: 0,
23
+ fileWrites: 0,
24
+ fileReads: 0,
25
+ sessionStarts: 0,
26
+ sessionEnds: 0,
27
+ userCreated: 0,
28
+ userDeleted: 0,
29
+ clientConnects: 0,
30
+ clientDisconnects: 0,
31
+ };
32
+ maxLogSize;
33
+ /**
34
+ * Creates a new HoneyPot instance.
35
+ *
36
+ * @param maxLogSize Maximum audit log entries to retain (default: 10000).
37
+ */
38
+ constructor(maxLogSize = 10000) {
39
+ this.maxLogSize = maxLogSize;
40
+ }
41
+ /**
42
+ * Attaches honeypot listeners to all provided event emitters.
43
+ *
44
+ * @param shell VirtualShell instance.
45
+ * @param vfs VirtualFileSystem instance.
46
+ * @param users VirtualUserManager instance.
47
+ * @param ssh SshMimic instance (optional).
48
+ * @param sftp SftpMimic instance (optional).
49
+ */
50
+ attach(shell, vfs, users, ssh, sftp) {
51
+ this.attachVirtualShell(shell);
52
+ this.attachVirtualFileSystem(vfs);
53
+ this.attachVirtualUserManager(users);
54
+ if (ssh) {
55
+ this.attachSshMimic(ssh);
56
+ }
57
+ if (sftp) {
58
+ this.attachSftpMimic(sftp);
59
+ }
60
+ }
61
+ /**
62
+ * Attaches to VirtualShell events.
63
+ */
64
+ attachVirtualShell(shell) {
65
+ shell.on("initialized", () => {
66
+ this.log("VirtualShell", "initialized", {});
67
+ });
68
+ shell.on("command", (data) => {
69
+ this.stats.commands++;
70
+ this.log("VirtualShell", "command", data);
71
+ });
72
+ shell.on("session:start", (data) => {
73
+ this.stats.sessionStarts++;
74
+ this.log("VirtualShell", "session:start", data);
75
+ });
76
+ }
77
+ /**
78
+ * Attaches to VirtualFileSystem events.
79
+ */
80
+ attachVirtualFileSystem(vfs) {
81
+ vfs.on("file:read", (data) => {
82
+ this.stats.fileReads++;
83
+ this.log("VirtualFileSystem", "file:read", data);
84
+ });
85
+ vfs.on("file:write", (data) => {
86
+ this.stats.fileWrites++;
87
+ this.log("VirtualFileSystem", "file:write", data);
88
+ });
89
+ vfs.on("dir:create", (data) => {
90
+ this.log("VirtualFileSystem", "dir:create", data);
91
+ });
92
+ vfs.on("mirror:flush", () => {
93
+ this.log("VirtualFileSystem", "mirror:flush", {});
94
+ });
95
+ }
96
+ /**
97
+ * Attaches to VirtualUserManager events.
98
+ */
99
+ attachVirtualUserManager(users) {
100
+ users.on("initialized", () => {
101
+ this.log("VirtualUserManager", "initialized", {});
102
+ });
103
+ users.on("user:add", (data) => {
104
+ this.stats.userCreated++;
105
+ this.log("VirtualUserManager", "user:add", data);
106
+ });
107
+ users.on("user:delete", (data) => {
108
+ this.stats.userDeleted++;
109
+ this.log("VirtualUserManager", "user:delete", data);
110
+ });
111
+ users.on("session:register", (data) => {
112
+ this.log("VirtualUserManager", "session:register", data);
113
+ });
114
+ users.on("session:unregister", (data) => {
115
+ this.stats.sessionEnds++;
116
+ this.log("VirtualUserManager", "session:unregister", data);
117
+ });
118
+ }
119
+ /**
120
+ * Attaches to SshMimic events.
121
+ */
122
+ attachSshMimic(ssh) {
123
+ ssh.on("start", (data) => {
124
+ this.log("SshMimic", "start", data);
125
+ });
126
+ ssh.on("stop", () => {
127
+ this.log("SshMimic", "stop", {});
128
+ });
129
+ ssh.on("auth:success", (data) => {
130
+ this.stats.authAttempts++;
131
+ this.stats.authSuccesses++;
132
+ this.log("SshMimic", "auth:success", data);
133
+ });
134
+ ssh.on("auth:failure", (data) => {
135
+ this.stats.authAttempts++;
136
+ this.stats.authFailures++;
137
+ this.log("SshMimic", "auth:failure", data);
138
+ });
139
+ ssh.on("client:connect", () => {
140
+ this.stats.clientConnects++;
141
+ this.log("SshMimic", "client:connect", {});
142
+ });
143
+ ssh.on("client:disconnect", (data) => {
144
+ this.stats.clientDisconnects++;
145
+ this.log("SshMimic", "client:disconnect", data);
146
+ });
147
+ }
148
+ /**
149
+ * Attaches to SftpMimic events.
150
+ */
151
+ attachSftpMimic(sftp) {
152
+ sftp.on("start", (data) => {
153
+ this.log("SftpMimic", "start", data);
154
+ });
155
+ sftp.on("stop", () => {
156
+ this.log("SftpMimic", "stop", {});
157
+ });
158
+ sftp.on("auth:success", (data) => {
159
+ this.stats.authAttempts++;
160
+ this.stats.authSuccesses++;
161
+ this.log("SftpMimic", "auth:success", data);
162
+ });
163
+ sftp.on("auth:failure", (data) => {
164
+ this.stats.authAttempts++;
165
+ this.stats.authFailures++;
166
+ this.log("SftpMimic", "auth:failure", data);
167
+ });
168
+ sftp.on("client:connect", () => {
169
+ this.stats.clientConnects++;
170
+ this.log("SftpMimic", "client:connect", {});
171
+ });
172
+ sftp.on("client:disconnect", (data) => {
173
+ this.stats.clientDisconnects++;
174
+ this.log("SftpMimic", "client:disconnect", data);
175
+ });
176
+ }
177
+ /**
178
+ * Records an audit log entry.
179
+ *
180
+ * @param source Event source (e.g., "SshMimic", "VirtualFileSystem").
181
+ * @param type Event type.
182
+ * @param details Event-specific data.
183
+ */
184
+ log(source, type, details) {
185
+ const entry = {
186
+ timestamp: new Date().toISOString(),
187
+ type,
188
+ source,
189
+ details,
190
+ };
191
+ this.auditLog.push(entry);
192
+ // Trim log if exceeds max size
193
+ if (this.auditLog.length > this.maxLogSize) {
194
+ this.auditLog = this.auditLog.slice(-this.maxLogSize);
195
+ }
196
+ // Console output for real-time monitoring
197
+ console.log(`[AUDIT] ${entry.timestamp} | ${source} | ${type}`, details);
198
+ }
199
+ /**
200
+ * Returns audit log entries matching optional filters.
201
+ *
202
+ * @param type Optional event type filter.
203
+ * @param source Optional source filter.
204
+ * @returns Filtered audit log entries.
205
+ */
206
+ getAuditLog(type, source) {
207
+ return this.auditLog.filter((entry) => (!type || entry.type === type) && (!source || entry.source === source));
208
+ }
209
+ /**
210
+ * Returns current activity statistics.
211
+ *
212
+ * @returns Snapshot of honeypot stats.
213
+ */
214
+ getStats() {
215
+ return Object.freeze({ ...this.stats });
216
+ }
217
+ /**
218
+ * Clears audit log and resets statistics.
219
+ */
220
+ reset() {
221
+ this.auditLog = [];
222
+ this.stats = {
223
+ authAttempts: 0,
224
+ authSuccesses: 0,
225
+ authFailures: 0,
226
+ commands: 0,
227
+ fileWrites: 0,
228
+ fileReads: 0,
229
+ sessionStarts: 0,
230
+ sessionEnds: 0,
231
+ userCreated: 0,
232
+ userDeleted: 0,
233
+ clientConnects: 0,
234
+ clientDisconnects: 0,
235
+ };
236
+ }
237
+ /**
238
+ * Returns recent log entries in reverse chronological order.
239
+ *
240
+ * @param limit Number of recent entries to return (default: 100).
241
+ * @returns Recent audit log entries.
242
+ */
243
+ getRecent(limit = 100) {
244
+ return this.auditLog.slice(Math.max(0, this.auditLog.length - limit));
245
+ }
246
+ /**
247
+ * Detects potential security issues based on activity patterns.
248
+ *
249
+ * @returns Array of anomalies detected.
250
+ */
251
+ detectAnomalies() {
252
+ const anomalies = [];
253
+ // High auth failure rate
254
+ if (this.stats.authAttempts > 0 &&
255
+ this.stats.authFailures / this.stats.authAttempts > 0.5) {
256
+ anomalies.push({
257
+ type: "high_auth_failure_rate",
258
+ severity: "medium",
259
+ message: `Auth failure rate: ${((this.stats.authFailures / this.stats.authAttempts) * 100).toFixed(1)}%`,
260
+ });
261
+ }
262
+ // Excessive auth failures in short time
263
+ if (this.stats.authFailures > 10) {
264
+ anomalies.push({
265
+ type: "excessive_auth_failures",
266
+ severity: "high",
267
+ message: `${this.stats.authFailures} authentication failures detected`,
268
+ });
269
+ }
270
+ // Unusual command execution volume
271
+ if (this.stats.commands > 1000) {
272
+ anomalies.push({
273
+ type: "high_command_volume",
274
+ severity: "low",
275
+ message: `${this.stats.commands} commands executed`,
276
+ });
277
+ }
278
+ // Unusual file write volume
279
+ if (this.stats.fileWrites > 500) {
280
+ anomalies.push({
281
+ type: "high_write_volume",
282
+ severity: "medium",
283
+ message: `${this.stats.fileWrites} file write operations`,
284
+ });
285
+ }
286
+ return anomalies;
287
+ }
288
+ }
289
+ export default HoneyPot;
package/dist/index.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  import { SshClient } from "./SSHClient";
2
- import { SshMimic } from "./SSHMimic/index";
2
+ import { SftpMimic, SshMimic } from "./SSHMimic/index";
3
3
  import VirtualFileSystem from "./VirtualFileSystem";
4
4
  import { VirtualShell } from "./VirtualShell";
5
5
  import { VirtualUserManager } from "./VirtualUserManager";
6
+ import { HoneyPot } from "./honeypot";
6
7
  export type { CommandContext, CommandMode, CommandOutcome, CommandResult, NanoEditorSession, ShellModule, SudoChallenge, } from "./types/commands";
7
8
  export type { ExecStream, ShellStream } from "./types/streams";
8
9
  export type { RemoveOptions, VfsBaseNode, VfsDirectoryNode, VfsFileNode, VfsNodeStats, VfsNodeType, VfsSnapshot, VfsSnapshotBaseNode, VfsSnapshotDirectoryNode, VfsSnapshotFileNode, VfsSnapshotNode, WriteFileOptions, } from "./types/vfs";
9
- export { SshClient, VirtualFileSystem, VirtualShell, SshMimic as VirtualSshServer, VirtualUserManager, };
10
+ export type { AuditLogEntry, HoneyPotStats, } from "./honeypot";
11
+ export { SshClient, VirtualFileSystem, SftpMimic as VirtualSftpServer, VirtualShell, SshMimic as VirtualSshServer, VirtualUserManager, HoneyPot, };
10
12
  export { getArg, getFlag, ifFlag, } from "./commands/command-helpers";
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,YAAY,EACX,cAAc,EACd,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,aAAa,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC/D,YAAY,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,QAAQ,IAAI,gBAAgB,EAC5B,kBAAkB,GAClB,CAAC;AAEF,OAAO,EACN,MAAM,EACN,OAAO,EACP,MAAM,GACN,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,YAAY,EACX,cAAc,EACd,WAAW,EACX,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,aAAa,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC/D,YAAY,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EACX,aAAa,EACb,aAAa,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,SAAS,EACT,iBAAiB,EACjB,SAAS,IAAI,iBAAiB,EAC9B,YAAY,EACZ,QAAQ,IAAI,gBAAgB,EAC5B,kBAAkB,EAClB,QAAQ,GACR,CAAC;AAEF,OAAO,EACN,MAAM,EACN,OAAO,EACP,MAAM,GACN,MAAM,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { SshClient } from "./SSHClient";
2
- import { SshMimic } from "./SSHMimic/index";
2
+ import { SftpMimic, SshMimic } from "./SSHMimic/index";
3
3
  import VirtualFileSystem from "./VirtualFileSystem";
4
4
  import { VirtualShell } from "./VirtualShell";
5
5
  import { VirtualUserManager } from "./VirtualUserManager";
6
- export { SshClient, VirtualFileSystem, VirtualShell, SshMimic as VirtualSshServer, VirtualUserManager, };
6
+ import { HoneyPot } from "./honeypot";
7
+ export { SshClient, VirtualFileSystem, SftpMimic as VirtualSftpServer, VirtualShell, SshMimic as VirtualSshServer, VirtualUserManager, HoneyPot, };
7
8
  export { getArg, getFlag, ifFlag, } from "./commands/command-helpers";
@@ -1,4 +1,4 @@
1
- import { VirtualShell, VirtualSshServer } from ".";
1
+ import { VirtualSftpServer, VirtualShell, VirtualSshServer } from ".";
2
2
  const hostname = process.env.SSH_MIMIC_HOSTNAME ?? "typescript-vm";
3
3
  const virtualShell = new VirtualShell(hostname);
4
4
  virtualShell.addCommand("demo", [], () => {
@@ -23,3 +23,12 @@ new VirtualSshServer({
23
23
  console.error("Failed to start SSH Mimic:", error);
24
24
  process.exit(1);
25
25
  });
26
+ new VirtualSftpServer({ port: 2223, hostname, shell: virtualShell })
27
+ .start()
28
+ .then((port) => {
29
+ console.log(`SFTP Mimic initialized. Listening on port ${port}.`);
30
+ })
31
+ .catch((error) => {
32
+ console.error("Failed to start SFTP Mimic:", error);
33
+ process.exit(1);
34
+ });