spark_sdk/wallet/internal_handlers/implementations/
authenticate.rs1use std::str::FromStr;
2
3use crate::error::SparkSdkError;
4use crate::rpc::connections::connection::SparkConnection;
5use crate::rpc::traits::SparkRpcConnection;
6use crate::signer::traits::SparkSigner;
7use crate::wallet::client::Session;
8use crate::wallet::internal_handlers::traits::authenticate::AuthenticateInternalHandlers;
9use crate::SparkSdk;
10use prost::Message;
11use spark_protos::authn::GetChallengeRequest;
12use spark_protos::authn::VerifyChallengeRequest;
13use tonic::async_trait;
14use tonic::transport::Uri;
15use tonic::Request;
16
17#[async_trait]
18impl<S: SparkSigner + Send + Sync + Clone + 'static> AuthenticateInternalHandlers<S>
19 for SparkSdk<S>
20{
21 async fn authenticate(&self) -> Result<Vec<Session>, SparkSdkError> {
22 let spark_operators = self.config.spark_config.spark_operators.clone();
23
24 let mut operator_sessions = Vec::new();
25
26 for operator in spark_operators {
27 let uri = Uri::from_str(&operator.address)?;
28 let client = SparkConnection::establish_connection(uri).await?;
29 let mut auth_client = client.get_new_spark_authn_service_connection()?;
30
31 let pk_bytes = self.get_identity_public_key();
33 let challenge_req = GetChallengeRequest {
34 public_key: pk_bytes.to_vec(),
35 };
36
37 let spark_authn_response = auth_client
39 .get_challenge(Request::new(challenge_req))
40 .await?
41 .into_inner();
42
43 let protected_challenge = spark_authn_response.protected_challenge.ok_or(
44 SparkSdkError::AuthenticationError(
45 "No ProtectedChallenge returned by server".to_string(),
46 ),
47 )?;
48
49 let challenge =
51 protected_challenge
52 .challenge
53 .clone()
54 .ok_or(SparkSdkError::AuthenticationError(
55 "Missing Challenge within ProtectedChallenge".to_string(),
56 ))?;
57
58 let challenge_bytes = challenge.encode_to_vec(); let serialized_signature = self
61 .signer
62 .sign_message_ecdsa_with_identity_key(&challenge_bytes, true)?;
63
64 let verify_req = VerifyChallengeRequest {
65 protected_challenge: Some(protected_challenge),
66 signature: serialized_signature,
67 public_key: pk_bytes.to_vec(),
68 };
69
70 let verify_resp = auth_client
71 .verify_challenge(Request::new(verify_req))
72 .await?
73 .into_inner();
74
75 let session = Session {
76 session_token: verify_resp.session_token,
77 expiration_timestamp: verify_resp.expiration_timestamp,
78 };
79
80 operator_sessions.push(session);
81 }
82
83 Ok(operator_sessions)
84 }
85}