diff --git a/README.md b/README.md index 199ee0e6..fd8a6315 100644 --- a/README.md +++ b/README.md @@ -106,14 +106,13 @@ var orejimeConfig = { cookies: [ '_ga', '_gat', - '_gid', - '__utma', - '__utmb', - '__utmc', - '__utmt', - '__utmz', - '_gat_gtag_' + GTM_UA, - '_gat_' + GTM_UA + '_gat_' + GTM_UA, + + // Regexes can be provided as strings or RegExp objects to match names + // more broadly. + '/^_gat_.+$/i', + /^_gat_.+$/i, + new RegExp('^_gat_.+$', 'i') ], // [optional] @@ -148,6 +147,7 @@ var orejimeConfig = { description: 'Example of an inline tracking script', cookies: [ 'inline-tracker', + // When deleting a cookie, Orejime will try to delete a cookie with the // given name, the "/" path, and multiple domains (the current domain // and `"." + current domain`). diff --git a/src/core/utils/deletePurposeCookies.ts b/src/core/utils/deletePurposeCookies.ts index fe1dd982..30174123 100644 --- a/src/core/utils/deletePurposeCookies.ts +++ b/src/core/utils/deletePurposeCookies.ts @@ -1,6 +1,6 @@ import {PurposeCookie} from '../types'; import {deleteCookie, getCookieNames} from './cookies'; -import escapeRegex from './escapeRegex'; +import {toRegex} from './regexes'; export default (cookies: PurposeCookie[]) => { const cookieNames = getCookieNames(); @@ -13,12 +13,10 @@ export default (cookies: PurposeCookie[]) => { [pattern, path, domain] = pattern; } - if (!(pattern instanceof RegExp)) { - pattern = new RegExp(`^${escapeRegex(pattern)}$`); - } + const regex = toRegex(pattern); cookieNames - .filter((name) => (pattern as RegExp).test(name)) + .filter((name) => regex.test(name)) .forEach((cookie) => { deleteCookie(cookie, path, domain); }); diff --git a/src/core/utils/escapeRegex.ts b/src/core/utils/escapeRegex.ts deleted file mode 100644 index febdc5ad..00000000 --- a/src/core/utils/escapeRegex.ts +++ /dev/null @@ -1,2 +0,0 @@ -export default (regex: string) => - regex.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); diff --git a/src/core/utils/regexes.test.ts b/src/core/utils/regexes.test.ts new file mode 100644 index 00000000..07d6a8a2 --- /dev/null +++ b/src/core/utils/regexes.test.ts @@ -0,0 +1,22 @@ +import {toRegex} from './regexes'; + +describe('toRegex', () => { + test('should return a regex as-is', () => { + const regex = new RegExp('pattern', 'gi'); + expect(toRegex(regex)).toEqual(regex); + }); + + test('should turn a pattern into a regex', () => { + expect(toRegex('/pattern/')).toEqual(new RegExp('pattern')); + expect(toRegex('/pattern/i')).toEqual(new RegExp('pattern', 'i')); + + // The only flag allowed is `i` + expect(toRegex('/pattern/g')).not.toEqual(new RegExp('pattern', 'g')); + expect(toRegex('/pattern/gi')).not.toEqual(new RegExp('pattern', 'gi')); + }); + + test('should turn a string into a regex', () => { + expect(toRegex('pattern')).toEqual(new RegExp('^pattern$')); + expect(toRegex('^pattern$')).toEqual(new RegExp('^\\^pattern\\$$')); + }); +}); diff --git a/src/core/utils/regexes.ts b/src/core/utils/regexes.ts new file mode 100644 index 00000000..732d412f --- /dev/null +++ b/src/core/utils/regexes.ts @@ -0,0 +1,27 @@ +// Turns a pattern into a regex. +// If the string looks like a regex pattern, it is used as-is. +// Otherwise, a regex is build to match the string exactly. +export const toRegex = (pattern: string | RegExp) => { + if (pattern instanceof RegExp) { + return pattern; + } + + if (pattern.startsWith('/')) { + // A regex to match a (simplistic) regex to match cookie names. + // `i` is the only relevant flag in that context. + const matches = /^\/(.*)\/(i?)$/.exec(pattern); + + if (matches) { + try { + return new RegExp(matches[1], matches[2]); + } catch (e) {} + } + } + + const escaped = pattern.replace( + /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, + '\\$&' + ); + + return new RegExp(`^${escaped}$`); +};