Skip to main content

tower_defense/
middleware.rs

1use jsonrpsee::{
2    MethodResponse,
3    core::{
4        ClientError,
5        middleware::{Batch, Notification, RpcServiceT},
6        traits::ToRpcParams as _,
7    },
8    types::{ErrorCode, Id, Request},
9};
10
11use crate::{
12    auth::{AuthenticatedParams, VerifyTimestamp},
13    crypto::Keypair,
14};
15
16pub struct Sign<S> {
17    keypair: Keypair,
18    inner: S,
19}
20
21impl<S> Sign<S> {
22    pub fn new(keypair: Keypair, inner: S) -> Self {
23        Self { keypair, inner }
24    }
25}
26
27impl<S, MR, NR, BR> RpcServiceT for Sign<S>
28where
29    S: RpcServiceT<
30            MethodResponse = Result<MR, ClientError>,
31            NotificationResponse = Result<NR, ClientError>,
32            BatchResponse = Result<BR, ClientError>,
33        > + Send
34        + Sync
35        + Clone
36        + 'static,
37{
38    type MethodResponse = S::MethodResponse;
39    type NotificationResponse = S::NotificationResponse;
40    type BatchResponse = S::BatchResponse;
41
42    fn call<'a>(
43        &self,
44        request: Request<'a>,
45    ) -> impl Future<Output = Self::MethodResponse> + Send + 'a {
46        let inner = self.inner.clone();
47        let keypair = self.keypair.clone();
48
49        async move {
50            let Ok(auth) = AuthenticatedParams::prepare_now(
51                &keypair,
52                &request.id,
53                request.method.as_ref(),
54                request.params,
55            ) else {
56                return Err(ClientError::Custom(
57                    "Failed to prepare authenticated params".into(),
58                ));
59            };
60
61            let Ok(params) = auth.to_rpc_params() else {
62                return Err(ClientError::Custom(
63                    "Failed to serialize authenticated params".into(),
64                ));
65            };
66
67            let request = Request::owned(request.method.into_owned(), params, request.id);
68
69            inner.call(request).await
70        }
71    }
72
73    #[expect(clippy::manual_async_fn)]
74    fn batch<'a>(
75        &self,
76        _requests: Batch<'a>,
77    ) -> impl Future<Output = Self::BatchResponse> + Send + 'a {
78        async {
79            Err(ClientError::Custom(
80                "Authenticated batch calls are not supported".into(),
81            ))
82        }
83    }
84
85    #[expect(clippy::manual_async_fn)]
86    fn notification<'a>(
87        &self,
88        _n: Notification<'a>,
89    ) -> impl Future<Output = Self::NotificationResponse> + Send + 'a {
90        async {
91            Err(ClientError::Custom(
92                "Authenticated notifications are not supported".into(),
93            ))
94        }
95    }
96}
97
98pub struct Verify<S, VT> {
99    inner: S,
100    verify_timestamp: VT,
101}
102
103impl<S, VT> Verify<S, VT> {
104    pub fn new(inner: S, verify_timestamp: VT) -> Self {
105        Self {
106            inner,
107            verify_timestamp,
108        }
109    }
110}
111
112impl<S, VT> RpcServiceT for Verify<S, VT>
113where
114    S: RpcServiceT<MethodResponse = MethodResponse> + Send + Clone + 'static,
115    VT: VerifyTimestamp + Clone + Send + 'static,
116{
117    type MethodResponse = MethodResponse;
118    type NotificationResponse = MethodResponse;
119    type BatchResponse = MethodResponse;
120
121    fn call<'a>(
122        &self,
123        mut request: Request<'a>,
124    ) -> impl Future<Output = Self::MethodResponse> + Send + 'a {
125        let inner = self.inner.clone();
126        let verify_timestamp = self.verify_timestamp.clone();
127
128        async move {
129            let Ok(auth) = request.params().parse::<AuthenticatedParams>() else {
130                return MethodResponse::error(request.id, ErrorCode::InvalidRequest);
131            };
132
133            let Ok(verified) = auth.verify(&request.id, request.method_name(), &verify_timestamp)
134            else {
135                return MethodResponse::error(request.id, ErrorCode::InvalidRequest);
136            };
137
138            request.params = verified.inner;
139            request.extensions_mut().insert(verified.peer);
140
141            inner.call(request).await
142        }
143    }
144
145    #[expect(clippy::manual_async_fn)]
146    fn batch<'a>(
147        &self,
148        _requests: Batch<'a>,
149    ) -> impl Future<Output = Self::BatchResponse> + Send + 'a {
150        async { MethodResponse::error(Id::Null, ErrorCode::InternalError) }
151    }
152
153    #[expect(clippy::manual_async_fn)]
154    fn notification<'a>(
155        &self,
156        _n: Notification<'a>,
157    ) -> impl Future<Output = Self::NotificationResponse> + Send + 'a {
158        async { MethodResponse::error(Id::Null, ErrorCode::InternalError) }
159    }
160}