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

1use async_graphql::{
2    dynamic::{Field, FieldFuture, InputValue, TypeRef},
3    Value,
4};
5use log::error;
6use webauthn_rs::prelude::RegisterPublicKeyCredential;
7
8use crate::{data_sources::DataSources, graphql::schema::ServiceSchema};
9
10use super::ServiceUser;
11
12impl ServiceSchema {
13    pub fn create_register_finish(mut self) -> Self {
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            "register_finish",
23            TypeRef::named_nn(TypeRef::BOOLEAN),
24            move |ctx| {
25                let auth_config = auth_config.clone();
26
27                FieldFuture::new(async move {
28                    let data_sources = ctx.data_unchecked::<DataSources>().clone();
29
30                    let data_source = DataSources::get_data_source_by_name(
31                        &data_sources,
32                        &auth_config.data_source,
33                    );
34
35                    let identifier = match ctx.args.try_get("identifier") {
36                        Ok(input) => input
37                            .deserialize::<String>()
38                            .expect("Failed to deserialize."),
39                        Err(e) => {
40                            return Err(async_graphql::Error::new(format!(
41                                "Failed to get input: {:?}",
42                                e
43                            )));
44                        }
45                    };
46
47                    let pub_key = match ctx.args.try_get("public_key") {
48                        Ok(input) => input
49                            .deserialize::<String>()
50                            .expect("Failed to deserialize."),
51                        Err(e) => {
52                            ServiceSchema::delete_user(&data_source, &identifier).await?;
53                            return Err(async_graphql::Error::new(format!(
54                                "Failed to get input: {:?}",
55                                e
56                            )));
57                        }
58                    };
59
60                    let user = ServiceSchema::get_user(&data_source, &identifier).await;
61
62                    let user = match user {
63                        Ok(user) => user,
64                        Err(e) => {
65                            return Err(async_graphql::Error::new(format!(
66                                "Failed to get user: {:?}",
67                                e
68                            )))
69                        }
70                    };
71
72                    if user.is_none() {
73                        error!("User Not Found: {:?}", &identifier);
74                        return Err(async_graphql::Error::new(format!(
75                            "User Not Found: {:?}",
76                            &identifier
77                        )));
78                    }
79
80                    let webauthn = match ServiceSchema::build_webauthn(&auth_config) {
81                        Ok(w) => Ok(w),
82                        Err(e) => {
83                            ServiceSchema::delete_user(&data_source, &identifier).await?;
84                            Err(async_graphql::Error::new(format!(
85                                "something went wrong when building webauthn: {:?}",
86                                e
87                            )))
88                        }
89                    }?;
90
91                    let pub_key: Result<RegisterPublicKeyCredential, async_graphql::Error> =
92                        serde_json::from_str(&pub_key).map_err(|e| {
93                            async_graphql::Error::new(format!("Failed to deserialize: {:?}", e))
94                        });
95
96                    let pub_key = match pub_key {
97                        Ok(pk) => pk,
98                        Err(error) => {
99                            ServiceSchema::delete_user(&data_source, &identifier).await?;
100                            return Err(error);
101                        }
102                    };
103
104                    let passkey = webauthn
105                        .finish_passkey_registration(
106                            &pub_key,
107                            &user.clone().unwrap().registration_state,
108                        )
109                        .map_err(|e| {
110                            async_graphql::Error::new(format!(
111                                "Failed to finish registration: {:?}",
112                                e
113                            ))
114                        });
115                    let passkey = match passkey {
116                        Ok(pk) => pk,
117                        Err(error) => {
118                            ServiceSchema::delete_user(&data_source, &identifier).await?;
119                            return Err(error);
120                        }
121                    };
122
123                    // Update user with sk
124                    let service_user = ServiceUser {
125                        identifier: identifier.clone(),
126                        registration_state: user.clone().unwrap().registration_state,
127                        passkey: Some(passkey),
128                        authentication_state: None,
129                        uuid: user.unwrap().uuid,
130                    };
131
132                    let updated = ServiceSchema::update_user(&data_source, service_user).await;
133                    match updated {
134                        Ok(_) => (),
135                        Err(e) => {
136                            ServiceSchema::delete_user(&data_source, &identifier).await?;
137                            return Err(e);
138                        }
139                    };
140
141                    Ok(Some(Value::from(true)))
142                })
143            },
144        )
145        .argument(InputValue::new(
146            "identifier",
147            TypeRef::named_nn(TypeRef::STRING),
148        ))
149        .argument(InputValue::new(
150            "public_key",
151            TypeRef::named_nn(TypeRef::STRING),
152        ));
153
154        self.mutation = self.mutation.field(resolver);
155        self
156    }
157}