1 /// Pinned SSH host keys for smbCloud deployment servers.
2 ///
3 /// These are **public** keys — safe to commit to a public repository.
4 /// Host keys are designed to be known; only the private half (which never
5 /// leaves the server) provides authentication.
6 ///
7 /// Purpose: protect every `smb deploy` user from DNS/BGP hijacking.
8 /// By pairing these constants with `StrictHostKeyChecking=yes` and a
9 /// generated temp `UserKnownHostsFile`, the CLI refuses to connect to any
10 /// server that doesn't present one of these exact keys — even if the
11 /// hostname resolves correctly to an attacker's IP.
12 ///
13 /// Both servers run OpenSSH 9.2p1 on Debian 12.
14 ///
15 /// # Key rotation
16 ///
17 /// If a server's host key is ever rotated (e.g. after a compromise or
18 /// reprovisioning), update the relevant constant here and cut a new CLI
19 /// release. Users on old releases will receive a hard SSH refusal:
20 ///
21 /// ```text
22 /// Host key verification failed.
23 /// ```
24 ///
25 /// That is the correct behaviour — they must upgrade before deploying.
26 ///
27 /// To re-fetch the current keys:
28 ///
29 /// ```sh
30 /// ssh-keyscan -t ed25519 api.smbcloud.xyz api-1.smbcloud.xyz 2>/dev/null
31 /// ```
32 /// Pinned ed25519 host key for `api.smbcloud.xyz` (NodeJs / Static tier).
33 pub const API_SMBCLOUD_XYZ: &str =
34 "api.smbcloud.xyz ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINGy4LHGyOilS7SXo770V3tQnXDRVQr7X7JsPLCfy4XB";
35
36 /// Pinned ed25519 host key for `api-1.smbcloud.xyz` (Ruby / Swift tier).
37 pub const API_1_SMBCLOUD_XYZ: &str =
38 "api-1.smbcloud.xyz ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII1G3JyS66+yIFGrN3Vgc/UlvBm/oS98qq5pS96UYxcz";
39
40 /// Returns the pinned host key line for the given rsync hostname.
41 ///
42 /// The returned string is in `known_hosts` format and can be written
43 /// directly to a temp file passed to SSH via `-o UserKnownHostsFile=`.
44 pub fn for_host(rsync_host: &str) -> &'static str {
45 if rsync_host.starts_with("api-1.") {
46 API_1_SMBCLOUD_XYZ
47 } else {
48 API_SMBCLOUD_XYZ
49 }
50 }
51
52 /// Returns whether `host` has a host key pinned by this crate.
53 pub fn is_pinned_host(host: &str) -> bool {
54 matches!(host, "api.smbcloud.xyz" | "api-1.smbcloud.xyz")
55 }
56
57 #[cfg(test)]
58 mod tests {
59 use super::*;
60
61 #[test]
62 fn api_host_returns_correct_key() {
63 let key = for_host("api.smbcloud.xyz");
64 assert!(key.starts_with("api.smbcloud.xyz ssh-ed25519 "));
65 assert!(!key.contains("api-1"));
66 }
67
68 #[test]
69 fn api_1_host_returns_correct_key() {
70 let key = for_host("api-1.smbcloud.xyz");
71 assert!(key.starts_with("api-1.smbcloud.xyz ssh-ed25519 "));
72 }
73
74 #[test]
75 fn keys_are_distinct() {
76 assert_ne!(API_SMBCLOUD_XYZ, API_1_SMBCLOUD_XYZ);
77 }
78
79 #[test]
80 fn keys_contain_valid_ed25519_prefix() {
81 // ed25519 public keys always begin with this base64 prefix
82 assert!(API_SMBCLOUD_XYZ.contains("AAAA"));
83 assert!(API_1_SMBCLOUD_XYZ.contains("AAAA"));
84 }
85
86 #[test]
87 fn rejects_unpinned_hosts() {
88 assert!(is_pinned_host("api.smbcloud.xyz"));
89 assert!(is_pinned_host("api-1.smbcloud.xyz"));
90 assert!(!is_pinned_host("example.com"));
91 }
92 }