ddnet_account_client/
sign.rs1use anyhow::anyhow;
2use ddnet_accounts_shared::client::{
3 account_data::AccountDataForClient, machine_id::machine_uid, sign::prepare_sign_request,
4};
5use thiserror::Error;
6use x509_parser::oid_registry::asn1_rs::FromDer;
7
8use crate::{
9 errors::{FsLikeError, HttpLikeError},
10 interface::Io,
11 safe_interface::{IoSafe, SafeIo},
12};
13
14#[derive(Error, Debug)]
16pub enum SignResult {
17 #[error("The session was not valid anymore.")]
19 SessionWasInvalid,
20 #[error("{0}")]
23 FsLikeError(FsLikeError),
24 #[error("{err}")]
26 HttpLikeError {
27 err: HttpLikeError,
29 account_data: AccountDataForClient,
31 },
32 #[error("Signing failed: {err}")]
34 Other {
35 err: anyhow::Error,
37 account_data: AccountDataForClient,
39 },
40}
41
42impl From<FsLikeError> for SignResult {
43 fn from(value: FsLikeError) -> Self {
44 Self::FsLikeError(value)
45 }
46}
47
48#[derive(Debug, Clone)]
52pub struct SignData {
53 pub certificate_der: Vec<u8>,
57 pub session_key_pair: AccountDataForClient,
59}
60
61pub async fn sign(io: &dyn Io) -> anyhow::Result<SignData, SignResult> {
72 sign_impl(io.into()).await
73}
74
75async fn sign_impl(io: IoSafe<'_>) -> anyhow::Result<SignData, SignResult> {
76 let key_pair = io.read_serialized_session_key_pair().await?;
78
79 let hashed_hw_id = machine_uid().map_err(|err| SignResult::Other {
80 account_data: key_pair.clone(),
81 err,
82 })?;
83
84 let msg = prepare_sign_request(hashed_hw_id, &key_pair.private_key, key_pair.public_key);
86 let sign_res = io
87 .request_sign(msg)
88 .await
89 .map_err(|err| SignResult::HttpLikeError {
90 account_data: key_pair.clone(),
91 err,
92 })?
93 .map_err(|err| SignResult::Other {
94 err: err.into(),
95 account_data: key_pair.clone(),
96 })?;
97 let certificate = {
98 x509_parser::certificate::X509Certificate::from_der(&sign_res.cert_der)
99 .is_ok()
100 .then_some(sign_res.cert_der)
101 };
102
103 certificate.map_or_else(
104 || {
105 Err(SignResult::Other {
106 err: anyhow!("the certificate is not in a valid der format"),
107 account_data: key_pair.clone(),
108 })
109 },
110 |certificate| {
111 Ok(SignData {
112 certificate_der: certificate,
113 session_key_pair: key_pair.clone(),
114 })
115 },
116 )
117}