Skip to content

updating to DataDome Fastly Module 2.25.0 #750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 10, 2025
Merged

Conversation

lriberon
Copy link
Contributor

updating to DataDome Fastly Module 2.25.0

lriberon and others added 2 commits June 26, 2025 18:18
* Append surrogate keys instead of replacing them

* Append surrogate keys instead of replacing them

* Changes needed to follow the syntax of PHP 8.4

* Updated composer.json PHP constraint

* Adapt surrogate keys only on outermost Fastly node

* Update etc/vcl_snippets/fetch.vcl

Co-authored-by: Kevin P. Fleming <[email protected]>

* Update datacenters.json

* removed WAF button

* Bump 1.2.224

* Update Netacea integration to 5.10.6

* Update F_MitSvc hostname

* Additional variable check

* Bump 1.2.225

* Update netacea_integration.json to 5.10.7

* Update datacenters.json

* Bump 1.2.226

* Implemented method which uses bulk update API for ACLs, use this logic for IP list update in fastly:maintenance command

* Bump 1.2.227

* Bump 1.2.228

* Update datacenters.json

* Fixes issue: fastly#745

* Bump 1.2.229

* updating to DataDome Fastly Module 2.25.0

---------

Co-authored-by: Mark J. Becker <[email protected]>
Co-authored-by: ivanviduka <[email protected]>
Co-authored-by: Kevin P. Fleming <[email protected]>
Co-authored-by: github-actions <vvuksan [email protected]>
Co-authored-by: Domagoj Potkoc <[email protected]>
Co-authored-by: Katsuyuki Omuro <[email protected]>
Co-authored-by: Richard Walkden <[email protected]>
Co-authored-by: Jonathan Abela <[email protected]>
@rcaril
Copy link
Contributor

rcaril commented Jul 8, 2025

Hi @lriberon - we'll review on our side.

If possible, please provide a list update of changes in text along with PRs going forward to help speed up our review process.

@rcaril
Copy link
Contributor

rcaril commented Jul 8, 2025

Notes provided by DD team:

2.25.0 (2025-06-17)
Exclude requests from DataDome protection when including a x-datadome-skip-detection header with the request ID (see FAQ section)
2.24.3 (2025-06-09)
Unset conflicting enriched headers from client requests to prevent unintended overrides of DataDome empty value
2.24.2 (2025-02-14)
Add new static file extensions to default exclusion regex
Increase first_byte_timeout to 300ms to align with the configuration of other integrations

