jsonrpc_quic/
jsonrpc.rs

1// Copyright 2020 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT
4// http://opensource.org/licenses/MIT> or the Modified BSD license <LICENSE-BSD
5// https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be copied,
6// modified, or distributed except according to those terms. Please review the Licences for the
7// specific language governing permissions and limitations relating to use of the SAFE Network
8// Software.
9
10use super::Error;
11use rand::{self, Rng};
12use serde::{de::DeserializeOwned, Deserialize, Serialize};
13
14type Result<T> = std::result::Result<T, Error>;
15
16// Version of the JSON-RPC used in the requests
17const SAFE_AUTHD_JSONRPC_VERSION: &str = "2.0";
18
19// JSON-RPC error codes as defined at https://www.jsonrpc.org/specification#response_object
20const 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    // Construct a JsonRpcResponse containing a successfull response
59    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    // Construct a JsonRpcResponse containing an error response
69    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
83// It parses the request bytes an returns a JsonRpcRequest, or a
84// serialised JSON-RPC error response ready to send back to the origin
85pub(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
115// Parse bytes to construct a JsonRpcResponse expected to contain a result of type T
116pub(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
159// Generates a serialised JSON-RPC error response
160fn 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}