subgraph/graphql/schema/create_auth_service/
mod.rs

1use std::str::FromStr;
2
3use super::ServiceSchema;
4use base64::{engine::general_purpose, Engine as _};
5use biscuit_auth::{KeyPair, PrivateKey};
6use log::{debug, error, info, trace};
7use serde::{Deserialize, Deserializer, Serialize};
8use uuid::Uuid;
9use webauthn_rs::prelude::{Passkey, PasskeyAuthentication, PasskeyRegistration};
10
11pub mod build_webauthn;
12pub mod delete_user;
13mod finish_authentication;
14mod finish_register;
15pub mod get_user;
16mod start_authentication;
17mod start_register;
18pub mod update_user;
19
20#[derive(Debug, Clone, Deserialize, Serialize)]
21pub struct ServiceUser {
22    #[serde(deserialize_with = "deserialize_uuid")]
23    uuid: uuid::Uuid,
24    identifier: String,
25    #[serde(deserialize_with = "deserialize_registration_state")]
26    registration_state: PasskeyRegistration,
27    #[serde(deserialize_with = "deserialize_passkey")]
28    passkey: Option<Passkey>,
29    #[serde(deserialize_with = "deserialize_authentication_state")]
30    authentication_state: Option<PasskeyAuthentication>,
31}
32
33fn deserialize_uuid<'de, D>(deserializer: D) -> Result<Uuid, D::Error>
34where
35    D: Deserializer<'de>,
36{
37    debug!("Deserializing UUID");
38    let s = String::deserialize(deserializer)?;
39    trace!("Parsing UUID: {}", &s);
40    match Uuid::from_str(&s) {
41        Ok(uuid) => {
42            trace!("Parsed UUID: {}", &uuid);
43            Ok(uuid)
44        }
45        Err(_) => {
46            trace!("Failed to parse UUID: {}", &s);
47            Uuid::from_str(&s).map_err(serde::de::Error::custom)
48        }
49    }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct TokenData {
54    pub user_uuid: String,
55    pub identifier: String,
56}
57
58fn deserialize_registration_state<'de, D>(deserializer: D) -> Result<PasskeyRegistration, D::Error>
59where
60    D: serde::Deserializer<'de>,
61{
62    debug!("Deserializing registration state");
63    let s = String::deserialize(deserializer)?;
64    let reg_state = serde_json::from_str(&s).unwrap();
65    trace!("Deserialized registration state: {:?}", &reg_state);
66    Ok(reg_state)
67}
68
69fn deserialize_passkey<'de, D>(deserializer: D) -> Result<Option<Passkey>, D::Error>
70where
71    D: serde::Deserializer<'de>,
72{
73    debug!("Deserializing passkey");
74    let s = String::deserialize(deserializer);
75    match s {
76        Ok(s) => {
77            let passkey = serde_json::from_str(&s).unwrap();
78            trace!("Deserialized passkey: {:?}", &passkey);
79            Ok(Some(passkey))
80        }
81        Err(_) => Ok(None),
82    }
83}
84
85fn deserialize_authentication_state<'de, D>(
86    deserializer: D,
87) -> Result<Option<PasskeyAuthentication>, D::Error>
88where
89    D: serde::Deserializer<'de>,
90{
91    debug!("Deserializing authentication state");
92    let s = String::deserialize(deserializer);
93    match s {
94        Ok(s) => {
95            let auth_state = serde_json::from_str(&s).unwrap();
96            trace!("Deserialized authentication state: {:?}", &auth_state);
97            Ok(Some(auth_state))
98        }
99        Err(_) => Ok(None),
100    }
101}
102
103impl ServiceSchema {
104    pub fn create_auth_service(mut self) -> Self {
105        self = self.create_register_start();
106        self = self.create_register_finish();
107        self = self.create_authenticate_start();
108        self = self.create_authenticate_finish();
109        self
110    }
111
112    /// Enables the auth service by creating a key pair unless one is provided.
113    pub fn get_key_pair(&mut self) {
114        debug!("Getting key pair");
115        let key_pair;
116        if self.subgraph_config.service.auth.is_some() {
117            //info message with an unicode icon
118            info!("🔐 Auth Enabled!");
119            let auth = self.subgraph_config.service.auth.clone().unwrap();
120            let b64_private_key = auth.private_key;
121
122            if b64_private_key.is_some() {
123                trace!("Using provided key pair");
124                let bytes_private_key = &general_purpose::URL_SAFE_NO_PAD
125                    .decode(b64_private_key.unwrap())
126                    .map_err(|e| {
127                        error!("Error decoding private key: {}", e);
128                        e
129                    })
130                    .unwrap();
131
132                let private_key = PrivateKey::from_bytes(bytes_private_key);
133
134                key_pair = Some(KeyPair::from(&private_key.unwrap()));
135            } else {
136                key_pair = Some(KeyPair::new());
137            }
138        } else {
139            key_pair = None;
140        }
141        self.key_pair = key_pair;
142    }
143}