diff --git a/Cargo.lock b/Cargo.lock index 4b2ea2a33..60da709f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4641,6 +4641,7 @@ dependencies = [ "rand_core 0.6.4", "safelog", "serde", + "serde_json", "thiserror", "tor-async-utils", "tor-basic-utils", @@ -4674,6 +4675,7 @@ dependencies = [ "rand 0.8.5", "sec1", "serde", + "serde_json", "ssh-key", "tempfile", "thiserror", diff --git a/crates/tor-hsservice/Cargo.toml b/crates/tor-hsservice/Cargo.toml index 3912455c6..3006e60b0 100644 --- a/crates/tor-hsservice/Cargo.toml +++ b/crates/tor-hsservice/Cargo.toml @@ -61,4 +61,5 @@ void = "1" [dev-dependencies] humantime = "2" +serde_json = "1.0.104" tor-rtmock = { path = "../tor-rtmock", version = "0.9.0" } diff --git a/crates/tor-hsservice/src/nickname.rs b/crates/tor-hsservice/src/nickname.rs index 51eb8b220..3dd78754f 100644 --- a/crates/tor-hsservice/src/nickname.rs +++ b/crates/tor-hsservice/src/nickname.rs @@ -1,6 +1,7 @@ //! `HsNickname` module itself is private, but `HsNickname` etc. are re-exported use derive_more::{Display, From, Into}; +use serde::{Deserialize, Serialize}; use thiserror::Error; use tor_keymgr::ArtiPathComponent; @@ -19,6 +20,8 @@ use tor_keymgr::ArtiPathComponent; /// (These are the same rules as [`tor_keymgr::ArtiPathComponent`] #[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] #[derive(Display, From, Into)] +#[derive(Serialize, Deserialize)] +#[serde(try_from = "String", into = "String")] pub struct HsNickname(ArtiPathComponent); /// Local nickname for Tor Hidden Service (`.onion` service) was syntactically invalid @@ -85,4 +88,22 @@ mod test { assert_eq!(HsNickname::new("_c".into()), Err(InvalidNickname {})); assert_eq!(&HsNickname::new("x".into()).unwrap().to_string(), "x"); } + + #[test] + fn serde() { + // TODO HSS clone-and-hack with tor_keymgr::::key_specifier::test::serde + #[derive(Serialize, Deserialize, Debug)] + struct T { + n: HsNickname, + } + let j = serde_json::from_str(r#"{ "n": "x" }"#).unwrap(); + let t: T = serde_json::from_value(j).unwrap(); + assert_eq!(&t.n.to_string(), "x"); + + assert_eq!(&serde_json::to_string(&t).unwrap(), r#"{"n":"x"}"#); + + let j = serde_json::from_str(r#"{ "n": "!" }"#).unwrap(); + let e = serde_json::from_value::(j).unwrap_err(); + assert!(e.to_string().contains("Invalid syntax"), "wrong msg {e:?}"); + } } diff --git a/crates/tor-keymgr/Cargo.toml b/crates/tor-keymgr/Cargo.toml index ba70168c2..51f6921b3 100644 --- a/crates/tor-keymgr/Cargo.toml +++ b/crates/tor-keymgr/Cargo.toml @@ -51,6 +51,7 @@ tor-llcrypto = { path = "../tor-llcrypto", version = "0.5.2", features = ["keymg zeroize = "1" [dev-dependencies] +serde_json = "1.0.104" tempfile = "3" tor-basic-utils = { path = "../tor-basic-utils", version = "0.7.3" } diff --git a/crates/tor-keymgr/semver.md b/crates/tor-keymgr/semver.md index b1c29478b..4bfd62705 100644 --- a/crates/tor-keymgr/semver.md +++ b/crates/tor-keymgr/semver.md @@ -6,3 +6,4 @@ BREAKING: ssh-key is bumped to 0.6.0 (we re-export `ssh_key`) ADDED: ArtiPathComponent is TryFrom ADDED: ArtiPathComponent is AsRef ADDED: ArtiPathComponent is Hash, Eq, PartialEq, Ord, PartialOrd +ADDED: ArtiPathComponent is Serialize, Deserialize diff --git a/crates/tor-keymgr/src/key_specifier.rs b/crates/tor-keymgr/src/key_specifier.rs index 0627470e8..5c49df575 100644 --- a/crates/tor-keymgr/src/key_specifier.rs +++ b/crates/tor-keymgr/src/key_specifier.rs @@ -2,6 +2,7 @@ use crate::Result; use derive_more::{Deref, DerefMut, Display, Into}; +use serde::{Deserialize, Serialize}; use tor_error::internal; /// The path of a key in the Arti key store. @@ -50,6 +51,8 @@ impl ArtiPath { Clone, Debug, derive_more::Deref, derive_more::DerefMut, derive_more::Into, derive_more::Display, )] #[derive(Hash, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Serialize, Deserialize)] +#[serde(try_from = "String", into = "String")] pub struct ArtiPathComponent(String); impl ArtiPathComponent { @@ -206,4 +209,26 @@ mod test { check_valid!(ArtiPath, &path, true); check_valid!(ArtiPathComponent, &path, false); } + + #[test] + fn serde() { + // TODO HSS clone-and-hack with tor_hsservice::::nickname::test::serde + // perhaps there should be some utility in tor-basic-utils for testing + // validated string newtypes, or something + #[derive(Serialize, Deserialize, Debug)] + struct T { + n: ArtiPathComponent, + } + let j = serde_json::from_str(r#"{ "n": "x" }"#).unwrap(); + let t: T = serde_json::from_value(j).unwrap(); + assert_eq!(&t.n.to_string(), "x"); + + assert_eq!(&serde_json::to_string(&t).unwrap(), r#"{"n":"x"}"#); + + let j = serde_json::from_str(r#"{ "n": "!" }"#).unwrap(); + let e = serde_json::from_value::(j).unwrap_err(); + // TODO HSS this is the wrong error message, this might not be a bug; + // it could be bad config or something + assert!(e.to_string().contains("internal error"), "wrong msg {e:?}"); + } }