typescript-virtual-container 1.4.8 → 1.4.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.
Files changed (122) hide show
  1. package/README.md +1 -1
  2. package/builds/self-standalone.js +2 -3
  3. package/builds/standalone-wo-sftp.js +2 -3
  4. package/builds/standalone.cjs +37 -38
  5. package/builds/web-full-api.min.js +0 -1
  6. package/builds/web.min.js +0 -1
  7. package/dist/Honeypot/index.d.ts +6 -0
  8. package/dist/Honeypot/index.d.ts.map +1 -1
  9. package/dist/Honeypot/index.js +20 -0
  10. package/dist/Honeypot/index.js.map +1 -1
  11. package/dist/SSHMimic/index.d.ts +6 -5
  12. package/dist/SSHMimic/index.d.ts.map +1 -1
  13. package/dist/SSHMimic/index.js +6 -5
  14. package/dist/SSHMimic/index.js.map +1 -1
  15. package/dist/SSHMimic/sftp.d.ts +1 -0
  16. package/dist/SSHMimic/sftp.d.ts.map +1 -1
  17. package/dist/SSHMimic/sftp.js.map +1 -1
  18. package/dist/VirtualFileSystem/internalTypes.d.ts +4 -0
  19. package/dist/VirtualFileSystem/internalTypes.d.ts.map +1 -1
  20. package/dist/VirtualFileSystem/journal.d.ts +1 -0
  21. package/dist/VirtualFileSystem/journal.d.ts.map +1 -1
  22. package/dist/VirtualFileSystem/journal.js.map +1 -1
  23. package/dist/VirtualShell/idleManager.d.ts +6 -2
  24. package/dist/VirtualShell/idleManager.d.ts.map +1 -1
  25. package/dist/VirtualShell/idleManager.js +10 -6
  26. package/dist/VirtualShell/idleManager.js.map +1 -1
  27. package/dist/VirtualShell/index.d.ts +13 -1
  28. package/dist/VirtualShell/index.d.ts.map +1 -1
  29. package/dist/VirtualShell/index.js +10 -5
  30. package/dist/VirtualShell/index.js.map +1 -1
  31. package/dist/VirtualUserManager/index.d.ts +4 -2
  32. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  33. package/dist/VirtualUserManager/index.js +0 -1
  34. package/dist/VirtualUserManager/index.js.map +1 -1
  35. package/dist/commands/command-helpers.d.ts +5 -2
  36. package/dist/commands/command-helpers.d.ts.map +1 -1
  37. package/dist/commands/command-helpers.js.map +1 -1
  38. package/dist/index.d.ts +5 -2
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js.map +1 -1
  41. package/docs/assets/hierarchy.js +1 -1
  42. package/docs/assets/navigation.js +1 -1
  43. package/docs/assets/search.js +1 -1
  44. package/docs/classes/HoneyPot.html +9 -9
  45. package/docs/classes/IdleManager.html +12 -9
  46. package/docs/classes/SshClient.html +18 -18
  47. package/docs/classes/VirtualFileSystem.html +34 -42
  48. package/docs/classes/VirtualPackageManager.html +13 -13
  49. package/docs/classes/VirtualSftpServer.html +3 -3
  50. package/docs/classes/VirtualShell.html +33 -29
  51. package/docs/classes/VirtualSshServer.html +12 -7
  52. package/docs/classes/VirtualUserManager.html +30 -30
  53. package/docs/functions/assertDiff.html +2 -2
  54. package/docs/functions/diffSnapshots.html +2 -2
  55. package/docs/functions/formatDiff.html +2 -2
  56. package/docs/functions/getArg.html +3 -3
  57. package/docs/functions/getFlag.html +2 -2
  58. package/docs/functions/ifFlag.html +2 -2
  59. package/docs/hierarchy.html +1 -1
  60. package/docs/index.html +3 -3
  61. package/docs/interfaces/AuditLogEntry.html +3 -3
  62. package/docs/interfaces/CommandContext.html +13 -13
  63. package/docs/interfaces/CommandResult.html +13 -13
  64. package/docs/interfaces/ExecStream.html +6 -6
  65. package/docs/interfaces/HoneyPotStats.html +5 -3
  66. package/docs/interfaces/IdleManagerOptions.html +3 -3
  67. package/docs/interfaces/InstalledPackage.html +11 -11
  68. package/docs/interfaces/NanoEditorSession.html +5 -5
  69. package/docs/interfaces/PackageDefinition.html +14 -14
  70. package/docs/interfaces/PackageFile.html +5 -5
  71. package/docs/interfaces/PasswordChallenge.html +16 -0
  72. package/docs/interfaces/RemoveOptions.html +3 -3
  73. package/docs/interfaces/ShellEnv.html +4 -4
  74. package/docs/interfaces/ShellModule.html +8 -8
  75. package/docs/interfaces/ShellProperties.html +5 -5
  76. package/docs/interfaces/ShellStream.html +7 -7
  77. package/docs/interfaces/SudoChallenge.html +9 -9
  78. package/docs/interfaces/VfsBaseNode.html +7 -7
  79. package/docs/interfaces/VfsDiff.html +6 -6
  80. package/docs/interfaces/VfsDiffEntry.html +4 -4
  81. package/docs/interfaces/VfsDiffModified.html +6 -6
  82. package/docs/interfaces/VfsDirectoryNode.html +8 -8
  83. package/docs/interfaces/VfsFileNode.html +9 -9
  84. package/docs/interfaces/VfsOptions.html +6 -6
  85. package/docs/interfaces/VfsSnapshot.html +3 -3
  86. package/docs/interfaces/VfsSnapshotBaseNode.html +4 -4
  87. package/docs/interfaces/VfsSnapshotDirectoryNode.html +5 -5
  88. package/docs/interfaces/VfsSnapshotFileNode.html +6 -6
  89. package/docs/interfaces/VirtualActiveSession.html +12 -0
  90. package/docs/interfaces/VirtualSftpServerOptions.html +7 -0
  91. package/docs/interfaces/VirtualShellVfsLike.html +15 -0
  92. package/docs/interfaces/VirtualShellVfsOptions.html +3 -0
  93. package/docs/interfaces/WriteFileOptions.html +4 -4
  94. package/docs/modules.html +1 -1
  95. package/docs/types/ArgParseOptions.html +4 -0
  96. package/docs/types/CommandMode.html +2 -2
  97. package/docs/types/CommandOutcome.html +2 -2
  98. package/docs/types/IdleState.html +1 -1
  99. package/docs/types/VfsNodeStats.html +2 -2
  100. package/docs/types/VfsNodeType.html +2 -2
  101. package/docs/types/VfsPersistenceMode.html +2 -2
  102. package/docs/types/VfsSnapshotNode.html +2 -2
  103. package/examples/web.min.js +0 -1
  104. package/package.json +10 -10
  105. package/scripts/generate-manuals-bundle.mjs +1 -1
  106. package/scripts/publish-package.sh +1 -1
  107. package/src/Honeypot/index.ts +24 -0
  108. package/src/SSHMimic/index.ts +7 -5
  109. package/src/SSHMimic/sftp.ts +6 -0
  110. package/src/VirtualFileSystem/internalTypes.ts +4 -0
  111. package/src/VirtualFileSystem/journal.ts +1 -0
  112. package/src/VirtualShell/idleManager.ts +10 -6
  113. package/src/VirtualShell/index.ts +18 -3
  114. package/src/VirtualUserManager/index.ts +4 -2
  115. package/src/commands/command-helpers.ts +5 -1
  116. package/src/index.ts +5 -1
  117. package/typedoc.json +45 -0
  118. package/builds/self-standalone.js.map +0 -7
  119. package/builds/standalone-wo-sftp.js.map +0 -7
  120. package/builds/standalone.cjs.map +0 -7
  121. package/builds/web-full-api.min.js.map +0 -7
  122. package/builds/web.min.js.map +0 -7