@@ -76,12 +76,12 @@
"vcl": [
{
"priority": 7,
"template": "sub set_origin_header {\n if (req.backend.is_origin) {\n if (req.backend == datadome) {\n # Remove all unexpected headers\n header.filter_except(bereq, \"x-datadome-params\", \"accept-charset\", \"accept-language\", \"x-requested-with\", \"x-fl-productid\", \"x-flapi-session-id\", \"fastly-orig-accept-encoding\", \"cache-control\", \"client-id\", \"connection\", \"pragma\", \"accept\", \"headers-list\", \"host\", \"origin\", \"server-hostname\", \"server-name\", \"x-forwarded-for\", \"user-agent\", \"referer\", \"request\", \"content-type\", \"from\", \"true-client-ip\", \"via\", \"x-real-ip\", \"sec-ch-device-memory\", \"sec-ch-ua\", \"sec-ch-ua-arch\", \"sec-ch-ua-full-version-list\", \"sec-ch-ua-mobile\", \"sec-ch-ua-model\", \"sec-ch-ua-platform\", \"sec-fetch-dest\", \"sec-fetch-mode\", \"sec-fetch-site\", \"sec-fetch-user\");\n set bereq.http.x-datadome-params:key = \"{{datadome_api_key}}\";\n set bereq.http.x-datadome-params:requestmodulename = \"FastlyMagento\";\n set bereq.http.x-datadome-params:moduleversion = \"2.24.1\";\n set bereq.http.x-datadome-params:timerequest = time.start.usec;\n set bereq.http.x-datadome-params:servername = server.identity;\n set bereq.http.x-datadome-params:serverregion = server.region;\n set bereq.http.x-datadome-params:ip = urlencode(client.ip);\n set bereq.http.x-forwarded-proto = urlencode(req.protocol);\n set bereq.http.x-datadome-params:authorizationlen = std.strlen(req.http.authorization);\n # Truncating Headers - Start\n set bereq.http.accept-charset = substr(req.http.accept-charset, 0, 128);\n set bereq.http.accept-language = substr(req.http.accept-language, 0, 256);\n set bereq.http.x-requested-with = substr(req.http.x-requested-with, 0, 128);\n set bereq.http.x-fl-productid = substr(req.http.x-fl-productid, 0, 64);\n set bereq.http.x-flapi-session-id = substr(req.http.x-flapi-session-id, 0, 64);\n set bereq.http.fastly-orig-accept-encoding = substr(req.http.fastly-orig-accept-encoding, 0, 128);\n set bereq.http.cache-control = substr(req.http.cache-control, 0, 128);\n set bereq.http.client-id = substr(req.http.client-id, 0, 128);\n set bereq.http.connection = substr(req.http.connection, 0, 128);\n set bereq.http.pragma = substr(req.http.pragma, 0, 128);\n set bereq.http.accept = substr(req.http.accept, 0, 512);\n set bereq.http.headers-list = substr(req.http.headers-list, 0, 512);\n set bereq.http.host = substr(req.http.host, 0, 512);\n set bereq.http.origin = substr(req.http.origin, 0, 512);\n set bereq.http.server-hostname = substr(req.http.server-hostname, 0, 512);\n set bereq.http.server-name = substr(req.http.server-name, 0, 512);\n if( std.strlen(req.http.x-forwarded-for) \u003e 512 ) {\n # Truncate from the end\n set bereq.http.x-forwarded-for = substr(req.http.x-forwarded-for, -512);\n } else {\n set bereq.http.x-forwarded-for = req.http.x-forwarded-for;\n }\n set bereq.http.user-agent = substr(req.http.user-agent, 0, 768);\n set bereq.http.referer = substr(req.http.referer, 0, 1024);\n set bereq.http.request = substr(req.http.request, 0, 2048);\n set bereq.http.content-type = substr(req.http.content-type, 0, 64);\n set bereq.http.from = substr(req.http.from, 0, 128);\n set bereq.http.true-client-ip = substr(req.http.true-client-ip, 0, 128);\n set bereq.http.via = substr(req.http.via, 0, 256);\n set bereq.http.x-real-ip = substr(req.http.x-real-ip, 0, 128);\n set bereq.http.sec-ch-device-memory = substr(req.http.sec-ch-device-memory, 0, 8);\n set bereq.http.sec-ch-ua = substr(req.http.sec-ch-ua, 0, 128);\n set bereq.http.sec-ch-ua-arch = substr(req.http.sec-ch-ua-arch, 0, 16);\n set bereq.http.sec-ch-ua-full-version-list = substr(req.http.sec-ch-ua-full-version-list, 0, 256);\n set bereq.http.sec-ch-ua-mobile = substr(req.http.sec-ch-ua-mobile, 0, 8);\n set bereq.http.sec-ch-ua-model = substr(req.http.sec-ch-ua-model, 0, 128);\n set bereq.http.sec-ch-ua-platform = substr(req.http.sec-ch-ua-platform, 0, 32);\n set bereq.http.sec-fetch-dest = substr(req.http.sec-fetch-dest, 0, 32);\n set bereq.http.sec-fetch-mode = substr(req.http.sec-fetch-mode, 0, 32);\n set bereq.http.sec-fetch-site = substr(req.http.sec-fetch-site, 0, 64);\n set bereq.http.sec-fetch-user = substr(req.http.sec-fetch-user, 0, 8);\n # Truncating Headers - End\n if (req.http.x-datadome-clientid) {\n set bereq.http.x-datadome-params:clientid = urlencode(substr(req.http.x-datadome-clientid, 0, 128));\n set bereq.http.x-datadome-x-set-cookie = \"true\";\n } else {\n set bereq.http.x-datadome-params:clientid = urlencode(substr(req.http.cookie:datadome, 0, 128));\n }\n set bereq.http.x-datadome-params:cookieslen = std.strlen(req.http.cookie);\n # enforce gzip encoding between Fastly and DataDome\n set bereq.http.accept-encoding = \"gzip\";\n # disable ng-waf inspection on DataDome requests\n set bereq.http.x-sigsci-no-inspection = \"true\";\n } else {\n # prevent leak of the key\n unset bereq.http.x-datadome-params;\n }\n }\n}\n\nbackend datadome {\n .host = \"api-fastly.datadome.co\";\n .port = \"8443\";\n .max_tls_version = \"1.3\";\n .min_tls_version = \"1.2\";\n .connect_timeout = {{datadome_connect_timeout}}ms;\n .first_byte_timeout = {{datadome_between_bytes_timeout}}ms;\n .between_bytes_timeout = {{datadome_between_bytes_timeout}}ms;\n .max_connections = 200;\n .ssl = true;\n .dynamic = true;\n .probe = {\n .request = \"HEAD /.well-known/healthcheck-datadome HTTP/1.1\" \"Host: api-fastly.datadome.co\" \"Connection: close\" \"User-Agent: Varnish/fastly (healthcheck)\";\n .expected_response = 200;\n .initial = 5;\n .interval = 2s;\n .threshold = 1;\n .timeout = 2s;\n .window = 5;\n }\n}",
"template": "sub set_origin_header {\n if (req.backend.is_origin) {\n if (req.backend == datadome) {\n # Remove all unexpected headers\n header.filter_except(bereq, \"x-datadome-params\", \"accept-charset\", \"accept-language\", \"x-requested-with\", \"x-fl-productid\", \"x-flapi-session-id\", \"fastly-orig-accept-encoding\", \"cache-control\", \"client-id\", \"connection\", \"pragma\", \"accept\", \"headers-list\", \"host\", \"origin\", \"server-hostname\", \"server-name\", \"x-forwarded-for\", \"user-agent\", \"referer\", \"request\", \"content-type\", \"from\", \"true-client-ip\", \"via\", \"x-real-ip\", \"sec-ch-device-memory\", \"sec-ch-ua\", \"sec-ch-ua-arch\", \"sec-ch-ua-full-version-list\", \"sec-ch-ua-mobile\", \"sec-ch-ua-model\", \"sec-ch-ua-platform\", \"sec-fetch-dest\", \"sec-fetch-mode\", \"sec-fetch-site\", \"sec-fetch-user\");\n set bereq.http.x-datadome-params:key = \"{{datadome_api_key}}\";\n set bereq.http.x-datadome-params:requestmodulename = \"FastlyMagento\";\n set bereq.http.x-datadome-params:moduleversion = \"2.25.0\";\n set bereq.http.x-datadome-params:timerequest = time.start.usec;\n set bereq.http.x-datadome-params:servername = server.identity;\n set bereq.http.x-datadome-params:serverregion = server.region;\n set bereq.http.x-datadome-params:ip = urlencode(client.ip);\n set bereq.http.x-forwarded-proto = urlencode(req.protocol);\n set bereq.http.x-datadome-params:authorizationlen = std.strlen(req.http.authorization);\n # Truncating Headers - Start\n set bereq.http.accept-charset = substr(req.http.accept-charset, 0, 128);\n set bereq.http.accept-language = substr(req.http.accept-language, 0, 256);\n set bereq.http.x-requested-with = substr(req.http.x-requested-with, 0, 128);\n set bereq.http.x-fl-productid = substr(req.http.x-fl-productid, 0, 64);\n set bereq.http.x-flapi-session-id = substr(req.http.x-flapi-session-id, 0, 64);\n set bereq.http.fastly-orig-accept-encoding = substr(req.http.fastly-orig-accept-encoding, 0, 128);\n set bereq.http.cache-control = substr(req.http.cache-control, 0, 128);\n set bereq.http.client-id = substr(req.http.client-id, 0, 128);\n set bereq.http.connection = substr(req.http.connection, 0, 128);\n set bereq.http.pragma = substr(req.http.pragma, 0, 128);\n set bereq.http.accept = substr(req.http.accept, 0, 512);\n set bereq.http.headers-list = substr(req.http.headers-list, 0, 512);\n set bereq.http.host = substr(req.http.host, 0, 512);\n set bereq.http.origin = substr(req.http.origin, 0, 512);\n set bereq.http.server-hostname = substr(req.http.server-hostname, 0, 512);\n set bereq.http.server-name = substr(req.http.server-name, 0, 512);\n if( std.strlen(req.http.x-forwarded-for) \u003e 512 ) {\n # Truncate from the end\n set bereq.http.x-forwarded-for = substr(req.http.x-forwarded-for, -512);\n } else {\n set bereq.http.x-forwarded-for = req.http.x-forwarded-for;\n }\n set bereq.http.user-agent = substr(req.http.user-agent, 0, 768);\n set bereq.http.referer = substr(req.http.referer, 0, 1024);\n set bereq.http.request = substr(req.http.request, 0, 2048);\n set bereq.http.content-type = substr(req.http.content-type, 0, 64);\n set bereq.http.from = substr(req.http.from, 0, 128);\n set bereq.http.true-client-ip = substr(req.http.true-client-ip, 0, 128);\n set bereq.http.via = substr(req.http.via, 0, 256);\n set bereq.http.x-real-ip = substr(req.http.x-real-ip, 0, 128);\n set bereq.http.sec-ch-device-memory = substr(req.http.sec-ch-device-memory, 0, 8);\n set bereq.http.sec-ch-ua = substr(req.http.sec-ch-ua, 0, 128);\n set bereq.http.sec-ch-ua-arch = substr(req.http.sec-ch-ua-arch, 0, 16);\n set bereq.http.sec-ch-ua-full-version-list = substr(req.http.sec-ch-ua-full-version-list, 0, 256);\n set bereq.http.sec-ch-ua-mobile = substr(req.http.sec-ch-ua-mobile, 0, 8);\n set bereq.http.sec-ch-ua-model = substr(req.http.sec-ch-ua-model, 0, 128);\n set bereq.http.sec-ch-ua-platform = substr(req.http.sec-ch-ua-platform, 0, 32);\n set bereq.http.sec-fetch-dest = substr(req.http.sec-fetch-dest, 0, 32);\n set bereq.http.sec-fetch-mode = substr(req.http.sec-fetch-mode, 0, 32);\n set bereq.http.sec-fetch-site = substr(req.http.sec-fetch-site, 0, 64);\n set bereq.http.sec-fetch-user = substr(req.http.sec-fetch-user, 0, 8);\n # Truncating Headers - End\n if (req.http.x-datadome-clientid) {\n set bereq.http.x-datadome-params:clientid = urlencode(substr(req.http.x-datadome-clientid, 0, 128));\n set bereq.http.x-datadome-x-set-cookie = \"true\";\n } else {\n set bereq.http.x-datadome-params:clientid = urlencode(substr(req.http.cookie:datadome, 0, 128));\n }\n set bereq.http.x-datadome-params:cookieslen = std.strlen(req.http.cookie);\n # enforce gzip encoding between Fastly and DataDome\n set bereq.http.accept-encoding = \"gzip\";\n # disable ng-waf inspection on DataDome requests\n set bereq.http.x-sigsci-no-inspection = \"true\";\n } else {\n # prevent leak of the key\n unset bereq.http.x-datadome-params;\n }\n }\n}\n\nbackend datadome {\n .host = \"api-fastly.datadome.co\";\n .port = \"8443\";\n .max_tls_version = \"1.3\";\n .min_tls_version = \"1.2\";\n .connect_timeout = {{datadome_connect_timeout}}ms;\n .first_byte_timeout = {{datadome_first_byte_timeout}}ms;\n .between_bytes_timeout = {{datadome_between_bytes_timeout}}ms;\n .max_connections = 200;\n .ssl = true;\n .dynamic = true;\n .probe = {\n .request = \"HEAD /.well-known/healthcheck-datadome HTTP/1.1\" \"Host: api-fastly.datadome.co\" \"Connection: close\" \"User-Agent: Varnish/fastly (healthcheck)\";\n .expected_response = 200;\n .initial = 5;\n .interval = 2s;\n .threshold = 1;\n .timeout = 2s;\n .window = 5;\n }\n}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-set bereq.http.x-datadome-params:moduleversion = \"2.24.1\";
+set bereq.http.x-datadome-params:moduleversion = \"2.25.0\";
- .first_byte_timeout = {{datadome_between_bytes_timeout}}ms;
+ .first_byte_timeout = {{datadome_first_byte_timeout}}ms;

"type": "init"
},
{
"priority": 7,
"template": "if (req.backend == datadome) {\n declare local var.status STRING;\n set var.status = beresp.status;\n # check that it is real ApiServer response\n if (var.status != beresp.http.x-datadomeresponse) {\n restart;\n }\n unset beresp.http.x-datadomeresponse;\n # copy datadome headers\n set req.http.x-datadome-headers-pairs:x-datadome-headers = urlencode(beresp.http.x-datadome-headers);\n\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-set-cookie( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-set-cookie = urlencode(beresp.http.x-set-cookie);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-datadome-server( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-datadome-server = urlencode(beresp.http.x-datadome-server);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-datadome( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-datadome = urlencode(beresp.http.x-datadome);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+content-type( |$)+\") {\n set req.http.x-datadome-headers-pairs:content-type = urlencode(beresp.http.content-type);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+charset( |$)+\") {\n set req.http.x-datadome-headers-pairs:charset = urlencode(beresp.http.charset);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+cache-control( |$)+\") {\n set req.http.x-datadome-headers-pairs:cache-control = urlencode(beresp.http.cache-control);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+pragma( |$)+\") {\n set req.http.x-datadome-headers-pairs:pragma = urlencode(beresp.http.pragma);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+access-control-allow-credentials( |$)+\") {\n set req.http.x-datadome-headers-pairs:access-control-allow-credentials = urlencode(beresp.http.access-control-allow-credentials);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+access-control-expose-headers( |$)+\") {\n set req.http.x-datadome-headers-pairs:access-control-expose-headers = urlencode(beresp.http.access-control-expose-headers);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+access-control-allow-origin( |$)+\") {\n set req.http.x-datadome-headers-pairs:access-control-allow-origin = urlencode(beresp.http.access-control-allow-origin);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-datadome-cid( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-datadome-cid = urlencode(beresp.http.x-datadome-cid);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-dd-b( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-dd-b = urlencode(beresp.http.x-dd-b);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-dd-type = urlencode(beresp.http.x-dd-type);\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {\n set req.http.x-dd-type = beresp.http.x-dd-type;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botname( |$)+\") {\n set req.http.x-datadome-botname = beresp.http.x-datadome-botname;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {\n set req.http.x-datadome-botfamily = beresp.http.x-datadome-botfamily;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {\n set req.http.x-datadome-isbot = beresp.http.x-datadome-isbot;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {\n set req.http.x-datadome-captchapassed = beresp.http.x-datadome-captchapassed;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {\n set req.http.x-datadome-devicecheckpassed = beresp.http.x-datadome-devicecheckpassed;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {\n set req.http.x-datadome-traffic-rule-response = beresp.http.x-datadome-traffic-rule-response;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {\n set req.http.x-datadome-captchaurl = beresp.http.x-datadome-captchaurl;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {\n set req.http.x-datadome-requestid = beresp.http.x-datadome-requestid;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-score( |$)+\") {\n set req.http.x-datadome-score = beresp.http.x-datadome-score;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {\n set req.http.x-datadome-ruletype = beresp.http.x-datadome-ruletype;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {\n set req.http.x-datadome-matchedmodels = beresp.http.x-datadome-matchedmodels;\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {\n set req.http.x-datadome-sessionid = beresp.http.x-datadome-sessionid;\n }\n # don\u0027t forget about ApiServer\u0027s cookies\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+set-cookie( |$)+\") {\n set req.http.x-datadome-headers-pairs:set-cookie = urlencode(beresp.http.set-cookie);\n }\n\n # Continue only if ApiServer returns expected blocked status\n if (beresp.status != 403 \u0026\u0026 beresp.status != 401 \u0026\u0026 beresp.status != 301 \u0026\u0026 beresp.status != 302) {\n unset beresp.http.x-datadome-headers;\n unset beresp.http.x-datadome-request-headers;\n set req.http.x-datadome-cookie = beresp.http.x-datadome-cookie; # Allow Session Feature\n restart;\n }\n\n # ok, it is banned request, cleanup it a bit\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-dd-type( |$)+\") {\n unset beresp.http.x-dd-type;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botname( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-botname( |$)+\") {\n unset beresp.http.x-datadome-botname;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {\n unset beresp.http.x-datadome-botfamily;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {\n unset beresp.http.x-datadome-isbot;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {\n unset beresp.http.x-datadome-captchapassed;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {\n unset beresp.http.x-datadome-devicecheckpassed;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {\n unset beresp.http.x-datadome-traffic-rule-response;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {\n unset beresp.http.x-datadome-captchaurl;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {\n unset beresp.http.x-datadome-requestid;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-score( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-score( |$)+\") {\n unset beresp.http.x-datadome-score;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {\n unset beresp.http.x-datadome-ruletype;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {\n unset beresp.http.x-datadome-matchedmodels;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {\n unset beresp.http.x-datadome-sessionid;\n }\n }\n unset beresp.http.x-datadome-headers;\n unset beresp.http.x-datadome-request-headers;\n # restore method\n if (req.http.x-datadome-params:method) {\n set req.method = urldecode(req.http.x-datadome-params:method);\n }\n}",
"template": "if (req.backend == datadome) {\n declare local var.status STRING;\n set var.status = beresp.status;\n # check that it is real ApiServer response\n if (var.status != beresp.http.x-datadomeresponse) {\n restart;\n }\n unset beresp.http.x-datadomeresponse;\n # copy datadome headers\n set req.http.x-datadome-headers-pairs:x-datadome-headers = urlencode(beresp.http.x-datadome-headers);\n\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-set-cookie( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-set-cookie = urlencode(beresp.http.x-set-cookie);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-datadome-server( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-datadome-server = urlencode(beresp.http.x-datadome-server);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-datadome( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-datadome = urlencode(beresp.http.x-datadome);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+content-type( |$)+\") {\n set req.http.x-datadome-headers-pairs:content-type = urlencode(beresp.http.content-type);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+charset( |$)+\") {\n set req.http.x-datadome-headers-pairs:charset = urlencode(beresp.http.charset);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+cache-control( |$)+\") {\n set req.http.x-datadome-headers-pairs:cache-control = urlencode(beresp.http.cache-control);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+pragma( |$)+\") {\n set req.http.x-datadome-headers-pairs:pragma = urlencode(beresp.http.pragma);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+access-control-allow-credentials( |$)+\") {\n set req.http.x-datadome-headers-pairs:access-control-allow-credentials = urlencode(beresp.http.access-control-allow-credentials);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+access-control-expose-headers( |$)+\") {\n set req.http.x-datadome-headers-pairs:access-control-expose-headers = urlencode(beresp.http.access-control-expose-headers);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+access-control-allow-origin( |$)+\") {\n set req.http.x-datadome-headers-pairs:access-control-allow-origin = urlencode(beresp.http.access-control-allow-origin);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-datadome-cid( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-datadome-cid = urlencode(beresp.http.x-datadome-cid);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-dd-b( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-dd-b = urlencode(beresp.http.x-dd-b);\n }\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {\n set req.http.x-datadome-headers-pairs:x-dd-type = urlencode(beresp.http.x-dd-type);\n }\n unset req.http.x-dd-type;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {\n set req.http.x-dd-type = beresp.http.x-dd-type;\n }\n unset req.http.x-datadome-botname;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botname( |$)+\") {\n set req.http.x-datadome-botname = beresp.http.x-datadome-botname;\n }\n unset req.http.x-datadome-botfamily;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {\n set req.http.x-datadome-botfamily = beresp.http.x-datadome-botfamily;\n }\n unset req.http.x-datadome-isbot;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {\n set req.http.x-datadome-isbot = beresp.http.x-datadome-isbot;\n }\n unset req.http.x-datadome-captchapassed;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {\n set req.http.x-datadome-captchapassed = beresp.http.x-datadome-captchapassed;\n }\n unset req.http.x-datadome-devicecheckpassed;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {\n set req.http.x-datadome-devicecheckpassed = beresp.http.x-datadome-devicecheckpassed;\n }\n unset req.http.x-datadome-traffic-rule-response;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {\n set req.http.x-datadome-traffic-rule-response = beresp.http.x-datadome-traffic-rule-response;\n }\n unset req.http.x-datadome-captchaurl;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {\n set req.http.x-datadome-captchaurl = beresp.http.x-datadome-captchaurl;\n }\n unset req.http.x-datadome-requestid;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {\n set req.http.x-datadome-requestid = beresp.http.x-datadome-requestid;\n }\n unset req.http.x-datadome-score;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-score( |$)+\") {\n set req.http.x-datadome-score = beresp.http.x-datadome-score;\n }\n unset req.http.x-datadome-ruletype;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {\n set req.http.x-datadome-ruletype = beresp.http.x-datadome-ruletype;\n }\n unset req.http.x-datadome-matchedmodels;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {\n set req.http.x-datadome-matchedmodels = beresp.http.x-datadome-matchedmodels;\n }\n unset req.http.x-datadome-sessionid;\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {\n set req.http.x-datadome-sessionid = beresp.http.x-datadome-sessionid;\n }\n # don\u0027t forget about ApiServer\u0027s cookies\n if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+set-cookie( |$)+\") {\n set req.http.x-datadome-headers-pairs:set-cookie = urlencode(beresp.http.set-cookie);\n }\n\n # Continue only if ApiServer returns expected blocked status\n if (beresp.status != 403 \u0026\u0026 beresp.status != 401 \u0026\u0026 beresp.status != 301 \u0026\u0026 beresp.status != 302) {\n unset beresp.http.x-datadome-headers;\n unset beresp.http.x-datadome-request-headers;\n set req.http.x-datadome-cookie = beresp.http.x-datadome-cookie; # Allow Session Feature\n restart;\n }\n\n # ok, it is banned request, cleanup it a bit\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-dd-type( |$)+\") {\n unset beresp.http.x-dd-type;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botname( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-botname( |$)+\") {\n unset beresp.http.x-datadome-botname;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {\n unset beresp.http.x-datadome-botfamily;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {\n unset beresp.http.x-datadome-isbot;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {\n unset beresp.http.x-datadome-captchapassed;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {\n unset beresp.http.x-datadome-devicecheckpassed;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {\n unset beresp.http.x-datadome-traffic-rule-response;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {\n unset beresp.http.x-datadome-captchaurl;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {\n unset beresp.http.x-datadome-requestid;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-score( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-score( |$)+\") {\n unset beresp.http.x-datadome-score;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {\n unset beresp.http.x-datadome-ruletype;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {\n unset beresp.http.x-datadome-matchedmodels;\n }\n }\n if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {\n if (beresp.http.x-datadome-headers !~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {\n unset beresp.http.x-datadome-sessionid;\n }\n }\n unset beresp.http.x-datadome-headers;\n unset beresp.http.x-datadome-request-headers;\n # restore method\n if (req.http.x-datadome-params:method) {\n set req.method = urldecode(req.http.x-datadome-params:method);\n }\n}",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  if (beresp.http.x-datadome-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {
  set req.http.x-datadome-headers-pairs:x-dd-type = urlencode(beresp.http.x-dd-type);
  }
+ unset req.http.x-dd-type;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-dd-type( |$)+\") {
  set req.http.x-dd-type = beresp.http.x-dd-type;
  }
+ unset req.http.x-datadome-botname;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botname( |$)+\") {
  set req.http.x-datadome-botname = beresp.http.x-datadome-botname;
  }
+ unset req.http.x-datadome-botfamily;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-botfamily( |$)+\") {
  set req.http.x-datadome-botfamily = beresp.http.x-datadome-botfamily;
  }
