Use the desktop's own monospace font in the terminal

Read org.gnome.desktop.interface monospace-font-name at startup rather than
hardcoding a family, so the terminal matches GNOME Terminal exactly and keeps
matching after the system font changes.

Pango reports points and CSS wants pixels, so 13 becomes 17.33px — rendering
it as 13px made the terminal a third too small, which reads as the wrong font
rather than the wrong size. The size is the trailing number, since families
may contain digits. Families are always quoted, because an unquoted
"Noto Sans Mono" is a three-family stack to CSS.

Also fixes tests/dial.test.ts, which hardcoded the test server's fingerprint
and so went red after every /tmp cleanup. It now asks ssh-keygen, which is a
stronger assertion anyway: the expected value comes from the reference
implementation rather than from this project's own fingerprint code.
This commit is contained in:
ylhan
2026-09-21 23:02:20 +08:00
parent 2697bff24d
commit e1193ed032
11 changed files with 369 additions and 16 deletions
+57 -10
View File
@@ -1,3 +1,4 @@
import { execFileSync } from 'node:child_process'
import { existsSync } from 'node:fs'
import { userInfo } from 'node:os'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
@@ -28,9 +29,55 @@ import { createTempDb, type TempDb } from './helpers'
*/
const TEST_PORT = 2222
const TEST_USER_KEY = '/tmp/testsshd/user_key'
const EXPECTED_FINGERPRINT = 'SHA256:ASmbFHszdZLp5YkSiJnqmGfAhpZKOZwQJnk3rLUo4Xo'
const TEST_HOST_KEY = '/tmp/testsshd/host_key.pub'
const prerequisitesPresent = existsSync(TEST_USER_KEY)
// ssh-keygen is what tells us the expected value, so it is part of the
// prerequisite too.
const prerequisitesPresent =
existsSync(TEST_USER_KEY) &&
existsSync(TEST_HOST_KEY) &&
(() => {
try {
execFileSync('ssh-keygen', ['-lf', TEST_HOST_KEY], { stdio: 'ignore' })
return true
} catch {
return false
}
})()
/**
* Ask `ssh-keygen` what the server's fingerprint is, rather than writing it
* down here.
*
* A literal would be tied to whichever key happened to exist when it was
* pasted in, and the test key is regenerated whenever `/tmp` is cleared — so
* the suite would go red after every reboot for a reason that has nothing to
* do with the code. A check that cries wolf is a check people learn to ignore.
*
* It is also a stronger assertion: the expected value comes from the reference
* implementation, not from this project's own fingerprint code.
*/
function expectedFingerprint(): string | null {
try {
const output = execFileSync('ssh-keygen', ['-lf', TEST_HOST_KEY], { encoding: 'utf8' })
return /SHA256:[A-Za-z0-9+/]+=*/.exec(output)?.[0] ?? null
} catch {
return null
}
}
/**
* Read fresh at each call rather than captured once.
*
* A module-level constant would be fine here, but a function makes it obvious
* at every call site that this value comes from outside — which is the whole
* point of not hardcoding it.
*/
function EXPECTED_FINGERPRINT(): string {
const value = expectedFingerprint()
if (!value) throw new Error('could not read the test sshd host key fingerprint')
return value
}
let temp: TempDb
const openClients: Client[] = []
@@ -89,7 +136,7 @@ describe.runIf(prerequisitesPresent)('dial — trust on first use', () => {
if (result.failure.reason !== 'unknown-host-key') return
// The fingerprint shown must be the real one, or the user cannot check it.
expect(result.failure.fingerprint).toBe(EXPECTED_FINGERPRINT)
expect(result.failure.fingerprint).toBe(EXPECTED_FINGERPRINT())
expect(result.failure.keyType).toBe('ssh-ed25519')
})
@@ -102,21 +149,21 @@ describe.runIf(prerequisitesPresent)('dial — trust on first use', () => {
})
it('connects when the presented fingerprint is trusted', async () => {
const result = await attempt({}, EXPECTED_FINGERPRINT)
const result = await attempt({}, EXPECTED_FINGERPRINT())
expect(result.ok).toBe(true)
if (result.ok) expect(result.fingerprint).toBe(EXPECTED_FINGERPRINT)
if (result.ok) expect(result.fingerprint).toBe(EXPECTED_FINGERPRINT())
})
it('remembers the key once trusted', async () => {
await attempt({}, EXPECTED_FINGERPRINT)
await attempt({}, EXPECTED_FINGERPRINT())
const known = findKnownHost(temp.db, '127.0.0.1', TEST_PORT, 'ssh-ed25519')
expect(known?.fingerprint).toBe(EXPECTED_FINGERPRINT)
expect(known?.fingerprint).toBe(EXPECTED_FINGERPRINT())
})
it('connects without a prompt once the key is recorded', async () => {
await attempt({}, EXPECTED_FINGERPRINT)
await attempt({}, EXPECTED_FINGERPRINT())
const second = await attempt()
@@ -143,7 +190,7 @@ describe.runIf(prerequisitesPresent)('dial — trust on first use', () => {
expect(result.failure.reason).toBe('host-key-mismatch')
if (result.failure.reason !== 'host-key-mismatch') return
expect(result.failure.expected).toBe('SHA256:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB')
expect(result.failure.actual).toBe(EXPECTED_FINGERPRINT)
expect(result.failure.actual).toBe(EXPECTED_FINGERPRINT())
})
it('reports a readable failure for an unreadable key file', async () => {
@@ -174,7 +221,7 @@ describe.runIf(prerequisitesPresent)('dial — trust on first use', () => {
// never reaches authentication.
const result = await attempt(
{ authType: 'password' },
EXPECTED_FINGERPRINT,
EXPECTED_FINGERPRINT(),
'definitely-not-the-password',
)