From a2363fd64d229b0354d5b6fb9db0b4f83c28a1af Mon Sep 17 00:00:00 2001 From: Ice3man Date: Sun, 12 Jan 2025 22:18:37 +0530 Subject: [PATCH 01/22] feat: added new full headless mode to katana (wip) --- .gitignore | 3 +- cmd/katana/main.go | 3 +- go.mod | 9 +- go.sum | 22 +- internal/runner/options.go | 2 +- internal/runner/runner.go | 3 + pkg/engine/headless/browser/browser.go | 423 ++++++++++++++++++ pkg/engine/headless/browser/element.go | 248 ++++++++++ pkg/engine/headless/crawler/crawler.go | 334 ++++++++++++++ .../headless/crawler/normalizer/dom_utils.go | 165 +++++++ .../crawler/normalizer/dom_utils_test.go | 78 ++++ .../headless/crawler/normalizer/helpers.go | 43 ++ .../headless/crawler/normalizer/normalizer.go | 104 +++++ .../headless/crawler/normalizer/text_utils.go | 62 +++ .../crawler/normalizer/text_utils_test.go | 42 ++ pkg/engine/headless/crawler/state.go | 257 +++++++++++ pkg/engine/headless/crawler/state_test.go | 103 +++++ pkg/engine/headless/graph/graph.go | 138 ++++++ pkg/engine/headless/headless.go | 69 +++ pkg/engine/headless/js/js.go | 27 ++ pkg/engine/headless/js/page-init.js | 160 +++++++ pkg/engine/headless/js/utils.js | 357 +++++++++++++++ pkg/engine/headless/types/types.go | 286 ++++++++++++ pkg/types/options.go | 2 + 24 files changed, 2926 insertions(+), 14 deletions(-) create mode 100644 pkg/engine/headless/browser/browser.go create mode 100644 pkg/engine/headless/browser/element.go create mode 100644 pkg/engine/headless/crawler/crawler.go create mode 100644 pkg/engine/headless/crawler/normalizer/dom_utils.go create mode 100644 pkg/engine/headless/crawler/normalizer/dom_utils_test.go create mode 100644 pkg/engine/headless/crawler/normalizer/helpers.go create mode 100644 pkg/engine/headless/crawler/normalizer/normalizer.go create mode 100644 pkg/engine/headless/crawler/normalizer/text_utils.go create mode 100644 pkg/engine/headless/crawler/normalizer/text_utils_test.go create mode 100644 pkg/engine/headless/crawler/state.go create mode 100644 pkg/engine/headless/crawler/state_test.go create mode 100644 pkg/engine/headless/graph/graph.go create mode 100644 pkg/engine/headless/headless.go create mode 100644 pkg/engine/headless/js/js.go create mode 100644 pkg/engine/headless/js/page-init.js create mode 100644 pkg/engine/headless/js/utils.js create mode 100644 pkg/engine/headless/types/types.go diff --git a/.gitignore b/.gitignore index 629564ec..825cdece 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ katana_*/ dist/ .vscode -.devcontainer \ No newline at end of file +.devcontainer +.DS_Store \ No newline at end of file diff --git a/cmd/katana/main.go b/cmd/katana/main.go index ec425716..6cbd6be2 100644 --- a/cmd/katana/main.go +++ b/cmd/katana/main.go @@ -136,7 +136,8 @@ pipelines offering both headless and non-headless crawling.`) ) flagSet.CreateGroup("headless", "Headless", - flagSet.BoolVarP(&options.Headless, "headless", "hl", false, "enable headless hybrid crawling (experimental)"), + flagSet.BoolVarP(&options.Headless, "headless", "hl", false, "enable headless crawling (experimental)"), + flagSet.BoolVarP(&options.HeadlessHybrid, "hybrid", "hh", false, "enable headless hybrid crawling (experimental)"), flagSet.BoolVarP(&options.UseInstalledChrome, "system-chrome", "sc", false, "use local installed chrome browser instead of katana installed"), flagSet.BoolVarP(&options.ShowBrowser, "show-browser", "sb", false, "show the browser on the screen with headless mode"), flagSet.StringSliceVarP(&options.HeadlessOptionalArguments, "headless-options", "ho", nil, "start headless chrome with additional options", goflags.FileCommaSeparatedStringSliceOptions), diff --git a/go.mod b/go.mod index b8cfde76..6fc61f1f 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,11 @@ go 1.21 require ( github.com/BishopFox/jsluice v0.0.0-20240110145140-0ddfab153e06 github.com/PuerkitoBio/goquery v1.8.1 - github.com/go-rod/rod v0.114.1 + github.com/adrianbrad/queue v1.3.0 + github.com/dominikbraun/graph v0.23.0 + github.com/go-rod/rod v0.116.2 github.com/json-iterator/go v1.1.12 + github.com/lmittmann/tint v1.0.6 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/lukasbob/srcset v0.0.0-20190730101422-86b742e617f3 github.com/mitchellh/mapstructure v1.5.0 @@ -92,7 +95,7 @@ require ( github.com/tidwall/rtred v0.1.2 // indirect github.com/tidwall/tinyqueue v0.1.1 // indirect github.com/ysmood/fetchup v0.2.3 // indirect - github.com/ysmood/got v0.34.1 // indirect + github.com/ysmood/got v0.40.0 // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect github.com/zcalusic/sysinfo v1.0.2 // indirect @@ -136,7 +139,7 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/ysmood/goob v0.4.0 // indirect github.com/ysmood/gson v0.7.3 // indirect - github.com/ysmood/leakless v0.8.0 // indirect + github.com/ysmood/leakless v0.9.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect diff --git a/go.sum b/go.sum index 13143c86..cd15c50b 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJs github.com/RumbleDiscovery/rumble-tools v0.0.0-20201105153123-f2adbb3244d2/go.mod h1:jD2+mU+E2SZUuAOHZvZj4xP4frlOo+N/YrXDvASFhkE= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/adrianbrad/queue v1.3.0 h1:8FH1N+93HXbqta5+URa1AL+diV7MP3VDXAEnP+DNp48= +github.com/adrianbrad/queue v1.3.0/go.mod h1:wYiPC/3MPbyT45QHLrPR4zcqJWPePubM1oEP/xTwhUs= github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w= github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= @@ -74,6 +76,8 @@ github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yA github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= +github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= @@ -88,8 +92,8 @@ github.com/gaissmai/bart v0.9.5 h1:vy+r4Px6bjZ+v2QYXAsg63vpz9IfzdW146A8Cn4GPIo= github.com/gaissmai/bart v0.9.5/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-rod/rod v0.114.1 h1:osBWr88guzTXAIzwJWVmGZe3/utT9+lqKjkGSBsYMxw= -github.com/go-rod/rod v0.114.1/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= +github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= @@ -160,6 +164,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/lmittmann/tint v1.0.6 h1:vkkuDAZXc0EFGNzYjWcV0h7eEX+uujH48f/ifSkJWgc= +github.com/lmittmann/tint v1.0.6/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= @@ -343,16 +349,16 @@ github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= -github.com/ysmood/gop v0.0.2 h1:VuWweTmXK+zedLqYufJdh3PlxDNBOfFHjIZlPT2T5nw= -github.com/ysmood/gop v0.0.2/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk= -github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s= -github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= +github.com/ysmood/gop v0.2.0 h1:+tFrG0TWPxT6p9ZaZs+VY+opCvHU8/3Fk6BaNv6kqKg= +github.com/ysmood/gop v0.2.0/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk= +github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= +github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY= github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= -github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= -github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= +github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= +github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg= diff --git a/internal/runner/options.go b/internal/runner/options.go index b796707d..fc73becb 100644 --- a/internal/runner/options.go +++ b/internal/runner/options.go @@ -32,7 +32,7 @@ func validateOptions(options *types.Options) error { gologger.Info().Msgf("Automatic form fill (-aff) has been disabled for headless navigation.") } - if (options.HeadlessOptionalArguments != nil || options.HeadlessNoSandbox || options.SystemChromePath != "") && !options.Headless { + if (options.HeadlessOptionalArguments != nil || options.HeadlessNoSandbox || options.SystemChromePath != "") && !options.Headless && !options.HeadlessHybrid { return errorutil.New("headless mode (-hl) is required if -ho, -nos or -scp are set") } if options.SystemChromePath != "" { diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 9fcd09fe..9011412f 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -7,6 +7,7 @@ import ( "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/katana/pkg/engine" + "github.com/projectdiscovery/katana/pkg/engine/headless" "github.com/projectdiscovery/katana/pkg/engine/hybrid" "github.com/projectdiscovery/katana/pkg/engine/parser" "github.com/projectdiscovery/katana/pkg/engine/standard" @@ -96,6 +97,8 @@ func New(options *types.Options) (*Runner, error) { switch { case options.Headless: + crawler, err = headless.New(crawlerOptions) + case options.HeadlessHybrid: crawler, err = hybrid.New(crawlerOptions) default: crawler, err = standard.New(crawlerOptions) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go new file mode 100644 index 00000000..6e0e8268 --- /dev/null +++ b/pkg/engine/headless/browser/browser.go @@ -0,0 +1,423 @@ +package browser + +import ( + "bytes" + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + "net/http/httputil" + "os" + "strings" + "sync" + "time" + + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/launcher" + "github.com/go-rod/rod/lib/launcher/flags" + "github.com/go-rod/rod/lib/proto" + rodutils "github.com/go-rod/rod/lib/utils" + "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/js" + "github.com/projectdiscovery/katana/pkg/navigation" + "github.com/projectdiscovery/katana/pkg/output" + "github.com/projectdiscovery/katana/pkg/utils" + "github.com/rs/xid" +) + +// Launcher is a high level controller to launch browsers +// and do the execution on them. +type Launcher struct { + browserPool rod.Pool[BrowserPage] + + opts LauncherOptions +} + +// LauncherOptions contains options for the launcher +type LauncherOptions struct { + ChromiumPath string + MaxBrowsers int + PageMaxTimeout time.Duration + ShowBrowser bool + Proxy string + SlowMotion bool + + RequestCallback func(*output.Result) +} + +// NewLauncher returns a new launcher instance +func NewLauncher(opts LauncherOptions) (*Launcher, error) { + l := &Launcher{ + opts: opts, + browserPool: rod.NewPool[BrowserPage](opts.MaxBrowsers), + } + return l, nil +} + +func (l *Launcher) launchBrowser() (*rod.Browser, error) { + chromeLauncher := launcher.New(). + Leakless(true). + Set("disable-gpu", "true"). + Set("ignore-certificate-errors", "true"). + Set("disable-crash-reporter", "true"). + Set("disable-notifications", "true"). + Set("hide-scrollbars", "true"). + Set("window-size", fmt.Sprintf("%d,%d", 1080, 1920)). + Set("mute-audio", "true"). + Set("incognito", "true"). + // Set("proxy-server", opts.Proxy). + Delete("use-mock-keychain"). + Delete("disable-ipc-flooding-protection"). // somehow this causes loops + Headless(true) + + for _, flag := range headlessFlags { + splitted := strings.TrimPrefix(flag, "--") + values := strings.Split(splitted, "=") + if len(values) == 2 { + chromeLauncher = chromeLauncher.Set(flags.Flag(values[0]), strings.Split(values[1], ",")...) + } else { + chromeLauncher = chromeLauncher.Set(flags.Flag(splitted), "true") + } + } + + if l.opts.ShowBrowser { + chromeLauncher = chromeLauncher.Headless(false) + } + + // CHeck to see if we need to disable sandbox + if os.Getuid() == 0 { + chromeLauncher = chromeLauncher.Set("no-sandbox", "true") + } + + if l.opts.ChromiumPath != "" { + chromeLauncher = chromeLauncher.Bin(l.opts.ChromiumPath) + } + + launcherURL, err := chromeLauncher.Launch() + if err != nil { + return nil, err + } + + browser := rod.New(). + ControlURL(launcherURL) + + if l.opts.SlowMotion { + browser = browser.SlowMotion(1 * time.Second) + } + if browserErr := browser.Connect(); browserErr != nil { + return nil, browserErr + } + return browser, nil +} + +// Close closes the launcher +func (l *Launcher) Close() { + l.browserPool.Cleanup(func(b *BrowserPage) { + b.cancel() + b.CloseBrowserPage() + }) +} + +// BrowserPage is a combination of a browser and a page +type BrowserPage struct { + *rod.Page + Browser *rod.Browser + cancel context.CancelFunc + + launcher *Launcher +} + +// WaitPageLoadHeurisitics waits for the page to load using heuristics +func (b *BrowserPage) WaitPageLoadHeurisitics() error { + chainedTimeout := b.Timeout(30 * time.Second) + + _ = chainedTimeout.WaitLoad() + _ = chainedTimeout.WaitIdle(1 * time.Second) + _ = b.WaitNewStable(500 * time.Millisecond) + return nil +} + +// WaitStable waits until the page is stable for d duration. +func (p *BrowserPage) WaitNewStable(d time.Duration) error { + var err error + + setErr := sync.Once{} + + rodutils.All(func() { + e := p.WaitLoad() + setErr.Do(func() { err = e }) + }, func() { + p.WaitRequestIdle(d, nil, []string{}, nil)() + }, func() { + // e := p.WaitDOMStable(d, 0) + //setErr.Do(func() { err = e }) + })() + + return err +} + +func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { + browser, err := l.launchBrowser() + if err != nil { + return nil, err + } + page, err := browser.Page(proto.TargetCreateTarget{}) + if err != nil { + return nil, errors.Wrap(err, "could not create new page") + } + page = page.Sleeper(func() rodutils.Sleeper { + return backoffCountSleeper(30*time.Millisecond, 1*time.Second, 5, func(d time.Duration) time.Duration { + return d * 2 + }) + }) + ctx := page.GetContext() + cancelCtx, cancel := context.WithCancel(ctx) + page = page.Context(cancelCtx) + + browserPage := &BrowserPage{ + Page: page, + Browser: browser, + launcher: l, + cancel: cancel, + } + browserPage.handlePageDialogBoxes() + + err = js.InitJavascriptEnv(page) + if err != nil { + return nil, errors.Wrap(err, "could not initialize javascript env") + } + return browserPage, nil +} + +// GetPageFromPool returns a page from the pool +func (l *Launcher) GetPageFromPool() (*BrowserPage, error) { + browserPage, err := l.browserPool.Get(l.createBrowserPageFunc) + if err != nil { + return nil, err + } + + return browserPage, nil +} + +// backoffCountSleeper returns a sleeper that uses backoff strategy but stops after max attempts. +// It combines the functionality of BackoffSleeper and CountSleeper. +func backoffCountSleeper(initInterval, maxInterval time.Duration, maxAttempts int, algorithm func(time.Duration) time.Duration) rodutils.Sleeper { + backoff := rodutils.BackoffSleeper(initInterval, maxInterval, algorithm) + count := rodutils.CountSleeper(maxAttempts) + + return rodutils.EachSleepers(backoff, count) +} + +func (b *BrowserPage) handlePageDialogBoxes() error { + err := proto.FetchEnable{ + Patterns: []*proto.FetchRequestPattern{ + { + URLPattern: "*", + RequestStage: proto.FetchRequestStageResponse, + }, + }, + }.Call(b.Page) + if err != nil { + return errors.Wrap(err, "could not enable fetch domain") + } + + // Handle all the javascript dialogs and accept them + // with optional text to ensure it doesn't block screenshots. + go b.Page.EachEvent( + func(e *proto.PageJavascriptDialogOpening) { + _ = proto.PageHandleJavaScriptDialog{ + Accept: true, + PromptText: xid.New().String(), + }.Call(b.Page) + }, + + func(e *proto.FetchRequestPaused) { + if e.ResponseStatusCode == nil || e.ResponseErrorReason != "" || *e.ResponseStatusCode >= 301 && *e.ResponseStatusCode <= 308 { + fetchContinueRequest(b.Page, e) + return + } + body, err := fetchGetResponseBody(b.Page, e) + if err != nil { + return + } + _ = fetchContinueRequest(b.Page, e) + + httpreq, err := netHTTPRequestFromProto(e.Request) + if err != nil { + return + } + + rawBytesRequest, _ := httputil.DumpRequestOut(httpreq, true) + + req := navigation.Request{ + Method: httpreq.Method, + URL: httpreq.URL.String(), + Body: string(body), + Headers: utils.FlattenHeaders(httpreq.Header), + Raw: string(rawBytesRequest), + } + + httpresp := netHTTPResponseFromProto(e, body) + + rawBytesResponse, _ := httputil.DumpResponse(httpresp, true) + + resp := &navigation.Response{ + Body: string(body), + StatusCode: httpresp.StatusCode, + Headers: utils.FlattenHeaders(httpresp.Header), + Raw: string(rawBytesResponse), + ContentLength: httpresp.ContentLength, + } + b.launcher.opts.RequestCallback(&output.Result{ + Timestamp: time.Now(), + Request: &req, + Response: resp, + }) + }, + )() + return nil +} + +func fetchContinueRequest(page *rod.Page, e *proto.FetchRequestPaused) error { + return proto.FetchContinueRequest{ + RequestID: e.RequestID, + }.Call(page) +} + +// fetchGetResponseBody get request body. +func fetchGetResponseBody(page *rod.Page, e *proto.FetchRequestPaused) ([]byte, error) { + m := proto.FetchGetResponseBody{ + RequestID: e.RequestID, + } + r, err := m.Call(page) + if err != nil { + return nil, err + } + + if !r.Base64Encoded { + return []byte(r.Body), nil + } + + bs, err := base64.StdEncoding.DecodeString(r.Body) + if err != nil { + return nil, err + } + return bs, nil +} + +func netHTTPRequestFromProto(e *proto.NetworkRequest) (*http.Request, error) { + req, err := http.NewRequest(e.Method, e.URL, nil) + if err != nil { + return nil, errors.Wrap(err, "could not create new request") + } + for k, v := range e.Headers { + req.Header.Set(k, v.Str()) + } + if e.PostData != "" { + req.Body = io.NopCloser(strings.NewReader(e.PostData)) + req.ContentLength = int64(len(e.PostData)) + } + return req, nil +} + +func netHTTPResponseFromProto(e *proto.FetchRequestPaused, body []byte) *http.Response { + httpresp := &http.Response{ + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: make(http.Header), + StatusCode: *e.ResponseStatusCode, + Status: e.ResponseStatusText, + Body: io.NopCloser(bytes.NewReader(body)), + ContentLength: int64(len(body)), + } + for _, header := range e.ResponseHeaders { + httpresp.Header.Set(header.Name, header.Value) + } + return httpresp +} + +func (l *Launcher) PutBrowserToPool(browser *BrowserPage) { + // If the browser is not connected, close it + if !isBrowserConnected(browser.Browser) { + browser.cancel() + _ = browser.Browser.Close() + return + } + + pages, err := browser.Browser.Pages() + if err != nil { + browser.cancel() + _ = browser.Browser.Close() + return + } + + // Close all pages except the current one + currentPageID := browser.Page.TargetID + for _, page := range pages { + if page.TargetID != currentPageID { + _ = page.Close() + } + } + l.browserPool.Put(browser) +} + +func isBrowserConnected(browser *rod.Browser) bool { + getVersionResult, err := proto.BrowserGetVersion{}.Call(browser) + if err != nil { + return false + } + if getVersionResult == nil || getVersionResult.Product == "" { + return false + } + return true +} + +func (b *BrowserPage) CloseBrowserPage() { + b.Page.Close() + b.Browser.Close() +} + +// taken from playwright +var headlessFlags = []string{ + "--disable-field-trial-config", // https://source.chromium.org/chromium/chromium/src/+/main:testing/variations/README.md + "--disable-background-networking", + "--enable-features=NetworkService,NetworkServiceInProcess", + "--disable-background-timer-throttling", + "--disable-backgrounding-occluded-windows", + "--disable-back-forward-cache", // Avoids surprises like main request not being intercepted during page.goBack(). + "--disable-breakpad", + "--disable-client-side-phishing-detection", + "--disable-component-extensions-with-background-pages", + "--disable-component-update", // Avoids unneeded network activity after startup. + "--no-default-browser-check", + "--disable-default-apps", + "--disable-dev-shm-usage", + "--disable-extensions", + "--disable-web-security", + "--no-zygote", + // AvoidUnnecessaryBeforeUnloadCheckSync - https://github.com/microsoft/playwright/issues/14047 + // Translate - https://github.com/microsoft/playwright/issues/16126 + // HttpsUpgrades - https://github.com/microsoft/playwright/pull/27605 + // PaintHolding - https://github.com/microsoft/playwright/issues/28023 + "--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate,HttpsUpgrades,PaintHolding", + "--allow-pre-commit-input", + "--disable-hang-monitor", + "--disable-popup-blocking", + "--disable-prompt-on-repost", + "--disable-renderer-backgrounding", + "--force-color-profile=srgb", + "--metrics-recording-only", + "--no-first-run", + "--enable-automation", + "--password-store=basic", + "--use-mock-keychain", + // See https://chromium-review.googlesource.com/c/chromium/src/+/2436773 + "--no-service-autorun", + "--export-tagged-pdf", + // https://chromium-review.googlesource.com/c/chromium/src/+/4853540 + "--disable-search-engine-choice-screen", + // https://issues.chromium.org/41491762 + "--unsafely-disable-devtools-self-xss-warnings", +} diff --git a/pkg/engine/headless/browser/element.go b/pkg/engine/headless/browser/element.go new file mode 100644 index 00000000..011309fa --- /dev/null +++ b/pkg/engine/headless/browser/element.go @@ -0,0 +1,248 @@ +package browser + +import ( + "strconv" + "strings" + + "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/types" +) + +const ( + // buttonsCSSSelector is the css selector for all buttons + buttonsCSSSelector = "button, input[type='button'], input[type='submit']" + // linksCSSSelector is the css selector for all anchor tags + linksCSSSelector = "a" +) + +// FindNavigation attempts to find more navigations on the page which could +// be done to find more links and pages. +// +// This includes the following - +// 1. Forms +// 2. Buttons +// 3. Links +// 4. Elements with event listeners +// +// The navigations found are unique across the page. The caller +// needs to ensure they are unique globally before doing further actions with details. +func (b *BrowserPage) FindNavigations() ([]*types.Action, error) { + unique := make(map[string]struct{}) + + navigations := make([]*types.Action, 0) + + buttons, err := b.GetAllElements(buttonsCSSSelector) + if err != nil { + return nil, errors.Wrap(err, "could not get buttons") + } + for _, button := range buttons { + hash := button.Hash() + button.MD5Hash = hash + + if _, found := unique[hash]; found { + continue + } + unique[hash] = struct{}{} + navigations = append(navigations, &types.Action{ + Type: types.ActionTypeLeftClick, + Element: button, + }) + } + + links, err := b.GetAllElements(linksCSSSelector) + if err != nil { + return nil, errors.Wrap(err, "could not get links") + } + for _, link := range links { + if link.Attributes["href"] == "" { + continue + } + hash := link.Hash() + link.MD5Hash = hash + + if _, found := unique[hash]; found { + continue + } + unique[hash] = struct{}{} + navigations = append(navigations, &types.Action{ + Type: types.ActionTypeLeftClick, + Element: link, + }) + } + + eventListeners, err := b.GetEventListeners() + if err != nil { + return nil, errors.Wrap(err, "could not get event listeners") + } + for _, listener := range eventListeners { + if _, found := relevantEventListeners[listener.Type]; !found { + continue + } + hash := listener.Element.Hash() + listener.Element.MD5Hash = hash + if _, found := unique[hash]; found { + continue + } + unique[hash] = struct{}{} + navigations = append(navigations, types.ActionFromEventListener(listener)) + } + + forms, err := b.GetAllForms() + if err != nil { + return nil, errors.Wrap(err, "could not get forms") + } + for _, form := range forms { + for _, element := range form.Elements { + if element.TagName != "BUTTON" { + continue + } + // TODO: Check if this button is already in the unique map + // and if so remove it + unique[element.Hash()] = struct{}{} + } + hash := form.Hash() + if _, found := unique[hash]; found { + continue + } + unique[hash] = struct{}{} + + navigations = append(navigations, &types.Action{ + Type: types.ActionTypeFillForm, + Form: form, + }) + } + + return navigations, nil +} + +// GetAllElements returns all elements matching the selector +func (b *BrowserPage) GetAllElements(selector string) ([]*types.HTMLElement, error) { + objects, err := b.Page.Eval(`() => window.getAllElements(` + strconv.Quote(selector) + `)`) + if err != nil { + return nil, err + } + + elements := make([]*types.HTMLElement, 0) + if err := objects.Value.Unmarshal(&elements); err != nil { + return nil, err + } + return elements, nil +} + +func (b *BrowserPage) GetElementFromXpath(xpath string) (*types.HTMLElement, error) { + object, err := b.Page.Eval(`() => window.getElementFromXPath(` + strconv.Quote(xpath) + `)`) + if err != nil { + return nil, err + } + + element := &types.HTMLElement{} + if err := object.Value.Unmarshal(element); err != nil { + return nil, err + } + return element, nil +} + +// GetAllForms returns all forms on the page +func (b *BrowserPage) GetAllForms() ([]*types.HTMLForm, error) { + objects, err := b.Page.Eval(`() => window.getAllForms()`) + if err != nil { + return nil, err + } + + elements := make([]*types.HTMLForm, 0) + if err := objects.Value.Unmarshal(&elements); err != nil { + return nil, err + } + return elements, nil +} + +// GetEventListeners returns all event listeners on the page +func (b *BrowserPage) GetEventListeners() ([]*types.EventListener, error) { + listeners := make([]*types.EventListener, 0) + + eventlisteners, err := b.Eval(`() => window.__eventListeners`) + if err == nil { + _ = eventlisteners.Value.Unmarshal(&listeners) + } + + // Also get inline event listeners + var inlineEventListeners []struct { + Element *types.HTMLElement `json:"element"` + Listeners []struct { + Type string `json:"type"` + Listener string `json:"listener"` + } `json:"listeners"` + } + inlineListeners, err := b.Eval(`() => window.getAllElementsWithEventListeners()`) + if err != nil { + return nil, err + } + if err := inlineListeners.Value.Unmarshal(&inlineEventListeners); err != nil { + return nil, err + } + + for _, inlineListener := range inlineEventListeners { + for _, listener := range inlineListener.Listeners { + listenerType := strings.TrimPrefix(listener.Type, "on") + listeners = append(listeners, &types.EventListener{ + Type: listenerType, + Listener: listener.Listener, + Element: inlineListener.Element, + }) + } + } + return listeners, nil +} + +// NavigatedLink is a link navigated collected from one of the +// navigation hooks. +type NavigatedLink struct { + URL string `json:"url"` + Source string `json:"source"` +} + +// GetNavigatedLinks returns all navigated links on the page +func (b *BrowserPage) GetNavigatedLinks() ([]*NavigatedLink, error) { + navigatedLinks, err := b.Eval(`() => window.__navigatedLinks`) + if err != nil { + return nil, err + } + + listeners := make([]*NavigatedLink, 0) + if err := navigatedLinks.Value.Unmarshal(&listeners); err != nil { + return nil, err + } + return listeners, nil +} + +// Define the map to hold event types +var relevantEventListeners = map[string]struct{}{ + // Focus and Blur events + "focusin": {}, + "focus": {}, + "blur": {}, + "focusout": {}, + + // Click and Mouse events + "click": {}, + "auxclick": {}, + "mousedown": {}, + "mouseup": {}, + "dblclick": {}, + "mouseover": {}, + "mouseenter": {}, + "mouseleave": {}, + "mouseout": {}, + "wheel": {}, + "contextmenu": {}, + + // Key events + "keydown": {}, + "keypress": {}, + "keyup": {}, + + // Form events + "submit": {}, + "input": {}, + "change": {}, +} diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go new file mode 100644 index 00000000..9acd3b18 --- /dev/null +++ b/pkg/engine/headless/crawler/crawler.go @@ -0,0 +1,334 @@ +package crawler + +import ( + "fmt" + "log/slog" + "regexp" + "sync" + "time" + + "github.com/adrianbrad/queue" + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/proto" + "github.com/go-rod/rod/lib/utils" + "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/browser" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/normalizer" + "github.com/projectdiscovery/katana/pkg/engine/headless/graph" + "github.com/projectdiscovery/katana/pkg/engine/headless/types" + "github.com/projectdiscovery/katana/pkg/output" +) + +type Crawler struct { + launcher *browser.Launcher + options Options + crawlQueue queue.Queue[*types.Action] + crawlGraph *graph.CrawlGraph + uniqueActions map[string]struct{} +} + +type Options struct { + ChromiumPath string + MaxBrowsers int + MaxDepth int + PageMaxTimeout time.Duration + ShowBrowser bool + SlowMotion bool + MaxCrawlDuration time.Duration + + RequestCallback func(*output.Result) +} + +var domNormalizer *normalizer.Normalizer +var initOnce sync.Once + +func init() { + initOnce.Do(func() { + var err error + domNormalizer, err = normalizer.New() + if err != nil { + panic(err) + } + }) +} + +func New(opts Options) (*Crawler, error) { + launcher, err := browser.NewLauncher(browser.LauncherOptions{ + ChromiumPath: opts.ChromiumPath, + MaxBrowsers: opts.MaxBrowsers, + PageMaxTimeout: opts.PageMaxTimeout, + ShowBrowser: opts.ShowBrowser, + RequestCallback: opts.RequestCallback, + SlowMotion: opts.SlowMotion, + }) + if err != nil { + return nil, err + } + + crawler := &Crawler{ + launcher: launcher, + options: opts, + uniqueActions: make(map[string]struct{}), + } + return crawler, nil +} + +func (c *Crawler) Close() { + c.launcher.Close() +} + +func (c *Crawler) Crawl(URL string) error { + actions := []*types.Action{{ + Type: types.ActionTypeLoadURL, + Input: URL, + Depth: 0, + OriginID: emptyPageHash, + }} + + crawlQueue := queue.NewLinked(actions) + c.crawlQueue = crawlQueue + + crawlGraph := graph.NewCrawlGraph() + c.crawlGraph = crawlGraph + + // Add the initial blank state + err := crawlGraph.AddPageState(types.PageState{ + UniqueID: emptyPageHash, + URL: "about:blank", + Depth: 0, + }) + if err != nil { + return err + } + + var crawlTimeout <-chan time.Time + if c.options.MaxCrawlDuration > 0 { + crawlTimeout = time.After(c.options.MaxCrawlDuration) + } + + for { + select { + case <-crawlTimeout: + slog.Info("Max crawl duration reached, stopping crawl") + return nil + default: + page, err := c.launcher.GetPageFromPool() + if err != nil { + return err + } + + action, err := crawlQueue.Get() + if err == queue.ErrNoElementsAvailable { + slog.Info("No more actions to process") + return nil + } + if err != nil { + return err + } + + slog.Info("Processing action", + slog.String("action", action.String()), + ) + if c.options.MaxDepth > 0 && action.Depth > c.options.MaxDepth { + continue + } + + if err := c.crawlFn(action, page); err != nil { + if err == ErrNoCrawlingAction { + break + } + if errors.Is(err, ErrNoNavigationPossible) { + slog.Warn("Skipping action as no navigation possible", slog.String("action", action.String())) + continue + } + if errors.Is(err, &utils.MaxSleepCountError{}) { + slog.Warn("Skipping action as it is taking too long", slog.String("action", action.String())) + continue + } + slog.Error("Error processing action", + slog.String("error", err.Error()), + slog.String("action", action.String()), + ) + return err + } + } + } +} + +var ErrNoCrawlingAction = errors.New("no more actions to crawl") + +func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error { + defer func() { + c.launcher.PutBrowserToPool(page) + }() + + currentPageHash, err := getPageHash(page) + if err != nil { + return err + } + + if action.OriginID != "" && action.OriginID != currentPageHash { + newPageHash, err := c.navigateBackToStateOrigin(action, page, currentPageHash) + if err != nil { + return err + } + // Refresh the page hash + currentPageHash = newPageHash + } + + // Check the action and do actions based on action type + if err := c.executeCrawlStateAction(action, page); err != nil { + return err + } + + pageState, err := newPageState(page, action) + if err != nil { + return err + } + pageState.OriginID = currentPageHash + + navigations, err := page.FindNavigations() + if err != nil { + return err + } + for _, nav := range navigations { + actionHash := nav.Hash() + if _, ok := c.uniqueActions[actionHash]; ok { + continue + } + c.uniqueActions[actionHash] = struct{}{} + + // Check if the element we have is a logout page + if nav.Element != nil && isLogoutPage(nav.Element) { + slog.Debug("Skipping Found logout page", + slog.String("url", nav.Element.Attributes["href"]), + ) + continue + } + nav.OriginID = pageState.UniqueID + + slog.Debug("Got new navigation", + slog.Any("navigation", nav), + ) + if err := c.crawlQueue.Offer(nav); err != nil { + return err + } + } + err = c.crawlGraph.AddPageState(*pageState) + if err != nil { + return err + } + + // TODO: Check if the page opened new sub pages and if so capture their + // navigation as well as close them so the state change can work. + + if len(navigations) == 0 && c.crawlQueue.Size() == 0 { + return ErrNoCrawlingAction + } + return nil +} + +func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.BrowserPage) error { + var err error + switch action.Type { + case types.ActionTypeLoadURL: + if err := page.Navigate(action.Input); err != nil { + return err + } + if err = page.WaitPageLoadHeurisitics(); err != nil { + return err + } + case types.ActionTypeFillForm: + if err := c.processForm(page, action.Form); err != nil { + return err + } + case types.ActionTypeLeftClick, types.ActionTypeLeftClickDown: + element, err := page.ElementX(action.Element.XPath) + if err != nil { + return err + } + visible, err := element.Visible() + if err != nil { + return err + } + if !visible { + slog.Debug("Skipping click on element as it is not visible", + slog.String("element", action.Element.XPath), + ) + return nil + } + if err := element.Click(proto.InputMouseButtonLeft, 1); err != nil { + if errors.Is(err, &rod.NoPointerEventsError{}) { + slog.Debug("Skipping click on element as it is not pointer events", + slog.String("element", action.Element.XPath), + ) + return nil + } + return err + } + if err = page.WaitPageLoadHeurisitics(); err != nil { + return err + } + default: + return fmt.Errorf("unknown action type: %v", action.Type) + } + return nil +} + +var logoutPattern = regexp.MustCompile(`(?i)(log[\s-]?out|sign[\s-]?out|signout|deconnexion|cerrar[\s-]?sesion|sair|abmelden|uitloggen|exit|disconnect|terminate|end[\s-]?session|salir|desconectar|ausloggen|afmelden|wyloguj|logout|sign[\s-]?off)`) + +func isLogoutPage(element *types.HTMLElement) bool { + return logoutPattern.MatchString(element.TextContent) || + logoutPattern.MatchString(element.Attributes["href"]) +} + +var formFillingData = map[string]string{ + "text": "test", + "number": "5", + "password": "test", + "email": "test@test.com", +} + +func (c *Crawler) processForm(page *browser.BrowserPage, form *types.HTMLForm) error { + var err error + + var submitButtonFinal *rod.Element + for _, field := range form.Elements { + var element *rod.Element + if field.XPath != "" { + if element, err = page.ElementX(field.XPath); err != nil { + return err + } + } + + switch field.TagName { + case "INPUT": + var inputValue string + switch field.Type { + case "text": + inputValue = formFillingData["text"] + case "number": + inputValue = formFillingData["number"] + case "password": + inputValue = formFillingData["password"] + case "email": + inputValue = formFillingData["email"] + } + if err := element.Input(inputValue); err != nil { + return err + } + case "TEXTAREA": + + case "BUTTON": + if submitButtonFinal == nil && field.Type == "submit" { + submitButtonFinal = element + } + } + } + if submitButtonFinal != nil { + if err := submitButtonFinal.Click(proto.InputMouseButtonLeft, 1); err != nil { + return err + } + } + return nil +} diff --git a/pkg/engine/headless/crawler/normalizer/dom_utils.go b/pkg/engine/headless/crawler/normalizer/dom_utils.go new file mode 100644 index 00000000..6efbb22f --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/dom_utils.go @@ -0,0 +1,165 @@ +package normalizer + +import ( + "strings" + + "github.com/PuerkitoBio/goquery" + "golang.org/x/net/html" +) + +// DefaultDOMTransformations is default list of CSS selectors to remove from the DOM. +var DefaultDOMTransformations = []string{ + "style, script, path", // remove script and style tags + "input[type='hidden']", // remove hidden inputs + "meta[content]", // remove meta tags with content + "link[rel='stylesheet']", // remove stylesheet links + "svg", // remove svg + "grammarly-desktop-integration", // remove grammarly + "div[class*='ad'], div[id*='ad'], div[class*='banner'], div[id*='banner'], div[class*='pixel'], div[id*='pixel']", // remove ad, banner and pixel divs + "input[name*='csrf'], input[name*='token']", // remove csrf and token inputs +} + +// NoChildrenDomTransformations removes all elements with no children +var NoChildrenDomTransformations = []string{ + "div", // remove divs with no children + "span", // remove spans with no children +} + +// DOMNormalizer is a normalizer for DOM content +type DOMNormalizer struct { + customTransformations []domTransformationFunc +} + +// NewDOMNormalizer returns a new DOMNormalizer +// +// transformations is a list of CSS selectors to remove from the DOM. +func NewDOMNormalizer() *DOMNormalizer { + var customTransformations []domTransformationFunc + for _, t := range DefaultDOMTransformations { + t := t + customTransformations = append(customTransformations, func(doc *goquery.Document) { + doc.Find(t).Each(func(_ int, s *goquery.Selection) { + s.Remove() + }) + }) + } + customTransformations = append(customTransformations, func(doc *goquery.Document) { + doc.Find("p").Each(func(_ int, s *goquery.Selection) { + // Remove or replace the text node inside

+ removeTextNodes(s) + }) + }) + for _, t := range NoChildrenDomTransformations { + t := t + customTransformations = append(customTransformations, func(doc *goquery.Document) { + doc.Find(t).Each(func(_ int, s *goquery.Selection) { + if s.Children().Length() == 0 && strings.TrimSpace(s.Text()) == "" { + s.Remove() + } + }) + }) + } + return &DOMNormalizer{customTransformations: customTransformations} +} + +func removeTextNodes(s *goquery.Selection) { + node := s.Get(0) + if node == nil { + return + } + for c := node.FirstChild; c != nil; { + next := c.NextSibling + // If it's a text node, remove it. + if c.Type == html.TextNode { + node.RemoveChild(c) + } + c = next + } +} + +// Apply applies the normalizers to the given content +func (d *DOMNormalizer) Apply(content string) (string, error) { + doc, err := goquery.NewDocumentFromReader(strings.NewReader(content)) + if err != nil { + return "", err + } + // Apply selection based transformations + doc.Find("*").Each(func(_ int, s *goquery.Selection) { + for _, f := range selectionBasedTransformationFuncs { + f(s) + } + }) + // Apply custom transformations + for _, f := range d.customTransformations { + f(doc) + } + result, err := doc.Html() + if err != nil { + return "", err + } + return result, nil +} + +// domTransformationFunc does required transformation on document. +type domTransformationFunc func(doc *goquery.Document) + +type selectionTransformationFunc func(s *goquery.Selection) + +var selectionBasedTransformationFuncs = []selectionTransformationFunc{ + removeCommentsDomTransformationFunc, // remove comments + removeClassIDDataAttributesDomTransformationFunc, // remove class, id and data attributes +} + +func removeComments(n *html.Node) { + if n.Type == html.CommentNode { + n.Parent.RemoveChild(n) + } + + for c := n.FirstChild; c != nil; c = c.NextSibling { + removeComments(c) + } +} + +func removeCommentsDomTransformationFunc(s *goquery.Selection) { + removeComments(s.Get(0)) +} + +var attributes = []string{ + "class", + "id", + "name", // name tags is often random + "href", // remove href + "style", + "width", + "height", + "src", + "nowrap", + "target", + "valign", + "cellpadding", + "cellspacing", +} + +func removeClassIDDataAttributesDomTransformationFunc(s *goquery.Selection) { + removeAttributes(s) + + // Handle children + s.Children().Each(func(_ int, child *goquery.Selection) { + removeClassIDDataAttributesDomTransformationFunc(child) + }) +} + +func removeAttributes(s *goquery.Selection) { + for _, attr := range attributes { + s.RemoveAttr(attr) + } + + for _, node := range s.Nodes { + for _, attr := range node.Attr { + attr := attr + if strings.HasPrefix(attr.Key, "data-") || strings.HasPrefix(attr.Key, "aria-") || strings.HasPrefix(attr.Key, "js") { + s.RemoveAttr(attr.Key) + } + } + } +} diff --git a/pkg/engine/headless/crawler/normalizer/dom_utils_test.go b/pkg/engine/headless/crawler/normalizer/dom_utils_test.go new file mode 100644 index 00000000..0100e260 --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/dom_utils_test.go @@ -0,0 +1,78 @@ +package normalizer + +import ( + "testing" +) + +func TestDOMNormalizer_Apply(t *testing.T) { + type args struct { + content string + } + normalizer := NewDOMNormalizer() + + tests := []struct { + name string + d *DOMNormalizer + args args + want string + wantErr bool + }{ + { + name: "comments-style-script", + d: normalizer, + args: args{ + content: `

Hello World

`, + }, + want: "

Hello World

", + wantErr: false, + }, + { + name: "hidden input", + d: normalizer, + args: args{ + content: ``, + }, + want: "", + wantErr: false, + }, + // write tests for other cases + { + name: "csrf", + d: normalizer, + args: args{ + content: ``, + }, + want: "", + wantErr: false, + }, + { + name: "class-id-data-attributes", + d: normalizer, + args: args{ + content: `
`, + }, + want: "
", + }, + { + name: "inline-style", + d: normalizer, + args: args{ + content: `
`, + }, + want: "
", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + d := normalizer + got, err := d.Apply(tt.args.content) + if (err != nil) != tt.wantErr { + t.Errorf("DOMNormalizer.Apply() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("DOMNormalizer.Apply() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/engine/headless/crawler/normalizer/helpers.go b/pkg/engine/headless/crawler/normalizer/helpers.go new file mode 100644 index 00000000..e59bfbbf --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/helpers.go @@ -0,0 +1,43 @@ +package normalizer + +// dateTimePatterns contains regex patterns for various date and time formats +// The ordering is important for proper matching +var dateTimePatterns = []string{ + /* with days */ + "[a-zA-Z]{3,} [0-9]{1,2} [a-zA-Z]{3,} [0-9]{4}", + "[a-zA-Z]{3,} [0-9]{1,2} [a-zA-Z]{3,} '[0-9]{2}", + "[a-zA-Z]{3,} [0-9]{1,2} [a-zA-Z]{3,}", + + /* only numeric */ + "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}", + "[0-9]{4}\\.[0-9]{1,2}\\.[0-9]{1,2}", + "[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}", + "[0-9]{1,2}-[0-9]{1,2}-[0-9]{4}", + "[0-9]{1,2}\\.[0-9]{1,2}\\.[0-9]{4}", + "[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}", + "[0-9]{1,2}-[0-9]{1,2}-'[0-9]{2}", + "[0-9]{1,2}\\.[0-9]{1,2}\\.'[0-9]{2}", + "[0-9]{1,2}/[0-9]{1,2}/'[0-9]{2}", + "[0-9]{1,2}-[0-9]{1,2}-[0-9]{2}", + "[0-9]{1,2}\\.[0-9]{1,2}\\.[0-9]{2}", + "[0-9]{1,2}/[0-9]{1,2}/[0-9]{2}", + + /* long months */ + "[0-9]{1,2} [a-zA-Z]{3,} [0-9]{4}", + "[0-9]{1,2}th [a-zA-Z]{3,} [0-9]{4}", + "[0-9]{1,2}th [a-zA-Z]{3,}", + "[0-9]{4} [a-zA-Z]{3,} [0-9]{1,2}", + "[0-9]{4}[a-zA-Z]{3,}[0-9]{1,2}", + "[a-zA-Z]{3,} [0-9]{4}", + "[a-zA-Z]{3,} '[0-9]{2}", + "[a-zA-Z]{3,} [0-9]{1,2} [0-9]{4}", + "[a-zA-Z]{3,} [0-9]{1,2}, [0-9]{4}", + "[a-zA-Z]{3,} [0-9]{1,2} '[0-9]{2}", + "[a-zA-Z]{3,} [0-9]{1,2}, '[0-9]{2}", + + /* Times */ + "[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}( )?(pm|PM|am|AM)", + "[0-9]{1,2}:[0-9]{1,2}( )?(pm|PM|am|AM)", + "[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}", + "[0-9]{1,2}:[0-9]{1,2}", +} diff --git a/pkg/engine/headless/crawler/normalizer/normalizer.go b/pkg/engine/headless/crawler/normalizer/normalizer.go new file mode 100644 index 00000000..24a693c7 --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/normalizer.go @@ -0,0 +1,104 @@ +package normalizer + +import ( + "fmt" + "html" + "net/url" + "regexp" + "strconv" + "strings" + + "github.com/pkg/errors" +) + +var whiteSpacesRegex = regexp.MustCompile(`\\n|\\r|\s+`) + +// Normalizer is a normalizer for text and DOM content +type Normalizer struct { + dom *DOMNormalizer + text *TextNormalizer +} + +// New returns a new Normalizer +// +// textPatterns is a list of regex patterns to remove from the text. +// domSelectors is a list of CSS selectors to remove from the DOM. +func New() (*Normalizer, error) { + textNormalizer, err := NewTextNormalizer() + if err != nil { + return nil, errors.Wrap(err, "failed to create text normalizer") + } + domNormalizer := NewDOMNormalizer() + return &Normalizer{ + dom: domNormalizer, + text: textNormalizer, + }, nil +} + +// Apply applies the normalizers to the given content +// +// It normalizes the given content by: +// - Applying the DOM normalizer +// - Applying the text normalizer +// - Denormalizing it +func (n *Normalizer) Apply(text string) (string, error) { + first := normalizeDocument(text) + + firstpass, err := n.dom.Apply(first) + if err != nil { + return "", errors.Wrap(err, "failed to apply DOM normalizer") + } + secondpass := n.text.Apply(firstpass) + + thirdpass := normalizeDocument(secondpass) + return thirdpass, nil +} + +// normalizeDocument normalizes the given document by: +// - Lowercasing it +// - URL decoding it +// - HTML entity decoding it +// - Replacing all whitespace variations with a space +// - Trimming the document whitespaces +func normalizeDocument(text string) string { + // Lowercase the document + lowercased := strings.ToLower(text) + + // Convert hexadecimal escape sequences to HTML entities + converted := convertHexEscapeSequencesToEntities(lowercased) + unescaped := html.UnescapeString(converted) + + // URL Decode and HTML entity decode the document to standardize it. + urlDecoded, err := url.QueryUnescape(unescaped) + if err != nil { + urlDecoded = unescaped + } + + // Replace all whitespaces with a space + normalized := whiteSpacesRegex.ReplaceAllString(urlDecoded, " ") + + // Trim the document to remove leading and trailing whitespaces + return strings.Trim(normalized, " \r\n\t") +} + +func replaceHexEscapeSequence(match string) string { + // Remove the '\x' prefix + code := strings.TrimPrefix(match, "\\x") + // Parse the hexadecimal code to an integer + value, err := strconv.ParseInt(code, 16, 32) + if err != nil { + // If there's an error, return the original match + return match + } + // Return the corresponding HTML entity + return fmt.Sprintf("&#x%x;", value) +} + +// Define the regex pattern to match hexadecimal escape sequences +var pattern = regexp.MustCompile(`\\x[0-9a-fA-F]{2}`) + +func convertHexEscapeSequencesToEntities(input string) string { + return pattern.ReplaceAllStringFunc(input, func(match string) string { + return replaceHexEscapeSequence(match) + }) +} diff --git a/pkg/engine/headless/crawler/normalizer/text_utils.go b/pkg/engine/headless/crawler/normalizer/text_utils.go new file mode 100644 index 00000000..c7fcba2e --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/text_utils.go @@ -0,0 +1,62 @@ +package normalizer + +import ( + "fmt" + "regexp" + "slices" +) + +// DefaultTextPatterns is a list of regex patterns for the text normalizer +var DefaultTextPatterns = []string{ + // emailAddress + `[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}`, + // ipAddress + `(?:[0-9]{1,3}\.){3}[0-9]{1,3}`, + // uuid + `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`, + // relativeDates + `(?:[0-9]{1,2}\s(?:days?|weeks?|months?|years?)\s(?:ago|from\snow))`, + // priceAmounts + `[\$€£¥]\s*\d+(?:\.\d{1,2})?`, + // phoneNumbers + `(?:\+?1[0-9]{3}|0[0-9]{2})[ -]?\d{3}[ -]?\d{4}`, + // ssnNumbers + `[\$€£¥]\s*\d+(?:\.\d{1,2})?`, + // timestampRegex + `(?:(?:[0-9]{4}-[0-9]{2}-[0-9]{2})|(?:(?:[0-9]{2}\/){2}[0-9]{4}))\s(?:[0-9]{2}:[0-9]{2}:[0-9]{2})`, +} + +// TextNormalizer is a normalizer for text +type TextNormalizer struct { + // patterns is a list of regex patterns for the text normalizer + patterns []*regexp.Regexp +} + +// NewTextNormalizer returns a new TextNormalizer +// +// patterns is a list of regex patterns for the text normalizer +// DefaultTextPatterns is used if patterns is nil. See DefaultTextPatterns for more info. +func NewTextNormalizer() (*TextNormalizer, error) { + patterns := slices.Clone(DefaultTextPatterns) + patterns = append(patterns, dateTimePatterns...) + + var compiledPatterns []*regexp.Regexp + for _, pattern := range patterns { + pattern := pattern + compiledPattern, err := regexp.Compile(fmt.Sprintf("\\b%s\\b", pattern)) + if err != nil { + return nil, fmt.Errorf("error compiling pattern %s: %v", pattern, err) + } + compiledPatterns = append(compiledPatterns, compiledPattern) + } + return &TextNormalizer{patterns: compiledPatterns}, nil +} + +// Apply applies the patterns to the text and returns the normalized text +func (n *TextNormalizer) Apply(text string) string { + for _, pattern := range n.patterns { + pattern := pattern + text = pattern.ReplaceAllString(text, "") + } + return text +} diff --git a/pkg/engine/headless/crawler/normalizer/text_utils_test.go b/pkg/engine/headless/crawler/normalizer/text_utils_test.go new file mode 100644 index 00000000..69eb6d7a --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/text_utils_test.go @@ -0,0 +1,42 @@ +package normalizer + +import ( + "regexp" + "testing" +) + +func TestTextNormalizer_Apply(t *testing.T) { + type fields struct { + patterns []*regexp.Regexp + } + type args struct { + text string + } + tests := []struct { + name string + fields fields + args args + want string + }{ + { + name: "test", + fields: fields{ + patterns: []*regexp.Regexp{regexp.MustCompile(`[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}`)}, + }, + args: args{ + text: "nizamul@pd.io", + }, + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &TextNormalizer{ + patterns: tt.fields.patterns, + } + if got := n.Apply(tt.args.text); got != tt.want { + t.Errorf("TextNormalizer.Apply() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/engine/headless/crawler/state.go b/pkg/engine/headless/crawler/state.go new file mode 100644 index 00000000..53be772b --- /dev/null +++ b/pkg/engine/headless/crawler/state.go @@ -0,0 +1,257 @@ +package crawler + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "log/slog" + + graphlib "github.com/dominikbraun/graph" + "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/browser" + "github.com/projectdiscovery/katana/pkg/engine/headless/types" +) + +var emptyPageHash = sha256Hash("") + +func isCorrectNavigation(page *browser.BrowserPage, action *types.Action) (string, error) { + currentPageHash, err := getPageHash(page) + if err != nil { + return "", err + } + if currentPageHash != action.OriginID { + return "", fmt.Errorf("failed to navigate back to origin page") + } + return currentPageHash, nil +} + +func getPageHash(page *browser.BrowserPage) (string, error) { + pageState, err := newPageState(page, nil) + if err == ErrEmptyPage { + return emptyPageHash, nil + } + if err != nil { + return "", errors.Wrap(err, "could not get page state") + } + return pageState.UniqueID, nil +} + +var ErrEmptyPage = errors.New("page is empty") + +func newPageState(page *browser.BrowserPage, action *types.Action) (*types.PageState, error) { + pageInfo, err := page.Info() + if err != nil { + return nil, errors.Wrap(err, "could not get page info") + } + if pageInfo.URL == "" || pageInfo.URL == "about:blank" { + return nil, ErrEmptyPage + } + + outerHTML, err := page.HTML() + if err != nil { + return nil, errors.Wrap(err, "could not get html content") + } + + state := &types.PageState{ + URL: pageInfo.URL, + DOM: outerHTML, + NavigationAction: action, + Title: pageInfo.Title, + } + if action != nil { + state.Depth = action.Depth + 1 + } + strippedDOM, err := getStrippedDOM(outerHTML) + if err != nil { + return nil, errors.Wrap(err, "could not get stripped dom") + } + state.StrippedDOM = strippedDOM + + // Get sha256 hash of the stripped dom + state.UniqueID = sha256Hash(strippedDOM) + + return state, nil +} + +func sha256Hash(item string) string { + hasher := sha256.New() + hasher.Write([]byte(item)) + hashItem := hex.EncodeToString(hasher.Sum(nil)) + return hashItem +} + +func getStrippedDOM(contents string) (string, error) { + normalized, err := domNormalizer.Apply(contents) + if err != nil { + return "", errors.Wrap(err, "could not normalize dom") + } + return normalized, nil +} + +var ErrNoNavigationPossible = errors.New("no navigation possible") + +// navigateBackToStateOrigin implements the logic to navigate back to the state origin +// +// It implements different logics as an optimization to decide +// how to navigate back. +// +// 1. If the action has an element, check if the element is visible on the current page +// If the element is visible, directly use that to navigate. +// +// 2. If we have browser history, and the page is in the history which was the origin +// of the action, then we can directly use the browser history to navigate back. +// +// 3. If all else fails, we have the shortest path navigation. +func (c *Crawler) navigateBackToStateOrigin(action *types.Action, page *browser.BrowserPage, currentPageHash string) (string, error) { + slog.Debug("Found action with different origin id", + slog.String("action_origin_id", action.OriginID), + slog.String("current_page_hash", currentPageHash), + ) + + // Get vertex from the graph + originPageState, err := c.crawlGraph.GetPageState(action.OriginID) + if err != nil { + slog.Debug("Failed to get origin page state", slog.String("error", err.Error())) + return "", err + } + + // First, check if the element we want to interact with exists on current page + if action.Element != nil && currentPageHash != emptyPageHash { + newPageHash, err := c.tryElementNavigation(page, action, currentPageHash) + if err != nil { + slog.Debug("Failed to navigate back to origin page using element", slog.String("error", err.Error())) + } + if newPageHash != "" { + return newPageHash, nil + } + } + + // Try to see if we can move back using the browser history + newPageHash, err := c.tryBrowserHistoryNavigation(page, originPageState, action) + if err != nil { + slog.Debug("Failed to navigate back using browser history", slog.String("error", err.Error())) + } + if newPageHash != "" { + return newPageHash, nil + } + + // Finally try Shortest path walking from root. + newPageHash, err = c.tryShortestPathNavigation(action, page, currentPageHash) + if err != nil { + return "", err + } + if newPageHash == "" { + return "", ErrNoNavigationPossible + } + return newPageHash, nil +} + +func (c *Crawler) tryElementNavigation(page *browser.BrowserPage, action *types.Action, currentPageHash string) (string, error) { + element, err := page.ElementX(action.Element.XPath) + if err != nil { + return "", err + } + visible, err := element.Visible() + if err != nil { + return "", err + } + if !visible { + return "", nil + } + // Ensure its the same element + htmlElement, err := page.GetElementFromXpath(action.Element.XPath) + if err != nil { + return "", err + } + // Ensure its the same element in some form + if htmlElement.ID == action.Element.ID || htmlElement.Classes == action.Element.Classes || htmlElement.TextContent == action.Element.TextContent { + slog.Debug("Found target element on current page, proceeding without navigation") + // FIXME: Return the origin element ID so that the graph shows + // correctly the fastest way to reach the state. + return action.OriginID, nil + } + return "", nil +} + +func (c *Crawler) tryBrowserHistoryNavigation(page *browser.BrowserPage, originPageState *types.PageState, action *types.Action) (string, error) { + canNavigateBack, stepsBack, err := c.isBackNavigationPossible(page, originPageState) + if err != nil { + return "", err + } + if !canNavigateBack { + return "", nil + } + + slog.Debug("Navigating back using browser history", slog.Int("steps_back", stepsBack)) + + var navigatedSuccessfully bool + for i := 0; i < stepsBack; i++ { + if err := page.NavigateBack(); err != nil { + return "", err + } + navigatedSuccessfully = true + } + + if !navigatedSuccessfully { + return "", nil + } + + if err := page.WaitPageLoadHeurisitics(); err != nil { + slog.Debug("Failed to wait for page load after navigating back using browser history", slog.String("error", err.Error())) + } + newPageHash, err := isCorrectNavigation(page, action) + if err != nil { + return "", err + } + return newPageHash, nil +} + +func (c *Crawler) isBackNavigationPossible(page *browser.BrowserPage, originPage *types.PageState) (bool, int, error) { + history, err := page.GetNavigationHistory() + if err != nil { + return false, 0, err + } + if len(history.Entries) == 0 { + return false, 0, nil + } + + currentIndex := history.CurrentIndex + for i, entry := range history.Entries { + if entry.URL == originPage.URL && originPage.Title == entry.Title { + stepsBack := currentIndex - i + return true, stepsBack, nil + } + } + return false, 0, nil +} + +func (c *Crawler) tryShortestPathNavigation(action *types.Action, page *browser.BrowserPage, currentPageHash string) (string, error) { + slog.Debug("Trying Shortest path to navigate back to origin page", slog.String("action_origin_id", action.OriginID), slog.String("current_page_hash", currentPageHash)) + + actions, err := c.crawlGraph.ShortestPath(currentPageHash, action.OriginID) + if err != nil { + if errors.Is(err, graphlib.ErrTargetNotReachable) { + slog.Debug("Target not reachable, reaching from blank state", + slog.String("action_origin_id", action.OriginID), + ) + + actions, err = c.crawlGraph.ShortestPath(emptyPageHash, action.OriginID) + if err != nil { + return "", errors.Wrap(err, "could not find path to origin page") + } + } + } + slog.Debug("Found actions to traverse", + slog.Any("actions", actions), + ) + for _, action := range actions { + if err := c.executeCrawlStateAction(action, page); err != nil { + return "", err + } + } + newPageHash, err := isCorrectNavigation(page, action) + if err != nil { + return "", err + } + return newPageHash, nil +} diff --git a/pkg/engine/headless/crawler/state_test.go b/pkg/engine/headless/crawler/state_test.go new file mode 100644 index 00000000..27628c2e --- /dev/null +++ b/pkg/engine/headless/crawler/state_test.go @@ -0,0 +1,103 @@ +package crawler + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +func TestPageFingerprint_Stability(t *testing.T) { + +} + +func TestPageFingerprint(t *testing.T) { + tests := []struct { + name string + html1 string + html2 string + shouldMatch bool + }{ + { + name: "same page different dynamic content", + html1: ` + + Home + +

Welcome John!

+ + + `, + html2: ` + + Home + +

Welcome Jane!

+ + + `, + shouldMatch: true, + }, + { + name: "same form different values", + html1: ` +
+ + +
`, + html2: ` +
+ + +
`, + shouldMatch: true, + }, + { + name: "different error messages", + html1: ` +
Invalid password
`, + html2: ` +
Account locked
`, + shouldMatch: true, + }, + { + name: "different page structure", + html1: ` +

Page 1

Content

`, + html2: ` +

Page 1

Content
`, + shouldMatch: false, + }, + } + + getHash := func(html string) (string, error) { + strippedDOM, err := getStrippedDOM(html) + if err != nil { + return "", errors.Wrap(err, "could not get stripped dom") + } + // Get sha256 hash of the stripped dom + return sha256Hash(strippedDOM), nil + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hash1, err := getHash(tt.html1) + assert.NoError(t, err) + + hash2, err := getHash(tt.html2) + assert.NoError(t, err) + + if tt.shouldMatch { + assert.Equal(t, hash1, hash2) + } else { + assert.NotEqual(t, hash1, hash2) + } + }) + } +} diff --git a/pkg/engine/headless/graph/graph.go b/pkg/engine/headless/graph/graph.go new file mode 100644 index 00000000..e9f318fe --- /dev/null +++ b/pkg/engine/headless/graph/graph.go @@ -0,0 +1,138 @@ +// Package graph implements a Directed Graph for storing +// state information during crawling of a Web Application. +package graph + +import ( + "os" + + "github.com/dominikbraun/graph" + "github.com/dominikbraun/graph/draw" + "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/types" +) + +// CrawlGraph is a graph for storing state information during crawling +type CrawlGraph struct { + graph graph.Graph[string, types.PageState] +} + +func navigationHasherFunc(n types.PageState) string { + return n.UniqueID +} + +// NewCrawlGraph creates a new CrawlGraph instance +func NewCrawlGraph() *CrawlGraph { + return &CrawlGraph{ + graph: graph.New(navigationHasherFunc, func(t *graph.Traits) { + t.IsDirected = true + t.IsRooted = true + t.IsWeighted = true + }), + } +} + +func (g *CrawlGraph) GetVertices() []string { + vertices := []string{} + adjacencyMap, err := g.graph.AdjacencyMap() + if err != nil { + return nil + } + for vertex := range adjacencyMap { + vertices = append(vertices, vertex) + } + return vertices +} + +// AddNavigation adds a navigation to the graph +func (g *CrawlGraph) AddPageState(n types.PageState) error { + vertexAttrs := map[string]string{ + "label": n.URL, + } + if n.IsRoot { + vertexAttrs["is_root"] = "true" + } + + err := g.graph.AddVertex(n, func(vp *graph.VertexProperties) { + vp.Weight = n.Depth + vp.Attributes = vertexAttrs + }) + if err != nil { + if errors.Is(err, graph.ErrVertexAlreadyExists) { + return nil + } + return errors.Wrap(err, "could not add vertex to graph") + } + + if n.NavigationAction != nil { + edgeAttrs := map[string]string{ + "label": n.NavigationAction.String(), + } + + err = g.graph.AddEdge(n.OriginID, n.UniqueID, func(ep *graph.EdgeProperties) { + ep.Weight = n.Depth + ep.Attributes = edgeAttrs + }) + if err != nil { + if errors.Is(err, graph.ErrEdgeAlreadyExists) { + return nil + } + return errors.Wrap(err, "could not add edge to graph") + } + } + return nil +} + +func (g *CrawlGraph) AddEdge(sourceState, targetState string, action *types.Action) error { + edgeAttrs := map[string]string{ + "label": action.String(), + } + err := g.graph.AddEdge(sourceState, targetState, func(ep *graph.EdgeProperties) { + ep.Weight = action.Depth + ep.Attributes = edgeAttrs + }) + if err != nil { + if errors.Is(err, graph.ErrEdgeAlreadyExists) { + return nil + } + return errors.Wrap(err, "could not add edge to graph") + } + return nil +} + +func (g *CrawlGraph) GetPageState(id string) (*types.PageState, error) { + pageVertex, err := g.graph.Vertex(id) + if err != nil { + return nil, errors.Wrap(err, "could not get vertex") + } + return &pageVertex, nil +} + +func (g *CrawlGraph) ShortestPath(sourceState, targetState string) ([]*types.Action, error) { + shortestPath, err := graph.ShortestPath(g.graph, sourceState, targetState) + if err != nil { + return nil, errors.Wrap(err, "could not find shortest path") + } + var actionsSlice []*types.Action + for _, path := range shortestPath { + pageVertex, err := g.graph.Vertex(path) + if err != nil { + return nil, errors.Wrap(err, "could not get vertex") + } + + if pageVertex.URL == "about:blank" { + continue + } + actionsSlice = append(actionsSlice, pageVertex.NavigationAction) + } + return actionsSlice, nil +} + +func (g *CrawlGraph) DrawGraph(file string) error { + f, err := os.Create(file) + if err != nil { + return errors.Wrap(err, "could not create graph file") + } + defer f.Close() + + return draw.DOT(g.graph, f) +} diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go new file mode 100644 index 00000000..4ee1d8dc --- /dev/null +++ b/pkg/engine/headless/headless.go @@ -0,0 +1,69 @@ +package headless + +import ( + "log/slog" + "os" + "time" + + "github.com/lmittmann/tint" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler" + "github.com/projectdiscovery/katana/pkg/output" + "github.com/projectdiscovery/katana/pkg/types" +) + +type Headless struct { + options *types.CrawlerOptions +} + +// New returns a new headless crawler instance +func New(options *types.CrawlerOptions) (*Headless, error) { + // create a new logger + writer := os.Stderr + + // set global logger with custom options + level := slog.LevelInfo + if options.Options.Debug { + level = slog.LevelDebug + } + slog.SetDefault(slog.New( + tint.NewHandler(writer, &tint.Options{ + Level: level, + TimeFormat: time.Kitchen, + }), + )) + + return &Headless{ + options: options, + }, nil +} + +// Crawl executes the headless crawling on a given URL +func (h *Headless) Crawl(URL string) error { + crawlOpts := crawler.Options{ + ChromiumPath: h.options.Options.SystemChromePath, + MaxDepth: h.options.Options.MaxDepth, + ShowBrowser: h.options.Options.ShowBrowser, + MaxCrawlDuration: h.options.Options.CrawlDuration, + MaxBrowsers: 1, + PageMaxTimeout: 30 * time.Second, + RequestCallback: func(rr *output.Result) { + h.options.OutputWriter.Write(rr) + }, + } + // TODO: Make the crawling multi-threaded. Right now concurrency is hardcoded to 1. + + headlessCrawler, err := crawler.New(crawlOpts) + if err != nil { + return err + } + defer headlessCrawler.Close() + + if err = headlessCrawler.Crawl(URL); err != nil { + return err + } + return nil +} + +func (h *Headless) Close() error { + return nil +} diff --git a/pkg/engine/headless/js/js.go b/pkg/engine/headless/js/js.go new file mode 100644 index 00000000..ea65cc7e --- /dev/null +++ b/pkg/engine/headless/js/js.go @@ -0,0 +1,27 @@ +package js + +import ( + _ "embed" + + "github.com/go-rod/rod" + "github.com/pkg/errors" +) + +var ( + //go:embed utils.js + utilsJavascriptBundle string + + //go:embed page-init.js + pageInitJavascriptBundle string +) + +// InitJavascriptEnv injects the necessary javascript code into the browser +func InitJavascriptEnv(page *rod.Page) error { + if _, err := page.EvalOnNewDocument(utilsJavascriptBundle); err != nil { + return errors.Wrap(err, "failed to inject utils.js") + } + if _, err := page.EvalOnNewDocument(pageInitJavascriptBundle); err != nil { + return errors.Wrap(err, "failed to inject page-init.js") + } + return nil +} diff --git a/pkg/engine/headless/js/page-init.js b/pkg/engine/headless/js/page-init.js new file mode 100644 index 00000000..21426791 --- /dev/null +++ b/pkg/engine/headless/js/page-init.js @@ -0,0 +1,160 @@ +// This script initializes the page and hooks up event listeners +// and other interesting stuff needed to make the crawling work. +// +// Actions performed: +// +// 1. Hook addTargetListener to capture all the event listeners added on the page. +// These are accessible via window.__eventListeners +// 2. Hook window.open to capture all the opened pages. +// These are accessible via window.__navigatedLinks +// 3. Hook setTimeout and setInterval to speed up delayed actions +// 4. Hook form reset to prevent the form from being reset +// 5. Hook window.close to prevent the page from being closed +// 6. Hook history pushState and replaceState for new links +// 7. Add event listener for hashchange to identify new navigations +// 8. TODO: Hook inline event listeners so that layer0 event listeners can be tracked as well +(function pageInitAndHook() { + const markElementReadonlyProperties = { + writable: false, + configurable: false, + }; + + // hookNavigatedLinkSinks hooks the navigated link sinks + // on the page to capture all the navigated links. + function hookNavigatedLinkSinks() { + window.__navigatedLinks = []; + + // Hook history.pushState and history.replaceState to capture all the navigated links + window.history.pushState = function (a, b, c) { + window.__navigatedLinks.push({ url: c, source: "history.pushState" }); + }; + window.history.replaceState = function (a, b, c) { + window.__navigatedLinks.push({ url: c, source: "history.replaceState" }); + }; + Object.defineProperty( + window.history, + "pushState", + markElementReadonlyProperties + ); + Object.defineProperty( + window.history, + "replaceState", + markElementReadonlyProperties + ); + // Hook window.open to capture all the opened pages + window.open = function (url) { + console.log("[hook] open url request", url); + window.__navigatedLinks.push({ url: url, source: "window.open" }); + }; + Object.defineProperty(window, "open", markElementReadonlyProperties); + + // Add event listener for hashchange + window.addEventListener("hashchange", function () { + window.__navigatedLinks.push({ + url: document.location.href, + source: "hashchange", + }); + }); + + var oldWebSocket = window.WebSocket; + window.WebSocket = function (url, arg) { + window.__navigatedLinks.push({ url: url, source: "websocket" }); + return new oldWebSocket(url, arg); + }; + + var oldEventSource = window.EventSource; + window.EventSource = function (url, arg) { + window.__navigatedLinks.push({ url: url, source: "eventsource" }); + return new oldEventSource(url, arg); + }; + + var originalFetch = window.fetch; + window.fetch = function (...args) { + const url = args[0] instanceof Request ? args[0].url : args[0]; + window.__navigatedLinks.push({ url: url, source: "fetch" }); + return originalFetch.apply(this, args); + }; + } + + // hookMiscellaneousUtilities performs miscellaneous hooks + // on the page to prevent certain actions from happening + // and to speed up certain actions. + function hookMiscellaneousUtilities() { + // Hook form reset to prevent the form from being reset + HTMLFormElement.prototype.reset = function () { + console.log("[hook] cancel reset form"); + }; + Object.defineProperty( + HTMLFormElement.prototype, + "reset", + markElementReadonlyProperties + ); + + // Hook window.close to prevent the page from being closed + window.close = function () { + console.log("[hook] trying to close page."); + }; + Object.defineProperty(window, "close", markElementReadonlyProperties); + + // Hook setTimeout and setInterval to speed up delayed actions + // on the page. This is useful where there is some request happening + // on the page after a delay or some animation happening after a delay. + const originalSetTimeout = window.setTimeout; + const originalSetInterval = window.setInterval; + + const speedUpFactor = 0.1; // For example, 10 times faster + + window.setTimeout = function (callback, delay, ...args) { + return originalSetTimeout(callback, delay * speedUpFactor, ...args); + }; + window.setInterval = function (callback, delay, ...args) { + return originalSetInterval(callback, delay * speedUpFactor, ...args); + }; + } + + // hookAddEventListener hooks the addTargetListener to capture + // all the event listeners added on the page + function hookAddEventListener() { + const originalAddEventListener = Element.prototype.addEventListener; + + window.__eventListeners = []; + Element.prototype.addEventListener = function (type, listener, options) { + // Ensure `this` is a valid element and has the necessary properties + if (!this || !this.tagName) { + return originalAddEventListener.call(this, type, listener, options); + } + + if (this.tagName == "BODY") { + return originalAddEventListener.call(this, type, listener, options); + } + let item = { + element: { + tagName: this.tagName, + id: this.id, + classes: this.className, + outerHTML: this.outerHTML.slice(0, 100), // Capture a snippet of the element's outerHTML + xpath: window.getXPath(this), + cssSelector: window.getCssPath(this), + attributes: window.getElementAttributes(this), + textContent: this.textContent.trim(), + hidden: this.hidden, + name: this.name, + type: this.type, + value: this.value, + }, + type: type, + listener: listener.toString(), + options: options || {}, + }; + console.log("[hook] got event listener", item); + window.__eventListeners.push(item); + return originalAddEventListener.call(this, type, listener, options); + }; + } + + // Main hook initialization part + // hookAddEventListener(); + // hookNavigatedLinkSinks(); + // hookMiscellaneousUtilities(); + })(); + \ No newline at end of file diff --git a/pkg/engine/headless/js/utils.js b/pkg/engine/headless/js/utils.js new file mode 100644 index 00000000..28cf9384 --- /dev/null +++ b/pkg/engine/headless/js/utils.js @@ -0,0 +1,357 @@ +// This file contains utility JS functions that are utilised by +// the main crawling JS code to perform actions. +(function initUtilityFunctions() { + // getElementAttributes returns the attributes of an element + window.getElementAttributes = function (element) { + const attrs = {}; + for (let attr of element.attributes) { + attrs[attr.name] = attr.value; + } + return attrs; + }; + + // _elementDataFromElement returns the data for an element + window._elementDataFromElement = function (el) { + return { + tagName: el.tagName, + id: el.id, + classes: el.className, + attributes: getElementAttributes(el), + hidden: el.hidden, + outerHTML: el.outerHTML, + name: el.name, + type: el.type, + value: el.value, + textContent: el.textContent.trim(), + xpath: window.getXPath(el), + cssSelector: window.getCssPath(el), + }; + }; + + // getAllElements returns all the elements for a query + // selector on the page + window.getAllElements = function (selector) { + const buttons = document.querySelectorAll(selector); + return Array.from(buttons).map((button) => _elementDataFromElement(button)); + }; + + window.getElementFromXPath = function (xpath) { + const element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; + if (!element) { + return null; + } + return _elementDataFromElement(element); + } + + // getAllElementsWithEventListeners returns all the elements + // on the page along with their event listeners + // TODO: Is it optimized? or do we need to do something else? + window.getAllElementsWithEventListeners = function () { + const elements = document.querySelectorAll("*"); + const elementsWithListeners = []; + for (let el of elements) { + const listeners = getEventListeners(el); + if (listeners && listeners.length) { + elementsWithListeners.push({ + element: _elementDataFromElement(el), + listeners: listeners, + }); + } + } + return elementsWithListeners; + }; + + // getEventListeners returns all the event listeners + // attached to an element + function getEventListeners(element) { + const listeners = []; + for (let event in element) { + if (event.startsWith("on")) { + const listener = element[event]; + if (typeof listener === "function") { + listeners.push({ + type: event, + listener: listener.toString(), + }); + } + } + } + return listeners; + } + + // getAllForms returns all the forms on the page + // along with their elements + window.getAllForms = function () { + const forms = document.querySelectorAll("form"); + const pseudoForms = document.querySelectorAll("div.form"); + + const allForms = [...forms, ...pseudoForms]; + return Array.from(allForms).map((form) => ({ + tagName: form.tagName, + id: form.id, + classes: form.className, + attributes: getElementAttributes(form), + outerHTML: form.outerHTML, + action: form.action, + method: form.method, + xpath: window.getXPath(form), + cssSelector: window.getCssPath(form), + elements: form.elements ? + Array.from(form.elements).map((el) => _elementDataFromElement(el)) : + Array.from(form.querySelectorAll('input, select, textarea, button')).map((el) => _elementDataFromElement(el)) + })); + }; + + // Copyright (C) Chrome Authors + // The below code is part of the Chrome DevTools project + // and is adapted from there. + + // Utility to get the CSS selector path for an element. + window.getCssPath = function (node, optimized = false) { + if (node.nodeType !== Node.ELEMENT_NODE) return ""; + + const steps = []; + let contextNode = node; + while (contextNode) { + const step = window._cssPathStep( + contextNode, + optimized, + contextNode === node + ); + if (!step) break; // Error - bail out early. + steps.push(step.value); + if (step.optimized) break; + contextNode = contextNode.parentNode; + } + + steps.reverse(); + return steps.join(" > "); + }; + + // Utility to get the XPath for an element. + window.getXPath = function (node, optimized = false) { + if (node.nodeType === Node.DOCUMENT_NODE) return "/"; + + const steps = []; + let contextNode = node; + while (contextNode) { + const step = window._xPathValue(contextNode, optimized); + if (!step) break; // Error - bail out early. + steps.push(step.value); + if (step.optimized) break; + contextNode = contextNode.parentNode; + } + + steps.reverse(); + return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/"); + }; + + // Helper to create a step in the CSS path. + window._cssPathStep = function (node, optimized, isTargetNode) { + if (node.nodeType !== Node.ELEMENT_NODE) return null; + + const id = node.getAttribute("id"); + if (optimized) { + if (id) return { value: `#${id}`, optimized: true }; + const nodeNameLower = node.nodeName.toLowerCase(); + if ( + nodeNameLower === "body" || + nodeNameLower === "head" || + nodeNameLower === "html" + ) + return { value: node.nodeName, optimized: true }; + } + const nodeName = node.nodeName; + + if (id) return { value: `${nodeName}#${id}`, optimized: true }; + const parent = node.parentNode; + if (!parent || parent.nodeType === Node.DOCUMENT_NODE) + return { value: nodeName, optimized: true }; + + const prefixedOwnClassNamesArray = window.prefixedElementClassNames(node); + let needsClassNames = false; + let needsNthChild = false; + let ownIndex = -1; + let elementIndex = -1; + const siblings = parent.children; + for ( + let i = 0; + (ownIndex === -1 || !needsNthChild) && i < siblings.length; + ++i + ) { + const sibling = siblings[i]; + if (sibling.nodeType !== Node.ELEMENT_NODE) continue; + elementIndex += 1; + if (sibling === node) { + ownIndex = elementIndex; + continue; + } + if (needsNthChild) continue; + if (sibling.nodeName.toLowerCase() !== nodeName.toLowerCase()) continue; + + needsClassNames = true; + const ownClassNames = new Set(prefixedOwnClassNamesArray); + if (!ownClassNames.size) { + needsNthChild = true; + continue; + } + const siblingClassNamesArray = window.prefixedElementClassNames(sibling); + for (let j = 0; j < siblingClassNamesArray.length; ++j) { + const siblingClass = siblingClassNamesArray[j]; + if (!ownClassNames.has(siblingClass)) continue; + ownClassNames.delete(siblingClass); + if (!ownClassNames.size) { + needsNthChild = true; + break; + } + } + } + + let result = nodeName; + if ( + isTargetNode && + nodeName.toLowerCase() === "input" && + node.getAttribute("type") && + !node.getAttribute("id") && + !node.getAttribute("class") + ) + result += '[type="' + node.getAttribute("type") + '"]'; + if (needsNthChild) { + result += `:nth-child(${ownIndex + 1})`; + } else if (needsClassNames) { + for (const prefixedName of prefixedOwnClassNamesArray) + result += "." + window.escapeIdentifierIfNeeded(prefixedName.substr(1)); + } + + return { value: result, optimized: false }; + }; + + // Helper to get class names prefixed with '$' for mapping purposes. + window.prefixedElementClassNames = function (node) { + const classAttribute = node.getAttribute("class"); + if (!classAttribute) return []; + + return classAttribute + .split(/\s+/g) + .filter(Boolean) + .map(function (name) { + return "$" + name; + }); + }; + + // Helper to escape identifiers for use in CSS selectors. + window.escapeIdentifierIfNeeded = function (ident) { + if (window.isCSSIdentifier(ident)) return ident; + const shouldEscapeFirst = /^(?:[0-9]|-[0-9-]?)/.test(ident); + const lastIndex = ident.length - 1; + return ident.replace(/./g, function (c, i) { + return (shouldEscapeFirst && i === 0) || !window.isCSSIdentChar(c) + ? window.escapeAsciiChar(c, i === lastIndex) + : c; + }); + }; + + // Helper to determine if a character is valid in a CSS identifier. + window.isCSSIdentChar = function (c) { + if (/[a-zA-Z0-9_-]/.test(c)) return true; + return c.charCodeAt(0) >= 0xa0; + }; + + // Helper to determine if a string is a valid CSS identifier. + window.isCSSIdentifier = function (value) { + return /^-{0,2}[a-zA-Z_][a-zA-Z0-9_-]*$/.test(value); + }; + + // Helper to escape ASCII characters for use in CSS selectors. + window.escapeAsciiChar = function (c, isLast) { + return ( + "\\" + c.charCodeAt(0).toString(16).padStart(2, "0") + (isLast ? "" : " ") + ); + }; + + // Helper to get the XPath step for a node. + window._xPathValue = function (node, optimized) { + let ownValue; + const ownIndex = window._xPathIndex(node); + if (ownIndex === -1) return null; + + switch (node.nodeType) { + case Node.ELEMENT_NODE: + if (optimized && node.getAttribute("id")) + return { + value: `//*[@id="${node.getAttribute("id")}"]`, + optimized: true, + }; + ownValue = node.localName; + break; + case Node.ATTRIBUTE_NODE: + ownValue = "@" + node.nodeName; + break; + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + ownValue = "text()"; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ownValue = "processing-instruction()"; + break; + case Node.COMMENT_NODE: + ownValue = "comment()"; + break; + case Node.DOCUMENT_NODE: + ownValue = ""; + break; + default: + ownValue = ""; + break; + } + + if (ownIndex > 0) ownValue += `[${ownIndex}]`; + + return { value: ownValue, optimized: node.nodeType === Node.DOCUMENT_NODE }; + }; + + // Helper to get the XPath index for a node. + window._xPathIndex = function (node) { + function areNodesSimilar(left, right) { + if (left === right) return true; + + if ( + left.nodeType === Node.ELEMENT_NODE && + right.nodeType === Node.ELEMENT_NODE + ) + return left.localName === right.localName; + + if (left.nodeType === right.nodeType) return true; + + const leftType = + left.nodeType === Node.CDATA_SECTION_NODE + ? Node.TEXT_NODE + : left.nodeType; + const rightType = + right.nodeType === Node.CDATA_SECTION_NODE + ? Node.TEXT_NODE + : right.nodeType; + return leftType === rightType; + } + + const siblings = node.parentNode ? node.parentNode.children : null; + if (!siblings) return 0; + let hasSameNamedElements = false; + for (let i = 0; i < siblings.length; ++i) { + if (areNodesSimilar(node, siblings[i]) && siblings[i] !== node) { + hasSameNamedElements = true; + break; + } + } + if (!hasSameNamedElements) return 0; + let ownIndex = 1; + for (let i = 0; i < siblings.length; ++i) { + if (areNodesSimilar(node, siblings[i])) { + if (siblings[i] === node) return ownIndex; + ++ownIndex; + } + } + return -1; + }; + })(); + \ No newline at end of file diff --git a/pkg/engine/headless/types/types.go b/pkg/engine/headless/types/types.go new file mode 100644 index 00000000..6b20a989 --- /dev/null +++ b/pkg/engine/headless/types/types.go @@ -0,0 +1,286 @@ +package types + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "regexp" + "sort" + "strings" +) + +var ( + IsDiagnosticEnabled = false +) + +// PageState represents a page in the state of the +// web application as determined by the crawler. +// It represents the vertex of the crawl graph +type PageState struct { + UniqueID string `json:"unique_id"` + OriginID string `json:"origin_id"` + URL string `json:"url"` + Title string `json:"title"` + DOM string `json:"dom"` + StrippedDOM string `json:"stripped_dom"` + Depth int `json:"depth"` + IsRoot bool `json:"is_root"` + + // NavigationAction is actions taken to reach this state + NavigationAction *Action `json:"navigation_actions"` +} + +// Action is a action taken in the browser +type Action struct { + OriginID string `json:"origin_id"` + Type ActionType `json:"type"` + Input string `json:"input"` + Element *HTMLElement `json:"element"` + Form *HTMLForm `json:"form"` + Depth int `json:"depth"` + ResultID string `json:"result_id"` +} + +func (a *Action) Hash() string { + if a.Element != nil { + return a.Element.Hash() + } + if a.Form != nil { + return a.Form.Hash() + } + return "" +} + +func (a *Action) String() string { + var builder strings.Builder + builder.WriteString(string(a.Type)) + if a.Type == ActionTypeLoadURL { + builder.WriteString(fmt.Sprintf(" %s", a.Input)) + } + if a.Element != nil { + builder.WriteString(fmt.Sprintf(" on %s", a.Element)) + } + value := builder.String() + return value +} + +type ActionType string + +const ( + ActionTypeUnknown ActionType = "unknown" + ActionTypeLoadURL ActionType = "load_url" + ActionTypeExecuteJS ActionType = "execute_js" + ActionTypeLeftClick ActionType = "left_click" + ActionTypeLeftClickDown ActionType = "left_click_down" + ActionTypeLeftClickUp ActionType = "left_click_up" + ActionTypeRightClick ActionType = "right_click" + ActionTypeDoubleClick ActionType = "double_click" + ActionTypeScroll ActionType = "scroll" + ActionTypeSendKeys ActionType = "send_keys" + ActionTypeKeyUp ActionType = "key_up" + ActionTypeKeyDown ActionType = "key_down" + ActionTypeHover ActionType = "hover" + ActionTypeFocus ActionType = "focus" + ActionTypeBlur ActionType = "blur" + ActionTypeMouseOverAndOut ActionType = "mouse_over_and_out" + ActionTypeMouseWheel ActionType = "mouse_wheel" + ActionTypeFillForm ActionType = "fill_form" + ActionTypeWait ActionType = "wait" + ActionTypeRedirect ActionType = "redirect" + ActionTypeSubRequest ActionType = "sub_request" +) + +func ActionFromEventListener(listener *EventListener) *Action { + var actionType ActionType + + switch listener.Type { + case "click": + actionType = ActionTypeLeftClick + case "mousedown": + actionType = ActionTypeLeftClickDown + case "mouseup": + actionType = ActionTypeLeftClickUp + case "keydown": + actionType = ActionTypeKeyDown + case "keyup": + actionType = ActionTypeKeyUp + case "focus": + actionType = ActionTypeFocus + case "blur": + actionType = ActionTypeBlur + case "scroll": + actionType = ActionTypeScroll + case "dblclick": + actionType = ActionTypeDoubleClick + case "contextmenu": + actionType = ActionTypeRightClick + case "mouseover", "mouseout": + actionType = ActionTypeMouseOverAndOut + case "wheel": + actionType = ActionTypeMouseWheel + } + + return &Action{ + Type: actionType, + Element: listener.Element, + } +} + +// HTMLElement represents a DOM element +type HTMLElement struct { + TagName string `json:"tagName"` + ID string `json:"id"` + Classes string `json:"classes"` + Attributes map[string]string `json:"attributes"` + Hidden bool `json:"hidden"` + OuterHTML string `json:"outerHTML"` + Type string `json:"type"` + Value string `json:"value"` + CSSSelector string `json:"cssSelector"` + XPath string `json:"xpath"` + TextContent string `json:"textContent"` + MD5Hash string `json:"md5Hash"` +} + +func (e *HTMLElement) String() string { + var builder strings.Builder + builder.WriteString(e.TagName) + if e.ID != "" { + builder.WriteString(fmt.Sprintf("#%s", e.ID)) + } + if e.Classes != "" { + builder.WriteString(fmt.Sprintf(".%s", e.Classes)) + } + if e.TextContent != "" { + e.TextContent = strings.Trim(e.TextContent, " \n\r\t") + builder.WriteString(fmt.Sprintf(" (%s)", e.TextContent)) + } + value := builder.String() + return value +} + +var ( + dynamicIDAndClassPattern = regexp.MustCompile(`^\d+$|^id_\d+|\bclass_\w{8}\b`) +) + +func (e *HTMLElement) Hash() string { + hasher := md5.New() + + var parts []string + // Use stable identifiers + parts = append(parts, e.TagName) + + if e.ID != "" { + parts = append(parts, "id:"+e.ID) + } + if e.Classes != "" { + parts = append(parts, "class:"+e.Classes) + } + + // Add stable attributes + stableAttrs := getStableAttributes(e.Attributes) + for _, k := range stableAttrs { + parts = append(parts, fmt.Sprintf("%s:%s", k, e.Attributes[k])) + } + + hashInput := strings.Join(parts, "|") + if IsDiagnosticEnabled { + fmt.Printf("[diagnostic] Element hash input: %s\n", hashInput) + } + hasher.Write([]byte(hashInput)) + return hex.EncodeToString(hasher.Sum(nil)) +} + +// HTMLForm represents a form element +type HTMLForm struct { + TagName string `json:"tagName"` + ID string `json:"id"` + Classes string `json:"classes"` + Attributes map[string]string `json:"attributes"` + Hidden bool `json:"hidden"` + OuterHTML string `json:"outerHTML"` + Action string `json:"action"` + Method string `json:"method"` + Elements []*HTMLElement `json:"elements"` + CSSSelector string `json:"cssSelector"` + XPath string `json:"xpath"` +} + +func (f *HTMLForm) Hash() string { + hasher := md5.New() + + var parts []string + parts = append(parts, f.TagName) + + if f.ID != "" { + parts = append(parts, "id:"+f.ID) + } + if f.Classes != "" { + parts = append(parts, "class:"+f.Classes) + } + + // Add stable attributes + stableAttrs := getStableAttributes(f.Attributes) + for _, k := range stableAttrs { + parts = append(parts, fmt.Sprintf("%s:%s", k, f.Attributes[k])) + } + parts = append(parts, fmt.Sprintf("action:%s", f.Action), fmt.Sprintf("method:%s", f.Method)) + + // Include hashes of form elements + for _, element := range f.Elements { + parts = append(parts, element.Hash()) + } + + hashInput := strings.Join(parts, "|") + if IsDiagnosticEnabled { + fmt.Printf("[diagnostic] Form hash input: %s\n", hashInput) + } + hasher.Write([]byte(hashInput)) + return hex.EncodeToString(hasher.Sum(nil)) +} + +// getStableAttributes returns a sorted slice of attribute keys that are considered stable. +func getStableAttributes(attrs map[string]string) []string { + stableKeys := map[string]struct{}{ + "id": {}, + "name": {}, + "type": {}, + "href": {}, + "src": {}, + "action": {}, + "method": {}, + "placeholder": {}, + } + + var stableAttrs []string + for key := range attrs { + if _, exists := stableKeys[key]; exists { + stableAttrs = append(stableAttrs, key) + } + } + + // Sort the attributes to ensure consistent order for hashing. + sort.Strings(stableAttrs) + + return stableAttrs +} + +type EventListener struct { + Element *HTMLElement `json:"element"` + Type string `json:"type"` + Listener string `json:"listener"` +} + +// NavigationType represents the type of navigation +type NavigationType string + +const ( + // NavigationTypeForm represents a form navigation + NavigationTypeForm NavigationType = "form" + // NavigationTypeButton represents a button navigation + NavigationTypeButton NavigationType = "button" + // NavigationTypeLink represents a link navigation + NavigationTypeLink NavigationType = "link" + // NavigationTypeEventListener represents an event listener navigation + NavigationTypeEventListener NavigationType = "eventlistener" +) diff --git a/pkg/types/options.go b/pkg/types/options.go index cc536b75..09fc5e1a 100644 --- a/pkg/types/options.go +++ b/pkg/types/options.go @@ -97,6 +97,8 @@ type Options struct { CustomHeaders goflags.StringSlice // Headless enables headless scraping Headless bool + // HeadlessHybrid enables headless hybrid scraping + HeadlessHybrid bool // AutomaticFormFill enables optional automatic form filling and submission AutomaticFormFill bool // FormExtraction enables extraction of form, input, textarea & select elements From e27c636adae8d7cbc7a7280a2d49e053b5962802 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Mon, 13 Jan 2025 19:47:29 +0530 Subject: [PATCH 02/22] feat: use requests body + close browser & page --- pkg/engine/headless/browser/browser.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 6e0e8268..6054bc91 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -108,6 +108,7 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { if browserErr := browser.Connect(); browserErr != nil { return nil, browserErr } + return browser, nil } @@ -196,7 +197,6 @@ func (l *Launcher) GetPageFromPool() (*BrowserPage, error) { if err != nil { return nil, err } - return browserPage, nil } @@ -253,7 +253,7 @@ func (b *BrowserPage) handlePageDialogBoxes() error { req := navigation.Request{ Method: httpreq.Method, URL: httpreq.URL.String(), - Body: string(body), + Body: e.Request.PostData, Headers: utils.FlattenHeaders(httpreq.Header), Raw: string(rawBytesRequest), } @@ -342,14 +342,14 @@ func (l *Launcher) PutBrowserToPool(browser *BrowserPage) { // If the browser is not connected, close it if !isBrowserConnected(browser.Browser) { browser.cancel() - _ = browser.Browser.Close() + browser.CloseBrowserPage() return } pages, err := browser.Browser.Pages() if err != nil { browser.cancel() - _ = browser.Browser.Close() + browser.CloseBrowserPage() return } From 59ff15d6be9f6ce1918efb026d110b7b4628c060 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Wed, 15 Jan 2025 02:55:57 +0530 Subject: [PATCH 03/22] feat: misc additions to scope --- pkg/engine/headless/browser/browser.go | 7 ++++++ pkg/engine/headless/browser/element.go | 33 +++++++++++++++++++++++++- pkg/engine/headless/crawler/crawler.go | 5 ++++ pkg/engine/headless/headless.go | 28 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 6054bc91..8ff51e86 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -43,9 +43,12 @@ type LauncherOptions struct { Proxy string SlowMotion bool + ScopeValidator ScopeValidator RequestCallback func(*output.Result) } +type ScopeValidator func(string) bool + // NewLauncher returns a new launcher instance func NewLauncher(opts LauncherOptions) (*Launcher, error) { l := &Launcher{ @@ -55,6 +58,10 @@ func NewLauncher(opts LauncherOptions) (*Launcher, error) { return l, nil } +func (l *Launcher) ScopeValidator() ScopeValidator { + return l.opts.ScopeValidator +} + func (l *Launcher) launchBrowser() (*rod.Browser, error) { chromeLauncher := launcher.New(). Leakless(true). diff --git a/pkg/engine/headless/browser/element.go b/pkg/engine/headless/browser/element.go index 011309fa..6262f417 100644 --- a/pkg/engine/headless/browser/element.go +++ b/pkg/engine/headless/browser/element.go @@ -1,6 +1,7 @@ package browser import ( + "net/url" "strconv" "strings" @@ -49,14 +50,30 @@ func (b *BrowserPage) FindNavigations() ([]*types.Action, error) { }) } + scopeValidator := b.launcher.ScopeValidator() links, err := b.GetAllElements(linksCSSSelector) if err != nil { return nil, errors.Wrap(err, "could not get links") } + info, err := b.Page.Info() + if err != nil { + return nil, errors.Wrap(err, "could not get page info") + } for _, link := range links { - if link.Attributes["href"] == "" { + href := link.Attributes["href"] + if href == "" { + continue + } + + resolvedHref, err := resolveURL(info.URL, href) + if err != nil { + continue + } + + if !scopeValidator(resolvedHref) { continue } + hash := link.Hash() link.MD5Hash = hash @@ -246,3 +263,17 @@ var relevantEventListeners = map[string]struct{}{ "input": {}, "change": {}, } + +// resolveURL resolves a potentially relative URL against a base URL +func resolveURL(baseURLStr, href string) (string, error) { + baseURL, err := url.Parse(baseURLStr) + if err != nil { + return "", err + } + + resolvedURL, err := baseURL.Parse(href) + if err != nil { + return "", err + } + return resolvedURL.String(), nil +} diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 9acd3b18..01482c90 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -36,6 +36,7 @@ type Options struct { SlowMotion bool MaxCrawlDuration time.Duration + ScopeValidator browser.ScopeValidator RequestCallback func(*output.Result) } @@ -60,6 +61,7 @@ func New(opts Options) (*Crawler, error) { ShowBrowser: opts.ShowBrowser, RequestCallback: opts.RequestCallback, SlowMotion: opts.SlowMotion, + ScopeValidator: opts.ScopeValidator, }) if err != nil { return nil, err @@ -176,6 +178,9 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error currentPageHash = newPageHash } + // FIXME: TODO: Restrict the navigation using scope manager and only + // proceed with actions if the scope is allowed + // Check the action and do actions based on action type if err := c.executeCrawlStateAction(action, page); err != nil { return err diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 4ee1d8dc..7231f9ac 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -2,10 +2,12 @@ package headless import ( "log/slog" + "net/url" "os" "time" "github.com/lmittmann/tint" + "github.com/projectdiscovery/katana/pkg/engine/headless/browser" "github.com/projectdiscovery/katana/pkg/engine/headless/crawler" "github.com/projectdiscovery/katana/pkg/output" "github.com/projectdiscovery/katana/pkg/types" @@ -37,8 +39,30 @@ func New(options *types.CrawlerOptions) (*Headless, error) { }, nil } +func validateScopeFunc(h *Headless, URL string) browser.ScopeValidator { + parsedURL, err := url.Parse(URL) + if err != nil { + return nil + } + rootHostname := parsedURL.Hostname() + + return func(s string) bool { + parsed, err := url.Parse(s) + if err != nil { + return false + } + validated, err := h.options.ScopeManager.Validate(parsed, rootHostname) + if err != nil { + return false + } + return validated + } +} + // Crawl executes the headless crawling on a given URL func (h *Headless) Crawl(URL string) error { + scopeValidator := validateScopeFunc(h, URL) + crawlOpts := crawler.Options{ ChromiumPath: h.options.Options.SystemChromePath, MaxDepth: h.options.Options.MaxDepth, @@ -46,7 +70,11 @@ func (h *Headless) Crawl(URL string) error { MaxCrawlDuration: h.options.Options.CrawlDuration, MaxBrowsers: 1, PageMaxTimeout: 30 * time.Second, + ScopeValidator: scopeValidator, RequestCallback: func(rr *output.Result) { + if !scopeValidator(rr.Request.URL) { + return + } h.options.OutputWriter.Write(rr) }, } From 21472384848018e4bbaf85c71df0113a442b59d6 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Wed, 15 Jan 2025 15:59:30 +0530 Subject: [PATCH 04/22] feat: pass logger from outside + do not use global --- pkg/engine/headless/crawler/crawler.go | 25 ++++++++++++++----------- pkg/engine/headless/crawler/state.go | 20 ++++++++++---------- pkg/engine/headless/headless.go | 25 ++++++++++++++++++------- pkg/types/crawler_options.go | 4 ++++ 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 01482c90..fc13a5f6 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -20,6 +20,7 @@ import ( ) type Crawler struct { + logger *slog.Logger launcher *browser.Launcher options Options crawlQueue queue.Queue[*types.Action] @@ -36,6 +37,7 @@ type Options struct { SlowMotion bool MaxCrawlDuration time.Duration + Logger *slog.Logger ScopeValidator browser.ScopeValidator RequestCallback func(*output.Result) } @@ -70,6 +72,7 @@ func New(opts Options) (*Crawler, error) { crawler := &Crawler{ launcher: launcher, options: opts, + logger: opts.Logger, uniqueActions: make(map[string]struct{}), } return crawler, nil @@ -111,7 +114,7 @@ func (c *Crawler) Crawl(URL string) error { for { select { case <-crawlTimeout: - slog.Info("Max crawl duration reached, stopping crawl") + c.logger.Info("Max crawl duration reached, stopping crawl") return nil default: page, err := c.launcher.GetPageFromPool() @@ -121,14 +124,14 @@ func (c *Crawler) Crawl(URL string) error { action, err := crawlQueue.Get() if err == queue.ErrNoElementsAvailable { - slog.Info("No more actions to process") + c.logger.Info("No more actions to process") return nil } if err != nil { return err } - slog.Info("Processing action", + c.logger.Info("Processing action", slog.String("action", action.String()), ) if c.options.MaxDepth > 0 && action.Depth > c.options.MaxDepth { @@ -140,14 +143,14 @@ func (c *Crawler) Crawl(URL string) error { break } if errors.Is(err, ErrNoNavigationPossible) { - slog.Warn("Skipping action as no navigation possible", slog.String("action", action.String())) + c.logger.Warn("Skipping action as no navigation possible", slog.String("action", action.String())) continue } if errors.Is(err, &utils.MaxSleepCountError{}) { - slog.Warn("Skipping action as it is taking too long", slog.String("action", action.String())) + c.logger.Warn("Skipping action as it is taking too long", slog.String("action", action.String())) continue } - slog.Error("Error processing action", + c.logger.Error("Error processing action", slog.String("error", err.Error()), slog.String("action", action.String()), ) @@ -205,14 +208,14 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error // Check if the element we have is a logout page if nav.Element != nil && isLogoutPage(nav.Element) { - slog.Debug("Skipping Found logout page", + c.logger.Debug("Skipping Found logout page", slog.String("url", nav.Element.Attributes["href"]), ) continue } nav.OriginID = pageState.UniqueID - slog.Debug("Got new navigation", + c.logger.Debug("Got new navigation", slog.Any("navigation", nav), ) if err := c.crawlQueue.Offer(nav); err != nil { @@ -257,14 +260,14 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br return err } if !visible { - slog.Debug("Skipping click on element as it is not visible", + c.logger.Debug("Skipping click on element as it is not visible", slog.String("element", action.Element.XPath), ) return nil } if err := element.Click(proto.InputMouseButtonLeft, 1); err != nil { if errors.Is(err, &rod.NoPointerEventsError{}) { - slog.Debug("Skipping click on element as it is not pointer events", + c.logger.Debug("Skipping click on element as it is not pointer events", slog.String("element", action.Element.XPath), ) return nil @@ -280,7 +283,7 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br return nil } -var logoutPattern = regexp.MustCompile(`(?i)(log[\s-]?out|sign[\s-]?out|signout|deconnexion|cerrar[\s-]?sesion|sair|abmelden|uitloggen|exit|disconnect|terminate|end[\s-]?session|salir|desconectar|ausloggen|afmelden|wyloguj|logout|sign[\s-]?off)`) +var logoutPattern = regexp.MustCompile(`(?i)(log[\s-]?out|sign[\s-]?out|signout|deconnexion|cerrar[\s-]?sesion|sair|abmelden|uitloggen|exit|disconnect|terminate|end[\s-]?session|salir|desconectar|auc.loggergen|afmelden|wyloguj|logout|sign[\s-]?off)`) func isLogoutPage(element *types.HTMLElement) bool { return logoutPattern.MatchString(element.TextContent) || diff --git a/pkg/engine/headless/crawler/state.go b/pkg/engine/headless/crawler/state.go index 53be772b..d5889aad 100644 --- a/pkg/engine/headless/crawler/state.go +++ b/pkg/engine/headless/crawler/state.go @@ -103,7 +103,7 @@ var ErrNoNavigationPossible = errors.New("no navigation possible") // // 3. If all else fails, we have the shortest path navigation. func (c *Crawler) navigateBackToStateOrigin(action *types.Action, page *browser.BrowserPage, currentPageHash string) (string, error) { - slog.Debug("Found action with different origin id", + c.logger.Debug("Found action with different origin id", slog.String("action_origin_id", action.OriginID), slog.String("current_page_hash", currentPageHash), ) @@ -111,7 +111,7 @@ func (c *Crawler) navigateBackToStateOrigin(action *types.Action, page *browser. // Get vertex from the graph originPageState, err := c.crawlGraph.GetPageState(action.OriginID) if err != nil { - slog.Debug("Failed to get origin page state", slog.String("error", err.Error())) + c.logger.Debug("Failed to get origin page state", slog.String("error", err.Error())) return "", err } @@ -119,7 +119,7 @@ func (c *Crawler) navigateBackToStateOrigin(action *types.Action, page *browser. if action.Element != nil && currentPageHash != emptyPageHash { newPageHash, err := c.tryElementNavigation(page, action, currentPageHash) if err != nil { - slog.Debug("Failed to navigate back to origin page using element", slog.String("error", err.Error())) + c.logger.Debug("Failed to navigate back to origin page using element", slog.String("error", err.Error())) } if newPageHash != "" { return newPageHash, nil @@ -129,7 +129,7 @@ func (c *Crawler) navigateBackToStateOrigin(action *types.Action, page *browser. // Try to see if we can move back using the browser history newPageHash, err := c.tryBrowserHistoryNavigation(page, originPageState, action) if err != nil { - slog.Debug("Failed to navigate back using browser history", slog.String("error", err.Error())) + c.logger.Debug("Failed to navigate back using browser history", slog.String("error", err.Error())) } if newPageHash != "" { return newPageHash, nil @@ -165,7 +165,7 @@ func (c *Crawler) tryElementNavigation(page *browser.BrowserPage, action *types. } // Ensure its the same element in some form if htmlElement.ID == action.Element.ID || htmlElement.Classes == action.Element.Classes || htmlElement.TextContent == action.Element.TextContent { - slog.Debug("Found target element on current page, proceeding without navigation") + c.logger.Debug("Found target element on current page, proceeding without navigation") // FIXME: Return the origin element ID so that the graph shows // correctly the fastest way to reach the state. return action.OriginID, nil @@ -182,7 +182,7 @@ func (c *Crawler) tryBrowserHistoryNavigation(page *browser.BrowserPage, originP return "", nil } - slog.Debug("Navigating back using browser history", slog.Int("steps_back", stepsBack)) + c.logger.Debug("Navigating back using browser history", slog.Int("steps_back", stepsBack)) var navigatedSuccessfully bool for i := 0; i < stepsBack; i++ { @@ -197,7 +197,7 @@ func (c *Crawler) tryBrowserHistoryNavigation(page *browser.BrowserPage, originP } if err := page.WaitPageLoadHeurisitics(); err != nil { - slog.Debug("Failed to wait for page load after navigating back using browser history", slog.String("error", err.Error())) + c.logger.Debug("Failed to wait for page load after navigating back using browser history", slog.String("error", err.Error())) } newPageHash, err := isCorrectNavigation(page, action) if err != nil { @@ -226,12 +226,12 @@ func (c *Crawler) isBackNavigationPossible(page *browser.BrowserPage, originPage } func (c *Crawler) tryShortestPathNavigation(action *types.Action, page *browser.BrowserPage, currentPageHash string) (string, error) { - slog.Debug("Trying Shortest path to navigate back to origin page", slog.String("action_origin_id", action.OriginID), slog.String("current_page_hash", currentPageHash)) + c.logger.Debug("Trying Shortest path to navigate back to origin page", slog.String("action_origin_id", action.OriginID), slog.String("current_page_hash", currentPageHash)) actions, err := c.crawlGraph.ShortestPath(currentPageHash, action.OriginID) if err != nil { if errors.Is(err, graphlib.ErrTargetNotReachable) { - slog.Debug("Target not reachable, reaching from blank state", + c.logger.Debug("Target not reachable, reaching from blank state", slog.String("action_origin_id", action.OriginID), ) @@ -241,7 +241,7 @@ func (c *Crawler) tryShortestPathNavigation(action *types.Action, page *browser. } } } - slog.Debug("Found actions to traverse", + c.logger.Debug("Found actions to traverse", slog.Any("actions", actions), ) for _, action := range actions { diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 7231f9ac..113cc45e 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -14,12 +14,25 @@ import ( ) type Headless struct { + logger *slog.Logger options *types.CrawlerOptions } // New returns a new headless crawler instance func New(options *types.CrawlerOptions) (*Headless, error) { - // create a new logger + logger := newLogger(options) + + return &Headless{ + logger: logger, + options: options, + }, nil +} + +func newLogger(options *types.CrawlerOptions) *slog.Logger { + if options.Logger != nil { + return options.Logger + } + writer := os.Stderr // set global logger with custom options @@ -27,16 +40,13 @@ func New(options *types.CrawlerOptions) (*Headless, error) { if options.Options.Debug { level = slog.LevelDebug } - slog.SetDefault(slog.New( + logger := slog.New( tint.NewHandler(writer, &tint.Options{ Level: level, TimeFormat: time.Kitchen, }), - )) - - return &Headless{ - options: options, - }, nil + ) + return logger } func validateScopeFunc(h *Headless, URL string) browser.ScopeValidator { @@ -77,6 +87,7 @@ func (h *Headless) Crawl(URL string) error { } h.options.OutputWriter.Write(rr) }, + Logger: h.logger, } // TODO: Make the crawling multi-threaded. Right now concurrency is hardcoded to 1. diff --git a/pkg/types/crawler_options.go b/pkg/types/crawler_options.go index 170c7a16..c6976155 100644 --- a/pkg/types/crawler_options.go +++ b/pkg/types/crawler_options.go @@ -2,6 +2,7 @@ package types import ( "context" + "log/slog" "regexp" "time" @@ -34,6 +35,9 @@ type CrawlerOptions struct { Dialer *fastdialer.Dialer // Wappalyzer instance for technologies detection Wappalyzer *wappalyzer.Wappalyze + + // Optional structured logger for headless crawler + Logger *slog.Logger } // NewCrawlerOptions creates a new crawler options structure From 2577bc20b2dfcf921a6d1718e2782521b81649cd Mon Sep 17 00:00:00 2001 From: Ice3man Date: Wed, 15 Jan 2025 19:45:46 +0530 Subject: [PATCH 05/22] added user to optioanl flags --- pkg/engine/headless/browser/browser.go | 30 ++++++++++++++++++++------ pkg/engine/headless/crawler/crawler.go | 3 +++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 8ff51e86..cad828e4 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -9,6 +9,8 @@ import ( "net/http" "net/http/httputil" "os" + "os/user" + "strconv" "strings" "sync" "time" @@ -31,7 +33,8 @@ import ( type Launcher struct { browserPool rod.Pool[BrowserPage] - opts LauncherOptions + userDataDir string + opts LauncherOptions } // LauncherOptions contains options for the launcher @@ -42,6 +45,7 @@ type LauncherOptions struct { ShowBrowser bool Proxy string SlowMotion bool + ChromeUser *user.User // optional chrome user to use ScopeValidator ScopeValidator RequestCallback func(*output.Result) @@ -92,15 +96,26 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { chromeLauncher = chromeLauncher.Headless(false) } - // CHeck to see if we need to disable sandbox - if os.Getuid() == 0 { - chromeLauncher = chromeLauncher.Set("no-sandbox", "true") - } - if l.opts.ChromiumPath != "" { chromeLauncher = chromeLauncher.Bin(l.opts.ChromiumPath) } + if l.opts.ChromeUser != nil { + tempDir, err := os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") + if err != nil { + return nil, errors.Wrap(err, "could not create temporary chrome data directory") + } + uid, _ := strconv.Atoi(l.opts.ChromeUser.Uid) + gid, _ := strconv.Atoi(l.opts.ChromeUser.Gid) + + // Sets proper ownership of the Chrome data directory + if err := os.Chown(tempDir, uid, gid); err != nil { + return nil, errors.Wrap(err, "could not change ownership of chrome data directory") + } + chromeLauncher = chromeLauncher.Set("user-data-dir", tempDir) + l.userDataDir = tempDir + } + launcherURL, err := chromeLauncher.Launch() if err != nil { return nil, err @@ -125,6 +140,9 @@ func (l *Launcher) Close() { b.cancel() b.CloseBrowserPage() }) + if l.userDataDir != "" { + _ = os.RemoveAll(l.userDataDir) + } } // BrowserPage is a combination of a browser and a page diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index fc13a5f6..c3a96435 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -3,6 +3,7 @@ package crawler import ( "fmt" "log/slog" + "os/user" "regexp" "sync" "time" @@ -40,6 +41,7 @@ type Options struct { Logger *slog.Logger ScopeValidator browser.ScopeValidator RequestCallback func(*output.Result) + ChromeUser *user.User } var domNormalizer *normalizer.Normalizer @@ -64,6 +66,7 @@ func New(opts Options) (*Crawler, error) { RequestCallback: opts.RequestCallback, SlowMotion: opts.SlowMotion, ScopeValidator: opts.ScopeValidator, + ChromeUser: opts.ChromeUser, }) if err != nil { return nil, err From eeff64658569c1afe0d73a0fc1d03563a5f2233b Mon Sep 17 00:00:00 2001 From: Ice3man Date: Wed, 15 Jan 2025 19:47:35 +0530 Subject: [PATCH 06/22] misc --- pkg/engine/headless/headless.go | 3 ++- pkg/types/crawler_options.go | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 113cc45e..8b74c8f4 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -87,7 +87,8 @@ func (h *Headless) Crawl(URL string) error { } h.options.OutputWriter.Write(rr) }, - Logger: h.logger, + Logger: h.logger, + ChromeUser: h.options.ChromeUser, } // TODO: Make the crawling multi-threaded. Right now concurrency is hardcoded to 1. diff --git a/pkg/types/crawler_options.go b/pkg/types/crawler_options.go index c6976155..5f06e57c 100644 --- a/pkg/types/crawler_options.go +++ b/pkg/types/crawler_options.go @@ -3,6 +3,7 @@ package types import ( "context" "log/slog" + "os/user" "regexp" "time" @@ -38,6 +39,8 @@ type CrawlerOptions struct { // Optional structured logger for headless crawler Logger *slog.Logger + // ChromeUser is the user to use for chrome + ChromeUser *user.User } // NewCrawlerOptions creates a new crawler options structure From 0ffba7320e7a36c27bdefb3fbcf6ad455e91396d Mon Sep 17 00:00:00 2001 From: Ice3man Date: Thu, 16 Jan 2025 13:21:26 +0530 Subject: [PATCH 07/22] misc changes --- pkg/engine/headless/browser/browser.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index cad828e4..fa57adca 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -99,6 +99,7 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { if l.opts.ChromiumPath != "" { chromeLauncher = chromeLauncher.Bin(l.opts.ChromiumPath) } + chromeLauncher = chromeLauncher.Logger(os.Stderr) if l.opts.ChromeUser != nil { tempDir, err := os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") @@ -420,8 +421,6 @@ var headlessFlags = []string{ "--disable-default-apps", "--disable-dev-shm-usage", "--disable-extensions", - "--disable-web-security", - "--no-zygote", // AvoidUnnecessaryBeforeUnloadCheckSync - https://github.com/microsoft/playwright/issues/14047 // Translate - https://github.com/microsoft/playwright/issues/16126 // HttpsUpgrades - https://github.com/microsoft/playwright/pull/27605 From 0e575386d740703fd7815343b32c73b2fcf330c7 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Thu, 16 Jan 2025 19:34:13 +0530 Subject: [PATCH 08/22] feat: multiple bug fixes + edge cases handlings --- pkg/engine/headless/browser/browser.go | 5 ++-- pkg/engine/headless/crawler/crawler.go | 37 +++++++++++++++----------- pkg/engine/headless/crawler/state.go | 7 +++++ pkg/engine/headless/js/utils.js | 8 +++--- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index fa57adca..3e6d2e85 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -99,7 +99,6 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { if l.opts.ChromiumPath != "" { chromeLauncher = chromeLauncher.Bin(l.opts.ChromiumPath) } - chromeLauncher = chromeLauncher.Logger(os.Stderr) if l.opts.ChromeUser != nil { tempDir, err := os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") @@ -194,8 +193,8 @@ func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { return nil, errors.Wrap(err, "could not create new page") } page = page.Sleeper(func() rodutils.Sleeper { - return backoffCountSleeper(30*time.Millisecond, 1*time.Second, 5, func(d time.Duration) time.Duration { - return d * 2 + return backoffCountSleeper(100*time.Millisecond, 1*time.Second, 4, func(d time.Duration) time.Duration { + return d + (d / 2) // This avoids the float conversion issue }) }) ctx := page.GetContext() diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index c3a96435..29a5fddb 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -117,40 +117,48 @@ func (c *Crawler) Crawl(URL string) error { for { select { case <-crawlTimeout: - c.logger.Info("Max crawl duration reached, stopping crawl") + c.logger.Debug("Max crawl duration reached, stopping crawl") return nil default: - page, err := c.launcher.GetPageFromPool() - if err != nil { - return err - } - action, err := crawlQueue.Get() if err == queue.ErrNoElementsAvailable { - c.logger.Info("No more actions to process") + c.logger.Debug("No more actions to process") return nil } if err != nil { return err } - c.logger.Info("Processing action", - slog.String("action", action.String()), - ) if c.options.MaxDepth > 0 && action.Depth > c.options.MaxDepth { continue } + page, err := c.launcher.GetPageFromPool() + if err != nil { + return err + } + + c.logger.Debug("Processing action", + slog.String("action", action.String()), + ) + if err := c.crawlFn(action, page); err != nil { if err == ErrNoCrawlingAction { break } + if errors.Is(err, &rod.NavigationError{}) { + c.logger.Debug("Skipping action as navigation failed", + slog.String("action", action.String()), + slog.String("error", err.Error()), + ) + continue + } if errors.Is(err, ErrNoNavigationPossible) { - c.logger.Warn("Skipping action as no navigation possible", slog.String("action", action.String())) + c.logger.Debug("Skipping action as no navigation possible", slog.String("action", action.String())) continue } if errors.Is(err, &utils.MaxSleepCountError{}) { - c.logger.Warn("Skipping action as it is taking too long", slog.String("action", action.String())) + c.logger.Debug("Skipping action as it is taking too long", slog.String("action", action.String())) continue } c.logger.Error("Error processing action", @@ -269,10 +277,7 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br return nil } if err := element.Click(proto.InputMouseButtonLeft, 1); err != nil { - if errors.Is(err, &rod.NoPointerEventsError{}) { - c.logger.Debug("Skipping click on element as it is not pointer events", - slog.String("element", action.Element.XPath), - ) + if errors.Is(err, &rod.NoPointerEventsError{}) || errors.Is(err, &rod.InvisibleShapeError{}) { return nil } return err diff --git a/pkg/engine/headless/crawler/state.go b/pkg/engine/headless/crawler/state.go index d5889aad..efdf22f5 100644 --- a/pkg/engine/headless/crawler/state.go +++ b/pkg/engine/headless/crawler/state.go @@ -158,6 +158,13 @@ func (c *Crawler) tryElementNavigation(page *browser.BrowserPage, action *types. if !visible { return "", nil } + + // Also ensure its interactable + interactable, err := element.Interactable() + if err != nil || interactable == nil { + return "", nil + } + // Ensure its the same element htmlElement, err := page.GetElementFromXpath(action.Element.XPath) if err != nil { diff --git a/pkg/engine/headless/js/utils.js b/pkg/engine/headless/js/utils.js index 28cf9384..c8137c8e 100644 --- a/pkg/engine/headless/js/utils.js +++ b/pkg/engine/headless/js/utils.js @@ -15,13 +15,13 @@ return { tagName: el.tagName, id: el.id, - classes: el.className, + classes: typeof el.className === 'string' ? el.className : Array.from(el.classList).join(' '), attributes: getElementAttributes(el), hidden: el.hidden, outerHTML: el.outerHTML, name: el.name, type: el.type, - value: el.value, + value: el.value != null ? String(el.value) : '', textContent: el.textContent.trim(), xpath: window.getXPath(el), cssSelector: window.getCssPath(el), @@ -89,10 +89,10 @@ return Array.from(allForms).map((form) => ({ tagName: form.tagName, id: form.id, - classes: form.className, + classes: typeof form.className === 'string' ? form.className : Array.from(form.classList).join(' '), attributes: getElementAttributes(form), outerHTML: form.outerHTML, - action: form.action, + action: form.action ? String(form.action) : '', method: form.method, xpath: window.getXPath(form), cssSelector: window.getCssPath(form), From c1b06d7f54489ae22adca3a58d1c21e5b85f9675 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Mon, 16 Jun 2025 23:02:40 +0530 Subject: [PATCH 09/22] feat: more additions + code, diagnostics, cookie-popups and stealth --- cmd/katana/main.go | 2 + pkg/engine/headless/browser/browser.go | 47 +- pkg/engine/headless/browser/cookie/cookie.go | 120 + .../headless/browser/cookie/cookie_test.go | 48 + pkg/engine/headless/browser/cookie/rules.json | 19539 ++++++++++++++++ pkg/engine/headless/browser/stealth/assets.go | 8 + pkg/engine/headless/crawler/crawler.go | 117 +- .../crawler/diagnostics/diagnostics.go | 127 + .../headless/crawler/normalizer/dom_utils.go | 6 +- pkg/engine/headless/crawler/state.go | 34 +- pkg/engine/headless/headless.go | 59 +- pkg/engine/headless/types/types.go | 84 +- pkg/types/options.go | 4 + 13 files changed, 20103 insertions(+), 92 deletions(-) create mode 100644 pkg/engine/headless/browser/cookie/cookie.go create mode 100644 pkg/engine/headless/browser/cookie/cookie_test.go create mode 100644 pkg/engine/headless/browser/cookie/rules.json create mode 100644 pkg/engine/headless/browser/stealth/assets.go create mode 100644 pkg/engine/headless/crawler/diagnostics/diagnostics.go diff --git a/cmd/katana/main.go b/cmd/katana/main.go index 6cbd6be2..b1b7e5ea 100644 --- a/cmd/katana/main.go +++ b/cmd/katana/main.go @@ -147,6 +147,8 @@ pipelines offering both headless and non-headless crawling.`) flagSet.BoolVarP(&options.HeadlessNoIncognito, "no-incognito", "noi", false, "start headless chrome without incognito mode"), flagSet.StringVarP(&options.ChromeWSUrl, "chrome-ws-url", "cwu", "", "use chrome browser instance launched elsewhere with the debugger listening at this URL"), flagSet.BoolVarP(&options.XhrExtraction, "xhr-extraction", "xhr", false, "extract xhr request url,method in jsonl output"), + flagSet.IntVarP(&options.MaxFailureCount, "max-failure-count", "mfc", 10, "maximum number of consecutive action failures before stopping"), + flagSet.BoolVarP(&options.EnableDiagnostics, "enable-diagnostics", "ed", false, "enable diagnostics"), ) flagSet.CreateGroup("scope", "Scope", diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 3e6d2e85..567c848a 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -21,6 +21,8 @@ import ( "github.com/go-rod/rod/lib/proto" rodutils "github.com/go-rod/rod/lib/utils" "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/browser/cookie" + "github.com/projectdiscovery/katana/pkg/engine/headless/browser/stealth" "github.com/projectdiscovery/katana/pkg/engine/headless/js" "github.com/projectdiscovery/katana/pkg/navigation" "github.com/projectdiscovery/katana/pkg/output" @@ -39,13 +41,15 @@ type Launcher struct { // LauncherOptions contains options for the launcher type LauncherOptions struct { - ChromiumPath string - MaxBrowsers int - PageMaxTimeout time.Duration - ShowBrowser bool - Proxy string - SlowMotion bool - ChromeUser *user.User // optional chrome user to use + ChromiumPath string + MaxBrowsers int + PageMaxTimeout time.Duration + ShowBrowser bool + Proxy string + SlowMotion bool + Trace bool + CookieConsentBypass bool + ChromeUser *user.User // optional chrome user to use ScopeValidator ScopeValidator RequestCallback func(*output.Result) @@ -123,6 +127,9 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { browser := rod.New(). ControlURL(launcherURL) + if l.opts.Trace { + browser = browser.Trace(true) + } if l.opts.SlowMotion { browser = browser.SlowMotion(1 * time.Second) @@ -156,7 +163,7 @@ type BrowserPage struct { // WaitPageLoadHeurisitics waits for the page to load using heuristics func (b *BrowserPage) WaitPageLoadHeurisitics() error { - chainedTimeout := b.Timeout(30 * time.Second) + chainedTimeout := b.Timeout(15 * time.Second) _ = chainedTimeout.WaitLoad() _ = chainedTimeout.WaitIdle(1 * time.Second) @@ -193,8 +200,8 @@ func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { return nil, errors.Wrap(err, "could not create new page") } page = page.Sleeper(func() rodutils.Sleeper { - return backoffCountSleeper(100*time.Millisecond, 1*time.Second, 4, func(d time.Duration) time.Duration { - return d + (d / 2) // This avoids the float conversion issue + return backoffCountSleeper(100*time.Millisecond, 1*time.Second, 3, func(d time.Duration) time.Duration { + return d * 1 }) }) ctx := page.GetContext() @@ -209,6 +216,11 @@ func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { } browserPage.handlePageDialogBoxes() + // Add stealth evasion JS + _, err = page.EvalOnNewDocument(stealth.JS) + if err != nil { + return nil, errors.Wrap(err, "could not initialize stealth") + } err = js.InitJavascriptEnv(page) if err != nil { return nil, errors.Wrap(err, "could not initialize javascript env") @@ -258,6 +270,21 @@ func (b *BrowserPage) handlePageDialogBoxes() error { }, func(e *proto.FetchRequestPaused) { + if b.launcher.opts.CookieConsentBypass { + // Check if request should be blocked by cookie consent rules + var originStr string + if origin, ok := e.Request.Headers["Origin"]; ok { + originStr = origin.Str() + } + if cookie.ShouldBlockRequest(e.Request.URL, e.ResourceType, originStr) { + _ = proto.FetchFailRequest{ + RequestID: e.RequestID, + ErrorReason: proto.NetworkErrorReasonBlockedByClient, + }.Call(b.Page) + return + } + } + if e.ResponseStatusCode == nil || e.ResponseErrorReason != "" || *e.ResponseStatusCode >= 301 && *e.ResponseStatusCode <= 308 { fetchContinueRequest(b.Page, e) return diff --git a/pkg/engine/headless/browser/cookie/cookie.go b/pkg/engine/headless/browser/cookie/cookie.go new file mode 100644 index 00000000..ae15882e --- /dev/null +++ b/pkg/engine/headless/browser/cookie/cookie.go @@ -0,0 +1,120 @@ +// Package cookie implements cookie consent handling for the +// crawler. Its a partial port of I-Still-Dont-Care-About-Cookies. +package cookie + +import ( + _ "embed" + "encoding/json" + "strings" + + "github.com/go-rod/rod/lib/proto" +) + +type CookieConsentBlockRequest struct { + ID int `json:"id"` + Priority int `json:"priority"` + Condition Condition `json:"condition,omitempty"` +} + +type Action struct { + Type string `json:"type"` +} + +type Condition struct { + URLFilter string `json:"urlFilter"` + ResourceTypes []string `json:"resourceTypes"` + InitiatorDomains []string `json:"initiatorDomains"` + ExcludedInitiatorDomains []string `json:"excludedInitiatorDomains"` +} + +//go:embed rules.json +var rules []byte + +var cookieConsentBlockRequests []CookieConsentBlockRequest + +func init() { + err := json.Unmarshal(rules, &cookieConsentBlockRequests) + if err != nil { + panic(err) + } +} + +// ShouldBlockRequest determines if a request should be blocked based on cookie consent rules +func ShouldBlockRequest(url string, resourceType proto.NetworkResourceType, initiatorDomain string) bool { + resourceTypeStr := getResourceType(resourceType) + for _, rule := range cookieConsentBlockRequests { + if matchesRule(rule, url, resourceTypeStr, initiatorDomain) { + return true + } + } + return false +} + +// matchesRule checks if a request matches a specific cookie consent block rule +func matchesRule(rule CookieConsentBlockRequest, url string, resourceType string, initiatorDomain string) bool { + if !strings.Contains(url, rule.Condition.URLFilter) { + return false + } + + if len(rule.Condition.ResourceTypes) > 0 { + matched := false + for _, rt := range rule.Condition.ResourceTypes { + if rt == resourceType { + matched = true + break + } + } + if !matched { + return false + } + } + + if len(rule.Condition.InitiatorDomains) > 0 { + matched := false + for _, domain := range rule.Condition.InitiatorDomains { + if strings.Contains(initiatorDomain, domain) { + matched = true + break + } + } + if !matched { + return false + } + } + + if len(rule.Condition.ExcludedInitiatorDomains) > 0 { + for _, domain := range rule.Condition.ExcludedInitiatorDomains { + if strings.Contains(initiatorDomain, domain) { + return false + } + } + } + + return true +} + +func getResourceType(resourceType proto.NetworkResourceType) string { + switch resourceType { + case proto.NetworkResourceTypeStylesheet: + return "stylesheet" + case proto.NetworkResourceTypeScript: + return "script" + case proto.NetworkResourceTypeImage: + return "image" + case proto.NetworkResourceTypeFont: + return "font" + case proto.NetworkResourceTypeXHR: + return "xmlhttprequest" + case proto.NetworkResourceTypePing: + return "ping" + case proto.NetworkResourceTypeCSPViolationReport: + return "csp_report" + case proto.NetworkResourceTypeMedia: + return "media" + case proto.NetworkResourceTypeWebSocket: + return "websocket" + case proto.NetworkResourceTypeOther: + return "other" + } + return string(resourceType) +} diff --git a/pkg/engine/headless/browser/cookie/cookie_test.go b/pkg/engine/headless/browser/cookie/cookie_test.go new file mode 100644 index 00000000..7de1ff57 --- /dev/null +++ b/pkg/engine/headless/browser/cookie/cookie_test.go @@ -0,0 +1,48 @@ +package cookie + +import ( + "testing" + + "github.com/go-rod/rod/lib/proto" +) + +func TestShouldBlockRequest(t *testing.T) { + tests := []struct { + name string + url string + resourceType proto.NetworkResourceType + initiatorDomain string + want bool + }{ + { + name: "should block trustarc consent notice", + url: "https://consent.trustarc.com/notice?domain=hackerone.com", + resourceType: proto.NetworkResourceTypeScript, + initiatorDomain: "hackerone.com", + want: true, + }, + { + name: "should not block trustarc for excluded domain", + url: "https://consent.trustarc.com/notice", + resourceType: proto.NetworkResourceTypeScript, + initiatorDomain: "forbes.com", + want: false, + }, + { + name: "should not block non-matching URL", + url: "https://example.com/other-path", + resourceType: proto.NetworkResourceTypeScript, + initiatorDomain: "hackerone.com", + want: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := ShouldBlockRequest(tt.url, tt.resourceType, tt.initiatorDomain) + if got != tt.want { + t.Errorf("ShouldBlockRequest() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/engine/headless/browser/cookie/rules.json b/pkg/engine/headless/browser/cookie/rules.json new file mode 100644 index 00000000..80fef03a --- /dev/null +++ b/pkg/engine/headless/browser/cookie/rules.json @@ -0,0 +1,19539 @@ +[ + { + "id": 1, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/iubenda_cs", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "radiomontecarlo.net", + "video.repubblica.it", + "video.lastampa.it", + "nablawave.com", + "buondi.it", + "tgcom24.mediaset.it", + "mediasetinfinity.mediaset.it", + "mediaset.it", + "telerama.fr", + "skuola.net" + ] + } + }, + { + "id": 2, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm19_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["ccm19.de"] + } + }, + { + "id": 3, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.clickskeks.at", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 4, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/amp-user-notification-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 5, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sn.sanoma.fi/js/sccm", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 6, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/api/rest/settings/public?fields=endUserAgreement", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 7, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "congstar-media.de/fileadmin/cpolicy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 8, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "connect.danone.es", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 9, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/components/es6/PrivacyPolicy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 10, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "codice.shinystat.it/cgi-bin/getcod.cgi", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 11, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "whitepress.pl/common/pltk/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 12, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "js.hs-analytics.net/analytics", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 13, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jsdelivr.net/wp/wp-slimstat", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 14, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/dsvgo.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 15, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Flurrybox_EnhancedPrivacy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 16, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.axept.io/sdk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 17, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tarteaucitron.css", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 18, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "notice.sp-prod.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 19, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "htmedia.in/analytics-js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 20, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "campact.containers.piwik.pro", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 21, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "containers.piwik.pro", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 22, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wpcc.io/lib", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 23, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tag.goadopt.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 24, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/supi/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 25, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "omnigrafitalia.it/policy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 26, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/edgecastcdn.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 27, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/koriolis_gtm/theshield", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 28, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "fourmizz.fr/rgpd", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 29, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "hu-manity.co/hu-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 30, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ConsentManager,Sticky", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 31, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/rgpd/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 32, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/module-rgpd/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 33, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rcs_cpmt/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["video.corriere.it", "video.gazzetta.it"] + } + }, + { + "id": 34, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bloc/django/ckcsfrg", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 35, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm19.vucx.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 36, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/avia-bootstrap/js/klaro/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 37, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "exm-medien.de/cman", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 38, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "e2d-cms.de/cman", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 39, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/usercentrics-sdk/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 40, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cc.dalten.cz/ccJs", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 41, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm19os/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 42, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "transcend.io/cm/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 43, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/avisopcdidomi", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 44, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm19/public/app", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 45, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "webcache.datareporter.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 46, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "webcache-eu.datareporter.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 47, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.realpeoplemedia.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 48, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets-usercentrics/uc-version", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 49, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Sticky2,ConsentManager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 50, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cnilCookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 51, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "basketballbelieve.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 52, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.usercentrics.eu/browser-ui/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["kicker.de", "kicker.ch"] + } + }, + { + "id": 53, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cc.anytrack.de/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 54, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag/ctm/business-insurance/prod/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 55, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/GDPRPanelComponent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 56, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "aida.de/assets/coobann/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 57, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ModalEngage,ConsentManager,Sticky", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 58, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/coolkies-walkies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 59, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tagcommander/tc_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 60, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/media/plg_system_cookieconfirm", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 61, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_meldung.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 62, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiewarning.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 63, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiewarning4.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 64, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "catalogocoop.it/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 65, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/mu-plugins/cookie_notifier", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 66, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "freegamehosting.eu/js/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 67, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jp2w.pl/a/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 68, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "https://cdn.serviceform.com/serviceform-tools/privacy/sf-privacy-partner.js?v=nethit", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["https://www.lumise.se/"] + } + }, + { + "id": 69, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "talktalk.co.uk", + "blackboard.com", + "kayak.pl", + "gamersgate.com" + ] + } + }, + { + "id": 70, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/inc/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 71, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "metpartner.pl/cookie/info_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 72, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "catalogo.pusc.it/pusc_jquery.cookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 73, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_law.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 74, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "lebendiges-aachen.de/includes/javascript/cookiechoices/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 75, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.reedbusiness.nl/script/cookiechecker/cookiejs.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 76, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/javascript/garante-privacy/js-cookie-master", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 77, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cookie-compliance", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 78, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.webgenerator.nl/_NoCDN/Javascript/CookieBar/cookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 79, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiesamtykke.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 80, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/mod_pescookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 81, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesdirective", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 82, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/webapps/bb-cookie-disclosure", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 83, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-use-policy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 84, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.orangegames.com/assets/js/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 85, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-policy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["newpharma.be"] + } + }, + { + "id": 86, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ico_cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 87, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/comun/cookie_comercial.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 88, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "hogarutil.com/js/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 89, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookielaw.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 90, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bootstrap-cookie-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 91, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieDisclaimer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 92, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/public/scripts/cookie/popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 93, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gartneriraadgivningen.dk/skinCss/website/js/cookie/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 94, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "blackboard.com", + "kayak.pl", + "portal.easygreenenergy.at", + "oekostrom.at", + "gin-rummy-online.com", + "gamersgate.com", + "spielemax.de", + "tonershop.at", + "plus-gp-joule.de" + ] + } + }, + { + "id": 95, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsentpopup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 96, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiePolicyEUPopin", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 97, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookielawscript.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 98, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiepolicy-client.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 99, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-disclaimer.lemm.de/cd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 100, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiebar-init.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 101, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["check24.de"] + } + }, + { + "id": 102, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiewarning2.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 103, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "phufart.pl/info_o_cookie_utf8.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 104, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieInfo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 105, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "oleificiozucchi.it/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 106, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieAccept.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 107, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "videoland.com/external/cookiewall", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 108, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesDirective.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 109, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-law-plugin_en.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 110, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/libernazione-utils/js/libcookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 111, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "aegon.nl/data/cookiewall", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 112, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cultizm.com/templates/c2012light/javascript/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 113, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieprivacygenerator.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 114, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogcindario.com/cookie.php", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 115, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "promoracing.it/cookies/popup.cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 116, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "harazd.net/info_o_cookie_utf8.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 117, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_acceptance_modal.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 118, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "eurail_responsive_law_cookie_banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 119, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dometic/dist/components/cookiescomponent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 120, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "basiszinssatz.info/cookiescript.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 121, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "leporc.com/sites/all/modules/custom/info_cookies/info_cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 122, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.origos.hu/s/js/custom/origo/accept-cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 123, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jquery-easy-eu-cookie-law.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 124, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "shop.szakalmetal.hu//js/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 125, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.nwmgroups.hu/s/js/custom/origo/accept-cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 126, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bootsticks.npage.de/assets/js/cookieconsent.latest.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 127, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.it/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 128, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.at/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 129, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.es/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 130, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ee/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 131, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.pl/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 132, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.cz/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 133, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.dk/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 134, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ie/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 135, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.fr/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 136, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.si/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 137, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.hu/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 138, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.sk/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 139, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.se/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 140, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.fi/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 141, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.lt/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 142, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.gr/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 143, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ro/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 144, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.bg/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 145, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.be/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 146, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.hr/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 147, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.de/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 148, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.pt/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 149, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.nl/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 150, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.no/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 151, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.is/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 152, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.cl/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 153, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.lv/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 154, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ch/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 155, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ba/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 156, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.lk/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 157, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ru/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 158, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.com/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 159, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.co.uk/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 160, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "blogspot.ca/js/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 161, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ext/zt_popupcookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 162, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "iti.si/deljene_datoteke/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 163, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/responsive-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 164, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "skm.warszawa.pl/js/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 165, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookie-info.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 166, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_law/plugin.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 167, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jslibrary/cookiewarning?", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 168, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cookie-notice", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["kapitalkontor.com", "barzahlen.de"] + } + }, + { + "id": 169, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "airnewzealand.co.nz/vbook/actions/cookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 170, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cg_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 171, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "grsuk.com/scripts/cookie-info.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 172, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-consent.es5.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 173, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookielaw_mip.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 174, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "informacja_cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 175, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiefix.dynamicline.hu/fixcookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 176, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 177, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-policy.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 178, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/eu-cookie-law-wp-cookie-law/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 179, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "eurocookie.galilcloud.wixapps.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 180, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-terms.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 181, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookieStatement.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 182, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wawona.hu/cookie-box/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 183, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/components/cookiescomponent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 184, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesinfo/cookieinfo.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 185, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent/cookie-consent.umd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 186, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebanner.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "huk24.de", + "huk.de", + "adtipp.de", + "nectar.com", + "neckermann.de", + "exali.de", + "raiplaysound.it", + "check24.de" + ] + } + }, + { + "id": 187, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/common/cpol/cookiepolicy.php", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 188, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-widget/latest/cookiewidget.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 189, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.talparadio.nl/js/cookiecheck.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 190, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bmedonline.es/js/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 191, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consentcookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 192, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie.consent.is", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 193, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-notification.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 194, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "filer_-_cookie_disclaimer_ny/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 195, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cpresources/cookieconsent/js/cookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 196, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "layer22.net/scripts/cookies-no-conflict-naxa", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 197, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiecuttr-eu-cookie-law-compliance/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 198, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jquery.eu-cookie-consent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 199, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebar.jquery.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 200, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "trashmail.com/js/cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 201, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gratiz.nl/cookie-script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 202, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-service/js/client.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 203, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/euc_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 204, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/web/components/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 205, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.cookiesdirective.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["servizionline.gruppoascopiave.it"] + } + }, + { + "id": 206, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-consent.azureedge.net/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 207, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jquery.cookie.policy.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 208, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/prettycookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 209, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/accept-ad-targeting/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 210, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.cookielaw.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 211, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.cookielaw-script.it", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 212, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiealert.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["viessmann.com.pl"] + } + }, + { + "id": 213, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/external/ico.cookie.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 214, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/script/ico.cookie.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 215, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiewall.es5.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 216, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiecompliance.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 217, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/remote/v1/cookie-notification", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 218, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-warning.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 219, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookienotice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["betterworldbooks.com"] + } + }, + { + "id": 220, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "private.dmscookie.com/scripts/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 221, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tgory.sr.gov.pl/js/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 222, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eu-cookie-law.js?browserId", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 223, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.innershed.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 224, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/mu-plugins/cookie_notifier/cn.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 225, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebar_tls.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 226, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/smart-cookie-kit/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 227, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-notice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 228, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookiePolicy/resources/scripts/cookie.policy.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 229, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/cookieconsent/js/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 230, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jquery.cookiepol.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 231, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-bar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 232, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie/cc_min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 233, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookielaw/piskotkar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 234, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "myportalcms.com/template/js/mp_acookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 235, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieplugin/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 236, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-message.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 237, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 238, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "doitonlinemedia.nl/global-js/avg-cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["palazzogroep.nl"] + } + }, + { + "id": 239, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy.digimedia.com/check_cookie_country_code.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 240, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fortune_cookie_popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 241, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiecsnt2/js/cookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 242, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-note.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 243, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "policy.app.cookieinformation.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "kartor.eniro.se", + "kart.gulesider.no", + "kort.degulesider.dk", + "map.krak.dk", + "altibox.no", + "babysam.dk", + "elkjop.no", + "minaftale.dk", + "skousen.dk", + "skousen.no", + "whiteaway.com", + "whiteaway.no", + "whiteaway.se", + "dvdoo.dk" + ] + } + }, + { + "id": 244, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookienotice/Js/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 245, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/fortune-cookie-consent-policy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 246, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdl-cookiebar.tnt-digital.com/js/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 247, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/nl-cookie-law.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 248, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieaccept.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 249, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ercookiebar.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 250, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiewarn.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 251, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-hinweis/script-v2.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 252, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookieMessage.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 253, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/js/sera/web/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 254, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiebanner.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 255, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/z7_cookiemanager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 256, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent/js/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["kawalekkodu.pl"] + } + }, + { + "id": 257, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieconsentnotice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 258, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/tnzcookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 259, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/gdpr-cookie-compliance", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 260, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/components/cookie-modal/cookie-modal.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 261, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-window.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 262, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiewall-inline-for-popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 263, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cc-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 264, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiePolicyV4.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 265, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/cookiechoices.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 266, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-widget/bootstrap.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 267, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.tipsy.cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 268, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_choices.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 269, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/wp-cookie-allow/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["learndutch.org"] + } + }, + { + "id": 270, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cookiemedia/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 271, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Resources/Public/js/cookiebar.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 272, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/system/cookiespolicynotificationbar", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 273, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieassistant.com/widget.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 274, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/helper-scripts/cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 275, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/msifestiwal/Scripts/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 276, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-overlay-pl.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 277, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.notify.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 278, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cpol/cookiepolicy.php", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 279, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-manager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 280, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "dtt.taleo.net/careersection/theme/381362/1547022019000/en/theme/js/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 281, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/cookies/cookiesLayer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 282, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookiePolicyGa/cookiepolicyga.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 283, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sdc/cookie_consent.html", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 284, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tmo_cookies/Resources/Public/Javascript/CookieSettings.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 285, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "deltaxmultimedia.com/cookielaw", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 286, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/web/components/cookieusage", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 287, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/eagerly-tools-cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 288, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/scripts/cookiebar", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 289, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/resources/CookieConsent/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 290, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "buro-3.nl/cookie/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 291, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ll_cookie_bar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 292, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.cookiemonster.is/embed", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 293, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/g361-cookies-consents", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 294, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Scripts/Cookies/cookieacceptance.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 295, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/extimages/scripts/ukcookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 296, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.aptelink.pl/nc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 297, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "eu_cookie_banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 298, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eu_cookie_compliance.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 299, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dc-cookie-privacy-settings.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 300, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesPolicy/static/lib.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 301, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiewarning-nosql.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 302, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.bpcookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 303, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/resources/js/cookie/cookie-bar", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 304, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsentDialog.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 305, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/bc-cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 306, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/idxcookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 307, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/javascript/cookieser.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 308, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesWidget/widget.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 309, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.cookiebot.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "storyhouseegmont.dk", + "storyhouseegmont.no", + "storyhouseegmont.se", + "egmont.com", + "stadtmobil.de", + "wwf.fi", + "login.nos.pt", + "asambeauty.com", + "cineplex.de", + "berlingske.dk", + "digimon.kochfilms.de", + "kino.dk", + "hoyavision.com", + "linak.es", + "linak.de", + "cajamar.es", + "digitaltrends.com", + "mein-grundeinkommen.de", + "werder.de", + "finanzmarktwelt.de", + "danbolig.dk", + "bt.dk", + "scubadiving.com", + "biomarkt.de", + "harzwasserwerke.de", + "stern.de", + "dasinvestment.com", + "derivate.bnpparibas.com", + "werkenbijlidl.nl", + "swspremberg.de", + "nngroup.com", + "bankia.es", + "bergbauernmilch.de", + "spiele-kostenlos-online.de", + "ekstrabladet.dk", + "epochtimes.de" + ] + } + }, + { + "id": 310, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccp-sites/components/structure/cookie-notification/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 311, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-info.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 312, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.algo.at", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 313, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiehub.net/c", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 314, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/widgets/eu-cookie-law/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 315, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.cookieyes.com/client_data", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 316, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/skinCss/website/js/cookie/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 317, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "freeprivacypolicy.com/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 318, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-module/dist", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 319, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieOptIn.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 320, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookie_banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 321, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery-cookies-alert.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 322, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookielaw.emea.fcagroup.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 323, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/tnk-cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 324, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiepopup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 325, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.cookiefirst.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "swietawdomu.pl", + "deutschesapothekenportal.de" + ] + } + }, + { + "id": 326, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-policy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 327, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/liquorice-cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 328, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-switch.viminds.de/api", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 329, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "skyscnr.com/sttc/oc-registry/components/cookie-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 330, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/cookiesplus/views/js/cookiesplus.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 331, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mws-cookie-solution.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 332, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ajax/libs/cookieconsent2", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "membersuite.com", + "la-becanerie.com", + "rijbewijskeuringennederland.nl", + "download.pixelexperience.org", + "ceramtec-group.com" + ] + } + }, + { + "id": 333, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "talktalk.co.uk", + "codexis.cz", + "lacoste.com", + "huuray.se", + "indiearenabooth.com" + ] + } + }, + { + "id": 334, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookienotice-bootstrap.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 335, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cookieEuGH", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 336, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 337, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/cookie-notice", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 338, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiechoices.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 339, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 340, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieconsent.popupsmart.com/src/js/popper.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 341, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "flixbus.com/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 342, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/jscookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 343, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.cookie-policy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 344, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-alert.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 345, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "up-cookiemon.wavecdn.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 346, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieBanner.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "adtipp.de", + "nectar.com", + "neckermann.de", + "exali.de", + "raiplaysound.it", + "check24.de" + ] + } + }, + { + "id": 347, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/politica-cookies/leyCookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 348, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/trwcookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 349, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dc_components/site/cookie-control/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 350, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-manager.de/cookie-manager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 351, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pxpcookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 352, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie/uccb-main", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 353, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_consent_min_js.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 354, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/onlinemanufaktur-cookie-notice/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 355, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mq_cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 356, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/static/cookies/cookie-layer-wc-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 357, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-bar/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["vectra.pl", "urbanista.de"] + } + }, + { + "id": 358, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebar/scripts.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 359, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fileadmin/cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 360, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieopt-min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 361, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/micado.web.dsgvo.cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 362, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wip.pl/js/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 363, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/docroot/js/app/modules/cookies-selection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 364, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/cookieman/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 365, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiecode.dist.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 366, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_agreement_dialogue.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 367, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "googleapis.com/55_cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 368, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/nsd-cookie-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 369, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/responsive-eu-cookie-notice", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 370, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/master-popups-cookieplus", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 371, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner-one.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 372, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiemanagement.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 373, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/mod_eu_cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 374, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.cookiefy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 375, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "websitepolicies.com/lib/cookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 376, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/aip_cookie_law", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 377, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie.gg/c", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 378, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plg_system_vpcookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 379, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/p8-cookie-bar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 380, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner/cb.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 381, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/echonetcookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 382, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-policy-en.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 383, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bb_cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 384, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/?tx_z7cookiemanager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 385, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/kmacookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 386, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/_hw_cookie_dialog.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 387, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-settings-ui/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 388, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookietrust.eu/script", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 389, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bs-cookie.staging.springbok.agency", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 390, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["nice.org.uk"] + } + }, + { + "id": 391, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/WebUI/Cookies/allowcookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 392, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/SharedComponents/bundle-scripts/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 393, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent.klaro.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 394, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookies_bar", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 395, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modal/cookie-wall/?modal_view=true", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 396, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/better_cookie_consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 397, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/jquery-eu-cookie-law-popup", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 398, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "flipdish-cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 399, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookie-law-ansi", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 400, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieconsent.syreta.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 401, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/deferred/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 402, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/rodo-cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 403, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/hw-cookie-dialog.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 404, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/accept-cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 405, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_warning.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 406, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/cookies/tinybox.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 407, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/web/components/cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 408, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-bar.salessquad.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 409, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieMunchr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 410, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "nicmanager.com/static/cookie_guideline", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 411, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "traderfox.de/lib/tfcookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 412, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/amadeus-plugin-cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 413, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rh-cookieconsent-microsites.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 414, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/components/content/cookie-overlay/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 415, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiemon.atcom.gr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 416, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "nbcsports.com/cookie-ack.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 417, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/gdpr/gdpr-cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 418, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.ihavecookies.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["wisla-plock.pl"] + } + }, + { + "id": 419, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/b2b-market/src/addons/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 420, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vue/components/cookie-monster", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 421, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/do-you-want-cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 422, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bascom.nl/cookies/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 423, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fluvius-eu-cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 424, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/lyxor-cookies-disclaimer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 425, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/grt-cookie-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 426, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bundles/cookiebar", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 427, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/avia-snippet-cookieconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 428, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/user-cookie-banner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 429, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/we_cookie_consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 430, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/vp-cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 431, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/system/modules/cookiecontrol/assets/js/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 432, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsentNotif.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 433, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/ne_cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 434, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-bar.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 435, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ilovecookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 436, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/luxcookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 437, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiehint/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 438, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieOptIn.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 439, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sg_cookie_optin/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 440, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebox.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["footroll.pl"] + } + }, + { + "id": 441, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.privacy.protection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 442, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/new-cookie-policy.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 443, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiehint.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 444, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/public-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 445, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mod_jt_cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 446, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/dist/cookieAcceptance", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 447, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebanner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 448, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/acc.cookienotification.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 449, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiepolicy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 450, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_api/cccframe", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 451, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookienote-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 452, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/metro?sc_device=webcomponent&components=cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 453, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_msg.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 454, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_info.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 455, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "js.cookietagmanager.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 456, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/mnd-cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 457, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js_cookies_legal.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 458, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ys_cookie_consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 459, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-v2/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 460, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/beautiful-and-responsive-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 461, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie/banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 462, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/widget-module-cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 463, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/lightweight-cookie-notice/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 464, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ocean-cookie-notice/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 465, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jst_eu_cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 466, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "procookie.by.nf", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 467, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 468, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jquery-eu-cookie-law-popup", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 469, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cp_cookieconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 470, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.ae-webdesign.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 471, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ws5_eucookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 472, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsent/cookieModal.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 473, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/consent-cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 474, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.fo/qookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 475, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/hw-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 476, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["labs.strava.com", "crossfit.com"] + } + }, + { + "id": 477, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/w4.cookiebar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 478, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cookielay/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 479, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "plugin-cookie-consent/build", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 480, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie/onetrust/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 481, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-settings-modal/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 482, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/components/consent-cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 483, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-service.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 484, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent.bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 485, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/lgpd-cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 486, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cookies-and-content-security-policy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 487, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiebox_uc_build.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 488, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gen/cookie-notification", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 489, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesjsr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["lcp.fr"] + } + }, + { + "id": 490, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/eu-cookies-bar/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 491, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieOverlay-view.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 492, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/Widgets/cookieWidget", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["losteria.de"] + } + }, + { + "id": 493, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/minified/cookiecontrol.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 494, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/ab1d_cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 495, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/module/kabimba_cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 496, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/woody-addon-cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 497, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/__enzuzo-cookiebar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 498, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_policy/ack.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 499, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["northernpowergrid.com"] + } + }, + { + "id": 500, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/zedwcookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 501, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiedisclosure/core.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 502, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie.thynk.media/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 503, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/usercentrics/cookiebox", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 504, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-tool/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 505, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-notification.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 506, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "onetrust.com/cookieconsentpub", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["fujifilm-x.com"] + } + }, + { + "id": 507, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/dp_cookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 508, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 509, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/om_cookie_main.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 510, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.rgpd-cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 511, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bandeau_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 512, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dist/js/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 513, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "sonnenverlauf.de", + "mondverlauf.de", + "leanlibrary.com", + "retrogames.cc", + "exagon.de", + "sozialversicherung-kompetent.de", + "varcevanje-energije.si", + "khl.ru", + "bauen-und-heimwerken.de", + "carport-diagnose.de", + "tricount.com" + ] + } + }, + { + "id": 514, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsentApp.js.gz", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 515, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fileadmin/templates/cookie/fc_thin.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 516, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.cookiecode.nl", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 517, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/nd-cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 518, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent-all.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 519, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieBanner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 520, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-wall.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 521, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.giant.cz/assets/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 522, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.praguebest.cz/dist", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 523, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-prompt/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["gestiontv.vodafone.es"] + } + }, + { + "id": 524, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bootstrap-cookie-consent-settings.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 525, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rails_cookie_consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 526, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rgpd/js/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 527, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieBannerLoader.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 528, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieform.pl/assets/js/plugin", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 529, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/components/cookiemanager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 530, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ewcookienoteext.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 531, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/clientlibs/components/content/cookie/cookielayer", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 532, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rm-cookieconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 533, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner-vue", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 534, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiecdn.com/cwc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 535, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/om-gdpr-cookie-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 536, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn-cookieyes.com/client_data", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 537, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "digitalsternemarketing.de/dscookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 538, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modal-acceptare-cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 539, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-bar/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 540, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookieconsent.blob.core.windows.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 541, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/all-cookieconsent-js.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 542, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-browser-alert-ui.fragment.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 543, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tcf/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 544, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bsgdprcookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 545, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": ".cookiehub.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 546, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "traveljuice-engines.prod.traveljuice.fr/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 547, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eu_cookie_compliance_override.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 548, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/smart-eu-cookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 549, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 550, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Pictorium/scripts/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 551, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jsLib/gdpr/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 552, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieBar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 553, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cc.controlcookies.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 554, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieNotice.build.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 555, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ux.ui-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 556, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesPopUp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 557, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/in2cookiemodal", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 558, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner/cookie-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 559, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/polityka-prywatnosci/js/cookie-overlay", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 560, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-portlet/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 561, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/simple-gdpr-cookie-compliance/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 562, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-consents.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["posta.sk"] + } + }, + { + "id": 563, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "theme-cookie/app/cookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 564, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "plugins/ShprCookieFavour/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 565, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.ptj.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 566, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieModal/clientlib", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 567, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-banner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 568, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dxcookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 569, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/real-cookie-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 570, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sohoshopcookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 571, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "am-static.com/cookie-banner/sdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 572, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/marked-cookie-consent-web/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 573, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.cookielaw.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["cnn.com"] + } + }, + { + "id": 574, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/borlabs-cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 575, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/gdpr-cookie-compliance/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 576, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/etagen_cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 577, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_overlay.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 578, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/cookies-and-content-security-policy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 579, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieBar.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 580, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiedialog/cookieutility.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 581, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/creare-eu-cookie-law-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 582, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jsdelivr.net/npm/@finsweet/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 583, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieseubox.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 584, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie/cc_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 585, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["fransdewitte.nl"] + } + }, + { + "id": 586, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/category-assets/experiences/recurring/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 587, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/storage/ui/cookies-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 588, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiedisturber/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 589, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/lightweight-cookie-notice", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 590, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/dm_cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 591, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-dialogue.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 592, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dist/scripts/cookie-control", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 593, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "am-static.com/cookie-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 594, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/marked-cookie-consent-web/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 595, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.falconcookie.de/storage", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 596, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/brd_cookies_consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 597, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/hicookielaw/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 598, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/kbv-cookieconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 599, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-mycity.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 600, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/components/src/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 601, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/webtoffee-gdpr-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["altheaprovence.com"] + } + }, + { + "id": 602, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.neuca24.pl/nc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 603, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies/manage-cookies-runtime", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 604, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/ppw_cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 605, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-widget/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 606, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/pages/js/cookie-dialog.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 607, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3temp/assets/compressed/cookieman", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 608, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiethough.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 609, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "beyond-cookiebanner.de/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 610, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/js/cookie_consent_manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 611, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/viva-cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 612, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieMessage.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 613, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/michnhokn/cookie-banner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 614, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ddjnocookie.com/prod_public", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 615, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/cookie_policy/frontend/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 616, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 617, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpsystem.eu/pl/cookiesprivacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 618, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fcc-cookie-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 619, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-cookie-consent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 620, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsentScript", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 621, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookienoticepro.script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 622, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dsgvo/js/cookiemonster", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 623, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_consent_js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 624, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent-request.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 625, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wko.at/gcm/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 626, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wko.at/css-js/scripts/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 627, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/frontend-core/js/cookieBox.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 628, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiemanager.dk/js/cm.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 629, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mod_pixim_cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 630, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tmgonlinemedia.nl/consent/script/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 631, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy.ariadneathome.nl/script/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 632, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy.vtwonen.nl/script/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 633, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wpjslib-chunk-consent-form.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 634, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/consentbar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 635, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdprpro/views/js/gdpr-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 636, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/consent-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 637, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "s.clickiocdn.com/t/consent_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 638, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jppol-consent/js/bootstrap.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 639, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/opbox-rodo-consent-modal/index", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 640, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "optanon.blob.core.windows.net/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 641, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "libertatea.ro/consent/config.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 642, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent-notice.magix.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 643, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/taunton-user-consent-eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 644, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consensu.org/t/consent_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["softzone.es"] + } + }, + { + "id": 645, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consentmanager.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "sourceforge.net", + "webfail.com", + "sudoku-aktuell.de" + ] + } + }, + { + "id": 646, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consently.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 647, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "s.adroll.com/j/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 648, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-panel-vue.chunk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 649, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.theneweuropean.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 650, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy-consent-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 651, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "thezen.garden/projects/zenconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 652, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "smartconsent.ro/js/smart-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 653, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/webflow-consent-manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 654, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.consentassist.com/widget.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 655, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "s.luxupcdnc.com/t/consent_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 656, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.appconsent.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["lefigaro.fr"] + } + }, + { + "id": 657, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.23g.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 658, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "browser-consent-front.coco.s-cloud.fi", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 659, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/consent-manager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 660, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.weersvoorspelling.nl/v1", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 661, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.webmasterplan.com/v2", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 662, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/adsconsent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 663, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.truste.com/get?name=notice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 664, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.trustarc.com/notice", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "tripit.com", + "concursolutions.com", + "fortune.com", + "formula1.com", + "forbes.com" + ] + } + }, + { + "id": 665, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent-manager.metomic.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 666, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.uniconsent.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["photopea.com"] + } + }, + { + "id": 667, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-banner-bootstrap", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 668, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tmgrup.com.tr/tmd-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 669, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/consent-modal.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 670, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/api/snippets/js/consent-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 671, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sixfifty.com/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 672, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 673, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "choices.consentframework.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 674, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cache.consentframework.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 675, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consentserve.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 676, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "analytics-consent-manager.azureedge.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 677, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mgm_consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 678, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "hoffmann-group.com/common/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 679, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dv_t3_consent_management/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 680, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gsso_consent_manager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 681, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "avandor.com/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 682, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/data_consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 683, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "smart.idmnet.pl/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 684, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "kalevakonserni.fi/consent/gravito", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 685, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bundle-consent-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 686, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modal-consent-component.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 687, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-management/_include/init_consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 688, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "pitcom-webanalyse.de/dsgvo/consent-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 689, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wrd-aws.com/consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 690, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/ag-consentmanager-no-bootstrap/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 691, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/static/consent-dialog.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 692, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/opbox-gdpr-consents/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 693, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/consent-manager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 694, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ampproject.org/v0/amp-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["smartdroid.de", "lelum.pl"] + } + }, + { + "id": 695, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.trustarc.com/v2/notice", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 696, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/resources/onetrust/js/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 697, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-manager/lazy-consent-manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 698, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/addons/consent_manager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 699, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/npm/ez-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 700, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/piwik-consent-banner-script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 701, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fileadmin/template/js/cconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 702, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/kconsent/kconsent29.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 703, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-layer/js/consent-layer-loader.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 704, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tm-gdpr-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 705, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "snigelweb.com/adconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 706, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sncmp.com/adconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 707, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consentmanager.net/delivery/js/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["winfuture.de", "infranken.de"] + } + }, + { + "id": 708, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent-manager.confirmic.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 709, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consentbanner.de/public/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 710, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "classistatic.de/consent-statics", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 711, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consentcheck.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 712, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-consent-management-platform/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 713, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/drdsgvo-consent-script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 714, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-consent.bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 715, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent/civic-bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 716, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "totalweb.gr/gdpr/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 717, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/epaas.consentdrawer.bundle", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 718, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consentbanner-fragment/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 719, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "altravia.com/connector/consent_mode.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 720, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consentmanager.net/delivery/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["winfuture.de", "infranken.de"] + } + }, + { + "id": 721, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/taunton-user-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 722, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fileadmin/templates/js/cconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 723, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/okf-euconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 724, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.daa.net/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 725, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-consent-banner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 726, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-management-app/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 727, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.hr/delivery/js/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 728, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bundles/consent-init?v=", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 729, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/acc.consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 730, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.scm-verlagsgruppe.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 731, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/consent-magic-pro", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 732, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "7gra.us/consentbar", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 733, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dgp-cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 734, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/as24-cmp/consent-banner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 735, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/log-user-consents/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 736, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent-bist.de/public/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 737, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.digiapi.com/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 738, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "idealo.com/storage/cmp/consent-management.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 739, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.prointernet.com/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 740, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/coockieconsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 741, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consentmanager.net/delivery", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "winfuture.de", + "echo-online.de", + "stern.de", + "spar.hu", + "spar.hr", + "spar.at", + "spar.si", + "interspar.at" + ] + } + }, + { + "id": 742, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.comply-app.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 743, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "kesko.fi/kconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 744, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "unpkg.com/@segment/consent-manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 745, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wko.at/static/ct/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 746, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consenttool.haendlerbund.de/app.js?apiKey", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 747, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.extrazimut.net/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 748, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cs_consent_modal.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 749, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/gdpr_footer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 750, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/gdpr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 751, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/comun/avisopcgdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 752, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 753, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr.internetbrands.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 754, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": ".be/api/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 755, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": ".nl/api/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 756, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "-gdpr-min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 757, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-transparency-apnxs/latest/gdpr-bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 758, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sitemaps.services.zam.com/gdpr_optout.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 759, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ibeugdpr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 760, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consensu.org/gdpr/cmp/gdpr-cmp-ui.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 761, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "s3.amazonaws.com/sitemaps.services.zam.com/gdpr_standalone.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 762, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sizzlegdpr.snippet.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 763, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/gdpr/messaging.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 764, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mdp.javascript.gdpr.min", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 765, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/emg-framework/public/js/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 766, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/emg-framework/assets/js/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 767, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/assets/js/gdpr.js?ver", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 768, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/injectable.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 769, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ishop-plugins/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 770, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "secure-cdn.mplxtms.com/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 771, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 772, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/am2-gdpr-public.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 773, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdprscript.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 774, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/surbma-gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 775, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-banner.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 776, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "libraries.wmgartistservices.com/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 777, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdprmain/prod/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 778, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.thisisdone.com/gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 779, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr-banner.awsmpsa.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 780, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "securebrainpull.com/gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 781, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr500.com/widget/pandawidget/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 782, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bundle-gdpr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 783, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/CookieConsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["kayak.pl"] + } + }, + { + "id": 784, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/2018-gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 785, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-cmp-ui.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 786, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/gdpr.min.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 787, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/gdpr/gdpr_ncoi.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 788, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/static/new/js/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 789, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/libs/gdpr/cmp/cmp.bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 790, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pgdpr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 791, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/policies/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 792, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/spd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 793, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "prizelogic.com/gdpr/third-party-optin.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 794, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 795, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wordpress-ptchrgdprplugin/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 796, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr-wrapper.privacymanager.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "kinuskikissa.fi", + "geenstijl.nl", + "dailybuzz.nl", + "rtvnoord.nl", + "omroepbrabant.nl", + "futurezone.at", + "profil.at", + "kurier.at", + "weeronline.nl", + "lablue.de", + "vesti.bg" + ] + } + }, + { + "id": 797, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "evidon.com/pub/gdprnotice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 798, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/ct-ultimate-gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 799, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr.mandarin-medien.de/manager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 800, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr-tcfv2.sp-prod.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "computerbild.de", + "programme-tv.net", + "bold.dk", + "welt.de", + "sport1.de", + "ostsee-zeitung.de", + "sky.com", + "lvz.de", + "mein-schoener-garten.de", + "autobild.de", + "bike-bild.de", + "bz-berlin.de", + "travelbook.de", + "si.com", + "capital.fr", + "t3n.de", + "is.fi" + ] + } + }, + { + "id": 801, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "yastatic.net/s3/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 802, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/zgdpr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 803, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/pp_agreement.pc.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 804, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/cmp/cmpBundle.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 805, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/webmd.gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 806, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/motus-gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 807, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/gdprprivacysetup/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 808, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc-gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 809, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "metronom.com/library/scripts/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 810, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/lin_gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 811, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tronic-gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 812, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-banner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 813, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/typo3conf/ext/dbb_gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 814, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-appliance.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 815, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "pdcc.gdpr.es", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 816, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-redirect.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 817, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/shared/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 818, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sdk-gdpr.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 819, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/gdpr-component", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 820, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdprDialog.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 821, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bluelabs-gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 822, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdprScriptComponent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 823, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "mediavine.com/tags/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 824, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "pubnation.com/tags/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 825, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ecos.am/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 826, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modal-gdpr.umd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 827, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr_notice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 828, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/lexon-gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 829, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/popin-gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 830, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modules/gdprpro/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 831, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gdpr-api.sharethis.com/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 832, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/media/plg_system_eprivacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["reshade.me"] + } + }, + { + "id": 833, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "recepttar.hu/js/privacy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 834, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.dmgmediaprivacy.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["metro.co.uk", "gbnews.uk"] + } + }, + { + "id": 835, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jssdk.privacy.pre.schibsted.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 836, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "secureprivacy.ai/secureprivacy-plugin/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 837, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vendor/weka/privacykit/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 838, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy.clym.io/js/clym-widget.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 839, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/privacypolicy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 840, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bosch-privacy-settings-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 841, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/general/avada-privacy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 842, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "public.message-business.com/Javascript/mb.privacyManager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 843, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.reeltime.no/pm_assets/privacy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 844, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ftcguardian.com/privacy-update", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 845, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacypolicy.trgr.be/widget", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 846, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacyopt.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 847, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacypolicy/styles/all/template/remove_url.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 848, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "psi.schibsted.com/api/v2/privacy/notification", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 849, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/privacy-policy-info/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 850, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/e-privacy.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 851, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacyConsentBar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 852, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tagcommander.com/privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["labanquepostale.fr"] + } + }, + { + "id": 853, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "isgprivacy.cbsi.com/dist/optanon", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "cbsnews.com", + "startrek.com", + "insideedition.com", + "cbslocal.com", + "etonline.com" + ] + } + }, + { + "id": 854, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/contao-privacy-center.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 855, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-policy.u-lab.nl", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 856, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "trustcommander.net/privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["tf1info.fr", "tf1.fr"] + } + }, + { + "id": 857, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.eprivacy-keeper.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 858, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/en-privacy-notification/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 859, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy.claytonhomes.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 860, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "shopify.com/shopifycloud/privacy-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 861, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/enua-privacy-policy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 862, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "demotywatory.pl/res/js/privacy_policy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 863, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eprivacy/js/eprivacy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 864, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sf-tagomo-privacy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 865, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/s4s-privacy-module/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 866, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/shopsshort/privacy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 867, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "heg-cp.com/upm/privacy-manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 868, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tag=ui/privacy/CookiesConsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 869, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dock-privacy-settings.esm.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 870, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy.wum.rocks/public/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 871, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tagcommander/privacy_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 872, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/serviceform-tools/privacy/sf-privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 873, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy-dialog-tracking.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 874, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy/providers/CookiesDataProvider", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 875, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/contao-privacy-center", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 876, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/myagileprivacy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 877, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.lemonde.fr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 878, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.quantcast.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 879, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.nextday.media/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["vi.nl", "omroepwest.nl"] + } + }, + { + "id": 880, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.dreamlab.pl", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 881, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/media/cmp/int_cmp_banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 882, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consensu.org/delivery/cmp.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 883, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sipaof.mgr.consensu.org/sipacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 884, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/sourcepoint/sp-msg.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 885, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.cdntrf.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 886, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.mediavine.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 887, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmpCookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 888, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/library/cmp/cmp.bundle-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 889, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp-loader.choice.faktor.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 890, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/diyscmp.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 891, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bilsyndication.com/js/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 892, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bilsyndication.com/plugins/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 893, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.osano.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 894, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "vlitag.com/plugins/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 895, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.md-nx.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 896, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.opencmp.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["foraum.de", "idowa.de"] + } + }, + { + "id": 897, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.faktor.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["omroepwest.nl", "consent.talpanetwork.com"] + } + }, + { + "id": 898, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gravito.net/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 899, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdncmp.richaudience.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 900, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "heymatic.com/assets/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 901, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/js/vendors~cmpUi", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 902, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ustatik.com/public/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 903, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "mrf.io/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 904, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.cls.pm", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 905, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gravito.net/lightcmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 906, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "onetag-sys.com/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 907, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/truendo_cmp.pid.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 908, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.optad360.io", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 909, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "snigelweb.com/sncmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 910, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "seznam.cz/js/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 911, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pubtech-cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 912, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.pafo.fairbung.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 913, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sibbo.net/v2/sibbo-cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 914, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "24net.cz/resources/js/cmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 915, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/quorn-cmp.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 916, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmps.o2.cz/delivery", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 917, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tcf-cmp.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 918, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "fastcmp.com/fast-cmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 919, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "apps.ludostation.com/cmp/v2/cmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 920, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "mrdev-cmp/assets/js/script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 921, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.setupcmp.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 922, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.meteored.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 923, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "veodys.fr/api/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 924, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sibbo-cmp-core.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["atresplayer.com"] + } + }, + { + "id": 925, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gravito.net/alehdetcmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 926, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "fastcmp.com/fast-cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 927, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sibbo-cmp-loader.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 928, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.springernature.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 929, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "determinator.service-cmp.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 930, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "seznam.cz/js/cmp2/scmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 931, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "seznam.cz/js/cmp2/scmp-external.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 932, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gofundme.com/js/3.0/visitorCookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 933, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookiesDirective", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 934, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "CookieAccept/affirmation.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 935, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ariba.com/assets/scripts/classes/Ariba.Compliance.CookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 936, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "aldermore.co.uk/Scripts/Logic/CookieDisclaimer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 937, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tweeboo.com/r/js/CookieDirective", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 938, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jqueryCookieGuard", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 939, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jquery.smartCookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 940, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc-bar/cCookiesH.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 941, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieDirective.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 942, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/setPrivacyCookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 943, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/clientlib-webpack-publish/js/CookiesApp-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 944, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/CookieManager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 945, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bundle_CookieLegalNotice.prod.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 946, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/acceptCookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 947, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/i_CookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 948, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Amasty_GdprCookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "planet-cards.co.uk", + "sunkost.no", + "wondrium.com", + "nova-motors.de", + "moleonline.com", + "durstexpress.de", + "littlelunch.com", + "twinpack.nl", + "eckeroline.fi", + "eilles.de", + "xt500parts.com", + "cupper-teas.de" + ] + } + }, + { + "id": 949, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ts/components/CookieConsent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 950, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/SDG_CookieLayer.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 951, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/slr_js/allowCookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 952, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/javascript/component-CookieConsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 953, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/whCookieManager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 954, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Cookie-GetCookieModal", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 955, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/1990KB-CookieConsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 956, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Magento_Cookie/js/notices", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 957, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/iwCookieBanner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 958, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "blackboard.com", + "kayak.pl", + "gamersgate.com" + ] + } + }, + { + "id": 959, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/CookieConsentNew", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 960, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieManagerUi.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 961, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/widgets/global/vendors~LegalCookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 962, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/getCookieConsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 963, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/kssCookieManager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 964, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ModalCookiesPrivacy.php", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 965, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookiesManager/CookiesManager.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 966, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/components/CookieManager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 967, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/SiteElements/Scripts/CookieBanner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 968, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/plugins/CookiePop/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 969, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/IntegerNet_CookieConsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 970, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/new_Cookiebanner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 971, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/feoCookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 972, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Plumrocket_CookieConsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["8020.net"] + } + }, + { + "id": 973, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/static/CookieManager/js/app", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 974, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/optInCookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 975, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ja/controlCookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 976, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utils/CookiePrompter", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 977, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Wamoco_CookieConsentUi/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 978, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/standaloneModalCookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 979, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Detco_CookieBanner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 980, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vfConsentCookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 981, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Cookie-Interfrog/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 982, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "quantcast.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "sourceforge.net", + "tumblr.com", + "wpolityce.pl", + "player.livespotting.com", + "indy100.com", + "vi.nl", + "independent.co.uk", + "express.co.uk", + "joe.ie", + "joe.co.uk", + "standard.co.uk", + "avsforum.com", + "pcgamer.com", + "nfl.com", + "filmvandaag.nl", + "gamesradar.com", + "iol.pt" + ] + } + }, + { + "id": 983, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "gemius.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 984, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sddan.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 985, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "digitrust.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 986, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sharethis.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 987, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "webads.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 988, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "etarget.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 989, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "optad360.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["infogliwice.pl"] + } + }, + { + "id": 990, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "shinystat.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 991, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "dan.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 992, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ogury.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 993, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "inforpl.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 994, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "sibboventures.mgr.consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 995, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consensu.infor.pl", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 996, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ciasteczkowapolityka.pl/getscript", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 997, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bsl.nl/extern/smbv-incl/script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 998, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ssl.synovite-scripts.com/ut", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 999, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "zoneadsl.com/clientscript/cnil.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1000, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "angrybirdsmovie.net/site/scripts/nettracking4.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1001, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bobulous.org.uk/javascript-head-sitewide.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1002, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wroclaw.pl/portal/themes/js/script-rodo.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1003, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/scripts/pookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1004, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "metasrc.com/assets/javascripts/compliance.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1005, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "geo.fr/assets/scripts/sourcepoint.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1006, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/rodo/rodo_script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1007, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.praivacy.eu/scripts", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1008, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "script.getcomplied.com/scripts/complyWidget/assets/getCompliedListWidget.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1009, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Gpdr/assets/ccc-script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1010, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "kookiecheck.cz/static/script", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1011, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "legalblink.it/api/scripts/lb_cs.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1012, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dgsvo/script.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1013, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/cc/js/cc.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1014, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "common.i12.de/cms/file/plugin/dp/dp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1015, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/shapepress-dsgvo/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1016, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/iticonseil-rgpd/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1017, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/pixelmate/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1018, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/pixelmate-opt-in/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1019, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.trbo.com/plugin", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1020, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/fb-pixel-dsgvo/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1021, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "id-ward.com/static/idw_plugin", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1022, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ishop-plugins/ishop-cp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1023, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/rrze-legal", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1024, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/rrze-legal", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1025, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wp-content/plugins/jjarolim-tracking/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1026, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/acton/bn/tracker", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1027, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "etracker.de/optin_overlay.php", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1028, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/libraries/google/do-not-track.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1029, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tracking-permission-dialog.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1030, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "origin-images.wikia.com/fandom-ae-assets/tracking-opt-in", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1031, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tracking-opt-in.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1032, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/contaotrackingmanager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1033, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/peg_utils/tracking/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1034, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/kixsimpletrack/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1035, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rodo.js?pp_pr=", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1036, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/templates/rodo/rodo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1037, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/rodo/rodo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1038, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/rodo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1039, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "rodo.agora.pl/agreement/check", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1040, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/min-js?f=js/rodo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1041, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rodo_rmf", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1042, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/popup/rodo.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1043, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rodo/rodo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1044, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rodo-agreement-popup.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1045, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "www.capitol.fr/streaming/cnil/cnil.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1046, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "prismamediadigital.com/cnil.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1047, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "newsletters.ftv-preprod.fr/cnil/js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1048, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Dock/DockContent/Cards/GDPRCard/index.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1049, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "nanoGDPR.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1050, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/GDPR/GDPR.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["3ds.com"] + } + }, + { + "id": 1051, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/GDPRPanelComponent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1052, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tdn.r42tag.com/lib/ut", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1053, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "c.betrad.com/pub/third.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1054, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "fundingchoices.google.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1055, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "fundingchoicesmessages.google.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": [ + "rtl.hr", + "fernsehserien.de", + "bbc.com", + "iol.pt", + "stooq.pl", + "stooq.com" + ] + } + }, + { + "id": 1056, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "spiffymachine.com/v2/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1057, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.userdatatrust.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1058, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.pubguru.com/pg.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1059, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "qualtrics.com/WRSiteInterceptEngine", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["logmeininc.com"] + } + }, + { + "id": 1060, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "a.svtrd.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["ns.nl"] + } + }, + { + "id": 1061, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "foolcdn.com/mms/resources/js/international-visitor-notice-js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1062, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "heraeus.com/media/system_files/special_applications/heraues_datapolicy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1063, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "libraries.wmgartistservices.com/pplightbox", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1064, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "assets.ubembed.com/universal", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1065, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "pi.pardot.com/analytics", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1066, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.useinsider.com/ins.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1067, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "a.optmnstr.com/app/js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1068, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "borderfree.com/v1/dist/cbt.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1069, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.justuno.com/mwgt", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1070, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "caringzinc.com/v2", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1071, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "dam.bbcchannels.com/m/2fmpg/js/outside-iframe.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1072, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "dam.bbcchannels.com/m/2fmph/js/outside-iframe.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1073, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.truendo.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1074, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "intelligentscissors.com/v2", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1075, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.adnuntius.com/adn.dmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1076, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cct-pubweb.com/ccpa", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1077, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "widgets.legalmonster.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1078, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "nexus.ensighten.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1079, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "einfachonline.com/sid", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1080, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/railwayreason.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1081, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/teenytinycellar.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1082, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/lovelydrum.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1083, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/hatefulrequest.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1084, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/aloofvest.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1085, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacidade.api.milvus.com.br", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1086, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "global.ketchcdn.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1087, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "e-i.com/SITW", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1088, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pleasantpump.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1089, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fearlessfaucet.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1090, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "unpkg.com/orejime", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1091, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/superficialeyes.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1092, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cassiecloud.com/loader.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1093, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/childlikeform.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1094, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "baycloud.com/tgcl.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1095, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/chickensstation.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1096, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/handsomelyhealth.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1097, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "s2.getsitecontrol.com/widgets", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1098, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "prismamediadigital.com/cnil.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1099, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.efilli.com/efl.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1100, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.brookiebot.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1101, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tiqcdn.com/utag/tui/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1102, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/basketballbelieve.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1103, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/colossalchance.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1104, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/aliasanvil.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1105, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.byscuit.com/data/client", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1106, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.lawwwing.com/widgets", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1107, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/hallowedinvention.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1108, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "pcz.pl/static/js/moo-cooker.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1109, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eucd/eucd.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1110, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cinabre.sudoc.abes.fr/psi_gui/js/bandeau.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1111, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/euopties.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1112, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cknotiz.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1113, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/common/disclaimer/load.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1114, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wpjslib-chunk-notification.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1115, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cpb.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1116, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.tagsOptOut.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1117, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.termly.io/embed.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1118, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.wpolityce.pl/rhododendron/js/terms_of_service.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1119, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/info_cook.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1120, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/datenschutz.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1121, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "c.sd1.fr/cn/cn.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1122, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "zgody.infor.pl/build/assets/js/main.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1123, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "static.s-sfr.fr/stats/sbtF.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1124, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dsgvo_2018.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1125, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/dsgvo.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1126, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "partner.vxcp.de/_js/vxcp_Common.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1127, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js?renew=false&referer=www.rs2.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1128, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/twcdisclaimer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1129, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jqueryCL.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1130, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/trustArcHelper.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1131, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "widget.clym.io/clym.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1132, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "htmedia.in/analytics-js/dap.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1133, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ufti/uftiLoader.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1134, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/includes/pltk/pltk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1135, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/onstuimig-tag-manager/base/adf-tm-base-min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1136, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/GDRP_banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1137, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ads/rgpd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1138, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "samtykker.agm.as/agent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1139, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "samtykker.agdermedia.no/agent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1140, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/PopUpPriva/PopPrivacymin.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1141, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "dialogue.sp-prod.net/messagingWithoutDetection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "excludedInitiatorDomains": ["globalplayer.com"] + } + }, + { + "id": 1142, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/datenschutz.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1143, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm19.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1144, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/app.dsgvo.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1145, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/trigoAboveBox.jquery.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1146, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dsgvoinit.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1147, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/styleguide/mxqasqco.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1148, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tvp-tcfapi.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1149, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm19.de/app/public/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1150, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm.ceasy.de/public/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1151, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/orejime/js/orejime.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1152, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm/public/app.js?apiKey", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1153, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm19.de/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1154, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wwwschutz.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1155, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm19/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1156, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dsvgobanner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1157, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wecoma-lite.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1158, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "resourcesurw.azureedge.net/js/cc55.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1159, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccnst/ccbundle.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1160, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cc.mpa-web.de/public/app.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1161, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/klaro/klaro-pe.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1162, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "klaro-no-css.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1163, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ionic-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1164, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ckpl-webc.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1165, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "wagtail_tag_manager/wtm.bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1166, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "www.capitol.fr/streaming/cnil/cnil.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1167, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Dock/DockContent/Cards/GDPRCard/index.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1168, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "nanoGDPR.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1169, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "newsletters.ftv-preprod.fr/cnil/js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1170, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/components/es6/PrivacyPolicy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1171, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "js.hs-analytics.net/analytics", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1172, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jsdelivr.net/wp/wp-slimstat", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1173, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/dsvgo.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1174, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/GDPR/GDPR.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1175, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "htmedia.in/analytics-js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1176, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/rgpd/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1177, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/avia-bootstrap/js/klaro/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1178, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/tarteaucitron", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1179, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pandectes-core.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1180, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/orejime.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1181, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "jsdelivr.net/npm/cookify", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1182, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cbgCConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1183, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ckpl-webc.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1184, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/klaro-no-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1185, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tcfapi/tcfapi.umd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1186, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "mein.clickskeks.at/app.js?apiKey", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"] + } + }, + { + "id": 1187, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consumer/cookie/client", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bt.com"] + } + }, + { + "id": 1188, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/frontend/ajax/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["romstal.ro"] + } + }, + { + "id": 1189, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rodo-agreement-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gremimedia.pl"] + } + }, + { + "id": 1190, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rodo-agreement-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zw.com.pl"] + } + }, + { + "id": 1191, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gtm.js?id=GTM-TCT2RJ", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fullrate.dk"] + } + }, + { + "id": 1192, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["paruvendu.fr"] + } + }, + { + "id": 1193, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "datenschutz.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wumpus-gollum-forum.de"] + } + }, + { + "id": 1194, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bho_infobar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ruecken-zentrum.de"] + } + }, + { + "id": 1195, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent/message.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ksta.de"] + } + }, + { + "id": 1196, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.truste.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["oracle.com"] + } + }, + { + "id": 1197, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cui-cookie-policy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["congstar.de"] + } + }, + { + "id": 1198, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bitly.com"] + } + }, + { + "id": 1199, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy/popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["cdaction.pl"] + } + }, + { + "id": 1200, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["knaufdoehetzelf.nl"] + } + }, + { + "id": 1201, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["louisvuitton.com"] + } + }, + { + "id": 1202, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/spmsg_addetection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tvspielfilm.de"] + } + }, + { + "id": 1203, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/firebox-gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["thelittleboxoffice.com"] + } + }, + { + "id": 1204, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.css", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["scholieren.com"] + } + }, + { + "id": 1205, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiescript.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["basiszinssatz.de"] + } + }, + { + "id": 1206, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies/bundle", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lucozadeenergy.com"] + } + }, + { + "id": 1207, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["guitarbackingtrack.com"] + } + }, + { + "id": 1208, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ip-consent.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["weersverwachting.nl"] + } + }, + { + "id": 1209, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiebot.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fluke.com"] + } + }, + { + "id": 1210, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tui-cookie-bar.html", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tuicruises.com"] + } + }, + { + "id": 1211, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-option.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["der-warnemuender.de"] + } + }, + { + "id": 1212, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["sexmarkt.nl"] + } + }, + { + "id": 1213, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ato-cookiebanner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["haag-streit.com"] + } + }, + { + "id": 1214, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["cummins.com"] + } + }, + { + "id": 1215, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/spd/spd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["woman.bg"] + } + }, + { + "id": 1216, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/spd/spd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["novini.bg"] + } + }, + { + "id": 1217, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/spd.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["sportal.bg"] + } + }, + { + "id": 1218, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieman.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["erfurter-bahn.de"] + } + }, + { + "id": 1219, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rg-gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lombardafiltri.it"] + } + }, + { + "id": 1220, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ibox.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aqualip.de"] + } + }, + { + "id": 1221, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cb-scripts", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["convertir-une-image.com"] + } + }, + { + "id": 1222, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.teraz.sk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["teraz.sk"] + } + }, + { + "id": 1223, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-policy.css", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["independent.com.mt"] + } + }, + { + "id": 1224, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/yello-cookie-layer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["yello.de"] + } + }, + { + "id": 1225, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["cashconverters.es"] + } + }, + { + "id": 1226, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/zsmessagebar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["christian.education"] + } + }, + { + "id": 1227, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pmc-pp-tou/privacy.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["rollingstone.com"] + } + }, + { + "id": 1228, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["outage.report"] + } + }, + { + "id": 1229, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/meWantCookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gamigo.de"] + } + }, + { + "id": 1230, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/meWantCookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gamigo.com"] + } + }, + { + "id": 1231, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bonniermag.se"] + } + }, + { + "id": 1232, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccpa/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lakesideparkmodels.com"] + } + }, + { + "id": 1233, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.umdaac.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["yoyogames.com"] + } + }, + { + "id": 1234, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vendor/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["norma-connect.de"] + } + }, + { + "id": 1235, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookiePolicy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["test-aankoop.be"] + } + }, + { + "id": 1236, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "aliveachiever.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["dailydot.com"] + } + }, + { + "id": 1237, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-bar.salessquad.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["blochworld.com"] + } + }, + { + "id": 1238, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/coobann", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aida.de"] + } + }, + { + "id": 1239, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dsgvoCC.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strabag-pfs.de"] + } + }, + { + "id": 1240, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.euck.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["avon-insurance.co.uk"] + } + }, + { + "id": 1241, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/cookie-popup", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["simyo.nl"] + } + }, + { + "id": 1242, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bottom.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["herokuapp.com"] + } + }, + { + "id": 1243, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["melaniemartinezmusic.com"] + } + }, + { + "id": 1244, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cm-body.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tarnkappe.info"] + } + }, + { + "id": 1245, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/idgy_gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["metallumnovum.lt"] + } + }, + { + "id": 1246, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jw.cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jacquelinewilson.co.uk"] + } + }, + { + "id": 1247, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["iban-rechner.de"] + } + }, + { + "id": 1248, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/kameleoon.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hanseaticbank.de"] + } + }, + { + "id": 1249, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["carriereonline.com"] + } + }, + { + "id": 1250, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eloqua", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["visma.fi"] + } + }, + { + "id": 1251, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eloqua", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["visma.no"] + } + }, + { + "id": 1252, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eloqua", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["visma.se"] + } + }, + { + "id": 1253, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eloqua", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["visma.nl"] + } + }, + { + "id": 1254, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eloqua", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["visma.com"] + } + }, + { + "id": 1255, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_banner_test.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["shinedown.com"] + } + }, + { + "id": 1256, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/streamify-gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["streamingbolaget.se"] + } + }, + { + "id": 1257, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies_alert.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lineadombra.it"] + } + }, + { + "id": 1258, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kidstaff.com.ua"] + } + }, + { + "id": 1259, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["catan.com"] + } + }, + { + "id": 1260, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["winbrok.es"] + } + }, + { + "id": 1261, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eurogdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jcbeurope.eu"] + } + }, + { + "id": 1262, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ig_cookie_frontend", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["volksbund.de"] + } + }, + { + "id": 1263, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "bounceexchange.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lumberliquidators.com"] + } + }, + { + "id": 1264, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["keltendorf-mitterkirchen.at"] + } + }, + { + "id": 1265, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mitterkirchen.at"] + } + }, + { + "id": 1266, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vils.at"] + } + }, + { + "id": 1267, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tarteaucitron/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ratp.fr"] + } + }, + { + "id": 1268, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "CheckCookiePolicy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["remixshop.com"] + } + }, + { + "id": 1269, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/japfg/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["myfridgefood.com"] + } + }, + { + "id": 1270, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["raggal.at"] + } + }, + { + "id": 1271, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["haugsdorf.at"] + } + }, + { + "id": 1272, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["umhausen.at"] + } + }, + { + "id": 1273, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookienote/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wittetools.com"] + } + }, + { + "id": 1274, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr-idgy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vejutechnika.lt"] + } + }, + { + "id": 1275, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pltk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["goodcontent.pl"] + } + }, + { + "id": 1276, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tarteaucitron/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arena-now.de"] + } + }, + { + "id": 1277, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/surbma-yes-no-popup/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bysarahkhan.com"] + } + }, + { + "id": 1278, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tryinteract.com"] + } + }, + { + "id": 1279, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consentMgmt/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["comdirect.de"] + } + }, + { + "id": 1280, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pasztor.at"] + } + }, + { + "id": 1281, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tealium-external/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["weltverbesserer.de"] + } + }, + { + "id": 1282, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiesettings.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aarhusmotion.dk"] + } + }, + { + "id": 1283, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/oil", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tv2.dk"] + } + }, + { + "id": 1284, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieajx", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["goettgen.de"] + } + }, + { + "id": 1285, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.parkers.co.uk", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["parkers.co.uk"] + } + }, + { + "id": 1286, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "lovelydrum.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["insidermonkey.com"] + } + }, + { + "id": 1287, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/intuCookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["intu.co.uk"] + } + }, + { + "id": 1288, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tags.tiqcdn.com/utag", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["123-reg.co.uk"] + } + }, + { + "id": 1289, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "stormyachiever.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["thewindowsclub.com"] + } + }, + { + "id": 1290, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gcb/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gallup.com"] + } + }, + { + "id": 1291, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/native-message", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wiwo.de"] + } + }, + { + "id": 1292, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "koekje.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["baustellenabsicherung24.de"] + } + }, + { + "id": 1293, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/getdisclaimer", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wikifolio.com"] + } + }, + { + "id": 1294, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/echonetcookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["muenchenticket.de"] + } + }, + { + "id": 1295, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies-anekis.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["premiosopenbank.com"] + } + }, + { + "id": 1296, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["latoisondor.com"] + } + }, + { + "id": 1297, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cbgCConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["carlsberggroup.com"] + } + }, + { + "id": 1298, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jugendregion.at"] + } + }, + { + "id": 1299, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp-v2/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["youmath.it"] + } + }, + { + "id": 1300, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/permission/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["1und1.de"] + } + }, + { + "id": 1301, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "js.driftt.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zenroom.org"] + } + }, + { + "id": 1302, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/bwx-cookie-consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nosta.com"] + } + }, + { + "id": 1303, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie_settings", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aerotime.aero"] + } + }, + { + "id": 1304, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stadt-bobingen.de"] + } + }, + { + "id": 1305, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "troubledtail.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["interestingengineering.com"] + } + }, + { + "id": 1306, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tracking.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arsys.es"] + } + }, + { + "id": 1307, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tracking.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arsys.fr"] + } + }, + { + "id": 1308, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tracking.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arsys.pt"] + } + }, + { + "id": 1309, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tracking.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arsys.net"] + } + }, + { + "id": 1310, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy/Bootstrap", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tescobank.com"] + } + }, + { + "id": 1311, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["adlkofen.de"] + } + }, + { + "id": 1312, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["klinikwersbach.de"] + } + }, + { + "id": 1313, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieWall/clb.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["innogy.pl"] + } + }, + { + "id": 1314, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["e-pages.dk"] + } + }, + { + "id": 1315, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/easycmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lagerhaus.at"] + } + }, + { + "id": 1316, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookielab/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ol.fr"] + } + }, + { + "id": 1317, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/thcookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["megadruck.de"] + } + }, + { + "id": 1318, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["catan.de"] + } + }, + { + "id": 1319, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["qcnet.com"] + } + }, + { + "id": 1320, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/msmCookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["moneysupermarket.com"] + } + }, + { + "id": 1321, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eon-com-tracking-consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["eon.com"] + } + }, + { + "id": 1322, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/website-cookie-preferences", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nationaltrust.org.uk"] + } + }, + { + "id": 1323, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-bundle", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zoopla.co.uk"] + } + }, + { + "id": 1324, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-wall", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["xebia.com"] + } + }, + { + "id": 1325, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["dhl.com"] + } + }, + { + "id": 1326, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cp01.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jzzo.com"] + } + }, + { + "id": 1327, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/klaro/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["salesviewer.com"] + } + }, + { + "id": 1328, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr.bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mediacourant.nl"] + } + }, + { + "id": 1329, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-management/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["plasteurope.com"] + } + }, + { + "id": 1330, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["dragnsurvey.com"] + } + }, + { + "id": 1331, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/snap-popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["maggiore.it"] + } + }, + { + "id": 1332, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/snap-popup.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["amicoblu.it"] + } + }, + { + "id": 1333, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/apprise", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["podrozerowerowe.info"] + } + }, + { + "id": 1334, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/data-consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stadtwerke-luebz.de"] + } + }, + { + "id": 1335, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/neo-cookie-layer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["united-domains.de"] + } + }, + { + "id": 1336, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieWidget.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["peter-bringts.de"] + } + }, + { + "id": 1337, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lux-residence.com"] + } + }, + { + "id": 1338, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-manager-v", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["df.eu"] + } + }, + { + "id": 1339, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mobilejob.com"] + } + }, + { + "id": 1340, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strato.de"] + } + }, + { + "id": 1341, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strato.nl"] + } + }, + { + "id": 1342, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strato.fr"] + } + }, + { + "id": 1343, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strato.es"] + } + }, + { + "id": 1344, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strato-hosting.co.uk"] + } + }, + { + "id": 1345, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["renault.de"] + } + }, + { + "id": 1346, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/checkCookieConsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["andrewssykes.fr"] + } + }, + { + "id": 1347, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-manager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["cornelsen.de"] + } + }, + { + "id": 1348, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["synopsys.com"] + } + }, + { + "id": 1349, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["total.com"] + } + }, + { + "id": 1350, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tcf2.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["0calc.com"] + } + }, + { + "id": 1351, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tcf2.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["0rechner.de"] + } + }, + { + "id": 1352, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tcf2.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["0calc.fr"] + } + }, + { + "id": 1353, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gusto.at"] + } + }, + { + "id": 1354, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dsgvo-opt-in.css", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kosta.at"] + } + }, + { + "id": 1355, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["total.nl"] + } + }, + { + "id": 1356, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dywc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["radioschwaben.de"] + } + }, + { + "id": 1357, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/microsite-consent-disclaimer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lyxoretf.com"] + } + }, + { + "id": 1358, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/eea", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["psychcentral.com"] + } + }, + { + "id": 1359, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sm-policy-banner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["storage-mart.com"] + } + }, + { + "id": 1360, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/unitb-cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["juedische-allgemeine.de"] + } + }, + { + "id": 1361, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["casanetwork.hu"] + } + }, + { + "id": 1362, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/legal/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kamkabel.ru"] + } + }, + { + "id": 1363, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/accept.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["oreluniver.ru"] + } + }, + { + "id": 1364, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/doria.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lactease.com"] + } + }, + { + "id": 1365, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "js.driftt.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ikonltd.co.uk"] + } + }, + { + "id": 1366, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/esb-privacy.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["erstebank.hr"] + } + }, + { + "id": 1367, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mediamus-cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["swl-unser-stadtwerk.de"] + } + }, + { + "id": 1368, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vinegar.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stadtwerke-herne.de"] + } + }, + { + "id": 1369, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vhs-assets-cookie-control-js.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["planet-beruf.de"] + } + }, + { + "id": 1370, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ob_rgpd/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["orangebank.fr"] + } + }, + { + "id": 1371, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mintos.com"] + } + }, + { + "id": 1372, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/syno_cookie_element", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["synology.com"] + } + }, + { + "id": 1373, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jcookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["javhd.com"] + } + }, + { + "id": 1374, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["sparkasse.at"] + } + }, + { + "id": 1375, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/PoliticaCookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fincaraiz.com.co"] + } + }, + { + "id": 1376, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Team23_SimpleCookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kleiderhelden.com"] + } + }, + { + "id": 1377, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["esprit.de"] + } + }, + { + "id": 1378, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieCutter", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["thebureauinvestigates.com"] + } + }, + { + "id": 1379, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ing.es"] + } + }, + { + "id": 1380, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tenable.com"] + } + }, + { + "id": 1381, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["thetrainline.com"] + } + }, + { + "id": 1382, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["op.fi"] + } + }, + { + "id": 1383, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.bundle.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fastbill.com"] + } + }, + { + "id": 1384, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gaming-style.com"] + } + }, + { + "id": 1385, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["transparenzregister.de"] + } + }, + { + "id": 1386, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/uc/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mcmakler.de"] + } + }, + { + "id": 1387, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-policy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ubuntu.com"] + } + }, + { + "id": 1388, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zitatezumnachdenken.com"] + } + }, + { + "id": 1389, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["metoffice.gov.uk"] + } + }, + { + "id": 1390, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["churchofengland.org"] + } + }, + { + "id": 1391, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cnst.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tauschticket.de"] + } + }, + { + "id": 1392, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["liberbank.es"] + } + }, + { + "id": 1393, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/iCookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["h-supertools.com"] + } + }, + { + "id": 1394, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/he-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["dennree.de"] + } + }, + { + "id": 1395, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/uc_cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gastro24.de"] + } + }, + { + "id": 1396, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bopla.de"] + } + }, + { + "id": 1397, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["telerama.fr"] + } + }, + { + "id": 1398, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["courrierinternational.com"] + } + }, + { + "id": 1399, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vodkaster.com"] + } + }, + { + "id": 1400, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "brsimg.com/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["boursorama.com"] + } + }, + { + "id": 1401, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "trcking.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["canalplus.com"] + } + }, + { + "id": 1402, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hauptbahnhofcity.wien"] + } + }, + { + "id": 1403, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pons.com"] + } + }, + { + "id": 1404, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiefly/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["internet-rockstars.com"] + } + }, + { + "id": 1405, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stepstone.de"] + } + }, + { + "id": 1406, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stepstone.at"] + } + }, + { + "id": 1407, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["santander.pl"] + } + }, + { + "id": 1408, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "trcking.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["canal-plus.com"] + } + }, + { + "id": 1409, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aftenposten.no"] + } + }, + { + "id": 1410, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["coca-cola-deutschland.de"] + } + }, + { + "id": 1411, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-layer/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bahn.de"] + } + }, + { + "id": 1412, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["yodel.co.uk"] + } + }, + { + "id": 1413, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["digit-photo.com"] + } + }, + { + "id": 1414, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/checkcookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["iracing.com"] + } + }, + { + "id": 1415, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["avast.com"] + } + }, + { + "id": 1416, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vg.no"] + } + }, + { + "id": 1417, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tek.no"] + } + }, + { + "id": 1418, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["finn.no"] + } + }, + { + "id": 1419, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lifesycle.co.uk"] + } + }, + { + "id": 1420, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["next-immo.com"] + } + }, + { + "id": 1421, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fnGdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["financer.com"] + } + }, + { + "id": 1422, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-layer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mercedes-benz.io"] + } + }, + { + "id": 1423, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/messagingNoTcfApi.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["svd.se"] + } + }, + { + "id": 1424, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/sygnal42-gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["blitzrechner.de"] + } + }, + { + "id": 1425, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieLayer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["multipower.com"] + } + }, + { + "id": 1426, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_management.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["meteoradar.ch"] + } + }, + { + "id": 1427, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-preferences", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["halebop.se"] + } + }, + { + "id": 1428, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nif.no"] + } + }, + { + "id": 1429, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/klaro-no-css.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["frag-einen-anwalt.de"] + } + }, + { + "id": 1430, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stema.de"] + } + }, + { + "id": 1431, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieBox.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vinos.de"] + } + }, + { + "id": 1432, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["swisscom.ch"] + } + }, + { + "id": 1433, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["schwaebische.de"] + } + }, + { + "id": 1434, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["guldsmykket.dk"] + } + }, + { + "id": 1435, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mieterengel.de"] + } + }, + { + "id": 1436, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/uc_cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gastro-hero.de"] + } + }, + { + "id": 1437, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kurnik.pl"] + } + }, + { + "id": 1438, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dg-governance/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nytimes.com"] + } + }, + { + "id": 1439, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dg-governance/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["inyt.com"] + } + }, + { + "id": 1440, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zukunftsheizen.de"] + } + }, + { + "id": 1441, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["truphone.com"] + } + }, + { + "id": 1442, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["oka.be"] + } + }, + { + "id": 1443, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["prada.com"] + } + }, + { + "id": 1444, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["online-spellcheck.com"] + } + }, + { + "id": 1445, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/it-cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["geze.de"] + } + }, + { + "id": 1446, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/it-cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["geze.pl"] + } + }, + { + "id": 1447, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ConsentInit.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["smartphonehoesjes.nl"] + } + }, + { + "id": 1448, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieser.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aco.com.pl"] + } + }, + { + "id": 1449, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bluelightcard.co.uk"] + } + }, + { + "id": 1450, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/vfConsentCookiesCs.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vodafone.cz"] + } + }, + { + "id": 1451, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bt.no"] + } + }, + { + "id": 1452, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nwb-jobboerse.de"] + } + }, + { + "id": 1453, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ampparit.com"] + } + }, + { + "id": 1454, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["avg.com"] + } + }, + { + "id": 1455, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["washingtonpost.com"] + } + }, + { + "id": 1456, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aftenbladet.no"] + } + }, + { + "id": 1457, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_flyout.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["festo.com"] + } + }, + { + "id": 1458, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/klaro.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["beckhoff.com"] + } + }, + { + "id": 1459, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Manolo_CookieConsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["manoloblahnik.com"] + } + }, + { + "id": 1460, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/LdCookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["landkreis-eichstaett.de"] + } + }, + { + "id": 1461, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/legal-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["meineapotheke.de"] + } + }, + { + "id": 1462, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["inishpharmacy.com"] + } + }, + { + "id": 1463, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-main", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["godaddy.com"] + } + }, + { + "id": 1464, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ultraleicht-trekking.com"] + } + }, + { + "id": 1465, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/base-nf.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lecanardenchaine.fr"] + } + }, + { + "id": 1466, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "toestemmingen.snp.nl", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["snp.nl"] + } + }, + { + "id": 1467, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mendeley.com"] + } + }, + { + "id": 1468, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cm/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["howatherm.de"] + } + }, + { + "id": 1469, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/osb-cmp.min.mjs", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tvgids.nl"] + } + }, + { + "id": 1470, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["01net.com"] + } + }, + { + "id": 1471, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.maerkischekiste.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["maerkischekiste.de"] + } + }, + { + "id": 1472, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["coca-cola.pl"] + } + }, + { + "id": 1473, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["coca-cola.co.uk"] + } + }, + { + "id": 1474, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["coca-cola.dk"] + } + }, + { + "id": 1475, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/it_nsc.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nonsolocap.it"] + } + }, + { + "id": 1476, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["totalwar.com"] + } + }, + { + "id": 1477, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gameswelt.ch"] + } + }, + { + "id": 1478, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gameswelt.de"] + } + }, + { + "id": 1479, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gameswelt.at"] + } + }, + { + "id": 1480, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "h1.versicherungsjournal.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["versicherungsjournal.de"] + } + }, + { + "id": 1481, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["topannonces.fr"] + } + }, + { + "id": 1482, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ellisphere.fr"] + } + }, + { + "id": 1483, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mdv.cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["biehler-cycling.com"] + } + }, + { + "id": 1484, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["here.com"] + } + }, + { + "id": 1485, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gizchina.com"] + } + }, + { + "id": 1486, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["consorsbank.de"] + } + }, + { + "id": 1487, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/alert-info.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["asus.com"] + } + }, + { + "id": 1488, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/alert-info_cn.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["asus.com.cn"] + } + }, + { + "id": 1489, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["etuovi.com"] + } + }, + { + "id": 1490, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vuokraovi.com"] + } + }, + { + "id": 1491, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arvopaperi.fi"] + } + }, + { + "id": 1492, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp.genesis", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vodafone.de"] + } + }, + { + "id": 1493, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/newCookieChoice.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vape-phone.fr"] + } + }, + { + "id": 1494, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-settings-manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["aok.de"] + } + }, + { + "id": 1495, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Ronis_Cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["slaters.co.uk"] + } + }, + { + "id": 1496, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Hmm24_Cookiebanner/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zaehlerschrank24.de"] + } + }, + { + "id": 1497, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consensu.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["shinden.pl"] + } + }, + { + "id": 1498, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "js_privacy_cmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["e24.no"] + } + }, + { + "id": 1499, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieThough.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wochenblitz.com"] + } + }, + { + "id": 1500, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["beethoven.de"] + } + }, + { + "id": 1501, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieWall/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["eon.pl"] + } + }, + { + "id": 1502, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["technics.com"] + } + }, + { + "id": 1503, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookiebanner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["unibo.it"] + } + }, + { + "id": 1504, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["guloggratis.dk"] + } + }, + { + "id": 1505, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "trustarc.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["avantiwestcoast.co.uk"] + } + }, + { + "id": 1506, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["stickypassword.com"] + } + }, + { + "id": 1507, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_layer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["billiger-mietwagen.de"] + } + }, + { + "id": 1508, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/c22.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["cd.cz"] + } + }, + { + "id": 1509, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["o2.cz"] + } + }, + { + "id": 1510, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tarteaucitron/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["flaine.com"] + } + }, + { + "id": 1511, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nettikaravaani.com"] + } + }, + { + "id": 1512, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/stylecc", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["immozentral.com"] + } + }, + { + "id": 1513, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieConsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["loesdau.de"] + } + }, + { + "id": 1514, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zugtouren.de"] + } + }, + { + "id": 1515, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["t-mobile.cz"] + } + }, + { + "id": 1516, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gfps.com"] + } + }, + { + "id": 1517, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jquery.cookiekit.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["dgeg.gov.pt"] + } + }, + { + "id": 1518, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["minmote.no"] + } + }, + { + "id": 1519, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tc_privacy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["matmut.fr"] + } + }, + { + "id": 1520, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie_modal/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["shirtee.com"] + } + }, + { + "id": 1521, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/borlabs-cookie", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["finance-magazin.de"] + } + }, + { + "id": 1522, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["elle.se"] + } + }, + { + "id": 1523, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fyens.dk"] + } + }, + { + "id": 1524, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cf-analytics/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["chatfuel.com"] + } + }, + { + "id": 1525, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cc.labu24.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["labu24.de"] + } + }, + { + "id": 1526, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.ptj.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ptj.de"] + } + }, + { + "id": 1527, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.autopflege24.net", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["autopflege24.net"] + } + }, + { + "id": 1528, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["natune.net"] + } + }, + { + "id": 1529, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-banner", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["studio3t.com"] + } + }, + { + "id": 1530, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies_2020", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pensionlisboa.com"] + } + }, + { + "id": 1531, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ensighten/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["britishairways.com"] + } + }, + { + "id": 1532, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ensighten/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ba.com"] + } + }, + { + "id": 1533, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["finanz-forum.de"] + } + }, + { + "id": 1534, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["konsultacjejst.pl"] + } + }, + { + "id": 1535, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/klaro", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tarif4you.de"] + } + }, + { + "id": 1536, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm.carpassion.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["carpassion.com"] + } + }, + { + "id": 1537, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["godt.no"] + } + }, + { + "id": 1538, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pent.no"] + } + }, + { + "id": 1539, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["rtr.at"] + } + }, + { + "id": 1540, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-policy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hotmart.com"] + } + }, + { + "id": 1541, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["widforss.no"] + } + }, + { + "id": 1542, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/acmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ameblo.jp"] + } + }, + { + "id": 1543, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["regentcentre.co.uk"] + } + }, + { + "id": 1544, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dkmb_gdpr.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fightful.com"] + } + }, + { + "id": 1545, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pandectes-core.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["arktis.de"] + } + }, + { + "id": 1546, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pandectes-core.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["apfelband.de"] + } + }, + { + "id": 1547, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/pandectes-core.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["schvarz.com"] + } + }, + { + "id": 1548, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/uc-cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["santander.de"] + } + }, + { + "id": 1549, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookpop.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["electromenager-compare.com"] + } + }, + { + "id": 1550, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["klart.se"] + } + }, + { + "id": 1551, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tv.nu"] + } + }, + { + "id": 1552, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hemnet.se"] + } + }, + { + "id": 1553, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/aw-cookie.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["soprema.fr"] + } + }, + { + "id": 1554, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/fc_cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bosch-stiftung.de"] + } + }, + { + "id": 1555, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zurich.it"] + } + }, + { + "id": 1556, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.lavie.fr", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lavie.fr"] + } + }, + { + "id": 1557, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["twisto.pl"] + } + }, + { + "id": 1558, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["koestritzer.de"] + } + }, + { + "id": 1559, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiestarter", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["postfinance.ch"] + } + }, + { + "id": 1560, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/b2c.cookie-consent@latest/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["santanderconsumer.se"] + } + }, + { + "id": 1561, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/melindres/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["televes.com"] + } + }, + { + "id": 1562, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gdpr/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["broedersgezondheidswinkel.nl"] + } + }, + { + "id": 1563, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/DisclaimerControl.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["vontobel.com"] + } + }, + { + "id": 1564, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/gtcookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fixtout.fr"] + } + }, + { + "id": 1565, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["le-jackpot-des-medailles-safti.fr"] + } + }, + { + "id": 1566, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/RR_KE_ccm19/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kefalonia-griechenland.com"] + } + }, + { + "id": 1567, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/udg-uc-sdk.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["porsche.com"] + } + }, + { + "id": 1568, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mann.tv"] + } + }, + { + "id": 1569, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-page.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wz.de"] + } + }, + { + "id": 1570, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tarteaucitron.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["intex.fr"] + } + }, + { + "id": 1571, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mtb-news.de"] + } + }, + { + "id": 1572, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["rennrad-news.de"] + } + }, + { + "id": 1573, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["emtb-news.de"] + } + }, + { + "id": 1574, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["cyberghostvpn.com"] + } + }, + { + "id": 1575, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["playok.com"] + } + }, + { + "id": 1576, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "api.usercentrics.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ing.de"] + } + }, + { + "id": 1577, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/iceCookie.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mamacar.cz"] + } + }, + { + "id": 1578, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/otBannerSdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["springerprofessional.de"] + } + }, + { + "id": 1579, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tui.se"] + } + }, + { + "id": 1580, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tui.fi"] + } + }, + { + "id": 1581, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/index.php?consent_manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["papierkram.de"] + } + }, + { + "id": 1582, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/user-consent-management/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["americanexpress.com"] + } + }, + { + "id": 1583, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["privatebanking.hsbc.com"] + } + }, + { + "id": 1584, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hsbc.pl"] + } + }, + { + "id": 1585, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/smedia_cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["renzgroup.de"] + } + }, + { + "id": 1586, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.tanke-guenstig.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tanke-guenstig.de"] + } + }, + { + "id": 1587, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["histoire-et-civilisations.com"] + } + }, + { + "id": 1588, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/mfe-cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["santander.com.br"] + } + }, + { + "id": 1589, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm1.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["dlr.de"] + } + }, + { + "id": 1590, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent-manager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pdf24.org"] + } + }, + { + "id": 1591, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lawgazette.co.uk"] + } + }, + { + "id": 1592, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "ccm.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["abload.de"] + } + }, + { + "id": 1593, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies_utils.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["uca.es"] + } + }, + { + "id": 1594, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookie-overlay.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bensanitair.nl"] + } + }, + { + "id": 1595, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/boldCookie_custom.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["investice.cz"] + } + }, + { + "id": 1596, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmapp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ccm19.de"] + } + }, + { + "id": 1597, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cdn.civiccomputing.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gfms.com"] + } + }, + { + "id": 1598, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ppp/js/permission-client", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["meinaccount.gmx.net"] + } + }, + { + "id": 1599, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ppp/js/permission-client", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hilfe.gmx.net"] + } + }, + { + "id": 1600, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ppp/js/permission-client", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mein.web.de"] + } + }, + { + "id": 1601, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "tags.tiqcdn.com/utag", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lineadirecta.com"] + } + }, + { + "id": 1602, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ujam_tracking/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ujam.com"] + } + }, + { + "id": 1603, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ugp-api/webcontent/v1/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ae.com"] + } + }, + { + "id": 1604, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jobsireland.ie"] + } + }, + { + "id": 1605, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "app.usercentrics.eu", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mainpost.de"] + } + }, + { + "id": 1606, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "pdcookiepro//views/js/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["czasnaherbate.net"] + } + }, + { + "id": 1607, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dtc-fe/policy-control", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["zs-watch.com"] + } + }, + { + "id": 1608, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["loveholidays.ie"] + } + }, + { + "id": 1609, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/inc/cookie_modal_ajax.php", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["georg.at"] + } + }, + { + "id": 1610, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/_next/static/chunks/cookieOverlay", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["galaxus.fr"] + } + }, + { + "id": 1611, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.werner-mertz.de", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["werner-mertz.de"] + } + }, + { + "id": 1612, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/dist/js/cmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["corporate.modivo.com"] + } + }, + { + "id": 1613, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/jimmsconsent", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jimms.fi"] + } + }, + { + "id": 1614, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "chunk-cookie-consent-modal", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["jobup.ch"] + } + }, + { + "id": 1615, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Cookie/ccm19/public/index.php/app.js?", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["condair.de"] + } + }, + { + "id": 1616, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["eurostar.com"] + } + }, + { + "id": 1617, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/static/ct/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wko.at"] + } + }, + { + "id": 1618, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ui/common/scripts/cookies/cookieModalComponent-797ec8a07a.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["oem.no"] + } + }, + { + "id": 1619, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["politico.eu"] + } + }, + { + "id": 1620, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lovelybooks.de"] + } + }, + { + "id": 1621, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["idealo.de"] + } + }, + { + "id": 1622, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["idealo.at"] + } + }, + { + "id": 1623, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["idealo.es"] + } + }, + { + "id": 1624, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["idealo.fr"] + } + }, + { + "id": 1625, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["idealo.it"] + } + }, + { + "id": 1626, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["idealo.co.uk"] + } + }, + { + "id": 1627, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["femmeactuelle.fr"] + } + }, + { + "id": 1628, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["hausjournal.net"] + } + }, + { + "id": 1629, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["lepoint.fr"] + } + }, + { + "id": 1630, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["chefkoch.de"] + } + }, + { + "id": 1631, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["boerse.de"] + } + }, + { + "id": 1632, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["liberation.fr"] + } + }, + { + "id": 1633, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["caradisiac.com"] + } + }, + { + "id": 1634, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wrapperMessagingWithoutDetection", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["anderes-wort.de"] + } + }, + { + "id": 1635, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CookieBanner.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bauer-baumschulen.ch"] + } + }, + { + "id": 1636, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["strato.se"] + } + }, + { + "id": 1637, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["imusic.de"] + } + }, + { + "id": 1638, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["imusic.dk"] + } + }, + { + "id": 1639, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["imusic.no"] + } + }, + { + "id": 1640, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["imusic.se"] + } + }, + { + "id": 1641, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cc.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["imusic.co"] + } + }, + { + "id": 1642, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["comparethemarket.com"] + } + }, + { + "id": 1643, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["malservice.aftonbladet.se"] + } + }, + { + "id": 1644, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/brabo-cookie/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["brandpreventiewinkel.nl"] + } + }, + { + "id": 1645, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nettimoto.com"] + } + }, + { + "id": 1646, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["futura-sciences.com"] + } + }, + { + "id": 1647, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-box", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["schmalz.com"] + } + }, + { + "id": 1648, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/popupConsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["the-fence.com"] + } + }, + { + "id": 1649, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-files/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["paradoxwikis.com"] + } + }, + { + "id": 1650, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookieconsent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["expert.es"] + } + }, + { + "id": 1651, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.quantcast.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gettr.com"] + } + }, + { + "id": 1652, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "coco.we-online.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["we-online.com"] + } + }, + { + "id": 1653, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/modulos/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["villagrancanaria.com"] + } + }, + { + "id": 1654, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["carhartt.com"] + } + }, + { + "id": 1655, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/almacmp", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kotikokki.net"] + } + }, + { + "id": 1656, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rcs_cpmt/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["open.online"] + } + }, + { + "id": 1657, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rcs_cpmt/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["style.corriere.it"] + } + }, + { + "id": 1658, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ph-cookie-helper-mu/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["uwartsonline.nl"] + } + }, + { + "id": 1659, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": ".consent-", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pcgames.de"] + } + }, + { + "id": 1660, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.quantcast.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["deviantart.com"] + } + }, + { + "id": 1661, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["omni.se"] + } + }, + { + "id": 1662, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Libs/cookies", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nadeta.cz"] + } + }, + { + "id": 1663, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/standard-cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["standard.sk"] + } + }, + { + "id": 1664, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Disclaimer.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["private.com"] + } + }, + { + "id": 1665, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["seeandso.com"] + } + }, + { + "id": 1666, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/privacy/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["patente.it"] + } + }, + { + "id": 1667, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/utag.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["tk-aerztefuehrer.de"] + } + }, + { + "id": 1668, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/rcs_cpmt/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["giroditalia.it"] + } + }, + { + "id": 1669, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["behindthename.com"] + } + }, + { + "id": 1670, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "it-cc.index.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["boellhoff.com"] + } + }, + { + "id": 1671, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiecontrol.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["rembutiken.se"] + } + }, + { + "id": 1672, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["deutsches-schulportal.de"] + } + }, + { + "id": 1673, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Custom_clubhinweis", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["ofdb.de"] + } + }, + { + "id": 1674, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["elpais.com"] + } + }, + { + "id": 1675, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.quantcast.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["pr0gramm.com"] + } + }, + { + "id": 1676, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "cmp.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["helthjem.no"] + } + }, + { + "id": 1677, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["webkamery.online"] + } + }, + { + "id": 1678, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/infrasdk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["nofluffjobs.com"] + } + }, + { + "id": 1679, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["diariodejerez.es"] + } + }, + { + "id": 1680, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["leonoticias.com"] + } + }, + { + "id": 1681, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookies_master.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["bayern.de"] + } + }, + { + "id": 1682, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["france24.com"] + } + }, + { + "id": 1683, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/CKCookieConsent.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["caseking.de"] + } + }, + { + "id": 1684, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gea-waldviertler.at"] + } + }, + { + "id": 1685, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookie-consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["gea-waldviertler.de"] + } + }, + { + "id": 1686, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ccm_", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["kro-ncrv.nl"] + } + }, + { + "id": 1687, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["retinatendencias.com"] + } + }, + { + "id": 1688, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/tac.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["avenuedelabrique.com"] + } + }, + { + "id": 1689, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["eldiadecordoba.es"] + } + }, + { + "id": 1690, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/ConsentManager/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["flvw.de"] + } + }, + { + "id": 1691, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "analytics-consent-manager", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["terveystalo.com"] + } + }, + { + "id": 1692, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "seznam.cz", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["firmy.cz"] + } + }, + { + "id": 1693, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-center.org", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["fameplay.tv"] + } + }, + { + "id": 1694, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "poool.fr/access.min.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["spektrum.de"] + } + }, + { + "id": 1695, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/wimc_gtm_consent/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["wingo.ch"] + } + }, + { + "id": 1696, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp_puk.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["commerzbank.de"] + } + }, + { + "id": 1697, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/scmp-int.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["mapy.cz"] + } + }, + { + "id": 1698, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "privacy-mgmt.com", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["immobilien.derstandard.at"] + } + }, + { + "id": 1699, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/js/privacy", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["atu.de"] + } + }, + { + "id": 1700, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/consent.", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["onlinestempel.ch"] + } + }, + { + "id": 1701, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cookiewall/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["saeco.de"] + } + }, + { + "id": 1702, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/Cookies.js", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["sage.co.uk"] + } + }, + { + "id": 1703, + "priority": 1, + "action": { + "type": "block" + }, + "condition": { + "urlFilter": "/cmp/", + "resourceTypes": ["script", "stylesheet", "xmlhttprequest", "image"], + "initiatorDomains": ["liebherr.com"] + } + } +] diff --git a/pkg/engine/headless/browser/stealth/assets.go b/pkg/engine/headless/browser/stealth/assets.go new file mode 100644 index 00000000..d08be871 --- /dev/null +++ b/pkg/engine/headless/browser/stealth/assets.go @@ -0,0 +1,8 @@ +// from stealth go-rod +package stealth + +// JS for stealth +const JS = `;(() => { + +(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:'utils => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via ` + "`" + `Object.getOwnPropertyDescriptor(window, \'chrome\')` + "`" + `\n Object.defineProperty(window, \'chrome\', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We\'ll extend that later\n })\n }\n\n // That means we\'re running headful and don\'t need to mock anything\n if (\'app\' in window.chrome) {\n return // Nothing to do here\n }\n\n const makeError = {\n ErrorInInvocation: fn => {\n const err = new TypeError(` + "`" + `Error in invocation of app.${fn}()` + "`" + `)\n return utils.stripErrorWithAnchor(\n err,\n ` + "`" + `at ${fn} (eval at ` + "`" + `\n )\n }\n }\n\n // There\'s a some static data in that property which doesn\'t seem to change,\n // we should periodically check for updates: ` + "`" + `JSON.stringify(window.app, null, 2)` + "`" + `\n const STATIC_DATA = JSON.parse(\n ` + "`" + `\n{\n "isInstalled": false,\n "InstallState": {\n "DISABLED": "disabled",\n "INSTALLED": "installed",\n "NOT_INSTALLED": "not_installed"\n },\n "RunningState": {\n "CANNOT_RUN": "cannot_run",\n "READY_TO_RUN": "ready_to_run",\n "RUNNING": "running"\n }\n}\n ` + "`" + `.trim()\n )\n\n window.chrome.app = {\n ...STATIC_DATA,\n\n get isInstalled() {\n return false\n },\n\n getDetails: function getDetails() {\n if (arguments.length) {\n throw makeError.ErrorInInvocation(` + "`" + `getDetails` + "`" + `)\n }\n return null\n },\n getIsInstalled: function getDetails() {\n if (arguments.length) {\n throw makeError.ErrorInInvocation(` + "`" + `getIsInstalled` + "`" + `)\n }\n return false\n },\n runningState: function getDetails() {\n if (arguments.length) {\n throw makeError.ErrorInInvocation(` + "`" + `runningState` + "`" + `)\n }\n return \'cannot_run\'\n }\n }\n utils.patchToStringNested(window.chrome.app)\n }',_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"utils => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via ` + "`" + `Object.getOwnPropertyDescriptor(window, 'chrome')` + "`" + `\n Object.defineProperty(window, 'chrome', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We'll extend that later\n })\n }\n\n // That means we're running headful and don't need to mock anything\n if ('csi' in window.chrome) {\n return // Nothing to do here\n }\n\n // Check that the Navigation Timing API v1 is available, we need that\n if (!window.performance || !window.performance.timing) {\n return\n }\n\n const { timing } = window.performance\n\n window.chrome.csi = function() {\n return {\n onloadT: timing.domContentLoadedEventEnd,\n startE: timing.navigationStart,\n pageT: Date.now() - timing.navigationStart,\n tran: 15 // Transition type or something\n }\n }\n utils.patchToString(window.chrome.csi)\n }",_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts }) => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via ` + "`" + `Object.getOwnPropertyDescriptor(window, 'chrome')` + "`" + `\n Object.defineProperty(window, 'chrome', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We'll extend that later\n })\n }\n\n // That means we're running headful and don't need to mock anything\n if ('loadTimes' in window.chrome) {\n return // Nothing to do here\n }\n\n // Check that the Navigation Timing API v1 + v2 is available, we need that\n if (\n !window.performance ||\n !window.performance.timing ||\n !window.PerformancePaintTiming\n ) {\n return\n }\n\n const { performance } = window\n\n // Some stuff is not available on about:blank as it requires a navigation to occur,\n // let's harden the code to not fail then:\n const ntEntryFallback = {\n nextHopProtocol: 'h2',\n type: 'other'\n }\n\n // The API exposes some funky info regarding the connection\n const protocolInfo = {\n get connectionInfo() {\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ntEntry.nextHopProtocol\n },\n get npnNegotiatedProtocol() {\n // NPN is deprecated in favor of ALPN, but this implementation returns the\n // HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\n ? ntEntry.nextHopProtocol\n : 'unknown'\n },\n get navigationType() {\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ntEntry.type\n },\n get wasAlternateProtocolAvailable() {\n // The Alternate-Protocol header is deprecated in favor of Alt-Svc\n // (https://www.mnot.net/blog/2016/03/09/alt-svc), so technically this\n // should always return false.\n return false\n },\n get wasFetchedViaSpdy() {\n // SPDY is deprecated in favor of HTTP/2, but this implementation returns\n // true for HTTP/2 or HTTP2+QUIC/39 as well.\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\n },\n get wasNpnNegotiated() {\n // NPN is deprecated in favor of ALPN, but this implementation returns true\n // for HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.\n const ntEntry =\n performance.getEntriesByType('navigation')[0] || ntEntryFallback\n return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)\n }\n }\n\n const { timing } = window.performance\n\n // Truncate number to specific number of decimals, most of the ` + "`" + `loadTimes` + "`" + ` stuff has 3\n function toFixed(num, fixed) {\n var re = new RegExp('^-?\\\\d+(?:.\\\\d{0,' + (fixed || -1) + '})?')\n return num.toString().match(re)[0]\n }\n\n const timingInfo = {\n get firstPaintAfterLoadTime() {\n // This was never actually implemented and always returns 0.\n return 0\n },\n get requestTime() {\n return timing.navigationStart / 1000\n },\n get startLoadTime() {\n return timing.navigationStart / 1000\n },\n get commitLoadTime() {\n return timing.responseStart / 1000\n },\n get finishDocumentLoadTime() {\n return timing.domContentLoadedEventEnd / 1000\n },\n get finishLoadTime() {\n return timing.loadEventEnd / 1000\n },\n get firstPaintTime() {\n const fpEntry = performance.getEntriesByType('paint')[0] || {\n startTime: timing.loadEventEnd / 1000 // Fallback if no navigation occurred (` + "`" + `about:blank` + "`" + `)\n }\n return toFixed(\n (fpEntry.startTime + performance.timeOrigin) / 1000,\n 3\n )\n }\n }\n\n window.chrome.loadTimes = function() {\n return {\n ...protocolInfo,\n ...timingInfo\n }\n }\n utils.patchToString(window.chrome.loadTimes)\n }",_args:[{opts:{}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts, STATIC_DATA }) => {\n if (!window.chrome) {\n // Use the exact property descriptor found in headful Chrome\n // fetch it via ` + "`" + `Object.getOwnPropertyDescriptor(window, 'chrome')` + "`" + `\n Object.defineProperty(window, 'chrome', {\n writable: true,\n enumerable: true,\n configurable: false, // note!\n value: {} // We'll extend that later\n })\n }\n\n // That means we're running headful and don't need to mock anything\n const existsAlready = 'runtime' in window.chrome\n // ` + "`" + `chrome.runtime` + "`" + ` is only exposed on secure origins\n const isNotSecure = !window.location.protocol.startsWith('https')\n if (existsAlready || (isNotSecure && !opts.runOnInsecureOrigins)) {\n return // Nothing to do here\n }\n\n window.chrome.runtime = {\n // There's a bunch of static data in that property which doesn't seem to change,\n // we should periodically check for updates: ` + "`" + `JSON.stringify(window.chrome.runtime, null, 2)` + "`" + `\n ...STATIC_DATA,\n // ` + "`" + `chrome.runtime.id` + "`" + ` is extension related and returns undefined in Chrome\n get id() {\n return undefined\n },\n // These two require more sophisticated mocks\n connect: null,\n sendMessage: null\n }\n\n const makeCustomRuntimeErrors = (preamble, method, extensionId) => ({\n NoMatchingSignature: new TypeError(\n preamble + ` + "`" + `No matching signature.` + "`" + `\n ),\n MustSpecifyExtensionID: new TypeError(\n preamble +\n ` + "`" + `${method} called from a webpage must specify an Extension ID (string) for its first argument.` + "`" + `\n ),\n InvalidExtensionID: new TypeError(\n preamble + ` + "`" + `Invalid extension id: '${extensionId}'` + "`" + `\n )\n })\n\n // Valid Extension IDs are 32 characters in length and use the letter ` + "`" + `a` + "`" + ` to ` + "`" + `p` + "`" + `:\n // https://source.chromium.org/chromium/chromium/src/+/master:components/crx_file/id_util.cc;drc=14a055ccb17e8c8d5d437fe080faba4c6f07beac;l=90\n const isValidExtensionID = str =>\n str.length === 32 && str.toLowerCase().match(/^[a-p]+$/)\n\n /** Mock ` + "`" + `chrome.runtime.sendMessage` + "`" + ` */\n const sendMessageHandler = {\n apply: function(target, ctx, args) {\n const [extensionId, options, responseCallback] = args || []\n\n // Define custom errors\n const errorPreamble = ` + "`" + `Error in invocation of runtime.sendMessage(optional string extensionId, any message, optional object options, optional function responseCallback): ` + "`" + `\n const Errors = makeCustomRuntimeErrors(\n errorPreamble,\n ` + "`" + `chrome.runtime.sendMessage()` + "`" + `,\n extensionId\n )\n\n // Check if the call signature looks ok\n const noArguments = args.length === 0\n const tooManyArguments = args.length > 4\n const incorrectOptions = options && typeof options !== 'object'\n const incorrectResponseCallback =\n responseCallback && typeof responseCallback !== 'function'\n if (\n noArguments ||\n tooManyArguments ||\n incorrectOptions ||\n incorrectResponseCallback\n ) {\n throw Errors.NoMatchingSignature\n }\n\n // At least 2 arguments are required before we even validate the extension ID\n if (args.length < 2) {\n throw Errors.MustSpecifyExtensionID\n }\n\n // Now let's make sure we got a string as extension ID\n if (typeof extensionId !== 'string') {\n throw Errors.NoMatchingSignature\n }\n\n if (!isValidExtensionID(extensionId)) {\n throw Errors.InvalidExtensionID\n }\n\n return undefined // Normal behavior\n }\n }\n utils.mockWithProxy(\n window.chrome.runtime,\n 'sendMessage',\n function sendMessage() {},\n sendMessageHandler\n )\n\n /**\n * Mock ` + "`" + `chrome.runtime.connect` + "`" + `\n *\n * @see https://developer.chrome.com/apps/runtime#method-connect\n */\n const connectHandler = {\n apply: function(target, ctx, args) {\n const [extensionId, connectInfo] = args || []\n\n // Define custom errors\n const errorPreamble = ` + "`" + `Error in invocation of runtime.connect(optional string extensionId, optional object connectInfo): ` + "`" + `\n const Errors = makeCustomRuntimeErrors(\n errorPreamble,\n ` + "`" + `chrome.runtime.connect()` + "`" + `,\n extensionId\n )\n\n // Behavior differs a bit from sendMessage:\n const noArguments = args.length === 0\n const emptyStringArgument = args.length === 1 && extensionId === ''\n if (noArguments || emptyStringArgument) {\n throw Errors.MustSpecifyExtensionID\n }\n\n const tooManyArguments = args.length > 2\n const incorrectConnectInfoType =\n connectInfo && typeof connectInfo !== 'object'\n\n if (tooManyArguments || incorrectConnectInfoType) {\n throw Errors.NoMatchingSignature\n }\n\n const extensionIdIsString = typeof extensionId === 'string'\n if (extensionIdIsString && extensionId === '') {\n throw Errors.MustSpecifyExtensionID\n }\n if (extensionIdIsString && !isValidExtensionID(extensionId)) {\n throw Errors.InvalidExtensionID\n }\n\n // There's another edge-case here: extensionId is optional so we might find a connectInfo object as first param, which we need to validate\n const validateConnectInfo = ci => {\n // More than a first param connectInfo as been provided\n if (args.length > 1) {\n throw Errors.NoMatchingSignature\n }\n // An empty connectInfo has been provided\n if (Object.keys(ci).length === 0) {\n throw Errors.MustSpecifyExtensionID\n }\n // Loop over all connectInfo props an check them\n Object.entries(ci).forEach(([k, v]) => {\n const isExpected = ['name', 'includeTlsChannelId'].includes(k)\n if (!isExpected) {\n throw new TypeError(\n errorPreamble + ` + "`" + `Unexpected property: '${k}'.` + "`" + `\n )\n }\n const MismatchError = (propName, expected, found) =>\n TypeError(\n errorPreamble +\n ` + "`" + `Error at property '${propName}': Invalid type: expected ${expected}, found ${found}.` + "`" + `\n )\n if (k === 'name' && typeof v !== 'string') {\n throw MismatchError(k, 'string', typeof v)\n }\n if (k === 'includeTlsChannelId' && typeof v !== 'boolean') {\n throw MismatchError(k, 'boolean', typeof v)\n }\n })\n }\n if (typeof extensionId === 'object') {\n validateConnectInfo(extensionId)\n throw Errors.MustSpecifyExtensionID\n }\n\n // Unfortunately even when the connect fails Chrome will return an object with methods we need to mock as well\n return utils.patchToStringNested(makeConnectResponse())\n }\n }\n utils.mockWithProxy(\n window.chrome.runtime,\n 'connect',\n function connect() {},\n connectHandler\n )\n\n function makeConnectResponse() {\n const onSomething = () => ({\n addListener: function addListener() {},\n dispatch: function dispatch() {},\n hasListener: function hasListener() {},\n hasListeners: function hasListeners() {\n return false\n },\n removeListener: function removeListener() {}\n })\n\n const response = {\n name: '',\n sender: undefined,\n disconnect: function disconnect() {},\n onDisconnect: onSomething(),\n onMessage: onSomething(),\n postMessage: function postMessage() {\n if (!arguments.length) {\n throw new TypeError(` + "`" + `Insufficient number of arguments.` + "`" + `)\n }\n throw new Error(` + "`" + `Attempting to use a disconnected port object` + "`" + `)\n }\n }\n return response\n }\n }",_args:[{opts:{runOnInsecureOrigins:!1},STATIC_DATA:{OnInstalledReason:{CHROME_UPDATE:"chrome_update",INSTALL:"install",SHARED_MODULE_UPDATE:"shared_module_update",UPDATE:"update"},OnRestartRequiredReason:{APP_UPDATE:"app_update",OS_UPDATE:"os_update",PERIODIC:"periodic"},PlatformArch:{ARM:"arm",ARM64:"arm64",MIPS:"mips",MIPS64:"mips64",X86_32:"x86-32",X86_64:"x86-64"},PlatformNaclArch:{ARM:"arm",MIPS:"mips",MIPS64:"mips64",X86_32:"x86-32",X86_64:"x86-64"},PlatformOs:{ANDROID:"android",CROS:"cros",LINUX:"linux",MAC:"mac",OPENBSD:"openbsd",WIN:"win"},RequestUpdateCheckStatus:{NO_UPDATE:"no_update",THROTTLED:"throttled",UPDATE_AVAILABLE:"update_available"}}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"utils => {\n /**\n * Input might look funky, we need to normalize it so e.g. whitespace isn't an issue for our spoofing.\n *\n * @example\n * video/webm; codecs=\"vp8, vorbis\"\n * video/mp4; codecs=\"avc1.42E01E\"\n * audio/x-m4a;\n * audio/ogg; codecs=\"vorbis\"\n * @param {String} arg\n */\n const parseInput = arg => {\n const [mime, codecStr] = arg.trim().split(';')\n let codecs = []\n if (codecStr && codecStr.includes('codecs=\"')) {\n codecs = codecStr\n .trim()\n .replace(` + "`" + `codecs=\"` + "`" + `, '')\n .replace(` + "`" + `\"` + "`" + `, '')\n .trim()\n .split(',')\n .filter(x => !!x)\n .map(x => x.trim())\n }\n return {\n mime,\n codecStr,\n codecs\n }\n }\n\n const canPlayType = {\n // Intercept certain requests\n apply: function(target, ctx, args) {\n if (!args || !args.length) {\n return target.apply(ctx, args)\n }\n const { mime, codecs } = parseInput(args[0])\n // This specific mp4 codec is missing in Chromium\n if (mime === 'video/mp4') {\n if (codecs.includes('avc1.42E01E')) {\n return 'probably'\n }\n }\n // This mimetype is only supported if no codecs are specified\n if (mime === 'audio/x-m4a' && !codecs.length) {\n return 'maybe'\n }\n\n // This mimetype is only supported if no codecs are specified\n if (mime === 'audio/aac' && !codecs.length) {\n return 'probably'\n }\n // Everything else as usual\n return target.apply(ctx, args)\n }\n }\n\n /* global HTMLMediaElement */\n utils.replaceWithProxy(\n HTMLMediaElement.prototype,\n 'canPlayType',\n canPlayType\n )\n }",_args:[]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts }) => {\n utils.replaceGetterWithProxy(\n Object.getPrototypeOf(navigator),\n 'hardwareConcurrency',\n utils.makeHandler().getterValue(opts.hardwareConcurrency)\n )\n }",_args:[{opts:{hardwareConcurrency:4}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { opts }) => {\n const languages = opts.languages.length\n ? opts.languages\n : ['en-US', 'en']\n utils.replaceGetterWithProxy(\n Object.getPrototypeOf(navigator),\n 'languages',\n utils.makeHandler().getterValue(Object.freeze([...languages]))\n )\n }",_args:[{opts:{languages:[]}}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, opts) => {\n const isSecure = document.location.protocol.startsWith('https')\n\n // In headful on secure origins the permission should be \"default\", not \"denied\"\n if (isSecure) {\n utils.replaceGetterWithProxy(Notification, 'permission', {\n apply() {\n return 'default'\n }\n })\n }\n\n // Another weird behavior:\n // On insecure origins in headful the state is \"denied\",\n // whereas in headless it's \"prompt\"\n if (!isSecure) {\n const handler = {\n apply(target, ctx, args) {\n const param = (args || [])[0]\n\n const isNotifications =\n param && param.name && param.name === 'notifications'\n if (!isNotifications) {\n return utils.cache.Reflect.apply(...arguments)\n }\n\n return Promise.resolve(\n Object.setPrototypeOf(\n {\n state: 'denied',\n onchange: null\n },\n PermissionStatus.prototype\n )\n )\n }\n }\n // Note: Don't use ` + "`" + `Object.getPrototypeOf` + "`" + ` here\n utils.replaceWithProxy(Permissions.prototype, 'query', handler)\n }\n }",_args:[{}]}),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, { fns, data }) => {\n fns = utils.materializeFns(fns)\n\n // That means we're running headful\n const hasPlugins = 'plugins' in navigator && navigator.plugins.length\n if (hasPlugins) {\n return // nothing to do here\n }\n\n const mimeTypes = fns.generateMimeTypeArray(utils, fns)(data.mimeTypes)\n const plugins = fns.generatePluginArray(utils, fns)(data.plugins)\n\n // Plugin and MimeType cross-reference each other, let's do that now\n // Note: We're looping through ` + "`" + `data.plugins` + "`" + ` here, not the generated ` + "`" + `plugins` + "`" + `\n for (const pluginData of data.plugins) {\n pluginData.__mimeTypes.forEach((type, index) => {\n plugins[pluginData.name][index] = mimeTypes[type]\n\n Object.defineProperty(plugins[pluginData.name], type, {\n value: mimeTypes[type],\n writable: false,\n enumerable: false, // Not enumerable\n configurable: true\n })\n Object.defineProperty(mimeTypes[type], 'enabledPlugin', {\n value:\n type === 'application/x-pnacl'\n ? mimeTypes['application/x-nacl'].enabledPlugin // these reference the same plugin, so we need to re-use the Proxy in order to avoid leaks\n : new Proxy(plugins[pluginData.name], {}), // Prevent circular references\n writable: false,\n enumerable: false, // Important: ` + "`" + `JSON.stringify(navigator.plugins)` + "`" + `\n configurable: true\n })\n })\n }\n\n const patchNavigator = (name, value) =>\n utils.replaceProperty(Object.getPrototypeOf(navigator), name, {\n get() {\n return value\n }\n })\n\n patchNavigator('mimeTypes', mimeTypes)\n patchNavigator('plugins', plugins)\n\n // All done\n }",_args:[{fns:{generateMimeTypeArray:"(utils, fns) => mimeTypesData => {\n return fns.generateMagicArray(utils, fns)(\n mimeTypesData,\n MimeTypeArray.prototype,\n MimeType.prototype,\n 'type'\n )\n}",generatePluginArray:"(utils, fns) => pluginsData => {\n return fns.generateMagicArray(utils, fns)(\n pluginsData,\n PluginArray.prototype,\n Plugin.prototype,\n 'name'\n )\n}",generateMagicArray:"(utils, fns) =>\n function(\n dataArray = [],\n proto = MimeTypeArray.prototype,\n itemProto = MimeType.prototype,\n itemMainProp = 'type'\n ) {\n // Quick helper to set props with the same descriptors vanilla is using\n const defineProp = (obj, prop, value) =>\n Object.defineProperty(obj, prop, {\n value,\n writable: false,\n enumerable: false, // Important for mimeTypes & plugins: ` + "`" + `JSON.stringify(navigator.mimeTypes)` + "`" + `\n configurable: true\n })\n\n // Loop over our fake data and construct items\n const makeItem = data => {\n const item = {}\n for (const prop of Object.keys(data)) {\n if (prop.startsWith('__')) {\n continue\n }\n defineProp(item, prop, data[prop])\n }\n return patchItem(item, data)\n }\n\n const patchItem = (item, data) => {\n let descriptor = Object.getOwnPropertyDescriptors(item)\n\n // Special case: Plugins have a magic length property which is not enumerable\n // e.g. ` + "`" + `navigator.plugins[i].length` + "`" + ` should always be the length of the assigned mimeTypes\n if (itemProto === Plugin.prototype) {\n descriptor = {\n ...descriptor,\n length: {\n value: data.__mimeTypes.length,\n writable: false,\n enumerable: false,\n configurable: true // Important to be able to use the ownKeys trap in a Proxy to strip ` + "`" + `length` + "`" + `\n }\n }\n }\n\n // We need to spoof a specific ` + "`" + `MimeType` + "`" + ` or ` + "`" + `Plugin` + "`" + ` object\n const obj = Object.create(itemProto, descriptor)\n\n // Virtually all property keys are not enumerable in vanilla\n const blacklist = [...Object.keys(data), 'length', 'enabledPlugin']\n return new Proxy(obj, {\n ownKeys(target) {\n return Reflect.ownKeys(target).filter(k => !blacklist.includes(k))\n },\n getOwnPropertyDescriptor(target, prop) {\n if (blacklist.includes(prop)) {\n return undefined\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n }\n })\n }\n\n const magicArray = []\n\n // Loop through our fake data and use that to create convincing entities\n dataArray.forEach(data => {\n magicArray.push(makeItem(data))\n })\n\n // Add direct property access based on types (e.g. ` + "`" + `obj['application/pdf']` + "`" + `) afterwards\n magicArray.forEach(entry => {\n defineProp(magicArray, entry[itemMainProp], entry)\n })\n\n // This is the best way to fake the type to make sure this is false: ` + "`" + `Array.isArray(navigator.mimeTypes)` + "`" + `\n const magicArrayObj = Object.create(proto, {\n ...Object.getOwnPropertyDescriptors(magicArray),\n\n // There's one ugly quirk we unfortunately need to take care of:\n // The ` + "`" + `MimeTypeArray` + "`" + ` prototype has an enumerable ` + "`" + `length` + "`" + ` property,\n // but headful Chrome will still skip it when running ` + "`" + `Object.getOwnPropertyNames(navigator.mimeTypes)` + "`" + `.\n // To strip it we need to make it first ` + "`" + `configurable` + "`" + ` and can then overlay a Proxy with an ` + "`" + `ownKeys` + "`" + ` trap.\n length: {\n value: magicArray.length,\n writable: false,\n enumerable: false,\n configurable: true // Important to be able to use the ownKeys trap in a Proxy to strip ` + "`" + `length` + "`" + `\n }\n })\n\n // Generate our functional function mocks :-)\n const functionMocks = fns.generateFunctionMocks(utils)(\n proto,\n itemMainProp,\n magicArray\n )\n\n // We need to overlay our custom object with a JS Proxy\n const magicArrayObjProxy = new Proxy(magicArrayObj, {\n get(target, key = '') {\n // Redirect function calls to our custom proxied versions mocking the vanilla behavior\n if (key === 'item') {\n return functionMocks.item\n }\n if (key === 'namedItem') {\n return functionMocks.namedItem\n }\n if (proto === PluginArray.prototype && key === 'refresh') {\n return functionMocks.refresh\n }\n // Everything else can pass through as normal\n return utils.cache.Reflect.get(...arguments)\n },\n ownKeys(target) {\n // There are a couple of quirks where the original property demonstrates \"magical\" behavior that makes no sense\n // This can be witnessed when calling ` + "`" + `Object.getOwnPropertyNames(navigator.mimeTypes)` + "`" + ` and the absence of ` + "`" + `length` + "`" + `\n // My guess is that it has to do with the recent change of not allowing data enumeration and this being implemented weirdly\n // For that reason we just completely fake the available property names based on our data to match what regular Chrome is doing\n // Specific issues when not patching this: ` + "`" + `length` + "`" + ` property is available, direct ` + "`" + `types` + "`" + ` props (e.g. ` + "`" + `obj['application/pdf']` + "`" + `) are missing\n const keys = []\n const typeProps = magicArray.map(mt => mt[itemMainProp])\n typeProps.forEach((_, i) => keys.push(` + "`" + `${i}` + "`" + `))\n typeProps.forEach(propName => keys.push(propName))\n return keys\n },\n getOwnPropertyDescriptor(target, prop) {\n if (prop === 'length') {\n return undefined\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n }\n })\n\n return magicArrayObjProxy\n }",generateFunctionMocks:"utils => (\n proto,\n itemMainProp,\n dataArray\n) => ({\n /** Returns the MimeType object with the specified index. */\n item: utils.createProxy(proto.item, {\n apply(target, ctx, args) {\n if (!args.length) {\n throw new TypeError(\n ` + "`" + `Failed to execute 'item' on '${\n proto[Symbol.toStringTag]\n }': 1 argument required, but only 0 present.` + "`" + `\n )\n }\n // Special behavior alert:\n // - Vanilla tries to cast strings to Numbers (only integers!) and use them as property index lookup\n // - If anything else than an integer (including as string) is provided it will return the first entry\n const isInteger = args[0] && Number.isInteger(Number(args[0])) // Cast potential string to number first, then check for integer\n // Note: Vanilla never returns ` + "`" + `undefined` + "`" + `\n return (isInteger ? dataArray[Number(args[0])] : dataArray[0]) || null\n }\n }),\n /** Returns the MimeType object with the specified name. */\n namedItem: utils.createProxy(proto.namedItem, {\n apply(target, ctx, args) {\n if (!args.length) {\n throw new TypeError(\n ` + "`" + `Failed to execute 'namedItem' on '${\n proto[Symbol.toStringTag]\n }': 1 argument required, but only 0 present.` + "`" + `\n )\n }\n return dataArray.find(mt => mt[itemMainProp] === args[0]) || null // Not ` + "`" + `undefined` + "`" + `!\n }\n }),\n /** Does nothing and shall return nothing */\n refresh: proto.refresh\n ? utils.createProxy(proto.refresh, {\n apply(target, ctx, args) {\n return undefined\n }\n })\n : undefined\n})"},data:{mimeTypes:[{type:"application/pdf",suffixes:"pdf",description:"",__pluginName:"Chrome PDF Viewer"},{type:"application/x-google-chrome-pdf",suffixes:"pdf",description:"Portable Document Format",__pluginName:"Chrome PDF Plugin"},{type:"application/x-nacl",suffixes:"",description:"Native Client Executable",__pluginName:"Native Client"},{type:"application/x-pnacl",suffixes:"",description:"Portable Native Client Executable",__pluginName:"Native Client"}],plugins:[{name:"Chrome PDF Plugin",filename:"internal-pdf-viewer",description:"Portable Document Format",__mimeTypes:["application/x-google-chrome-pdf"]},{name:"Chrome PDF Viewer",filename:"mhjfbmdgcfjbbpaeojofohoefgiehjai",description:"",__mimeTypes:["application/pdf"]},{name:"Native Client",filename:"internal-nacl-plugin",description:"",__mimeTypes:["application/x-nacl","application/x-pnacl"]}]}}]}),!1===navigator.webdriver||void 0===navigator.webdriver||delete Object.getPrototypeOf(navigator).webdriver,(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, opts) => {\n const getParameterProxyHandler = {\n apply: function(target, ctx, args) {\n const param = (args || [])[0]\n const result = utils.cache.Reflect.apply(target, ctx, args)\n // UNMASKED_VENDOR_WEBGL\n if (param === 37445) {\n return opts.vendor || 'Intel Inc.' // default in headless: Google Inc.\n }\n // UNMASKED_RENDERER_WEBGL\n if (param === 37446) {\n return opts.renderer || 'Intel Iris OpenGL Engine' // default in headless: Google SwiftShader\n }\n return result\n }\n }\n\n // There's more than one WebGL rendering context\n // https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext#Browser_compatibility\n // To find out the original values here: Object.getOwnPropertyDescriptors(WebGLRenderingContext.prototype.getParameter)\n const addProxy = (obj, propName) => {\n utils.replaceWithProxy(obj, propName, getParameterProxyHandler)\n }\n // For whatever weird reason loops don't play nice with Object.defineProperty, here's the next best thing:\n addProxy(WebGLRenderingContext.prototype, 'getParameter')\n addProxy(WebGL2RenderingContext.prototype, 'getParameter')\n }",_args:[{}]}),(()=>{try{if(window.outerWidth&&window.outerHeight)return;const n=85;window.outerWidth=window.innerWidth,window.outerHeight=window.innerHeight+n}catch(n){}})(),(({_utilsFns:_utilsFns,_mainFunction:_mainFunction,_args:_args})=>{const utils=Object.fromEntries(Object.entries(_utilsFns).map((([key,value])=>[key,eval(value)])));utils.init(),eval(_mainFunction)(utils,..._args)})({_utilsFns:{init:"() => {\n utils.preloadCache()\n}",stripProxyFromErrors:"(handler = {}) => {\n const newHandler = {\n setPrototypeOf: function (target, proto) {\n if (proto === null)\n throw new TypeError('Cannot convert object to primitive value')\n if (Object.getPrototypeOf(target) === Object.getPrototypeOf(proto)) {\n throw new TypeError('Cyclic __proto__ value')\n }\n return Reflect.setPrototypeOf(target, proto)\n }\n }\n // We wrap each trap in the handler in a try/catch and modify the error stack if they throw\n const traps = Object.getOwnPropertyNames(handler)\n traps.forEach(trap => {\n newHandler[trap] = function () {\n try {\n // Forward the call to the defined proxy handler\n return handler[trap].apply(this, arguments || [])\n } catch (err) {\n // Stack traces differ per browser, we only support chromium based ones currently\n if (!err || !err.stack || !err.stack.includes(` + "`" + `at ` + "`" + `)) {\n throw err\n }\n\n // When something throws within one of our traps the Proxy will show up in error stacks\n // An earlier implementation of this code would simply strip lines with a blacklist,\n // but it makes sense to be more surgical here and only remove lines related to our Proxy.\n // We try to use a known \"anchor\" line for that and strip it with everything above it.\n // If the anchor line cannot be found for some reason we fall back to our blacklist approach.\n\n const stripWithBlacklist = (stack, stripFirstLine = true) => {\n const blacklist = [\n ` + "`" + `at Reflect.${trap} ` + "`" + `, // e.g. Reflect.get or Reflect.apply\n ` + "`" + `at Object.${trap} ` + "`" + `, // e.g. Object.get or Object.apply\n ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // caused by this very wrapper :-)\n ]\n return (\n err.stack\n .split('\\n')\n // Always remove the first (file) line in the stack (guaranteed to be our proxy)\n .filter((line, index) => !(index === 1 && stripFirstLine))\n // Check if the line starts with one of our blacklisted strings\n .filter(line => !blacklist.some(bl => line.trim().startsWith(bl)))\n .join('\\n')\n )\n }\n\n const stripWithAnchor = (stack, anchor) => {\n const stackArr = stack.split('\\n')\n anchor = anchor || ` + "`" + `at Object.newHandler. [as ${trap}] ` + "`" + ` // Known first Proxy line in chromium\n const anchorIndex = stackArr.findIndex(line =>\n line.trim().startsWith(anchor)\n )\n if (anchorIndex === -1) {\n return false // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n return stackArr.join('\\n')\n }\n\n // Special cases due to our nested toString proxies\n err.stack = err.stack.replace(\n 'at Object.toString (',\n 'at Function.toString ('\n )\n if ((err.stack || '').includes('at Function.toString (')) {\n err.stack = stripWithBlacklist(err.stack, false)\n throw err\n }\n\n // Try using the anchor method, fallback to blacklist if necessary\n err.stack = stripWithAnchor(err.stack) || stripWithBlacklist(err.stack)\n\n throw err // Re-throw our now sanitized error\n }\n }\n })\n return newHandler\n}",stripErrorWithAnchor:"(err, anchor) => {\n const stackArr = err.stack.split('\\n')\n const anchorIndex = stackArr.findIndex(line => line.trim().startsWith(anchor))\n if (anchorIndex === -1) {\n return err // 404, anchor not found\n }\n // Strip everything from the top until we reach the anchor line (remove anchor line as well)\n // Note: We're keeping the 1st line (zero index) as it's unrelated (e.g. ` + "`" + `TypeError` + "`" + `)\n stackArr.splice(1, anchorIndex)\n err.stack = stackArr.join('\\n')\n return err\n}",replaceProperty:"(obj, propName, descriptorOverrides = {}) => {\n return Object.defineProperty(obj, propName, {\n // Copy over the existing descriptors (writable, enumerable, configurable, etc)\n ...(Object.getOwnPropertyDescriptor(obj, propName) || {}),\n // Add our overrides (e.g. value, get())\n ...descriptorOverrides\n })\n}",preloadCache:"() => {\n if (utils.cache) {\n return\n }\n utils.cache = {\n // Used in our proxies\n Reflect: {\n get: Reflect.get.bind(Reflect),\n apply: Reflect.apply.bind(Reflect)\n },\n // Used in ` + "`" + `makeNativeString` + "`" + `\n nativeToStringStr: Function.toString + '' // => ` + "`" + `function toString() { [native code] }` + "`" + `\n }\n}",makeNativeString:"(name = '') => {\n return utils.cache.nativeToStringStr.replace('toString', name || '')\n}",patchToString:"(obj, str = '') => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === obj) {\n // We either return the optional string verbatim or derive the most desired result automatically\n return str || utils.makeNativeString(obj.name)\n }\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",patchToStringNested:"(obj = {}) => {\n return utils.execRecursively(obj, ['function'], utils.patchToString)\n}",redirectToString:"(proxyObj, originalObj) => {\n const handler = {\n apply: function (target, ctx) {\n // This fixes e.g. ` + "`" + `HTMLMediaElement.prototype.canPlayType.toString + \"\"` + "`" + `\n if (ctx === Function.prototype.toString) {\n return utils.makeNativeString('toString')\n }\n\n // ` + "`" + `toString` + "`" + ` targeted at our proxied Object detected\n if (ctx === proxyObj) {\n const fallback = () =>\n originalObj && originalObj.name\n ? utils.makeNativeString(originalObj.name)\n : utils.makeNativeString(proxyObj.name)\n\n // Return the toString representation of our original object if possible\n return originalObj + '' || fallback()\n }\n\n if (typeof ctx === 'undefined' || ctx === null) {\n return target.call(ctx)\n }\n\n // Check if the toString protype of the context is the same as the global prototype,\n // if not indicates that we are doing a check across different windows., e.g. the iframeWithdirect` + "`" + ` test case\n const hasSameProto = Object.getPrototypeOf(\n Function.prototype.toString\n ).isPrototypeOf(ctx.toString) // eslint-disable-line no-prototype-builtins\n if (!hasSameProto) {\n // Pass the call on to the local Function.prototype.toString instead\n return ctx.toString()\n }\n\n return target.call(ctx)\n }\n }\n\n const toStringProxy = new Proxy(\n Function.prototype.toString,\n utils.stripProxyFromErrors(handler)\n )\n utils.replaceProperty(Function.prototype, 'toString', {\n value: toStringProxy\n })\n}",replaceWithProxy:"(obj, propName, handler) => {\n const originalObj = obj[propName]\n const proxyObj = new Proxy(obj[propName], utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.redirectToString(proxyObj, originalObj)\n\n return true\n}",replaceGetterWithProxy:"(obj, propName, handler) => {\n const fn = Object.getOwnPropertyDescriptor(obj, propName).get\n const fnStr = fn.toString() // special getter function string\n const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { get: proxyObj })\n utils.patchToString(proxyObj, fnStr)\n\n return true\n}",replaceGetterSetter:"(obj, propName, handlerGetterSetter) => {\n const ownPropertyDescriptor = Object.getOwnPropertyDescriptor(obj, propName)\n const handler = { ...ownPropertyDescriptor }\n\n if (handlerGetterSetter.get !== undefined) {\n const nativeFn = ownPropertyDescriptor.get\n handler.get = function() {\n return handlerGetterSetter.get.call(this, nativeFn.bind(this))\n }\n utils.redirectToString(handler.get, nativeFn)\n }\n\n if (handlerGetterSetter.set !== undefined) {\n const nativeFn = ownPropertyDescriptor.set\n handler.set = function(newValue) {\n handlerGetterSetter.set.call(this, newValue, nativeFn.bind(this))\n }\n utils.redirectToString(handler.set, nativeFn)\n }\n\n Object.defineProperty(obj, propName, handler)\n}",mockWithProxy:"(obj, propName, pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n\n utils.replaceProperty(obj, propName, { value: proxyObj })\n utils.patchToString(proxyObj)\n\n return true\n}",createProxy:"(pseudoTarget, handler) => {\n const proxyObj = new Proxy(pseudoTarget, utils.stripProxyFromErrors(handler))\n utils.patchToString(proxyObj)\n\n return proxyObj\n}",splitObjPath:"objPath => ({\n // Remove last dot entry (property) ==> ` + "`" + `HTMLMediaElement.prototype` + "`" + `\n objName: objPath.split('.').slice(0, -1).join('.'),\n // Extract last dot entry ==> ` + "`" + `canPlayType` + "`" + `\n propName: objPath.split('.').slice(-1)[0]\n})",replaceObjPathWithProxy:"(objPath, handler) => {\n const { objName, propName } = utils.splitObjPath(objPath)\n const obj = eval(objName) // eslint-disable-line no-eval\n return utils.replaceWithProxy(obj, propName, handler)\n}",execRecursively:"(obj = {}, typeFilter = [], fn) => {\n function recurse(obj) {\n for (const key in obj) {\n if (obj[key] === undefined) {\n continue\n }\n if (obj[key] && typeof obj[key] === 'object') {\n recurse(obj[key])\n } else {\n if (obj[key] && typeFilter.includes(typeof obj[key])) {\n fn.call(this, obj[key])\n }\n }\n }\n }\n recurse(obj)\n return obj\n}",stringifyFns:"(fnObj = { hello: () => 'world' }) => {\n // Object.fromEntries() ponyfill (in 6 lines) - supported only in Node v12+, modern browsers are fine\n // https://github.com/feross/fromentries\n function fromEntries(iterable) {\n return [...iterable].reduce((obj, [key, val]) => {\n obj[key] = val\n return obj\n }, {})\n }\n return (Object.fromEntries || fromEntries)(\n Object.entries(fnObj)\n .filter(([key, value]) => typeof value === 'function')\n .map(([key, value]) => [key, value.toString()]) // eslint-disable-line no-eval\n )\n}",materializeFns:"(fnStrObj = { hello: \"() => 'world'\" }) => {\n return Object.fromEntries(\n Object.entries(fnStrObj).map(([key, value]) => {\n if (value.startsWith('function')) {\n // some trickery is needed to make oldschool functions work :-)\n return [key, eval(` + "`" + `() => ${value}` + "`" + `)()] // eslint-disable-line no-eval\n } else {\n // arrow functions just work\n return [key, eval(value)] // eslint-disable-line no-eval\n }\n })\n )\n}",makeHandler:"() => ({\n // Used by simple ` + "`" + `navigator` + "`" + ` getter evasions\n getterValue: value => ({\n apply(target, ctx, args) {\n // Let's fetch the value first, to trigger and escalate potential errors\n // Illegal invocations like ` + "`" + `navigator.__proto__.vendor` + "`" + ` will throw here\n utils.cache.Reflect.apply(...arguments)\n return value\n }\n })\n})",arrayEquals:"(array1, array2) => {\n if (array1.length !== array2.length) {\n return false\n }\n for (let i = 0; i < array1.length; ++i) {\n if (array1[i] !== array2[i]) {\n return false\n }\n }\n return true\n}",memoize:"fn => {\n const cache = []\n return function(...args) {\n if (!cache.some(c => utils.arrayEquals(c.key, args))) {\n cache.push({ key: args, value: fn.apply(this, args) })\n }\n return cache.find(c => utils.arrayEquals(c.key, args)).value\n }\n}"},_mainFunction:"(utils, opts) => {\n try {\n // Adds a contentWindow proxy to the provided iframe element\n const addContentWindowProxy = iframe => {\n const contentWindowProxy = {\n get(target, key) {\n // Now to the interesting part:\n // We actually make this thing behave like a regular iframe window,\n // by intercepting calls to e.g. ` + "`" + `.self` + "`" + ` and redirect it to the correct thing. :)\n // That makes it possible for these assertions to be correct:\n // iframe.contentWindow.self === window.top // must be false\n if (key === 'self') {\n return this\n }\n // iframe.contentWindow.frameElement === iframe // must be true\n if (key === 'frameElement') {\n return iframe\n }\n // Intercept iframe.contentWindow[0] to hide the property 0 added by the proxy.\n if (key === '0') {\n return undefined\n }\n return Reflect.get(target, key)\n }\n }\n\n if (!iframe.contentWindow) {\n const proxy = new Proxy(window, contentWindowProxy)\n Object.defineProperty(iframe, 'contentWindow', {\n get() {\n return proxy\n },\n set(newValue) {\n return newValue // contentWindow is immutable\n },\n enumerable: true,\n configurable: false\n })\n }\n }\n\n // Handles iframe element creation, augments ` + "`" + `srcdoc` + "`" + ` property so we can intercept further\n const handleIframeCreation = (target, thisArg, args) => {\n const iframe = target.apply(thisArg, args)\n\n // We need to keep the originals around\n const _iframe = iframe\n const _srcdoc = _iframe.srcdoc\n\n // Add hook for the srcdoc property\n // We need to be very surgical here to not break other iframes by accident\n Object.defineProperty(iframe, 'srcdoc', {\n configurable: true, // Important, so we can reset this later\n get: function() {\n return _srcdoc\n },\n set: function(newValue) {\n addContentWindowProxy(this)\n // Reset property, the hook is only needed once\n Object.defineProperty(iframe, 'srcdoc', {\n configurable: false,\n writable: false,\n value: _srcdoc\n })\n _iframe.srcdoc = newValue\n }\n })\n return iframe\n }\n\n // Adds a hook to intercept iframe creation events\n const addIframeCreationSniffer = () => {\n /* global document */\n const createElementHandler = {\n // Make toString() native\n get(target, key) {\n return Reflect.get(target, key)\n },\n apply: function(target, thisArg, args) {\n const isIframe =\n args && args.length && ` + "`" + `${args[0]}` + "`" + `.toLowerCase() === 'iframe'\n if (!isIframe) {\n // Everything as usual\n return target.apply(thisArg, args)\n } else {\n return handleIframeCreation(target, thisArg, args)\n }\n }\n }\n // All this just due to iframes with srcdoc bug\n utils.replaceWithProxy(\n document,\n 'createElement',\n createElementHandler\n )\n }\n\n // Let's go\n addIframeCreationSniffer()\n } catch (err) {\n // console.warn(err)\n }\n }",_args:[]}); +})();` diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 29a5fddb..75e9c2e4 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -3,7 +3,9 @@ package crawler import ( "fmt" "log/slog" + "os" "os/user" + "path/filepath" "regexp" "sync" "time" @@ -14,6 +16,7 @@ import ( "github.com/go-rod/rod/lib/utils" "github.com/pkg/errors" "github.com/projectdiscovery/katana/pkg/engine/headless/browser" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/diagnostics" "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/normalizer" "github.com/projectdiscovery/katana/pkg/engine/headless/graph" "github.com/projectdiscovery/katana/pkg/engine/headless/types" @@ -27,16 +30,26 @@ type Crawler struct { crawlQueue queue.Queue[*types.Action] crawlGraph *graph.CrawlGraph uniqueActions map[string]struct{} + diagnostics diagnostics.Writer } type Options struct { - ChromiumPath string - MaxBrowsers int - MaxDepth int - PageMaxTimeout time.Duration - ShowBrowser bool - SlowMotion bool - MaxCrawlDuration time.Duration + ChromiumPath string + MaxBrowsers int + MaxDepth int + PageMaxTimeout time.Duration + ShowBrowser bool + SlowMotion bool + MaxCrawlDuration time.Duration + MaxFailureCount int + Trace bool + CookieConsentBypass bool + + // EnableDiagnostics enables the diagnostics mode + // which writes diagnostic information to a directory + // specified by the DiagnosticsDir optionally. + EnableDiagnostics bool + DiagnosticsDir string Logger *slog.Logger ScopeValidator browser.ScopeValidator @@ -59,30 +72,52 @@ func init() { func New(opts Options) (*Crawler, error) { launcher, err := browser.NewLauncher(browser.LauncherOptions{ - ChromiumPath: opts.ChromiumPath, - MaxBrowsers: opts.MaxBrowsers, - PageMaxTimeout: opts.PageMaxTimeout, - ShowBrowser: opts.ShowBrowser, - RequestCallback: opts.RequestCallback, - SlowMotion: opts.SlowMotion, - ScopeValidator: opts.ScopeValidator, - ChromeUser: opts.ChromeUser, + ChromiumPath: opts.ChromiumPath, + MaxBrowsers: opts.MaxBrowsers, + PageMaxTimeout: opts.PageMaxTimeout, + ShowBrowser: opts.ShowBrowser, + RequestCallback: opts.RequestCallback, + SlowMotion: opts.SlowMotion, + ScopeValidator: opts.ScopeValidator, + ChromeUser: opts.ChromeUser, + Trace: opts.Trace, + CookieConsentBypass: opts.CookieConsentBypass, }) if err != nil { return nil, err } + var diagnosticsWriter diagnostics.Writer + if opts.EnableDiagnostics { + directory := opts.DiagnosticsDir + if directory == "" { + cwd, _ := os.Getwd() + directory = filepath.Join(cwd, fmt.Sprintf("katana-diagnostics-%s", time.Now().Format(time.RFC3339))) + } + + writer, err := diagnostics.NewWriter(directory) + if err != nil { + return nil, err + } + diagnosticsWriter = writer + opts.Logger.Info("Diagnostics enabled", slog.String("directory", directory)) + } + crawler := &Crawler{ launcher: launcher, options: opts, logger: opts.Logger, uniqueActions: make(map[string]struct{}), + diagnostics: diagnosticsWriter, } return crawler, nil } func (c *Crawler) Close() { c.launcher.Close() + if c.diagnostics != nil { + c.diagnostics.Close() + } } func (c *Crawler) Crawl(URL string) error { @@ -114,12 +149,22 @@ func (c *Crawler) Crawl(URL string) error { crawlTimeout = time.After(c.options.MaxCrawlDuration) } + consecutiveFailures := 0 + for { select { case <-crawlTimeout: c.logger.Debug("Max crawl duration reached, stopping crawl") return nil default: + // Check for too many failures + if c.options.MaxFailureCount > 0 && consecutiveFailures >= c.options.MaxFailureCount { + c.logger.Warn("Too many consecutive failures, stopping crawl", + slog.Int("failures", consecutiveFailures), + ) + return nil + } + action, err := crawlQueue.Get() if err == queue.ErrNoElementsAvailable { c.logger.Debug("No more actions to process") @@ -143,8 +188,19 @@ func (c *Crawler) Crawl(URL string) error { ) if err := c.crawlFn(action, page); err != nil { + consecutiveFailures++ if err == ErrNoCrawlingAction { - break + return nil + } + if errors.Is(err, ErrElementNotVisible) { + continue + } + if errors.Is(err, &rod.NoPointerEventsError{}) || errors.Is(err, &rod.InvisibleShapeError{}) { + c.logger.Debug("Skipping action as it is not visible", + slog.String("action", action.String()), + slog.String("error", err.Error()), + ) + continue } if errors.Is(err, &rod.NavigationError{}) { c.logger.Debug("Skipping action as navigation failed", @@ -167,6 +223,9 @@ func (c *Crawler) Crawl(URL string) error { ) return err } + + // Reset consecutive failures on success + consecutiveFailures = 0 } } } @@ -178,7 +237,7 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error c.launcher.PutBrowserToPool(page) }() - currentPageHash, err := getPageHash(page) + currentPageHash, _, err := getPageHash(page) if err != nil { return err } @@ -196,6 +255,11 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error // proceed with actions if the scope is allowed // Check the action and do actions based on action type + if c.diagnostics != nil { + if err := c.diagnostics.LogAction(action); err != nil { + return err + } + } if err := c.executeCrawlStateAction(action, page); err != nil { return err } @@ -204,6 +268,11 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error if err != nil { return err } + if c.diagnostics != nil { + if err := c.diagnostics.LogPageState(pageState, diagnostics.PostActionPageState); err != nil { + return err + } + } pageState.OriginID = currentPageHash navigations, err := page.FindNavigations() @@ -233,6 +302,7 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error return err } } + err = c.crawlGraph.AddPageState(*pageState) if err != nil { return err @@ -247,6 +317,8 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error return nil } +var ErrElementNotVisible = errors.New("element not visible") + func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.BrowserPage) error { var err error switch action.Type { @@ -266,20 +338,17 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br if err != nil { return err } + if err := element.ScrollIntoView(); err != nil { + return err + } visible, err := element.Visible() if err != nil { return err } if !visible { - c.logger.Debug("Skipping click on element as it is not visible", - slog.String("element", action.Element.XPath), - ) - return nil + return ErrElementNotVisible } if err := element.Click(proto.InputMouseButtonLeft, 1); err != nil { - if errors.Is(err, &rod.NoPointerEventsError{}) || errors.Is(err, &rod.InvisibleShapeError{}) { - return nil - } return err } if err = page.WaitPageLoadHeurisitics(); err != nil { diff --git a/pkg/engine/headless/crawler/diagnostics/diagnostics.go b/pkg/engine/headless/crawler/diagnostics/diagnostics.go new file mode 100644 index 00000000..a670169c --- /dev/null +++ b/pkg/engine/headless/crawler/diagnostics/diagnostics.go @@ -0,0 +1,127 @@ +package diagnostics + +import ( + "encoding/json" + "os" + "path/filepath" + "sync" + + "github.com/projectdiscovery/katana/pkg/engine/headless/types" + mapsutil "github.com/projectdiscovery/utils/maps" +) + +// Writer is a writer that writes diagnostics to a directory +// for the katana headless crawler module. +type Writer interface { + Close() error + LogAction(action *types.Action) error + LogPageState(state *types.PageState, stateType PageStateType) error +} + +type PageStateType string + +var ( + PreActionPageState PageStateType = "pre-action" + PostActionPageState PageStateType = "post-action" +) + +type diskWriter struct { + index mapsutil.OrderedMap[string, *stateMetadata] + actions []*types.Action + mu sync.Mutex + directory string +} + +type stateMetadata struct { + UniqueID string `json:"unique_id"` + URL string `json:"url"` + Title string `json:"title"` + Occurence int `json:"occurence"` + Type string `json:"type"` +} + +// NewWriter creates a new Writer. +func NewWriter(directory string) (Writer, error) { + if err := os.MkdirAll(directory, 0755); err != nil { + return nil, err + } + return &diskWriter{ + directory: directory, + index: mapsutil.NewOrderedMap[string, *stateMetadata](), + actions: make([]*types.Action, 0), + mu: sync.Mutex{}, + }, nil +} + +func (w *diskWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + + actionsList := w.actions + marshallIndented, err := json.MarshalIndent(actionsList, "", " ") + if err != nil { + return err + } + if err := os.WriteFile(filepath.Join(w.directory, "actions.json"), marshallIndented, 0644); err != nil { + return err + } + + // Write index to a separate file + var data []*stateMetadata + w.index.Iterate(func(key string, value *stateMetadata) bool { + data = append(data, value) + return true + }) + + marshallIndented, err = json.MarshalIndent(data, "", " ") + if err != nil { + return err + } + return os.WriteFile(filepath.Join(w.directory, "index.json"), marshallIndented, 0644) +} + +func (w *diskWriter) LogAction(action *types.Action) error { + w.mu.Lock() + defer w.mu.Unlock() + + w.actions = append(w.actions, action) + return nil +} + +func (w *diskWriter) LogPageState(state *types.PageState, stateType PageStateType) error { + w.mu.Lock() + val, ok := w.index.Get(state.UniqueID) + if ok && val != nil { + w.mu.Unlock() + val.Occurence++ + return nil + } + w.index.Set(state.UniqueID, &stateMetadata{ + URL: state.URL, + Title: state.Title, + Occurence: 1, + Type: string(stateType), + UniqueID: state.UniqueID, + }) + w.mu.Unlock() + + // Write dom to a separate file and remove striped dom + // Create new directory for each state + dom, strippedDOM := state.DOM, state.StrippedDOM + state.DOM, state.StrippedDOM = "", "" + + dir := filepath.Join(w.directory, state.UniqueID) + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + + domFile := filepath.Join(dir, "dom.html") + if err := os.WriteFile(domFile, []byte(dom), 0644); err != nil { + return err + } + strippedDOMFile := filepath.Join(dir, "stripped-dom.html") + if err := os.WriteFile(strippedDOMFile, []byte(strippedDOM), 0644); err != nil { + return err + } + return nil +} diff --git a/pkg/engine/headless/crawler/normalizer/dom_utils.go b/pkg/engine/headless/crawler/normalizer/dom_utils.go index 6efbb22f..52643944 100644 --- a/pkg/engine/headless/crawler/normalizer/dom_utils.go +++ b/pkg/engine/headless/crawler/normalizer/dom_utils.go @@ -21,8 +21,10 @@ var DefaultDOMTransformations = []string{ // NoChildrenDomTransformations removes all elements with no children var NoChildrenDomTransformations = []string{ - "div", // remove divs with no children - "span", // remove spans with no children + "div", // remove divs with no children + "span", // remove spans with no children + "form", // remove forms with no children + "iframe", // remove iframes } // DOMNormalizer is a normalizer for DOM content diff --git a/pkg/engine/headless/crawler/state.go b/pkg/engine/headless/crawler/state.go index efdf22f5..fca3bea6 100644 --- a/pkg/engine/headless/crawler/state.go +++ b/pkg/engine/headless/crawler/state.go @@ -9,31 +9,32 @@ import ( graphlib "github.com/dominikbraun/graph" "github.com/pkg/errors" "github.com/projectdiscovery/katana/pkg/engine/headless/browser" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/diagnostics" "github.com/projectdiscovery/katana/pkg/engine/headless/types" ) var emptyPageHash = sha256Hash("") -func isCorrectNavigation(page *browser.BrowserPage, action *types.Action) (string, error) { - currentPageHash, err := getPageHash(page) +func isCorrectNavigation(page *browser.BrowserPage, action *types.Action) (string, *types.PageState, error) { + currentPageHash, pageState, err := getPageHash(page) if err != nil { - return "", err + return "", nil, err } if currentPageHash != action.OriginID { - return "", fmt.Errorf("failed to navigate back to origin page") + return "", pageState, fmt.Errorf("failed to navigate back to origin page: %s != %s", currentPageHash, action.OriginID) } - return currentPageHash, nil + return currentPageHash, pageState, nil } -func getPageHash(page *browser.BrowserPage) (string, error) { +func getPageHash(page *browser.BrowserPage) (string, *types.PageState, error) { pageState, err := newPageState(page, nil) if err == ErrEmptyPage { - return emptyPageHash, nil + return emptyPageHash, nil, nil } if err != nil { - return "", errors.Wrap(err, "could not get page state") + return "", nil, errors.Wrap(err, "could not get page state") } - return pageState.UniqueID, nil + return pageState.UniqueID, pageState, nil } var ErrEmptyPage = errors.New("page is empty") @@ -69,7 +70,6 @@ func newPageState(page *browser.BrowserPage, action *types.Action) (*types.PageS // Get sha256 hash of the stripped dom state.UniqueID = sha256Hash(strippedDOM) - return state, nil } @@ -206,7 +206,12 @@ func (c *Crawler) tryBrowserHistoryNavigation(page *browser.BrowserPage, originP if err := page.WaitPageLoadHeurisitics(); err != nil { c.logger.Debug("Failed to wait for page load after navigating back using browser history", slog.String("error", err.Error())) } - newPageHash, err := isCorrectNavigation(page, action) + newPageHash, pageState, err := isCorrectNavigation(page, action) + if c.diagnostics != nil && pageState != nil { + if err := c.diagnostics.LogPageState(pageState, diagnostics.PreActionPageState); err != nil { + return "", err + } + } if err != nil { return "", err } @@ -256,7 +261,12 @@ func (c *Crawler) tryShortestPathNavigation(action *types.Action, page *browser. return "", err } } - newPageHash, err := isCorrectNavigation(page, action) + newPageHash, pageState, err := isCorrectNavigation(page, action) + if c.diagnostics != nil && pageState != nil { + if err := c.diagnostics.LogPageState(pageState, diagnostics.PreActionPageState); err != nil { + return "", err + } + } if err != nil { return "", err } diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 8b74c8f4..7bba869d 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -11,11 +11,14 @@ import ( "github.com/projectdiscovery/katana/pkg/engine/headless/crawler" "github.com/projectdiscovery/katana/pkg/output" "github.com/projectdiscovery/katana/pkg/types" + mapsutil "github.com/projectdiscovery/utils/maps" ) type Headless struct { logger *slog.Logger options *types.CrawlerOptions + + deduplicator *mapsutil.SyncLockMap[string, struct{}] } // New returns a new headless crawler instance @@ -25,6 +28,8 @@ func New(options *types.CrawlerOptions) (*Headless, error) { return &Headless{ logger: logger, options: options, + + deduplicator: mapsutil.NewSyncLockMap[string, struct{}](), }, nil } @@ -78,6 +83,7 @@ func (h *Headless) Crawl(URL string) error { MaxDepth: h.options.Options.MaxDepth, ShowBrowser: h.options.Options.ShowBrowser, MaxCrawlDuration: h.options.Options.CrawlDuration, + MaxFailureCount: h.options.Options.MaxFailureCount, MaxBrowsers: 1, PageMaxTimeout: 30 * time.Second, ScopeValidator: scopeValidator, @@ -85,10 +91,20 @@ func (h *Headless) Crawl(URL string) error { if !scopeValidator(rr.Request.URL) { return } + // navigationRequests := h.performJavascriptAnalysis(rr) + // for _, req := range navigationRequests { + // h.options.OutputWriter.Write(req) + // } + + rr.Response.Raw = "" + rr.Response.Body = "" h.options.OutputWriter.Write(rr) }, - Logger: h.logger, - ChromeUser: h.options.ChromeUser, + Logger: h.logger, + ChromeUser: h.options.ChromeUser, + EnableDiagnostics: h.options.Options.EnableDiagnostics, + Trace: h.options.Options.EnableDiagnostics, + CookieConsentBypass: true, } // TODO: Make the crawling multi-threaded. Right now concurrency is hardcoded to 1. @@ -107,3 +123,42 @@ func (h *Headless) Crawl(URL string) error { func (h *Headless) Close() error { return nil } + +// // Integrate JS analysis and other stuff here only in request callback +// func (h *Headless) performJavascriptAnalysis(rr *output.Result) []*output.Result { +// parsedURL, err := url.Parse(rr.Request.URL) +// if err != nil { +// return nil +// } + +// contentType := rr.Response.Headers["Content-Type"] +// if !(strings.HasSuffix(parsedURL.Path, ".js") || strings.HasSuffix(parsedURL.Path, ".css") || strings.Contains(contentType, "/javascript")) { +// return nil +// } +// if utils.IsPathCommonJSLibraryFile(parsedURL.Path) { +// return nil +// } + +// endpointsItems := utils.ExtractJsluiceEndpoints(string(rr.Response.Body)) +// newResp := &navigation.Response{ +// Resp: &http.Response{ +// Request: &http.Request{ +// URL: parsedURL, +// }, +// }, +// } + +// navigationRequests := make([]*output.Result, 0) +// for _, item := range endpointsItems { +// resp := navigation.NewNavigationRequestURLFromResponse(item.Endpoint, rr.Request.URL, "js", fmt.Sprintf("jsluice-%s", item.Type), newResp) +// if _, ok := h.deduplicator.Get(resp.URL); ok { +// continue +// } +// h.deduplicator.Set(resp.URL, struct{}{}) + +// navigationRequests = append(navigationRequests, &output.Result{ +// Request: resp, +// }) +// } +// return navigationRequests +// } diff --git a/pkg/engine/headless/types/types.go b/pkg/engine/headless/types/types.go index 6b20a989..dbbee426 100644 --- a/pkg/engine/headless/types/types.go +++ b/pkg/engine/headless/types/types.go @@ -17,28 +17,28 @@ var ( // web application as determined by the crawler. // It represents the vertex of the crawl graph type PageState struct { - UniqueID string `json:"unique_id"` - OriginID string `json:"origin_id"` - URL string `json:"url"` - Title string `json:"title"` - DOM string `json:"dom"` - StrippedDOM string `json:"stripped_dom"` - Depth int `json:"depth"` - IsRoot bool `json:"is_root"` + UniqueID string `json:"unique_id,omitempty"` + OriginID string `json:"origin_id,omitempty"` + URL string `json:"url,omitempty"` + Title string `json:"title,omitempty"` + DOM string `json:"dom,omitempty"` + StrippedDOM string `json:"stripped_dom,omitempty"` + Depth int `json:"depth,omitempty"` + IsRoot bool `json:"is_root,omitempty"` // NavigationAction is actions taken to reach this state - NavigationAction *Action `json:"navigation_actions"` + NavigationAction *Action `json:"navigation_actions,omitempty"` } // Action is a action taken in the browser type Action struct { - OriginID string `json:"origin_id"` - Type ActionType `json:"type"` - Input string `json:"input"` - Element *HTMLElement `json:"element"` - Form *HTMLForm `json:"form"` - Depth int `json:"depth"` - ResultID string `json:"result_id"` + OriginID string `json:"origin_id,omitempty"` + Type ActionType `json:"type,omitempty"` + Input string `json:"input,omitempty"` + Element *HTMLElement `json:"element,omitempty"` + Form *HTMLForm `json:"form,omitempty"` + Depth int `json:"depth,omitempty"` + ResultID string `json:"result_id,omitempty"` } func (a *Action) Hash() string { @@ -128,18 +128,18 @@ func ActionFromEventListener(listener *EventListener) *Action { // HTMLElement represents a DOM element type HTMLElement struct { - TagName string `json:"tagName"` - ID string `json:"id"` - Classes string `json:"classes"` - Attributes map[string]string `json:"attributes"` - Hidden bool `json:"hidden"` - OuterHTML string `json:"outerHTML"` - Type string `json:"type"` - Value string `json:"value"` - CSSSelector string `json:"cssSelector"` - XPath string `json:"xpath"` - TextContent string `json:"textContent"` - MD5Hash string `json:"md5Hash"` + TagName string `json:"tagName,omitempty"` + ID string `json:"id,omitempty"` + Classes string `json:"classes,omitempty"` + Attributes map[string]string `json:"attributes,omitempty"` + Hidden bool `json:"hidden,omitempty"` + OuterHTML string `json:"outerHTML,omitempty"` + Type string `json:"type,omitempty"` + Value string `json:"value,omitempty"` + CSSSelector string `json:"cssSelector,omitempty"` + XPath string `json:"xpath,omitempty"` + TextContent string `json:"textContent,omitempty"` + MD5Hash string `json:"md5Hash,omitempty"` } func (e *HTMLElement) String() string { @@ -193,17 +193,17 @@ func (e *HTMLElement) Hash() string { // HTMLForm represents a form element type HTMLForm struct { - TagName string `json:"tagName"` - ID string `json:"id"` - Classes string `json:"classes"` - Attributes map[string]string `json:"attributes"` - Hidden bool `json:"hidden"` - OuterHTML string `json:"outerHTML"` - Action string `json:"action"` - Method string `json:"method"` - Elements []*HTMLElement `json:"elements"` - CSSSelector string `json:"cssSelector"` - XPath string `json:"xpath"` + TagName string `json:"tagName,omitempty"` + ID string `json:"id,omitempty"` + Classes string `json:"classes,omitempty"` + Attributes map[string]string `json:"attributes,omitempty"` + Hidden bool `json:"hidden,omitempty"` + OuterHTML string `json:"outerHTML,omitempty"` + Action string `json:"action,omitempty"` + Method string `json:"method,omitempty"` + Elements []*HTMLElement `json:"elements,omitempty"` + CSSSelector string `json:"cssSelector,omitempty"` + XPath string `json:"xpath,omitempty"` } func (f *HTMLForm) Hash() string { @@ -266,9 +266,9 @@ func getStableAttributes(attrs map[string]string) []string { } type EventListener struct { - Element *HTMLElement `json:"element"` - Type string `json:"type"` - Listener string `json:"listener"` + Element *HTMLElement `json:"element,omitempty"` + Type string `json:"type,omitempty"` + Listener string `json:"listener,omitempty"` } // NavigationType represents the type of navigation diff --git a/pkg/types/options.go b/pkg/types/options.go index 09fc5e1a..eb1c7aca 100644 --- a/pkg/types/options.go +++ b/pkg/types/options.go @@ -47,6 +47,8 @@ type Options struct { Timeout int // CrawlDuration is the duration in seconds to crawl target from CrawlDuration time.Duration + // MaxFailureCount is the maximum number of consecutive failures before stopping + MaxFailureCount int // Delay is the delay between each crawl requests in seconds Delay int // RateLimit is the maximum number of requests to send per second @@ -87,6 +89,8 @@ type Options struct { Verbose bool // TechDetect enables technology detection TechDetect bool + // EnableDiagnostics enables diagnostics + EnableDiagnostics bool // Version enables showing of crawler version Version bool // ScrapeJSResponses enables scraping of relative endpoints from javascript From 3677f0937a36cb7f07a5af12b07ada4fe1d26181 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Thu, 26 Jun 2025 19:59:27 +0530 Subject: [PATCH 10/22] feat: added additional simhash + misc additions and fixes --- pkg/engine/headless/TODOS.md | 393 ++++++++++++++++++ pkg/engine/headless/browser/browser.go | 83 +++- pkg/engine/headless/browser/element.go | 33 ++ pkg/engine/headless/crawler/crawler.go | 57 +++ .../crawler/diagnostics/diagnostics.go | 68 +++ .../crawler/normalizer/simhash/simhash.go | 198 +++++++++ .../normalizer/simhash/simhash_test.go | 72 ++++ pkg/engine/headless/crawler/state.go | 39 +- pkg/engine/headless/crawler/state_test.go | 70 ++++ pkg/engine/headless/graph/graph.go | 2 +- pkg/engine/headless/headless.go | 63 +-- pkg/engine/headless/types/types.go | 1 + 12 files changed, 1026 insertions(+), 53 deletions(-) create mode 100644 pkg/engine/headless/TODOS.md create mode 100644 pkg/engine/headless/crawler/normalizer/simhash/simhash.go create mode 100644 pkg/engine/headless/crawler/normalizer/simhash/simhash_test.go diff --git a/pkg/engine/headless/TODOS.md b/pkg/engine/headless/TODOS.md new file mode 100644 index 00000000..bd3e972d --- /dev/null +++ b/pkg/engine/headless/TODOS.md @@ -0,0 +1,393 @@ +# 🗺️ Headless-Crawler Road-Map +--- + +## 🥇 Core Improvements (High-impact / first passes) + +- [ ] After clicking on elements there isn't enough wait time to reflect SPA navigation + +- [ ] **Replace exact DOM hash with perceptual fingerprint** + - Stage 1: keep current SHA-256 on stripped DOM for cheap exact-match. + - Stage 2: compute 64-bit SimHash/MinHash over 3–4-word shingles of the stripped DOM; treat pages equal when Hamming distance ≤ 3 bits. + - Stage 3 (optional): if SimHash inconclusive, take a low-res screenshot and compare pHash/dHash. + - Store `ExactHash` & `FuzzyHash`; update graph comparison logic. + +- [ ] **Robust “page ready” detector** + - Inject `MutationObserver` + `requestIdleCallback`. + - Resolve when: + * no DOM mutation for N ms **and** + * `location.href`/`history.length`/`` stable. + - Wrap as `page.WaitForRouteChange()` and replace `WaitPageLoadHeuristics`. + +- [ ] **Lazy-load / infinite-scroll support** + - Loop: `scrollBy(0, viewportHeight*0.9)` until `scrollHeight` stops growing. + - Fallback: IntersectionObserver on a sentinel div. + +- [ ] **Capture all secondary resource navigations** + - Enable `FetchEnable` + `Network.*` events. + - Record: XHR/Fetch URLs, WebSocket, EventSource, Service-Worker scripts. + - Feed new, in-scope URLs into the crawl queue (dedup by host/path). + +--- + +## 🥈 Mid-term Enhancements + +- [ ] **Dynamic form-filling** + - Generate values based on `type`, `pattern`, `min`, `max`, `maxlength`, `required`. + - Pluggable `ValueProvider` interface for site-specific logic. + +- [ ] **Site adapters / hooks** + - Allow user-supplied Go or JS snippets per hostname (e.g. dismiss cookie wall, auto login, click “load more”). + +- [ ] **Concurrent tab execution** + - Worker pool consuming the action queue. + - Use multiple `rod.Page` instances (shared browser) – make `CrawlGraph` concurrency-safe. + +- [ ] **Smart time-out & retry budgets** + - Adaptive timeout: first nav longer, later ones shorter; one automatic reload on stall. + +- [ ] **Viewport variants** + - Crawl again at typical mobile (390×844) & tablet (768×1024) sizes to reveal responsive content. + +- [ ] **Memory & process recycling** + - Close background tabs after use. + - If Chrome RSS > threshold, restart browser (persist cookies if needed). + +- [ ] **Anti-bot hardening** + - Spoof fonts, canvas & audio contexts. + - Rotate realistic UA strings, languages, `hardwareConcurrency`. + - Optional headful mode via XVFB to enable GPU paths. + +--- + +## 🥉 Nice-to-have / Advanced + +- [ ] **Export crawl sessions** + - HAR or WARC output in parallel to existing JSON. + +- [ ] **JS coverage tracking** + - `Profiler.startPreciseCoverage` → know which scripts never executed. + +- [ ] **Metrics & health** + - Prometheus counters (pages, active tabs, JS errors, nav errors). + - `/debug/pprof` enabled by default. + +- [ ] **TLS / proxy flexibility** + - Accept custom CA bundle, client certs, upstream proxy rotation. + +- [ ] **Sandboxing & security** + - Run Chrome under seccomp / user-namespaces or separate UID/GID automatically. + +- [ ] **Graceful crash recovery** + - Detect `Page.crashed` / `Browser.disconnected`; re-spawn browser, resume queue. + + +---------------------------------- + +Claude OPUS info below: + + + +## 🎯 Critical Bug Fixes & Edge Cases + +- [ ] **Handle iframe content extraction** + - Cross-origin iframe detection and flagging + - Same-origin iframe DOM traversal + - Nested iframe support (up to N levels) + +- [ ] **WebComponent & Shadow DOM support** + - Detect custom elements with shadow roots + - Traverse open shadow DOMs for form/link discovery + - Handle slot-based content projection + +- [ ] **Multi-window/tab detection** + - Track `window.open()` calls that bypass current hooks + - Handle popup windows that close parent + - Manage tab focus for proper event firing + +## 🔐 Authentication & Session Management + +- [ ] **Auth state detection** + - Detect login/logout UI patterns + - Monitor cookie changes for session tracking + - Implement auth health checks between actions + +- [ ] **Multi-step auth flows** + - OAuth redirect handling + - 2FA/MFA detection and waiting + - SAML/SSO flow support + +- [ ] **Session persistence** + - Save/restore cookies between crawls + - Handle JWT token refresh + - Detect and handle session timeouts + +## 🎪 Advanced Interaction Patterns + +- [ ] **Complex UI interactions** + - Drag & drop detection and execution + - File upload with generated test files + - Multi-select and combo-box handling + - Date/time picker interaction + +- [ ] **Keyboard navigation support** + - Tab-order based discovery + - Keyboard shortcut detection (Ctrl+K, etc.) + - Access key enumeration + +- [ ] **Touch/mobile gestures** + - Swipe detection for mobile views + - Long-press context menus + - Pinch-to-zoom aware navigation + +## 📊 Analytics & Monitoring + +- [ ] **Performance metrics** + - Page load time tracking + - JavaScript execution overhead + - Memory usage per page state + - Network request waterfalls + +- [ ] **Crawl quality metrics** + - Code coverage per domain + - Unique vs duplicate state ratio + - Action success/failure rates + - Depth distribution analysis + +- [ ] **Error tracking** + - JavaScript console error capture + - Network error categorization + - CSP violation logging + - Failed action root cause analysis + +## 🧠 Smart Crawling Features + +- [ ] **ML-based duplicate detection** + - Train model on visual similarity + - Semantic HTML structure comparison + - Learn site-specific patterns + +- [ ] **Priority queue optimization** + - High-value path prediction + - Anomaly detection for interesting states + - Dynamic depth adjustment based on yield + +- [ ] **State space reduction** + - Identify and prune redundant actions + - Detect pagination patterns + - Group similar forms (search variations) + +## 🛡️ Security & Compliance + +- [ ] **CAPTCHA handling** + - Detection of common CAPTCHA providers + - Integration points for solving services + - Graceful degradation strategies + +- [ ] **Rate limiting & politeness** + - Per-domain request throttling + - Respect robots.txt for headless + - Adaptive delays based on response times + +- [ ] **Privacy compliance** + - PII detection in forms + - GDPR banner interaction + - Data retention policies + +## 🔌 Integration Features + +- [ ] **API extraction** + - GraphQL query/mutation detection + - REST endpoint parameter learning + - WebSocket message format detection + +- [ ] **Export formats** + - OpenAPI spec generation from discoveries + - Postman collection export + - Burp Suite state file compatibility + +- [ ] **Workflow recording** + - Playwright/Puppeteer script generation + - Selenium IDE format export + - Custom DSL for replay + +## 🚀 Performance Optimizations + +- [ ] **Rendering optimizations** + - Disable images/fonts for text-only analysis + - Viewport-based lazy rendering + - CPU throttling for battery saving + +- [ ] **Caching layer** + - DOM diff caching + - Screenshot perceptual hashes + - JavaScript execution results + +- [ ] **Distributed crawling** + - Work queue distribution + - State synchronization protocol + - Result aggregation pipeline + +## 🔧 Developer Experience + +- [ ] **Debug tooling** + - Live crawl visualization + - State graph explorer UI + - Action replay debugger + +- [ ] **Configuration management** + - Per-site config profiles + - A/B testing different strategies + - Hot-reload of site adapters + +- [ ] **Testing infrastructure** + - Headless crawler unit tests + - Integration tests with test sites + - Regression detection suite + + +state.go is the crawler’s “state-manager”. +Everything else in the headless package (browser wrappers, normalizer, graph, diagnostics) either feeds data into it or asks it to restore a known state. +To make the crawler scalable, reliable and de-dupe friendly the file should be responsible for exactly three things: + +1. Build a reproducible fingerprint (“state ID”) for the current page. +2. Persist the surrounding metadata that we need to replay that state later. +3. Provide deterministic, cheapest-first logic to get back to any recorded state. + +Below is a complete design that meets those goals and leaves room for future TODOs. + + +──────────────────────────────────────────────────────────────────────────── +1. Fingerprint strategy (page → id) +──────────────────────────────────────────────────────────────────────────── +A. Canonical DOM extraction + • Use the existing domNormalizer (strip scripts, styles, dynamic IDs etc.). + • Remove all transient event-attributes (`onclick`, `onmouseover`, …). + • Collapse whitespace → single space. + +B. Two-tier hash + • ExactHash = SHA-256(strippedDOM). + • FuzzyHash = SimHash64(4-word shingles of strippedDOM). + • Treat states equal if + - ExactHash matches, or + - Hamming(FuzzyHash, other.FuzzyHash) ≤ 3 bits. + • Persist both; the graph layer deduplicates on (ExactHash || close-enough FuzzyHash). + +C. Optional visual fallback + • If comparison is inconclusive (≥ 4 bit distance but DOM len < 1 MiB) + → low-res screenshot, pHash/dHash → same threshold logic. + • Executed lazily to avoid perf hit. + +Resulting struct: + +type PageState struct { + ExactHash string // always present + FuzzyHash uint64 // present if SimHash computed + URL string + Title string + Depth int + StrippedDOM string + NavigationAction *Action // edge that produced this state + Timestamp time.Time +} + +–––– Advantages +• SimHash makes minor DOM variations (ads, CSRF tokens) resolve to the same state, reducing graph size. +• Screenshot hash catches SPA view switches that don’t touch the DOM tree much but look different. + +──────────────────────────────────────────────────────────────────────────── +2. Metadata collection (page → PageState) +──────────────────────────────────────────────────────────────────────────── +Algorithm newPageState(page, causingAction): + +1. Grab `page.Info()`; bail out if URL is empty or about:blank. +2. outerHTML := page.HTML(). +3. stripped := domNormalizer.Apply(outerHTML). +4. Build PageState as above. +5. Compute hashes as described. +6. Diagnostics hook (save stripped DOM, screenshots, etc.). +7. Return the fully populated PageState. + +Edge cases handled: +• Empty page → custom ErrEmptyPage (already present). +• Non-deterministic DOM normalizer failure → bubbled up with context. + +──────────────────────────────────────────────────────────────────────────── +3. Return-to-origin algorithm (current page, targetOriginID) → (pageID, error) +──────────────────────────────────────────────────────────────────────────── +Keep the existing three-level approach but hard-code their priority and exit conditions. + +Step 0 Fast-fail: if currentID == target → done. + +Step 1 Element re-use + • If `action.Element` is non-nil, locate by XPath, ensure Visible & Interactable, + *plus* DOM equality check under the canonicalizer to avoid false positives. + • If match, return targetOriginID. + +Step 2 Browser history + • page.GetNavigationHistory() + • Walk back until (url == origin.URL && title == origin.Title). + • Limit: max 10 steps to avoid long loops. + • After each back() call wait with WaitForRouteChange() (new detector described below). + • Recompute fingerprint; if equal (exact or fuzzy) → success. + +Step 3 Graph shortest path + • crawlerGraph.ShortestPath(currentID, targetID). + • If unreachable, retry from emptyPageHash (fresh tab). + • Execute each Action; after each, WaitForRouteChange(). + • After final step verify state (same equality logic as Step 2). + • Failure → ErrNoNavigationPossible. + +Enhancements +• Cache the computed “distance” between two states; next call can skip graph search. +• Record statistics (#navigationBackSuccessByMethod) to tune the priority order. + +──────────────────────────────────────────────────────────────────────────── +4. “Page ready” detector (WaitForRouteChange) +──────────────────────────────────────────────────────────────────────────── +Replace the brittle WaitPageLoadHeuristics with: + +Injected JS once per tab: + +const idle = () => new Promise(res => { + const done = () => { obs.disconnect(); res(); }; + let t; + const reset = () => { clearTimeout(t); t = setTimeout(done, 300); }; + const obs = new MutationObserver(reset); + obs.observe(document, {subtree: true, childList: true, attributes: true}); + reset(); +}); + +window.__katanaReady = () => Promise.all([ + idle(), + new Promise(r => requestIdleCallback(r, {timeout: 5000})) +]); + +Go side: + +func (p *BrowserPage) WaitForRouteChange() error { + ctx, cancel := context.WithTimeout(p.ctx, 15*time.Second) + defer cancel() + return rod.Try(func() { + p.Eval(ctx, `await window.__katanaReady()`) + }) +} + +Detects route changes, SPA navigations, AJAX content, infinite scroll “settling”, etc. + +──────────────────────────────────────────────────────────────────────────── +5. Extensibility hooks +──────────────────────────────────────────────────────────────────────────── +• FingerprintStrategy interface so users can plug in custom SimHash/Screenshot logic. +• ValueProvider & SiteAdapter interfaces already planned can depend on PageState to decide actions. +• Diagnostics sink gets PageState + serialized Action graph for offline visualizer. + +──────────────────────────────────────────────────────────────────────────── +6. Migration plan +──────────────────────────────────────────────────────────────────────────── +1. Stage 1 (quick): keep old sha256 flow, introduce struct fields & interface but stub SimHash. +2. Stage 2: integrate open-source SimHash library, enable fuzzy comparator in graph. +3. Stage 3: optional pHash path guarded by feature flag. +4. Replace WaitPageLoadHeuristics with WaitForRouteChange(). +5. Add metrics around navigation-back success. + +This architecture keeps state.go focused, removes hidden coupling, and sets up the crawler for future road-map items (concurrent tabs, adapters, ML dedup, etc.) while remaining incremental enough to merge in small PRs. \ No newline at end of file diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 567c848a..6f1b3fa3 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -161,13 +161,86 @@ type BrowserPage struct { launcher *Launcher } -// WaitPageLoadHeurisitics waits for the page to load using heuristics +// WaitOptions controls how WaitPageLoadHeurisitics determines navigation completion. +// All durations are conservative defaults and can be tuned later via package-level variables +// or future setter methods (kept simple here to avoid breaking public API). +type WaitOptions struct { + URLPollInterval time.Duration // interval between successive URL polls + URLPollTimeout time.Duration // how long to keep polling before giving up on URL change + PostChangeWait time.Duration // small grace period after URL change for late requests + IdleWait time.Duration // network-idle window when no URL change happened + DOMStableWait time.Duration // DOM-stable window (used after idle) + MaxTimeout time.Duration // absolute upper bound for all waiting +} + +// defaultWaitOptions are derived from empirical measurements on modern SPA pages. +var defaultWaitOptions = WaitOptions{ + URLPollInterval: 100 * time.Millisecond, + URLPollTimeout: 2 * time.Second, + PostChangeWait: 300 * time.Millisecond, + IdleWait: 1 * time.Second, + DOMStableWait: 1 * time.Second, + MaxTimeout: 15 * time.Second, +} + +// WaitPageLoadHeurisitics waits for the page to load using multiple heuristics. +// Strategy order: +// 1. Wait for initial load event (covers classic navigation & first paint). +// 2. Poll for a URL change – the strongest signal on SPAs with client-side routing. +// 3. If URL changes, wait a short grace period + network-idle window. +// 4. If URL doesn't change, fall back to network-idle + DOM-stable windows. +// +// This keeps fast pages fast while still succeeding on noisy, long-running SPAs. func (b *BrowserPage) WaitPageLoadHeurisitics() error { - chainedTimeout := b.Timeout(15 * time.Second) + opts := defaultWaitOptions + + chained := b.Timeout(opts.MaxTimeout) + + // 1. Wait for the basic load event (DOMContentLoaded / load). + _ = chained.WaitLoad() + + // 2. Capture the current URL so we can detect route changes. + urlVal, _ := b.Eval("() => window.location.href") + startURL := "" + if urlVal != nil { + startURL = urlVal.Value.Str() + } + + // 3. Poll for a different URL for up to URLPollTimeout. + urlChanged := false + if startURL != "" { + pollCount := int(opts.URLPollTimeout / opts.URLPollInterval) + for i := 0; i < pollCount; i++ { + time.Sleep(opts.URLPollInterval) + cur, err := b.Eval("() => window.location.href") + if err == nil && cur != nil && cur.Value.Str() != startURL { + urlChanged = true + break + } + } + } + + if urlChanged { + // 4a. URL changed – short grace period then network idle & done. + _ = chained.WaitIdle(opts.PostChangeWait) + return nil + } + + // 4b. URL didn't change – fall back to broader heuristics. + _ = chained.WaitIdle(opts.IdleWait) + _ = b.WaitNewStable(opts.DOMStableWait) + + return nil +} + +// WaitPageLoadHeuristicsFallback provides the enhanced timeouts for complex navigation +func (b *BrowserPage) WaitPageLoadHeuristicsFallback() error { + chainedTimeout := b.Timeout(20 * time.Second) _ = chainedTimeout.WaitLoad() - _ = chainedTimeout.WaitIdle(1 * time.Second) - _ = b.WaitNewStable(500 * time.Millisecond) + _ = chainedTimeout.WaitIdle(4 * time.Second) + _ = b.WaitNewStable(2 * time.Second) + return nil } @@ -311,6 +384,7 @@ func (b *BrowserPage) handlePageDialogBoxes() error { } httpresp := netHTTPResponseFromProto(e, body) + httpresp.Request = httpreq rawBytesResponse, _ := httputil.DumpResponse(httpresp, true) @@ -320,6 +394,7 @@ func (b *BrowserPage) handlePageDialogBoxes() error { Headers: utils.FlattenHeaders(httpresp.Header), Raw: string(rawBytesResponse), ContentLength: httpresp.ContentLength, + Resp: httpresp, } b.launcher.opts.RequestCallback(&output.Result{ Timestamp: time.Now(), diff --git a/pkg/engine/headless/browser/element.go b/pkg/engine/headless/browser/element.go index 6262f417..2dd2f48d 100644 --- a/pkg/engine/headless/browser/element.go +++ b/pkg/engine/headless/browser/element.go @@ -16,6 +16,35 @@ const ( linksCSSSelector = "a" ) +// isElementDisabled checks if a button element is disabled +func isElementDisabled(element *types.HTMLElement) bool { + if element.Attributes == nil { + return false + } + + // Standard HTML disabled attribute + if _, disabled := element.Attributes["disabled"]; disabled { + return true + } + + // Tailwind or framework class-based detection + if classAttr, ok := element.Attributes["class"]; ok { + classList := strings.Fields(classAttr) + for _, class := range classList { + if class == "cursor-not-allowed" || class == "pointer-events-none" { + return true + } + } + } + + // Optionally support ARIA disabled + if aria, ok := element.Attributes["aria-disabled"]; ok && (aria == "true" || aria == "1") { + return true + } + + return false +} + // FindNavigation attempts to find more navigations on the page which could // be done to find more links and pages. // @@ -37,6 +66,10 @@ func (b *BrowserPage) FindNavigations() ([]*types.Action, error) { return nil, errors.Wrap(err, "could not get buttons") } for _, button := range buttons { + if isElementDisabled(button) { + continue + } + hash := button.Hash() button.MD5Hash = hash diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 75e9c2e4..cde68c24 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -18,6 +18,7 @@ import ( "github.com/projectdiscovery/katana/pkg/engine/headless/browser" "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/diagnostics" "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/normalizer" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/normalizer/simhash" "github.com/projectdiscovery/katana/pkg/engine/headless/graph" "github.com/projectdiscovery/katana/pkg/engine/headless/types" "github.com/projectdiscovery/katana/pkg/output" @@ -29,6 +30,7 @@ type Crawler struct { options Options crawlQueue queue.Queue[*types.Action] crawlGraph *graph.CrawlGraph + simhashOracle *simhash.Oracle uniqueActions map[string]struct{} diagnostics diagnostics.Writer } @@ -109,6 +111,7 @@ func New(opts Options) (*Crawler, error) { logger: opts.Logger, uniqueActions: make(map[string]struct{}), diagnostics: diagnosticsWriter, + simhashOracle: simhash.NewOracle(), } return crawler, nil } @@ -120,7 +123,21 @@ func (c *Crawler) Close() { } } +func (c *Crawler) GetCrawlGraph() *graph.CrawlGraph { + return c.crawlGraph +} + func (c *Crawler) Crawl(URL string) error { + defer func() { + if c.diagnostics == nil { + return + } + err := c.crawlGraph.DrawGraph(filepath.Join(c.options.DiagnosticsDir, "crawl-graph.dot")) + if err != nil { + c.logger.Error("Failed to draw crawl graph", slog.String("error", err.Error())) + } + }() + actions := []*types.Action{{ Type: types.ActionTypeLoadURL, Input: URL, @@ -242,7 +259,17 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error return err } + c.logger.Debug("Processing action - current state", + slog.String("current_page_hash", currentPageHash), + slog.String("action_origin_id", action.OriginID), + slog.String("action", action.String()), + ) + if action.OriginID != "" && action.OriginID != currentPageHash { + c.logger.Debug("Need to navigate back to origin", + slog.String("from", currentPageHash), + slog.String("to", action.OriginID), + ) newPageHash, err := c.navigateBackToStateOrigin(action, page, currentPageHash) if err != nil { return err @@ -279,6 +306,23 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error if err != nil { return err } + + // Log navigations for diagnostics + if c.diagnostics != nil { + screenshotState, err := page.Screenshot(false, &proto.PageCaptureScreenshot{ + Format: proto.PageCaptureScreenshotFormatPng, + }) + if err != nil { + c.logger.Error("Failed to take screenshot", slog.String("error", err.Error())) + } + if err := c.diagnostics.LogPageStateScreenshot(pageState.UniqueID, screenshotState); err != nil { + c.logger.Error("Failed to log page state screenshot", slog.String("error", err.Error())) + } + if err := c.diagnostics.LogNavigations(pageState.UniqueID, navigations); err != nil { + c.logger.Error("Failed to log navigations", slog.String("error", err.Error())) + } + } + for _, nav := range navigations { actionHash := nav.Hash() if _, ok := c.uniqueActions[actionHash]; ok { @@ -348,6 +392,19 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br if !visible { return ErrElementNotVisible } + + // Check if element is interactable (not blocked by overlays) + interactable, err := element.Interactable() + if err != nil { + if errors.Is(err, &rod.CoveredError{}) { + return ErrElementNotVisible + } + return err + } + if interactable == nil { + return ErrElementNotVisible + } + if err := element.Click(proto.InputMouseButtonLeft, 1); err != nil { return err } diff --git a/pkg/engine/headless/crawler/diagnostics/diagnostics.go b/pkg/engine/headless/crawler/diagnostics/diagnostics.go index a670169c..1b8358e6 100644 --- a/pkg/engine/headless/crawler/diagnostics/diagnostics.go +++ b/pkg/engine/headless/crawler/diagnostics/diagnostics.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "sync" + "time" "github.com/projectdiscovery/katana/pkg/engine/headless/types" mapsutil "github.com/projectdiscovery/utils/maps" @@ -16,6 +17,8 @@ type Writer interface { Close() error LogAction(action *types.Action) error LogPageState(state *types.PageState, stateType PageStateType) error + LogNavigations(pageStateID string, navigations []*types.Action) error + LogPageStateScreenshot(pageStateID string, screenshot []byte) error } type PageStateType string @@ -40,11 +43,20 @@ type stateMetadata struct { Type string `json:"type"` } +type navigationEntry struct { + PageStateID string `json:"page_state_id"` + URL string `json:"url"` + NavigationCount int `json:"navigation_count"` + Navigations []*types.Action `json:"navigations"` + Timestamp int64 `json:"timestamp"` +} + // NewWriter creates a new Writer. func NewWriter(directory string) (Writer, error) { if err := os.MkdirAll(directory, 0755); err != nil { return nil, err } + return &diskWriter{ directory: directory, index: mapsutil.NewOrderedMap[string, *stateMetadata](), @@ -125,3 +137,59 @@ func (w *diskWriter) LogPageState(state *types.PageState, stateType PageStateTyp } return nil } + +func (w *diskWriter) LogNavigations(pageStateID string, navigations []*types.Action) error { + w.mu.Lock() + defer w.mu.Unlock() + + metadata, exists := w.index.Get(pageStateID) + url := "" + if exists && metadata != nil { + url = metadata.URL + } + + dir := filepath.Join(w.directory, pageStateID) + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + + navigationsFile := filepath.Join(dir, "navigations.json") + + var entry navigationEntry + if existingData, err := os.ReadFile(navigationsFile); err == nil { + if err := json.Unmarshal(existingData, &entry); err != nil { + return err + } + + entry.Navigations = append(entry.Navigations, navigations...) + entry.NavigationCount = len(entry.Navigations) + entry.Timestamp = time.Now().Unix() + } else { + entry = navigationEntry{ + PageStateID: pageStateID, + URL: url, + NavigationCount: len(navigations), + Navigations: navigations, + Timestamp: time.Now().Unix(), + } + } + marshalledData, err := json.MarshalIndent(entry, "", " ") + if err != nil { + return err + } + + // Write to navigations.json file in the state directory + return os.WriteFile(navigationsFile, marshalledData, 0644) +} + +func (w *diskWriter) LogPageStateScreenshot(pageStateID string, screenshot []byte) error { + w.mu.Lock() + defer w.mu.Unlock() + + dir := filepath.Join(w.directory, pageStateID) + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + screenshotFile := filepath.Join(dir, "screenshot.png") + return os.WriteFile(screenshotFile, screenshot, 0644) +} diff --git a/pkg/engine/headless/crawler/normalizer/simhash/simhash.go b/pkg/engine/headless/crawler/normalizer/simhash/simhash.go new file mode 100644 index 00000000..ab4318e0 --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/simhash/simhash.go @@ -0,0 +1,198 @@ +// Package simhash implements SimHash algorithm for near-duplicate detection. +// +// The original algorithm is taken from: https://github.com/yahoo/gryffin/blob/master/html-distance/feature.go +// Optimized implementation with performance improvements. +// +// Original Copyright 2015, Yahoo Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package simhash + +import ( + "bytes" + "fmt" + "io" + "sync" + + "github.com/mfonda/simhash" + "golang.org/x/net/html" +) + +// Constants for optimization +const ( + maxTokens = 5000 + featuresBufSize = 1000 +) + +// Pre-allocated buffers for feature generation +var bufferPool = sync.Pool{ + New: func() interface{} { + return &bytes.Buffer{} + }, +} + +func fingerprintOptimized(r io.Reader, shingle int) uint64 { + if shingle < 1 { + shingle = 1 + } + + v := simhash.Vector{} + z := html.NewTokenizer(r) + + features := make([]string, 0, featuresBufSize) + window := make([][]byte, shingle) + windowIndex := 0 + + // Single-pass tokenization and feature extraction + count := 0 + for count < maxTokens { + if tt := z.Next(); tt == html.ErrorToken { + break + } + t := z.Token() + count++ + + extractFeatures(&t, &features) + } + + // Process features with shingling + buf := bufferPool.Get().(*bytes.Buffer) + defer func() { + buf.Reset() + bufferPool.Put(buf) + }() + + for _, f := range features { + window[windowIndex%shingle] = []byte(f) + windowIndex++ + + buf.Reset() + for i := 0; i < shingle; i++ { + if i > 0 { + buf.WriteByte(' ') + } + buf.Write(window[(windowIndex-shingle+i+shingle)%shingle]) + } + + sum := simhash.NewFeature(buf.Bytes()).Sum() + + for i := uint8(0); i < 64; i++ { + if (sum>>i)&1 == 1 { + v[i]++ + } else { + v[i]-- + } + } + } + + return simhash.Fingerprint(v) +} + +// extractFeatures extracts features from HTML token and appends to slice +func extractFeatures(t *html.Token, features *[]string) { + // Pre-allocate string builder for efficiency + var s string + + switch t.Type { + case html.StartTagToken: + s = "A:" + t.DataAtom.String() + case html.EndTagToken: + s = "B:" + t.DataAtom.String() + case html.SelfClosingTagToken: + s = "C:" + t.DataAtom.String() + case html.DoctypeToken: + s = "D:" + string(t.Data) + case html.CommentToken: + s = "E:" + string(t.Data) + case html.TextToken: + s = "F:" + string(t.Data) + case html.ErrorToken: + s = "Z:" + string(t.Data) + default: + return + } + + *features = append(*features, s) + + // Process attributes + for _, attr := range t.Attr { + switch attr.Key { + case "class", "name", "rel": + s = fmt.Sprintf("G:%s:%s:%s", t.DataAtom.String(), attr.Key, attr.Val) + default: + s = fmt.Sprintf("G:%s:%s", t.DataAtom.String(), attr.Key) + } + *features = append(*features, s) + } +} + +// Fingerprint is the original function signature for compatibility +func Fingerprint(r io.Reader, shingle int) uint64 { + return fingerprintOptimized(r, shingle) +} + +type Oracle struct { + fingerprint uint64 // node value. + nodes [65]*Oracle // leaf nodes +} + +// NewOracle return an oracle that could tell if the fingerprint has been seen or not. +func NewOracle() *Oracle { + return newNode(0) +} + +func newNode(f uint64) *Oracle { + return &Oracle{fingerprint: f} +} + +// Distance return the similarity distance between two fingerprint. +func Distance(a, b uint64) uint8 { + return simhash.Compare(a, b) +} + +// See asks the oracle to see the fingerprint. +func (n *Oracle) See(f uint64) *Oracle { + d := Distance(n.fingerprint, f) + + if d == 0 { + // current node with same fingerprint. + return n + } + + // the target node is already set, + if c := n.nodes[d]; c != nil { + return c.See(f) + } + + n.nodes[d] = newNode(f) + return n.nodes[d] +} + +// Seen asks the oracle if anything closed to the fingerprint in a range (r) is seen before. +func (n *Oracle) Seen(f uint64, r uint8) bool { + d := Distance(n.fingerprint, f) + if d <= r { + return true + } + + // Check the direct child at distance d first + if c := n.nodes[d]; c != nil && c.Seen(f, r) { + return true + } + + // Optimized search: start from closest distance and expand outward + for offset := uint8(1); offset <= r; offset++ { + // Check both directions + if d >= offset { + if c := n.nodes[d-offset]; c != nil && c.Seen(f, r) { + return true + } + } + if d+offset <= 64 { + if c := n.nodes[d+offset]; c != nil && c.Seen(f, r) { + return true + } + } + } + return false +} diff --git a/pkg/engine/headless/crawler/normalizer/simhash/simhash_test.go b/pkg/engine/headless/crawler/normalizer/simhash/simhash_test.go new file mode 100644 index 00000000..479fae9e --- /dev/null +++ b/pkg/engine/headless/crawler/normalizer/simhash/simhash_test.go @@ -0,0 +1,72 @@ +package simhash + +import ( + "strings" + "testing" +) + +var ( + htmlA = `<html><body><p>Hello World</p></body></html>` + // htmlB differs by an exclamation mark. This should keep the documents fairly similar + // while still resulting in a different SimHash fingerprint. + htmlB = `<html><body><p>Hello World!</p></body></html>` +) + +// TestFingerprintDeterministic ensures that hashing the same document twice produces +// identical fingerprints and that a shingle value of 0 gracefully falls back to 1. +func TestFingerprintDeterministic(t *testing.T) { + in1 := strings.NewReader(htmlA) + in2 := strings.NewReader(htmlA) + + fp1 := Fingerprint(in1, 0) + fp2 := Fingerprint(in2, 1) + + if fp1 != fp2 { + t.Fatalf("expected identical fingerprints, got %d and %d", fp1, fp2) + } +} + +// TestFingerprintSimilarity checks that two similar documents yield fingerprints with +// a small (non-zero) Hamming distance. +func TestFingerprintSimilarity(t *testing.T) { + fpA := Fingerprint(strings.NewReader(htmlA), 3) + fpB := Fingerprint(strings.NewReader(htmlB), 3) + + d := Distance(fpA, fpB) + if d == 0 { + t.Fatalf("expected different fingerprints, got distance 0") + } + + const maxReasonableDistance = 20 // out of a maximum of 64 + if d > maxReasonableDistance { + t.Fatalf("expected similar documents to have distance <= %d, got %d", maxReasonableDistance, d) + } +} + +// TestOracle validates the basic behaviour of the Oracle structure. +func TestOracle(t *testing.T) { + fpA := Fingerprint(strings.NewReader(htmlA), 3) + fpB := Fingerprint(strings.NewReader(htmlB), 3) + + o := NewOracle() + + if o.Seen(fpA, 0) { + t.Fatalf("oracle should not have seen fingerprint yet") + } + + // Teach the oracle about fpA. + o.See(fpA) + + if !o.Seen(fpA, 0) { + t.Fatalf("oracle should recognise an identical fingerprint once seen") + } + + if o.Seen(fpB, 0) { + t.Fatalf("oracle should not treat different fingerprint as identical when r=0") + } + + r := Distance(fpA, fpB) + if !o.Seen(fpB, r) { + t.Fatalf("oracle should recognise fingerprint within distance %d", r) + } +} diff --git a/pkg/engine/headless/crawler/state.go b/pkg/engine/headless/crawler/state.go index fca3bea6..3cd84e36 100644 --- a/pkg/engine/headless/crawler/state.go +++ b/pkg/engine/headless/crawler/state.go @@ -5,25 +5,50 @@ import ( "encoding/hex" "fmt" "log/slog" + "strings" graphlib "github.com/dominikbraun/graph" "github.com/pkg/errors" "github.com/projectdiscovery/katana/pkg/engine/headless/browser" "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/diagnostics" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/normalizer/simhash" "github.com/projectdiscovery/katana/pkg/engine/headless/types" ) var emptyPageHash = sha256Hash("") -func isCorrectNavigation(page *browser.BrowserPage, action *types.Action) (string, *types.PageState, error) { +const simhashThreshold = 2 // Allow up to 2 bits difference + +func (c *Crawler) isCorrectNavigation(page *browser.BrowserPage, action *types.Action) (string, *types.PageState, error) { currentPageHash, pageState, err := getPageHash(page) if err != nil { return "", nil, err } - if currentPageHash != action.OriginID { - return "", pageState, fmt.Errorf("failed to navigate back to origin page: %s != %s", currentPageHash, action.OriginID) + + if currentPageHash == action.OriginID { + return currentPageHash, pageState, nil + } + + // Get the origin page state to compare SimHash + originPageState, err := c.crawlGraph.GetPageState(action.OriginID) + if err != nil { + return "", pageState, fmt.Errorf("failed to get origin page state: %w", err) + } + + if pageState != nil && originPageState != nil { + distance := simhash.Distance(pageState.SimHash, originPageState.SimHash) + if distance <= simhashThreshold { + c.logger.Debug("Page is similar enough to origin, proceeding", + slog.String("current_hash", currentPageHash), + slog.String("origin_hash", action.OriginID), + slog.Uint64("simhash_distance", uint64(distance)), + ) + // Treat this page as the origin state to avoid creating a new vertex + return originPageState.UniqueID, pageState, nil + } } - return currentPageHash, pageState, nil + + return "", pageState, fmt.Errorf("failed to navigate back to origin page: %s != %s", currentPageHash, action.OriginID) } func getPageHash(page *browser.BrowserPage) (string, *types.PageState, error) { @@ -70,6 +95,8 @@ func newPageState(page *browser.BrowserPage, action *types.Action) (*types.PageS // Get sha256 hash of the stripped dom state.UniqueID = sha256Hash(strippedDOM) + state.SimHash = simhash.Fingerprint(strings.NewReader(strippedDOM), 3) + return state, nil } @@ -206,7 +233,7 @@ func (c *Crawler) tryBrowserHistoryNavigation(page *browser.BrowserPage, originP if err := page.WaitPageLoadHeurisitics(); err != nil { c.logger.Debug("Failed to wait for page load after navigating back using browser history", slog.String("error", err.Error())) } - newPageHash, pageState, err := isCorrectNavigation(page, action) + newPageHash, pageState, err := c.isCorrectNavigation(page, action) if c.diagnostics != nil && pageState != nil { if err := c.diagnostics.LogPageState(pageState, diagnostics.PreActionPageState); err != nil { return "", err @@ -261,7 +288,7 @@ func (c *Crawler) tryShortestPathNavigation(action *types.Action, page *browser. return "", err } } - newPageHash, pageState, err := isCorrectNavigation(page, action) + newPageHash, pageState, err := c.isCorrectNavigation(page, action) if c.diagnostics != nil && pageState != nil { if err := c.diagnostics.LogPageState(pageState, diagnostics.PreActionPageState); err != nil { return "", err diff --git a/pkg/engine/headless/crawler/state_test.go b/pkg/engine/headless/crawler/state_test.go index 27628c2e..e2737cbf 100644 --- a/pkg/engine/headless/crawler/state_test.go +++ b/pkg/engine/headless/crawler/state_test.go @@ -1,9 +1,11 @@ package crawler import ( + "strings" "testing" "github.com/pkg/errors" + "github.com/projectdiscovery/katana/pkg/engine/headless/crawler/normalizer/simhash" "github.com/stretchr/testify/assert" ) @@ -101,3 +103,71 @@ func TestPageFingerprint(t *testing.T) { }) } } + +func TestSimHashSimilarity(t *testing.T) { + tests := []struct { + name string + html1 string + html2 string + threshold uint8 + similar bool + }{ + { + name: "identical pages", + html1: `<html><body><h1>Hello World</h1><p>Content here</p></body></html>`, + html2: `<html><body><h1>Hello World</h1><p>Content here</p></body></html>`, + threshold: 4, + similar: true, + }, + { + name: "pages with minor changes", + html1: `<html><body><h1>Hello World</h1><p>Content here</p><span>Time: 12:00</span></body></html>`, + html2: `<html><body><h1>Hello World</h1><p>Content here</p><span>Time: 12:01</span></body></html>`, + threshold: 4, + similar: true, + }, + { + name: "pages with different content", + html1: `<html><body><h1>Hello World</h1><p>Content here</p></body></html>`, + html2: `<html><body><h1>Goodbye World</h1><p>Different content</p><div>Extra stuff</div></body></html>`, + threshold: 4, + similar: false, + }, + { + name: "pages with dynamic IDs", + html1: `<html><body><div id="content-12345"><h1>Hello</h1></div></body></html>`, + html2: `<html><body><div id="content-67890"><h1>Hello</h1></div></body></html>`, + threshold: 4, + similar: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Normalize and compute SimHash + norm1, err := domNormalizer.Apply(tt.html1) + if err != nil { + t.Fatalf("Failed to normalize html1: %v", err) + } + + norm2, err := domNormalizer.Apply(tt.html2) + if err != nil { + t.Fatalf("Failed to normalize html2: %v", err) + } + + hash1 := simhash.Fingerprint(strings.NewReader(norm1), 3) + hash2 := simhash.Fingerprint(strings.NewReader(norm2), 3) + + distance := simhash.Distance(hash1, hash2) + isSimilar := distance <= tt.threshold + + if isSimilar != tt.similar { + t.Errorf("Expected similar=%v, got similar=%v (distance=%d)", tt.similar, isSimilar, distance) + t.Logf("Hash1: %064b", hash1) + t.Logf("Hash2: %064b", hash2) + t.Logf("Normalized HTML1:\n%s", norm1) + t.Logf("Normalized HTML2:\n%s", norm2) + } + }) + } +} diff --git a/pkg/engine/headless/graph/graph.go b/pkg/engine/headless/graph/graph.go index e9f318fe..3e7f5609 100644 --- a/pkg/engine/headless/graph/graph.go +++ b/pkg/engine/headless/graph/graph.go @@ -76,7 +76,7 @@ func (g *CrawlGraph) AddPageState(n types.PageState) error { if errors.Is(err, graph.ErrEdgeAlreadyExists) { return nil } - return errors.Wrap(err, "could not add edge to graph") + return errors.Wrapf(err, "could not add edge to graph: source vertex %s", n.OriginID) } } return nil diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 7bba869d..e004e2a5 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -9,6 +9,7 @@ import ( "github.com/lmittmann/tint" "github.com/projectdiscovery/katana/pkg/engine/headless/browser" "github.com/projectdiscovery/katana/pkg/engine/headless/crawler" + "github.com/projectdiscovery/katana/pkg/engine/parser" "github.com/projectdiscovery/katana/pkg/output" "github.com/projectdiscovery/katana/pkg/types" mapsutil "github.com/projectdiscovery/utils/maps" @@ -91,10 +92,10 @@ func (h *Headless) Crawl(URL string) error { if !scopeValidator(rr.Request.URL) { return } - // navigationRequests := h.performJavascriptAnalysis(rr) - // for _, req := range navigationRequests { - // h.options.OutputWriter.Write(req) - // } + navigationRequests := h.performAdditionalAnalysis(rr) + for _, req := range navigationRequests { + h.options.OutputWriter.Write(req) + } rr.Response.Raw = "" rr.Response.Body = "" @@ -124,41 +125,19 @@ func (h *Headless) Close() error { return nil } -// // Integrate JS analysis and other stuff here only in request callback -// func (h *Headless) performJavascriptAnalysis(rr *output.Result) []*output.Result { -// parsedURL, err := url.Parse(rr.Request.URL) -// if err != nil { -// return nil -// } - -// contentType := rr.Response.Headers["Content-Type"] -// if !(strings.HasSuffix(parsedURL.Path, ".js") || strings.HasSuffix(parsedURL.Path, ".css") || strings.Contains(contentType, "/javascript")) { -// return nil -// } -// if utils.IsPathCommonJSLibraryFile(parsedURL.Path) { -// return nil -// } - -// endpointsItems := utils.ExtractJsluiceEndpoints(string(rr.Response.Body)) -// newResp := &navigation.Response{ -// Resp: &http.Response{ -// Request: &http.Request{ -// URL: parsedURL, -// }, -// }, -// } - -// navigationRequests := make([]*output.Result, 0) -// for _, item := range endpointsItems { -// resp := navigation.NewNavigationRequestURLFromResponse(item.Endpoint, rr.Request.URL, "js", fmt.Sprintf("jsluice-%s", item.Type), newResp) -// if _, ok := h.deduplicator.Get(resp.URL); ok { -// continue -// } -// h.deduplicator.Set(resp.URL, struct{}{}) - -// navigationRequests = append(navigationRequests, &output.Result{ -// Request: resp, -// }) -// } -// return navigationRequests -// } +func (h *Headless) performAdditionalAnalysis(rr *output.Result) []*output.Result { + newNavigations := parser.ParseResponse(rr.Response) + + navigationRequests := make([]*output.Result, 0) + for _, resp := range newNavigations { + if _, ok := h.deduplicator.Get(resp.URL); ok { + continue + } + h.deduplicator.Set(resp.URL, struct{}{}) + + navigationRequests = append(navigationRequests, &output.Result{ + Request: resp, + }) + } + return navigationRequests +} diff --git a/pkg/engine/headless/types/types.go b/pkg/engine/headless/types/types.go index dbbee426..45766b69 100644 --- a/pkg/engine/headless/types/types.go +++ b/pkg/engine/headless/types/types.go @@ -18,6 +18,7 @@ var ( // It represents the vertex of the crawl graph type PageState struct { UniqueID string `json:"unique_id,omitempty"` + SimHash uint64 `json:"sim_hash,omitempty"` OriginID string `json:"origin_id,omitempty"` URL string `json:"url,omitempty"` Title string `json:"title,omitempty"` From 1571d1edc8f0138a0a36ee4849ac0d35d15fe518 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Wed, 16 Jul 2025 02:17:31 +0530 Subject: [PATCH 11/22] feat: fixed panic + parser not working for katana headless --- pkg/engine/headless/browser/browser.go | 6 ++++++ pkg/utils/extensions/extensions.go | 1 + 2 files changed, 7 insertions(+) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 6f1b3fa3..049e7ba5 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -15,6 +15,7 @@ import ( "sync" "time" + "github.com/PuerkitoBio/goquery" "github.com/go-rod/rod" "github.com/go-rod/rod/lib/launcher" "github.com/go-rod/rod/lib/launcher/flags" @@ -388,6 +389,10 @@ func (b *BrowserPage) handlePageDialogBoxes() error { rawBytesResponse, _ := httputil.DumpResponse(httpresp, true) + doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body)) + if err != nil { + return + } resp := &navigation.Response{ Body: string(body), StatusCode: httpresp.StatusCode, @@ -395,6 +400,7 @@ func (b *BrowserPage) handlePageDialogBoxes() error { Raw: string(rawBytesResponse), ContentLength: httpresp.ContentLength, Resp: httpresp, + Reader: doc, } b.launcher.opts.RequestCallback(&output.Result{ Timestamp: time.Now(), diff --git a/pkg/utils/extensions/extensions.go b/pkg/utils/extensions/extensions.go index 87c61316..749c7ed7 100644 --- a/pkg/utils/extensions/extensions.go +++ b/pkg/utils/extensions/extensions.go @@ -42,6 +42,7 @@ func (e *Validator) ValidatePath(item string) bool { u, err := urlutil.Parse(item) if err != nil { gologger.Warning().Msgf("validatepath: failed to parse url %v got %v", item, err) + return false } if u.Path != "" { extension = strings.ToLower(path.Ext(u.Path)) From 3ace6f79c1b399cad6e57c78a0a8c1e228fbec72 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Wed, 16 Jul 2025 02:29:29 +0530 Subject: [PATCH 12/22] feat: handle singleton lock issue with multiple instances --- pkg/engine/headless/browser/browser.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 049e7ba5..c6646262 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -105,6 +105,7 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { chromeLauncher = chromeLauncher.Bin(l.opts.ChromiumPath) } + // Always create a temporary user data directory to avoid SingletonLock conflicts if l.opts.ChromeUser != nil { tempDir, err := os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") if err != nil { @@ -119,6 +120,14 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { } chromeLauncher = chromeLauncher.Set("user-data-dir", tempDir) l.userDataDir = tempDir + } else { + // Create a temporary user data directory even when ChromeUser is not specified + tempDir, err := os.MkdirTemp("", "katana-chrome-data-*") + if err != nil { + return nil, errors.Wrap(err, "could not create temporary chrome data directory") + } + chromeLauncher = chromeLauncher.Set("user-data-dir", tempDir) + l.userDataDir = tempDir } launcherURL, err := chromeLauncher.Launch() From af26d37c7f443ffdb81c39cf6fb013e157fb1dd5 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Thu, 17 Jul 2025 00:58:30 +0530 Subject: [PATCH 13/22] feat: fixed singleton error with multiple processes in linux --- pkg/engine/headless/browser/browser.go | 78 ++++++++++++++------------ 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index c6646262..5ea533c4 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -64,6 +64,7 @@ func NewLauncher(opts LauncherOptions) (*Launcher, error) { opts: opts, browserPool: rod.NewPool[BrowserPage](opts.MaxBrowsers), } + return l, nil } @@ -71,7 +72,7 @@ func (l *Launcher) ScopeValidator() ScopeValidator { return l.opts.ScopeValidator } -func (l *Launcher) launchBrowser() (*rod.Browser, error) { +func (l *Launcher) launchBrowserWithDataDir(userDataDir string) (*rod.Browser, error) { chromeLauncher := launcher.New(). Leakless(true). Set("disable-gpu", "true"). @@ -82,9 +83,8 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { Set("window-size", fmt.Sprintf("%d,%d", 1080, 1920)). Set("mute-audio", "true"). Set("incognito", "true"). - // Set("proxy-server", opts.Proxy). Delete("use-mock-keychain"). - Delete("disable-ipc-flooding-protection"). // somehow this causes loops + Delete("disable-ipc-flooding-protection"). Headless(true) for _, flag := range headlessFlags { @@ -105,29 +105,8 @@ func (l *Launcher) launchBrowser() (*rod.Browser, error) { chromeLauncher = chromeLauncher.Bin(l.opts.ChromiumPath) } - // Always create a temporary user data directory to avoid SingletonLock conflicts - if l.opts.ChromeUser != nil { - tempDir, err := os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") - if err != nil { - return nil, errors.Wrap(err, "could not create temporary chrome data directory") - } - uid, _ := strconv.Atoi(l.opts.ChromeUser.Uid) - gid, _ := strconv.Atoi(l.opts.ChromeUser.Gid) - - // Sets proper ownership of the Chrome data directory - if err := os.Chown(tempDir, uid, gid); err != nil { - return nil, errors.Wrap(err, "could not change ownership of chrome data directory") - } - chromeLauncher = chromeLauncher.Set("user-data-dir", tempDir) - l.userDataDir = tempDir - } else { - // Create a temporary user data directory even when ChromeUser is not specified - tempDir, err := os.MkdirTemp("", "katana-chrome-data-*") - if err != nil { - return nil, errors.Wrap(err, "could not create temporary chrome data directory") - } - chromeLauncher = chromeLauncher.Set("user-data-dir", tempDir) - l.userDataDir = tempDir + if userDataDir != "" { + chromeLauncher = chromeLauncher.UserDataDir(userDataDir) } launcherURL, err := chromeLauncher.Launch() @@ -157,16 +136,14 @@ func (l *Launcher) Close() { b.cancel() b.CloseBrowserPage() }) - if l.userDataDir != "" { - _ = os.RemoveAll(l.userDataDir) - } } // BrowserPage is a combination of a browser and a page type BrowserPage struct { *rod.Page - Browser *rod.Browser - cancel context.CancelFunc + Browser *rod.Browser + cancel context.CancelFunc + userDataDir string launcher *Launcher } @@ -274,12 +251,36 @@ func (p *BrowserPage) WaitNewStable(d time.Duration) error { } func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { - browser, err := l.launchBrowser() + // Create unique temp userDataDir for this browser instance + var tempDir string + if l.opts.ChromeUser != nil { + var err error + tempDir, err = os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") + if err != nil { + return nil, errors.Wrap(err, "could not create temporary chrome data directory") + } + uid, _ := strconv.Atoi(l.opts.ChromeUser.Uid) + gid, _ := strconv.Atoi(l.opts.ChromeUser.Gid) + if err := os.Chown(tempDir, uid, gid); err != nil { + return nil, errors.Wrap(err, "could not change ownership of chrome data directory") + } + } else { + var err error + tempDir, err = os.MkdirTemp("", "katana-chrome-data-*") + if err != nil { + return nil, errors.Wrap(err, "could not create temporary chrome data directory") + } + } + + browser, err := l.launchBrowserWithDataDir(tempDir) if err != nil { + _ = os.RemoveAll(tempDir) return nil, err } + page, err := browser.Page(proto.TargetCreateTarget{}) if err != nil { + _ = os.RemoveAll(tempDir) return nil, errors.Wrap(err, "could not create new page") } page = page.Sleeper(func() rodutils.Sleeper { @@ -292,10 +293,11 @@ func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { page = page.Context(cancelCtx) browserPage := &BrowserPage{ - Page: page, - Browser: browser, - launcher: l, - cancel: cancel, + Page: page, + Browser: browser, + launcher: l, + cancel: cancel, + userDataDir: tempDir, } browserPage.handlePageDialogBoxes() @@ -519,6 +521,10 @@ func isBrowserConnected(browser *rod.Browser) bool { func (b *BrowserPage) CloseBrowserPage() { b.Page.Close() b.Browser.Close() + // Clean up the temp user data directory + if b.userDataDir != "" { + _ = os.RemoveAll(b.userDataDir) + } } // taken from playwright From 37d55fe03684177370cbd512ca016cea95489de2 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Tue, 22 Jul 2025 19:54:09 +0530 Subject: [PATCH 14/22] pprof misc fix --- cmd/katana/main.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/katana/main.go b/cmd/katana/main.go index b1b7e5ea..5aee3ec6 100644 --- a/cmd/katana/main.go +++ b/cmd/katana/main.go @@ -46,6 +46,8 @@ func main() { } defer katanaRunner.Close() + // Check if env has profiling enabled + // close handler resumeFilename := defaultResumeFilename() go func() { @@ -70,9 +72,11 @@ func main() { pprofServer = pprofutils.NewPprofServer() pprofServer.Start() } - if pprofServer != nil { - defer pprofServer.Stop() - } + defer func() { + if pprofServer != nil { + defer pprofServer.Stop() + } + }() if err := katanaRunner.ExecuteCrawling(); err != nil { gologger.Fatal().Msgf("could not execute crawling: %s", err) From c888a6a9a8ee6d2a324001e6540f8bedb8d7ddf3 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Wed, 23 Jul 2025 21:43:22 +0530 Subject: [PATCH 15/22] feat: added timeout + fixing stuck on large lists --- pkg/engine/headless/browser/browser.go | 26 +++++++++++++++++++----- pkg/engine/headless/crawler/crawler.go | 28 ++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 5ea533c4..0d1ca669 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -233,18 +233,25 @@ func (b *BrowserPage) WaitPageLoadHeuristicsFallback() error { // WaitStable waits until the page is stable for d duration. func (p *BrowserPage) WaitNewStable(d time.Duration) error { - var err error + // Enforce an upper-bound on how long we will wait for the page to become + // stable. We simply reuse the heuristic window (d) and give the combined + // operation 2× that duration. This guarantees that callers will be + // released after a finite time instead of blocking forever when a page + // keeps a long-lived connection open (analytics beacons, WebSockets, etc.). + + chained := p.Timeout(2 * d) + var err error setErr := sync.Once{} rodutils.All(func() { - e := p.WaitLoad() + e := chained.WaitLoad() setErr.Do(func() { err = e }) }, func() { - p.WaitRequestIdle(d, nil, []string{}, nil)() + chained.WaitRequestIdle(d, nil, []string{}, nil)() }, func() { - // e := p.WaitDOMStable(d, 0) - //setErr.Do(func() { err = e }) + e := chained.WaitDOMStable(d, 0) + setErr.Do(func() { err = e }) })() return err @@ -319,6 +326,8 @@ func (l *Launcher) GetPageFromPool() (*BrowserPage, error) { if err != nil { return nil, err } + // TODO: should we check if the browser is alive because sometimes it + // might die? return browserPage, nil } @@ -483,6 +492,13 @@ func netHTTPResponseFromProto(e *proto.FetchRequestPaused, body []byte) *http.Re } func (l *Launcher) PutBrowserToPool(browser *BrowserPage) { + // Discard pages that hit a deadline or were cancelled to avoid immediately + // returning a poisoned page that will fail every subsequent call. + if cerr := browser.Page.GetContext().Err(); cerr != nil { + browser.cancel() + browser.CloseBrowserPage() + return + } // If the browser is not connected, close it if !isBrowserConnected(browser.Browser) { browser.cancel() diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index cde68c24..13dce641 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -1,6 +1,7 @@ package crawler import ( + "context" "fmt" "log/slog" "os" @@ -161,6 +162,21 @@ func (c *Crawler) Crawl(URL string) error { return err } + // Create a master context that will automatically cancel all page operations + // once the per-URL crawl deadline is reached. + var ( + ctx context.Context + cancel context.CancelFunc + ) + if c.options.MaxCrawlDuration > 0 { + ctx, cancel = context.WithTimeout(context.Background(), c.options.MaxCrawlDuration) + } else { + ctx, cancel = context.WithCancel(context.Background()) + } + defer cancel() + + // Retain the legacy time.After guard as a secondary fail-safe but the + // context cancellation is what actually stops in-flight rod calls. var crawlTimeout <-chan time.Time if c.options.MaxCrawlDuration > 0 { crawlTimeout = time.After(c.options.MaxCrawlDuration) @@ -200,6 +216,10 @@ func (c *Crawler) Crawl(URL string) error { return err } + // Tie this BrowserPage to the master context so any rod call will + // respect the crawl deadline. + page.Page = page.Page.Context(ctx) + c.logger.Debug("Processing action", slog.String("action", action.String()), ) @@ -367,7 +387,10 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br var err error switch action.Type { case types.ActionTypeLoadURL: - if err := page.Navigate(action.Input); err != nil { + // Apply a timeout to every critical Rod call. + pTimeout := page.Timeout(c.options.PageMaxTimeout) + + if err := pTimeout.Navigate(action.Input); err != nil { return err } if err = page.WaitPageLoadHeurisitics(); err != nil { @@ -378,7 +401,8 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br return err } case types.ActionTypeLeftClick, types.ActionTypeLeftClickDown: - element, err := page.ElementX(action.Element.XPath) + pTimeout := page.Timeout(c.options.PageMaxTimeout) + element, err := pTimeout.ElementX(action.Element.XPath) if err != nil { return err } From 0bb25cac65c2ced8bb490e7e585d6cd0884e7f5a Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Sun, 27 Jul 2025 21:22:42 +0530 Subject: [PATCH 16/22] misc additions + debug --- pkg/engine/headless/crawler/crawler.go | 4 +- pkg/engine/headless/debugger.go | 125 +++++++++++++++++++++++++ pkg/engine/headless/headless.go | 32 ++++++- pkg/engine/parser/parser.go | 28 +++++- pkg/engine/parser/parser_test.go | 41 ++++++++ 5 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 pkg/engine/headless/debugger.go diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 13dce641..58cbc1f7 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -406,7 +406,9 @@ func (c *Crawler) executeCrawlStateAction(action *types.Action, page *browser.Br if err != nil { return err } - if err := element.ScrollIntoView(); err != nil { + + elementTimeout := element.Timeout(c.options.PageMaxTimeout) + if err := elementTimeout.ScrollIntoView(); err != nil { return err } visible, err := element.Visible() diff --git a/pkg/engine/headless/debugger.go b/pkg/engine/headless/debugger.go new file mode 100644 index 00000000..1108d34a --- /dev/null +++ b/pkg/engine/headless/debugger.go @@ -0,0 +1,125 @@ +package headless + +import ( + "encoding/json" + "fmt" + "net/http" + "sync" + "time" +) + +// ActiveURL represents a URL currently being processed +type ActiveURL struct { + URL string `json:"url"` + StartTime time.Time `json:"start_time"` + Duration string `json:"duration"` + Depth int `json:"depth"` +} + +// CrawlDebugger tracks active URLs for debugging +type CrawlDebugger struct { + mu sync.RWMutex + activeURLs map[string]*ActiveURL + httpServer *http.Server + enableHTTP bool +} + +// NewCrawlDebugger creates a new debugger instance +func NewCrawlDebugger(httpPort int) *CrawlDebugger { + cd := &CrawlDebugger{ + activeURLs: make(map[string]*ActiveURL), + } + + if cd.enableHTTP { + mux := http.NewServeMux() + mux.HandleFunc("/debug/active-urls", cd.handleActiveURLs) + mux.HandleFunc("/debug/health", cd.handleHealth) + + cd.httpServer = &http.Server{ + Addr: fmt.Sprintf(":%d", httpPort), + Handler: mux, + } + + go func() { + if err := cd.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + fmt.Printf("Debug HTTP server error: %v\n", err) + } + }() + } + + return cd +} + +// StartURL marks a URL as being processed +func (cd *CrawlDebugger) StartURL(url string, depth int) { + if cd == nil { + return + } + + cd.mu.Lock() + cd.activeURLs[url] = &ActiveURL{ + URL: url, + StartTime: time.Now(), + Depth: depth, + } + cd.mu.Unlock() +} + +// EndURL marks a URL as finished processing +func (cd *CrawlDebugger) EndURL(url string) { + if cd == nil { + return + } + + cd.mu.Lock() + delete(cd.activeURLs, url) + cd.mu.Unlock() +} + +// GetActiveURLs returns currently active URLs with durations +func (cd *CrawlDebugger) GetActiveURLs() []ActiveURL { + if cd == nil { + return nil + } + + cd.mu.RLock() + defer cd.mu.RUnlock() + + urls := make([]ActiveURL, 0, len(cd.activeURLs)) + now := time.Now() + for _, au := range cd.activeURLs { + copy := *au + copy.Duration = now.Sub(au.StartTime).String() + urls = append(urls, copy) + } + return urls +} + +// HTTP handlers +func (cd *CrawlDebugger) handleActiveURLs(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]interface{}{ + "timestamp": time.Now().Format(time.RFC3339), + "active_urls": cd.GetActiveURLs(), + "count": len(cd.GetActiveURLs()), + }) +} + +func (cd *CrawlDebugger) handleHealth(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]interface{}{ + "status": "ok", + "timestamp": time.Now().Format(time.RFC3339), + }) +} + +// Close shuts down the debugger +func (cd *CrawlDebugger) Close() { + if cd == nil { + return + } + + if cd.httpServer != nil { + cd.httpServer.Close() + } +} diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index e004e2a5..cd91b807 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -12,6 +12,7 @@ import ( "github.com/projectdiscovery/katana/pkg/engine/parser" "github.com/projectdiscovery/katana/pkg/output" "github.com/projectdiscovery/katana/pkg/types" + "github.com/projectdiscovery/katana/pkg/utils" mapsutil "github.com/projectdiscovery/utils/maps" ) @@ -20,18 +21,27 @@ type Headless struct { options *types.CrawlerOptions deduplicator *mapsutil.SyncLockMap[string, struct{}] + + debugger *CrawlDebugger } // New returns a new headless crawler instance func New(options *types.CrawlerOptions) (*Headless, error) { logger := newLogger(options) - return &Headless{ + headless := &Headless{ logger: logger, options: options, deduplicator: mapsutil.NewSyncLockMap[string, struct{}](), - }, nil + } + + // Show crawl debugger if verbose is enabled + if options.Options.Verbose { + headless.debugger = NewCrawlDebugger(8089) + } + + return headless, nil } func newLogger(options *types.CrawlerOptions) *slog.Logger { @@ -77,8 +87,19 @@ func validateScopeFunc(h *Headless, URL string) browser.ScopeValidator { // Crawl executes the headless crawling on a given URL func (h *Headless) Crawl(URL string) error { + if h.debugger != nil { + h.debugger.StartURL(URL, 0) + } + defer func() { + if h.debugger != nil { + h.debugger.EndURL(URL) + } + }() + scopeValidator := validateScopeFunc(h, URL) + blcChecker := utils.NewBrokenLinkChecker() + crawlOpts := crawler.Options{ ChromiumPath: h.options.Options.SystemChromePath, MaxDepth: h.options.Options.MaxDepth, @@ -92,7 +113,7 @@ func (h *Headless) Crawl(URL string) error { if !scopeValidator(rr.Request.URL) { return } - navigationRequests := h.performAdditionalAnalysis(rr) + navigationRequests := h.performAdditionalAnalysis(rr, blcChecker) for _, req := range navigationRequests { h.options.OutputWriter.Write(req) } @@ -122,10 +143,13 @@ func (h *Headless) Crawl(URL string) error { } func (h *Headless) Close() error { + if h.debugger != nil { + h.debugger.Close() + } return nil } -func (h *Headless) performAdditionalAnalysis(rr *output.Result) []*output.Result { +func (h *Headless) performAdditionalAnalysis(rr *output.Result, blcChecker *utils.BrokenLinkChecker) []*output.Result { newNavigations := parser.ParseResponse(rr.Response) navigationRequests := make([]*output.Result, 0) diff --git a/pkg/engine/parser/parser.go b/pkg/engine/parser/parser.go index cb2fd378..964b5e47 100644 --- a/pkg/engine/parser/parser.go +++ b/pkg/engine/parser/parser.go @@ -75,16 +75,38 @@ func ParseResponse(resp *navigation.Response) (navigationRequests []*navigation. for _, parser := range responseParsers { switch { case parser.parserType == headerParser && resp.Resp != nil: - navigationRequests = append(navigationRequests, parser.parserFunc(resp)...) + navigationRequests = appendFiltered(navigationRequests, parser.parserFunc(resp)) case parser.parserType == bodyParser && resp.Reader != nil: - navigationRequests = append(navigationRequests, parser.parserFunc(resp)...) + navigationRequests = appendFiltered(navigationRequests, parser.parserFunc(resp)) case parser.parserType == contentParser && len(resp.Body) > 0: - navigationRequests = append(navigationRequests, parser.parserFunc(resp)...) + navigationRequests = appendFiltered(navigationRequests, parser.parserFunc(resp)) } } return } +// appendFiltered filters navigation requests and appends valid ones to the slice +func appendFiltered(existing []*navigation.Request, new []*navigation.Request) []*navigation.Request { + for _, req := range new { + if isValidNavigationRequest(req) { + existing = append(existing, req) + } + } + return existing +} + +func isValidNavigationRequest(req *navigation.Request) bool { + if req == nil || req.URL == "" { + return false + } + + // Direct checks - fastest for small number of schemes + url := req.URL + return !(strings.HasPrefix(url, "data:") || + strings.HasPrefix(url, "mailto:") || + strings.HasPrefix(url, "javascript:")) +} + // ------------------------------------------------------------------------- // Begin Header based parsers // ------------------------------------------------------------------------- diff --git a/pkg/engine/parser/parser_test.go b/pkg/engine/parser/parser_test.go index a381c875..d733c3d2 100644 --- a/pkg/engine/parser/parser_test.go +++ b/pkg/engine/parser/parser_test.go @@ -523,3 +523,44 @@ func TestHtmxBodyParser(t *testing.T) { require.Equal(t, "PATCH", navigationRequests[0].Method, "could not get correct method") }) } + +func TestDataURIFiltering(t *testing.T) { + parsed, _ := urlutil.Parse("https://example.com/test") + + t.Run("data-uri-filtering", func(t *testing.T) { + // Test various HTML elements with data URIs to ensure they're filtered out by ParseResponse + htmlContent := ` + <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="> + <a href="data:text/html,<h1>Hello</h1>">Data Link</a> + <link href="data:text/css,body{color:red}"> + <script src="data:application/javascript,console.log('test')"></script> + <iframe src="data:text/html,<p>Test</p>"></iframe> + <object data="data:application/pdf,test"></object> + <embed src="data:application/x-shockwave-flash,test"> + <audio src="data:audio/mp3,test"></audio> + <video src="data:video/mp4,test"></video> + <a href="mailto:test@example.com">Email Link</a> + <a href="javascript:alert('test')">JS Link</a> + ` + + documentReader, _ := goquery.NewDocumentFromReader(strings.NewReader(htmlContent)) + resp := &navigation.Response{ + Resp: &http.Response{Request: &http.Request{URL: parsed.URL}}, + Reader: documentReader, + } + + // Test the main ParseResponse function to ensure all invalid URIs are filtered out + navigationRequests := ParseResponse(resp) + for _, req := range navigationRequests { + require.False(t, strings.HasPrefix(req.URL, "data:"), + "Found data URI in ParseResponse results: %s", req.URL) + require.False(t, strings.HasPrefix(req.URL, "mailto:"), + "Found mailto URI in ParseResponse results: %s", req.URL) + require.False(t, strings.HasPrefix(req.URL, "javascript:"), + "Found javascript URI in ParseResponse results: %s", req.URL) + } + + // Ensure we have 0 requests since all should be filtered + require.Equal(t, 0, len(navigationRequests), "Expected all invalid URIs to be filtered out") + }) +} From 3d19d3186fafb7a781e81467c0e280a9d37c26b8 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Sun, 27 Jul 2025 21:59:20 +0530 Subject: [PATCH 17/22] misc --- pkg/engine/headless/debugger.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/pkg/engine/headless/debugger.go b/pkg/engine/headless/debugger.go index 1108d34a..8fd60229 100644 --- a/pkg/engine/headless/debugger.go +++ b/pkg/engine/headless/debugger.go @@ -21,7 +21,6 @@ type CrawlDebugger struct { mu sync.RWMutex activeURLs map[string]*ActiveURL httpServer *http.Server - enableHTTP bool } // NewCrawlDebugger creates a new debugger instance @@ -30,23 +29,21 @@ func NewCrawlDebugger(httpPort int) *CrawlDebugger { activeURLs: make(map[string]*ActiveURL), } - if cd.enableHTTP { - mux := http.NewServeMux() - mux.HandleFunc("/debug/active-urls", cd.handleActiveURLs) - mux.HandleFunc("/debug/health", cd.handleHealth) + mux := http.NewServeMux() + mux.HandleFunc("/debug/active-urls", cd.handleActiveURLs) + mux.HandleFunc("/debug/health", cd.handleHealth) - cd.httpServer = &http.Server{ - Addr: fmt.Sprintf(":%d", httpPort), - Handler: mux, - } - - go func() { - if err := cd.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { - fmt.Printf("Debug HTTP server error: %v\n", err) - } - }() + cd.httpServer = &http.Server{ + Addr: fmt.Sprintf(":%d", httpPort), + Handler: mux, } + go func() { + if err := cd.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { + fmt.Printf("Debug HTTP server error: %v\n", err) + } + }() + return cd } From 8bf4a348cf8e28615df6a734f6213c24a8f4579b Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Sun, 27 Jul 2025 22:08:51 +0530 Subject: [PATCH 18/22] misc --- pkg/engine/headless/headless.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index cd91b807..e3b8e3b3 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -12,7 +12,6 @@ import ( "github.com/projectdiscovery/katana/pkg/engine/parser" "github.com/projectdiscovery/katana/pkg/output" "github.com/projectdiscovery/katana/pkg/types" - "github.com/projectdiscovery/katana/pkg/utils" mapsutil "github.com/projectdiscovery/utils/maps" ) @@ -98,8 +97,6 @@ func (h *Headless) Crawl(URL string) error { scopeValidator := validateScopeFunc(h, URL) - blcChecker := utils.NewBrokenLinkChecker() - crawlOpts := crawler.Options{ ChromiumPath: h.options.Options.SystemChromePath, MaxDepth: h.options.Options.MaxDepth, @@ -149,7 +146,7 @@ func (h *Headless) Close() error { return nil } -func (h *Headless) performAdditionalAnalysis(rr *output.Result, blcChecker *utils.BrokenLinkChecker) []*output.Result { +func (h *Headless) performAdditionalAnalysis(rr *output.Result) []*output.Result { newNavigations := parser.ParseResponse(rr.Response) navigationRequests := make([]*output.Result, 0) From 348eba03c6ffd5b9261dd46ca45f516f5796aed2 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Sun, 27 Jul 2025 23:13:54 +0530 Subject: [PATCH 19/22] misc --- go.mod | 41 ++++++++++------ go.sum | 84 +++++++++++++++++++++------------ pkg/engine/headless/headless.go | 2 +- 3 files changed, 80 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index 6fc61f1f..a8e09ee9 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/projectdiscovery/katana -go 1.21 +go 1.24 + +toolchain go1.24.2 require ( github.com/BishopFox/jsluice v0.0.0-20240110145140-0ddfab153e06 @@ -8,10 +10,12 @@ require ( github.com/adrianbrad/queue v1.3.0 github.com/dominikbraun/graph v0.23.0 github.com/go-rod/rod v0.116.2 + github.com/imroc/req/v3 v3.54.0 github.com/json-iterator/go v1.1.12 github.com/lmittmann/tint v1.0.6 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/lukasbob/srcset v0.0.0-20190730101422-86b742e617f3 + github.com/mfonda/simhash v0.0.0-20151007195837-79f94a1100d6 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 github.com/projectdiscovery/dsl v0.3.6 @@ -28,7 +32,7 @@ require ( github.com/rs/xid v1.5.0 github.com/stretchr/testify v1.10.0 go.uber.org/multierr v1.11.0 - golang.org/x/net v0.31.0 + golang.org/x/net v0.41.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -39,14 +43,14 @@ require ( github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect - github.com/andybalholm/brotli v1.0.6 // indirect + github.com/andybalholm/brotli v1.2.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/charmbracelet/glamour v0.8.0 // indirect github.com/charmbracelet/lipgloss v0.13.0 // indirect github.com/charmbracelet/x/ansi v0.3.2 // indirect github.com/cheggaaa/pb/v3 v3.1.4 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/cloudflare/circl v1.6.1 // indirect github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c // indirect github.com/dlclark/regexp2 v1.11.4 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -56,13 +60,16 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-github/v30 v30.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect + github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.1 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hdm/jarm-go v0.0.7 // indirect + github.com/icholy/digest v1.1.0 // indirect github.com/kataras/jwt v0.1.8 // indirect - github.com/klauspost/compress v1.17.4 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -73,12 +80,15 @@ require ( github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect + github.com/onsi/gomega v1.36.3 // indirect github.com/pierrec/lz4/v4 v4.1.2 // indirect github.com/projectdiscovery/asnmap v1.1.1 // indirect github.com/projectdiscovery/blackrock v0.0.1 // indirect github.com/projectdiscovery/gostruct v0.0.2 // indirect github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect - github.com/refraction-networking/utls v1.6.7 // indirect + github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/quic-go v0.53.0 // indirect + github.com/refraction-networking/utls v1.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/sashabaranov/go-openai v1.14.2 // indirect @@ -99,12 +109,13 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect github.com/zcalusic/sysinfo v1.0.2 // indirect + go.uber.org/mock v0.5.2 // indirect golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/term v0.26.0 // indirect + golang.org/x/sync v0.15.0 // indirect + golang.org/x/term v0.32.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect ) require ( @@ -144,12 +155,12 @@ require ( github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect go.etcd.io/bbolt v1.3.7 // indirect - golang.org/x/crypto v0.29.0 // indirect + golang.org/x/crypto v0.39.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/text v0.20.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/mod v0.25.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + golang.org/x/tools v0.34.0 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index cd15c50b..0c49f648 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,8 @@ github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4E github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= -github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= @@ -60,8 +60,8 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -114,8 +114,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA= @@ -123,14 +123,20 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q= github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4= +github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= @@ -141,6 +147,10 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4= +github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= +github.com/imroc/req/v3 v3.54.0 h1:kwWJSpT7OvjJ/Q8ykp+69Ye5H486RKDcgEoepw1Ren4= +github.com/imroc/req/v3 v3.54.0/go.mod h1:P8gCJjG/XNUFeP6WOi40VAXfYwT+uPM00xvoBWiwzUQ= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -150,8 +160,8 @@ github.com/kataras/jwt v0.1.8 h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk= github.com/kataras/jwt v0.1.8/go.mod h1:Q5j2IkcIHnfwy+oNY3TVWuEBJNw0ADgCcXK9CaZwV4o= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= @@ -183,6 +193,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mfonda/simhash v0.0.0-20151007195837-79f94a1100d6 h1:bjfMeqxWEJ6IRUvGkiTkSwx0a6UdQJsbirRSoXogteY= +github.com/mfonda/simhash v0.0.0-20151007195837-79f94a1100d6/go.mod h1:WVJJvUw/pIOcwu2O8ZzHEhmigq2jzwRNfJVRMJB7bR8= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= @@ -215,8 +227,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= +github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM= @@ -260,8 +272,12 @@ github.com/projectdiscovery/utils v0.4.1 h1:DRAqVMuLuo5NJChzXVdSqsKfAY3eFf9N1NX3 github.com/projectdiscovery/utils v0.4.1/go.mod h1:tV//VyD+4qZYn3s3XCS7xDbhW20qjUjV6CWDDHE2VfQ= github.com/projectdiscovery/wappalyzergo v0.2.5 h1:DhPEgeD+9i6yg+aGlbkT4iOAspQfB5ZzrmpEhwoiMlA= github.com/projectdiscovery/wappalyzergo v0.2.5/go.mod h1:fXiqsyLHaX/ovBNUe/nX0318bWON6SHftLvgq1xaOq0= -github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= -github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI= +github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= +github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo= +github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -343,6 +359,8 @@ github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxB github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= @@ -382,6 +400,8 @@ github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21 github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -397,15 +417,15 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -423,8 +443,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= @@ -434,8 +454,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -464,16 +484,16 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -483,8 +503,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= -golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -492,8 +512,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -504,8 +524,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -522,3 +542,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index e3b8e3b3..8b177a39 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -110,7 +110,7 @@ func (h *Headless) Crawl(URL string) error { if !scopeValidator(rr.Request.URL) { return } - navigationRequests := h.performAdditionalAnalysis(rr, blcChecker) + navigationRequests := h.performAdditionalAnalysis(rr) for _, req := range navigationRequests { h.options.OutputWriter.Write(req) } From 665d973376782e7d78525968468c1e2fd8198927 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Thu, 25 Sep 2025 17:31:31 +0530 Subject: [PATCH 20/22] feat: addressed review comments + better form fill + misc --- go.mod | 8 +- go.sum | 17 -- internal/runner/options.go | 11 +- pkg/engine/headless/browser/browser.go | 36 ++- pkg/engine/headless/browser/cookie/cookie.go | 5 + pkg/engine/headless/browser/element.go | 57 +++-- pkg/engine/headless/crawler/crawler.go | 65 +---- .../crawler/diagnostics/diagnostics.go | 2 +- pkg/engine/headless/crawler/formfill.go | 240 ++++++++++++++++++ .../headless/crawler/normalizer/normalizer.go | 2 +- pkg/engine/headless/graph/graph.go | 7 +- pkg/engine/headless/headless.go | 19 +- pkg/engine/headless/js/utils.js | 17 +- pkg/engine/headless/types/types.go | 9 +- pkg/engine/parser/parser.go | 16 +- 15 files changed, 373 insertions(+), 138 deletions(-) create mode 100644 pkg/engine/headless/crawler/formfill.go diff --git a/go.mod b/go.mod index a8e09ee9..fcb6bc67 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,6 @@ require ( github.com/adrianbrad/queue v1.3.0 github.com/dominikbraun/graph v0.23.0 github.com/go-rod/rod v0.116.2 - github.com/imroc/req/v3 v3.54.0 github.com/json-iterator/go v1.1.12 github.com/lmittmann/tint v1.0.6 github.com/logrusorgru/aurora v2.0.3+incompatible @@ -58,16 +57,14 @@ require ( github.com/felixge/fgprof v0.9.5 // indirect github.com/gaissmai/bart v0.9.5 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-github/v30 v30.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.3.1 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hdm/jarm-go v0.0.7 // indirect - github.com/icholy/digest v1.1.0 // indirect github.com/kataras/jwt v0.1.8 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/pgzip v1.2.5 // indirect @@ -86,8 +83,6 @@ require ( github.com/projectdiscovery/blackrock v0.0.1 // indirect github.com/projectdiscovery/gostruct v0.0.2 // indirect github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect - github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.53.0 // indirect github.com/refraction-networking/utls v1.7.3 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect @@ -109,7 +104,6 @@ require ( github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect github.com/zcalusic/sysinfo v1.0.2 // indirect - go.uber.org/mock v0.5.2 // indirect golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sync v0.15.0 // indirect golang.org/x/term v0.32.0 // indirect diff --git a/go.sum b/go.sum index 0c49f648..6bf93c87 100644 --- a/go.sum +++ b/go.sum @@ -132,11 +132,6 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM= @@ -147,10 +142,6 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4= -github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= -github.com/imroc/req/v3 v3.54.0 h1:kwWJSpT7OvjJ/Q8ykp+69Ye5H486RKDcgEoepw1Ren4= -github.com/imroc/req/v3 v3.54.0/go.mod h1:P8gCJjG/XNUFeP6WOi40VAXfYwT+uPM00xvoBWiwzUQ= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -272,10 +263,6 @@ github.com/projectdiscovery/utils v0.4.1 h1:DRAqVMuLuo5NJChzXVdSqsKfAY3eFf9N1NX3 github.com/projectdiscovery/utils v0.4.1/go.mod h1:tV//VyD+4qZYn3s3XCS7xDbhW20qjUjV6CWDDHE2VfQ= github.com/projectdiscovery/wappalyzergo v0.2.5 h1:DhPEgeD+9i6yg+aGlbkT4iOAspQfB5ZzrmpEhwoiMlA= github.com/projectdiscovery/wappalyzergo v0.2.5/go.mod h1:fXiqsyLHaX/ovBNUe/nX0318bWON6SHftLvgq1xaOq0= -github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= -github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI= -github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY= github.com/refraction-networking/utls v1.7.3 h1:L0WRhHY7Oq1T0zkdzVZMR6zWZv+sXbHB9zcuvsAEqCo= github.com/refraction-networking/utls v1.7.3/go.mod h1:TUhh27RHMGtQvjQq+RyO11P6ZNQNBb3N0v7wsEjKAIQ= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= @@ -400,8 +387,6 @@ github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21 github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -542,5 +527,3 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/internal/runner/options.go b/internal/runner/options.go index fc73becb..47de8ef4 100644 --- a/internal/runner/options.go +++ b/internal/runner/options.go @@ -27,13 +27,18 @@ func validateOptions(options *types.Options) error { // Disabling automatic form fill (-aff) for headless navigation due to incorrect implementation. // Form filling should be handled via headless actions within the page context - if options.Headless && options.AutomaticFormFill { + if options.HeadlessHybrid && options.AutomaticFormFill { options.AutomaticFormFill = false gologger.Info().Msgf("Automatic form fill (-aff) has been disabled for headless navigation.") } - if (options.HeadlessOptionalArguments != nil || options.HeadlessNoSandbox || options.SystemChromePath != "") && !options.Headless && !options.HeadlessHybrid { - return errorutil.New("headless mode (-hl) is required if -ho, -nos or -scp are set") + // Disallow ambiguous engine selection + if options.Headless && options.HeadlessHybrid { + return errorutil.New("flags -hl (headless) and -hh (hybrid) are mutually exclusive") + } + if (options.HeadlessOptionalArguments != nil || options.HeadlessNoSandbox || options.SystemChromePath != "") && + !options.Headless && !options.HeadlessHybrid { + return errorutil.New("headless (-hl) or hybrid (-hh) mode is required if -ho, -nos or -scp are set") } if options.SystemChromePath != "" { if !fileutil.FileExists(options.SystemChromePath) { diff --git a/pkg/engine/headless/browser/browser.go b/pkg/engine/headless/browser/browser.go index 0d1ca669..3720006d 100644 --- a/pkg/engine/headless/browser/browser.go +++ b/pkg/engine/headless/browser/browser.go @@ -6,6 +6,7 @@ import ( "encoding/base64" "fmt" "io" + "log/slog" "net/http" "net/http/httputil" "os" @@ -46,6 +47,7 @@ type LauncherOptions struct { MaxBrowsers int PageMaxTimeout time.Duration ShowBrowser bool + NoSandbox bool Proxy string SlowMotion bool Trace bool @@ -97,6 +99,10 @@ func (l *Launcher) launchBrowserWithDataDir(userDataDir string) (*rod.Browser, e } } + if l.opts.NoSandbox { + chromeLauncher = chromeLauncher.NoSandbox(true) + } + if l.opts.ShowBrowser { chromeLauncher = chromeLauncher.Headless(false) } @@ -136,6 +142,7 @@ func (l *Launcher) Close() { b.cancel() b.CloseBrowserPage() }) + close(l.browserPool) } // BrowserPage is a combination of a browser and a page @@ -260,14 +267,30 @@ func (p *BrowserPage) WaitNewStable(d time.Duration) error { func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { // Create unique temp userDataDir for this browser instance var tempDir string + shouldCleanup := true + + // Deferred cleanup function that will be set after tempDir creation + defer func() { + if shouldCleanup && tempDir != "" { + _ = os.RemoveAll(tempDir) + } + }() + if l.opts.ChromeUser != nil { var err error tempDir, err = os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*") if err != nil { return nil, errors.Wrap(err, "could not create temporary chrome data directory") } - uid, _ := strconv.Atoi(l.opts.ChromeUser.Uid) - gid, _ := strconv.Atoi(l.opts.ChromeUser.Gid) + + uid, err := strconv.Atoi(l.opts.ChromeUser.Uid) + if err != nil { + return nil, errors.Wrap(err, "invalid user ID") + } + gid, err := strconv.Atoi(l.opts.ChromeUser.Gid) + if err != nil { + return nil, errors.Wrap(err, "invalid group ID") + } if err := os.Chown(tempDir, uid, gid); err != nil { return nil, errors.Wrap(err, "could not change ownership of chrome data directory") } @@ -281,13 +304,11 @@ func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { browser, err := l.launchBrowserWithDataDir(tempDir) if err != nil { - _ = os.RemoveAll(tempDir) return nil, err } page, err := browser.Page(proto.TargetCreateTarget{}) if err != nil { - _ = os.RemoveAll(tempDir) return nil, errors.Wrap(err, "could not create new page") } page = page.Sleeper(func() rodutils.Sleeper { @@ -317,6 +338,9 @@ func (l *Launcher) createBrowserPageFunc() (*BrowserPage, error) { if err != nil { return nil, errors.Wrap(err, "could not initialize javascript env") } + + // Success - cancel the deferred cleanup + shouldCleanup = false return browserPage, nil } @@ -385,6 +409,8 @@ func (b *BrowserPage) handlePageDialogBoxes() error { } body, err := fetchGetResponseBody(b.Page, e) if err != nil { + // Continue the request even if we can't get the body + _ = fetchContinueRequest(b.Page, e) return } _ = fetchContinueRequest(b.Page, e) @@ -411,7 +437,7 @@ func (b *BrowserPage) handlePageDialogBoxes() error { doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body)) if err != nil { - return + slog.Warn("could not parse response body", "error", err) } resp := &navigation.Response{ Body: string(body), diff --git a/pkg/engine/headless/browser/cookie/cookie.go b/pkg/engine/headless/browser/cookie/cookie.go index ae15882e..4947883e 100644 --- a/pkg/engine/headless/browser/cookie/cookie.go +++ b/pkg/engine/headless/browser/cookie/cookie.go @@ -5,6 +5,7 @@ package cookie import ( _ "embed" "encoding/json" + "sort" "strings" "github.com/go-rod/rod/lib/proto" @@ -37,6 +38,10 @@ func init() { if err != nil { panic(err) } + + sort.SliceStable(cookieConsentBlockRequests, func(i, j int) bool { + return cookieConsentBlockRequests[i].Priority > cookieConsentBlockRequests[j].Priority + }) } // ShouldBlockRequest determines if a request should be blocked based on cookie consent rules diff --git a/pkg/engine/headless/browser/element.go b/pkg/engine/headless/browser/element.go index 2dd2f48d..3167259a 100644 --- a/pkg/engine/headless/browser/element.go +++ b/pkg/engine/headless/browser/element.go @@ -61,6 +61,31 @@ func (b *BrowserPage) FindNavigations() ([]*types.Action, error) { navigations := make([]*types.Action, 0) + forms, err := b.GetAllForms() + if err != nil { + return nil, errors.Wrap(err, "could not get forms") + } + for _, form := range forms { + for _, element := range form.Elements { + if element.TagName != "BUTTON" { + continue + } + // TODO: Check if this button is already in the unique map + // and if so remove it + unique[element.Hash()] = struct{}{} + } + hash := form.Hash() + if _, found := unique[hash]; found { + continue + } + unique[hash] = struct{}{} + + navigations = append(navigations, &types.Action{ + Type: types.ActionTypeFillForm, + Form: form, + }) + } + buttons, err := b.GetAllElements(buttonsCSSSelector) if err != nil { return nil, errors.Wrap(err, "could not get buttons") @@ -103,6 +128,13 @@ func (b *BrowserPage) FindNavigations() ([]*types.Action, error) { continue } + u, err := url.Parse(resolvedHref) + if err != nil { + continue + } + if u.Scheme != "http" && u.Scheme != "https" { + continue + } if !scopeValidator(resolvedHref) { continue } @@ -137,31 +169,6 @@ func (b *BrowserPage) FindNavigations() ([]*types.Action, error) { navigations = append(navigations, types.ActionFromEventListener(listener)) } - forms, err := b.GetAllForms() - if err != nil { - return nil, errors.Wrap(err, "could not get forms") - } - for _, form := range forms { - for _, element := range form.Elements { - if element.TagName != "BUTTON" { - continue - } - // TODO: Check if this button is already in the unique map - // and if so remove it - unique[element.Hash()] = struct{}{} - } - hash := form.Hash() - if _, found := unique[hash]; found { - continue - } - unique[hash] = struct{}{} - - navigations = append(navigations, &types.Action{ - Type: types.ActionTypeFillForm, - Form: form, - }) - } - return navigations, nil } diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 58cbc1f7..26549845 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -41,12 +41,14 @@ type Options struct { MaxBrowsers int MaxDepth int PageMaxTimeout time.Duration + NoSandbox bool ShowBrowser bool SlowMotion bool MaxCrawlDuration time.Duration MaxFailureCount int Trace bool CookieConsentBypass bool + AutomaticFormFill bool // EnableDiagnostics enables the diagnostics mode // which writes diagnostic information to a directory @@ -62,18 +64,23 @@ type Options struct { var domNormalizer *normalizer.Normalizer var initOnce sync.Once +var initError error func init() { initOnce.Do(func() { var err error domNormalizer, err = normalizer.New() if err != nil { - panic(err) + initError = errors.Wrap(err, "failed to create domnormalizer") } }) } func New(opts Options) (*Crawler, error) { + if initError != nil { + return nil, initError + } + launcher, err := browser.NewLauncher(browser.LauncherOptions{ ChromiumPath: opts.ChromiumPath, MaxBrowsers: opts.MaxBrowsers, @@ -85,6 +92,7 @@ func New(opts Options) (*Crawler, error) { ChromeUser: opts.ChromeUser, Trace: opts.Trace, CookieConsentBypass: opts.CookieConsentBypass, + NoSandbox: opts.NoSandbox, }) if err != nil { return nil, err @@ -120,7 +128,9 @@ func New(opts Options) (*Crawler, error) { func (c *Crawler) Close() { c.launcher.Close() if c.diagnostics != nil { - c.diagnostics.Close() + if err := c.diagnostics.Close(); err != nil { + c.logger.Warn("Failed to close diagnostics", slog.String("error", err.Error())) + } } } @@ -449,54 +459,3 @@ func isLogoutPage(element *types.HTMLElement) bool { return logoutPattern.MatchString(element.TextContent) || logoutPattern.MatchString(element.Attributes["href"]) } - -var formFillingData = map[string]string{ - "text": "test", - "number": "5", - "password": "test", - "email": "test@test.com", -} - -func (c *Crawler) processForm(page *browser.BrowserPage, form *types.HTMLForm) error { - var err error - - var submitButtonFinal *rod.Element - for _, field := range form.Elements { - var element *rod.Element - if field.XPath != "" { - if element, err = page.ElementX(field.XPath); err != nil { - return err - } - } - - switch field.TagName { - case "INPUT": - var inputValue string - switch field.Type { - case "text": - inputValue = formFillingData["text"] - case "number": - inputValue = formFillingData["number"] - case "password": - inputValue = formFillingData["password"] - case "email": - inputValue = formFillingData["email"] - } - if err := element.Input(inputValue); err != nil { - return err - } - case "TEXTAREA": - - case "BUTTON": - if submitButtonFinal == nil && field.Type == "submit" { - submitButtonFinal = element - } - } - } - if submitButtonFinal != nil { - if err := submitButtonFinal.Click(proto.InputMouseButtonLeft, 1); err != nil { - return err - } - } - return nil -} diff --git a/pkg/engine/headless/crawler/diagnostics/diagnostics.go b/pkg/engine/headless/crawler/diagnostics/diagnostics.go index 1b8358e6..b7ef2bc2 100644 --- a/pkg/engine/headless/crawler/diagnostics/diagnostics.go +++ b/pkg/engine/headless/crawler/diagnostics/diagnostics.go @@ -104,8 +104,8 @@ func (w *diskWriter) LogPageState(state *types.PageState, stateType PageStateTyp w.mu.Lock() val, ok := w.index.Get(state.UniqueID) if ok && val != nil { - w.mu.Unlock() val.Occurence++ + w.mu.Unlock() return nil } w.index.Set(state.UniqueID, &stateMetadata{ diff --git a/pkg/engine/headless/crawler/formfill.go b/pkg/engine/headless/crawler/formfill.go new file mode 100644 index 00000000..4a6ff0dc --- /dev/null +++ b/pkg/engine/headless/crawler/formfill.go @@ -0,0 +1,240 @@ +package crawler + +import ( + "fmt" + "log/slog" + + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/proto" + "github.com/projectdiscovery/katana/pkg/engine/headless/browser" + "github.com/projectdiscovery/katana/pkg/engine/headless/types" + utilsformfill "github.com/projectdiscovery/katana/pkg/utils" + mapsutil "github.com/projectdiscovery/utils/maps" +) + +func deriveName(e *types.HTMLElement) string { + if n, ok := e.Attributes["name"]; ok && n != "" { + return n + } + return e.ID +} + +func copyAttrs(src map[string]string, skipKeys ...string) mapsutil.OrderedMap[string, string] { + skip := map[string]struct{}{} + for _, k := range skipKeys { + skip[k] = struct{}{} + } + dst := mapsutil.NewOrderedMap[string, string]() + for k, v := range src { + if _, s := skip[k]; !s { + dst.Set(k, v) + } + } + return dst +} + +func convertHTMLElementToFormInput(element *types.HTMLElement) utilsformfill.FormInput { + return utilsformfill.FormInput{ + Name: deriveName(element), + Type: element.Type, + Value: element.Value, + Attributes: copyAttrs(element.Attributes, "name", "value", "type"), + } +} + +func convertHTMLElementToFormTextArea(element *types.HTMLElement) utilsformfill.FormTextArea { + return utilsformfill.FormTextArea{ + Name: deriveName(element), + Attributes: copyAttrs(element.Attributes, "name"), + } +} + +func convertHTMLElementToFormSelect(element *types.HTMLElement) utilsformfill.FormSelect { + return utilsformfill.FormSelect{ + Name: deriveName(element), + Attributes: copyAttrs(element.Attributes, "name"), + SelectOptions: []utilsformfill.SelectOption{}, + } +} + +func (c *Crawler) processForm(page *browser.BrowserPage, form *types.HTMLForm) error { + if !c.options.AutomaticFormFill { + return nil + } + + var formFields []interface{} + var submitButton *rod.Element + elementMap := make(map[string]*rod.Element) + + for _, field := range form.Elements { + if field.XPath == "" { + continue + } + + element, err := page.ElementX(field.XPath) + if err != nil { + c.logger.Debug("Could not find form element", + slog.String("xpath", field.XPath), + slog.String("error", err.Error()), + ) + continue + } + + fieldName := c.getFieldName(field) + + switch field.TagName { + case "INPUT": + if field.Type == "submit" || field.Type == "button" { + if submitButton == nil && field.Type == "submit" { + submitButton = element + } + continue + } + + formInput := convertHTMLElementToFormInput(field) + formFields = append(formFields, formInput) + if fieldName != "" { + elementMap[fieldName] = element + } + + case "TEXTAREA": + formTextArea := convertHTMLElementToFormTextArea(field) + formFields = append(formFields, formTextArea) + if fieldName != "" { + elementMap[fieldName] = element + } + + case "SELECT": + formSelect := c.buildFormSelectWithOptions(page, field, element) + formFields = append(formFields, formSelect) + if fieldName != "" { + elementMap[fieldName] = element + } + + case "BUTTON": + if field.Type == "submit" && submitButton == nil { + submitButton = element + } + } + } + + fillSuggestions := utilsformfill.FormFillSuggestions(formFields) + + if err := c.applyFormSuggestions(fillSuggestions, elementMap); err != nil { + c.logger.Debug("Error applying form suggestions", slog.String("error", err.Error())) + } + + if submitButton != nil { + if err := submitButton.Click(proto.InputMouseButtonLeft, 1); err != nil { + return err + } + } + + return nil +} + +func (c *Crawler) getFieldName(field *types.HTMLElement) string { + return deriveName(field) +} + +func (c *Crawler) buildFormSelectWithOptions(page *browser.BrowserPage, field *types.HTMLElement, element *rod.Element) utilsformfill.FormSelect { + formSelect := convertHTMLElementToFormSelect(field) + + options, err := element.Elements("option") + if err == nil && len(options) > 0 { + formSelect.SelectOptions = []utilsformfill.SelectOption{} + for _, opt := range options { + optionValue, _ := opt.Attribute("value") + if optionValue == nil { + text, _ := opt.Text() + optionValue = &text + } + + selected, _ := opt.Attribute("selected") + selectOption := utilsformfill.SelectOption{ + Value: *optionValue, + Selected: "", + } + if selected != nil { + selectOption.Selected = "selected" + } + formSelect.SelectOptions = append(formSelect.SelectOptions, selectOption) + } + } else { + formSelect.SelectOptions = []utilsformfill.SelectOption{ + {Value: utilsformfill.FormData.Placeholder, Selected: "selected"}, + } + } + + return formSelect +} + +func (c *Crawler) applyFormSuggestions(suggestions mapsutil.OrderedMap[string, string], elementMap map[string]*rod.Element) error { + suggestions.Iterate(func(fieldName, value string) bool { + element, exists := elementMap[fieldName] + if !exists || value == "" { + return true + } + + tagName, err := element.Eval(`() => this.tagName`) + if err != nil { + c.logger.Debug("Failed to get element tag", + slog.String("field", fieldName), + slog.String("error", err.Error()), + ) + return true + } + + switch tagName.Value.String() { + case "INPUT": + inputType, _ := element.Attribute("type") + if inputType != nil { + switch *inputType { + case "checkbox", "radio": + if value == "on" || value == fieldName { + if err := element.Click(proto.InputMouseButtonLeft, 1); err != nil { + c.logger.Debug("Failed to check input", + slog.String("field", fieldName), + slog.String("type", *inputType), + slog.String("error", err.Error()), + ) + } + } + default: + if err := element.Input(value); err != nil { + c.logger.Debug("Failed to fill input field", + slog.String("field", fieldName), + slog.String("value", value), + slog.String("error", err.Error()), + ) + } + } + } + + case "TEXTAREA": + if err := element.Input(value); err != nil { + c.logger.Debug("Failed to fill textarea", + slog.String("field", fieldName), + slog.String("value", value), + slog.String("error", err.Error()), + ) + } + + case "SELECT": + if err := element.Select([]string{value}, true, rod.SelectorTypeText); err != nil { + valueSelector := fmt.Sprintf(`[value="%s"]`, value) + if err := element.Select([]string{valueSelector}, true, rod.SelectorTypeCSSSector); err != nil { + c.logger.Debug("Failed to select option", + slog.String("field", fieldName), + slog.String("value", value), + slog.String("error", err.Error()), + ) + } + } + } + + return true + }) + + return nil +} diff --git a/pkg/engine/headless/crawler/normalizer/normalizer.go b/pkg/engine/headless/crawler/normalizer/normalizer.go index 24a693c7..44eccca4 100644 --- a/pkg/engine/headless/crawler/normalizer/normalizer.go +++ b/pkg/engine/headless/crawler/normalizer/normalizer.go @@ -11,7 +11,7 @@ import ( "github.com/pkg/errors" ) -var whiteSpacesRegex = regexp.MustCompile(`\\n|\\r|\s+`) +var whiteSpacesRegex = regexp.MustCompile(`[\r\n]+|\s+`) // Normalizer is a normalizer for text and DOM content type Normalizer struct { diff --git a/pkg/engine/headless/graph/graph.go b/pkg/engine/headless/graph/graph.go index 3e7f5609..154b1939 100644 --- a/pkg/engine/headless/graph/graph.go +++ b/pkg/engine/headless/graph/graph.go @@ -83,6 +83,9 @@ func (g *CrawlGraph) AddPageState(n types.PageState) error { } func (g *CrawlGraph) AddEdge(sourceState, targetState string, action *types.Action) error { + if action == nil { + return errors.New("add edge: action cannot be nil") + } edgeAttrs := map[string]string{ "label": action.String(), } @@ -112,14 +115,14 @@ func (g *CrawlGraph) ShortestPath(sourceState, targetState string) ([]*types.Act if err != nil { return nil, errors.Wrap(err, "could not find shortest path") } - var actionsSlice []*types.Action + actionsSlice := make([]*types.Action, 0, len(shortestPath)) for _, path := range shortestPath { pageVertex, err := g.graph.Vertex(path) if err != nil { return nil, errors.Wrap(err, "could not get vertex") } - if pageVertex.URL == "about:blank" { + if pageVertex.URL == "about:blank" || pageVertex.NavigationAction == nil { continue } actionsSlice = append(actionsSlice, pageVertex.NavigationAction) diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 8b177a39..68c4a93d 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -98,14 +98,16 @@ func (h *Headless) Crawl(URL string) error { scopeValidator := validateScopeFunc(h, URL) crawlOpts := crawler.Options{ - ChromiumPath: h.options.Options.SystemChromePath, - MaxDepth: h.options.Options.MaxDepth, - ShowBrowser: h.options.Options.ShowBrowser, - MaxCrawlDuration: h.options.Options.CrawlDuration, - MaxFailureCount: h.options.Options.MaxFailureCount, - MaxBrowsers: 1, - PageMaxTimeout: 30 * time.Second, - ScopeValidator: scopeValidator, + ChromiumPath: h.options.Options.SystemChromePath, + MaxDepth: h.options.Options.MaxDepth, + ShowBrowser: h.options.Options.ShowBrowser, + MaxCrawlDuration: h.options.Options.CrawlDuration, + MaxFailureCount: h.options.Options.MaxFailureCount, + NoSandbox: h.options.Options.HeadlessNoSandbox, + MaxBrowsers: 1, + PageMaxTimeout: 30 * time.Second, + ScopeValidator: scopeValidator, + AutomaticFormFill: h.options.Options.AutomaticFormFill, RequestCallback: func(rr *output.Result) { if !scopeValidator(rr.Request.URL) { return @@ -125,6 +127,7 @@ func (h *Headless) Crawl(URL string) error { Trace: h.options.Options.EnableDiagnostics, CookieConsentBypass: true, } + // TODO: Make the crawling multi-threaded. Right now concurrency is hardcoded to 1. headlessCrawler, err := crawler.New(crawlOpts) diff --git a/pkg/engine/headless/js/utils.js b/pkg/engine/headless/js/utils.js index c8137c8e..3a7cd5dd 100644 --- a/pkg/engine/headless/js/utils.js +++ b/pkg/engine/headless/js/utils.js @@ -31,16 +31,23 @@ // getAllElements returns all the elements for a query // selector on the page window.getAllElements = function (selector) { - const buttons = document.querySelectorAll(selector); - return Array.from(buttons).map((button) => _elementDataFromElement(button)); + try { + const nodes = document.querySelectorAll(selector); + return Array.from(nodes).map((el) => _elementDataFromElement(el)); + } catch (_) { + return []; + } }; window.getElementFromXPath = function (xpath) { - const element = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; - if (!element) { + try { + const element = document + .evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null) + .singleNodeValue; + return element ? _elementDataFromElement(element) : null; + } catch (_) { return null; } - return _elementDataFromElement(element); } // getAllElementsWithEventListeners returns all the elements diff --git a/pkg/engine/headless/types/types.go b/pkg/engine/headless/types/types.go index 45766b69..b46d6d4d 100644 --- a/pkg/engine/headless/types/types.go +++ b/pkg/engine/headless/types/types.go @@ -4,6 +4,7 @@ import ( "crypto/md5" "encoding/hex" "fmt" + "os" "regexp" "sort" "strings" @@ -153,8 +154,8 @@ func (e *HTMLElement) String() string { builder.WriteString(fmt.Sprintf(".%s", e.Classes)) } if e.TextContent != "" { - e.TextContent = strings.Trim(e.TextContent, " \n\r\t") - builder.WriteString(fmt.Sprintf(" (%s)", e.TextContent)) + trimmedContent := strings.Trim(e.TextContent, " \n\r\t") + builder.WriteString(fmt.Sprintf(" (%s)", trimmedContent)) } value := builder.String() return value @@ -186,7 +187,7 @@ func (e *HTMLElement) Hash() string { hashInput := strings.Join(parts, "|") if IsDiagnosticEnabled { - fmt.Printf("[diagnostic] Element hash input: %s\n", hashInput) + fmt.Fprintf(os.Stderr, "[diagnostic] Element hash input: %s\n", hashInput) } hasher.Write([]byte(hashInput)) return hex.EncodeToString(hasher.Sum(nil)) @@ -234,7 +235,7 @@ func (f *HTMLForm) Hash() string { hashInput := strings.Join(parts, "|") if IsDiagnosticEnabled { - fmt.Printf("[diagnostic] Form hash input: %s\n", hashInput) + fmt.Fprintf(os.Stderr, "[diagnostic] Form hash input: %s\n", hashInput) } hasher.Write([]byte(hashInput)) return hex.EncodeToString(hasher.Sum(nil)) diff --git a/pkg/engine/parser/parser.go b/pkg/engine/parser/parser.go index 964b5e47..01c3a330 100644 --- a/pkg/engine/parser/parser.go +++ b/pkg/engine/parser/parser.go @@ -96,15 +96,17 @@ func appendFiltered(existing []*navigation.Request, new []*navigation.Request) [ } func isValidNavigationRequest(req *navigation.Request) bool { - if req == nil || req.URL == "" { + if req == nil { return false } - - // Direct checks - fastest for small number of schemes - url := req.URL - return !(strings.HasPrefix(url, "data:") || - strings.HasPrefix(url, "mailto:") || - strings.HasPrefix(url, "javascript:")) + url := strings.TrimSpace(req.URL) + if url == "" { + return false + } + lc := strings.ToLower(url) + return !(strings.HasPrefix(lc, "data:") || + strings.HasPrefix(lc, "mailto:") || + strings.HasPrefix(lc, "javascript:")) } // ------------------------------------------------------------------------- From 3f9b1d7688fabf7362bca20b34b1b4bf4a98949d Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Thu, 25 Sep 2025 18:29:55 +0530 Subject: [PATCH 21/22] feat: more code review comments --- .../crawler/diagnostics/diagnostics.go | 1 - .../headless/crawler/normalizer/dom_utils.go | 38 +++++--- .../headless/crawler/normalizer/normalizer.go | 3 - .../headless/crawler/normalizer/text_utils.go | 20 ++--- .../crawler/normalizer/text_utils_test.go | 88 +++++++++++++------ pkg/engine/headless/crawler/state.go | 33 ++++++- pkg/engine/headless/debugger.go | 8 +- pkg/engine/headless/headless.go | 3 + pkg/engine/headless/js/page-init.js | 39 ++++---- 9 files changed, 151 insertions(+), 82 deletions(-) diff --git a/pkg/engine/headless/crawler/diagnostics/diagnostics.go b/pkg/engine/headless/crawler/diagnostics/diagnostics.go index b7ef2bc2..34d9c0cb 100644 --- a/pkg/engine/headless/crawler/diagnostics/diagnostics.go +++ b/pkg/engine/headless/crawler/diagnostics/diagnostics.go @@ -120,7 +120,6 @@ func (w *diskWriter) LogPageState(state *types.PageState, stateType PageStateTyp // Write dom to a separate file and remove striped dom // Create new directory for each state dom, strippedDOM := state.DOM, state.StrippedDOM - state.DOM, state.StrippedDOM = "", "" dir := filepath.Join(w.directory, state.UniqueID) if err := os.MkdirAll(dir, 0755); err != nil { diff --git a/pkg/engine/headless/crawler/normalizer/dom_utils.go b/pkg/engine/headless/crawler/normalizer/dom_utils.go index 52643944..a1494e3f 100644 --- a/pkg/engine/headless/crawler/normalizer/dom_utils.go +++ b/pkg/engine/headless/crawler/normalizer/dom_utils.go @@ -45,18 +45,26 @@ func NewDOMNormalizer() *DOMNormalizer { }) }) } - customTransformations = append(customTransformations, func(doc *goquery.Document) { - doc.Find("p").Each(func(_ int, s *goquery.Selection) { - // Remove or replace the text node inside <p> - removeTextNodes(s) + + // TODO: Check impact of removing paragraph text stripping + /* + customTransformations = append(customTransformations, func(doc *goquery.Document) { + doc.Find("p").Each(func(_ int, s *goquery.Selection) { + // Remove or replace the text node inside <p> + removeTextNodes(s) + }) }) - }) + */ + for _, t := range NoChildrenDomTransformations { t := t customTransformations = append(customTransformations, func(doc *goquery.Document) { doc.Find(t).Each(func(_ int, s *goquery.Selection) { if s.Children().Length() == 0 && strings.TrimSpace(s.Text()) == "" { - s.Remove() + // Only remove if there are no attributes as well + if node := s.Get(0); node != nil && len(node.Attr) == 0 { + s.Remove() + } } }) }) @@ -64,6 +72,10 @@ func NewDOMNormalizer() *DOMNormalizer { return &DOMNormalizer{customTransformations: customTransformations} } +// TODO: Check impact of removing this helper function +// This function was used to strip text nodes from paragraph elements. +// Commented out pending impact assessment on deduplication behavior. +/* func removeTextNodes(s *goquery.Selection) { node := s.Get(0) if node == nil { @@ -78,6 +90,7 @@ func removeTextNodes(s *goquery.Selection) { c = next } } +*/ // Apply applies the normalizers to the given content func (d *DOMNormalizer) Apply(content string) (string, error) { @@ -85,16 +98,14 @@ func (d *DOMNormalizer) Apply(content string) (string, error) { if err != nil { return "", err } - // Apply selection based transformations - doc.Find("*").Each(func(_ int, s *goquery.Selection) { - for _, f := range selectionBasedTransformationFuncs { - f(s) - } - }) - // Apply custom transformations + // Apply custom transformations first (selector-based removals, etc.) for _, f := range d.customTransformations { f(doc) } + // Apply selection based transformations once at the root (recursive helpers will traverse) + for _, f := range selectionBasedTransformationFuncs { + f(doc.Selection) + } result, err := doc.Html() if err != nil { return "", err @@ -144,7 +155,6 @@ var attributes = []string{ func removeClassIDDataAttributesDomTransformationFunc(s *goquery.Selection) { removeAttributes(s) - // Handle children s.Children().Each(func(_ int, child *goquery.Selection) { removeClassIDDataAttributesDomTransformationFunc(child) diff --git a/pkg/engine/headless/crawler/normalizer/normalizer.go b/pkg/engine/headless/crawler/normalizer/normalizer.go index 44eccca4..d93e9d67 100644 --- a/pkg/engine/headless/crawler/normalizer/normalizer.go +++ b/pkg/engine/headless/crawler/normalizer/normalizer.go @@ -20,9 +20,6 @@ type Normalizer struct { } // New returns a new Normalizer -// -// textPatterns is a list of regex patterns to remove from the text. -// domSelectors is a list of CSS selectors to remove from the DOM. func New() (*Normalizer, error) { textNormalizer, err := NewTextNormalizer() if err != nil { diff --git a/pkg/engine/headless/crawler/normalizer/text_utils.go b/pkg/engine/headless/crawler/normalizer/text_utils.go index c7fcba2e..8a85df89 100644 --- a/pkg/engine/headless/crawler/normalizer/text_utils.go +++ b/pkg/engine/headless/crawler/normalizer/text_utils.go @@ -9,21 +9,21 @@ import ( // DefaultTextPatterns is a list of regex patterns for the text normalizer var DefaultTextPatterns = []string{ // emailAddress - `[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}`, + `\b(?i)[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b`, // ipAddress - `(?:[0-9]{1,3}\.){3}[0-9]{1,3}`, + `\b(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}\b`, // uuid - `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`, + `\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b`, // relativeDates - `(?:[0-9]{1,2}\s(?:days?|weeks?|months?|years?)\s(?:ago|from\snow))`, - // priceAmounts - `[\$€£¥]\s*\d+(?:\.\d{1,2})?`, + `\b(?:[0-9]{1,2}\s(?:days?|weeks?|months?|years?)\s(?:ago|from\s+now))\b`, + // priceAmounts (no leading \b due to currency symbols) + `[\$€£¥]\s*\d+(?:\.\d{1,2})?\b`, // phoneNumbers - `(?:\+?1[0-9]{3}|0[0-9]{2})[ -]?\d{3}[ -]?\d{4}`, + `\b\+?\d{7,15}\b`, // ssnNumbers - `[\$€£¥]\s*\d+(?:\.\d{1,2})?`, + `\b\d{3}-\d{2}-\d{4}\b`, // timestampRegex - `(?:(?:[0-9]{4}-[0-9]{2}-[0-9]{2})|(?:(?:[0-9]{2}\/){2}[0-9]{4}))\s(?:[0-9]{2}:[0-9]{2}:[0-9]{2})`, + `\b(?:(?:[0-9]{4}-[0-9]{2}-[0-9]{2})|(?:(?:[0-9]{2}\/){2}[0-9]{4}))\s(?:[0-9]{2}:[0-9]{2}:[0-9]{2})\b`, } // TextNormalizer is a normalizer for text @@ -43,7 +43,7 @@ func NewTextNormalizer() (*TextNormalizer, error) { var compiledPatterns []*regexp.Regexp for _, pattern := range patterns { pattern := pattern - compiledPattern, err := regexp.Compile(fmt.Sprintf("\\b%s\\b", pattern)) + compiledPattern, err := regexp.Compile(pattern) if err != nil { return nil, fmt.Errorf("error compiling pattern %s: %v", pattern, err) } diff --git a/pkg/engine/headless/crawler/normalizer/text_utils_test.go b/pkg/engine/headless/crawler/normalizer/text_utils_test.go index 69eb6d7a..eb1bdd05 100644 --- a/pkg/engine/headless/crawler/normalizer/text_utils_test.go +++ b/pkg/engine/headless/crawler/normalizer/text_utils_test.go @@ -1,42 +1,72 @@ package normalizer import ( - "regexp" + "strings" "testing" ) -func TestTextNormalizer_Apply(t *testing.T) { - type fields struct { - patterns []*regexp.Regexp +func TestTextNormalizer_AllPatterns(t *testing.T) { + normalizer, err := NewTextNormalizer() + if err != nil { + t.Fatalf("Failed to create normalizer: %v", err) } - type args struct { - text string - } - tests := []struct { - name string - fields fields - args args - want string + + testText := ` + Contact us at test@example.com or admin@SITE.ORG for support. + Server IP: 192.168.1.1 and public IP: 8.8.8.8 + Invalid IPs should not match: 999.999.999.999 or 300.400.500.600 + UUID: 550e8400-e29b-41d4-a716-446655440000 + Relative dates: 5 days ago, 2 weeks from now, 10 months ago + Prices: $19.99, €50.00, £25.50, ¥1000 + Phone numbers: +1234567890, +447911123456, +33123456789 + SSN: 123-45-6789, 987-65-4321 + Timestamps: 2023-12-25 14:30:00, 12/25/2023 09:15:30 + ` + + result := normalizer.Apply(testText) + + // Check that sensitive data was removed + testCases := []struct { + pattern string + shouldBeRemoved bool + description string }{ - { - name: "test", - fields: fields{ - patterns: []*regexp.Regexp{regexp.MustCompile(`[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}`)}, - }, - args: args{ - text: "<a href='nav'>nizamul@pd.io</a>", - }, - want: "<a href='nav'></a>", - }, + {"test@example.com", true, "lowercase email"}, + {"admin@SITE.ORG", true, "uppercase email"}, + {"192.168.1.1", true, "private IP"}, + {"8.8.8.8", true, "public IP"}, + {"999.999.999.999", false, "invalid IP (too high octets)"}, + {"300.400.500.600", false, "invalid IP (too high octets)"}, + {"550e8400-e29b-41d4-a716-446655440000", true, "UUID"}, + {"5 days ago", true, "relative date - days ago"}, + {"2 weeks from now", true, "relative date - weeks from now"}, + {"10 months ago", true, "relative date - months ago"}, + {"$19.99", true, "USD price"}, + {"€50.00", true, "EUR price"}, + {"£25.50", true, "GBP price"}, + {"¥1000", true, "JPY price"}, + {"+1234567890", true, "international phone"}, + {"+447911123456", true, "UK phone"}, + {"+33123456789", true, "French phone"}, + {"123-45-6789", true, "SSN format 1"}, + {"987-65-4321", true, "SSN format 2"}, + {"2023-12-25 14:30:00", true, "ISO timestamp"}, + {"12/25/2023 09:15:30", true, "US timestamp"}, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - n := &TextNormalizer{ - patterns: tt.fields.patterns, + + for _, tc := range testCases { + if tc.shouldBeRemoved { + if strings.Contains(result, tc.pattern) { + t.Errorf("%s: Pattern '%s' should have been removed but was found in result", tc.description, tc.pattern) } - if got := n.Apply(tt.args.text); got != tt.want { - t.Errorf("TextNormalizer.Apply() = %v, want %v", got, tt.want) + } else { + if !strings.Contains(result, tc.pattern) { + t.Errorf("%s: Invalid pattern '%s' should not have been removed but was not found in result", tc.description, tc.pattern) } - }) + } } + + t.Logf("Original text length: %d", len(testText)) + t.Logf("Normalized text length: %d", len(result)) + t.Logf("Normalized result: %s", result) } diff --git a/pkg/engine/headless/crawler/state.go b/pkg/engine/headless/crawler/state.go index 3cd84e36..996efa21 100644 --- a/pkg/engine/headless/crawler/state.go +++ b/pkg/engine/headless/crawler/state.go @@ -197,8 +197,8 @@ func (c *Crawler) tryElementNavigation(page *browser.BrowserPage, action *types. if err != nil { return "", err } - // Ensure its the same element in some form - if htmlElement.ID == action.Element.ID || htmlElement.Classes == action.Element.Classes || htmlElement.TextContent == action.Element.TextContent { + // Ensure its the same element with stronger identity matching + if isElementMatch(htmlElement, action.Element) { c.logger.Debug("Found target element on current page, proceeding without navigation") // FIXME: Return the origin element ID so that the graph shows // correctly the fastest way to reach the state. @@ -207,6 +207,33 @@ func (c *Crawler) tryElementNavigation(page *browser.BrowserPage, action *types. return "", nil } +// isElementMatch implements stronger identity matching logic to reduce false positives. +// It treats identical ID as definitive match, otherwise requires both Classes and TextContent +// to match, or enforces at least two matching non-empty attributes. +func isElementMatch(current, target *types.HTMLElement) bool { + if current == nil || target == nil { + return false + } + // Definitive match: identical non-empty IDs + if current.ID != "" && target.ID != "" && current.ID == target.ID { + return true + } + matchCount := 0 + + if current.Classes != "" && target.Classes != "" && current.Classes == target.Classes { + matchCount++ + } + if current.TextContent != "" && target.TextContent != "" && current.TextContent == target.TextContent { + matchCount++ + } + if current.TagName != "" && target.TagName != "" && current.TagName == target.TagName { + matchCount++ + } + // Require at least two matching non-empty attributes for a positive match + // This ensures stronger identity verification while still allowing reasonable fallbacks + return matchCount >= 2 +} + func (c *Crawler) tryBrowserHistoryNavigation(page *browser.BrowserPage, originPageState *types.PageState, action *types.Action) (string, error) { canNavigateBack, stepsBack, err := c.isBackNavigationPossible(page, originPageState) if err != nil { @@ -278,6 +305,8 @@ func (c *Crawler) tryShortestPathNavigation(action *types.Action, page *browser. if err != nil { return "", errors.Wrap(err, "could not find path to origin page") } + } else { + return "", errors.Wrap(err, "failed to find shortest path") } } c.logger.Debug("Found actions to traverse", diff --git a/pkg/engine/headless/debugger.go b/pkg/engine/headless/debugger.go index 8fd60229..a3223acd 100644 --- a/pkg/engine/headless/debugger.go +++ b/pkg/engine/headless/debugger.go @@ -34,8 +34,12 @@ func NewCrawlDebugger(httpPort int) *CrawlDebugger { mux.HandleFunc("/debug/health", cd.handleHealth) cd.httpServer = &http.Server{ - Addr: fmt.Sprintf(":%d", httpPort), - Handler: mux, + Addr: fmt.Sprintf("127.0.0.1:%d", httpPort), + Handler: mux, + ReadTimeout: 5 * time.Second, + ReadHeaderTimeout: 2 * time.Second, + WriteTimeout: 5 * time.Second, + IdleTimeout: 30 * time.Second, } go func() { diff --git a/pkg/engine/headless/headless.go b/pkg/engine/headless/headless.go index 68c4a93d..cb5796cb 100644 --- a/pkg/engine/headless/headless.go +++ b/pkg/engine/headless/headless.go @@ -72,6 +72,9 @@ func validateScopeFunc(h *Headless, URL string) browser.ScopeValidator { rootHostname := parsedURL.Hostname() return func(s string) bool { + if h.options.ScopeManager == nil { + return true + } parsed, err := url.Parse(s) if err != nil { return false diff --git a/pkg/engine/headless/js/page-init.js b/pkg/engine/headless/js/page-init.js index 21426791..edf73e46 100644 --- a/pkg/engine/headless/js/page-init.js +++ b/pkg/engine/headless/js/page-init.js @@ -25,28 +25,25 @@ window.__navigatedLinks = []; // Hook history.pushState and history.replaceState to capture all the navigated links - window.history.pushState = function (a, b, c) { - window.__navigatedLinks.push({ url: c, source: "history.pushState" }); - }; - window.history.replaceState = function (a, b, c) { - window.__navigatedLinks.push({ url: c, source: "history.replaceState" }); - }; - Object.defineProperty( - window.history, - "pushState", - markElementReadonlyProperties - ); - Object.defineProperty( - window.history, - "replaceState", - markElementReadonlyProperties - ); + const __origPushState = window.history.pushState.bind(window.history); + const __origReplaceState = window.history.replaceState.bind(window.history); + function __wrappedPushState(a, b, c) { + try { window.__navigatedLinks.push({ url: c, source: "history.pushState" }); } catch (_) {} + return __origPushState(a, b, c); + } + function __wrappedReplaceState(a, b, c) { + try { window.__navigatedLinks.push({ url: c, source: "history.replaceState" }); } catch (_) {} + return __origReplaceState(a, b, c); + } + Object.defineProperty(window.history, "pushState", { value: __wrappedPushState, writable: false, configurable: false }); + Object.defineProperty(window.history, "replaceState", { value: __wrappedReplaceState, writable: false, configurable: false }); // Hook window.open to capture all the opened pages - window.open = function (url) { - console.log("[hook] open url request", url); - window.__navigatedLinks.push({ url: url, source: "window.open" }); - }; - Object.defineProperty(window, "open", markElementReadonlyProperties); + const __origOpen = window.open.bind(window); + function __wrappedOpen(url, ...rest) { + try { window.__navigatedLinks.push({ url, source: "window.open" }); } catch (_) {} + return __origOpen(url, ...rest); + } + Object.defineProperty(window, "open", { value: __wrappedOpen, writable: false, configurable: false }); // Add event listener for hashchange window.addEventListener("hashchange", function () { From 20e61c987dea6d22224db3905e09229c7c529a88 Mon Sep 17 00:00:00 2001 From: Ice3man <nizamulrana@gmail.com> Date: Tue, 30 Sep 2025 15:02:41 +0530 Subject: [PATCH 22/22] fix out of scope parsing --- pkg/engine/headless/crawler/crawler.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkg/engine/headless/crawler/crawler.go b/pkg/engine/headless/crawler/crawler.go index 26549845..abbad119 100644 --- a/pkg/engine/headless/crawler/crawler.go +++ b/pkg/engine/headless/crawler/crawler.go @@ -332,6 +332,18 @@ func (c *Crawler) crawlFn(action *types.Action, page *browser.BrowserPage) error } pageState.OriginID = currentPageHash + if c.options.ScopeValidator != nil { + if !c.options.ScopeValidator(pageState.URL) { + c.logger.Debug("Skipping navigation collection - current page is out of scope", + slog.String("url", pageState.URL), + ) + if c.crawlQueue.Size() == 0 { + return ErrNoCrawlingAction + } + return nil + } + } + navigations, err := page.FindNavigations() if err != nil { return err