+ unset req.http.x-datadome-isbot;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-isbot( |$)+\") {
  set req.http.x-datadome-isbot = beresp.http.x-datadome-isbot;
  }
+ unset req.http.x-datadome-captchapassed;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchapassed( |$)+\") {
  set req.http.x-datadome-captchapassed = beresp.http.x-datadome-captchapassed;
  }
+ unset req.http.x-datadome-devicecheckpassed;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-devicecheckpassed( |$)+\") {
  set req.http.x-datadome-devicecheckpassed = beresp.http.x-datadome-devicecheckpassed;
  }
+ unset req.http.x-datadome-traffic-rule-response;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-traffic-rule-response( |$)+\") {
  set req.http.x-datadome-traffic-rule-response = beresp.http.x-datadome-traffic-rule-response;
  }
+ unset req.http.x-datadome-captchaurl;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-captchaurl( |$)+\") {
  set req.http.x-datadome-captchaurl = beresp.http.x-datadome-captchaurl;
  }
+ unset req.http.x-datadome-requestid;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-requestid( |$)+\") {
  set req.http.x-datadome-requestid = beresp.http.x-datadome-requestid;
  }
+ unset req.http.x-datadome-score;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-score( |$)+\") {
  set req.http.x-datadome-score = beresp.http.x-datadome-score;
  }
