subgraph/graphql/schema/create_auth_service/start_authentication/
mod.rs1use async_graphql::{
2 dynamic::{Field, FieldFuture, InputValue, TypeRef},
3 Value,
4};
5use log::{debug, error, trace};
6
7use crate::{data_sources::DataSources, graphql::schema::ServiceSchema};
8
9use super::ServiceUser;
10
11impl ServiceSchema {
12 pub fn create_authenticate_start(mut self) -> Self {
13 debug!("Creating authenticate start");
14 let auth_config = match self.subgraph_config.service.auth.clone() {
15 Some(auth) => auth,
16 None => {
17 panic!("Auth config not found.");
18 }
19 };
20
21 let resolver = Field::new(
22 "authenticate_start",
23 TypeRef::named_nn(TypeRef::STRING),
24 move |ctx| {
25 debug!("Resolving authenticate start");
26 let auth_config = auth_config.clone();
27
28 FieldFuture::new(async move {
29 let identifier = match ctx.args.try_get("identifier") {
30 Ok(input) => input.deserialize::<String>().map_err(|e| {
31 error!("Failed to get input: {:?}", e);
32 async_graphql::Error::new(format!("Failed to get input: {:?}", e))
33 })?,
34 Err(e) => {
35 error!("Failed to get input: {:?}", e);
36 return Err(async_graphql::Error::new(format!(
37 "Failed to get input: {:?}",
38 e
39 )));
40 }
41 };
42
43 let data_sources = ctx.data_unchecked::<DataSources>();
44 let data_source = DataSources::get_data_source_by_name(
45 &data_sources,
46 &auth_config.data_source,
47 );
48
49 let user = ServiceSchema::get_user(&data_source, &identifier).await;
50
51 let user = match user {
52 Ok(user) => user,
53 Err(e) => {
54 error!("Failed to get user: {:?}", e);
55 return Err(async_graphql::Error::new(format!(
56 "Failed to get user: {:?}",
57 e
58 )));
59 }
60 };
61
62 let user = match user {
63 Some(user) => user,
64 None => {
65 error!("User not found.");
66 return Err(async_graphql::Error::new(format!("User not found.")));
67 }
68 };
69
70 if user.passkey.is_none() {
71 error!("User does not have a passkey.");
72 return Err(async_graphql::Error::new(format!(
73 "User does not have a passkey."
74 )));
75 };
76 trace!("User: {:?}", &user);
77
78 let webauthn = ServiceSchema::build_webauthn(&auth_config).map_err(|e| {
79 error!("Failed to build webauthn: {:?}", e);
80 async_graphql::Error::new(format!("Failed to build webauthn: {:?}", e))
81 })?;
82
83 let (rcr, auth_state) = webauthn
84 .start_passkey_authentication(&vec![user.clone().passkey.unwrap()])
85 .map_err(|e| {
86 error!("Failed to start authentication: {:?}", e);
87 async_graphql::Error::new(format!(
88 "Failed to start authentication: {:?}",
89 e
90 ))
91 })?;
92
93 let service_user = ServiceUser {
95 identifier: identifier.clone(),
96 registration_state: user.registration_state,
97 passkey: user.passkey,
98 authentication_state: Some(auth_state),
99 uuid: user.uuid,
100 };
101
102 let updated = ServiceSchema::update_user(&data_source, service_user).await;
103
104 trace!("Updated User: {:?}", &updated);
105
106 match updated {
107 Ok(_) => {
108 let rcr_json = match serde_json::to_value(&rcr) {
109 Ok(rcr_json) => rcr_json,
110 Err(e) => {
111 error!("Failed to serialize rcr: {:?}", e);
112 return Err(async_graphql::Error::new(format!(
113 "Failed to serialize rcr: {:?}",
114 e
115 )));
116 }
117 };
118 let value = Value::from_json(rcr_json);
119 match value {
120 Ok(value) => Ok(Some(value)),
121 Err(e) => {
122 error!("Failed to create value: {:?}", e);
123 return Err(async_graphql::Error::new(format!(
124 "Failed to create value: {:?}",
125 e
126 )));
127 }
128 }
129 }
130 Err(e) => {
131 error!("Failed to update user: {:?}", e);
132 return Err(async_graphql::Error::new(format!(
133 "Failed to update user: {:?}",
134 e
135 )));
136 }
137 }
138 })
139 },
140 )
141 .argument(InputValue::new(
142 "identifier",
143 TypeRef::named_nn(TypeRef::STRING),
144 ));
145
146 self.mutation = self.mutation.field(resolver);
147 self
148 }
149}