Connection tree with interleaved folders and hosts, tabbed terminals grouped by host, a pinned local shell, TOFU host key verification, and credentials held by the OS keyring. Terminal bytes travel on a per-session MessagePort with credit-based flow control, so one session running `cat` on a large file cannot stall the others. Transports reconnect on their own with jittered backoff, keeping the scrollback and the tab while replacing only the connection beneath. 156 tests, including integration tests against a real sshd and a migration exercised against a database built in the old shape.
33 lines
1.1 KiB
TypeScript
33 lines
1.1 KiB
TypeScript
import { createHash } from 'node:crypto'
|
|
|
|
/**
|
|
* OpenSSH-format SHA256 fingerprint: `SHA256:` followed by the base64 digest
|
|
* with padding stripped.
|
|
*
|
|
* Computed here rather than using ssh2's `hostHash` option, because that yields
|
|
* hex while `ssh-keygen -lf`, `known_hosts` and every piece of documentation a
|
|
* user might compare against use base64. A fingerprint the user cannot check
|
|
* against anything is not a fingerprint worth showing.
|
|
*/
|
|
export function fingerprintOf(keyBlob: Buffer): string {
|
|
const digest = createHash('sha256').update(keyBlob).digest('base64')
|
|
return `SHA256:${digest.replace(/=+$/, '')}`
|
|
}
|
|
|
|
/**
|
|
* The key's algorithm name, read from the SSH wire format.
|
|
*
|
|
* A public key blob is a length-prefixed string holding the algorithm name
|
|
* ("ssh-ed25519", "rsa-sha2-512", …), followed by the key material.
|
|
*/
|
|
export function keyTypeOf(keyBlob: Buffer): string {
|
|
if (keyBlob.length < 4) return 'unknown'
|
|
|
|
const nameLength = keyBlob.readUInt32BE(0)
|
|
if (nameLength <= 0 || nameLength > 64 || 4 + nameLength > keyBlob.length) {
|
|
return 'unknown'
|
|
}
|
|
|
|
return keyBlob.subarray(4, 4 + nameLength).toString('ascii')
|
|
}
|