summaryrefslogtreecommitdiffstats
path: root/src/client/database.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-29 22:55:49 +0100
committersalmonik <salmonik@tuta.io>2026-10-29 22:55:49 +0100
commit49df948de25d28601469e9ca993f33530989ebd0 (patch)
tree291aae0f57d0d7d12a27eb28038e43f942d6b991 /src/client/database.rs
parentv2.4.0: key stored credentials by certificate fingerprint (diff)
downloadzagan-bet-49df948de25d28601469e9ca993f33530989ebd0.tar.gz
zagan-bet-49df948de25d28601469e9ca993f33530989ebd0.zip
v3.0.0: cursor-driven roulette felt with splits and corners; drop schema migrations; require 80x24
Diffstat (limited to 'src/client/database.rs')
-rw-r--r--src/client/database.rs41
1 files changed, 0 insertions, 41 deletions
diff --git a/src/client/database.rs b/src/client/database.rs
index 04a271a..c4601b5 100644
--- a/src/client/database.rs
+++ b/src/client/database.rs
@@ -20,14 +20,9 @@ pub fn init_db(conn: &Connection) {
20 [], 20 [],
21 ) 21 )
22 .unwrap(); 22 .unwrap();
23 // Migration for databases created before TOFU trust.
24 let _ = conn.execute("ALTER TABLE hosts ADD COLUMN fingerprint TEXT", []);
25 23
26 // Credentials belong to a server identity (the certificate key), not to a 24 // Credentials belong to a server identity (the certificate key), not to a
27 // single address, so every address that presents the same key shares them. 25 // single address, so every address that presents the same key shares them.
28 if has_column(conn, "credentials", "host") {
29 migrate_credentials_to_fingerprints(conn);
30 }
31 conn.execute( 26 conn.execute(
32 "CREATE TABLE IF NOT EXISTS credentials ( 27 "CREATE TABLE IF NOT EXISTS credentials (
33 fingerprint TEXT PRIMARY KEY, 28 fingerprint TEXT PRIMARY KEY,
@@ -39,42 +34,6 @@ pub fn init_db(conn: &Connection) {
39 .unwrap(); 34 .unwrap();
40} 35}
41 36
42fn has_column(conn: &Connection, table: &str, column: &str) -> bool {
43 let Ok(mut statement) = conn.prepare(&format!("PRAGMA table_info({table})")) else {
44 return false;
45 };
46 let Ok(rows) = statement.query_map([], |row| row.get::<_, String>(1)) else {
47 return false;
48 };
49 rows.flatten().any(|name| name == column)
50}
51
52/// Re-key host-bound credentials by the fingerprint of their host.
53///
54/// Rows whose host was already forgotten have no identity to attach to and are
55/// dropped; those addresses have to re-authenticate once.
56fn migrate_credentials_to_fingerprints(conn: &Connection) {
57 let tx = conn.unchecked_transaction().unwrap();
58 tx.execute_batch(
59 "DROP TABLE IF EXISTS credentials_by_identity;
60 CREATE TABLE credentials_by_identity (
61 fingerprint TEXT PRIMARY KEY,
62 username TEXT NOT NULL,
63 password TEXT NOT NULL
64 );
65 INSERT OR REPLACE INTO credentials_by_identity (fingerprint, username, password)
66 SELECT h.fingerprint, c.username, c.password
67 FROM credentials c
68 JOIN hosts h ON h.host = c.host
69 WHERE h.fingerprint IS NOT NULL
70 ORDER BY h.last_used ASC, h.host ASC;
71 DROP TABLE credentials;
72 ALTER TABLE credentials_by_identity RENAME TO credentials;",
73 )
74 .unwrap();
75 tx.commit().unwrap();
76}
77
78pub fn get_last_host(conn: &Connection) -> Option<String> { 37pub fn get_last_host(conn: &Connection) -> Option<String> {
79 let mut stmt = conn 38 let mut stmt = conn
80 .prepare("SELECT host FROM hosts ORDER BY last_used DESC LIMIT 1") 39 .prepare("SELECT host FROM hosts ORDER BY last_used DESC LIMIT 1")