subgraph/graphql/schema/create_auth_service/start_authentication/
mod.rs

1use 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                    //Update the user property auth_state
94                    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}