Skip to content
Merged
Show file tree
Hide file tree
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
39 changes: 13 additions & 26 deletions crates/trusted-server-core/src/integrations/datadome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
//! automatically rewrite `DataDome` script URLs in HTML responses:
//!
//! - `<script src="https://js.datadome.co/tags.js">` becomes
//! `<script src="https://publisher.com/integrations/datadome/tags.js">`
//! `<script src="/integrations/datadome/tags.js">`
//! - Handles both `src` and `href` attributes (for preload/prefetch links)

use std::sync::{Arc, LazyLock};
Expand Down Expand Up @@ -803,7 +803,7 @@ impl IntegrationAttributeRewriter for DataDomeIntegration {
&self,
_attr_name: &str,
attr_value: &str,
ctx: &IntegrationAttributeContext<'_>,
_ctx: &IntegrationAttributeContext<'_>,
) -> AttributeRewriteAction {
// Check if this is a DataDome script URL
let is_datadome =
Expand All @@ -814,10 +814,12 @@ impl IntegrationAttributeRewriter for DataDomeIntegration {
}

let path = Self::extract_datadome_path(attr_value);
let new_url = format!(
"{}://{}/integrations/datadome{}",
ctx.request_scheme, ctx.request_host, path
);
// Root-relative so the browser resolves it against the page host.
// Note: a page-level `<base href>` participates in this resolution, so
// on pages that set an external base URL these resolve against that base
// rather than the address-bar origin — an accepted tradeoff, matching
// GTM/Didomi/Testlight which are also relative.
let new_url = format!("/integrations/datadome{path}");

log::info!(
"[datadome] Rewriting script src from {} to {}",
Expand Down Expand Up @@ -1328,10 +1330,7 @@ mod tests {
let action = integration.rewrite("src", "https://js.datadome.co/tags.js", &ctx);
match action {
AttributeRewriteAction::Replace(new_url) => {
assert_eq!(
new_url,
"https://publisher.com/integrations/datadome/tags.js"
);
assert_eq!(new_url, "/integrations/datadome/tags.js");
}
_ => panic!("Expected Replace action"),
}
Expand All @@ -1340,10 +1339,7 @@ mod tests {
let action = integration.rewrite("href", "https://js.datadome.co/tags.js", &ctx);
match action {
AttributeRewriteAction::Replace(new_url) => {
assert_eq!(
new_url,
"https://publisher.com/integrations/datadome/tags.js"
);
assert_eq!(new_url, "/integrations/datadome/tags.js");
}
_ => panic!("Expected Replace action for href"),
}
Expand All @@ -1368,10 +1364,7 @@ mod tests {
let action = integration.rewrite("src", "https://js.datadome.co/js/check", &ctx);
match action {
AttributeRewriteAction::Replace(new_url) => {
assert_eq!(
new_url,
"https://publisher.com/integrations/datadome/js/check"
);
assert_eq!(new_url, "/integrations/datadome/js/check");
}
_ => panic!("Expected Replace action"),
}
Expand All @@ -1380,10 +1373,7 @@ mod tests {
let action = integration.rewrite("href", "//js.datadome.co/js/signal", &ctx);
match action {
AttributeRewriteAction::Replace(new_url) => {
assert_eq!(
new_url,
"https://publisher.com/integrations/datadome/js/signal"
);
assert_eq!(new_url, "/integrations/datadome/js/signal");
}
_ => panic!("Expected Replace action for protocol-relative URL"),
}
Expand All @@ -1392,10 +1382,7 @@ mod tests {
let action = integration.rewrite("src", "https://js.datadome.co", &ctx);
match action {
AttributeRewriteAction::Replace(new_url) => {
assert_eq!(
new_url,
"https://publisher.com/integrations/datadome/tags.js"
);
assert_eq!(new_url, "/integrations/datadome/tags.js");
}
_ => panic!("Expected Replace action for bare domain"),
}
Expand Down
16 changes: 9 additions & 7 deletions crates/trusted-server-core/src/integrations/gpt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,17 +435,19 @@ impl IntegrationAttributeRewriter for GptIntegration {
&self,
_attr_name: &str,
attr_value: &str,
ctx: &IntegrationAttributeContext<'_>,
_ctx: &IntegrationAttributeContext<'_>,
) -> AttributeRewriteAction {
if !self.config.rewrite_script {
return AttributeRewriteAction::keep();
}

if Self::is_gpt_script_url(attr_value) {
AttributeRewriteAction::replace(format!(
"{}://{}/integrations/gpt/script",
ctx.request_scheme, ctx.request_host
))
// Root-relative so the browser resolves it against the page host.
// Note: a page-level `<base href>` participates in this resolution,
// so on pages that set an external base URL these resolve against
// that base rather than the address-bar origin — an accepted
// tradeoff, matching GTM/Didomi/Testlight which are also relative.
AttributeRewriteAction::replace("/integrations/gpt/script".to_string())
Comment thread
aram356 marked this conversation as resolved.
} else {
AttributeRewriteAction::keep()
}
Expand Down Expand Up @@ -587,8 +589,8 @@ mod tests {
match result {
AttributeRewriteAction::Replace(url) => {
assert_eq!(
url, "https://edge.example.com/integrations/gpt/script",
"should rewrite to first-party script endpoint"
url, "/integrations/gpt/script",
"should rewrite to root-relative first-party script endpoint"
);
}
other => panic!("Expected Replace action, got {:?}", other),
Expand Down
18 changes: 9 additions & 9 deletions crates/trusted-server-core/src/integrations/lockr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,17 +412,19 @@ impl IntegrationAttributeRewriter for LockrIntegration {
&self,
_attr_name: &str,
attr_value: &str,
ctx: &IntegrationAttributeContext<'_>,
_ctx: &IntegrationAttributeContext<'_>,
) -> AttributeRewriteAction {
if !self.config.rewrite_sdk {
return AttributeRewriteAction::Keep;
}

if self.is_lockr_sdk_url(attr_value) {
let replacement = format!(
"{}://{}/integrations/lockr/sdk",
ctx.request_scheme, ctx.request_host
);
// Root-relative so the browser resolves it against the page host.
// Note: a page-level `<base href>` participates in this resolution,
// so on pages that set an external base URL these resolve against
// that base rather than the address-bar origin — an accepted
// tradeoff, matching GTM/Didomi/Testlight which are also relative.
let replacement = "/integrations/lockr/sdk".to_string();
log::debug!("Rewriting Lockr SDK URL to {}", replacement);
AttributeRewriteAction::Replace(replacement)
} else {
Expand Down Expand Up @@ -532,10 +534,8 @@ mod tests {

assert_eq!(
result,
AttributeRewriteAction::Replace(
"https://edge.example.com/integrations/lockr/sdk".to_string()
),
"should rewrite Lockr SDK URL to first-party proxy"
AttributeRewriteAction::Replace("/integrations/lockr/sdk".to_string()),
"should rewrite Lockr SDK URL to root-relative first-party proxy"
);
}

Expand Down
16 changes: 9 additions & 7 deletions crates/trusted-server-core/src/integrations/permutive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,18 +425,20 @@ impl IntegrationAttributeRewriter for PermutiveIntegration {
&self,
_attr_name: &str,
attr_value: &str,
ctx: &IntegrationAttributeContext<'_>,
_ctx: &IntegrationAttributeContext<'_>,
) -> AttributeRewriteAction {
if !self.config.rewrite_sdk {
return AttributeRewriteAction::keep();
}

if self.is_permutive_sdk_url(attr_value) {
// Rewrite to first-party SDK endpoint
AttributeRewriteAction::replace(format!(
"{}://{}/integrations/permutive/sdk",
ctx.request_scheme, ctx.request_host
))
// Rewrite to first-party SDK endpoint.
// Root-relative so the browser resolves it against the page host.
// Note: a page-level `<base href>` participates in this resolution,
// so on pages that set an external base URL these resolve against
// that base rather than the address-bar origin — an accepted
// tradeoff, matching GTM/Didomi/Testlight which are also relative.
AttributeRewriteAction::replace("/integrations/permutive/sdk".to_string())
} else {
AttributeRewriteAction::keep()
}
Expand Down Expand Up @@ -547,7 +549,7 @@ mod tests {

assert!(matches!(rewritten, AttributeRewriteAction::Replace(_)));
if let AttributeRewriteAction::Replace(url) = rewritten {
assert_eq!(url, "https://edge.example.com/integrations/permutive/sdk");
assert_eq!(url, "/integrations/permutive/sdk");
}
}

Expand Down
22 changes: 10 additions & 12 deletions crates/trusted-server-core/src/integrations/sourcepoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,7 @@ impl SourcepointIntegration {
Ok(target.to_string())
}

fn build_first_party_url(
&self,
source_url: &str,
ctx: &IntegrationAttributeContext<'_>,
) -> Option<String> {
fn build_first_party_url(&self, source_url: &str) -> Option<String> {
let parsed = parse_sourcepoint_url(source_url)?;
if parsed.host_str()? != SOURCEPOINT_CDN_HOST {
return None;
Expand All @@ -301,10 +297,12 @@ impl SourcepointIntegration {
.map(|value| format!("?{value}"))
.unwrap_or_default();

Some(format!(
"{}://{}{}{}{}",
ctx.request_scheme, ctx.request_host, SOURCEPOINT_CDN_PREFIX, path, query
))
// Root-relative so the browser resolves it against the page host.
// Note: a page-level `<base href>` participates in this resolution, so
// on pages that set an external base URL these resolve against that base
// rather than the address-bar origin — an accepted tradeoff, matching
// GTM/Didomi/Testlight which are also relative.
Some(format!("{SOURCEPOINT_CDN_PREFIX}{path}{query}"))
}

fn copy_headers(
Expand Down Expand Up @@ -851,11 +849,11 @@ impl IntegrationAttributeRewriter for SourcepointIntegration {
&self,
_attr_name: &str,
attr_value: &str,
ctx: &IntegrationAttributeContext<'_>,
_ctx: &IntegrationAttributeContext<'_>,
) -> AttributeRewriteAction {
// `handles_attribute()` already gates on `rewrite_sdk`, so this
// method is only called when rewriting is enabled.
if let Some(rewritten) = self.build_first_party_url(attr_value, ctx) {
if let Some(rewritten) = self.build_first_party_url(attr_value) {
return AttributeRewriteAction::replace(rewritten);
}

Expand Down Expand Up @@ -986,7 +984,7 @@ mod tests {
assert_eq!(
rewritten,
AttributeRewriteAction::replace(
"https://edge.example.com/integrations/sourcepoint/cdn/mms/v2/get_site_data?account_id=821",
"/integrations/sourcepoint/cdn/mms/v2/get_site_data?account_id=821",
)
);
}
Expand Down
Loading