diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/storage.rs | 113 |
1 files changed, 108 insertions, 5 deletions
diff --git a/tests/storage.rs b/tests/storage.rs index b6e1369..19936c2 100644 --- a/tests/storage.rs +++ b/tests/storage.rs | |||
| @@ -20,21 +20,124 @@ fn client_credentials_roundtrip() { | |||
| 20 | let (_, conn) = tmp_db("creds"); | 20 | let (_, conn) = tmp_db("creds"); |
| 21 | client_database::init_db(&conn); | 21 | client_database::init_db(&conn); |
| 22 | 22 | ||
| 23 | assert_eq!(client_database::get_credentials(&conn, "h1"), None); | 23 | let identity = "5a15c712230831cb"; |
| 24 | client_database::save_credentials(&conn, "h1", "alice", "pw").unwrap(); | 24 | assert_eq!(client_database::get_credentials(&conn, identity), None); |
| 25 | client_database::save_credentials(&conn, identity, "alice", "pw").unwrap(); | ||
| 25 | assert_eq!( | 26 | assert_eq!( |
| 26 | client_database::get_credentials(&conn, "h1"), | 27 | client_database::get_credentials(&conn, identity), |
| 27 | Some(("alice".to_string(), "pw".to_string())) | 28 | Some(("alice".to_string(), "pw".to_string())) |
| 28 | ); | 29 | ); |
| 29 | // Overwrite works. | 30 | // Overwrite works. |
| 30 | client_database::save_credentials(&conn, "h1", "alice", "pw2").unwrap(); | 31 | client_database::save_credentials(&conn, identity, "alice", "pw2").unwrap(); |
| 31 | assert_eq!( | 32 | assert_eq!( |
| 32 | client_database::get_credentials(&conn, "h1"), | 33 | client_database::get_credentials(&conn, identity), |
| 33 | Some(("alice".to_string(), "pw2".to_string())) | 34 | Some(("alice".to_string(), "pw2".to_string())) |
| 34 | ); | 35 | ); |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | #[test] | 38 | #[test] |
| 39 | fn credentials_belong_to_the_certificate_not_the_address() { | ||
| 40 | let (_, conn) = tmp_db("creds-identity"); | ||
| 41 | client_database::init_db(&conn); | ||
| 42 | |||
| 43 | // Two addresses for one server, one address for another. | ||
| 44 | client_database::save_host(&conn, "10.0.0.100:11525"); | ||
| 45 | client_database::save_host(&conn, "127.0.0.1:11525"); | ||
| 46 | client_database::save_host(&conn, "other.example:11525"); | ||
| 47 | client_database::save_fingerprint(&conn, "10.0.0.100:11525", "server-a").unwrap(); | ||
| 48 | client_database::save_fingerprint(&conn, "127.0.0.1:11525", "server-a").unwrap(); | ||
| 49 | client_database::save_fingerprint(&conn, "other.example:11525", "server-b").unwrap(); | ||
| 50 | |||
| 51 | client_database::save_credentials(&conn, "server-a", "alice", "pw").unwrap(); | ||
| 52 | |||
| 53 | assert_eq!( | ||
| 54 | client_database::get_credentials(&conn, "server-a"), | ||
| 55 | Some(("alice".to_string(), "pw".to_string())), | ||
| 56 | "one login covers every address with the same key" | ||
| 57 | ); | ||
| 58 | assert_eq!( | ||
| 59 | client_database::get_credentials(&conn, "server-b"), | ||
| 60 | None, | ||
| 61 | "a different key must not inherit the credentials" | ||
| 62 | ); | ||
| 63 | } | ||
| 64 | |||
| 65 | #[test] | ||
| 66 | fn forgetting_one_address_keeps_the_shared_credentials() { | ||
| 67 | let (_, conn) = tmp_db("creds-forget"); | ||
| 68 | client_database::init_db(&conn); | ||
| 69 | |||
| 70 | client_database::save_host(&conn, "10.0.0.100:11525"); | ||
| 71 | client_database::save_host(&conn, "127.0.0.1:11525"); | ||
| 72 | client_database::save_fingerprint(&conn, "10.0.0.100:11525", "server-a").unwrap(); | ||
| 73 | client_database::save_fingerprint(&conn, "127.0.0.1:11525", "server-a").unwrap(); | ||
| 74 | client_database::save_credentials(&conn, "server-a", "alice", "pw").unwrap(); | ||
| 75 | |||
| 76 | let outcome = client_database::forget_host(&conn, "10.0.0.100:11525").unwrap(); | ||
| 77 | assert!(!outcome.credentials_removed); | ||
| 78 | assert_eq!(outcome.siblings, vec!["127.0.0.1:11525".to_string()]); | ||
| 79 | assert_eq!( | ||
| 80 | client_database::get_credentials(&conn, "server-a"), | ||
| 81 | Some(("alice".to_string(), "pw".to_string())), | ||
| 82 | "the server is still reachable, so the login is still useful" | ||
| 83 | ); | ||
| 84 | |||
| 85 | let outcome = client_database::forget_host(&conn, "127.0.0.1:11525").unwrap(); | ||
| 86 | assert!(outcome.credentials_removed); | ||
| 87 | assert!(outcome.siblings.is_empty()); | ||
| 88 | assert_eq!(client_database::get_credentials(&conn, "server-a"), None); | ||
| 89 | } | ||
| 90 | |||
| 91 | #[test] | ||
| 92 | fn legacy_host_keyed_credentials_are_rekeyed_by_fingerprint() { | ||
| 93 | let (_, conn) = tmp_db("creds-migrate"); | ||
| 94 | conn.execute_batch( | ||
| 95 | "CREATE TABLE hosts ( | ||
| 96 | host TEXT PRIMARY KEY, | ||
| 97 | last_used DATETIME DEFAULT CURRENT_TIMESTAMP, | ||
| 98 | fingerprint TEXT | ||
| 99 | ); | ||
| 100 | CREATE TABLE credentials ( | ||
| 101 | host TEXT PRIMARY KEY, | ||
| 102 | username TEXT NOT NULL, | ||
| 103 | password TEXT NOT NULL | ||
| 104 | ); | ||
| 105 | INSERT INTO hosts (host, last_used, fingerprint) | ||
| 106 | VALUES ('a:1', '2020-01-01 00:00:00', 'server-a'); | ||
| 107 | INSERT INTO hosts (host, last_used, fingerprint) | ||
| 108 | VALUES ('b:2', '2021-01-01 00:00:00', 'server-a'); | ||
| 109 | INSERT INTO hosts (host, last_used, fingerprint) | ||
| 110 | VALUES ('c:3', '2022-01-01 00:00:00', NULL); | ||
| 111 | INSERT INTO credentials VALUES ('a:1', 'alice', 'old'); | ||
| 112 | INSERT INTO credentials VALUES ('b:2', 'alice', 'recent'); | ||
| 113 | INSERT INTO credentials VALUES ('c:3', 'carol', 'untrusted');", | ||
| 114 | ) | ||
| 115 | .unwrap(); | ||
| 116 | |||
| 117 | client_database::init_db(&conn); | ||
| 118 | |||
| 119 | assert_eq!( | ||
| 120 | client_database::get_credentials(&conn, "server-a"), | ||
| 121 | Some(("alice".to_string(), "recent".to_string())), | ||
| 122 | "the most recently used address wins when legacy rows disagree" | ||
| 123 | ); | ||
| 124 | assert_eq!( | ||
| 125 | client_database::get_credentials(&conn, "carol"), | ||
| 126 | None, | ||
| 127 | "a host with no trusted key cannot be re-keyed" | ||
| 128 | ); | ||
| 129 | |||
| 130 | // The old table is gone: the column set is the fingerprint schema. | ||
| 131 | let mut statement = conn.prepare("PRAGMA table_info(credentials)").unwrap(); | ||
| 132 | let columns: Vec<String> = statement | ||
| 133 | .query_map([], |row| row.get(1)) | ||
| 134 | .unwrap() | ||
| 135 | .filter_map(|row| row.ok()) | ||
| 136 | .collect(); | ||
| 137 | assert_eq!(columns, vec!["fingerprint", "username", "password"]); | ||
| 138 | } | ||
| 139 | |||
| 140 | #[test] | ||
| 38 | fn client_last_host_tracking() { | 141 | fn client_last_host_tracking() { |
| 39 | let (_, conn) = tmp_db("hosts"); | 142 | let (_, conn) = tmp_db("hosts"); |
| 40 | client_database::init_db(&conn); | 143 | client_database::init_db(&conn); |
