diff --git a/packages/cookie-banner/src/activation.ts b/packages/cookie-banner/src/activation.ts index 5764b93a2..6416a8db2 100644 --- a/packages/cookie-banner/src/activation.ts +++ b/packages/cookie-banner/src/activation.ts @@ -314,53 +314,29 @@ function deactivateElement(el: Element, label?: string): void { } } -const KNOWN_MULTI_PART_TLDS = new Set([ - "co.uk", - "co.jp", - "co.kr", - "co.nz", - "co.za", - "co.in", - "co.id", - "com.au", - "com.br", - "com.cn", - "com.mx", - "com.tw", - "com.hk", - "com.sg", - "com.ar", - "com.co", - "com.tr", - "net.au", - "org.uk", - "org.au", - "ac.uk", - "gov.uk", - "ne.jp", - "or.jp", -]); - -function getRootDomain(hostname: string): string { +function getCandidateDomains(hostname: string): string[] { const parts = hostname.split("."); - if (parts.length <= 2) { - return parts.length === 2 ? "." + hostname : hostname; + if (parts.length <= 1) return []; + + const candidates: string[] = []; + // Try progressively broader parent domains. The browser silently + // ignores attempts to clear cookies on public suffixes, so + // over-trying is safe and avoids maintaining a TLD list. + for (let i = 0; i < parts.length - 1; i++) { + candidates.push("." + parts.slice(i).join(".")); } - const lastTwo = parts.slice(-2).join("."); - if (KNOWN_MULTI_PART_TLDS.has(lastTwo)) { - return "." + parts.slice(-3).join("."); - } - - return "." + lastTwo; + return candidates; } function removeCookies(names: string[]): void { - const rootDomain = getRootDomain(location.hostname); + const domains = getCandidateDomains(location.hostname); for (const name of names) { document.cookie = `${name}=; path=/; max-age=0`; - document.cookie = `${name}=; path=/; domain=${rootDomain}; max-age=0`; + for (const domain of domains) { + document.cookie = `${name}=; path=/; domain=${domain}; max-age=0`; + } } } diff --git a/packages/cookie-banner/src/client.ts b/packages/cookie-banner/src/client.ts index 8c42195de..76284b3ea 100644 --- a/packages/cookie-banner/src/client.ts +++ b/packages/cookie-banner/src/client.ts @@ -153,7 +153,7 @@ export class CookieBannerClient { return this.consent !== null; } - async acceptAll(): Promise { + acceptAll(): void { const cfg = this.config; const consentData: Record = {}; @@ -161,10 +161,10 @@ export class CookieBannerClient { consentData[cat.name] = true; } - return this.recordConsent("ACCEPT_ALL", consentData); + this.recordConsent("ACCEPT_ALL", consentData); } - async rejectAll(): Promise { + rejectAll(): void { const cfg = this.config; const consentData: Record = {}; @@ -172,12 +172,10 @@ export class CookieBannerClient { consentData[cat.name] = cat.kind === "NECESSARY"; } - return this.recordConsent("REJECT_ALL", consentData); + this.recordConsent("REJECT_ALL", consentData); } - async customize( - categories: Record, - ): Promise { + customize(categories: Record): void { const cfg = this.config; const consentData: Record = {}; @@ -185,39 +183,21 @@ export class CookieBannerClient { consentData[cat.name] = cat.kind === "NECESSARY" || !!categories[cat.name]; } - return this.recordConsent("CUSTOMIZE", consentData); + this.recordConsent("CUSTOMIZE", consentData); } - private async recordConsent( + private recordConsent( action: ConsentAction, consentData: Record, - ): Promise { + ): void { const cfg = this.config; - const url = new URL(`${this.bannerId}/consents`, this.baseUrl); - const body = { - visitor_id: this.visitorId, - version: cfg.version, - action, - consent_data: consentData, - }; - - let record: ConsentRecord | null = null; - try { - record = await fetchJSON(url, { - method: "POST", - body, - }); - void flush(this.bannerId); - } catch { - enqueue(this.bannerId, url.href, body); - } this.consent = { visitor_id: this.visitorId, version: cfg.version, action, consent_data: consentData, - created_at: record?.created_at ?? "", + created_at: "", }; setConsentCookie( @@ -232,12 +212,16 @@ export class CookieBannerClient { this.activate(consentData); - return record ?? { - id: "", + const url = new URL(`${this.bannerId}/consents`, this.baseUrl); + const body = { visitor_id: this.visitorId, + version: cfg.version, action, - created_at: "", + consent_data: consentData, }; + void fetchJSON(url, { method: "POST", body }) + .then(() => void flush(this.bannerId)) + .catch(() => enqueue(this.bannerId, url.href, body)); } private activate(consentData: Record): void { diff --git a/packages/cookie-banner/src/components/buttons.ts b/packages/cookie-banner/src/components/buttons.ts index e3a4ba8ff..ca87dba24 100644 --- a/packages/cookie-banner/src/components/buttons.ts +++ b/packages/cookie-banner/src/components/buttons.ts @@ -34,32 +34,30 @@ class ProboActionButton extends ProboElement { export class ProboAcceptButton extends ProboActionButton { protected handleClick = (): void => { if (!this.root) return; - void this.root.client.acceptAll().then(() => { - this.root!.setState("hidden"); - this.root!.dispatchEvent( - new CustomEvent("probo-consent", { - bubbles: true, - composed: true, - detail: { action: "ACCEPT_ALL" }, - }), - ); - }); + this.root.client.acceptAll(); + this.root.setState("hidden"); + this.root.dispatchEvent( + new CustomEvent("probo-consent", { + bubbles: true, + composed: true, + detail: { action: "ACCEPT_ALL" }, + }), + ); }; } export class ProboRejectButton extends ProboActionButton { protected handleClick = (): void => { if (!this.root) return; - void this.root.client.rejectAll().then(() => { - this.root!.setState("hidden"); - this.root!.dispatchEvent( - new CustomEvent("probo-consent", { - bubbles: true, - composed: true, - detail: { action: "REJECT_ALL" }, - }), - ); - }); + this.root.client.rejectAll(); + this.root.setState("hidden"); + this.root.dispatchEvent( + new CustomEvent("probo-consent", { + bubbles: true, + composed: true, + detail: { action: "REJECT_ALL" }, + }), + ); }; } diff --git a/packages/cookie-banner/src/components/preference-panel.ts b/packages/cookie-banner/src/components/preference-panel.ts index 989f8d013..247252189 100644 --- a/packages/cookie-banner/src/components/preference-panel.ts +++ b/packages/cookie-banner/src/components/preference-panel.ts @@ -78,15 +78,14 @@ export class ProboSaveButton extends ProboElement { private handleClick = (): void => { if (!this.root) return; const draft = { ...this.root.consentDraft }; - void this.root.client.customize(draft).then(() => { - this.root!.setState("hidden"); - this.root!.dispatchEvent( - new CustomEvent("probo-consent", { - bubbles: true, - composed: true, - detail: { action: "CUSTOMIZE", consent_data: draft }, - }), - ); - }); + this.root.client.customize(draft); + this.root.setState("hidden"); + this.root.dispatchEvent( + new CustomEvent("probo-consent", { + bubbles: true, + composed: true, + detail: { action: "CUSTOMIZE", consent_data: draft }, + }), + ); }; }