From c2f1452806a88ee9b5015fbd992a9de72dad60c6 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 3 Mar 2026 09:51:23 -0500 Subject: [PATCH 1/3] Update Lockr integration to use dedicated trust-server SDK Lockr now provides a pre-configured SDK (identity-lockr-trust-server.js) that routes API calls through the first-party proxy out of the box. This eliminates the need for fragile runtime regex rewriting of obfuscated host assignments in the SDK JavaScript. - Update default sdk_url to identity-lockr-trust-server.js - Remove rewrite_sdk_host config field, regex method, and related tests - Simplify handle_sdk_serving to serve SDK as-is (no host rewriting) - Fix operator precedence in is_lockr_sdk_url (clarity, no behavioral change) - Add debug logging to attribute rewriter for diagnosing rewrite issues - Extract test helpers, add trust-server URL detection test --- crates/common/src/integrations/lockr.rs | 416 +++++++----------------- trusted-server.toml | 2 +- 2 files changed, 113 insertions(+), 305 deletions(-) diff --git a/crates/common/src/integrations/lockr.rs b/crates/common/src/integrations/lockr.rs index 29576e01..88d52fce 100644 --- a/crates/common/src/integrations/lockr.rs +++ b/crates/common/src/integrations/lockr.rs @@ -3,15 +3,9 @@ //! This module provides transparent proxying for Lockr's SDK and API, //! enabling first-party identity resolution while maintaining privacy controls. //! -//! ## Host Rewriting -//! -//! The integration can rewrite the Lockr SDK JavaScript to replace the hardcoded -//! API host with a relative URL pointing to the first-party proxy. This ensures -//! all API calls from the SDK go through the trusted server instead of directly -//! to Lockr's servers, improving privacy and enabling additional controls. -//! -//! The rewriting finds the obfuscated host assignment pattern in the SDK and -//! replaces it with: `'host': '/integrations/lockr/api'` +//! Lockr provides a dedicated trust-server SDK (`identity-lockr-trust-server.js`) +//! that is pre-configured to route API calls through the first-party proxy, +//! so no runtime rewriting of the SDK JavaScript is needed. use std::sync::Arc; @@ -19,7 +13,6 @@ use async_trait::async_trait; use error_stack::{Report, ResultExt}; use fastly::http::{header, Method, StatusCode}; use fastly::{Request, Response}; -use regex::Regex; use serde::Deserialize; use validator::Validate; @@ -50,7 +43,7 @@ pub struct LockrConfig { #[validate(url)] pub api_endpoint: String, - /// SDK URL (default: ) + /// SDK URL (default: ) #[serde(default = "default_sdk_url")] #[validate(url)] pub sdk_url: String, @@ -64,10 +57,6 @@ pub struct LockrConfig { #[serde(default = "default_rewrite_sdk")] pub rewrite_sdk: bool, - /// Whether to rewrite the host variable in the Lockr SDK JavaScript - #[serde(default = "default_rewrite_sdk_host")] - pub rewrite_sdk_host: bool, - /// Override the Origin header sent to Lockr API. /// Use this when running locally or from a domain not registered with Lockr. /// Example: "" @@ -103,48 +92,22 @@ impl LockrIntegration { fn is_lockr_sdk_url(&self, url: &str) -> bool { let lower = url.to_ascii_lowercase(); lower.contains("aim.loc.kr") - || lower.contains("identity.loc.kr") + || (lower.contains("identity.loc.kr") && lower.contains("identity-lockr") - && lower.ends_with(".js") - } - - /// Rewrite the host variable in the Lockr SDK JavaScript. - /// - /// Replaces the obfuscated host assignment with a direct assignment to the - /// first-party API proxy endpoint. Uses regex to match varying obfuscation patterns. - fn rewrite_sdk_host(&self, sdk_body: Vec) -> Result, Report> { - // Convert bytes to string - let sdk_string = String::from_utf8(sdk_body) - .change_context(Self::error("SDK content is not valid UTF-8"))?; - - // Pattern matches: 'host': _0xABCDEF(0x123) + _0xABCDEF(0x456) + _0xABCDEF(0x789) - // This is the obfuscated way Lockr constructs the API host - // The function names and hex values change with each build, so we use regex - let pattern = Regex::new( - r"'host':\s*_0x[a-f0-9]+\(0x[a-f0-9]+\)\s*\+\s*_0x[a-f0-9]+\(0x[a-f0-9]+\)\s*\+\s*_0x[a-f0-9]+\(0x[a-f0-9]+\)", - ) - .change_context(Self::error("Failed to compile regex pattern"))?; - - // Replace with first-party API proxy endpoint - let rewritten = pattern.replace(&sdk_string, "'host': '/integrations/lockr/api'"); - - Ok(rewritten.as_bytes().to_vec()) + && lower.ends_with(".js")) } - /// Handle SDK serving - fetch from Lockr CDN and serve through first-party domain. + /// Handle SDK serving — fetch from Lockr CDN and serve through first-party domain. async fn handle_sdk_serving( &self, _settings: &Settings, _req: Request, ) -> Result> { - log::info!("Handling Lockr SDK request"); - let sdk_url = &self.config.sdk_url; - log::info!("Fetching Lockr SDK from: {}", sdk_url); + log::info!("Fetching Lockr SDK from {}", sdk_url); // TODO: Check KV store cache first (future enhancement) - // Fetch SDK from Lockr CDN let mut lockr_req = Request::new(Method::GET, sdk_url); lockr_req.set_header(header::USER_AGENT, "TrustedServer/1.0"); lockr_req.set_header(header::ACCEPT, "application/javascript, */*"); @@ -162,7 +125,7 @@ impl LockrIntegration { if !lockr_response.get_status().is_success() { log::error!( - "Lockr SDK fetch failed with status: {}", + "Lockr SDK fetch failed with status {}", lockr_response.get_status() ); return Err(Report::new(Self::error(format!( @@ -171,14 +134,8 @@ impl LockrIntegration { )))); } - let mut sdk_body = lockr_response.take_body_bytes(); - log::info!("Successfully fetched Lockr SDK: {} bytes", sdk_body.len()); - - // Rewrite the host variable in the SDK if enabled - if self.config.rewrite_sdk_host { - sdk_body = self.rewrite_sdk_host(sdk_body)?; - log::info!("Rewrote SDK host variable: {} bytes", sdk_body.len()); - } + let sdk_body = lockr_response.take_body_bytes(); + log::info!("Fetched Lockr SDK ({} bytes)", sdk_body.len()); // TODO: Cache in KV store (future enhancement) @@ -193,14 +150,10 @@ impl LockrIntegration { ) .with_header("X-Lockr-SDK-Proxy", "true") .with_header("X-SDK-Source", sdk_url) - .with_header( - "X-Lockr-Host-Rewritten", - self.config.rewrite_sdk_host.to_string(), - ) .with_body(sdk_body)) } - /// Handle API proxy - forward requests to identity.lockr.kr. + /// Handle API proxy — forward requests to identity.lockr.kr. async fn handle_api_proxy( &self, _settings: &Settings, @@ -211,13 +164,12 @@ impl LockrIntegration { log::info!("Proxying Lockr API request: {} {}", method, original_path); - // Extract path after /integrations/lockr/api and pass through directly - // This allows the Lockr SDK to use any API endpoint without hardcoded mappings + // Extract path after /integrations/lockr/api and pass through directly. + // This allows the Lockr SDK to use any API endpoint without hardcoded mappings. let target_path = original_path .strip_prefix("/integrations/lockr/api") .ok_or_else(|| Self::error(format!("Invalid Lockr API path: {}", original_path)))?; - // Build full target URL with query parameters let query = req .get_url() .query() @@ -227,19 +179,14 @@ impl LockrIntegration { log::info!("Forwarding to Lockr API: {}", target_url); - // Create new request let mut target_req = Request::new(method.clone(), &target_url); - - // Copy headers self.copy_request_headers(&req, &mut target_req); - // Copy body for POST/PUT/PATCH if matches!(method, &Method::POST | &Method::PUT | &Method::PATCH) { let body = req.take_body(); target_req.set_body(body); } - // Get backend and forward let backend_name = BackendConfig::from_url(&self.config.api_endpoint, true) .change_context(Self::error("Failed to determine backend for API proxy"))?; @@ -255,7 +202,7 @@ impl LockrIntegration { } }; - log::info!("Lockr API responded with status: {}", response.get_status()); + log::info!("Lockr API responded with status {}", response.get_status()); Ok(response) } @@ -278,7 +225,7 @@ impl LockrIntegration { } } - // Handle Origin header - use override if configured, otherwise forward original + // Use origin override if configured, otherwise forward original let origin = self .config .origin_override @@ -288,7 +235,6 @@ impl LockrIntegration { to.set_header(header::ORIGIN, origin); } - // Copy any X-* custom headers, skipping TS-internal headers copy_custom_headers(from, to); } } @@ -310,6 +256,10 @@ fn build(settings: &Settings) -> Option> { #[must_use] pub fn register(settings: &Settings) -> Option { let integration = build(settings)?; + log::info!( + "Registering Lockr integration (rewrite_sdk={})", + integration.config.rewrite_sdk + ); Some( IntegrationRegistration::builder(LOCKR_INTEGRATION_ID) .with_proxy(integration.clone()) @@ -364,22 +314,30 @@ impl IntegrationAttributeRewriter for LockrIntegration { ctx: &IntegrationAttributeContext<'_>, ) -> AttributeRewriteAction { if !self.config.rewrite_sdk { + log::debug!("[lockr] Rewrite skipped, rewrite_sdk is disabled"); return AttributeRewriteAction::Keep; } - if self.is_lockr_sdk_url(attr_value) { - // Rewrite to first-party SDK endpoint - AttributeRewriteAction::Replace(format!( + let is_lockr = self.is_lockr_sdk_url(attr_value); + log::debug!( + "[lockr] Rewrite check: value={:?}, is_lockr_sdk={}", + attr_value, + is_lockr + ); + + if is_lockr { + let replacement = format!( "{}://{}/integrations/lockr/sdk", ctx.request_scheme, ctx.request_host - )) + ); + log::debug!("[lockr] Rewriting SDK URL to {}", replacement); + AttributeRewriteAction::Replace(replacement) } else { AttributeRewriteAction::Keep } } } -// Default value functions fn default_enabled() -> bool { true } @@ -389,41 +347,49 @@ fn default_api_endpoint() -> String { } fn default_sdk_url() -> String { - "https://aim.loc.kr/identity-lockr-v1.0.js".to_string() + "https://aim.loc.kr/identity-lockr-trust-server.js".to_string() } fn default_cache_ttl() -> u32 { - 3600 // 1 hour + 3600 } fn default_rewrite_sdk() -> bool { true } -fn default_rewrite_sdk_host() -> bool { - true -} - #[cfg(test)] mod tests { use super::*; - #[test] - fn test_lockr_sdk_url_detection() { - let config = LockrConfig { + fn test_config() -> LockrConfig { + LockrConfig { enabled: true, app_id: "test-app-id".to_string(), api_endpoint: default_api_endpoint(), sdk_url: default_sdk_url(), cache_ttl_seconds: 3600, rewrite_sdk: true, - rewrite_sdk_host: true, origin_override: None, - }; - let integration = LockrIntegration::new(config); + } + } + + fn test_context() -> IntegrationAttributeContext<'static> { + IntegrationAttributeContext { + attribute_name: "src", + request_host: "edge.example.com", + request_scheme: "https", + origin_host: "origin.example.com", + } + } + + #[test] + fn test_lockr_sdk_url_detection() { + let integration = LockrIntegration::new(test_config()); // Should match Lockr SDK URLs assert!(integration.is_lockr_sdk_url("https://aim.loc.kr/identity-lockr-v1.0.js")); + assert!(integration.is_lockr_sdk_url("https://aim.loc.kr/identity-lockr-trust-server.js")); assert!(integration.is_lockr_sdk_url("https://identity.loc.kr/identity-lockr-v2.0.js")); // Should not match other URLs @@ -432,77 +398,55 @@ mod tests { #[test] fn test_attribute_rewriter_rewrites_sdk_urls() { - let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: true, - rewrite_sdk_host: true, - origin_override: None, - }; - let integration = LockrIntegration::new(config); + let integration = LockrIntegration::new(test_config()); + let ctx = test_context(); - let ctx = IntegrationAttributeContext { - attribute_name: "src", - request_host: "edge.example.com", - request_scheme: "https", - origin_host: "origin.example.com", - }; + let result = integration.rewrite("src", "https://aim.loc.kr/identity-lockr-v1.0.js", &ctx); - let rewritten = - integration.rewrite("src", "https://aim.loc.kr/identity-lockr-v1.0.js", &ctx); + assert_eq!( + result, + AttributeRewriteAction::Replace( + "https://edge.example.com/integrations/lockr/sdk".to_string() + ), + "should rewrite Lockr SDK URL to first-party proxy" + ); + } - match rewritten { - AttributeRewriteAction::Replace(url) => { - assert_eq!(url, "https://edge.example.com/integrations/lockr/sdk"); - } - _ => panic!("Expected Replace action"), - } + #[test] + fn test_attribute_rewriter_keeps_non_lockr_urls() { + let integration = LockrIntegration::new(test_config()); + let ctx = test_context(); + + let result = integration.rewrite("src", "https://example.com/other.js", &ctx); + + assert_eq!( + result, + AttributeRewriteAction::Keep, + "should keep non-Lockr URLs unchanged" + ); } #[test] fn test_attribute_rewriter_noop_when_disabled() { let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: false, // Disabled - rewrite_sdk_host: true, - origin_override: None, + rewrite_sdk: false, + ..test_config() }; let integration = LockrIntegration::new(config); + let ctx = test_context(); - let ctx = IntegrationAttributeContext { - attribute_name: "src", - request_host: "edge.example.com", - request_scheme: "https", - origin_host: "origin.example.com", - }; - - let rewritten = - integration.rewrite("src", "https://aim.loc.kr/identity-lockr-v1.0.js", &ctx); + let result = integration.rewrite("src", "https://aim.loc.kr/identity-lockr-v1.0.js", &ctx); - assert_eq!(rewritten, AttributeRewriteAction::Keep); - } - - #[test] - fn test_api_path_extraction_with_camel_case() { - // Test that we properly extract paths with correct casing - let path = "/integrations/lockr/api/publisher/app/v1/identityLockr/settings"; - let extracted = path - .strip_prefix("/integrations/lockr/api") - .expect("should strip prefix"); - assert_eq!(extracted, "/publisher/app/v1/identityLockr/settings"); + assert_eq!( + result, + AttributeRewriteAction::Keep, + "should keep all URLs when rewrite_sdk is disabled" + ); } #[test] fn test_api_path_extraction_preserves_casing() { - // Test various Lockr API endpoints maintain their original casing - let test_cases = vec![ + let test_cases = [ ( "/integrations/lockr/api/publisher/app/v1/identityLockr/settings", "/publisher/app/v1/identityLockr/settings", @@ -521,174 +465,38 @@ mod tests { let result = input .strip_prefix("/integrations/lockr/api") .expect("should strip prefix"); - assert_eq!(result, expected, "Failed for input: {}", input); + assert_eq!( + result, expected, + "should preserve casing for path: {}", + input + ); } } #[test] fn test_routes_registered() { - let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: true, - rewrite_sdk_host: true, - origin_override: None, - }; - let integration = LockrIntegration::new(config); - + let integration = LockrIntegration::new(test_config()); let routes = integration.routes(); - assert_eq!(routes.len(), 3); - - // Verify SDK route - assert!(routes - .iter() - .any(|r| r.path == "/integrations/lockr/sdk" && r.method == Method::GET)); - - // Verify API routes (GET and POST) - assert!(routes - .iter() - .any(|r| r.path == "/integrations/lockr/api/*" && r.method == Method::POST)); - assert!(routes - .iter() - .any(|r| r.path == "/integrations/lockr/api/*" && r.method == Method::GET)); - } - - #[test] - fn test_sdk_host_rewriting() { - let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: true, - rewrite_sdk_host: true, - origin_override: None, - }; - let integration = LockrIntegration::new(config); - - // Mock obfuscated SDK JavaScript with the host pattern (old pattern) - let mock_sdk_old = r#" -const identityLockr = { - 'host': _0x3a740e(0x3d1) + _0x3a740e(0x367) + _0x3a740e(0x14e), - 'app_id': null, - 'expiryDateKeys': localStorage['getItem']('identityLockr_expiryDateKeys') ? JSON['parse'](localStorage['getItem']('identityLockr_expiryDateKeys')) : [], - 'firstPartyCookies': [], - 'canRefreshToken': !![] -}; - "#; - - let result = integration.rewrite_sdk_host(mock_sdk_old.as_bytes().to_vec()); - assert!(result.is_ok()); - - let rewritten = String::from_utf8(result.expect("should rewrite SDK host")) - .expect("should be valid UTF-8"); - - // Verify the host was rewritten to the proxy endpoint - assert!(rewritten.contains("'host': '/integrations/lockr/api'")); - - // Verify the obfuscated pattern was removed - assert!(!rewritten.contains("_0x3a740e(0x3d1) + _0x3a740e(0x367) + _0x3a740e(0x14e)")); - - // Verify other parts of the code remain intact - assert!(rewritten.contains("'app_id': null")); - assert!(rewritten.contains("'firstPartyCookies': []")); - } - - #[test] - fn test_sdk_host_rewriting_real_pattern() { - let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: true, - rewrite_sdk_host: true, - origin_override: None, - }; - let integration = LockrIntegration::new(config); - - // Real obfuscated SDK JavaScript from actual Lockr SDK - let mock_sdk_real = r#" -const identityLockr = { - 'host': _0x4ed951(0xcb) + _0x4ed951(0x173) + _0x4ed951(0x1c2), - 'app_id': null, - 'expiryDateKeys': localStorage['getItem']('identityLockr_expiryDateKeys') ? JSON['parse'](localStorage['getItem']('identityLockr_expiryDateKeys')) : [], - 'firstPartyCookies': [], - 'canRefreshToken': !![] -}; - "#; - - let result = integration.rewrite_sdk_host(mock_sdk_real.as_bytes().to_vec()); - assert!(result.is_ok()); - - let rewritten = String::from_utf8(result.expect("should rewrite SDK host")) - .expect("should be valid UTF-8"); - - // Verify the host was rewritten to the proxy endpoint - assert!(rewritten.contains("'host': '/integrations/lockr/api'")); - - // Verify the obfuscated pattern was removed - assert!(!rewritten.contains("_0x4ed951(0xcb)")); - assert!(!rewritten.contains("_0x4ed951(0x173)")); - assert!(!rewritten.contains("_0x4ed951(0x1c2)")); - - // Verify other parts of the code remain intact - assert!(rewritten.contains("'app_id': null")); - assert!(rewritten.contains("'firstPartyCookies': []")); - } - - #[test] - fn test_sdk_host_rewriting_disabled() { - let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: true, - rewrite_sdk_host: false, // Disabled - origin_override: None, - }; - - // When rewrite_sdk_host is false, the handle_sdk_serving function - // won't call rewrite_sdk_host at all, so the SDK is served as-is - assert!(!config.rewrite_sdk_host); - } - - #[test] - fn test_sdk_host_rewriting_no_match() { - let config = LockrConfig { - enabled: true, - app_id: "test-app-id".to_string(), - api_endpoint: default_api_endpoint(), - sdk_url: default_sdk_url(), - cache_ttl_seconds: 3600, - rewrite_sdk: true, - rewrite_sdk_host: true, - origin_override: None, - }; - let integration = LockrIntegration::new(config); - - // Test with SDK that doesn't have the expected pattern - let mock_sdk = r#" -const identityLockr = { - 'host': 'https://example.com', - 'app_id': null -}; - "#; - - let result = integration.rewrite_sdk_host(mock_sdk.as_bytes().to_vec()); - assert!(result.is_ok()); - - let rewritten = String::from_utf8(result.expect("should rewrite SDK host")) - .expect("should be valid UTF-8"); - // When pattern doesn't match, content should be unchanged - assert!(rewritten.contains("'host': 'https://example.com'")); + assert_eq!(routes.len(), 3, "should register 3 routes"); + + assert!( + routes + .iter() + .any(|r| r.path == "/integrations/lockr/sdk" && r.method == Method::GET), + "should register SDK GET route" + ); + assert!( + routes + .iter() + .any(|r| r.path == "/integrations/lockr/api/*" && r.method == Method::POST), + "should register API POST route" + ); + assert!( + routes + .iter() + .any(|r| r.path == "/integrations/lockr/api/*" && r.method == Method::GET), + "should register API GET route" + ); } } diff --git a/trusted-server.toml b/trusted-server.toml index 0c0a6f7e..b146f163 100644 --- a/trusted-server.toml +++ b/trusted-server.toml @@ -80,7 +80,7 @@ secure_signals_endpoint = "https://secure-signals.permutive.app" enabled = false app_id = "" api_endpoint = "https://identity.loc.kr" -sdk_url = "https://aim.loc.kr/identity-lockr-v1.0.js" +sdk_url = "https://aim.loc.kr/identity-lockr-trust-server.js" cache_ttl_seconds = 3600 rewrite_sdk = true From 6f4077ac9668cec73eee26a88ed93daf10c70e94 Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 9 Mar 2026 13:30:26 -0500 Subject: [PATCH 2/3] Address PR review feedback for Lockr SDK update --- crates/common/src/integrations/lockr.rs | 59 ++++++++++++++++++------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/crates/common/src/integrations/lockr.rs b/crates/common/src/integrations/lockr.rs index 88d52fce..f3bef355 100644 --- a/crates/common/src/integrations/lockr.rs +++ b/crates/common/src/integrations/lockr.rs @@ -38,7 +38,7 @@ pub struct LockrConfig { #[validate(length(min = 1))] pub app_id: String, - /// Base URL for Lockr API (default: ) + /// Base URL for Lockr API (default: ) #[serde(default = "default_api_endpoint")] #[validate(url)] pub api_endpoint: String, @@ -57,6 +57,11 @@ pub struct LockrConfig { #[serde(default = "default_rewrite_sdk")] pub rewrite_sdk: bool, + /// Deprecated — the trust-server SDK handles host routing natively. + /// Kept for backwards compatibility so existing configs don't cause parse errors. + #[serde(default)] + pub rewrite_sdk_host: Option, + /// Override the Origin header sent to Lockr API. /// Use this when running locally or from a domain not registered with Lockr. /// Example: "" @@ -91,10 +96,9 @@ impl LockrIntegration { /// Check if a URL is a Lockr SDK URL. fn is_lockr_sdk_url(&self, url: &str) -> bool { let lower = url.to_ascii_lowercase(); - lower.contains("aim.loc.kr") - || (lower.contains("identity.loc.kr") - && lower.contains("identity-lockr") - && lower.ends_with(".js")) + (lower.contains("aim.loc.kr") || lower.contains("identity.loc.kr")) + && lower.contains("identity-lockr") + && lower.ends_with(".js") } /// Handle SDK serving — fetch from Lockr CDN and serve through first-party domain. @@ -149,11 +153,12 @@ impl LockrIntegration { format!("public, max-age={}", self.config.cache_ttl_seconds), ) .with_header("X-Lockr-SDK-Proxy", "true") + .with_header("X-Lockr-SDK-Mode", "trust-server") .with_header("X-SDK-Source", sdk_url) .with_body(sdk_body)) } - /// Handle API proxy — forward requests to identity.lockr.kr. + /// Handle API proxy — forward requests to identity.loc.kr. async fn handle_api_proxy( &self, _settings: &Settings, @@ -256,6 +261,12 @@ fn build(settings: &Settings) -> Option> { #[must_use] pub fn register(settings: &Settings) -> Option { let integration = build(settings)?; + if integration.config.rewrite_sdk_host.is_some() { + log::warn!( + "lockr: `rewrite_sdk_host` is deprecated and ignored; \ + the trust-server SDK handles host routing natively" + ); + } log::info!( "Registering Lockr integration (rewrite_sdk={})", integration.config.rewrite_sdk @@ -318,14 +329,7 @@ impl IntegrationAttributeRewriter for LockrIntegration { return AttributeRewriteAction::Keep; } - let is_lockr = self.is_lockr_sdk_url(attr_value); - log::debug!( - "[lockr] Rewrite check: value={:?}, is_lockr_sdk={}", - attr_value, - is_lockr - ); - - if is_lockr { + if self.is_lockr_sdk_url(attr_value) { let replacement = format!( "{}://{}/integrations/lockr/sdk", ctx.request_scheme, ctx.request_host @@ -343,7 +347,7 @@ fn default_enabled() -> bool { } fn default_api_endpoint() -> String { - "https://identity.lockr.kr".to_string() + "https://identity.loc.kr".to_string() } fn default_sdk_url() -> String { @@ -370,6 +374,7 @@ mod tests { sdk_url: default_sdk_url(), cache_ttl_seconds: 3600, rewrite_sdk: true, + rewrite_sdk_host: None, origin_override: None, } } @@ -392,8 +397,30 @@ mod tests { assert!(integration.is_lockr_sdk_url("https://aim.loc.kr/identity-lockr-trust-server.js")); assert!(integration.is_lockr_sdk_url("https://identity.loc.kr/identity-lockr-v2.0.js")); + // Should not match non-SDK resources on Lockr domains + assert!( + !integration.is_lockr_sdk_url("https://aim.loc.kr/pixel.gif"), + "should not match non-JS assets on aim.loc.kr" + ); + assert!( + !integration.is_lockr_sdk_url("https://aim.loc.kr/styles.css"), + "should not match CSS files on aim.loc.kr" + ); + // Should not match other URLs - assert!(!integration.is_lockr_sdk_url("https://example.com/script.js")); + assert!( + !integration.is_lockr_sdk_url("https://example.com/script.js"), + "should not match unrelated domains" + ); + } + + #[test] + fn test_default_sdk_url_uses_trust_server() { + let url = default_sdk_url(); + assert!( + url.contains("trust-server"), + "should use the trust-server SDK variant by default" + ); } #[test] From df8ca54aa487129a08ad4bac1d8134fedbddc6cc Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 10 Mar 2026 11:45:22 -0500 Subject: [PATCH 3/3] Address remaining review feedback: clean up dead code, logs, and tests - Remove unreachable debug log from rewrite() guard (handles_attribute gates first) - Drop inconsistent [lockr] prefix from debug log to match file conventions - Fix hardcoded domain in doc comment to reference configured endpoint - Add negative test for non-SDK .js files on identity.loc.kr --- crates/common/src/integrations/lockr.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/common/src/integrations/lockr.rs b/crates/common/src/integrations/lockr.rs index f3bef355..a2268526 100644 --- a/crates/common/src/integrations/lockr.rs +++ b/crates/common/src/integrations/lockr.rs @@ -158,7 +158,7 @@ impl LockrIntegration { .with_body(sdk_body)) } - /// Handle API proxy — forward requests to identity.loc.kr. + /// Handle API proxy — forward requests to the configured Lockr API endpoint. async fn handle_api_proxy( &self, _settings: &Settings, @@ -325,7 +325,6 @@ impl IntegrationAttributeRewriter for LockrIntegration { ctx: &IntegrationAttributeContext<'_>, ) -> AttributeRewriteAction { if !self.config.rewrite_sdk { - log::debug!("[lockr] Rewrite skipped, rewrite_sdk is disabled"); return AttributeRewriteAction::Keep; } @@ -334,7 +333,7 @@ impl IntegrationAttributeRewriter for LockrIntegration { "{}://{}/integrations/lockr/sdk", ctx.request_scheme, ctx.request_host ); - log::debug!("[lockr] Rewriting SDK URL to {}", replacement); + log::debug!("Rewriting Lockr SDK URL to {}", replacement); AttributeRewriteAction::Replace(replacement) } else { AttributeRewriteAction::Keep @@ -406,6 +405,10 @@ mod tests { !integration.is_lockr_sdk_url("https://aim.loc.kr/styles.css"), "should not match CSS files on aim.loc.kr" ); + assert!( + !integration.is_lockr_sdk_url("https://identity.loc.kr/some-other-script.js"), + "should not match non-SDK JS files on identity.loc.kr" + ); // Should not match other URLs assert!(