Files
ylhan 430d78b9f0 NexusTerm: an SSH session manager for Linux
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.
2026-09-17 03:12:24 +08:00

90 lines
2.6 KiB
TypeScript

import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { openDatabase, closeDatabase, type Db } from '../src/main/db/database'
import type { Keyring } from '../src/main/security/keyring'
import type { SafeStorageStatus } from '../src/shared/ipc-schemas'
export interface TempDb {
db: Db
path: string
cleanup: () => void
}
/**
* A real file-backed database in a temp directory, not `:memory:`.
*
* Tests that assert a secret never reaches disk need an actual file to inspect,
* and WAL mode does not apply to in-memory databases — so the in-memory
* shortcut would quietly skip the behaviour most worth checking.
*/
export function createTempDb(): TempDb {
const dir = mkdtempSync(join(tmpdir(), 'nexusterm-test-'))
const path = join(dir, 'test.db')
const db = openDatabase(path)
return {
db,
path,
cleanup: () => {
closeDatabase(db)
rmSync(dir, { recursive: true, force: true })
},
}
}
/**
* A stand-in keyring.
*
* `wrap` is a reversible transform rather than real encryption, and that is
* deliberate: it is not trying to be secure, it is trying to be *observable*.
* The point is that the bytes handed to SQLite are recognisably different from
* the plaintext, so tests can prove the vault actually called through to the
* keyring instead of passing a secret straight to storage.
*/
export function fakeKeyring(
status: SafeStorageStatus = {
available: true,
backend: 'test-keyring',
secure: true,
reason: 'ok',
},
): Keyring {
const PREFIX = 'WRAPPED:'
return {
status: () => status,
wrap: (plaintext) => Buffer.from(PREFIX + Buffer.from(plaintext, 'utf8').toString('hex')),
unwrap: (sealed) => {
const text = sealed.toString('utf8')
if (!text.startsWith(PREFIX)) {
throw new Error('blob was not wrapped by this keyring')
}
return Buffer.from(text.slice(PREFIX.length), 'hex').toString('utf8')
},
}
}
/**
* A keyring that reports the Linux `basic_text` condition: the API claims
* encryption is available, but the backend uses a hardcoded key. Both `wrap`
* and `unwrap` throw, so any code path that fails to check `secure` first will
* fail loudly rather than storing something weak.
*/
export function insecureKeyring(): Keyring {
const refuse = (): never => {
throw new Error('insecure keyring must not be used')
}
return {
status: () => ({
available: true,
backend: 'basic_text',
secure: false,
reason: 'basic-text',
}),
wrap: refuse,
unwrap: refuse,
}
}