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 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 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 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