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