diff --git a/api/src/lib.rs b/api/src/lib.rs index 0dc91b2a..e1842ceb 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -57,5 +57,6 @@ pub use crate::foreign_rpc::run_doctest_foreign; pub use crate::owner_rpc::run_doctest_owner; pub use types::{ - ECDHPubkey, EncryptedRequest, EncryptedResponse, EncryptionErrorResponse, PubAddress, Token, + ECDHPubkey, EncryptedRequest, EncryptedResponse, EncryptionErrorResponse, JsonId, PubAddress, + Token, }; diff --git a/api/src/types.rs b/api/src/types.rs index 31a736f7..bf711c4f 100644 --- a/api/src/types.rs +++ b/api/src/types.rs @@ -25,6 +25,17 @@ use ring::aead; use serde_json::{self, Value}; use std::collections::HashMap; +/// Represents a compliant JSON RPC 2.0 id. +/// Valid id: Integer, String. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(untagged)] +pub enum JsonId { + /// Integer Id + IntId(u32), + /// String Id + StrId(String), +} + /// Wrapper for API Tokens #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(transparent)] @@ -142,19 +153,18 @@ pub struct EncryptedRequest { /// method pub method: String, /// id - #[serde(with = "secp_ser::string_or_u64")] - pub id: u64, + pub id: JsonId, /// Body params, which includes nonce and encrypted request pub params: EncryptedBody, } impl EncryptedRequest { /// from json - pub fn from_json(id: u64, json_in: &Value, enc_key: &SecretKey) -> Result { + pub fn from_json(id: &JsonId, json_in: &Value, enc_key: &SecretKey) -> Result { Ok(EncryptedRequest { jsonrpc: "2.0".to_owned(), method: "encrypted_request_v3".to_owned(), - id: id, + id: id.clone(), params: EncryptedBody::from_json(json_in, enc_key)?, }) } @@ -188,15 +198,14 @@ pub struct EncryptedResponse { /// JSON RPC response pub jsonrpc: String, /// id - #[serde(with = "secp_ser::string_or_u64")] - pub id: u64, + pub id: JsonId, /// result pub result: HashMap, } impl EncryptedResponse { /// from json - pub fn from_json(id: u64, json_in: &Value, enc_key: &SecretKey) -> Result { + pub fn from_json(id: &JsonId, json_in: &Value, enc_key: &SecretKey) -> Result { let mut result_set = HashMap::new(); result_set.insert( "Ok".to_string(), @@ -204,7 +213,7 @@ impl EncryptedResponse { ); Ok(EncryptedResponse { jsonrpc: "2.0".to_owned(), - id: id, + id: id.clone(), result: result_set, }) } @@ -307,12 +316,13 @@ fn encrypted_request() -> Result<(), Error> { "token": "d202964900000000d302964900000000d402964900000000d502964900000000" } }); - let enc_req = EncryptedRequest::from_json(1, &req, &shared_key)?; + let enc_req = + EncryptedRequest::from_json(&JsonId::StrId(String::from("1")), &req, &shared_key)?; println!("{:?}", enc_req); let dec_req = enc_req.decrypt(&shared_key)?; println!("{:?}", dec_req); assert_eq!(req, dec_req); - let enc_res = EncryptedResponse::from_json(1, &req, &shared_key)?; + let enc_res = EncryptedResponse::from_json(&JsonId::IntId(1), &req, &shared_key)?; println!("{:?}", enc_res); println!("{:?}", enc_res.as_json_str()?); let dec_res = enc_res.decrypt(&shared_key)?; diff --git a/controller/src/controller.rs b/controller/src/controller.rs index b7eef9ce..98fea450 100644 --- a/controller/src/controller.rs +++ b/controller/src/controller.rs @@ -26,6 +26,7 @@ use crate::util::{from_hex, static_secp_instance, to_base64, Mutex}; use failure::ResultExt; use futures::future::{err, ok}; use futures::{Future, Stream}; +use grin_wallet_api::JsonId; use grin_wallet_util::OnionV3Address; use hyper::header::HeaderValue; use hyper::{Body, Request, Response, StatusCode}; @@ -497,7 +498,7 @@ impl OwnerV3Helpers { pub fn decrypt_request( key: Arc>>, req: &serde_json::Value, - ) -> Result<(u64, serde_json::Value), serde_json::Value> { + ) -> Result<(JsonId, serde_json::Value), serde_json::Value> { let share_key_ref = key.lock(); let shared_key = share_key_ref.as_ref().unwrap(); let enc_req: EncryptedRequest = serde_json::from_value(req.clone()).map_err(|e| { @@ -508,7 +509,7 @@ impl OwnerV3Helpers { ) .as_json_value() })?; - let id = enc_req.id; + let id = enc_req.id.clone(); let res = enc_req.decrypt(&shared_key).map_err(|e| { EncryptionErrorResponse::new(1, -32002, &format!("Decryption error: {}", e.kind())) .as_json_value() @@ -519,7 +520,7 @@ impl OwnerV3Helpers { /// Encrypt a response pub fn encrypt_response( key: Arc>>, - id: u64, + id: &JsonId, res: &serde_json::Value, ) -> Result { let share_key_ref = key.lock(); @@ -646,7 +647,7 @@ where let owner_api_s = &*api as &dyn OwnerRpcS; let mut is_init_secure_api = OwnerV3Helpers::is_init_secure_api(&val); let mut was_encrypted = false; - let mut encrypted_req_id = 0; + let mut encrypted_req_id = JsonId::StrId(String::from("")); if !is_init_secure_api { if let Err(v) = OwnerV3Helpers::check_encryption_started(key.clone()) { return ok(v); @@ -655,7 +656,7 @@ where match res { Err(e) => return ok(e), Ok(v) => { - encrypted_req_id = v.0; + encrypted_req_id = v.0.clone(); val = v.1; } } @@ -675,7 +676,7 @@ where if was_encrypted { let res = OwnerV3Helpers::encrypt_response( key.clone(), - encrypted_req_id, + &encrypted_req_id, &unencrypted_intercept, ); r = match res { diff --git a/libwallet/src/slate_versions/ser.rs b/libwallet/src/slate_versions/ser.rs index 82dfd82f..30bbc8fe 100644 --- a/libwallet/src/slate_versions/ser.rs +++ b/libwallet/src/slate_versions/ser.rs @@ -11,8 +11,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - //! Sane serialization & deserialization of cryptographic structs into hex + /// Serializes an OnionV3Address to and from hex pub mod option_ov3_serde { use serde::de::Error; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 1f55bda6..4a276fab 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -24,7 +24,7 @@ use std::sync::Arc; use std::{env, fs}; use util::{Mutex, ZeroingString}; -use grin_wallet_api::{EncryptedRequest, EncryptedResponse}; +use grin_wallet_api::{EncryptedRequest, EncryptedResponse, JsonId}; use grin_wallet_config::{GlobalWalletConfig, WalletConfig, GRIN_WALLET_DIR}; use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl}; use grin_wallet_libwallet::{NodeClient, WalletInfo, WalletInst}; @@ -371,7 +371,7 @@ where #[allow(dead_code)] pub fn send_request_enc( - sec_req_id: u64, + sec_req_id: &JsonId, internal_request_id: u32, dest: &str, req: &str, diff --git a/tests/owner_v3_init_secure.rs b/tests/owner_v3_init_secure.rs index 69432ff4..8cea0335 100644 --- a/tests/owner_v3_init_secure.rs +++ b/tests/owner_v3_init_secure.rs @@ -19,7 +19,7 @@ extern crate log; extern crate grin_wallet; -use grin_wallet_api::ECDHPubkey; +use grin_wallet_api::{ECDHPubkey, JsonId}; use grin_wallet_impls::test_framework::{self, LocalWalletClient, WalletProxy}; use clap::App; @@ -74,7 +74,13 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { // 1) Attempt to send an encrypted request before calling `init_secure_api` let req = include_str!("data/v3_reqs/retrieve_info.req.json"); - let res = send_request_enc::(1, 1, "http://127.0.0.1:33420/v3/owner", &req, &sec_key)?; + let res = send_request_enc::( + &JsonId::IntId(1), + 1, + "http://127.0.0.1:33420/v3/owner", + &req, + &sec_key, + )?; println!("RES 1: {:?}", res); assert!(res.is_err()); assert_eq!(res.unwrap_err().code, -32001); @@ -97,7 +103,7 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { // 4) A normal request, correct key let req = include_str!("data/v3_reqs/retrieve_info.req.json"); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:33420/v3/owner", &req, @@ -111,7 +117,7 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { bad_key.0[0] = 0; let req = include_str!("data/v3_reqs/retrieve_info.req.json"); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:33420/v3/owner", &req, @@ -153,7 +159,7 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { // 8) Encrypted call to `init_secure_api`, followed by re-deriving key let req = include_str!("data/v3_reqs/init_secure_api.req.json"); let res = send_request_enc( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:33420/v3/owner", &req.to_string(), @@ -167,7 +173,7 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { // 9) A normal request, with new correct key let req = include_str!("data/v3_reqs/retrieve_info.req.json"); let res = send_request_enc::( - 9, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:33420/v3/owner", &req, @@ -188,7 +194,7 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { // 11) A normal request, correct key let req = include_str!("data/v3_reqs/retrieve_info.req.json"); let res = send_request_enc::( - 11, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:33420/v3/owner", &req, @@ -207,16 +213,26 @@ fn owner_v3_init_secure() -> Result<(), grin_wallet_controller::Error> { } }) .to_string(); - let res = - send_request_enc::(12, 1, "http://127.0.0.1:33420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::IntId(12), + 1, + "http://127.0.0.1:33420/v3/owner", + &req, + &shared_key, + )?; println!("RES 12: {:?}", res); assert!(res.is_err()); assert_eq!(res.unwrap_err().code, -32601); // 13) A request which triggers an internal API error (not enough funds) let req = include_str!("data/v3_reqs/init_send_tx.req.json"); - let res = - send_request_enc::(13, 1, "http://127.0.0.1:33420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("13")), + 1, + "http://127.0.0.1:33420/v3/owner", + &req, + &shared_key, + )?; println!("RES 13: {:?}", res); assert!(res.is_err()); assert_eq!(res.unwrap_err().code, -32099); diff --git a/tests/owner_v3_lifecycle.rs b/tests/owner_v3_lifecycle.rs index 3651caf7..80930977 100644 --- a/tests/owner_v3_lifecycle.rs +++ b/tests/owner_v3_lifecycle.rs @@ -19,7 +19,7 @@ extern crate log; extern crate grin_wallet; -use grin_wallet_api::ECDHPubkey; +use grin_wallet_api::{ECDHPubkey, JsonId}; use grin_wallet_impls::test_framework::{self, LocalWalletClient, WalletProxy}; use clap::App; @@ -147,8 +147,13 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { // 2) get the top level directory, should default to ~/.grin/auto let req = include_str!("data/v3_reqs/get_top_level.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 2: {:?}", res); assert!(res.is_ok()); assert!(res.unwrap().contains("auto")); @@ -163,7 +168,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { } }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -174,8 +179,13 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { // 4) create a configuration file in top level directory let req = include_str!("data/v3_reqs/create_config.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 4: {:?}", res); assert!(res.is_ok()); let pb = PathBuf::from(format!("{}/wallet1/grin-wallet.toml", test_dir)); @@ -183,29 +193,49 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { // 5) Try and perform an operation without having a wallet open let req = include_str!("data/v3_reqs/retrieve_info.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 5: {:?}", res); assert!(res.is_err()); // 6) Create a wallet let req = include_str!("data/v3_reqs/create_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 6: {:?}", res); assert!(res.is_ok()); // 7) Try and create a wallet when one exists let req = include_str!("data/v3_reqs/create_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 7: {:?}", res); assert!(res.is_err()); // 8) Open the wallet let req = include_str!("data/v3_reqs/open_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 8: {:?}", res); assert!(res.is_ok()); let token = res.unwrap(); @@ -223,7 +253,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -245,7 +275,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -256,8 +286,13 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { // 11) Close the wallet let req = include_str!("data/v3_reqs/close_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 11: {:?}", res); assert!(res.is_ok()); @@ -274,7 +309,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -285,8 +320,13 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { // 13) Open the wallet again let req = include_str!("data/v3_reqs/open_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 13: {:?}", res); assert!(res.is_ok()); let token = res.unwrap(); @@ -303,7 +343,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { } }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -328,7 +368,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { } }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -379,21 +419,36 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { //17) Change the password let req = include_str!("data/v3_reqs/close_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 17: {:?}", res); assert!(res.is_ok()); let req = include_str!("data/v3_reqs/change_password.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 17a: {:?}", res); assert!(res.is_ok()); // 18) trying to open with old password should fail let req = include_str!("data/v3_reqs/open_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 18: {:?}", res); assert!(res.is_err()); @@ -408,7 +463,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { } }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -432,7 +487,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -455,7 +510,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -476,7 +531,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -494,7 +549,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { }); let res = send_request_enc::( - 1, + &JsonId::StrId(String::from("1")), 1, "http://127.0.0.1:43420/v3/owner", &req.to_string(), @@ -505,34 +560,59 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { // 24) Delete the wallet (close first) let req = include_str!("data/v3_reqs/close_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; assert!(res.is_ok()); let req = include_str!("data/v3_reqs/delete_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 24: {:?}", res); assert!(res.is_ok()); // 25) Wallet should be gone let req = include_str!("data/v3_reqs/open_wallet.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 25: {:?}", res); assert!(res.is_err()); // 26) Try to create a wallet with an invalid mnemonic let req = include_str!("data/v3_reqs/create_wallet_invalid_mn.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 26: {:?}", res); assert!(res.is_err()); // 27) Try to create a wallet with an valid mnemonic let req = include_str!("data/v3_reqs/create_wallet_valid_mn.req.json"); - let res = - send_request_enc::(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?; + let res = send_request_enc::( + &JsonId::StrId(String::from("1")), + 1, + "http://127.0.0.1:43420/v3/owner", + &req, + &shared_key, + )?; println!("RES 27: {:?}", res); assert!(res.is_ok());