summaryrefslogtreecommitdiffhomepage
path: root/packages/ssh/src/hostkey.test.ts
blob: 1975777373b7d6169609fcee5f9ba3592f3dd852 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { describe, expect, it } from "vitest";
import { decideHostKey, type HostKeyFingerprint, isKnownHost } from "./hostkey.js";

const fp = (token: string, key = "AAA"): HostKeyFingerprint => ({
	knownHostToken: token,
	keyBase64: key,
	keyType: "ssh-ed25519",
});

describe("decideHostKey — present + match → accept, no append", () => {
	it("accepts when the pinned key matches exactly", () => {
		const known = "myhost ssh-ed25519 AAA\n";
		const d = decideHostKey(known, fp("myhost", "AAA"));
		expect(d.accept).toBe(true);
		expect(d.append).toBeUndefined();
		expect(d.reason).toContain("matches");
	});

	it("matches ignoring leading/trailing whitespace differences", () => {
		const known = "myhost   ssh-ed25519   AAA\n";
		const d = decideHostKey(known, fp("myhost", "AAA"));
		expect(d.accept).toBe(true);
		expect(d.append).toBeUndefined();
	});

	it("matches a comma-host token list containing the alias", () => {
		const known = "hostA,myhost,hostB ssh-ed25519 AAA\n";
		const d = decideHostKey(known, fp("myhost", "AAA"));
		expect(d.accept).toBe(true);
	});
});

describe("decideHostKey — present + mismatch → REJECT, no append", () => {
	it("rejects loudly when the pinned key differs", () => {
		const known = "myhost ssh-ed25519 AAA\n";
		const d = decideHostKey(known, fp("myhost", "BBB"));
		expect(d.accept).toBe(false);
		expect(d.append).toBeUndefined(); // never pin a mismatched key
		expect(d.reason).toContain("HOST KEY CHANGED");
		expect(d.reason).toContain("myhost");
	});

	it("does not pin on mismatch (the user must clear the stale line)", () => {
		const known = "myhost ssh-ed25519 AAA\n";
		const d = decideHostKey(known, fp("myhost", "DIFFERENT"));
		expect(d.append).toBeUndefined();
	});
});

describe("decideHostKey — absent (first connect) → accept + pin", () => {
	it("accepts and produces the pin line to append", () => {
		const d = decideHostKey("", fp("newhost", "AAA"));
		expect(d.accept).toBe(true);
		expect(d.append).toBe("newhost ssh-ed25519 AAA");
		expect(d.reason).toContain("first connect");
		expect(d.reason).toContain("newhost");
	});

	it("ignores comment + empty lines when searching", () => {
		const known = "# a comment\n\n  \notherhost ssh-ed25519 ZZZ\n";
		const d = decideHostKey(known, fp("newhost", "AAA"));
		expect(d.accept).toBe(true);
		expect(d.append).toBe("newhost ssh-ed25519 AAA");
	});

	it("pins a bracketed token for a non-default port", () => {
		const d = decideHostKey("", fp("[localhost]:2222", "AAA"));
		expect(d.accept).toBe(true);
		expect(d.append).toBe("[localhost]:2222 ssh-ed25519 AAA");
	});
});

describe("decideHostKey — first field must match the token", () => {
	it("does not match a host that appears only as a substring of another token", () => {
		const known = "myhost-extra ssh-ed25519 AAA\n";
		const d = decideHostKey(known, fp("myhost", "AAA"));
		// "myhost" is not an exact first-field (nor comma element) → absent → pin.
		expect(d.accept).toBe(true);
		expect(d.append).toBe("myhost ssh-ed25519 AAA");
	});
});

describe("isKnownHost", () => {
	it("returns true when the token is a known_hosts first field", () => {
		expect(isKnownHost("a.example ssh-ed25519 AAA\n", "a.example")).toBe(true);
	});

	it("returns true for a comma-list token", () => {
		expect(isKnownHost("a,b,c ssh-ed25519 AAA\n", "b")).toBe(true);
	});

	it("returns false when the token is absent", () => {
		expect(isKnownHost("a.example ssh-ed25519 AAA\n", "b.example")).toBe(false);
	});

	it("returns false for an empty known_hosts", () => {
		expect(isKnownHost("", "anything")).toBe(false);
	});

	it("ignores comments and blanks", () => {
		const known = "# comment\n\nfoo ssh-ed25519 AAA\n";
		expect(isKnownHost(known, "foo")).toBe(true);
		expect(isKnownHost(known, "bar")).toBe(false);
	});
});