1use super::Error;
11use rand::{self, Rng};
12use serde::{de::DeserializeOwned, Deserialize, Serialize};
13
14type Result<T> = std::result::Result<T, Error>;
15
16const SAFE_AUTHD_JSONRPC_VERSION: &str = "2.0";
18
19const JSONRPC_PARSE_ERROR: isize = -32700;
21const JSONRPC_INVALID_REQUEST: isize = -32600;
22
23#[derive(Serialize, Deserialize, Debug, Clone)]
24pub struct JsonRpcRequest {
25 jsonrpc: String,
26 pub method: String,
27 pub params: serde_json::Value,
28 pub id: u32,
29}
30
31impl JsonRpcRequest {
32 pub fn new(method: &str, params: serde_json::Value) -> Self {
33 Self {
34 jsonrpc: SAFE_AUTHD_JSONRPC_VERSION.to_string(),
35 method: method.to_string(),
36 params,
37 id: rand::thread_rng().gen_range(0, std::u32::MAX) + 1,
38 }
39 }
40}
41
42#[derive(Deserialize, Serialize, Debug)]
43pub struct JsonRpcResponse {
44 jsonrpc: String,
45 result: Option<serde_json::Value>,
46 error: Option<JsonRpcError>,
47 id: Option<u32>,
48}
49
50#[derive(Serialize, Deserialize, Debug)]
51struct JsonRpcError {
52 code: isize,
53 message: String,
54 data: String,
55}
56
57impl JsonRpcResponse {
58 pub fn result(result: serde_json::Value, id: u32) -> Self {
60 Self {
61 jsonrpc: SAFE_AUTHD_JSONRPC_VERSION.to_string(),
62 result: Some(result),
63 error: None,
64 id: Some(id),
65 }
66 }
67
68 pub fn error(message: String, code: isize, id: Option<u32>) -> Self {
70 Self {
71 jsonrpc: SAFE_AUTHD_JSONRPC_VERSION.to_string(),
72 result: None,
73 error: Some(JsonRpcError {
74 code,
75 message,
76 data: "".to_string(),
77 }),
78 id,
79 }
80 }
81}
82
83pub(crate) fn parse_jsonrpc_request(req: Vec<u8>) -> std::result::Result<JsonRpcRequest, String> {
86 let req_payload = match String::from_utf8(req) {
87 Ok(payload) => payload,
88 Err(err) => {
89 let err_str = serialised_jsonrpc_error(
90 "Request payload is a malformed UTF-8 string".to_string(),
91 err.to_string(),
92 JSONRPC_PARSE_ERROR,
93 None,
94 )?;
95 return Err(err_str);
96 }
97 };
98
99 let jsonrpc_req: JsonRpcRequest = match serde_json::from_str(&req_payload) {
100 Ok(jsonrpc) => jsonrpc,
101 Err(err) => {
102 let err_str = serialised_jsonrpc_error(
103 "Failed to deserialise request payload as a JSON-RPC message".to_string(),
104 err.to_string(),
105 JSONRPC_INVALID_REQUEST,
106 None,
107 )?;
108 return Err(err_str);
109 }
110 };
111
112 Ok(jsonrpc_req)
113}
114
115pub(crate) fn parse_jsonrpc_response<T>(response_bytes: &[u8]) -> Result<T>
117where
118 T: DeserializeOwned,
119{
120 let res_payload = std::str::from_utf8(response_bytes)
121 .map_err(|err| Error::ClientError(format!("Failed to decode response data: {}", err)))?;
122
123 match serde_json::from_str(&res_payload) {
124 Ok(JsonRpcResponse {
125 jsonrpc,
126 result: Some(r),
127 ..
128 }) => {
129 if jsonrpc != SAFE_AUTHD_JSONRPC_VERSION {
130 Err(Error::ClientError(format!(
131 "JSON-RPC version {} not supported, only version {} is supported",
132 jsonrpc, SAFE_AUTHD_JSONRPC_VERSION
133 )))
134 } else {
135 let result = serde_json::from_value(r).map_err(|err| {
136 Error::ClientError(format!("Failed to decode response result: {}", err))
137 })?;
138
139 Ok(result)
140 }
141 }
142 Ok(JsonRpcResponse {
143 error: Some(err), ..
144 }) => Err(Error::RemoteEndpointError(err.message)),
145 Ok(JsonRpcResponse {
146 result: None,
147 error: None,
148 ..
149 }) => Err(Error::ClientError(
150 "Received an invalid JSON-RPC response from authd".to_string(),
151 )),
152 Err(err) => Err(Error::ClientError(format!(
153 "Failed to parse authd response: {}",
154 err
155 ))),
156 }
157}
158
159fn serialised_jsonrpc_error(
161 message: String,
162 data: String,
163 code: isize,
164 id: Option<u32>,
165) -> std::result::Result<String, String> {
166 let jsonrpc_err = JsonRpcResponse {
167 jsonrpc: SAFE_AUTHD_JSONRPC_VERSION.to_string(),
168 result: None,
169 error: Some(JsonRpcError {
170 code,
171 message,
172 data,
173 }),
174 id,
175 };
176 let serialised_err_res = serde_json::to_string(&jsonrpc_err)
177 .map_err(|err| format!("Failed to serialise authd error response: {:?}", err))?;
178
179 Ok(serialised_err_res)
180}