Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions walletkit-core/src/user_agent.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
//! User agent for HTTP requests.

const WORLD_APP_USER_AGENT_PRODUCT: &str = "WorldApp";
const WORLD_ID_APP_USER_AGENT_PRODUCT: &str = "WorldID";
const WORLD_ID_ANDROID_CLIENT_NAME: &str = "android-id";
const WORLD_ID_IOS_CLIENT_NAME: &str = "ios-id";

/// Represents a User-Agent string.
#[derive(Debug, Clone, uniffi::Object)]
pub struct UserAgent(pub String);
Expand All @@ -12,6 +17,15 @@ impl std::fmt::Display for UserAgent {
}
}

#[uniffi::export]
impl UserAgent {
/// Returns the header value for FFI consumers.
#[must_use]
pub fn header_value(&self) -> String {
self.0.clone()
}
}

/// Builds the [`UserAgent`] string sent as the HTTP `User-Agent` header.
///
/// Starts empty; call [`Self::with_segment`] for arbitrary `name/version` tokens and
Expand Down Expand Up @@ -41,6 +55,19 @@ impl UserAgentBuilder {
next
}

/// Appends the app product segment for the client name.
///
/// Uses `WorldID/{app_version}` for World ID app clients (`android-id` / `ios-id`),
/// and `WorldApp/{app_version}` for all other clients.
#[must_use]
pub fn with_app_segment_for_client(
&self,
app_version: &str,
client_name: &str,
) -> Self {
self.with_segment(user_agent_product_for_client(client_name), app_version)
}

/// Appends `walletkit-core/{crate version}`.
#[must_use]
pub fn with_walletkit_segment(&self) -> Self {
Expand All @@ -51,6 +78,12 @@ impl UserAgentBuilder {
next
}

/// Appends `{client_name}/{os_version}` to match the app client suffix convention.
#[must_use]
pub fn with_client_segment(&self, client_name: &str, os_version: &str) -> Self {
self.with_segment(client_name, os_version)
}

/// Finalizes the header value as [`UserAgent`].
#[must_use]
pub fn build(&self) -> UserAgent {
Expand All @@ -64,6 +97,15 @@ impl Default for UserAgentBuilder {
}
}

fn user_agent_product_for_client(client_name: &str) -> &'static str {
match client_name {
WORLD_ID_ANDROID_CLIENT_NAME | WORLD_ID_IOS_CLIENT_NAME => {
WORLD_ID_APP_USER_AGENT_PRODUCT
}
_ => WORLD_APP_USER_AGENT_PRODUCT,
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -96,7 +138,57 @@ mod tests {
concat!("walletkit-core/", env!("CARGO_PKG_VERSION"), " CLI/1.2.3");
"walletkit_then_cli"
)]
#[test_case(
&UserAgentBuilder::new()
.with_app_segment_for_client("4.0.2500", "android")
.with_walletkit_segment()
.with_client_segment("android", "15"),
concat!("WorldApp/4.0.2500 walletkit-core/", env!("CARGO_PKG_VERSION"), " android/15");
"world_app_android_client"
)]
#[test_case(
&UserAgentBuilder::new()
.with_app_segment_for_client("4.0.2500", "ios")
.with_walletkit_segment()
.with_client_segment("ios", "26.4.2"),
concat!("WorldApp/4.0.2500 walletkit-core/", env!("CARGO_PKG_VERSION"), " ios/26.4.2");
"world_app_ios_client"
)]
#[test_case(
&UserAgentBuilder::new()
.with_app_segment_for_client("1.0.100", "android-id")
.with_walletkit_segment()
.with_client_segment("android-id", "15"),
concat!("WorldID/1.0.100 walletkit-core/", env!("CARGO_PKG_VERSION"), " android-id/15");
"world_id_android_client"
)]
#[test_case(
&UserAgentBuilder::new()
.with_app_segment_for_client("1.0.100", "ios-id")
.with_walletkit_segment()
.with_client_segment("ios-id", "26.4.2"),
concat!("WorldID/1.0.100 walletkit-core/", env!("CARGO_PKG_VERSION"), " ios-id/26.4.2");
"world_id_ios_client"
)]
fn user_agent_builder_expected(builder: &UserAgentBuilder, expected: &'static str) {
assert_eq!(builder.build().to_string(), expected);
}

#[test]
fn user_agent_exposes_header_value_for_ffi_consumers() {
let user_agent = UserAgentBuilder::new()
.with_app_segment_for_client("1.0.100", "android-id")
.with_walletkit_segment()
.with_client_segment("android-id", "15")
.build();

assert_eq!(
user_agent.header_value(),
concat!(
"WorldID/1.0.100 walletkit-core/",
env!("CARGO_PKG_VERSION"),
" android-id/15"
)
);
}
}
Loading