ccwebtty 1.0.1 → 1.0.2
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/dist/index.js +56 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -428,19 +428,73 @@ while($true) {
|
|
|
428
428
|
process.on("SIGTERM", shutdown);
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
+
// src/updater.ts
|
|
432
|
+
var import_https = __toESM(require("https"));
|
|
433
|
+
var import_child_process2 = require("child_process");
|
|
434
|
+
var PKG_NAME = "ccwebtty";
|
|
435
|
+
function fetchLatestVersion() {
|
|
436
|
+
return new Promise((resolve, reject) => {
|
|
437
|
+
import_https.default.get(`https://registry.npmjs.org/${PKG_NAME}/latest`, (res) => {
|
|
438
|
+
let data = "";
|
|
439
|
+
res.on("data", (chunk) => data += chunk);
|
|
440
|
+
res.on("end", () => {
|
|
441
|
+
try {
|
|
442
|
+
resolve(JSON.parse(data).version);
|
|
443
|
+
} catch {
|
|
444
|
+
reject(new Error("Failed to parse registry response"));
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}).on("error", reject);
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
async function checkUpdate() {
|
|
451
|
+
try {
|
|
452
|
+
const latest = await fetchLatestVersion();
|
|
453
|
+
if (latest !== "1.0.2") {
|
|
454
|
+
console.log(
|
|
455
|
+
`
|
|
456
|
+
New version available: ${"1.0.2"} -> \x1B[32m${latest}\x1B[0m`
|
|
457
|
+
);
|
|
458
|
+
console.log(` Run \x1B[36mccweb update\x1B[0m to update
|
|
459
|
+
`);
|
|
460
|
+
}
|
|
461
|
+
} catch {
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
async function selfUpdate() {
|
|
465
|
+
try {
|
|
466
|
+
const latest = await fetchLatestVersion();
|
|
467
|
+
if (latest === "1.0.2") {
|
|
468
|
+
console.log(`Already up to date (v${"1.0.2"})`);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
console.log(`Updating ${PKG_NAME}: ${"1.0.2"} -> ${latest} ...`);
|
|
472
|
+
(0, import_child_process2.execSync)(`npm install -g ${PKG_NAME}@latest`, { stdio: "inherit" });
|
|
473
|
+
console.log(`Successfully updated to v${latest}`);
|
|
474
|
+
} catch (err) {
|
|
475
|
+
console.error(`Update failed: ${err.message}`);
|
|
476
|
+
process.exit(1);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
431
480
|
// src/index.ts
|
|
432
481
|
var program = new import_commander.Command();
|
|
433
|
-
program.name("ccweb").description("A CLI tool that exposes an interactive web terminal in the browser").version("1.0.
|
|
482
|
+
program.name("ccweb").description("A CLI tool that exposes an interactive web terminal in the browser").version("1.0.2");
|
|
483
|
+
program.command("update").description("Update ccweb to the latest version").action(async () => {
|
|
484
|
+
await selfUpdate();
|
|
485
|
+
});
|
|
486
|
+
program.command("start", { isDefault: true }).description("Start the web terminal server").option("-p, --port <number>", "port to listen on", "8080").option("-H, --host <address>", "host to bind to", "0.0.0.0").option(
|
|
434
487
|
"-s, --shell <path>",
|
|
435
488
|
"shell to spawn",
|
|
436
489
|
process.env.SHELL || "/bin/bash"
|
|
437
|
-
).option("-u, --username <name>", "username for authentication", "cc").option("--password <password>", "password for authentication (random if not set)").option("--tunnel", "expose via Cloudflare Tunnel (no account required)").action((opts) => {
|
|
490
|
+
).option("-u, --username <name>", "username for authentication", "cc").option("--password <password>", "password for authentication (random if not set)").option("--tunnel", "expose via Cloudflare Tunnel (no account required)").action(async (opts) => {
|
|
438
491
|
const port = parseInt(opts.port, 10);
|
|
439
492
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
440
493
|
console.error(`Invalid port: ${opts.port}`);
|
|
441
494
|
process.exit(1);
|
|
442
495
|
}
|
|
443
496
|
const password = opts.password || import_crypto3.default.randomBytes(12).toString("base64url");
|
|
497
|
+
checkUpdate();
|
|
444
498
|
startServer({
|
|
445
499
|
port,
|
|
446
500
|
host: opts.host,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/session-manager.ts","../src/terminal.ts"],"sourcesContent":["import crypto from \"crypto\";\nimport { Command } from \"commander\";\nimport { startServer } from \"./server\";\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name(\"ccweb\")\n .description(\"A CLI tool that exposes an interactive web terminal in the browser\")\n .version(__VERSION__)\n .option(\"-p, --port <number>\", \"port to listen on\", \"8080\")\n .option(\"-H, --host <address>\", \"host to bind to\", \"0.0.0.0\")\n .option(\n \"-s, --shell <path>\",\n \"shell to spawn\",\n process.env.SHELL || \"/bin/bash\"\n )\n .option(\"-u, --username <name>\", \"username for authentication\", \"cc\")\n .option(\"--password <password>\", \"password for authentication (random if not set)\")\n .option(\"--tunnel\", \"expose via Cloudflare Tunnel (no account required)\")\n .action((opts) => {\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n console.error(`Invalid port: ${opts.port}`);\n process.exit(1);\n }\n\n const password = opts.password || crypto.randomBytes(12).toString(\"base64url\");\n\n startServer({\n port,\n host: opts.host,\n shell: opts.shell,\n username: opts.username,\n password,\n tunnel: !!opts.tunnel,\n });\n });\n\nprogram.parse();\n","import crypto from \"crypto\";\nimport { spawn } from \"child_process\";\nimport express from \"express\";\nimport http from \"http\";\nimport os from \"os\";\nimport path from \"path\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport { SessionManager } from \"./session-manager\";\n\nexport interface ServerOptions {\n port: number;\n host: string;\n shell: string;\n username: string;\n password: string;\n tunnel?: boolean;\n}\n\ninterface ClientMessage {\n type: \"input\" | \"resize\" | \"kill\" | \"create\";\n data?: string;\n cols?: number;\n rows?: number;\n sessionId?: string;\n}\n\n// Cookie-based auth helpers\n\nfunction generateSecret(): string {\n return crypto.randomBytes(32).toString(\"hex\");\n}\n\nfunction signToken(payload: string, secret: string): string {\n const hmac = crypto.createHmac(\"sha256\", secret);\n hmac.update(payload);\n return payload + \".\" + hmac.digest(\"hex\");\n}\n\nfunction verifyToken(token: string, secret: string): boolean {\n const dotIdx = token.lastIndexOf(\".\");\n if (dotIdx === -1) return false;\n const payload = token.substring(0, dotIdx);\n const sig = token.substring(dotIdx + 1);\n const hmac = crypto.createHmac(\"sha256\", secret);\n hmac.update(payload);\n const expected = hmac.digest(\"hex\");\n if (sig.length !== expected.length) return false;\n return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));\n}\n\nfunction parseCookies(header: string | undefined): Record<string, string> {\n const cookies: Record<string, string> = {};\n if (!header) return cookies;\n for (const part of header.split(\";\")) {\n const eq = part.indexOf(\"=\");\n if (eq === -1) continue;\n const key = part.substring(0, eq).trim();\n const val = part.substring(eq + 1).trim();\n cookies[key] = decodeURIComponent(val);\n }\n return cookies;\n}\n\nexport function startServer(options: ServerOptions): void {\n const { port, host, shell, username, password, tunnel: enableTunnel } = options;\n\n const sessionManager = new SessionManager();\n const authSecret = generateSecret();\n\n const app = express();\n app.set(\"trust proxy\", true);\n const server = http.createServer(app);\n\n // Track all connected WebSocket clients for tab-list broadcasting\n const allClients = new Set<WebSocket>();\n\n function broadcastTabs(): void {\n const tabs = sessionManager.listIds();\n const msg = JSON.stringify({ type: \"tabs\", tabs });\n for (const client of allClients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(msg);\n }\n }\n }\n\n function isAuthenticated(cookieHeader: string | undefined): boolean {\n const cookies = parseCookies(cookieHeader);\n const token = cookies[\"ccweb_token\"];\n if (!token) return false;\n return verifyToken(token, authSecret);\n }\n\n // Login endpoint\n app.use(express.urlencoded({ extended: false }));\n\n app.post(\"/login\", (req, res) => {\n const { username: u, password: p } = req.body as { username?: string; password?: string };\n if (!u || !p) {\n return res.status(400).send(\"Missing credentials\");\n }\n const uMatch = u.length === username.length && crypto.timingSafeEqual(Buffer.from(u), Buffer.from(username));\n const pMatch = p.length === password.length && crypto.timingSafeEqual(Buffer.from(p), Buffer.from(password));\n if (!uMatch || !pMatch) {\n return res.status(401).send(\"Invalid credentials\");\n }\n const token = signToken(\"auth\", authSecret);\n const secure = req.protocol === \"https\" || req.headers[\"x-forwarded-proto\"] === \"https\";\n const cookieFlags = `Path=/; HttpOnly; SameSite=Lax${secure ? \"; Secure\" : \"\"}`;\n res.setHeader(\"Set-Cookie\", `ccweb_token=${encodeURIComponent(token)}; ${cookieFlags}`);\n res.redirect(\"/\");\n });\n\n // Auth middleware - skip login route and static login page\n app.use((req, res, next) => {\n if (isAuthenticated(req.headers.cookie)) {\n return next();\n }\n // Serve login page for GET requests\n if (req.method === \"GET\") {\n return res.sendFile(path.join(__dirname, \"public\", \"login.html\"));\n }\n res.status(401).send(\"Unauthorized\");\n });\n\n app.use(express.static(path.join(__dirname, \"public\")));\n\n app.get(\"/\", (_req, res) => {\n res.sendFile(path.join(__dirname, \"public\", \"index.html\"));\n });\n\n const wss = new WebSocketServer({ noServer: true });\n\n // WebSocket ping/pong keepalive (Cloudflare Tunnel idle timeout is ~100s)\n const WS_PING_INTERVAL = 30_000;\n const pingInterval = setInterval(() => {\n for (const client of wss.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.ping();\n }\n }\n }, WS_PING_INTERVAL);\n wss.on(\"close\", () => clearInterval(pingInterval));\n\n server.on(\"upgrade\", (req, socket, head) => {\n if (!isAuthenticated(req.headers.cookie)) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n });\n\n wss.on(\"connection\", (ws: WebSocket, req) => {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n const sessionId = url.searchParams.get(\"sessionId\");\n const cols = parseInt(url.searchParams.get(\"cols\") || \"80\", 10);\n const rows = parseInt(url.searchParams.get(\"rows\") || \"24\", 10);\n\n allClients.add(ws);\n\n // If no sessionId, this is a control connection - send current tab list\n if (!sessionId) {\n // Auto-create a default session if none exist\n if (sessionManager.listIds().length === 0) {\n const session = sessionManager.create(shell, cols, rows);\n console.log(`[ccweb] Default session: ${session.id}`);\n }\n ws.send(JSON.stringify({ type: \"tabs\", tabs: sessionManager.listIds() }));\n\n ws.on(\"message\", (raw: Buffer) => {\n try {\n const msg: ClientMessage = JSON.parse(raw.toString());\n if (msg.type === \"create\") {\n const c = msg.cols || 80;\n const r = msg.rows || 24;\n const session = sessionManager.create(shell, c, r);\n console.log(`[ccweb] New session: ${session.id}`);\n broadcastTabs();\n } else if (msg.type === \"kill\" && msg.sessionId) {\n console.log(`[ccweb] Session killed: ${msg.sessionId}`);\n sessionManager.remove(msg.sessionId);\n broadcastTabs();\n }\n } catch {\n // Ignore malformed messages\n }\n });\n\n ws.on(\"close\", () => {\n allClients.delete(ws);\n });\n ws.on(\"error\", () => {\n allClients.delete(ws);\n });\n return;\n }\n\n // Session-specific connection\n const session = sessionManager.get(sessionId);\n if (!session) {\n ws.send(JSON.stringify({ type: \"error\", data: \"Session not found\" }));\n ws.close();\n allClients.delete(ws);\n return;\n }\n\n console.log(`[ccweb] Client attached to session: ${sessionId}`);\n\n // Replay buffered output so new clients see existing content\n for (const chunk of session.buffer) {\n ws.send(JSON.stringify({ type: \"output\", data: chunk }));\n }\n\n // Subscribe to live output\n const onOutput = (data: string) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"output\", data }));\n }\n };\n session.clients.add(onOutput);\n\n const onExit = () => {\n console.log(`[ccweb] Session ended: ${sessionId}`);\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"exit\" }));\n ws.close();\n }\n sessionManager.remove(sessionId);\n broadcastTabs();\n };\n session.onExit.add(onExit);\n\n // Resize to match this client\n session.terminal.resize(cols, rows);\n\n ws.on(\"message\", (raw: Buffer) => {\n try {\n const msg: ClientMessage = JSON.parse(raw.toString());\n switch (msg.type) {\n case \"input\":\n if (msg.data) {\n session.terminal.write(msg.data);\n }\n break;\n case \"resize\":\n if (msg.cols && msg.rows) {\n session.terminal.resize(msg.cols, msg.rows);\n }\n break;\n }\n } catch {\n // Ignore malformed messages\n }\n });\n\n ws.on(\"close\", () => {\n allClients.delete(ws);\n session.clients.delete(onOutput);\n session.onExit.delete(onExit);\n });\n\n ws.on(\"error\", () => {\n allClients.delete(ws);\n session.clients.delete(onOutput);\n session.onExit.delete(onExit);\n });\n });\n\n server.listen(port, host, () => {\n const addr = host === \"0.0.0.0\" ? \"localhost\" : host;\n console.log(`[ccweb] Terminal server running at http://${addr}:${port}`);\n console.log(`[ccweb] Shell: ${shell}`);\n console.log(`[ccweb] Username: ${username}`);\n console.log(`[ccweb] Password: ${password}`);\n console.log(`[ccweb] Press Ctrl+C to stop`);\n\n // Start Cloudflare Tunnel if requested\n if (enableTunnel) {\n import(\"cloudflared\").then(({ Tunnel }) => {\n const t = new Tunnel([\"tunnel\", \"--url\", `http://localhost:${port}`, \"--no-autoupdate\"]);\n t.on(\"url\", (url: string) => {\n console.log(`[ccweb] Tunnel: ${url}`);\n });\n t.on(\"error\", (err: Error) => {\n console.error(`[ccweb] Tunnel error: ${err.message}`);\n });\n const stopTunnel = () => t.stop();\n process.on(\"SIGINT\", stopTunnel);\n process.on(\"SIGTERM\", stopTunnel);\n }).catch((err) => {\n console.error(\"[ccweb] Failed to start tunnel:\", err.message);\n });\n }\n\n // Prevent system sleep while ccweb is running\n const platform = os.platform();\n if (platform === \"darwin\") {\n const caffeinate = spawn(\"caffeinate\", [\"-s\", \"-w\", process.pid.toString()], {\n stdio: \"ignore\",\n });\n caffeinate.unref();\n console.log(\"[ccweb] Sleep prevention enabled (caffeinate)\");\n } else if (platform === \"win32\") {\n const script = `\nAdd-Type -TypeDefinition @\"\nusing System.Runtime.InteropServices;\npublic class Power {\n [DllImport(\"kernel32.dll\")]\n public static extern uint SetThreadExecutionState(uint esFlags);\n}\n\"@\nwhile($true) {\n [Power]::SetThreadExecutionState(0x80000001)\n Start-Sleep -Seconds 30\n}`;\n const ps = spawn(\"powershell\", [\"-NoProfile\", \"-Command\", script], {\n stdio: \"ignore\",\n });\n ps.unref();\n console.log(\"[ccweb] Sleep prevention enabled (SetThreadExecutionState)\");\n }\n });\n\n const shutdown = () => {\n console.log(\"\\n[ccweb] Shutting down...\");\n wss.clients.forEach((client) => client.close());\n sessionManager.destroyAll();\n server.close(() => process.exit(0));\n setTimeout(() => process.exit(1), 3000);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n","import crypto from \"crypto\";\nimport { Terminal } from \"./terminal\";\n\nexport interface Session {\n id: string;\n terminal: Terminal;\n buffer: string[];\n clients: Set<(data: string) => void>;\n onExit: Set<() => void>;\n alive: boolean;\n}\n\nconst MAX_BUFFER = 5000;\n\nexport class SessionManager {\n private sessions = new Map<string, Session>();\n private order: string[] = [];\n\n create(shell: string, cols: number, rows: number): Session {\n const id = crypto.randomUUID();\n const terminal = new Terminal({ shell, cols, rows });\n\n const session: Session = {\n id,\n terminal,\n buffer: [],\n clients: new Set(),\n onExit: new Set(),\n alive: true,\n };\n\n terminal.onData((data) => {\n if (session.buffer.length >= MAX_BUFFER) {\n session.buffer.shift();\n }\n session.buffer.push(data);\n for (const cb of session.clients) {\n cb(data);\n }\n });\n\n terminal.onExit(() => {\n session.alive = false;\n for (const cb of session.onExit) {\n cb();\n }\n });\n\n this.sessions.set(id, session);\n this.order.push(id);\n return session;\n }\n\n get(id: string): Session | undefined {\n const session = this.sessions.get(id);\n if (session && !session.alive) {\n this.sessions.delete(id);\n this.order = this.order.filter((x) => x !== id);\n return undefined;\n }\n return session;\n }\n\n listIds(): string[] {\n this.order = this.order.filter((id) => {\n const s = this.sessions.get(id);\n if (s && s.alive) return true;\n this.sessions.delete(id);\n return false;\n });\n return [...this.order];\n }\n\n remove(id: string): void {\n const session = this.sessions.get(id);\n if (session) {\n session.terminal.kill();\n this.sessions.delete(id);\n }\n this.order = this.order.filter((x) => x !== id);\n }\n\n destroyAll(): void {\n for (const session of this.sessions.values()) {\n session.terminal.kill();\n }\n this.sessions.clear();\n this.order = [];\n }\n}\n","import * as pty from \"node-pty\";\nimport os from \"os\";\n\nexport interface TerminalOptions {\n shell: string;\n cols?: number;\n rows?: number;\n cwd?: string;\n}\n\nexport class Terminal {\n private process: pty.IPty;\n private disposed = false;\n\n constructor(options: TerminalOptions) {\n const { shell, cols = 80, rows = 24, cwd } = options;\n const env = Object.assign({}, process.env, {\n TERM: \"xterm-256color\",\n COLORTERM: \"truecolor\",\n FORCE_COLOR: \"3\",\n TERM_PROGRAM: \"xterm-256color\",\n });\n delete (env as Record<string, string | undefined>).NO_COLOR;\n\n this.process = pty.spawn(shell, [], {\n name: \"xterm-256color\",\n cols,\n rows,\n cwd: cwd || os.homedir(),\n env: env as Record<string, string>,\n });\n }\n\n get pid(): number {\n return this.process.pid;\n }\n\n onData(callback: (data: string) => void): void {\n this.process.onData(callback);\n }\n\n onExit(callback: (exitCode: number, signal?: number) => void): void {\n this.process.onExit(({ exitCode, signal }) => {\n callback(exitCode, signal);\n });\n }\n\n write(data: string): void {\n if (!this.disposed) {\n this.process.write(data);\n }\n }\n\n resize(cols: number, rows: number): void {\n if (!this.disposed) {\n try {\n this.process.resize(cols, rows);\n } catch {\n // PTY may already be closed\n }\n }\n }\n\n kill(): void {\n if (!this.disposed) {\n this.disposed = true;\n try {\n this.process.kill();\n } catch {\n // Already dead\n }\n }\n }\n}\n"],"mappings":"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","names":["import_crypto","import_crypto","import_os","os","crypto","crypto","express","http","path","session","os","crypto"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/session-manager.ts","../src/terminal.ts","../src/updater.ts"],"sourcesContent":["import crypto from \"crypto\";\nimport { Command } from \"commander\";\nimport { startServer } from \"./server\";\nimport { checkUpdate, selfUpdate } from \"./updater\";\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name(\"ccweb\")\n .description(\"A CLI tool that exposes an interactive web terminal in the browser\")\n .version(__VERSION__);\n\nprogram\n .command(\"update\")\n .description(\"Update ccweb to the latest version\")\n .action(async () => {\n await selfUpdate();\n });\n\nprogram\n .command(\"start\", { isDefault: true })\n .description(\"Start the web terminal server\")\n .option(\"-p, --port <number>\", \"port to listen on\", \"8080\")\n .option(\"-H, --host <address>\", \"host to bind to\", \"0.0.0.0\")\n .option(\n \"-s, --shell <path>\",\n \"shell to spawn\",\n process.env.SHELL || \"/bin/bash\"\n )\n .option(\"-u, --username <name>\", \"username for authentication\", \"cc\")\n .option(\"--password <password>\", \"password for authentication (random if not set)\")\n .option(\"--tunnel\", \"expose via Cloudflare Tunnel (no account required)\")\n .action(async (opts) => {\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n console.error(`Invalid port: ${opts.port}`);\n process.exit(1);\n }\n\n const password = opts.password || crypto.randomBytes(12).toString(\"base64url\");\n\n // Check for updates in background (non-blocking)\n checkUpdate();\n\n startServer({\n port,\n host: opts.host,\n shell: opts.shell,\n username: opts.username,\n password,\n tunnel: !!opts.tunnel,\n });\n });\n\nprogram.parse();\n","import crypto from \"crypto\";\nimport { spawn } from \"child_process\";\nimport express from \"express\";\nimport http from \"http\";\nimport os from \"os\";\nimport path from \"path\";\nimport { WebSocketServer, WebSocket } from \"ws\";\nimport { SessionManager } from \"./session-manager\";\n\nexport interface ServerOptions {\n port: number;\n host: string;\n shell: string;\n username: string;\n password: string;\n tunnel?: boolean;\n}\n\ninterface ClientMessage {\n type: \"input\" | \"resize\" | \"kill\" | \"create\";\n data?: string;\n cols?: number;\n rows?: number;\n sessionId?: string;\n}\n\n// Cookie-based auth helpers\n\nfunction generateSecret(): string {\n return crypto.randomBytes(32).toString(\"hex\");\n}\n\nfunction signToken(payload: string, secret: string): string {\n const hmac = crypto.createHmac(\"sha256\", secret);\n hmac.update(payload);\n return payload + \".\" + hmac.digest(\"hex\");\n}\n\nfunction verifyToken(token: string, secret: string): boolean {\n const dotIdx = token.lastIndexOf(\".\");\n if (dotIdx === -1) return false;\n const payload = token.substring(0, dotIdx);\n const sig = token.substring(dotIdx + 1);\n const hmac = crypto.createHmac(\"sha256\", secret);\n hmac.update(payload);\n const expected = hmac.digest(\"hex\");\n if (sig.length !== expected.length) return false;\n return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));\n}\n\nfunction parseCookies(header: string | undefined): Record<string, string> {\n const cookies: Record<string, string> = {};\n if (!header) return cookies;\n for (const part of header.split(\";\")) {\n const eq = part.indexOf(\"=\");\n if (eq === -1) continue;\n const key = part.substring(0, eq).trim();\n const val = part.substring(eq + 1).trim();\n cookies[key] = decodeURIComponent(val);\n }\n return cookies;\n}\n\nexport function startServer(options: ServerOptions): void {\n const { port, host, shell, username, password, tunnel: enableTunnel } = options;\n\n const sessionManager = new SessionManager();\n const authSecret = generateSecret();\n\n const app = express();\n app.set(\"trust proxy\", true);\n const server = http.createServer(app);\n\n // Track all connected WebSocket clients for tab-list broadcasting\n const allClients = new Set<WebSocket>();\n\n function broadcastTabs(): void {\n const tabs = sessionManager.listIds();\n const msg = JSON.stringify({ type: \"tabs\", tabs });\n for (const client of allClients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(msg);\n }\n }\n }\n\n function isAuthenticated(cookieHeader: string | undefined): boolean {\n const cookies = parseCookies(cookieHeader);\n const token = cookies[\"ccweb_token\"];\n if (!token) return false;\n return verifyToken(token, authSecret);\n }\n\n // Login endpoint\n app.use(express.urlencoded({ extended: false }));\n\n app.post(\"/login\", (req, res) => {\n const { username: u, password: p } = req.body as { username?: string; password?: string };\n if (!u || !p) {\n return res.status(400).send(\"Missing credentials\");\n }\n const uMatch = u.length === username.length && crypto.timingSafeEqual(Buffer.from(u), Buffer.from(username));\n const pMatch = p.length === password.length && crypto.timingSafeEqual(Buffer.from(p), Buffer.from(password));\n if (!uMatch || !pMatch) {\n return res.status(401).send(\"Invalid credentials\");\n }\n const token = signToken(\"auth\", authSecret);\n const secure = req.protocol === \"https\" || req.headers[\"x-forwarded-proto\"] === \"https\";\n const cookieFlags = `Path=/; HttpOnly; SameSite=Lax${secure ? \"; Secure\" : \"\"}`;\n res.setHeader(\"Set-Cookie\", `ccweb_token=${encodeURIComponent(token)}; ${cookieFlags}`);\n res.redirect(\"/\");\n });\n\n // Auth middleware - skip login route and static login page\n app.use((req, res, next) => {\n if (isAuthenticated(req.headers.cookie)) {\n return next();\n }\n // Serve login page for GET requests\n if (req.method === \"GET\") {\n return res.sendFile(path.join(__dirname, \"public\", \"login.html\"));\n }\n res.status(401).send(\"Unauthorized\");\n });\n\n app.use(express.static(path.join(__dirname, \"public\")));\n\n app.get(\"/\", (_req, res) => {\n res.sendFile(path.join(__dirname, \"public\", \"index.html\"));\n });\n\n const wss = new WebSocketServer({ noServer: true });\n\n // WebSocket ping/pong keepalive (Cloudflare Tunnel idle timeout is ~100s)\n const WS_PING_INTERVAL = 30_000;\n const pingInterval = setInterval(() => {\n for (const client of wss.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.ping();\n }\n }\n }, WS_PING_INTERVAL);\n wss.on(\"close\", () => clearInterval(pingInterval));\n\n server.on(\"upgrade\", (req, socket, head) => {\n if (!isAuthenticated(req.headers.cookie)) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n });\n\n wss.on(\"connection\", (ws: WebSocket, req) => {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n const sessionId = url.searchParams.get(\"sessionId\");\n const cols = parseInt(url.searchParams.get(\"cols\") || \"80\", 10);\n const rows = parseInt(url.searchParams.get(\"rows\") || \"24\", 10);\n\n allClients.add(ws);\n\n // If no sessionId, this is a control connection - send current tab list\n if (!sessionId) {\n // Auto-create a default session if none exist\n if (sessionManager.listIds().length === 0) {\n const session = sessionManager.create(shell, cols, rows);\n console.log(`[ccweb] Default session: ${session.id}`);\n }\n ws.send(JSON.stringify({ type: \"tabs\", tabs: sessionManager.listIds() }));\n\n ws.on(\"message\", (raw: Buffer) => {\n try {\n const msg: ClientMessage = JSON.parse(raw.toString());\n if (msg.type === \"create\") {\n const c = msg.cols || 80;\n const r = msg.rows || 24;\n const session = sessionManager.create(shell, c, r);\n console.log(`[ccweb] New session: ${session.id}`);\n broadcastTabs();\n } else if (msg.type === \"kill\" && msg.sessionId) {\n console.log(`[ccweb] Session killed: ${msg.sessionId}`);\n sessionManager.remove(msg.sessionId);\n broadcastTabs();\n }\n } catch {\n // Ignore malformed messages\n }\n });\n\n ws.on(\"close\", () => {\n allClients.delete(ws);\n });\n ws.on(\"error\", () => {\n allClients.delete(ws);\n });\n return;\n }\n\n // Session-specific connection\n const session = sessionManager.get(sessionId);\n if (!session) {\n ws.send(JSON.stringify({ type: \"error\", data: \"Session not found\" }));\n ws.close();\n allClients.delete(ws);\n return;\n }\n\n console.log(`[ccweb] Client attached to session: ${sessionId}`);\n\n // Replay buffered output so new clients see existing content\n for (const chunk of session.buffer) {\n ws.send(JSON.stringify({ type: \"output\", data: chunk }));\n }\n\n // Subscribe to live output\n const onOutput = (data: string) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"output\", data }));\n }\n };\n session.clients.add(onOutput);\n\n const onExit = () => {\n console.log(`[ccweb] Session ended: ${sessionId}`);\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"exit\" }));\n ws.close();\n }\n sessionManager.remove(sessionId);\n broadcastTabs();\n };\n session.onExit.add(onExit);\n\n // Resize to match this client\n session.terminal.resize(cols, rows);\n\n ws.on(\"message\", (raw: Buffer) => {\n try {\n const msg: ClientMessage = JSON.parse(raw.toString());\n switch (msg.type) {\n case \"input\":\n if (msg.data) {\n session.terminal.write(msg.data);\n }\n break;\n case \"resize\":\n if (msg.cols && msg.rows) {\n session.terminal.resize(msg.cols, msg.rows);\n }\n break;\n }\n } catch {\n // Ignore malformed messages\n }\n });\n\n ws.on(\"close\", () => {\n allClients.delete(ws);\n session.clients.delete(onOutput);\n session.onExit.delete(onExit);\n });\n\n ws.on(\"error\", () => {\n allClients.delete(ws);\n session.clients.delete(onOutput);\n session.onExit.delete(onExit);\n });\n });\n\n server.listen(port, host, () => {\n const addr = host === \"0.0.0.0\" ? \"localhost\" : host;\n console.log(`[ccweb] Terminal server running at http://${addr}:${port}`);\n console.log(`[ccweb] Shell: ${shell}`);\n console.log(`[ccweb] Username: ${username}`);\n console.log(`[ccweb] Password: ${password}`);\n console.log(`[ccweb] Press Ctrl+C to stop`);\n\n // Start Cloudflare Tunnel if requested\n if (enableTunnel) {\n import(\"cloudflared\").then(({ Tunnel }) => {\n const t = new Tunnel([\"tunnel\", \"--url\", `http://localhost:${port}`, \"--no-autoupdate\"]);\n t.on(\"url\", (url: string) => {\n console.log(`[ccweb] Tunnel: ${url}`);\n });\n t.on(\"error\", (err: Error) => {\n console.error(`[ccweb] Tunnel error: ${err.message}`);\n });\n const stopTunnel = () => t.stop();\n process.on(\"SIGINT\", stopTunnel);\n process.on(\"SIGTERM\", stopTunnel);\n }).catch((err) => {\n console.error(\"[ccweb] Failed to start tunnel:\", err.message);\n });\n }\n\n // Prevent system sleep while ccweb is running\n const platform = os.platform();\n if (platform === \"darwin\") {\n const caffeinate = spawn(\"caffeinate\", [\"-s\", \"-w\", process.pid.toString()], {\n stdio: \"ignore\",\n });\n caffeinate.unref();\n console.log(\"[ccweb] Sleep prevention enabled (caffeinate)\");\n } else if (platform === \"win32\") {\n const script = `\nAdd-Type -TypeDefinition @\"\nusing System.Runtime.InteropServices;\npublic class Power {\n [DllImport(\"kernel32.dll\")]\n public static extern uint SetThreadExecutionState(uint esFlags);\n}\n\"@\nwhile($true) {\n [Power]::SetThreadExecutionState(0x80000001)\n Start-Sleep -Seconds 30\n}`;\n const ps = spawn(\"powershell\", [\"-NoProfile\", \"-Command\", script], {\n stdio: \"ignore\",\n });\n ps.unref();\n console.log(\"[ccweb] Sleep prevention enabled (SetThreadExecutionState)\");\n }\n });\n\n const shutdown = () => {\n console.log(\"\\n[ccweb] Shutting down...\");\n wss.clients.forEach((client) => client.close());\n sessionManager.destroyAll();\n server.close(() => process.exit(0));\n setTimeout(() => process.exit(1), 3000);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n}\n","import crypto from \"crypto\";\nimport { Terminal } from \"./terminal\";\n\nexport interface Session {\n id: string;\n terminal: Terminal;\n buffer: string[];\n clients: Set<(data: string) => void>;\n onExit: Set<() => void>;\n alive: boolean;\n}\n\nconst MAX_BUFFER = 5000;\n\nexport class SessionManager {\n private sessions = new Map<string, Session>();\n private order: string[] = [];\n\n create(shell: string, cols: number, rows: number): Session {\n const id = crypto.randomUUID();\n const terminal = new Terminal({ shell, cols, rows });\n\n const session: Session = {\n id,\n terminal,\n buffer: [],\n clients: new Set(),\n onExit: new Set(),\n alive: true,\n };\n\n terminal.onData((data) => {\n if (session.buffer.length >= MAX_BUFFER) {\n session.buffer.shift();\n }\n session.buffer.push(data);\n for (const cb of session.clients) {\n cb(data);\n }\n });\n\n terminal.onExit(() => {\n session.alive = false;\n for (const cb of session.onExit) {\n cb();\n }\n });\n\n this.sessions.set(id, session);\n this.order.push(id);\n return session;\n }\n\n get(id: string): Session | undefined {\n const session = this.sessions.get(id);\n if (session && !session.alive) {\n this.sessions.delete(id);\n this.order = this.order.filter((x) => x !== id);\n return undefined;\n }\n return session;\n }\n\n listIds(): string[] {\n this.order = this.order.filter((id) => {\n const s = this.sessions.get(id);\n if (s && s.alive) return true;\n this.sessions.delete(id);\n return false;\n });\n return [...this.order];\n }\n\n remove(id: string): void {\n const session = this.sessions.get(id);\n if (session) {\n session.terminal.kill();\n this.sessions.delete(id);\n }\n this.order = this.order.filter((x) => x !== id);\n }\n\n destroyAll(): void {\n for (const session of this.sessions.values()) {\n session.terminal.kill();\n }\n this.sessions.clear();\n this.order = [];\n }\n}\n","import * as pty from \"node-pty\";\nimport os from \"os\";\n\nexport interface TerminalOptions {\n shell: string;\n cols?: number;\n rows?: number;\n cwd?: string;\n}\n\nexport class Terminal {\n private process: pty.IPty;\n private disposed = false;\n\n constructor(options: TerminalOptions) {\n const { shell, cols = 80, rows = 24, cwd } = options;\n const env = Object.assign({}, process.env, {\n TERM: \"xterm-256color\",\n COLORTERM: \"truecolor\",\n FORCE_COLOR: \"3\",\n TERM_PROGRAM: \"xterm-256color\",\n });\n delete (env as Record<string, string | undefined>).NO_COLOR;\n\n this.process = pty.spawn(shell, [], {\n name: \"xterm-256color\",\n cols,\n rows,\n cwd: cwd || os.homedir(),\n env: env as Record<string, string>,\n });\n }\n\n get pid(): number {\n return this.process.pid;\n }\n\n onData(callback: (data: string) => void): void {\n this.process.onData(callback);\n }\n\n onExit(callback: (exitCode: number, signal?: number) => void): void {\n this.process.onExit(({ exitCode, signal }) => {\n callback(exitCode, signal);\n });\n }\n\n write(data: string): void {\n if (!this.disposed) {\n this.process.write(data);\n }\n }\n\n resize(cols: number, rows: number): void {\n if (!this.disposed) {\n try {\n this.process.resize(cols, rows);\n } catch {\n // PTY may already be closed\n }\n }\n }\n\n kill(): void {\n if (!this.disposed) {\n this.disposed = true;\n try {\n this.process.kill();\n } catch {\n // Already dead\n }\n }\n }\n}\n","import https from \"https\";\nimport { execSync } from \"child_process\";\n\ndeclare const __VERSION__: string;\nconst PKG_NAME = \"ccwebtty\";\n\nfunction fetchLatestVersion(): Promise<string> {\n return new Promise((resolve, reject) => {\n https\n .get(`https://registry.npmjs.org/${PKG_NAME}/latest`, (res) => {\n let data = \"\";\n res.on(\"data\", (chunk) => (data += chunk));\n res.on(\"end\", () => {\n try {\n resolve(JSON.parse(data).version);\n } catch {\n reject(new Error(\"Failed to parse registry response\"));\n }\n });\n })\n .on(\"error\", reject);\n });\n}\n\nexport async function checkUpdate(): Promise<void> {\n try {\n const latest = await fetchLatestVersion();\n if (latest !== __VERSION__) {\n console.log(\n `\\n New version available: ${__VERSION__} -> \\x1b[32m${latest}\\x1b[0m`\n );\n console.log(` Run \\x1b[36mccweb update\\x1b[0m to update\\n`);\n }\n } catch {\n // silently ignore network errors\n }\n}\n\nexport async function selfUpdate(): Promise<void> {\n try {\n const latest = await fetchLatestVersion();\n if (latest === __VERSION__) {\n console.log(`Already up to date (v${__VERSION__})`);\n return;\n }\n console.log(`Updating ${PKG_NAME}: ${__VERSION__} -> ${latest} ...`);\n execSync(`npm install -g ${PKG_NAME}@latest`, { stdio: \"inherit\" });\n console.log(`Successfully updated to v${latest}`);\n } catch (err: any) {\n console.error(`Update failed: ${err.message}`);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["import_crypto","import_crypto","import_os","os","crypto","crypto","express","http","path","session","os","import_child_process","https","crypto"]}
|