spark_rust/wallet/internal_handlers/implementations/
authenticate.rs1use crate::error::{network::NetworkError, validation::ValidationError, SparkSdkError};
2use crate::rpc::connections::connection::SparkConnection;
3use crate::rpc::traits::SparkRpcConnection;
4use crate::signer::traits::SparkSigner;
5use crate::wallet::config::spark::Session;
6use crate::wallet::internal_handlers::traits::authenticate::AuthenticateInternalHandlers;
7use crate::SparkSdk;
8use prost::Message;
9use spark_protos::authn::GetChallengeRequest;
10use spark_protos::authn::VerifyChallengeRequest;
11use tonic::async_trait;
12use tonic::Request;
13
14#[async_trait]
15impl<S: SparkSigner + Send + Sync + Clone + 'static> AuthenticateInternalHandlers<S>
16 for SparkSdk<S>
17{
18 #[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
19 async fn authenticate(&self) -> Result<Vec<Session>, SparkSdkError> {
20 let spark_operators = self.config.spark_config.operator_pool.operators.clone();
21
22 let mut operator_sessions = Vec::new();
23
24 for operator in spark_operators {
25 let client = SparkConnection::establish_connection(operator.address.clone()).await?;
26 let mut auth_client = client.get_new_spark_authn_service_connection()?;
27
28 let pk = self.get_spark_address()?;
30 let challenge_req = GetChallengeRequest {
31 public_key: pk.serialize().to_vec(),
32 };
33
34 let spark_authn_response = auth_client
36 .get_challenge(Request::new(challenge_req))
37 .await
38 .map_err(|status| SparkSdkError::from(NetworkError::Status(status)))?
39 .into_inner();
40
41 let protected_challenge =
42 spark_authn_response
43 .protected_challenge
44 .ok_or(SparkSdkError::from(ValidationError::InvalidInput {
45 field: "No ProtectedChallenge returned by server".to_string(),
46 }))?;
47
48 let challenge = protected_challenge
50 .challenge
51 .clone()
52 .ok_or(SparkSdkError::from(ValidationError::InvalidInput {
53 field: "Missing Challenge within ProtectedChallenge".to_string(),
54 }))?;
55
56 let challenge_bytes = challenge.encode_to_vec(); let network = self.config.spark_config.network.to_bitcoin_network();
59 let signature = self.signer.sign_message_ecdsa_with_identity_key(
60 &challenge_bytes,
61 true,
62 network,
63 )?;
64
65 let verify_req = VerifyChallengeRequest {
66 protected_challenge: Some(protected_challenge),
67 signature: signature.serialize_der().to_vec(),
68 public_key: pk.serialize().to_vec(),
69 };
70
71 let verify_resp = auth_client
72 .verify_challenge(Request::new(verify_req))
73 .await
74 .map_err(|status| SparkSdkError::from(NetworkError::Status(status)))?
75 .into_inner();
76
77 let session = Session {
78 session_token: verify_resp.session_token,
79 _expiration_timestamp: verify_resp.expiration_timestamp,
80 };
81
82 operator_sessions.push(session);
83 }
84
85 Ok(operator_sessions)
86 }
87}