Skip to content

Commit b50f51f

Browse files
test - replacing lockr host in javascript
1 parent c338e7e commit b50f51f

File tree

1 file changed

+63
-18
lines changed

1 file changed

+63
-18
lines changed

crates/common/src/integrations/lockr.rs

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use async_trait::async_trait;
1919
use error_stack::{Report, ResultExt};
2020
use fastly::http::{header, Method, StatusCode};
2121
use fastly::{Request, Response};
22+
use regex::Regex;
2223
use serde::Deserialize;
2324
use validator::Validate;
2425

@@ -29,7 +30,6 @@ use crate::integrations::{
2930
IntegrationEndpoint, IntegrationProxy, IntegrationRegistration,
3031
};
3132
use crate::settings::{IntegrationConfig as IntegrationConfigTrait, Settings};
32-
use crate::streaming_replacer::StreamingReplacer;
3333

3434
const LOCKR_INTEGRATION_ID: &str = "lockr";
3535

@@ -103,21 +103,24 @@ impl LockrIntegration {
103103
/// Rewrite the host variable in the Lockr SDK JavaScript.
104104
///
105105
/// Replaces the obfuscated host assignment with a direct assignment to the
106-
/// first-party API proxy endpoint.
106+
/// first-party API proxy endpoint. Uses regex to match varying obfuscation patterns.
107107
fn rewrite_sdk_host(&self, sdk_body: Vec<u8>) -> Result<Vec<u8>, Report<TrustedServerError>> {
108-
// Pattern to find: 'host': _0x3a740e(0x3d1) + _0x3a740e(0x367) + _0x3a740e(0x14e)
109-
// This is the obfuscated way Lockr sets the API host
110-
// We'll replace it with a relative URL to use the first-party proxy
111-
112-
let mut replacer = StreamingReplacer::new_single(
113-
"'host': _0x3a740e(0x3d1) + _0x3a740e(0x367) + _0x3a740e(0x14e)",
114-
"'host': '/integrations/lockr/api'",
115-
);
116-
117-
// Process the entire SDK in one chunk
118-
let processed = replacer.process_chunk(&sdk_body, true);
119-
120-
Ok(processed)
108+
// Convert bytes to string
109+
let sdk_string = String::from_utf8(sdk_body)
110+
.change_context(Self::error("SDK content is not valid UTF-8"))?;
111+
112+
// Pattern matches: 'host': _0xABCDEF(0x123) + _0xABCDEF(0x456) + _0xABCDEF(0x789)
113+
// This is the obfuscated way Lockr constructs the API host
114+
// The function names and hex values change with each build, so we use regex
115+
let pattern = Regex::new(
116+
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]+\)",
117+
)
118+
.change_context(Self::error("Failed to compile regex pattern"))?;
119+
120+
// Replace with first-party API proxy endpoint
121+
let rewritten = pattern.replace(&sdk_string, "'host': '/integrations/lockr/api'");
122+
123+
Ok(rewritten.as_bytes().to_vec())
121124
}
122125

123126
/// Handle SDK serving - fetch from Lockr CDN and serve through first-party domain.
@@ -551,8 +554,8 @@ mod tests {
551554
};
552555
let integration = LockrIntegration::new(config);
553556

554-
// Mock obfuscated SDK JavaScript with the host pattern
555-
let mock_sdk = r#"
557+
// Mock obfuscated SDK JavaScript with the host pattern (old pattern)
558+
let mock_sdk_old = r#"
556559
const identityLockr = {
557560
'host': _0x3a740e(0x3d1) + _0x3a740e(0x367) + _0x3a740e(0x14e),
558561
'app_id': null,
@@ -562,7 +565,7 @@ const identityLockr = {
562565
};
563566
"#;
564567

565-
let result = integration.rewrite_sdk_host(mock_sdk.as_bytes().to_vec());
568+
let result = integration.rewrite_sdk_host(mock_sdk_old.as_bytes().to_vec());
566569
assert!(result.is_ok());
567570

568571
let rewritten = String::from_utf8(result.unwrap()).unwrap();
@@ -578,6 +581,48 @@ const identityLockr = {
578581
assert!(rewritten.contains("'firstPartyCookies': []"));
579582
}
580583

584+
#[test]
585+
fn test_sdk_host_rewriting_real_pattern() {
586+
let config = LockrConfig {
587+
enabled: true,
588+
app_id: "test-app-id".to_string(),
589+
api_endpoint: default_api_endpoint(),
590+
sdk_url: default_sdk_url(),
591+
cache_ttl_seconds: 3600,
592+
rewrite_sdk: true,
593+
rewrite_sdk_host: true,
594+
};
595+
let integration = LockrIntegration::new(config);
596+
597+
// Real obfuscated SDK JavaScript from actual Lockr SDK
598+
let mock_sdk_real = r#"
599+
const identityLockr = {
600+
'host': _0x4ed951(0xcb) + _0x4ed951(0x173) + _0x4ed951(0x1c2),
601+
'app_id': null,
602+
'expiryDateKeys': localStorage['getItem']('identityLockr_expiryDateKeys') ? JSON['parse'](localStorage['getItem']('identityLockr_expiryDateKeys')) : [],
603+
'firstPartyCookies': [],
604+
'canRefreshToken': !![]
605+
};
606+
"#;
607+
608+
let result = integration.rewrite_sdk_host(mock_sdk_real.as_bytes().to_vec());
609+
assert!(result.is_ok());
610+
611+
let rewritten = String::from_utf8(result.unwrap()).unwrap();
612+
613+
// Verify the host was rewritten to the proxy endpoint
614+
assert!(rewritten.contains("'host': '/integrations/lockr/api'"));
615+
616+
// Verify the obfuscated pattern was removed
617+
assert!(!rewritten.contains("_0x4ed951(0xcb)"));
618+
assert!(!rewritten.contains("_0x4ed951(0x173)"));
619+
assert!(!rewritten.contains("_0x4ed951(0x1c2)"));
620+
621+
// Verify other parts of the code remain intact
622+
assert!(rewritten.contains("'app_id': null"));
623+
assert!(rewritten.contains("'firstPartyCookies': []"));
624+
}
625+
581626
#[test]
582627
fn test_sdk_host_rewriting_disabled() {
583628
let config = LockrConfig {

0 commit comments

Comments
 (0)