Extend cookie deprecation metadata issue to include opt-out percentages, if present. Sample screenshots: With 1P opt-out: https://screenshot.googleplex.com/8DfCEkp2WC6gJPU With 3P opt-out: https://screenshot.googleplex.com/XEZnoDPNHuvk2BE Also include cookie operation to determine whether to show the Read or Set description. Screenshot: https://screenshot.googleplex.com/BCkjXKX9yqd9WS7 Bug: b/341051114, b/341794619 Change-Id: Id19b50a22642d6dcfad413b9f1db6849cc822935 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5551153 Reviewed-by: Joshua Hood <jdh@chromium.org> Reviewed-by: Wolfgang Beyer <wolfi@chromium.org> Commit-Queue: Anton Maliev <amaliev@chromium.org>
diff --git a/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts b/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts index 557b671..295f224 100644 --- a/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts +++ b/front_end/models/issues_manager/CookieDeprecationMetadataIssue.ts
@@ -24,7 +24,9 @@ constructor( issueDetails: Protocol.Audits.CookieDeprecationMetadataIssueDetails, issuesModel: SDK.IssuesModel.IssuesModel) { - super(Protocol.Audits.InspectorIssueCode.CookieDeprecationMetadataIssue, issuesModel); + // Set a distinct code for ReadCookie and SetCookie issues, so they are grouped separately. + const issueCode = Protocol.Audits.InspectorIssueCode.CookieDeprecationMetadataIssue + '_' + issueDetails.operation; + super(issueCode, issuesModel); this.#issueDetails = issueDetails; } @@ -33,8 +35,20 @@ } getDescription(): MarkdownIssueDescription { + const fileName = this.#issueDetails.operation === 'SetCookie' ? 'cookieWarnMetadataGrantSet.md' : + 'cookieWarnMetadataGrantRead.md'; + + let optOutText = ''; + if (this.#issueDetails.isOptOutTopLevel && this.#issueDetails.optOutPercentage >= 0) { + optOutText = '\n\n (Top level site opt-out: ' + this.#issueDetails.optOutPercentage + + '% - [learn more](gracePeriodStagedControlExplainer))'; + } + return { - file: 'cookieWarnMetadataGrantRead.md', + file: fileName, + substitutions: new Map([ + ['PLACEHOLDER_topleveloptout', optOutText], + ]), links: [ { link: 'https://developer.chrome.com/docs/privacy-sandbox/third-party-cookie-phase-out/', @@ -56,13 +70,6 @@ return JSON.stringify(this.#issueDetails); } - override metadataAllowedSites(): Iterable<string> { - if (this.#issueDetails.allowedSites) { - return this.#issueDetails.allowedSites; - } - return []; - } - static fromInspectorIssue(issuesModel: SDK.IssuesModel.IssuesModel, inspectorIssue: Protocol.Audits.InspectorIssue): CookieDeprecationMetadataIssue[] { const details = inspectorIssue.details.cookieDeprecationMetadataIssueDetails;
diff --git a/front_end/models/issues_manager/Issue.ts b/front_end/models/issues_manager/Issue.ts index 4ce0551..cc43329 100644 --- a/front_end/models/issues_manager/Issue.ts +++ b/front_end/models/issues_manager/Issue.ts
@@ -173,10 +173,6 @@ return []; } - metadataAllowedSites(): Iterable<string> { - return []; - } - isAssociatedWithRequestId(requestId: string): boolean { for (const request of this.requests()) { if (request.requestId === requestId) {
diff --git a/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md b/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md index cd8b990..5f2379f 100644 --- a/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md +++ b/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantRead.md
@@ -1,3 +1,4 @@ # Third-party websites are allowed to read cookies on this page -One or more websites are allowed to bypass user settings to read third-party cookies on this page. Chrome no longer supports third-party cookies and web developers should take steps to remove these reads without disrupting user experience. To forcefully block these third-party cookies, update [user settings](https://support.google.com/chrome/answer/95647). +One or more websites are allowed to bypass user settings to read third-party cookies on this page. Chrome no longer supports third-party cookies and web developers should take steps to remove these reads without disrupting user experience. To forcefully block these third-party cookies, update [user settings](manageCookiesHelpPage). +{PLACEHOLDER_topleveloptout}
diff --git a/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md b/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md index 67ce5de..1b25b44 100644 --- a/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md +++ b/front_end/models/issues_manager/descriptions/cookieWarnMetadataGrantSet.md
@@ -1,3 +1,4 @@ # Third-party websites are allowed to set cookies on this page -One or more websites are allowed to bypass user settings to set third-party cookies on this page. Chrome no longer supports third-party cookies and web developers should take steps to remove these sets without disrupting user experience. To forcefully block these third-party cookies, update [user settings](https://support.google.com/chrome/answer/95647). +One or more websites are allowed to bypass user settings to set third-party cookies on this page. Chrome no longer supports third-party cookies and web developers should take steps to remove these sets without disrupting user experience. To forcefully block these third-party cookies, update [user settings](manageCookiesHelpPage). +{PLACEHOLDER_topleveloptout}
diff --git a/front_end/models/issues_manager/issues_manager.ts b/front_end/models/issues_manager/issues_manager.ts index a15b61c..3482ccb 100644 --- a/front_end/models/issues_manager/issues_manager.ts +++ b/front_end/models/issues_manager/issues_manager.ts
@@ -7,6 +7,7 @@ import * as ClientHintIssue from './ClientHintIssue.js'; import * as ContentSecurityPolicyIssue from './ContentSecurityPolicyIssue.js'; import * as ContrastCheckTrigger from './ContrastCheckTrigger.js'; +import * as CookieDeprecationMetadataIssue from './CookieDeprecationMetadataIssue.js'; import * as CookieIssue from './CookieIssue.js'; import * as CorsIssue from './CorsIssue.js'; import * as CrossOriginEmbedderPolicyIssue from './CrossOriginEmbedderPolicyIssue.js'; @@ -34,6 +35,7 @@ ClientHintIssue, ContentSecurityPolicyIssue, ContrastCheckTrigger, + CookieDeprecationMetadataIssue, CookieIssue, CorsIssue, CrossOriginEmbedderPolicyIssue,
diff --git a/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts b/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts index 17c09c2..a091194 100644 --- a/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts +++ b/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts
@@ -4,6 +4,7 @@ import * as i18n from '../../core/i18n/i18n.js'; import type * as Platform from '../../core/platform/platform.js'; +import * as UI from '../../ui/legacy/legacy.js'; import {AffectedResourcesView} from './AffectedResourcesView.js'; @@ -27,14 +28,33 @@ override update(): void { this.clear(); - const allowedSites = this.issue.getMetadataAllowedSites(); + const issues = this.issue.getCookieDeprecationMetadataIssues(); let count = 0; - for (const site of allowedSites) { + for (const issueData of issues) { const row = document.createElement('tr'); row.classList.add('affected-resource-directive'); - this.appendIssueDetailCell(row, site); + const textContentElement = document.createElement('div'); + const textElement = document.createElement('span'); + textElement.textContent = issueData.details().allowedSites.join(', '); + textContentElement.appendChild(textElement); + + if (!issueData.details().isOptOutTopLevel && issueData.details().optOutPercentage > 0) { + const optOutTextElement = document.createElement('span'); + optOutTextElement.textContent = ' (opt-out: ' + issueData.details().optOutPercentage + '% - '; + textContentElement.appendChild(optOutTextElement); + + const linkElement = UI.XLink.XLink.create( + 'https://github.com/amaliev/3pcd-exemption-heuristics/blob/main/explainer.md', 'learn more'); + textContentElement.appendChild(linkElement); + + const endTextElement = document.createElement('span'); + endTextElement.textContent = ')'; + textContentElement.appendChild(endTextElement); + } + + this.appendIssueDetailCell(row, textContentElement); this.affectedResources.appendChild(row); count++; }
diff --git a/front_end/panels/issues/AffectedResourcesView.ts b/front_end/panels/issues/AffectedResourcesView.ts index 8a6a002..2cd0f1c 100644 --- a/front_end/panels/issues/AffectedResourcesView.ts +++ b/front_end/panels/issues/AffectedResourcesView.ts
@@ -274,17 +274,25 @@ header.appendChild(info); } - protected createIssueDetailCell(textContent: string, additionalClass: string|null = null): HTMLTableDataCellElement { + protected createIssueDetailCell(textContent: string|HTMLElement, additionalClass: string|null = null): + HTMLTableDataCellElement { const cell = document.createElement('td'); - cell.textContent = textContent; + + if (typeof textContent === 'string') { + cell.textContent = textContent; + } else { + cell.appendChild(textContent); + } + if (additionalClass) { cell.classList.add(additionalClass); } return cell; } - protected appendIssueDetailCell(element: HTMLElement, textContent: string, additionalClass: string|null = null): - HTMLTableDataCellElement { + protected appendIssueDetailCell( + element: HTMLElement, textContent: string|HTMLElement, + additionalClass: string|null = null): HTMLTableDataCellElement { const cell = this.createIssueDetailCell(textContent, additionalClass); element.appendChild(cell); return cell;
diff --git a/front_end/panels/issues/IssueAggregator.ts b/front_end/panels/issues/IssueAggregator.ts index aa9cce1..3804f46 100644 --- a/front_end/panels/issues/IssueAggregator.ts +++ b/front_end/panels/issues/IssueAggregator.ts
@@ -40,7 +40,8 @@ #deprecationIssues = new Set<IssuesManager.DeprecationIssue.DeprecationIssue>(); #issueKind = IssuesManager.Issue.IssueKind.Improvement; #lowContrastIssues = new Set<IssuesManager.LowTextContrastIssue.LowTextContrastIssue>(); - #metadataAllowedSites = new Set<string>(); + #cookieDeprecationMetadataIssues = + new Set<IssuesManager.CookieDeprecationMetadataIssue.CookieDeprecationMetadataIssue>(); #mixedContentIssues = new Set<IssuesManager.MixedContentIssue.MixedContentIssue>(); #sharedArrayBufferIssues = new Set<IssuesManager.SharedArrayBufferIssue.SharedArrayBufferIssue>(); #quirksModeIssues = new Set<IssuesManager.QuirksModeIssue.QuirksModeIssue>(); @@ -94,8 +95,9 @@ return this.#heavyAdIssues; } - getMetadataAllowedSites(): Iterable<string> { - return this.#metadataAllowedSites.values(); + getCookieDeprecationMetadataIssues(): + Iterable<IssuesManager.CookieDeprecationMetadataIssue.CookieDeprecationMetadataIssue> { + return this.#cookieDeprecationMetadataIssues; } getMixedContentIssues(): Iterable<IssuesManager.MixedContentIssue.MixedContentIssue> { @@ -200,10 +202,8 @@ this.#affectedLocations.set(key, location); } } - for (const site of issue.metadataAllowedSites()) { - if (!this.#metadataAllowedSites.has(site)) { - this.#metadataAllowedSites.add(site); - } + if (issue instanceof IssuesManager.CookieDeprecationMetadataIssue.CookieDeprecationMetadataIssue) { + this.#cookieDeprecationMetadataIssues.add(issue); } if (issue instanceof IssuesManager.MixedContentIssue.MixedContentIssue) { this.#mixedContentIssues.add(issue);
diff --git a/front_end/ui/components/markdown_view/MarkdownLinksMap.ts b/front_end/ui/components/markdown_view/MarkdownLinksMap.ts index f0153d1..54b528a 100644 --- a/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +++ b/front_end/ui/components/markdown_view/MarkdownLinksMap.ts
@@ -51,7 +51,8 @@ ], ['PNASecureContextRestrictionFeatureStatus', 'https://chromestatus.com/feature/5954091755241472'], ['https://w3c.github.io/uievents/#legacy-event-types', 'https://w3c.github.io/uievents/#legacy-event-types'], - ['https://support.google.com/chrome/answer/95647', 'https://support.google.com/chrome/answer/95647'], + ['manageCookiesHelpPage', 'https://support.google.com/chrome/answer/95647'], + ['gracePeriodStagedControlExplainer', 'https://github.com/amaliev/3pcd-exemption-heuristics/blob/main/explainer.md'], ]); export const getMarkdownLink = (key: string): string => {
diff --git a/test/e2e/issues/cookie-deprecation-metadata-issues_test.ts b/test/e2e/issues/cookie-deprecation-metadata-issues_test.ts index 25bd577..ae48a86 100644 --- a/test/e2e/issues/cookie-deprecation-metadata-issues_test.ts +++ b/test/e2e/issues/cookie-deprecation-metadata-issues_test.ts
@@ -27,6 +27,9 @@ 'details': { 'cookieDeprecationMetadataIssueDetails': { 'allowedSites': ['example_1.test'], + 'optOutPercentage': 25, + 'isOptOutTopLevel': true, + 'operation': 'ReadCookie', }, }, }; @@ -37,6 +40,9 @@ 'details': { 'cookieDeprecationMetadataIssueDetails': { 'allowedSites': ['example_2.test'], + 'optOutPercentage': 50, + 'isOptOutTopLevel': false, + 'operation': 'ReadCookie', }, }, }; @@ -50,7 +56,7 @@ await ensureResourceSectionIsExpanded(section); const expectedTableRows = [ ['example_1.test'], - ['example_2.test'], + ['example_2.test (opt-out: 50% - learn more)'], ]; await waitForTableFromResourceSectionContents(section.content, expectedTableRows); });