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