tower_defense/
middleware.rs1use 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}