1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use super::{constants::SAFE_AUTHD_CONNECTION_IDLE_TIMEOUT, Error, Result};
use jsonrpc_quic::ClientEndpoint;
use log::info;
use serde::de::DeserializeOwned;
use threshold_crypto::SecretKey;
use tokio::runtime;
pub mod auth_types {
use safe_core::ipc::req::{ContainerPermissions, IpcReq};
use safe_nd::AppPermissions;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub type SafeAuthReq = IpcReq;
pub type SafeAuthReqId = u32;
#[derive(Debug, Serialize, Deserialize)]
pub struct AuthedApp {
pub id: String,
pub name: String,
pub vendor: String,
pub app_permissions: AppPermissions,
pub containers: HashMap<String, ContainerPermissions>,
pub own_container: bool,
}
pub type AuthedAppsList = Vec<AuthedApp>;
}
pub fn parse_hex(hex_str: &str) -> Vec<u8> {
let mut hex_bytes = hex_str
.as_bytes()
.iter()
.filter_map(|b| match b {
b'0'..=b'9' => Some(b - b'0'),
b'a'..=b'f' => Some(b - b'a' + 10),
b'A'..=b'F' => Some(b - b'A' + 10),
_ => None,
})
.fuse();
let mut bytes = Vec::new();
while let (Some(h), Some(l)) = (hex_bytes.next(), hex_bytes.next()) {
bytes.push(h << 4 | l)
}
bytes
}
pub fn sk_from_hex(hex_str: &str) -> Result<SecretKey> {
let sk_bytes = parse_hex(&hex_str);
bincode::deserialize(&sk_bytes)
.map_err(|_| Error::InvalidInput("Failed to deserialize provided secret key".to_string()))
}
pub async fn send_authd_request<T>(
dest_endpoint: &str,
method: &str,
params: serde_json::Value,
) -> Result<T>
where
T: DeserializeOwned,
{
info!(
"Sending '{}' request to SAFE Authenticator on {} ...",
method, dest_endpoint
);
match directories::ProjectDirs::from("net", "maidsafe", "safe-authd") {
None => Err(Error::AuthdClientError(
"Failed to obtain local project directory where to read certificate from".to_string(),
)),
Some(dirs) => {
let cert_base_path = dirs.config_dir().display().to_string();
let jsonrpc_quic_client = ClientEndpoint::new(
&cert_base_path,
Some(SAFE_AUTHD_CONNECTION_IDLE_TIMEOUT),
false,
)
.map_err(|err| {
Error::AuthdClientError(format!("Failed to create client endpoint: {}", err))
})?;
let runtime = match runtime::Handle::try_current() {
Ok(r) => r,
Err(_) => runtime::Runtime::new()
.map_err(|err| {
Error::AuthdClientError(format!("Failed to create runtime: {}", err))
})?
.handle()
.clone(),
};
let mut outgoing_conn = {
runtime
.enter(|| jsonrpc_quic_client.bind())
.map_err(|err| {
Error::AuthdClientError(format!("Failed to bind endpoint: {}", err))
})?
};
outgoing_conn
.connect(dest_endpoint, None)
.await
.map_err(|err| {
Error::AuthdClientError(format!(
"Failed to establish connection with authd: {}",
err
))
})?
.send(method, params)
.await
.map_err(|err| match err {
jsonrpc_quic::Error::RemoteEndpointError(msg) => Error::AuthdError(msg),
other => Error::AuthdClientError(other.to_string()),
})
}
}
}