commit eb59dfdd3ee94792c9638ae17a61c83b99805d27
parent 6820aa55412b4d6822ebdd72a902a067e9e5865f
Author: triesap <triesap@radroots.dev>
Date: Tue, 6 Jan 2026 16:43:27 +0000
nip46: accept single relay values in connect URLs
- allow relay param to be string or list
- normalize relay values into a clean Vec<String>
- keep bunker and nostrconnect parsing consistent
- preserve existing perms and metadata parsing
Diffstat:
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1871,6 +1871,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
+ "serde_qs",
"thiserror 1.0.69",
"tokio",
"tracing",
@@ -2226,6 +2227,17 @@ dependencies = [
]
[[package]]
+name = "serde_qs"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0431a35568651e363364210c91983c1da5eb29404d9f0928b67d4ebcfa7d330c"
+dependencies = [
+ "percent-encoding",
+ "serde",
+ "thiserror 1.0.69",
+]
+
+[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/transport/jsonrpc/nip46/connection.rs b/src/transport/jsonrpc/nip46/connection.rs
@@ -24,8 +24,15 @@ pub struct Nip46ConnectInfo {
}
#[derive(Debug, Deserialize)]
+#[serde(untagged)]
+enum RelayParam {
+ One(String),
+ Many(Vec<String>),
+}
+
+#[derive(Debug, Deserialize)]
struct Nip46ConnectQuery {
- relay: Option<Vec<String>>,
+ relay: Option<RelayParam>,
secret: Option<String>,
perms: Option<String>,
name: Option<String>,
@@ -47,7 +54,7 @@ fn parse_bunker_url(url: &Url) -> Result<Nip46ConnectInfo, RpcError> {
let query: Nip46ConnectQuery =
serde_qs::from_str(url.query().unwrap_or_default())
.map_err(|e| RpcError::InvalidParams(e.to_string()))?;
- let relays = query.relay.unwrap_or_default();
+ let relays = relay_list(query.relay);
let perms = parse_perms(query.perms);
Ok(Nip46ConnectInfo {
@@ -73,7 +80,7 @@ fn parse_nostrconnect_url(url: &Url) -> Result<Nip46ConnectInfo, RpcError> {
let query: Nip46ConnectQuery =
serde_qs::from_str(url.query().unwrap_or_default())
.map_err(|e| RpcError::InvalidParams(e.to_string()))?;
- let relays = query.relay.unwrap_or_default();
+ let relays = relay_list(query.relay);
let perms = parse_perms(query.perms);
Ok(Nip46ConnectInfo {
@@ -97,3 +104,16 @@ fn parse_perms(perms: Option<String>) -> Vec<String> {
.filter(|entry| !entry.is_empty())
.collect()
}
+
+fn relay_list(relay: Option<RelayParam>) -> Vec<String> {
+ let relays = match relay {
+ Some(RelayParam::One(value)) => vec![value],
+ Some(RelayParam::Many(values)) => values,
+ None => Vec::new(),
+ };
+ relays
+ .into_iter()
+ .map(|value| value.trim().to_string())
+ .filter(|value| !value.is_empty())
+ .collect()
+}