+ unset req.http.x-datadome-ruletype;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-ruletype( |$)+\") {
  set req.http.x-datadome-ruletype = beresp.http.x-datadome-ruletype;
  }
+ unset req.http.x-datadome-matchedmodels;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-matchedmodels( |$)+\") {
  set req.http.x-datadome-matchedmodels = beresp.http.x-datadome-matchedmodels;
  }
+ unset req.http.x-datadome-sessionid;
  if (beresp.http.x-datadome-request-headers ~ \"(?i)(^| )+x-datadome-sessionid( |$)+\") {
  set req.http.x-datadome-sessionid = beresp.http.x-datadome-sessionid;
  }

@@ -96,7 +96,7 @@
},
{
"priority": 7,
"template": "\n {{#if logging_endpoint}}\n ## Debug DataDome\n log {\"syslog \"} req.service_id {\" {{logging_endpoint}} :: \"}\n \" timestamp=%22\" now\n \"%22 client_ip=\" req.http.Fastly-Client-IP\n \" request=\" req.method\n \" url=%22\" cstr_escape(req.url.path)\n \"%22 restarts=\" req.restarts\n \" DataDomeDebug=\" \"Before_DataDome\"\n \" fastlyFF=\" fastly.ff.visits_this_service;\n ##\n {{/if}}\ndeclare local var.datadome_restore_referrer BOOL;\ndeclare local var.datadome_enable_graphql_support BOOL;\ndeclare local var.datadome_enable_replay_protection BOOL;\n\nset var.datadome_restore_referrer = {{datadome_restore_referrer}};\nset var.datadome_enable_graphql_support = {{datadome_enable_graphql_support}};\nset var.datadome_enable_replay_protection = {{datadome_enable_replay_protection}};\n\n\n# Configure the regular expression below to match URLs that\n# should be checked by DataDome\nif (fastly.ff.visits_this_service == 0 \u0026\u0026 req.restarts == 0 \u0026\u0026 req.method != \"FASTLYPURGE\" \u0026\u0026 !(req.url.path ~ \"{{datadome_exclusion_ext}}\" \u0026\u0026 (req.method == \"GET\" || req.method == \"HEAD\"))) {\n\n if (req.http.early-data == \"1\" \u0026\u0026 var.datadome_enable_replay_protection == true) {\n error 425;\n }\n\n set req.backend = datadome;\n unset req.http.x-datadome-params;\n set req.http.x-datadome-params:method = urlencode(req.method);\n set req.http.x-datadome-params:postparamlen = urlencode(req.http.content-length);\n set req.method = \"GET\";\n set req.http.x-datadome-params:tlsprotocol = urlencode(tls.client.protocol);\n set req.http.x-datadome-params:tlscipherslist = urlencode(tls.client.ciphers_list);\n set req.http.x-datadome-params:tlsextensionslist = urlencode(tls.client.tlsexts_list);\n set req.http.x-datadome-params:ja3 = urlencode(tls.client.ja3_md5);\n set req.http.x-datadome-params:ja4 = urlencode(tls.client.ja4);\n\n if (var.datadome_enable_graphql_support == true \u0026\u0026 req.http.x-datadome-params:method == \"POST\" \u0026\u0026 req.http.content-type ~ \"(?i)application\\/json\" \u0026\u0026 req.url.path ~ \"(?i)graphql\") {\n declare local var.graphQLQuery STRING;\n set var.graphQLQuery = std.strstr(req.body, \"%22query%22\");\n if (var.graphQLQuery ~ \"(?m)(query|mutation|subscription)?\\s*([A-Za-z_][A-Za-z0-9_]*)?\\s*[\\({@]\") {\n set req.http.x-datadome-params:graphqlOperationType = if(re.group.1, re.group.1, \"query\");\n if (re.group.2) {\n set req.http.x-datadome-params:graphqlOperationName = substr(re.group.2, 0, 128);\n }\n }\n }\n\n if (var.datadome_restore_referrer == true \u0026\u0026 req.url ~ \"dd_referrer=\") {\n \n declare local var.decoded_url STRING;\n declare local var.complete_request_url STRING;\n set var.decoded_url = urldecode(req.url);\n set var.complete_request_url = req.protocol \"://\" req.http.host querystring.filter(var.decoded_url, \"dd_referrer\");\n \n if (urldecode(querystring.clean(req.http.referer)) == querystring.clean(var.complete_request_url)) {\n # Referer header is the same as the current URL\n\n if (std.strlen(querystring.get(req.url, \"dd_referrer\")) \u003e 0) {\n # Not empty `dd_referrer`, restore header `referer` with param value\n set req.http.referer = urldecode(querystring.get(req.url, \"dd_referrer\"));\n } else if (querystring.get(req.url, \"dd_referrer\") == \"\") {\n # Empty `dd_referrer` param, remove header `referer`\n unset req.http.referer;\n } # Not set `dd_referrer`, do nothing\n \n # Remove `dd_referrer` query param from URL\n set req.url = querystring.filter(req.url, \"dd_referrer\");\n }\n }\n {{#if logging_endpoint}}\n ## Debug DataDome\n log {\"syslog \"} req.service_id {\" {{logging_endpoint}} :: \"}\n \" timestamp=%22\" now\n \"%22 client_ip=\" req.http.Fastly-Client-IP\n \" request=\" req.method\n \" host=\" req.http.host\n \" url=%22\" cstr_escape(req.url)\n \"%22 request_referer=%22\" cstr_escape(req.http.Referer)\n \"%22 request_user_agent=%22\" cstr_escape(req.http.User-Agent)\n \"%22 request_accept_language=%22\" cstr_escape(req.http.Accept-Language)\n \"%22 request_accept_charset=%22\" cstr_escape(req.http.Accept-Charset)\n \"%22 contentLength=\" req.http.Content-Length\n \" restarts=\" req.restarts\n \" DataDomeDebug=\" \"To_DataDome\"\n \" fastlyFF=\" fastly.ff.visits_this_service;\n ##\n {{/if}}\n return (pass);\n} else {\n if (req.http.x-datadome-params:method) {\n set req.method = urldecode(req.http.x-datadome-params:method);\n # After a restart, clustering is disabled. This re-enables it.\n set req.http.fastly-force-shield = \"1\";\n }\n unset req.http.x-datadome-params;\n {{#if logging_endpoint}}\n ## Debug DataDome\n log {\"syslog \"} req.service_id {\" {{logging_endpoint}} :: \"}\n \" timestamp=%22\" now\n \"%22 client_ip=\" req.http.Fastly-Client-IP\n \" request=\" req.method\n \" host=\" req.http.host\n \" url=%22\" cstr_escape(req.url)\n \"%22 request_referer=%22\" cstr_escape(req.http.Referer)\n \"%22 request_user_agent=%22\" cstr_escape(req.http.User-Agent)\n \"%22 request_accept_language=%22\" cstr_escape(req.http.Accept-Language)\n \"%22 request_accept_charset=%22\" cstr_escape(req.http.Accept-Charset)\n \"%22 contentLength=\" req.http.Content-Length\n \" restarts=\" req.restarts\n \" DataDomeDebug=\" \"Bypass_DataDome\"\n \" fastlyFF=\" fastly.ff.visits_this_service;\n ##\n {{/if}}\n}\n\n# we\u0027re using the first restart for datadome, update a part of fastly code\n# we can\u0027t replace whole macros because we haven\u0027t got any idea about backends\nif (req.restarts == 1) {\n if (!req.http.x-timer) {\n set req.http.x-timer = \"S\" time.start.sec \".\" time.start.usec_frac;\n }\n set req.http.x-timer = req.http.x-timer \",VS0\";\n}\n\nset var.fastly_req_do_shield = (req.restarts \u003c= 1);",
"template": "\n {{#if logging_endpoint}}\n ## Debug DataDome\n log {\"syslog \"} req.service_id {\" {{logging_endpoint}} :: \"}\n \" timestamp=%22\" now\n \"%22 client_ip=\" req.http.Fastly-Client-IP\n \" request=\" req.method\n \" url=%22\" cstr_escape(req.url.path)\n \"%22 restarts=\" req.restarts\n \" DataDomeDebug=\" \"Before_DataDome\"\n \" fastlyFF=\" fastly.ff.visits_this_service;\n ##\n {{/if}}\ndeclare local var.datadome_restore_referrer BOOL;\ndeclare local var.datadome_enable_graphql_support BOOL;\ndeclare local var.datadome_enable_replay_protection BOOL;\n\nset var.datadome_restore_referrer = {{datadome_restore_referrer}};\nset var.datadome_enable_graphql_support = {{datadome_enable_graphql_support}};\nset var.datadome_enable_replay_protection = {{datadome_enable_replay_protection}};\n\n\n# Configure the regular expression below to match URLs that\n# should be checked by DataDome\nif (fastly.ff.visits_this_service == 0 \u0026\u0026 req.restarts == 0 \u0026\u0026 req.method != \"FASTLYPURGE\" \u0026\u0026 req.http.x-datadome-skip-detection != req.xid \u0026\u0026 !((req.method == \"GET\" || req.method == \"HEAD\") \u0026\u0026 req.url.path ~ \"{{datadome_exclusion_ext}}\")) {\n\n if (req.http.early-data == \"1\" \u0026\u0026 var.datadome_enable_replay_protection == true) {\n error 425;\n }\n\n set req.backend = datadome;\n unset req.http.x-datadome-params;\n set req.http.x-datadome-params:method = urlencode(req.method);\n set req.http.x-datadome-params:postparamlen = urlencode(req.http.content-length);\n set req.method = \"GET\";\n set req.http.x-datadome-params:tlsprotocol = urlencode(tls.client.protocol);\n set req.http.x-datadome-params:tlscipherslist = urlencode(tls.client.ciphers_list);\n set req.http.x-datadome-params:tlsextensionslist = urlencode(tls.client.tlsexts_list);\n set req.http.x-datadome-params:ja3 = urlencode(tls.client.ja3_md5);\n set req.http.x-datadome-params:ja4 = urlencode(tls.client.ja4);\n\n if (var.datadome_enable_graphql_support == true \u0026\u0026 req.http.x-datadome-params:method == \"POST\" \u0026\u0026 req.http.content-type ~ \"(?i)application\\/json\" \u0026\u0026 req.url.path ~ \"(?i)graphql\") {\n declare local var.graphQLQuery STRING;\n set var.graphQLQuery = std.strstr(req.body, \"%22query%22\");\n if (var.graphQLQuery ~ \"(?m)(query|mutation|subscription)?\\s*([A-Za-z_][A-Za-z0-9_]*)?\\s*[\\({@]\") {\n set req.http.x-datadome-params:graphqlOperationType = if(re.group.1, re.group.1, \"query\");\n if (re.group.2) {\n set req.http.x-datadome-params:graphqlOperationName = substr(re.group.2, 0, 128);\n }\n }\n }\n\n if (var.datadome_restore_referrer == true \u0026\u0026 req.url ~ \"dd_referrer=\") {\n \n declare local var.decoded_url STRING;\n declare local var.complete_request_url STRING;\n set var.decoded_url = urldecode(req.url);\n set var.complete_request_url = req.protocol \"://\" req.http.host querystring.filter(var.decoded_url, \"dd_referrer\");\n \n if (urldecode(querystring.clean(req.http.referer)) == querystring.clean(var.complete_request_url)) {\n # Referer header is the same as the current URL\n\n if (std.strlen(querystring.get(req.url, \"dd_referrer\")) \u003e 0) {\n # Not empty `dd_referrer`, restore header `referer` with param value\n set req.http.referer = urldecode(querystring.get(req.url, \"dd_referrer\"));\n } else if (querystring.get(req.url, \"dd_referrer\") == \"\") {\n # Empty `dd_referrer` param, remove header `referer`\n unset req.http.referer;\n } # Not set `dd_referrer`, do nothing\n \n # Remove `dd_referrer` query param from URL\n set req.url = querystring.filter(req.url, \"dd_referrer\");\n }\n }\n {{#if logging_endpoint}}\n ## Debug DataDome\n log {\"syslog \"} req.service_id {\" {{logging_endpoint}} :: \"}\n \" timestamp=%22\" now\n \"%22 client_ip=\" req.http.Fastly-Client-IP\n \" request=\" req.method\n \" host=\" req.http.host\n \" url=%22\" cstr_escape(req.url)\n \"%22 request_referer=%22\" cstr_escape(req.http.Referer)\n \"%22 request_user_agent=%22\" cstr_escape(req.http.User-Agent)\n \"%22 request_accept_language=%22\" cstr_escape(req.http.Accept-Language)\n \"%22 request_accept_charset=%22\" cstr_escape(req.http.Accept-Charset)\n \"%22 contentLength=\" req.http.Content-Length\n \" restarts=\" req.restarts\n \" DataDomeDebug=\" \"To_DataDome\"\n \" fastlyFF=\" fastly.ff.visits_this_service;\n ##\n {{/if}}\n return (pass);\n} else {\n if (req.http.x-datadome-params:method) {\n set req.method = urldecode(req.http.x-datadome-params:method);\n # After a restart, clustering is disabled. This re-enables it.\n set req.http.fastly-force-shield = \"1\";\n }\n unset req.http.x-datadome-params;\n {{#if logging_endpoint}}\n ## Debug DataDome\n log {\"syslog \"} req.service_id {\" {{logging_endpoint}} :: \"}\n \" timestamp=%22\" now\n \"%22 client_ip=\" req.http.Fastly-Client-IP\n \" request=\" req.method\n \" host=\" req.http.host\n \" url=%22\" cstr_escape(req.url)\n \"%22 request_referer=%22\" cstr_escape(req.http.Referer)\n \"%22 request_user_agent=%22\" cstr_escape(req.http.User-Agent)\n \"%22 request_accept_language=%22\" cstr_escape(req.http.Accept-Language)\n \"%22 request_accept_charset=%22\" cstr_escape(req.http.Accept-Charset)\n \"%22 contentLength=\" req.http.Content-Length\n \" restarts=\" req.restarts\n \" DataDomeDebug=\" \"Bypass_DataDome\"\n \" fastlyFF=\" fastly.ff.visits_this_service;\n ##\n {{/if}}\n}\n\nunset req.http.x-datadome-skip-detection;\n\n# we\u0027re using the first restart for datadome, update a part of fastly code\n# we can\u0027t replace whole macros because we haven\u0027t got any idea about backends\nif (req.restarts == 1) {\n if (!req.http.x-timer) {\n set req.http.x-timer = \"S\" time.start.sec \".\" time.start.usec_frac;\n }\n set req.http.x-timer = req.http.x-timer \",VS0\";\n}\n\nset var.fastly_req_do_shield = (req.restarts \u003c= 1);",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 # Configure the regular expression below to match URLs that
 # should be checked by DataDome
-if (fastly.ff.visits_this_service == 0 && req.restarts == 0 && req.method != \"FASTLYPURGE\" && !(req.url.path ~ \"{{datadome_exclusion_ext}}\" && (req.method == \"GET\" || req.method == \"HEAD\"))) {
+if (fastly.ff.visits_this_service == 0 && req.restarts == 0 && req.method != \"FASTLYPURGE\" && req.http.x-datadome-skip-detection != req.xid && !((req.method == \"GET\" || req.method == \"HEAD\") && req.url.path ~ \"{{datadome_exclusion_ext}}\")) {
 
  if (req.http.early-data == \"1\" && var.datadome_enable_replay_protection == true) {
  error 425;
  }
  \" fastlyFF=\" fastly.ff.visits_this_service;
  ##
  {{/if}}
 }
 
+unset req.http.x-datadome-skip-detection;
 
 # we're using the first restart for datadome, update a part of fastly code
 # we can't replace whole macros because we haven't got any idea about backends

@harmony7 harmony7 merged commit 9d6bc60 into fastly:master Jul 10, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants