Skip to main content

cloudillo_auth_adapter_sqlite/
lib.rs

1use std::{fmt::Debug, path::Path, sync::Arc};
2
3use async_trait::async_trait;
4use jsonwebtoken::DecodingKey;
5use sqlx::sqlite::{self, SqlitePool};
6use tokio::fs;
7
8use cloudillo_types::{auth_adapter::*, prelude::*, worker::WorkerPool};
9
10mod api_key;
11mod auth;
12mod cert;
13mod crypto;
14mod profile_key;
15mod proxy_site;
16mod schema;
17mod tenant;
18mod utils;
19mod vapid;
20mod variable;
21mod webauthn;
22
23pub struct AuthAdapterSqlite {
24	db: SqlitePool,
25	worker: Arc<WorkerPool>,
26	jwt_secret_str: String,
27	jwt_secret: DecodingKey,
28}
29
30impl Debug for AuthAdapterSqlite {
31	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32		f.debug_struct("AuthAdapterSqlite").finish()
33	}
34}
35
36impl AuthAdapterSqlite {
37	pub async fn new(worker: Arc<WorkerPool>, path: impl AsRef<Path>) -> ClResult<Self> {
38		let db_path = path.as_ref().join("auth.db");
39		fs::create_dir_all(&path).await.expect("Cannot create auth-adapter dir");
40		let opts = sqlite::SqliteConnectOptions::new()
41			.filename(&db_path)
42			.create_if_missing(true)
43			.journal_mode(sqlite::SqliteJournalMode::Wal);
44		let db = sqlite::SqlitePoolOptions::new()
45			.max_connections(5)
46			.connect_with(opts)
47			.await
48			.inspect_err(|err| println!("DbError: {:#?}", err))
49			.or(Err(Error::DbError))?;
50
51		schema::init_db(&db)
52			.await
53			.inspect_err(|err| println!("DbError: {:#?}", err))
54			.or(Err(Error::DbError))?;
55
56		// Get or generate JWT secret
57		let jwt_secret_str = auth::ensure_jwt_secret(&db).await?;
58		let jwt_secret = DecodingKey::from_secret(jwt_secret_str.as_bytes());
59
60		Ok(Self { worker, db, jwt_secret_str, jwt_secret })
61	}
62}
63
64#[async_trait]
65impl AuthAdapter for AuthAdapterSqlite {
66	async fn validate_access_token(&self, tn_id: TnId, token: &str) -> ClResult<AuthCtx> {
67		auth::validate_access_token(&self.jwt_secret, tn_id, token).await
68	}
69
70	async fn read_id_tag(&self, tn_id: TnId) -> ClResult<Box<str>> {
71		tenant::read_id_tag(&self.db, tn_id).await
72	}
73
74	async fn read_tn_id(&self, id_tag: &str) -> ClResult<TnId> {
75		tenant::read_tn_id(&self.db, id_tag).await
76	}
77
78	async fn read_tenant(&self, id_tag: &str) -> ClResult<AuthProfile> {
79		tenant::read_tenant(&self.db, id_tag).await
80	}
81
82	async fn create_tenant_registration(&self, email: &str) -> ClResult<()> {
83		tenant::create_tenant_registration(&self.db, email).await
84	}
85
86	async fn create_tenant(&self, id_tag: &str, data: CreateTenantData<'_>) -> ClResult<TnId> {
87		tenant::create_tenant(&self.db, &self.worker, id_tag, data).await
88	}
89
90	async fn delete_tenant(&self, id_tag: &str) -> ClResult<()> {
91		tenant::delete_tenant(&self.db, id_tag).await
92	}
93
94	async fn list_tenants(&self, opts: &ListTenantsOptions<'_>) -> ClResult<Vec<TenantListItem>> {
95		tenant::list_tenants(&self.db, opts).await
96	}
97
98	async fn create_tenant_login(&self, id_tag: &str) -> ClResult<AuthLogin> {
99		auth::create_tenant_login(&self.db, &self.worker, id_tag, &self.jwt_secret_str).await
100	}
101
102	async fn check_tenant_password(&self, id_tag: &str, password: &str) -> ClResult<AuthLogin> {
103		auth::check_tenant_password(&self.db, &self.worker, id_tag, password, &self.jwt_secret_str)
104			.await
105	}
106
107	async fn update_tenant_password(&self, id_tag: &str, password: &str) -> ClResult<()> {
108		auth::update_tenant_password(&self.db, &self.worker, id_tag, password).await
109	}
110
111	async fn update_idp_api_key(&self, id_tag: &str, api_key: &str) -> ClResult<()> {
112		auth::update_idp_api_key(&self.db, id_tag, api_key).await
113	}
114
115	async fn create_cert(&self, cert_data: &CertData) -> ClResult<()> {
116		cert::create_cert(&self.db, cert_data).await
117	}
118
119	async fn read_cert_by_tn_id(&self, tn_id: TnId) -> ClResult<CertData> {
120		cert::read_cert_by_tn_id(&self.db, tn_id).await
121	}
122
123	async fn read_cert_by_id_tag(&self, id_tag: &str) -> ClResult<CertData> {
124		cert::read_cert_by_id_tag(&self.db, id_tag).await
125	}
126
127	async fn read_cert_by_domain(&self, domain: &str) -> ClResult<CertData> {
128		cert::read_cert_by_domain(&self.db, domain).await
129	}
130
131	async fn list_all_certs(&self) -> ClResult<Vec<CertData>> {
132		cert::list_all_certs(&self.db).await
133	}
134
135	async fn list_tenants_needing_cert_renewal(
136		&self,
137		renewal_days: u32,
138	) -> ClResult<Vec<(TnId, Box<str>)>> {
139		cert::list_tenants_needing_cert_renewal(&self.db, renewal_days).await
140	}
141
142	async fn list_profile_keys(&self, tn_id: TnId) -> ClResult<Vec<AuthKey>> {
143		profile_key::list_profile_keys(&self.db, tn_id).await
144	}
145
146	async fn read_profile_key(&self, tn_id: TnId, key_id: &str) -> ClResult<AuthKey> {
147		profile_key::read_profile_key(&self.db, tn_id, key_id).await
148	}
149
150	async fn create_profile_key(
151		&self,
152		tn_id: TnId,
153		expires_at: Option<Timestamp>,
154	) -> ClResult<AuthKey> {
155		profile_key::create_profile_key(&self.db, &self.worker, tn_id, expires_at).await
156	}
157
158	async fn create_access_token(
159		&self,
160		tn_id: TnId,
161		data: &AccessToken<&str>,
162	) -> ClResult<Box<str>> {
163		auth::create_access_token(&self.db, &self.worker, tn_id, data, &self.jwt_secret_str).await
164	}
165
166	async fn create_action_token(
167		&self,
168		tn_id: TnId,
169		action: cloudillo_types::action_types::CreateAction,
170	) -> ClResult<Box<str>> {
171		auth::create_action_token(&self.db, &self.worker, tn_id, action).await
172	}
173
174	async fn create_proxy_token(
175		&self,
176		tn_id: TnId,
177		id_tag: &str,
178		roles: &[Box<str>],
179	) -> ClResult<Box<str>> {
180		auth::create_proxy_token(&self.db, tn_id, id_tag, roles).await
181	}
182
183	async fn verify_access_token(&self, token: &str) -> ClResult<()> {
184		auth::verify_access_token(&self.jwt_secret, token).await
185	}
186
187	async fn read_vapid_key(&self, tn_id: TnId) -> ClResult<KeyPair> {
188		vapid::read_vapid_key(&self.db, tn_id).await
189	}
190
191	async fn read_vapid_public_key(&self, tn_id: TnId) -> ClResult<Box<str>> {
192		vapid::read_vapid_public_key(&self.db, tn_id).await
193	}
194
195	async fn create_vapid_key(&self, tn_id: TnId) -> ClResult<KeyPair> {
196		let keypair = crypto::generate_vapid_key(&self.worker).await?;
197		vapid::update_vapid_key(&self.db, tn_id, &keypair).await?;
198		Ok(keypair)
199	}
200
201	async fn update_vapid_key(&self, tn_id: TnId, key: &KeyPair) -> ClResult<()> {
202		vapid::update_vapid_key(&self.db, tn_id, key).await
203	}
204
205	async fn read_var(&self, tn_id: TnId, var: &str) -> ClResult<Box<str>> {
206		variable::read_var(&self.db, tn_id, var).await
207	}
208
209	async fn update_var(&self, tn_id: TnId, var: &str, value: &str) -> ClResult<()> {
210		variable::update_var(&self.db, tn_id, var, value).await
211	}
212
213	async fn list_webauthn_credentials(&self, tn_id: TnId) -> ClResult<Box<[Webauthn]>> {
214		webauthn::list_webauthn_credentials(&self.db, tn_id).await
215	}
216
217	async fn read_webauthn_credential(
218		&self,
219		tn_id: TnId,
220		credential_id: &str,
221	) -> ClResult<Webauthn> {
222		webauthn::read_webauthn_credential(&self.db, tn_id, credential_id).await
223	}
224
225	async fn create_webauthn_credential(&self, tn_id: TnId, data: &Webauthn) -> ClResult<()> {
226		webauthn::create_webauthn_credential(&self.db, tn_id, data).await
227	}
228
229	async fn update_webauthn_credential_counter(
230		&self,
231		tn_id: TnId,
232		credential_id: &str,
233		counter: u32,
234	) -> ClResult<()> {
235		webauthn::update_webauthn_credential_counter(&self.db, tn_id, credential_id, counter).await
236	}
237
238	async fn delete_webauthn_credential(&self, tn_id: TnId, credential_id: &str) -> ClResult<()> {
239		webauthn::delete_webauthn_credential(&self.db, tn_id, credential_id).await
240	}
241
242	// API Key management
243	async fn create_api_key(
244		&self,
245		tn_id: TnId,
246		opts: CreateApiKeyOptions<'_>,
247	) -> ClResult<CreatedApiKey> {
248		api_key::create_api_key(&self.db, &self.worker, tn_id, opts).await
249	}
250
251	async fn validate_api_key(&self, key: &str) -> ClResult<ApiKeyValidation> {
252		api_key::validate_api_key(&self.db, &self.worker, key).await
253	}
254
255	async fn list_api_keys(&self, tn_id: TnId) -> ClResult<Vec<ApiKeyInfo>> {
256		api_key::list_api_keys(&self.db, tn_id).await
257	}
258
259	async fn read_api_key(&self, tn_id: TnId, key_id: i64) -> ClResult<ApiKeyInfo> {
260		api_key::read_api_key(&self.db, tn_id, key_id).await
261	}
262
263	async fn update_api_key(
264		&self,
265		tn_id: TnId,
266		key_id: i64,
267		name: Option<&str>,
268		scopes: Option<&str>,
269		expires_at: Option<Timestamp>,
270	) -> ClResult<ApiKeyInfo> {
271		api_key::update_api_key(&self.db, tn_id, key_id, name, scopes, expires_at).await
272	}
273
274	async fn delete_api_key(&self, tn_id: TnId, key_id: i64) -> ClResult<()> {
275		api_key::delete_api_key(&self.db, tn_id, key_id).await
276	}
277
278	async fn cleanup_expired_api_keys(&self) -> ClResult<u32> {
279		api_key::cleanup_expired_api_keys(&self.db).await
280	}
281
282	async fn cleanup_expired_verification_codes(&self) -> ClResult<u32> {
283		let result = sqlx::query(
284			"DELETE FROM user_vfy WHERE expires_at IS NOT NULL AND expires_at < unixepoch()",
285		)
286		.execute(&self.db)
287		.await
288		.or(Err(Error::DbError))?;
289		Ok(result.rows_affected() as u32)
290	}
291
292	// Proxy site management
293	async fn create_proxy_site(&self, data: &CreateProxySiteData<'_>) -> ClResult<ProxySiteData> {
294		proxy_site::create_proxy_site(&self.db, data).await
295	}
296
297	async fn read_proxy_site(&self, site_id: i64) -> ClResult<ProxySiteData> {
298		proxy_site::read_proxy_site(&self.db, site_id).await
299	}
300
301	async fn read_proxy_site_by_domain(&self, domain: &str) -> ClResult<ProxySiteData> {
302		proxy_site::read_proxy_site_by_domain(&self.db, domain).await
303	}
304
305	async fn update_proxy_site(
306		&self,
307		site_id: i64,
308		data: &UpdateProxySiteData<'_>,
309	) -> ClResult<ProxySiteData> {
310		proxy_site::update_proxy_site(&self.db, site_id, data).await
311	}
312
313	async fn delete_proxy_site(&self, site_id: i64) -> ClResult<()> {
314		proxy_site::delete_proxy_site(&self.db, site_id).await
315	}
316
317	async fn list_proxy_sites(&self) -> ClResult<Vec<ProxySiteData>> {
318		proxy_site::list_proxy_sites(&self.db).await
319	}
320
321	async fn update_proxy_site_cert(
322		&self,
323		site_id: i64,
324		cert: &str,
325		key: &str,
326		expires_at: Timestamp,
327	) -> ClResult<()> {
328		proxy_site::update_proxy_site_cert(&self.db, site_id, cert, key, expires_at).await
329	}
330
331	async fn list_proxy_sites_needing_cert_renewal(
332		&self,
333		renewal_days: u32,
334	) -> ClResult<Vec<ProxySiteData>> {
335		proxy_site::list_proxy_sites_needing_cert_renewal(&self.db, renewal_days).await
336	}
337}
338
339// vim: ts=4