UNPKG

chrome-devtools-frontend

Version:
211 lines (191 loc) • 9.77 kB
// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /* eslint-disable rulesdir/no-imperative-dom-api */ import * as Common from '../../core/common/common.js'; import * as Host from '../../core/host/host.js'; import * as i18n from '../../core/i18n/i18n.js'; import * as Platform from '../../core/platform/platform.js'; import * as SDK from '../../core/sdk/sdk.js'; import type * as Protocol from '../../generated/protocol.js'; import * as IssuesManager from '../../models/issues_manager/issues_manager.js'; import {AffectedItem, AffectedResourcesView} from './AffectedResourcesView.js'; import * as IssuesComponents from './components/components.js'; const UIStrings = { /** *@description Singular or plural label for number of affected CSP (content security policy, * see https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) directives in issue view. */ nDirectives: '{n, plural, =1 {# directive} other {# directives}}', /** *@description Indicates that a CSP error should be treated as a warning */ reportonly: 'report-only', /** *@description The kind of resolution for a mixed content issue */ blocked: 'blocked', /** *@description Tooltip for button linking to the Elements panel */ clickToRevealTheViolatingDomNode: 'Click to reveal the violating DOM node in the Elements panel', /** *@description Header for the section listing affected directives */ directiveC: 'Directive', /** *@description Label for the column in the element list in the CSS overview report */ element: 'Element', /** *@description Header for the source location column */ sourceLocation: 'Source location', /** *@description Text for the status of something */ status: 'Status', /** *@description Text that refers to the resources of the web page */ resourceC: 'Resource', } as const; const str_ = i18n.i18n.registerUIStrings('panels/issues/AffectedDirectivesView.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class AffectedDirectivesView extends AffectedResourcesView { #appendStatus(element: Element, isReportOnly: boolean): void { const status = document.createElement('td'); if (isReportOnly) { status.classList.add('affected-resource-report-only-status'); status.textContent = i18nString(UIStrings.reportonly); } else { status.classList.add('affected-resource-blocked-status'); status.textContent = i18nString(UIStrings.blocked); } element.appendChild(status); } protected getResourceNameWithCount(count: number): Platform.UIString.LocalizedString { return i18nString(UIStrings.nDirectives, {n: count}); } #appendViolatedDirective(element: Element, directive: string): void { const violatedDirective = document.createElement('td'); violatedDirective.textContent = directive; element.appendChild(violatedDirective); } #appendBlockedURL(element: Element, url: Platform.DevToolsPath.UrlString): void { const info = document.createElement('td'); info.classList.add('affected-resource-directive-info'); info.textContent = url; element.appendChild(info); } #appendBlockedElement( element: Element, nodeId: Protocol.DOM.BackendNodeId|undefined, model: SDK.IssuesModel.IssuesModel): void { const elementsPanelLinkComponent = new IssuesComponents.ElementsPanelLink.ElementsPanelLink(); if (nodeId) { const violatingNodeId = nodeId; elementsPanelLinkComponent.title = i18nString(UIStrings.clickToRevealTheViolatingDomNode); const onElementRevealIconClick: (arg0?: Event|undefined) => void = () => { const target = model.getTargetIfNotDisposed(); if (target) { Host.userMetrics.issuesPanelResourceOpened(this.issue.getCategory(), AffectedItem.ELEMENT); const deferredDOMNode = new SDK.DOMModel.DeferredDOMNode(target, violatingNodeId); void Common.Revealer.reveal(deferredDOMNode); } }; const onElementRevealIconMouseEnter: (arg0?: Event|undefined) => void = () => { const target = model.getTargetIfNotDisposed(); if (target) { const deferredDOMNode = new SDK.DOMModel.DeferredDOMNode(target, violatingNodeId); if (deferredDOMNode) { deferredDOMNode.highlight(); } } }; const onElementRevealIconMouseLeave: (arg0?: Event|undefined) => void = () => { SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight(); }; elementsPanelLinkComponent .data = {onElementRevealIconClick, onElementRevealIconMouseEnter, onElementRevealIconMouseLeave}; } const violatingNode = document.createElement('td'); violatingNode.classList.add('affected-resource-csp-info-node'); violatingNode.appendChild(elementsPanelLinkComponent); element.appendChild(violatingNode); } #appendAffectedContentSecurityPolicyDetails( cspIssues: Iterable<IssuesManager.ContentSecurityPolicyIssue.ContentSecurityPolicyIssue>): void { const header = document.createElement('tr'); if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.inlineViolationCode) { this.appendColumnTitle(header, i18nString(UIStrings.directiveC)); this.appendColumnTitle(header, i18nString(UIStrings.element)); this.appendColumnTitle(header, i18nString(UIStrings.sourceLocation)); this.appendColumnTitle(header, i18nString(UIStrings.status)); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.urlViolationCode) { this.appendColumnTitle(header, i18nString(UIStrings.resourceC), 'affected-resource-directive-info-header'); this.appendColumnTitle(header, i18nString(UIStrings.status)); this.appendColumnTitle(header, i18nString(UIStrings.directiveC)); this.appendColumnTitle(header, i18nString(UIStrings.sourceLocation)); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.evalViolationCode) { this.appendColumnTitle(header, i18nString(UIStrings.sourceLocation)); this.appendColumnTitle(header, i18nString(UIStrings.directiveC)); this.appendColumnTitle(header, i18nString(UIStrings.status)); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.trustedTypesSinkViolationCode) { this.appendColumnTitle(header, i18nString(UIStrings.sourceLocation)); this.appendColumnTitle(header, i18nString(UIStrings.status)); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.trustedTypesPolicyViolationCode) { this.appendColumnTitle(header, i18nString(UIStrings.sourceLocation)); this.appendColumnTitle(header, i18nString(UIStrings.directiveC)); this.appendColumnTitle(header, i18nString(UIStrings.status)); } else { this.updateAffectedResourceCount(0); return; } this.affectedResources.appendChild(header); let count = 0; for (const cspIssue of cspIssues) { count++; this.#appendAffectedContentSecurityPolicyDetail(cspIssue); } this.updateAffectedResourceCount(count); } #appendAffectedContentSecurityPolicyDetail( cspIssue: IssuesManager.ContentSecurityPolicyIssue.ContentSecurityPolicyIssue): void { const element = document.createElement('tr'); element.classList.add('affected-resource-directive'); const cspIssueDetails = cspIssue.details(); const location = IssuesManager.Issue.toZeroBasedLocation(cspIssueDetails.sourceCodeLocation); const model = cspIssue.model(); const maybeTarget = cspIssue.model()?.getTargetIfNotDisposed(); if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.inlineViolationCode && model) { this.#appendViolatedDirective(element, cspIssueDetails.violatedDirective); this.#appendBlockedElement(element, cspIssueDetails.violatingNodeId, model); this.appendSourceLocation(element, location, maybeTarget); this.#appendStatus(element, cspIssueDetails.isReportOnly); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.urlViolationCode) { const url = cspIssueDetails.blockedURL ? cspIssueDetails.blockedURL as Platform.DevToolsPath.UrlString : Platform.DevToolsPath.EmptyUrlString; this.#appendBlockedURL(element, url); this.#appendStatus(element, cspIssueDetails.isReportOnly); this.#appendViolatedDirective(element, cspIssueDetails.violatedDirective); this.appendSourceLocation(element, location, maybeTarget); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.evalViolationCode) { this.appendSourceLocation(element, location, maybeTarget); this.#appendViolatedDirective(element, cspIssueDetails.violatedDirective); this.#appendStatus(element, cspIssueDetails.isReportOnly); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.trustedTypesSinkViolationCode) { this.appendSourceLocation(element, location, maybeTarget); this.#appendStatus(element, cspIssueDetails.isReportOnly); } else if (this.issue.code() === IssuesManager.ContentSecurityPolicyIssue.trustedTypesPolicyViolationCode) { this.appendSourceLocation(element, location, maybeTarget); this.#appendViolatedDirective(element, cspIssueDetails.violatedDirective); this.#appendStatus(element, cspIssueDetails.isReportOnly); } else { return; } this.affectedResources.appendChild(element); } update(): void { this.clear(); this.#appendAffectedContentSecurityPolicyDetails(this.issue.getCspIssues()); } }