package/README.md CHANGED
@@ -1102,7 +1102,7 @@ Type `help` in the shell for a grouped, colorized listing. Type `help <command>`
1102
1102
  | `su [user]` | | Switch user |
1103
1103
  | `sudo <cmd>` | `-i` | Run as root |
1104
1104
 
1105
- **ℹ️ All 91 built-in commands include complete JSDoc documentation** with `@category` and `@params` tags. See [src/commands/](src/commands/) for source code and inline documentation.
1105
+ **ℹ️ All 91 built-in commands include complete JSDoc documentation** with `@category` and `@params` tags. See [src/commands/](https://github.com/itsrealfortune/typescript-virtual-container/tree/main/src/commands) for source code and inline documentation.
1106
1106
 
1107
1107
  Custom commands: `shell.addCommand(name, params, callback)`.
1108
1108
 
@@ -1244,7 +1244,7 @@ echo 'neofetch: virtual stub'
1244
1244
  `),s=!1;s=this.writeIfChanged(this.usersPath,e.length>0?`${e}
1245
1245
  `:"",384)||s,s=this.writeIfChanged(this.sudoersPath,r.length>0?`${r}
1246
1246
  `:"",384)||s,s=this.writeIfChanged(this.quotasPath,i.length>0?`${i}
1247
- `:"",384)||s,s&&await this.vfs.flushMirror()}writeIfChanged(e,r,i){return this.vfs.exists(e)&&this.vfs.readFile(e)===r?(this.vfs.chmod(e,i),!1):(this.vfs.writeFile(e,r,{mode:i}),!0)}createRecord(e,r){let i=ks("sha256").update(e).update(":").update(r).digest("hex"),s=n.recordCache.get(i);if(s)return s;let o=po(16).toString("hex"),a={username:e,salt:o,passwordHash:this.hashPassword(r,o)};return n.recordCache.set(i,a),a}hasPassword(e){et.mark("hasPassword");let r=this.users.get(e);if(!r)return!1;let i=this.hashPassword("",r.salt);return r.passwordHash===i?!1:!!r.passwordHash}hashPassword(e,r=""){return n.fastPasswordHash?ks("sha256").update(r).update(e).digest("hex"):ho(e,r||"",32).toString("hex")}validateUsername(e){if(!e||e.trim()==="")throw new Error("invalid username");if(!/^[a-z_][a-z0-9_-]{0,31}$/i.test(e))throw new Error("invalid username")}validatePassword(e){if(!e||e.trim()==="")throw new Error("invalid password")}authorizedKeys=new Map;addAuthorizedKey(e,r,i){et.mark("addAuthorizedKey");let s=this.authorizedKeys.get(e)??[];s.push({algo:r,data:i}),this.authorizedKeys.set(e,s),this.emit("key:add",{username:e,algo:r})}removeAuthorizedKeys(e){this.authorizedKeys.delete(e),this.emit("key:remove",{username:e})}getAuthorizedKeys(e){return this.authorizedKeys.get(e)??[]}};function Is(n){let t=As.posix.normalize(n);return t.startsWith("/")?t:`/${t}`}import{EventEmitter as wo}from"node:events";var Ce=class extends wo{vfs;idleThresholdMs;checkIntervalMs;_state="active";_lastActivity=Date.now();_frozenBuffer=null;_checkTimer=null;constructor(t,e={}){super(),this.vfs=t,this.idleThresholdMs=e.idleThresholdMs??6e4,this.checkIntervalMs=e.checkIntervalMs??15e3}start(){this._checkTimer||(this._lastActivity=Date.now(),this._checkTimer=setInterval(()=>this._check(),this.checkIntervalMs),typeof this._checkTimer=="object"&&this._checkTimer!==null&&"unref"in this._checkTimer&&this._checkTimer.unref())}async stop(){this._checkTimer&&(clearInterval(this._checkTimer),this._checkTimer=null),this._state==="frozen"&&await this._thaw()}async ping(){this._lastActivity=Date.now(),this._state==="frozen"&&await this._thaw()}get state(){return this._state}get idleMs(){return Date.now()-this._lastActivity}_check(){this._state!=="frozen"&&Date.now()-this._lastActivity>=this.idleThresholdMs&&this._freeze()}async _freeze(){this._state!=="frozen"&&(await this.vfs.stopAutoFlush(),this._frozenBuffer=this.vfs.encodeBinary(),this.vfs.releaseTree(),this._state="frozen",this.emit("freeze"))}async _thaw(){if(this._state!=="frozen"||!this._frozenBuffer)return;let t=Mt(this._frozenBuffer);this.vfs.importRootTree(t),this._frozenBuffer=null,this._state="active",this.emit("thaw")}};import{readFile as bo,unlink as vo,writeFile as xo}from"node:fs/promises";import*as Ge from"node:path";function Os(n,t,e,r,i,s="unknown",o={cols:80,rows:24},a){let l="",c=0,u=Co(a.vfs,e),d=null,m="",p=`/home/${e}`,h=Tt(e,r),y=null,f=null,S=()=>{let O=`/home/${e}`,U=p===O?"~":Ge.posix.basename(p)||"/";return ge(e,r,U)},I=Array.from(new Set(jt())).sort();console.log(`[${i}] Shell started for user '${e}' at ${s}`),(async()=>{let O=`/home/${e}/.bashrc`;if(a.vfs.exists(O))try{let U=a.vfs.readFile(O);for(let V of U.split(`
1247
+ `:"",384)||s,s&&await this.vfs.flushMirror()}writeIfChanged(e,r,i){return this.vfs.exists(e)&&this.vfs.readFile(e)===r?(this.vfs.chmod(e,i),!1):(this.vfs.writeFile(e,r,{mode:i}),!0)}createRecord(e,r){let i=ks("sha256").update(e).update(":").update(r).digest("hex"),s=n.recordCache.get(i);if(s)return s;let o=po(16).toString("hex"),a={username:e,salt:o,passwordHash:this.hashPassword(r,o)};return n.recordCache.set(i,a),a}hasPassword(e){et.mark("hasPassword");let r=this.users.get(e);if(!r)return!1;let i=this.hashPassword("",r.salt);return r.passwordHash===i?!1:!!r.passwordHash}hashPassword(e,r=""){return n.fastPasswordHash?ks("sha256").update(r).update(e).digest("hex"):ho(e,r||"",32).toString("hex")}validateUsername(e){if(!e||e.trim()==="")throw new Error("invalid username");if(!/^[a-z_][a-z0-9_-]{0,31}$/i.test(e))throw new Error("invalid username")}validatePassword(e){if(!e||e.trim()==="")throw new Error("invalid password")}authorizedKeys=new Map;addAuthorizedKey(e,r,i){et.mark("addAuthorizedKey");let s=this.authorizedKeys.get(e)??[];s.push({algo:r,data:i}),this.authorizedKeys.set(e,s),this.emit("key:add",{username:e,algo:r})}removeAuthorizedKeys(e){this.authorizedKeys.delete(e),this.emit("key:remove",{username:e})}getAuthorizedKeys(e){return this.authorizedKeys.get(e)??[]}};function Is(n){let t=As.posix.normalize(n);return t.startsWith("/")?t:`/${t}`}import{EventEmitter as wo}from"node:events";var Ce=class extends wo{vfs;idleThresholdMs;checkIntervalMs;_state="active";_lastActivity=Date.now();_frozenBuffer=null;_checkTimer=null;constructor(t,e={}){super(),this.vfs=t,this.idleThresholdMs=e.idleThresholdMs??6e4,this.checkIntervalMs=e.checkIntervalMs??15e3}start(){this._checkTimer||(this._lastActivity=Date.now(),this._checkTimer=setInterval(()=>this._check(),this.checkIntervalMs),typeof this._checkTimer=="object"&&this._checkTimer!==null&&"unref"in this._checkTimer&&this._checkTimer.unref())}async stop(){this._checkTimer&&(clearInterval(this._checkTimer),this._checkTimer=null),this._state==="frozen"&&this._thaw()}ping(){this._lastActivity=Date.now(),this._state==="frozen"&&this._thaw()}get state(){return this._state}get idleMs(){return Date.now()-this._lastActivity}_check(){this._state!=="frozen"&&Date.now()-this._lastActivity>=this.idleThresholdMs&&this._freeze()}async _freeze(){this._state!=="frozen"&&(await this.vfs.stopAutoFlush(),this._frozenBuffer=this.vfs.encodeBinary(),this.vfs.releaseTree(),this._state="frozen",this.emit("freeze"))}_thaw(){if(this._state!=="frozen"||!this._frozenBuffer)return;let t=Mt(this._frozenBuffer);this.vfs.importRootTree(t),this._frozenBuffer=null,this._state="active",this.emit("thaw")}};import{readFile as bo,unlink as vo,writeFile as xo}from"node:fs/promises";import*as Ge from"node:path";function Os(n,t,e,r,i,s="unknown",o={cols:80,rows:24},a){let l="",c=0,u=Co(a.vfs,e),d=null,m="",p=`/home/${e}`,h=Tt(e,r),y=null,f=null,S=()=>{let O=`/home/${e}`,U=p===O?"~":Ge.posix.basename(p)||"/";return ge(e,r,U)},I=Array.from(new Set(jt())).sort();console.log(`[${i}] Shell started for user '${e}' at ${s}`),(async()=>{let O=`/home/${e}/.bashrc`;if(a.vfs.exists(O))try{let U=a.vfs.readFile(O);for(let V of U.split(`
1248
1248
  `)){let _=V.trim();!_||_.startsWith("#")||await J(_,e,r,"shell",p,a,void 0,h)}}catch{}})();function k(){let O=S();t.write(`\r${O}${l}\x1B[K`);let U=l.length-c;U>0&&t.write(`\x1B[${U}D`)}function b(){t.write("\r\x1B[K")}function M(O){f={...O,buffer:""},b(),t.write(O.prompt)}async function A(O){if(!f)return;let U=f;if(f=null,!O){t.write(`\r
1249
1249
  Sorry, try again.\r
1250
1250
  `),k();return}if(!U.commandLine){e=U.targetUser,U.loginShell&&(p=`/home/${e}`),a.users.updateSession(i,e,s),t.write(`\r
@@ -1273,7 +1273,7 @@ Sorry, try again.\r
1273
1273
  `),L.stderr&&t.write(`${Yt(L.stderr)}\r
1274
1274
  `),L.closeSession){t.write(`logout\r
1275
1275
  `),t.exit(L.exitCode??0),t.end();return}L.nextCwd&&(p=L.nextCwd),L.switchUser&&(e=L.switchUser,p=L.nextCwd??`/home/${e}`,a.users.updateSession(i,e,s),l="",c=0)}k();continue}if(_==="\x7F"||_==="\b"){c>0&&(l=`${l.slice(0,c-1)}${l.slice(c)}`,c-=1,k());continue}$(_)}}),t.on("close",()=>{y&&(y.process.kill("SIGTERM"),y=null)})}function Co(n,t){let e=`/home/${t}/.bash_history`;return n.exists(e)?n.readFile(e).split(`
1276
- `).map(i=>i.trim()).filter(i=>i.length>0):(n.writeFile(e,""),[])}function Po(n){return typeof n=="object"&&n!==null&&"vfsInstance"in n&&Fs(n.vfsInstance)}function Fs(n){if(typeof n!="object"||n===null)return!1;let t=n;return typeof t.restoreMirror=="function"&&typeof t.flushMirror=="function"&&typeof t.writeFile=="function"&&typeof t.readFile=="function"&&typeof t.mkdir=="function"&&typeof t.exists=="function"&&typeof t.stat=="function"&&typeof t.list=="function"&&typeof t.remove=="function"&&typeof t.copy=="function"&&typeof t.move=="function"&&typeof t.touch=="function"}var No={kernel:"1.0.0+itsrealfortune+1-amd64",os:"Fortune GNU/Linux x64",arch:"x86_64"},Gt=be("VirtualShell");function Eo(){let n=process.env.SSH_MIMIC_AUTO_SUDO_NEW_USERS;return n?!["0","false","no","off"].includes(n.toLowerCase()):!0}var $e=class extends $o{vfs;users;packageManager;hostname;properties;startTime;_idle=null;initialized;constructor(t,e,r){super(),Gt.mark("constructor"),this.hostname=t,this.properties=e||No,this.startTime=Date.now(),Fs(r)?this.vfs=r:Po(r)?this.vfs=r.vfsInstance:this.vfs=new Se(r??{}),this.users=new xe(this.vfs,Eo()),this.packageManager=new ve(this.vfs,this.users);let i=this.vfs,s=this.users,o=this.packageManager,a=this.properties,l=this.hostname,c=this.startTime;this.initialized=(async()=>{await i.restoreMirror(),await s.initialize(),Ns(i,s,l,a,c),o.load(),this.emit("initialized")})()}async ensureInitialized(){Gt.mark("ensureInitialized"),await this.initialized}addCommand(t,e,r){let i=t.trim().toLowerCase();if(i.length===0||/\s/.test(i))throw new Error("Command name must be non-empty and contain no spaces");Oe(Fe(i,e,r))}executeCommand(t,e,r){Gt.mark("executeCommand"),this._idle&&this._idle.ping(),J(t,e,this.hostname,"shell",r,this),this.emit("command",{command:t,user:e,cwd:r})}startInteractiveSession(t,e,r,i,s){Gt.mark("startInteractiveSession"),this._idle&&this._idle.ping(),this.emit("session:start",{user:e,sessionId:r,remoteAddress:i}),Os(this.properties,t,e,this.hostname,r,i,s,this),this.refreshProcSessions()}refreshProcFs(){we(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}mount(t,e,r={}){this.vfs.mount(t,e,r)}unmount(t){this.vfs.unmount(t)}getMounts(){return this.vfs.getMounts()}refreshProcSessions(){we(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}syncPasswd(){Ye(this.vfs,this.users)}getVfs(){return this?.vfs??null}getUsers(){return this?.users??null}getHostname(){return this?.hostname}writeFileAsUser(t,e,r){Gt.mark("writeFileAsUser"),this.users.assertWriteWithinQuota(t,e,r),this.vfs.writeFile(e,r)}enableIdleManagement(t){this._idle||(this._idle=new Ce(this.vfs,t),this._idle.on("freeze",()=>this.emit("shell:freeze")),this._idle.on("thaw",()=>this.emit("shell:thaw")),this._idle.start())}async disableIdleManagement(){this._idle&&(await this._idle.stop(),this._idle=null)}get idleState(){return this._idle?.state??"active"}get idleMs(){return this._idle?.idleMs??0}};var Ut=process.env.SSH_MIMIC_HOSTNAME??"typescript-vm",Je=process.argv.slice(2);console.clear();function Fo(){for(let n=0;n<Je.length;n+=1){let t=Je[n];if(t==="--user"){let e=Je[n+1];if(!e||e.startsWith("--"))throw new Error("self-standalone: --user requires a value");return e}if(t?.startsWith("--user="))return t.slice(7)||"root"}return"root"}var Ro=Fo(),q=new $e(Ut,void 0,{mode:"fs",snapshotPath:".vfs"});function To(n){let t=`/home/${n}/.lastlog`;if(!q.vfs.exists(t))return null;try{return JSON.parse(q.vfs.readFile(t))}catch{return null}}function _o(n,t){q.vfs.writeFile(`/home/${n}/.lastlog`,JSON.stringify({at:new Date().toISOString(),from:t}))}async function Jt(){await q.vfs.stopAutoFlush()}function Do(n){let t=`/home/${n}/.bash_history`;return q.vfs.exists(t)?q.vfs.readFile(t).split(`
1276
+ `).map(i=>i.trim()).filter(i=>i.length>0):(n.writeFile(e,""),[])}function Po(n){return typeof n=="object"&&n!==null&&"vfsInstance"in n&&Fs(n.vfsInstance)}function Fs(n){if(typeof n!="object"||n===null)return!1;let t=n;return typeof t.restoreMirror=="function"&&typeof t.flushMirror=="function"&&typeof t.writeFile=="function"&&typeof t.readFile=="function"&&typeof t.mkdir=="function"&&typeof t.exists=="function"&&typeof t.stat=="function"&&typeof t.list=="function"&&typeof t.remove=="function"&&typeof t.copy=="function"&&typeof t.move=="function"&&typeof t.touch=="function"}var No={kernel:"1.0.0+itsrealfortune+1-amd64",os:"Fortune GNU/Linux x64",arch:"x86_64"},Gt=be("VirtualShell");function Eo(){let n=process.env.SSH_MIMIC_AUTO_SUDO_NEW_USERS;return n?!["0","false","no","off"].includes(n.toLowerCase()):!0}var $e=class extends $o{vfs;users;packageManager;hostname;properties;startTime;_idle=null;initialized;constructor(t,e,r){super(),Gt.mark("constructor"),this.hostname=t,this.properties=e||No,this.startTime=Date.now(),Fs(r)?this.vfs=r:Po(r)?this.vfs=r.vfsInstance:this.vfs=new Se(r??{}),this.users=new xe(this.vfs,Eo()),this.packageManager=new ve(this.vfs,this.users);let i=this.vfs,s=this.users,o=this.packageManager,a=this.properties,l=this.hostname,c=this.startTime;this.initialized=(async()=>{await i.restoreMirror(),await s.initialize(),Ns(i,s,l,a,c),o.load(),this.emit("initialized")})()}async ensureInitialized(){Gt.mark("ensureInitialized"),await this.initialized}addCommand(t,e,r){let i=t.trim().toLowerCase();if(i.length===0||/\s/.test(i))throw new Error("Command name must be non-empty and contain no spaces");Oe(Fe(i,e,r))}executeCommand(t,e,r){Gt.mark("executeCommand"),this._idle?.ping(),J(t,e,this.hostname,"shell",r,this),this.emit("command",{command:t,user:e,cwd:r})}startInteractiveSession(t,e,r,i,s){Gt.mark("startInteractiveSession"),this._idle?.ping(),this.emit("session:start",{user:e,sessionId:r,remoteAddress:i}),Os(this.properties,t,e,this.hostname,r,i,s,this),this.refreshProcSessions()}refreshProcFs(){we(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}mount(t,e,r={}){this.vfs.mount(t,e,r)}unmount(t){this.vfs.unmount(t)}getMounts(){return this.vfs.getMounts()}refreshProcSessions(){we(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}syncPasswd(){Ye(this.vfs,this.users)}getVfs(){return this?.vfs??null}getUsers(){return this?.users??null}getHostname(){return this?.hostname}writeFileAsUser(t,e,r){Gt.mark("writeFileAsUser"),this.users.assertWriteWithinQuota(t,e,r),this.vfs.writeFile(e,r)}enableIdleManagement(t){this._idle||(this._idle=new Ce(this.vfs,t),this._idle.on("freeze",()=>this.emit("shell:freeze")),this._idle.on("thaw",()=>this.emit("shell:thaw")),this._idle.start())}async disableIdleManagement(){this._idle&&(await this._idle.stop(),this._idle=null)}get idleState(){return this._idle?.state??"active"}get idleMs(){return this._idle?.idleMs??0}pingIdle(){this._idle?.ping()}};var Ut=process.env.SSH_MIMIC_HOSTNAME??"typescript-vm",Je=process.argv.slice(2);console.clear();function Fo(){for(let n=0;n<Je.length;n+=1){let t=Je[n];if(t==="--user"){let e=Je[n+1];if(!e||e.startsWith("--"))throw new Error("self-standalone: --user requires a value");return e}if(t?.startsWith("--user="))return t.slice(7)||"root"}return"root"}var Ro=Fo(),q=new $e(Ut,void 0,{mode:"fs",snapshotPath:".vfs"});function To(n){let t=`/home/${n}/.lastlog`;if(!q.vfs.exists(t))return null;try{return JSON.parse(q.vfs.readFile(t))}catch{return null}}function _o(n,t){q.vfs.writeFile(`/home/${n}/.lastlog`,JSON.stringify({at:new Date().toISOString(),from:t}))}async function Jt(){await q.vfs.stopAutoFlush()}function Do(n){let t=`/home/${n}/.bash_history`;return q.vfs.exists(t)?q.vfs.readFile(t).split(`
1277
1277
  `).map(e=>e.trim()).filter(e=>e.length>0):(q.vfs.writeFile(t,""),[])}function Uo(n,t){let e=n.length>0?`${n.join(`
1278
1278
  `)}
1279
1279
  `:"";q.vfs.writeFile(`/home/${t}/.bash_history`,e)}function Lo(n,t,e){let r=e.lastIndexOf("/"),i=r>=0?e.slice(0,r+1):"",s=r>=0?e.slice(r+1):e,o=pe(t,i||".");try{return n.list(o).filter(a=>!a.startsWith(".")&&a.startsWith(s)).map(a=>{let l=Ts.posix.join(o,a),c=n.stat(l);return`${i}${a}${c.type==="directory"?"/":""}`}).sort()}catch{return[]}}function Vo(n){let t=Array.from(new Set(jt())).sort();return(e,r)=>{let{cwd:i}=n(),s=e.split(/\s+/).at(-1)??"",a=e.trimStart()===s?t.filter(u=>u.startsWith(s)):[],l=Lo(q.vfs,i,s),c=Array.from(new Set([...a,...l])).sort();r(null,[c,s])}}function Zt(n,t){return new Promise(e=>{if(!ut.isTTY||!ot.isTTY){n.question(t,e);return}let r=!!ut.isRaw,i="",s=()=>{ut.off("data",a),r||ut.setRawMode(!1)},o=l=>{s(),ot.write(`
@@ -1297,4 +1297,3 @@ deluser: done.
1297
1297
  `),a.write("",{ctrl:!0,name:"u"}),h()}),a.on("close",()=>{Jt().then(()=>{console.log(""),process.exit(0)})}),h()}Bo().catch(n=>{console.error("Failed to start readline SSH emulation:",n),process.exit(1)});var Rs=!1;async function Wo(n){if(!Rs){Rs=!0,process.stdout.write(`
1298
1298
  [${n}] Saving VFS...
1299
1299
  `);try{await q.vfs.stopAutoFlush()}catch{}process.exit(0)}}process.on("SIGTERM",()=>{Wo("SIGTERM")});process.on("beforeExit",()=>{q.vfs.stopAutoFlush()});process.on("uncaughtException",n=>{console.error("Uncaught exception:",n)});process.on("unhandledRejection",(n,t)=>{console.error("Unhandled rejection at:",t,"error:",n)});
1300
- //# sourceMappingURL=self-standalone.js.map
@@ -1257,7 +1257,7 @@ echo 'neofetch: virtual stub'
1257
1257
  `),i=!1;i=this.writeIfChanged(this.usersPath,e.length>0?`${e}
1258
1258
  `:"",384)||i,i=this.writeIfChanged(this.sudoersPath,r.length>0?`${r}
1259
1259
  `:"",384)||i,i=this.writeIfChanged(this.quotasPath,s.length>0?`${s}
1260
- `:"",384)||i,i&&await this.vfs.flushMirror()}writeIfChanged(e,r,s){return this.vfs.exists(e)&&this.vfs.readFile(e)===r?(this.vfs.chmod(e,s),!1):(this.vfs.writeFile(e,r,{mode:s}),!0)}createRecord(e,r){let s=(0,wn.createHash)("sha256").update(e).update(":").update(r).digest("hex"),i=n.recordCache.get(s);if(i)return i;let o=(0,wn.randomBytes)(16).toString("hex"),a={username:e,salt:o,passwordHash:this.hashPassword(r,o)};return n.recordCache.set(s,a),a}hasPassword(e){Tt.mark("hasPassword");let r=this.users.get(e);if(!r)return!1;let s=this.hashPassword("",r.salt);return r.passwordHash===s?!1:!!r.passwordHash}hashPassword(e,r=""){return n.fastPasswordHash?(0,wn.createHash)("sha256").update(r).update(e).digest("hex"):(0,wn.scryptSync)(e,r||"",32).toString("hex")}validateUsername(e){if(!e||e.trim()==="")throw new Error("invalid username");if(!/^[a-z_][a-z0-9_-]{0,31}$/i.test(e))throw new Error("invalid username")}validatePassword(e){if(!e||e.trim()==="")throw new Error("invalid password")}authorizedKeys=new Map;addAuthorizedKey(e,r,s){Tt.mark("addAuthorizedKey");let i=this.authorizedKeys.get(e)??[];i.push({algo:r,data:s}),this.authorizedKeys.set(e,i),this.emit("key:add",{username:e,algo:r})}removeAuthorizedKeys(e){this.authorizedKeys.delete(e),this.emit("key:remove",{username:e})}getAuthorizedKeys(e){return this.authorizedKeys.get(e)??[]}};function Dh(n){let t=Mh.posix.normalize(n);return t.startsWith("/")?t:`/${t}`}var $h=require("node:events");var ao=class extends $h.EventEmitter{vfs;idleThresholdMs;checkIntervalMs;_state="active";_lastActivity=Date.now();_frozenBuffer=null;_checkTimer=null;constructor(t,e={}){super(),this.vfs=t,this.idleThresholdMs=e.idleThresholdMs??6e4,this.checkIntervalMs=e.checkIntervalMs??15e3}start(){this._checkTimer||(this._lastActivity=Date.now(),this._checkTimer=setInterval(()=>this._check(),this.checkIntervalMs),typeof this._checkTimer=="object"&&this._checkTimer!==null&&"unref"in this._checkTimer&&this._checkTimer.unref())}async stop(){this._checkTimer&&(clearInterval(this._checkTimer),this._checkTimer=null),this._state==="frozen"&&await this._thaw()}async ping(){this._lastActivity=Date.now(),this._state==="frozen"&&await this._thaw()}get state(){return this._state}get idleMs(){return Date.now()-this._lastActivity}_check(){this._state!=="frozen"&&Date.now()-this._lastActivity>=this.idleThresholdMs&&this._freeze()}async _freeze(){this._state!=="frozen"&&(await this.vfs.stopAutoFlush(),this._frozenBuffer=this.vfs.encodeBinary(),this.vfs.releaseTree(),this._state="frozen",this.emit("freeze"))}async _thaw(){if(this._state!=="frozen"||!this._frozenBuffer)return;let t=mr(this._frozenBuffer);this.vfs.importRootTree(t),this._frozenBuffer=null,this._state="active",this.emit("thaw")}};var ti=require("node:fs/promises"),Nc=zt(require("node:path"),1);var Kh=require("node:child_process");var Fh=require("node:fs/promises"),co=zt(require("node:path"),1);function kc(n){return`'${n.replace(/'/g,"'\\''")}'`}function qi(n){return n.replace(/\r\n/g,`
1260
+ `:"",384)||i,i&&await this.vfs.flushMirror()}writeIfChanged(e,r,s){return this.vfs.exists(e)&&this.vfs.readFile(e)===r?(this.vfs.chmod(e,s),!1):(this.vfs.writeFile(e,r,{mode:s}),!0)}createRecord(e,r){let s=(0,wn.createHash)("sha256").update(e).update(":").update(r).digest("hex"),i=n.recordCache.get(s);if(i)return i;let o=(0,wn.randomBytes)(16).toString("hex"),a={username:e,salt:o,passwordHash:this.hashPassword(r,o)};return n.recordCache.set(s,a),a}hasPassword(e){Tt.mark("hasPassword");let r=this.users.get(e);if(!r)return!1;let s=this.hashPassword("",r.salt);return r.passwordHash===s?!1:!!r.passwordHash}hashPassword(e,r=""){return n.fastPasswordHash?(0,wn.createHash)("sha256").update(r).update(e).digest("hex"):(0,wn.scryptSync)(e,r||"",32).toString("hex")}validateUsername(e){if(!e||e.trim()==="")throw new Error("invalid username");if(!/^[a-z_][a-z0-9_-]{0,31}$/i.test(e))throw new Error("invalid username")}validatePassword(e){if(!e||e.trim()==="")throw new Error("invalid password")}authorizedKeys=new Map;addAuthorizedKey(e,r,s){Tt.mark("addAuthorizedKey");let i=this.authorizedKeys.get(e)??[];i.push({algo:r,data:s}),this.authorizedKeys.set(e,i),this.emit("key:add",{username:e,algo:r})}removeAuthorizedKeys(e){this.authorizedKeys.delete(e),this.emit("key:remove",{username:e})}getAuthorizedKeys(e){return this.authorizedKeys.get(e)??[]}};function Dh(n){let t=Mh.posix.normalize(n);return t.startsWith("/")?t:`/${t}`}var $h=require("node:events");var ao=class extends $h.EventEmitter{vfs;idleThresholdMs;checkIntervalMs;_state="active";_lastActivity=Date.now();_frozenBuffer=null;_checkTimer=null;constructor(t,e={}){super(),this.vfs=t,this.idleThresholdMs=e.idleThresholdMs??6e4,this.checkIntervalMs=e.checkIntervalMs??15e3}start(){this._checkTimer||(this._lastActivity=Date.now(),this._checkTimer=setInterval(()=>this._check(),this.checkIntervalMs),typeof this._checkTimer=="object"&&this._checkTimer!==null&&"unref"in this._checkTimer&&this._checkTimer.unref())}async stop(){this._checkTimer&&(clearInterval(this._checkTimer),this._checkTimer=null),this._state==="frozen"&&this._thaw()}ping(){this._lastActivity=Date.now(),this._state==="frozen"&&this._thaw()}get state(){return this._state}get idleMs(){return Date.now()-this._lastActivity}_check(){this._state!=="frozen"&&Date.now()-this._lastActivity>=this.idleThresholdMs&&this._freeze()}async _freeze(){this._state!=="frozen"&&(await this.vfs.stopAutoFlush(),this._frozenBuffer=this.vfs.encodeBinary(),this.vfs.releaseTree(),this._state="frozen",this.emit("freeze"))}_thaw(){if(this._state!=="frozen"||!this._frozenBuffer)return;let t=mr(this._frozenBuffer);this.vfs.importRootTree(t),this._frozenBuffer=null,this._state="active",this.emit("thaw")}};var ti=require("node:fs/promises"),Nc=zt(require("node:path"),1);var Kh=require("node:child_process");var Fh=require("node:fs/promises"),co=zt(require("node:path"),1);function kc(n){return`'${n.replace(/'/g,"'\\''")}'`}function qi(n){return n.replace(/\r\n/g,`
1261
1261
  `).replace(/\r/g,`
1262
1262
  `).replace(/\n/g,`\r
1263
1263
  `)}function Hh(n,t){let e=Number.isFinite(t.cols)&&t.cols>0?Math.floor(t.cols):80,r=Number.isFinite(t.rows)&&t.rows>0?Math.floor(t.rows):24;return`stty cols ${e} rows ${r} 2>/dev/null; ${n}`}function Qh(n,t){return!t||t.trim()===""||t==="."?n:t.startsWith("/")?co.posix.normalize(t):co.posix.normalize(co.posix.join(n,t))}async function Wh(n){try{let e=(await(0,Fh.readFile)(`/proc/${n}/task/${n}/children`,"utf8")).trim().split(/\s+/).filter(Boolean).map(s=>Number.parseInt(s,10)).filter(s=>Number.isInteger(s)&&s>0),r=await Promise.all(e.map(s=>Wh(s)));return[...e,...r.flat()]}catch{return[]}}async function qh(n=process.pid){let t=await Wh(n),e=Array.from(new Set(t)).sort((r,s)=>r-s);return e.length===0?null:e.join(",")}function Vh(n,t,e){let r=Hh(n,t),s=(0,Kh.spawn)("script",["-qfec",r,"/dev/null"],{stdio:["pipe","pipe","pipe"],env:{...process.env,TERM:process.env.TERM??"xterm-256color"}});return s.stdout.on("data",i=>{e.write(i.toString("utf8"))}),s.stderr.on("data",i=>{e.write(i.toString("utf8"))}),s}function Yh(n,t,e){return Vh(`nano -- ${kc(n)}`,t,e)}function zh(n,t,e){return Vh(`htop -p ${kc(n)}`,t,e)}function Gh(n,t,e){let r=[`Linux ${n} ${t.kernel} ${t.arch}`,"","The programs included with the Fortune GNU/Linux system are free software;","the exact distribution terms for each program are described in the","individual files in /usr/share/doc/*/copyright.","","Fortune GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent","permitted by applicable law."];if(e){let s=new Date(e.at),i=Number.isNaN(s.getTime())?e.at:eo(s);r.push(`Last login: ${i} from ${e.from||"unknown"}`)}return r.push(""),`${r.map(s=>`${s}\r
@@ -1290,7 +1290,7 @@ Sorry, try again.\r
1290
1290
  `),ie.stderr&&t.write(`${qi(ie.stderr)}\r
1291
1291
  `),ie.closeSession){t.write(`logout\r
1292
1292
  `),t.exit(ie.exitCode??0),t.end();return}ie.nextCwd&&(p=ie.nextCwd),ie.switchUser&&(e=ie.switchUser,p=ie.nextCwd??`/home/${e}`,a.users.updateSession(s,e,i),c="",l=0)}H();continue}if(ee==="\x7F"||ee==="\b"){l>0&&(c=`${c.slice(0,l-1)}${c.slice(l)}`,l-=1,H());continue}k(ee)}}),t.on("close",()=>{y&&(y.process.kill("SIGTERM"),y=null)})}function UE(n,t){let e=`/home/${t}/.bash_history`;return n.exists(e)?n.readFile(e).split(`
1293
- `).map(s=>s.trim()).filter(s=>s.length>0):(n.writeFile(e,""),[])}function ME(n){return typeof n=="object"&&n!==null&&"vfsInstance"in n&&Zh(n.vfsInstance)}function Zh(n){if(typeof n!="object"||n===null)return!1;let t=n;return typeof t.restoreMirror=="function"&&typeof t.flushMirror=="function"&&typeof t.writeFile=="function"&&typeof t.readFile=="function"&&typeof t.mkdir=="function"&&typeof t.exists=="function"&&typeof t.stat=="function"&&typeof t.list=="function"&&typeof t.remove=="function"&&typeof t.copy=="function"&&typeof t.move=="function"&&typeof t.touch=="function"}var $E={kernel:"1.0.0+itsrealfortune+1-amd64",os:"Fortune GNU/Linux x64",arch:"x86_64"},Ki=ir("VirtualShell");function FE(){let n=process.env.SSH_MIMIC_AUTO_SUDO_NEW_USERS;return n?!["0","false","no","off"].includes(n.toLowerCase()):!0}var yr=class extends Jh.EventEmitter{vfs;users;packageManager;hostname;properties;startTime;_idle=null;initialized;constructor(t,e,r){super(),Ki.mark("constructor"),this.hostname=t,this.properties=e||$E,this.startTime=Date.now(),Zh(r)?this.vfs=r:ME(r)?this.vfs=r.vfsInstance:this.vfs=new ro(r??{}),this.users=new oo(this.vfs,FE()),this.packageManager=new so(this.vfs,this.users);let s=this.vfs,i=this.users,o=this.packageManager,a=this.properties,c=this.hostname,l=this.startTime;this.initialized=(async()=>{await s.restoreMirror(),await i.initialize(),Th(s,i,c,a,l),o.load(),this.emit("initialized")})()}async ensureInitialized(){Ki.mark("ensureInitialized"),await this.initialized}addCommand(t,e,r){let s=t.trim().toLowerCase();if(s.length===0||/\s/.test(s))throw new Error("Command name must be non-empty and contain no spaces");dc(hc(s,e,r))}executeCommand(t,e,r){Ki.mark("executeCommand"),this._idle&&this._idle.ping(),wt(t,e,this.hostname,"shell",r,this),this.emit("command",{command:t,user:e,cwd:r})}startInteractiveSession(t,e,r,s,i){Ki.mark("startInteractiveSession"),this._idle&&this._idle.ping(),this.emit("session:start",{user:e,sessionId:r,remoteAddress:s}),Xh(this.properties,t,e,this.hostname,r,s,i,this),this.refreshProcSessions()}refreshProcFs(){io(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}mount(t,e,r={}){this.vfs.mount(t,e,r)}unmount(t){this.vfs.unmount(t)}getMounts(){return this.vfs.getMounts()}refreshProcSessions(){io(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}syncPasswd(){Cc(this.vfs,this.users)}getVfs(){return this?.vfs??null}getUsers(){return this?.users??null}getHostname(){return this?.hostname}writeFileAsUser(t,e,r){Ki.mark("writeFileAsUser"),this.users.assertWriteWithinQuota(t,e,r),this.vfs.writeFile(e,r)}enableIdleManagement(t){this._idle||(this._idle=new ao(this.vfs,t),this._idle.on("freeze",()=>this.emit("shell:freeze")),this._idle.on("thaw",()=>this.emit("shell:thaw")),this._idle.start())}async disableIdleManagement(){this._idle&&(await this._idle.stop(),this._idle=null)}get idleState(){return this._idle?.state??"active"}get idleMs(){return this._idle?.idleMs??0}};function ep(n){return n.replace(/\r\n/g,`
1293
+ `).map(s=>s.trim()).filter(s=>s.length>0):(n.writeFile(e,""),[])}function ME(n){return typeof n=="object"&&n!==null&&"vfsInstance"in n&&Zh(n.vfsInstance)}function Zh(n){if(typeof n!="object"||n===null)return!1;let t=n;return typeof t.restoreMirror=="function"&&typeof t.flushMirror=="function"&&typeof t.writeFile=="function"&&typeof t.readFile=="function"&&typeof t.mkdir=="function"&&typeof t.exists=="function"&&typeof t.stat=="function"&&typeof t.list=="function"&&typeof t.remove=="function"&&typeof t.copy=="function"&&typeof t.move=="function"&&typeof t.touch=="function"}var $E={kernel:"1.0.0+itsrealfortune+1-amd64",os:"Fortune GNU/Linux x64",arch:"x86_64"},Ki=ir("VirtualShell");function FE(){let n=process.env.SSH_MIMIC_AUTO_SUDO_NEW_USERS;return n?!["0","false","no","off"].includes(n.toLowerCase()):!0}var yr=class extends Jh.EventEmitter{vfs;users;packageManager;hostname;properties;startTime;_idle=null;initialized;constructor(t,e,r){super(),Ki.mark("constructor"),this.hostname=t,this.properties=e||$E,this.startTime=Date.now(),Zh(r)?this.vfs=r:ME(r)?this.vfs=r.vfsInstance:this.vfs=new ro(r??{}),this.users=new oo(this.vfs,FE()),this.packageManager=new so(this.vfs,this.users);let s=this.vfs,i=this.users,o=this.packageManager,a=this.properties,c=this.hostname,l=this.startTime;this.initialized=(async()=>{await s.restoreMirror(),await i.initialize(),Th(s,i,c,a,l),o.load(),this.emit("initialized")})()}async ensureInitialized(){Ki.mark("ensureInitialized"),await this.initialized}addCommand(t,e,r){let s=t.trim().toLowerCase();if(s.length===0||/\s/.test(s))throw new Error("Command name must be non-empty and contain no spaces");dc(hc(s,e,r))}executeCommand(t,e,r){Ki.mark("executeCommand"),this._idle?.ping(),wt(t,e,this.hostname,"shell",r,this),this.emit("command",{command:t,user:e,cwd:r})}startInteractiveSession(t,e,r,s,i){Ki.mark("startInteractiveSession"),this._idle?.ping(),this.emit("session:start",{user:e,sessionId:r,remoteAddress:s}),Xh(this.properties,t,e,this.hostname,r,s,i,this),this.refreshProcSessions()}refreshProcFs(){io(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}mount(t,e,r={}){this.vfs.mount(t,e,r)}unmount(t){this.vfs.unmount(t)}getMounts(){return this.vfs.getMounts()}refreshProcSessions(){io(this.vfs,this.properties,this.hostname,this.startTime,this.users.listActiveSessions())}syncPasswd(){Cc(this.vfs,this.users)}getVfs(){return this?.vfs??null}getUsers(){return this?.users??null}getHostname(){return this?.hostname}writeFileAsUser(t,e,r){Ki.mark("writeFileAsUser"),this.users.assertWriteWithinQuota(t,e,r),this.vfs.writeFile(e,r)}enableIdleManagement(t){this._idle||(this._idle=new ao(this.vfs,t),this._idle.on("freeze",()=>this.emit("shell:freeze")),this._idle.on("thaw",()=>this.emit("shell:thaw")),this._idle.start())}async disableIdleManagement(){this._idle&&(await this._idle.stop(),this._idle=null)}get idleState(){return this._idle?.state??"active"}get idleMs(){return this._idle?.idleMs??0}pingIdle(){this._idle?.ping()}};function ep(n){return n.replace(/\r\n/g,`
1294
1294
  `).replace(/\r/g,`
1295
1295
  `).replace(/\n/g,`\r
1296
1296
  `)}function tp(n,t,e,r,s){Promise.resolve(wt(t,e,r,"exec",`/home/${e}`,s,void 0,Jr(e,r))).then(i=>{i.stdout&&n.write(`${ep(i.stdout)}\r
@@ -1298,4 +1298,3 @@ Sorry, try again.\r
1298
1298
  `),n.exit(i.exitCode??0),n.end()}).catch(i=>{console.error("Exec error:",i),n.stderr.write(`Error: ${String(i)}\r
1299
1299
  `),n.exit(1),n.end()})}var np=require("node:crypto"),sr=require("node:fs"),lo=require("node:path");function Bc(n=process.cwd()){let t=(0,lo.resolve)(n,".ssh-mimic","host_rsa");if((0,sr.existsSync)(t))return(0,sr.readFileSync)(t,"utf8");let e=(0,np.generateKeyPairSync)("rsa",{modulusLength:2048,privateKeyEncoding:{type:"pkcs1",format:"pem"},publicKeyEncoding:{type:"pkcs1",format:"pem"}}).privateKey;return(0,sr.mkdirSync)((0,lo.dirname)(t),{recursive:!0}),(0,sr.writeFileSync)(t,e,{mode:384}),e}var HE=zt(ic(),1);var Rc=!!process.env.DEV_MODE,Ew=Rc?console.log.bind(console):()=>{},yw=Rc?console.warn.bind(console):()=>{},_w=Rc?console.error.bind(console):()=>{};var Sw=ir("SftpMimic");var Pc=ir("SshMimic"),QE=!!process.env.DEV_MODE,rp=QE?console.log.bind(console):()=>{},fo=class extends ip.EventEmitter{port;server;shell;maxAuthAttempts;lockoutDurationMs;authAttempts=new Map;constructor({port:t,hostname:e="typescript-vm",shell:r=new yr(e),maxAuthAttempts:s=5,lockoutDurationMs:i=6e4}){super(),Pc.mark("constructor"),this.port=t,this.server=null,this.shell=r,this.maxAuthAttempts=s,this.lockoutDurationMs=i}isLockedOut(t){let e=this.authAttempts.get(t);return e?Date.now()<e.lockedUntil?!0:(e.lockedUntil>0&&this.authAttempts.delete(t),!1):!1}recordFailure(t){let e=this.authAttempts.get(t)??{attempts:0,lockedUntil:0};e.attempts+=1,e.attempts>=this.maxAuthAttempts&&(e.lockedUntil=Date.now()+this.lockoutDurationMs,this.emit("auth:lockout",{ip:t,until:new Date(e.lockedUntil)})),this.authAttempts.set(t,e)}recordSuccess(t){this.authAttempts.delete(t)}ensureHomeDir(t){let e=`/home/${t}`;this.shell.vfs.exists(e)||(this.shell.vfs.mkdir(e,493),this.shell.vfs.writeFile(`${e}/README.txt`,`Welcome to ${this.shell.hostname}
1300
1300
  `),this.shell.vfs.stopAutoFlush())}async start(){Pc.mark("start");let t=this.shell,e=Bc();return await t.ensureInitialized(),this.server=new sp.Server({hostKeys:[e],ident:`SSH-2.0-${t.hostname}`},r=>{let s="root",i="unknown",o=null;this.emit("client:connect"),r.on("authentication",a=>{let c=a.username||"root";if(i=a.ip??i,this.isLockedOut(i)){this.emit("auth:failure",{username:c,remoteAddress:i,reason:"lockout"}),a.reject();return}if(a.method==="password"){if(!t.users.hasPassword(c)){s=c,o=t.users.registerSession(s,i).id,this.recordSuccess(i),this.emit("auth:success",{username:s,remoteAddress:i}),this.ensureHomeDir(s),a.accept();return}if(!a.password||a.password===""||!t.users.verifyPassword(c,a.password)){this.recordFailure(i),this.emit("auth:failure",{username:c,remoteAddress:i}),a.reject();return}s=c,o=t.users.registerSession(s,i).id,this.recordSuccess(i),this.emit("auth:success",{username:s,remoteAddress:i}),this.ensureHomeDir(s),a.accept();return}if(a.method==="publickey"){let l=t.users.getAuthorizedKeys(c);if(l.length===0){a.reject();return}let f=a.key;if(!l.some(h=>h.algo===f.algo&&h.data.equals(f.data))){this.recordFailure(i),this.emit("auth:failure",{username:c,remoteAddress:i,method:"publickey"}),a.reject();return}a.signature&&(s=c,o=t.users.registerSession(s,i).id,this.recordSuccess(i),this.emit("auth:success",{username:s,remoteAddress:i,method:"publickey"}),this.ensureHomeDir(s)),a.accept();return}a.reject(["password","publickey"])}),r.on("close",()=>{t.users.unregisterSession(o),this.emit("client:disconnect",{user:s}),o=null}),r.on("ready",()=>{r.on("session",a=>{let c=a(),l={cols:80,rows:24};c.on("pty",(f,u,h)=>{l.cols=h?.cols??l.cols,l.rows=h?.rows??l.rows,f()}),c.on("window-change",(f,u,h)=>{l.cols=h?.cols??l.cols,l.rows=h?.rows??l.rows}),c.on("shell",f=>{let u=f();t?.startInteractiveSession(u,s,o,i,l)}),c.on("exec",(f,u,h)=>{let p=f();p&&tp(p,h.command.trim(),s,t.hostname,t)})})})}),new Promise((r,s)=>{this.server?.once("error",i=>s(i)),this.server?.listen(this.port,"0.0.0.0",()=>{rp(`SSH Mimic listening on port ${this.port}`),this.emit("start",{port:this.port}),r(this.port)})})}stop(){Pc.mark("stop"),this.shell.vfs.stopAutoFlush(),this.server&&this.server.close(()=>{rp("SSH Mimic stopped"),this.emit("stop")})}clearLockout(t){this.authAttempts.delete(t)}};var op=process.env.SSH_MIMIC_HOSTNAME??"typescript-vm",ap=new yr(op,void 0,{mode:"fs",snapshotPath:".vfs"});ap.addCommand("demo",[],()=>({stdout:"This is a demo command. It does nothing useful.",exitCode:0}));new fo({port:2222,hostname:op,shell:ap}).start().catch(n=>{console.error("Failed to start SSH Mimic:",n),process.exit(1)});process.on("uncaughtException",n=>{console.log("Oh my god, something terrible happened: ",n)});process.on("unhandledRejection",(n,t)=>{console.log(" Oh Lord! We forgot to handle a promise rejection here: ",t),console.log(" The error was: ",n)});
1301
- //# sourceMappingURL=standalone-wo-sftp.js.map