arti_rpcserver/
session.rs1use arti_client::{
7 TorClient,
8 rpc::{ClientConnectionResult, ConnectWithPrefs, ResolvePtrWithPrefs, ResolveWithPrefs},
9};
10use derive_deftly::Deftly;
11use std::{
12 net::IpAddr,
13 sync::{Arc, Mutex},
14};
15use tor_error::into_internal;
16use tor_rtcompat::Runtime;
17
18use tor_rpcbase::{self as rpc, static_rpc_invoke_fn, templates::*};
19
20#[derive(Deftly)]
43#[derive_deftly(Object)]
44#[deftly(rpc(expose_outside_of_session))]
45pub struct RpcSession {
46 #[allow(unused)]
49 client: Arc<dyn Client>,
50
51 superuser: Mutex<Option<Arc<dyn rpc::Object>>>,
56}
57
58trait Client: rpc::Object {
60 fn isolated_client(&self) -> Arc<dyn rpc::Object>;
62
63 fn upcast_arc(self: Arc<Self>) -> Arc<dyn rpc::Object>;
65}
66
67impl<R: Runtime> Client for TorClient<R> {
68 fn isolated_client(&self) -> Arc<dyn rpc::Object> {
69 Arc::new(TorClient::isolated_client(self))
70 }
71
72 fn upcast_arc(self: Arc<Self>) -> Arc<dyn rpc::Object> {
73 self
74 }
75}
76
77impl RpcSession {
78 pub fn new_with_client<R: Runtime>(client: Arc<arti_client::TorClient<R>>) -> Arc<Self> {
80 Arc::new(Self {
81 client,
82 superuser: Mutex::new(None),
83 })
84 }
85
86 pub fn provide_superuser_permission(&self, superuser: Arc<dyn rpc::Object>) {
90 let mut su = self.superuser.lock().expect("Poisoned lock");
91 *su = Some(superuser);
92 }
93
94 fn client_as_object(&self) -> Arc<dyn rpc::Object> {
97 self.client.clone().upcast_arc()
98 }
99}
100
101#[derive(Debug, serde::Deserialize, serde::Serialize, Deftly)]
108#[derive_deftly(DynMethod)]
109#[deftly(rpc(method_name = "arti:get_client"))]
110struct GetClient {}
111
112impl rpc::RpcMethod for GetClient {
113 type Output = rpc::SingleIdResponse;
114 type Update = rpc::NoUpdates;
115}
116
117async fn get_client_on_session(
119 session: Arc<RpcSession>,
120 _method: Box<GetClient>,
121 ctx: Arc<dyn rpc::Context>,
122) -> Result<rpc::SingleIdResponse, rpc::RpcError> {
123 Ok(rpc::SingleIdResponse::from(
124 ctx.register_owned(session.client.clone().upcast_arc()),
125 ))
126}
127
128async fn isolated_client_on_session(
130 session: Arc<RpcSession>,
131 _method: Box<arti_client::rpc::IsolatedClient>,
132 ctx: Arc<dyn rpc::Context>,
133) -> Result<rpc::SingleIdResponse, rpc::RpcError> {
134 let new_client = session.client.isolated_client();
135 Ok(rpc::SingleIdResponse::from(ctx.register_owned(new_client)))
136}
137
138async fn session_connect_with_prefs(
142 session: Arc<RpcSession>,
143 method: Box<ConnectWithPrefs>,
144 ctx: Arc<dyn rpc::Context>,
145) -> ClientConnectionResult<arti_client::DataStream> {
146 *rpc::invoke_special_method(ctx, session.client_as_object(), method)
147 .await
148 .map_err(|e| Box::new(into_internal!("unable to delegate to TorClient")(e)) as _)?
149}
150
151async fn session_resolve_with_prefs(
155 session: Arc<RpcSession>,
156 method: Box<ResolveWithPrefs>,
157 ctx: Arc<dyn rpc::Context>,
158) -> ClientConnectionResult<Vec<IpAddr>> {
159 *rpc::invoke_special_method(ctx, session.client_as_object(), method)
160 .await
161 .map_err(|e| Box::new(into_internal!("unable to delegate to TorClient")(e)) as _)?
162}
163
164async fn session_resolve_ptr_with_prefs(
168 session: Arc<RpcSession>,
169 method: Box<ResolvePtrWithPrefs>,
170 ctx: Arc<dyn rpc::Context>,
171) -> ClientConnectionResult<Vec<String>> {
172 *rpc::invoke_special_method(ctx, session.client_as_object(), method)
173 .await
174 .map_err(|e| Box::new(into_internal!("unable to delegate to TorClient")(e)) as _)?
175}
176
177#[derive(Debug, serde::Deserialize, serde::Serialize, Deftly)]
185#[derive_deftly(DynMethod)]
186#[deftly(rpc(method_name = "arti:get_superuser_capability"))]
187struct GetSuperuserCapability {}
188
189impl rpc::RpcMethod for GetSuperuserCapability {
190 type Output = rpc::SingleIdResponse;
191 type Update = rpc::NoUpdates;
192}
193
194async fn get_superuser_capability_on_session(
196 session: Arc<RpcSession>,
197 _method: Box<GetSuperuserCapability>,
198 ctx: Arc<dyn rpc::Context>,
199) -> Result<rpc::SingleIdResponse, rpc::RpcError> {
200 let opt_su = session.superuser.lock().expect("Lock poisoned");
201 match opt_su.as_ref() {
202 Some(su) => {
203 let su = Arc::clone(su);
204 drop(opt_su);
205 let id = ctx.register_owned(su);
206 Ok(id.into())
207 }
208 None => Err(rpc::RpcError::new(
209 "Superuser access not permitted on this session".into(),
210 rpc::RpcErrorKind::RequestError,
211 )),
212 }
213}
214
215#[derive(Debug, serde::Deserialize, serde::Serialize, Deftly)]
238#[derive_deftly(DynMethod)]
239#[deftly(rpc(method_name = "arti:remove_superuser_permission"))]
240struct RemoveSuperuserPermission {}
241
242impl rpc::RpcMethod for RemoveSuperuserPermission {
243 type Output = rpc::Nil;
244 type Update = rpc::NoUpdates;
245}
246
247async fn remove_superuser_permission_on_session(
249 session: Arc<RpcSession>,
250 _method: Box<RemoveSuperuserPermission>,
251 _ctx: Arc<dyn rpc::Context>,
252) -> Result<rpc::Nil, rpc::RpcError> {
253 let mut opt_su = session.superuser.lock().expect("Lock poisoned");
254 *opt_su = None;
255 Ok(rpc::Nil::default())
256}
257
258static_rpc_invoke_fn! {
259 get_client_on_session;
260 isolated_client_on_session;
261 get_superuser_capability_on_session;
262 remove_superuser_permission_on_session;
263 @special session_connect_with_prefs;
264 @special session_resolve_with_prefs;
265 @special session_resolve_ptr_with_prefs;
266}
267
268#[cfg(feature = "describe-methods")]
269#[allow(clippy::missing_docs_in_private_items)] mod list_all_methods {
271 use std::{convert::Infallible, sync::Arc};
272
273 use derive_deftly::Deftly;
274 use tor_rpcbase::{self as rpc, RpcDispatchInformation, static_rpc_invoke_fn, templates::*};
275
276 #[derive(Debug, serde::Deserialize, Deftly)]
286 #[derive_deftly(DynMethod)]
287 #[deftly(rpc(method_name = "arti:x_list_all_rpc_methods"))]
288 struct ListAllRpcMethods {}
289
290 impl rpc::RpcMethod for ListAllRpcMethods {
291 type Output = RpcDispatchInformation;
292 type Update = rpc::NoUpdates;
293 }
294
295 async fn session_list_all_rpc_methods(
297 _session: Arc<super::RpcSession>,
298 _method: Box<ListAllRpcMethods>,
299 ctx: Arc<dyn rpc::Context>,
300 ) -> Result<RpcDispatchInformation, Infallible> {
301 Ok(ctx
302 .dispatch_table()
303 .read()
304 .expect("poisoned lock")
305 .dispatch_information())
306 }
307
308 static_rpc_invoke_fn! { session_list_all_rpc_methods; }
309}