1use rand_core::CryptoRngCore;
5
6use reach_core::{
7 AssureAuthentication,
8 memory::rng,
9 wire::{AttestantVerifyingKeys, InitAuthenticatedSession, ReachCommunication},
10};
11use reach_websocket::{
12 WebSocketClient, WebSocketError, WebSocketRemoteClientOptions, websocketstream_from_request,
13};
14
15use crate::cli_utils::MayBail;
16use crate::memory::AttestantSigningKeys;
17
18pub type ReachClient = WebSocketClient<ReachCommunication>;
19pub type ReachClientOptions<S, R> = WebSocketRemoteClientOptions<S, R>;
20
21pub async fn create<const B: usize, R>(url: &str, csprng: &R) -> Result<ReachClient, WebSocketError>
22where
23 R: CryptoRngCore + Clone + Send + 'static,
24{
25 websocketstream_from_request(url).await.map(|web_socket| {
26 ReachClient::from(ReachClientOptions::new(
27 web_socket,
28 vec![1000, 2000, 4000, 8000],
29 csprng.clone(),
30 ))
31 })
32}
33
34pub async fn authenticate(
35 attestant_signing_keys: &AttestantSigningKeys,
36 attestant_verifying_keys: &AttestantVerifyingKeys,
37 url: &str,
38) -> ReachClient {
39 let mut csprng = rng::<8192>().expect("should initialize random number generator");
40
41 let mut client = create::<10, _>(&url.replace("http", "ws"), &csprng)
42 .await
43 .map_err(|_| "Could not initiate client session. Is the server online?")
44 .may_bail(true);
45
46 let challenge = client
47 .send_and_wait(&InitAuthenticatedSession(0))
48 .await
49 .map_err(|_| "Did not receive an authentication challenge as expected…")
50 .may_bail(true);
51
52 let assurance = attestant_signing_keys.assure_authentication(
53 attestant_verifying_keys,
54 &challenge,
55 &mut csprng,
56 );
57
58 client
59 .send_and_wait(&assurance)
60 .await
61 .map(|_| client)
62 .map_err(|_| "Authentication failed.")
63 .may_bail(true)
64}