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
140
141
142
143
144
use super::{constants::SN_AUTHD_CONNECTION_IDLE_TIMEOUT, Error, Result};
use log::info;
use qjsonrpc::ClientEndpoint;
use serde::de::DeserializeOwned;
use tokio::runtime;
pub mod auth_types {
use crate::api::ipc::req::IpcReq;
use serde::{Deserialize, Serialize};
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 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 ed_sk_from_hex(hex_str: &str) -> Result<ed25519_dalek::SecretKey> {
let sk_bytes = parse_hex(&hex_str);
ed25519_dalek::SecretKey::from_bytes(&sk_bytes).map_err(|_| {
Error::InvalidInput("Failed to deserialize provided Ed25519 secret key".to_string())
})
}
pub fn sk_to_hex(sk: sn_data_types::SecretKey) -> String {
match sk {
sn_data_types::SecretKey::Ed25519(sk) => {
sk.to_bytes().iter().map(|b| format!("{:02x}", b)).collect()
}
sn_data_types::SecretKey::BlsShare(sk) => sk.inner().reveal(),
}
}
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 dirs_next::home_dir() {
None => Err(Error::AuthdClientError(
"Failed to obtain local project directory where to read certificate from".to_string(),
)),
Some(mut paths) => {
paths.push(".safe");
paths.push("authd");
let cert_base_path = paths.display().to_string();
let qjsonrpc_client = ClientEndpoint::new(
&cert_base_path,
Some(SN_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 = {
let _ = runtime.enter();
qjsonrpc_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 {
qjsonrpc::Error::RemoteEndpointError(msg) => Error::AuthdError(msg),
other => Error::AuthdClientError(other.to_string()),
})
}
}
}