mirror of
https://github.com/anomalyco/opentui.git
synced 2026-09-19 01:26:03 +08:00
9ef4691410
## Summary Adds `@opentui/ssh`, renderer-agnostic ssh server package for serving apps to remote terminals. Highlights: - `createServer(config).use(...).serve(handler)` builder api with typed middleware context - open, public key, password, and keyboard-interactive auth, including verified public-key possession and `authorized_keys` allowlists - host key loading/generation, startup banner, logging middleware, session resize/close hooks, raw writes, idle/max timeouts, and graceful shutdown --------- Co-authored-by: opencode-agent <opencode-agent@opencode.ai> Co-authored-by: Sebastian Herrlinger <hasta84@gmail.com>
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
/**
|
|
* Example: restrict access with an authorized_keys allowlist.
|
|
*
|
|
* ssh-keygen -y -f ~/.ssh/id_ed25519 > ./authorized_keys
|
|
* bun run packages/ssh/examples/authorized-keys.ts
|
|
*
|
|
* Then connect with the matching private key:
|
|
*
|
|
* ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
* -i ~/.ssh/id_ed25519 guest@localhost
|
|
*
|
|
* Set AUTHORIZED_KEYS=/path/to/authorized_keys to use a different file.
|
|
*/
|
|
import { BoxRenderable, TextRenderable } from "@opentui/core"
|
|
import { createServer } from "../src/index.js"
|
|
|
|
const PORT = Number(process.env.PORT ?? 2222)
|
|
const AUTHORIZED_KEYS = process.env.AUTHORIZED_KEYS ?? "./authorized_keys"
|
|
|
|
const server = createServer({
|
|
hostKey: { path: "./host_key" },
|
|
auth: {
|
|
publicKey: { authorizedKeys: AUTHORIZED_KEYS },
|
|
},
|
|
}).serve((session) => {
|
|
const { renderer, identity } = session
|
|
|
|
renderer.setBackgroundColor("#0f172a")
|
|
const box = new BoxRenderable(renderer, {
|
|
width: "100%",
|
|
height: "100%",
|
|
border: true,
|
|
borderStyle: "rounded",
|
|
borderColor: "#22c55e",
|
|
title: " @opentui/ssh · authorized_keys ",
|
|
titleAlignment: "center",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
})
|
|
|
|
box.add(new TextRenderable(renderer, { content: `Welcome, ${identity.username}!`, fg: "#e2e8f0" }))
|
|
box.add(new TextRenderable(renderer, { content: `key: ${identity.fingerprint}`, fg: "#86efac" }))
|
|
box.add(new TextRenderable(renderer, { content: `allowlist: ${AUTHORIZED_KEYS}`, fg: "#94a3b8" }))
|
|
box.add(new TextRenderable(renderer, { content: "Press q or Ctrl-C to quit.", fg: "#94a3b8" }))
|
|
renderer.root.add(box)
|
|
|
|
renderer.keyInput.on("keypress", (key) => {
|
|
if (key.name === "q" || (key.ctrl && key.name === "c")) session.end()
|
|
})
|
|
})
|
|
|
|
await server.listen(PORT)
|
|
|
|
process.on("SIGINT", async () => {
|
|
await server.close()
|
|
process.exit(0)
|
|
})
|