Goblin: generic browser User-Agent for Tor HTTP, drop duplicate UA
Replace the "goblin-wallet" User-Agent on every Tor-carried request with a
common desktop-browser string so the wallet's traffic is not trivially
classifiable as Goblin at the destination. The default lives in one const in
the Tor client and is applied once per request; price.rs no longer passes its
own User-Agent (which sent the header twice). Also fix a stale nip05 doc
comment ("Nym mixnet" -> "Tor"). No transport change: the update check stays
on its existing clearnet path for GRIM parity.
This commit is contained in:
+4
-4
@@ -241,10 +241,10 @@ async fn fetch_rate(vs: &str) -> Option<f64> {
|
||||
"https://api.coingecko.com/api/v3/simple/price?ids=grin&vs_currencies={}",
|
||||
vs
|
||||
);
|
||||
// CoinGecko rejects requests without a User-Agent (403). A static,
|
||||
// non-identifying UA is fine over Tor.
|
||||
let headers = vec![("User-Agent".to_string(), "goblin-wallet".to_string())];
|
||||
let body = tor::http_request("GET", url, None, headers).await?;
|
||||
// CoinGecko rejects requests without a User-Agent (403); the Tor client sets a
|
||||
// browser-like default UA on every request, so we pass no extra headers here
|
||||
// (passing one again would send the header twice).
|
||||
let body = tor::http_request("GET", url, None, vec![]).await?;
|
||||
let parsed: Option<f64> = serde_json::from_str::<serde_json::Value>(&body)
|
||||
.ok()
|
||||
.and_then(|doc| doc.get("grin")?.get(vs)?.as_f64());
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
//! NIP-05 username resolution/verification and goblin.st registration,
|
||||
//! all HTTP routed through the Nym mixnet (the in-process smolmix tunnel). Nothing
|
||||
//! here touches clearnet.
|
||||
//! all HTTP routed over Tor (the in-process arti tunnel). Nothing here touches
|
||||
//! clearnet.
|
||||
|
||||
use base64::Engine;
|
||||
use nostr_sdk::{EventBuilder, JsonUtil, Keys, Kind, PublicKey, Tag, TagKind};
|
||||
|
||||
+28
-1
@@ -59,6 +59,14 @@ const TUNNEL_WAIT: Duration = Duration::from_secs(60);
|
||||
/// Redirect hops to follow before giving up.
|
||||
const MAX_REDIRECTS: usize = 5;
|
||||
|
||||
/// Default `User-Agent` for every Tor-carried HTTP request. A common desktop
|
||||
/// browser string (not "goblin-wallet"), so the wallet's traffic is not trivially
|
||||
/// classifiable as Goblin at the destination. Callers may still override it by
|
||||
/// passing their own `User-Agent` in the headers list; the endpoints Goblin talks
|
||||
/// to (GitHub API, CoinGecko, name authorities) all accept a generic UA.
|
||||
const DEFAULT_USER_AGENT: &str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \
|
||||
Chrome/131.0.0.0 Safari/537.36";
|
||||
|
||||
// --- Tor data directories -----------------------------------------------------
|
||||
|
||||
/// Base Tor data directory (`<base>/tor`).
|
||||
@@ -193,7 +201,7 @@ async fn request_once(
|
||||
.method(m)
|
||||
.uri(path)
|
||||
.header(hyper::header::HOST, host_header)
|
||||
.header(hyper::header::USER_AGENT, "goblin-wallet");
|
||||
.header(hyper::header::USER_AGENT, DEFAULT_USER_AGENT);
|
||||
for (k, v) in headers {
|
||||
req = req.header(k, v);
|
||||
}
|
||||
@@ -259,3 +267,22 @@ where
|
||||
.map_err(|e| warn!("tor http: tls handshake with {host} failed: {e}"))
|
||||
.ok()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn default_user_agent_is_browser_like_not_goblin() {
|
||||
// The default UA must read as a common desktop browser, so Goblin's Tor
|
||||
// traffic is not trivially fingerprintable at the destination.
|
||||
assert!(DEFAULT_USER_AGENT.starts_with("Mozilla/5.0"));
|
||||
assert!(DEFAULT_USER_AGENT.contains("Chrome/"));
|
||||
assert!(DEFAULT_USER_AGENT.contains("Safari/"));
|
||||
// No line-continuation whitespace leaked into the literal.
|
||||
assert!(!DEFAULT_USER_AGENT.contains(" "));
|
||||
assert!(!DEFAULT_USER_AGENT.contains('\n'));
|
||||
// The old identifying string is gone.
|
||||
assert!(!DEFAULT_USER_AGENT.to_lowercase().contains("goblin"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user