tower_defense/auth/
mod.rs1use std::borrow::Cow;
2
3use jsonrpsee::{
4 core::{params::ObjectParams, traits::ToRpcParams},
5 types::Id,
6};
7use serde::{Deserialize, Serialize};
8use serde_json::value::RawValue;
9
10use crate::{
11 crypto::{Keypair, PeerId, PublicKey, Signature},
12 error::Error,
13};
14
15pub mod timestamp;
16pub use timestamp::VerifyTimestamp;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct AuthenticatedParams<'a> {
20 pub(crate) signer: PublicKey,
21 pub(crate) signature: Signature,
22 pub(crate) timestamp: u64,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub(crate) inner: Option<Cow<'a, RawValue>>,
25}
26
27#[derive(Debug, Clone)]
28pub struct VerifiedParams<'a> {
29 pub peer: PeerId,
30 pub inner: Option<Cow<'a, RawValue>>,
31}
32
33impl<'a> AuthenticatedParams<'a> {
34 #[must_use]
36 pub fn prepare(
37 keypair: &Keypair,
38 id: &Id<'_>,
39 method: &str,
40 params: Option<Cow<'a, RawValue>>,
41 now: u64,
42 ) -> Self {
43 let signing_metarial = signing_material(now, id, method, params.as_ref());
44 let signature = keypair.sign(&signing_metarial);
45
46 Self {
47 signer: keypair.public(),
48 signature,
49 timestamp: now,
50 inner: params,
51 }
52 }
53
54 pub fn prepare_now(
60 keypair: &Keypair,
61 id: &Id<'a>,
62 method: &'a str,
63 params: Option<Cow<'a, RawValue>>,
64 ) -> Result<Self, Error> {
65 Ok(Self::prepare(
66 keypair,
67 id,
68 method,
69 params,
70 timestamp::now()?,
71 ))
72 }
73
74 pub fn verify<VT: VerifyTimestamp>(
80 self,
81 id: &Id<'_>,
82 method: &str,
83 verify_timestamp: &VT,
84 ) -> Result<VerifiedParams<'a>, Error> {
85 let signing_metarial = signing_material(self.timestamp, id, method, self.inner.as_ref());
86 self.signer.verify(&signing_metarial, &self.signature)?;
87
88 let peer = PeerId::from(self.signer);
89
90 if !verify_timestamp.verify(&peer, self.timestamp) {
91 return Err(Error::InvalidTimestamp);
92 }
93
94 Ok(VerifiedParams {
95 peer,
96 inner: self.inner,
97 })
98 }
99}
100
101impl ToRpcParams for AuthenticatedParams<'_> {
102 fn to_rpc_params(self) -> Result<Option<Box<RawValue>>, serde_json::Error> {
103 let serde_json::Value::Object(obj) = serde_json::to_value(self)? else {
104 unreachable!("this type will always be serialize as a map");
105 };
106
107 let mut p = ObjectParams::new();
108 for (k, v) in obj {
109 p.insert(&k, v)?;
110 }
111
112 p.to_rpc_params()
113 }
114}
115
116fn signing_material(
117 ts: u64,
118 id: &Id<'_>,
119 method: &str,
120 params: Option<&Cow<'_, RawValue>>,
121) -> Vec<u8> {
122 let param_bytes = params.map(|i| i.get()).unwrap_or_default().as_bytes();
124 [
125 id.to_string().as_bytes(),
126 ts.to_be_bytes().as_slice(),
127 method.as_bytes(),
128 param_bytes,
129 ]
130 .concat()
131}