From 99b898fdbdd48d1bef71b8110fd7f46b88de886e Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 12 Jul 2024 19:32:25 +0100 Subject: [PATCH 1/6] feat: add url_ignorelist for autocapture config --- src/__tests__/autocapture.test.ts | 21 +++++++++++++++++++++ src/autocapture-utils.ts | 18 +++++++++++++++--- src/autocapture.ts | 1 + src/types.ts | 8 ++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/__tests__/autocapture.test.ts b/src/__tests__/autocapture.test.ts index c9f0c5d62..59d0fcdb6 100644 --- a/src/__tests__/autocapture.test.ts +++ b/src/__tests__/autocapture.test.ts @@ -1112,6 +1112,27 @@ describe('Autocapture system', () => { expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(false) }) + it('not capture urls which match the url regex ignorelist', () => { + const main_el = document.createElement('some-element') + const button = document.createElement('a') + button.innerHTML = 'bla' + main_el.appendChild(button) + const e = makeMouseEvent({ + target: main_el, + composedPath: () => [button, main_el], + }) + const autocapture_config = { + url_ignorelist: ['https://posthog.com/test/*'], + } + + window!.location = new URL('https://posthog.com/test/captured') as unknown as Location + + expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(false) + + window!.location = new URL('https://posthog.com/docs/not-captured') as unknown as Location + expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(true) + }) + it('an empty url regex allowlist does not match any url', () => { const main_el = document.createElement('some-element') const button = document.createElement('a') diff --git a/src/autocapture-utils.ts b/src/autocapture-utils.ts index 00c913359..674e26c83 100644 --- a/src/autocapture-utils.ts +++ b/src/autocapture-utils.ts @@ -9,6 +9,14 @@ export function splitClassString(s: string): string[] { return s ? trim(s).split(/\s+/) : [] } +function whenURLMatches(urlsList: (string | RegExp)[], resultOnMatch: boolean): boolean { + const url = window?.location.href + if (url && urlsList && urlsList.some((regex) => url.match(regex))) { + return resultOnMatch + } + return !resultOnMatch +} + /* * Get the className of an element, accounting for edge cases where element.className is an object * @@ -201,9 +209,13 @@ export function shouldCaptureDomEvent( } if (autocaptureConfig?.url_allowlist) { - const url = window.location.href - const allowlist = autocaptureConfig.url_allowlist - if (allowlist && !allowlist.some((regex) => url.match(regex))) { + if (whenURLMatches(autocaptureConfig.url_allowlist, true) === false) { + return false + } + } + + if (autocaptureConfig?.url_ignorelist) { + if (whenURLMatches(autocaptureConfig.url_ignorelist, false) === false) { return false } } diff --git a/src/autocapture.ts b/src/autocapture.ts index 31fb404c8..dbef30693 100644 --- a/src/autocapture.ts +++ b/src/autocapture.ts @@ -53,6 +53,7 @@ export class Autocapture { const config = isObject(this.instance.config.autocapture) ? this.instance.config.autocapture : {} // precompile the regex config.url_allowlist = config.url_allowlist?.map((url) => new RegExp(url)) + config.url_ignorelist = config.url_ignorelist?.map((url) => new RegExp(url)) return config } diff --git a/src/types.ts b/src/types.ts index cf7a7cbad..43a66016c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,9 +25,17 @@ export interface AutocaptureConfig { /** * List of URLs to allow autocapture on, can be strings to match * or regexes e.g. ['https://example.com', 'test.com/.*'] + * this is useful when you want to autocapture on specific pages only */ url_allowlist?: (string | RegExp)[] + /** + * List of URLs to not allow autocapture on, can be strings to match + * or regexes e.g. ['https://example.com', 'test.com/.*'] + * this is useful when you want to autocapture on most pages but not some specific ones + */ + url_ignorelist?: (string | RegExp)[] + /** * List of DOM events to allow autocapture on e.g. ['click', 'change', 'submit'] */ From 24f4e141f98e1124e78d743b75382d5891ec494e Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 12 Jul 2024 19:38:28 +0100 Subject: [PATCH 2/6] clearer --- src/__tests__/autocapture.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/__tests__/autocapture.test.ts b/src/__tests__/autocapture.test.ts index 59d0fcdb6..5740bc942 100644 --- a/src/__tests__/autocapture.test.ts +++ b/src/__tests__/autocapture.test.ts @@ -1104,11 +1104,11 @@ describe('Autocapture system', () => { url_allowlist: ['https://posthog.com/test/*'], } - window!.location = new URL('https://posthog.com/test/captured') as unknown as Location + window!.location = new URL('https://posthog.com/test/matching') as unknown as Location expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(true) - window!.location = new URL('https://posthog.com/docs/not-captured') as unknown as Location + window!.location = new URL('https://posthog.com/docs/not-matching') as unknown as Location expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(false) }) @@ -1125,11 +1125,11 @@ describe('Autocapture system', () => { url_ignorelist: ['https://posthog.com/test/*'], } - window!.location = new URL('https://posthog.com/test/captured') as unknown as Location + window!.location = new URL('https://posthog.com/test/matching') as unknown as Location expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(false) - window!.location = new URL('https://posthog.com/docs/not-captured') as unknown as Location + window!.location = new URL('https://posthog.com/docs/not-matching') as unknown as Location expect(shouldCaptureDomEvent(button, e, autocapture_config)).toBe(true) }) From 272ecca69cd8a36836807ca6e3a03bf3f692b990 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 12 Jul 2024 19:40:28 +0100 Subject: [PATCH 3/6] comment --- src/autocapture-utils.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/autocapture-utils.ts b/src/autocapture-utils.ts index 674e26c83..b02481a90 100644 --- a/src/autocapture-utils.ts +++ b/src/autocapture-utils.ts @@ -9,6 +9,15 @@ export function splitClassString(s: string): string[] { return s ? trim(s).split(/\s+/) : [] } +/** + * this is used by both an allowlist and an ignore list + * + * so the expected result can be passed in + * + * when being used as an allowlist, the expected result is true + * when being used as an ignore list, the expected result is false + * + */ function whenURLMatches(urlsList: (string | RegExp)[], resultOnMatch: boolean): boolean { const url = window?.location.href if (url && urlsList && urlsList.some((regex) => url.match(regex))) { From e5a41c6d2c82e2d1b6164a4ad279a174919b5a6f Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 12 Jul 2024 19:40:51 +0100 Subject: [PATCH 4/6] fix --- src/autocapture-utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/autocapture-utils.ts b/src/autocapture-utils.ts index b02481a90..d3208309e 100644 --- a/src/autocapture-utils.ts +++ b/src/autocapture-utils.ts @@ -18,7 +18,7 @@ export function splitClassString(s: string): string[] { * when being used as an ignore list, the expected result is false * */ -function whenURLMatches(urlsList: (string | RegExp)[], resultOnMatch: boolean): boolean { +function checkForURLMatches(urlsList: (string | RegExp)[], resultOnMatch: boolean): boolean { const url = window?.location.href if (url && urlsList && urlsList.some((regex) => url.match(regex))) { return resultOnMatch @@ -218,13 +218,13 @@ export function shouldCaptureDomEvent( } if (autocaptureConfig?.url_allowlist) { - if (whenURLMatches(autocaptureConfig.url_allowlist, true) === false) { + if (checkForURLMatches(autocaptureConfig.url_allowlist, true) === false) { return false } } if (autocaptureConfig?.url_ignorelist) { - if (whenURLMatches(autocaptureConfig.url_ignorelist, false) === false) { + if (checkForURLMatches(autocaptureConfig.url_ignorelist, false) === false) { return false } } From 3d2016a3a61380f50e8e13d02c9aa4ab0f81b13a Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 12 Jul 2024 19:43:02 +0100 Subject: [PATCH 5/6] that's nicer --- src/autocapture-utils.ts | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/autocapture-utils.ts b/src/autocapture-utils.ts index d3208309e..94b85b69e 100644 --- a/src/autocapture-utils.ts +++ b/src/autocapture-utils.ts @@ -9,21 +9,9 @@ export function splitClassString(s: string): string[] { return s ? trim(s).split(/\s+/) : [] } -/** - * this is used by both an allowlist and an ignore list - * - * so the expected result can be passed in - * - * when being used as an allowlist, the expected result is true - * when being used as an ignore list, the expected result is false - * - */ -function checkForURLMatches(urlsList: (string | RegExp)[], resultOnMatch: boolean): boolean { +function checkForURLMatches(urlsList: (string | RegExp)[]): boolean { const url = window?.location.href - if (url && urlsList && urlsList.some((regex) => url.match(regex))) { - return resultOnMatch - } - return !resultOnMatch + return !!(url && urlsList && urlsList.some((regex) => url.match(regex))) } /* @@ -218,13 +206,15 @@ export function shouldCaptureDomEvent( } if (autocaptureConfig?.url_allowlist) { - if (checkForURLMatches(autocaptureConfig.url_allowlist, true) === false) { + // if the current URL is not in the allow list, don't capture + if (!checkForURLMatches(autocaptureConfig.url_allowlist)) { return false } } if (autocaptureConfig?.url_ignorelist) { - if (checkForURLMatches(autocaptureConfig.url_ignorelist, false) === false) { + // if the current URL is in the ignore list, don't capture + if (checkForURLMatches(autocaptureConfig.url_ignorelist)) { return false } } From 1fc88bac3e70830dc21dd0578958e3a89d24c4a5 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Fri, 12 Jul 2024 19:52:31 +0100 Subject: [PATCH 6/6] clarify the comment --- src/types.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/types.ts b/src/types.ts index 43a66016c..17f7f0bb5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,6 +26,10 @@ export interface AutocaptureConfig { * List of URLs to allow autocapture on, can be strings to match * or regexes e.g. ['https://example.com', 'test.com/.*'] * this is useful when you want to autocapture on specific pages only + * + * if you set both url_allowlist and url_ignorelist, + * we check the allowlist first and then the ignorelist. + * the ignorelist can override the allowlist */ url_allowlist?: (string | RegExp)[] @@ -33,6 +37,10 @@ export interface AutocaptureConfig { * List of URLs to not allow autocapture on, can be strings to match * or regexes e.g. ['https://example.com', 'test.com/.*'] * this is useful when you want to autocapture on most pages but not some specific ones + * + * if you set both url_allowlist and url_ignorelist, + * we check the allowlist first and then the ignorelist. + * the ignorelist can override the allowlist */ url_ignorelist?: (string | RegExp)[]