1use log::{debug, error, info, warn};
13use r2d2::{Pool, PooledConnection};
14use r2d2_sqlite::SqliteConnectionManager;
15use rusqlite::{params, Error as SQLiteError, Result as SQLiteResult};
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18use std::sync::Arc;
19
20#[derive(Serialize, Deserialize, Debug, Clone, Default)]
22pub struct VaultCredentials {
23 pub root_unseal_keys: Vec<String>,
25 pub root_token: String,
26 pub sub_token: String,
28 pub transit_token: String,
30}
31
32pub type DbPool = Pool<SqliteConnectionManager>;
34pub type DbConnection = PooledConnection<SqliteConnectionManager>;
35
36#[derive(Clone)]
38pub struct DatabaseManager {
39 pool: Arc<DbPool>,
40}
41
42impl DatabaseManager {
43 pub fn new(db_path: &str) -> Result<Self, r2d2::Error> {
45 let manager = SqliteConnectionManager::file(db_path);
46 let pool = Pool::new(manager)?;
47
48 let connection = pool.get()?;
50 Self::init_database(&connection).unwrap_or_else(|e| {
51 error!("Failed to initialize database: {}", e);
52 });
53
54 Ok(Self {
55 pool: Arc::new(pool),
56 })
57 }
58
59 fn init_database(conn: &DbConnection) -> SQLiteResult<()> {
61 conn.execute(
63 "CREATE TABLE IF NOT EXISTS vault_credentials (
64 id INTEGER PRIMARY KEY,
65 root_unseal_keys TEXT NOT NULL,
66 root_token TEXT NOT NULL,
67 sub_token TEXT NOT NULL,
68 transit_token TEXT NOT NULL
69 )",
70 [],
71 )?;
72
73 conn.execute(
75 "CREATE TABLE IF NOT EXISTS vault_relationships (
76 id INTEGER PRIMARY KEY,
77 sub_addr TEXT NOT NULL UNIQUE,
78 root_addr TEXT NOT NULL
79 )",
80 [],
81 )?;
82
83 info!("Database initialized successfully");
84 Ok(())
85 }
86
87 pub fn save_vault_credentials(&self, credentials: &VaultCredentials) -> SQLiteResult<()> {
89 let conn = self.pool.get().map_err(|e| {
90 error!("Failed to get database connection: {}", e);
91 SQLiteError::ExecuteReturnedResults
92 })?;
93
94 let root_unseal_keys =
96 serde_json::to_string(&credentials.root_unseal_keys).map_err(|e| {
97 error!("Failed to serialize root_unseal_keys: {}", e);
98 SQLiteError::ExecuteReturnedResults
99 })?;
100
101 let count: i64 = conn.query_row("SELECT COUNT(*) FROM vault_credentials", [], |row| {
103 row.get(0)
104 })?;
105
106 if count > 0 {
107 conn.execute(
109 "UPDATE vault_credentials SET
110 root_unseal_keys = ?,
111 root_token = ?,
112 sub_token = ?,
113 transit_token = ?
114 WHERE id = 1",
115 params![
116 root_unseal_keys,
117 credentials.root_token,
118 credentials.sub_token,
119 credentials.transit_token
120 ],
121 )?;
122 debug!("Updated existing vault credentials in database");
123 } else {
124 conn.execute(
126 "INSERT INTO vault_credentials (
127 root_unseal_keys, root_token, sub_token, transit_token
128 ) VALUES (?, ?, ?, ?)",
129 params![
130 root_unseal_keys,
131 credentials.root_token,
132 credentials.sub_token,
133 credentials.transit_token
134 ],
135 )?;
136 debug!("Inserted new vault credentials into database");
137 }
138
139 info!("✅ Vault credentials successfully saved to database");
140 info!(" Root token length: {}", credentials.root_token.len());
141 info!(" Root unseal keys: {}", credentials.root_unseal_keys.len());
142 info!(" Sub token length: {}", credentials.sub_token.len());
143 info!(
144 " Transit token length: {}",
145 credentials.transit_token.len()
146 );
147
148 Ok(())
149 }
150
151 pub fn load_vault_credentials(&self) -> SQLiteResult<VaultCredentials> {
153 let conn = self.pool.get().map_err(|e| {
154 error!("Failed to get database connection: {}", e);
155 SQLiteError::ExecuteReturnedResults
156 })?;
157
158 let result = conn.query_row(
159 "SELECT root_unseal_keys, root_token, sub_token, transit_token FROM vault_credentials LIMIT 1",
160 [],
161 |row| {
162 let root_unseal_keys_json: String = row.get(0)?;
163
164 let root_unseal_keys: Vec<String> = serde_json::from_str(&root_unseal_keys_json)
166 .map_err(|e| {
167 error!("Failed to deserialize root_unseal_keys: {}", e);
168 SQLiteError::ExecuteReturnedResults
169 })?;
170
171 Ok(VaultCredentials {
172 root_unseal_keys,
173 root_token: row.get(1)?,
174 sub_token: row.get(2)?,
175 transit_token: row.get(3)?,
176 })
177 },
178 );
179
180 match result {
181 Ok(credentials) => {
182 info!("Loaded vault credentials from database");
183 info!(" Root token length: {}", credentials.root_token.len());
184 info!(" Root unseal keys: {}", credentials.root_unseal_keys.len());
185 info!(" Sub token length: {}", credentials.sub_token.len());
186 info!(
187 " Transit token length: {}",
188 credentials.transit_token.len()
189 );
190
191 Ok(credentials)
192 }
193 Err(e) => {
194 warn!("Failed to load vault credentials from database: {}", e);
195
196 if e == SQLiteError::QueryReturnedNoRows {
198 warn!("No credentials found in database, returning default");
199 return Ok(VaultCredentials::default());
200 }
201
202 Err(e)
203 }
204 }
205 }
206
207 pub fn save_unsealer_relationship(&self, sub_addr: &str, root_addr: &str) -> SQLiteResult<()> {
209 let conn = self.pool.get().map_err(|e| {
210 error!("Failed to get database connection: {}", e);
211 SQLiteError::ExecuteReturnedResults
212 })?;
213
214 conn.execute(
216 "INSERT OR REPLACE INTO vault_relationships (sub_addr, root_addr) VALUES (?, ?)",
217 params![sub_addr, root_addr],
218 )?;
219
220 info!(
221 "Saved unsealer relationship: sub={}, root={}",
222 sub_addr, root_addr
223 );
224
225 Ok(())
226 }
227
228 pub fn load_unsealer_relationships(&self) -> SQLiteResult<HashMap<String, String>> {
230 let conn = self.pool.get().map_err(|e| {
231 error!("Failed to get database connection: {}", e);
232 SQLiteError::ExecuteReturnedResults
233 })?;
234
235 let mut stmt = conn.prepare("SELECT sub_addr, root_addr FROM vault_relationships")?;
236
237 let rows = stmt.query_map([], |row| {
238 Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?))
239 })?;
240
241 let mut relationships = HashMap::new();
242 for row_result in rows {
243 match row_result {
244 Ok((sub_addr, root_addr)) => {
245 relationships.insert(sub_addr, root_addr);
246 }
247 Err(e) => {
248 warn!("Error reading relationship row: {}", e);
249 }
250 }
251 }
252
253 info!(
254 "Loaded {} unsealer relationships from database",
255 relationships.len()
256 );
257 Ok(relationships)
258 }
259
260 pub fn delete_unsealer_relationship(&self, sub_addr: &str) -> SQLiteResult<()> {
262 let conn = self.pool.get().map_err(|e| {
263 error!("Failed to get database connection: {}", e);
264 SQLiteError::ExecuteReturnedResults
265 })?;
266
267 conn.execute(
268 "DELETE FROM vault_relationships WHERE sub_addr = ?",
269 params![sub_addr],
270 )?;
271
272 info!("Deleted unsealer relationship for sub={}", sub_addr);
273 Ok(())
274 }
275
276 pub fn get_pool(&self) -> Arc<DbPool> {
278 self.pool.clone()
279 }
280}