subgraph/graphql/schema/create_auth_service/
mod.rs1use 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: {:?}", ®_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 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!("🔐 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}