summaryrefslogtreecommitdiffstats
path: root/src/bin/client/database.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/client/database.rs')
-rw-r--r--src/bin/client/database.rs46
1 files changed, 41 insertions, 5 deletions
diff --git a/src/bin/client/database.rs b/src/bin/client/database.rs
index a274f31..55051fb 100644
--- a/src/bin/client/database.rs
+++ b/src/bin/client/database.rs
@@ -1,15 +1,17 @@
1use rusqlite::Connection; 1use rusqlite::Connection;
2 2
3pub fn init_db() -> Connection { 3pub fn init_db(conn: &Connection) {
4 let conn = Connection::open("client.db").unwrap();
5 conn.execute( 4 conn.execute(
6 "CREATE TABLE IF NOT EXISTS hosts ( 5 "CREATE TABLE IF NOT EXISTS hosts (
7 host TEXT PRIMARY KEY, 6 host TEXT PRIMARY KEY,
8 last_used DATETIME DEFAULT CURRENT_TIMESTAMP 7 last_used DATETIME DEFAULT CURRENT_TIMESTAMP,
8 fingerprint TEXT
9 )", 9 )",
10 [], 10 [],
11 ) 11 )
12 .unwrap(); 12 .unwrap();
13 // Migration for databases created before TOFU trust.
14 let _ = conn.execute("ALTER TABLE hosts ADD COLUMN fingerprint TEXT", []);
13 conn.execute( 15 conn.execute(
14 "CREATE TABLE IF NOT EXISTS credentials ( 16 "CREATE TABLE IF NOT EXISTS credentials (
15 host TEXT PRIMARY KEY, 17 host TEXT PRIMARY KEY,
@@ -19,7 +21,6 @@ pub fn init_db() -> Connection {
19 [], 21 [],
20 ) 22 )
21 .unwrap(); 23 .unwrap();
22 conn
23} 24}
24 25
25pub fn get_last_host(conn: &Connection) -> Option<String> { 26pub fn get_last_host(conn: &Connection) -> Option<String> {
@@ -36,7 +37,8 @@ pub fn get_last_host(conn: &Connection) -> Option<String> {
36 37
37pub fn save_host(conn: &Connection, host: &str) { 38pub fn save_host(conn: &Connection, host: &str) {
38 conn.execute( 39 conn.execute(
39 "INSERT OR REPLACE INTO hosts (host, last_used) VALUES (?1, CURRENT_TIMESTAMP)", 40 "INSERT INTO hosts (host) VALUES (?1)
41 ON CONFLICT(host) DO UPDATE SET last_used = CURRENT_TIMESTAMP",
40 [host], 42 [host],
41 ) 43 )
42 .unwrap(); 44 .unwrap();
@@ -68,3 +70,37 @@ pub fn get_credentials(conn: &Connection, host: &str) -> Option<(String, String)
68 None 70 None
69 } 71 }
70} 72}
73
74/// SHA-256 SPKI fingerprint of a host's certificate, if trusted.
75pub fn get_fingerprint(conn: &Connection, host: &str) -> Option<String> {
76 let mut stmt = conn
77 .prepare("SELECT fingerprint FROM hosts WHERE host = ?1")
78 .ok()?;
79 let mut rows = stmt.query([host]).ok()?;
80 match rows.next() {
81 Ok(Some(row)) => row.get(0).ok(),
82 _ => None,
83 }
84}
85
86pub fn save_fingerprint(
87 conn: &Connection,
88 host: &str,
89 fingerprint: &str,
90) -> Result<(), rusqlite::Error> {
91 // Hosts may not exist yet (fingerprint can be saved before first
92 // successful connect completes save_host).
93 conn.execute("INSERT OR IGNORE INTO hosts (host) VALUES (?1)", [host])?;
94 conn.execute(
95 "UPDATE hosts SET fingerprint = ?2 WHERE host = ?1",
96 (host, fingerprint),
97 )?;
98 Ok(())
99}
100
101/// Remove all trust and credentials for a host ("forget this host").
102pub fn forget_host(conn: &Connection, host: &str) -> Result<(), rusqlite::Error> {
103 conn.execute("DELETE FROM hosts WHERE host = ?1", [host])?;
104 conn.execute("DELETE FROM credentials WHERE host = ?1", [host])?;
105 Ok(())
106}