systemprompt_users/repository/
device_cert.rs1use systemprompt_identifiers::{DeviceCertId, UserId};
7
8use crate::error::Result;
9use crate::models::UserDeviceCert;
10use crate::repository::UserRepository;
11
12pub struct EnrollDeviceCertParams<'a> {
13 pub id: &'a DeviceCertId,
14 pub user_id: &'a UserId,
15 pub fingerprint: &'a str,
16 pub label: &'a str,
17}
18
19impl UserRepository {
20 pub async fn enroll_device_cert(
21 &self,
22 params: EnrollDeviceCertParams<'_>,
23 ) -> Result<UserDeviceCert> {
24 let row = sqlx::query_as!(
25 UserDeviceCert,
26 r#"
27 INSERT INTO user_device_certs (id, user_id, fingerprint, label)
28 VALUES ($1, $2, $3, $4)
29 RETURNING id, user_id, fingerprint, label, enrolled_at, revoked_at
30 "#,
31 params.id.as_str(),
32 params.user_id.as_str(),
33 params.fingerprint,
34 params.label,
35 )
36 .fetch_one(&*self.write_pool)
37 .await?;
38 Ok(row)
39 }
40
41 pub async fn find_active_device_cert_by_fingerprint(
42 &self,
43 fingerprint: &str,
44 ) -> Result<Option<UserDeviceCert>> {
45 let row = sqlx::query_as!(
46 UserDeviceCert,
47 r#"
48 SELECT id, user_id, fingerprint, label, enrolled_at, revoked_at
49 FROM user_device_certs
50 WHERE fingerprint = $1 AND revoked_at IS NULL
51 "#,
52 fingerprint,
53 )
54 .fetch_optional(&*self.pool)
55 .await?;
56 Ok(row)
57 }
58
59 pub async fn list_device_certs_for_user(
60 &self,
61 user_id: &UserId,
62 ) -> Result<Vec<UserDeviceCert>> {
63 let rows = sqlx::query_as!(
64 UserDeviceCert,
65 r#"
66 SELECT id, user_id, fingerprint, label, enrolled_at, revoked_at
67 FROM user_device_certs
68 WHERE user_id = $1
69 ORDER BY enrolled_at DESC
70 "#,
71 user_id.as_str(),
72 )
73 .fetch_all(&*self.pool)
74 .await?;
75 Ok(rows)
76 }
77
78 pub async fn revoke_device_cert(&self, id: &DeviceCertId, user_id: &UserId) -> Result<bool> {
79 let result = sqlx::query!(
80 r#"
81 UPDATE user_device_certs
82 SET revoked_at = CURRENT_TIMESTAMP
83 WHERE id = $1 AND user_id = $2 AND revoked_at IS NULL
84 "#,
85 id.as_str(),
86 user_id.as_str(),
87 )
88 .execute(&*self.write_pool)
89 .await?;
90 Ok(result.rows_affected() > 0)
91 }
92}