mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(client-info): address review edge cases
Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@buzz.block.builderlab.xyz> Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@buzz.block.builderlab.xyz>
This commit is contained in:
parent
b5d067036e
commit
94db169622
@@ -35,8 +35,18 @@ impl ClientInfo {
|
||||
/// counter and also returns `None`, so it can never reject a request.
|
||||
#[must_use]
|
||||
pub fn from_headers(headers: &HeaderMap) -> Option<Self> {
|
||||
let value = headers.get("buzz-client")?;
|
||||
let parsed = value.to_str().ok().and_then(|raw| Self::parse(raw).ok());
|
||||
let all_values = headers.get_all("buzz-client");
|
||||
let mut values = all_values.iter();
|
||||
let first = values.next()?;
|
||||
let parsed = (|| {
|
||||
let mut raw = first.to_str().map_err(|_| ())?.to_owned();
|
||||
for value in values {
|
||||
raw.push_str(", ");
|
||||
raw.push_str(value.to_str().map_err(|_| ())?);
|
||||
}
|
||||
Self::parse(&raw)
|
||||
})()
|
||||
.ok();
|
||||
if parsed.is_none() {
|
||||
metrics::counter!("buzz_client_header_parse_failures_total").increment(1);
|
||||
}
|
||||
@@ -265,6 +275,43 @@ mod tests {
|
||||
assert_eq!(parse_failures(&recorder), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn joins_multiple_header_lines_before_parsing() {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.append(
|
||||
"buzz-client",
|
||||
HeaderValue::from_static(r#"v=1, app=buzz-mobile, platform=ios, app-version="0.4.5""#),
|
||||
);
|
||||
headers.append(
|
||||
"buzz-client",
|
||||
HeaderValue::from_static(r#"app-build="6", os-version="18.5""#),
|
||||
);
|
||||
|
||||
let client = ClientInfo::from_headers(&headers).expect("valid combined header");
|
||||
assert_eq!(client.app_version, "0.4.5");
|
||||
assert_eq!(client.app_build, "6");
|
||||
assert_eq!(client.os_version, "18.5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_non_utf8_in_any_header_line() {
|
||||
let recorder = DebuggingRecorder::new();
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.append(
|
||||
"buzz-client",
|
||||
HeaderValue::from_static(r#"v=1, app=buzz-mobile, platform=ios, app-version="0.4.5""#),
|
||||
);
|
||||
headers.append(
|
||||
"buzz-client",
|
||||
HeaderValue::from_bytes(&[0xff]).expect("opaque test header value"),
|
||||
);
|
||||
|
||||
metrics::with_local_recorder(&recorder, || {
|
||||
assert_eq!(ClientInfo::from_headers(&headers), None);
|
||||
});
|
||||
assert_eq!(parse_failures(&recorder), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn malformed_or_semantically_invalid_header_is_absent_and_counted() {
|
||||
for raw in [
|
||||
|
||||
@@ -131,6 +131,8 @@ class InviteJoinNotifier extends Notifier<InviteJoinState> {
|
||||
...clientHeadersForUrl(
|
||||
headers: ref.read(clientHeadersProvider),
|
||||
targetUrl: url,
|
||||
// Explicit confirmation makes the invite relay the user's
|
||||
// intended first-party destination for this claim.
|
||||
relayUrl: invite.relayUrl,
|
||||
),
|
||||
'Authorization': buildNip98AuthHeader(
|
||||
|
||||
@@ -57,7 +57,8 @@ class MediaGetAuthService {
|
||||
);
|
||||
final uri = Uri.tryParse(url);
|
||||
final relayUri = Uri.tryParse(_baseUrl);
|
||||
if (uri == null || relayUri == null) return const {};
|
||||
if (uri == null) return const {};
|
||||
if (relayUri == null) return identificationHeaders;
|
||||
if (!_isRelayMediaUrl(uri, relayUri)) return identificationHeaders;
|
||||
|
||||
final nsec = _nsec;
|
||||
|
||||
@@ -102,6 +102,38 @@ void main() {
|
||||
expect(headers, isNot(contains('Authorization')));
|
||||
});
|
||||
|
||||
test('sends only User-Agent when the relay base URL is malformed', () {
|
||||
const clientHeaders = ClientHeaders(
|
||||
appVersion: '1.0',
|
||||
buzzClient: 'test-client',
|
||||
userAgent: 'test-agent',
|
||||
);
|
||||
final auth = MediaGetAuthService(
|
||||
baseUrl: '://',
|
||||
nsec: nostr.Keys.generate().nsec,
|
||||
clientHeaders: clientHeaders,
|
||||
);
|
||||
|
||||
expect(
|
||||
auth.headersFor('https://cdn.cloudflare.example/attachments/abc.png'),
|
||||
{'User-Agent': 'test-agent'},
|
||||
);
|
||||
});
|
||||
|
||||
test('malformed target URL gets no headers', () {
|
||||
const clientHeaders = ClientHeaders(
|
||||
appVersion: '1.0',
|
||||
buzzClient: 'test-client',
|
||||
userAgent: 'test-agent',
|
||||
);
|
||||
final auth = _auth(
|
||||
nsec: nostr.Keys.generate().nsec,
|
||||
clientHeaders: clientHeaders,
|
||||
);
|
||||
|
||||
expect(auth.headersFor('://'), isEmpty);
|
||||
});
|
||||
|
||||
test('sends identification without a signing key', () {
|
||||
const clientHeaders = ClientHeaders(
|
||||
appVersion: '1.0',
|
||||
|
||||
Reference in New Issue
Block a user