mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-09 05:08:28 +08:00
Bug: chromium:1128885 Change-Id: Ia4fc5ee0fd03ad568eccc374db787dc705ee3cef Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2687501 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Wolfgang Beyer <wolfi@chromium.org>
255 lines
8.6 KiB
JavaScript
255 lines
8.6 KiB
JavaScript
// Copyright 2019 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.
|
|
|
|
import {ContentSecurityPolicyIssue} from './ContentSecurityPolicyIssue.js';
|
|
import {CorsIssue} from './CorsIssue.js';
|
|
import {CrossOriginEmbedderPolicyIssue, isCrossOriginEmbedderPolicyIssue} from './CrossOriginEmbedderPolicyIssue.js';
|
|
import {HeavyAdIssue} from './HeavyAdIssue.js';
|
|
import {Issue} from './Issue.js'; // eslint-disable-line no-unused-vars
|
|
import {LowTextContrastIssue} from './LowTextContrastIssue.js';
|
|
import {MixedContentIssue} from './MixedContentIssue.js';
|
|
import {SameSiteCookieIssue} from './SameSiteCookieIssue.js';
|
|
import {Capability, SDKModel, Target} from './SDKModel.js'; // eslint-disable-line no-unused-vars
|
|
import {SharedArrayBufferIssue} from './SharedArrayBufferIssue.js';
|
|
import {TrustedWebActivityIssue} from './TrustedWebActivityIssue.js';
|
|
|
|
|
|
/**
|
|
* The `IssuesModel` is a thin dispatch that does not store issues, but only creates the representation
|
|
* class (usually derived from `Issue`) and passes the instances on via a dispatched event.
|
|
* We chose this approach here because the lifetime of the Model is tied to the target, but DevTools
|
|
* wants to preserve issues for targets (e.g. iframes) that are already gone as well.
|
|
* @implements {ProtocolProxyApi.AuditsDispatcher}
|
|
*/
|
|
export class IssuesModel extends SDKModel {
|
|
/**
|
|
* @param {!Target} target
|
|
*/
|
|
constructor(target) {
|
|
super(target);
|
|
this._enabled = false;
|
|
/** @type {*} */
|
|
this._auditsAgent = null;
|
|
this.ensureEnabled();
|
|
this._disposed = false;
|
|
}
|
|
|
|
ensureEnabled() {
|
|
if (this._enabled) {
|
|
return;
|
|
}
|
|
|
|
this._enabled = true;
|
|
this.target().registerAuditsDispatcher(this);
|
|
this._auditsAgent = this.target().auditsAgent();
|
|
this._auditsAgent.invoke_enable();
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
* @param {!Protocol.Audits.IssueAddedEvent} issueAddedEvent
|
|
*/
|
|
issueAdded(issueAddedEvent) {
|
|
const issues = this._createIssuesFromProtocolIssue(issueAddedEvent.issue);
|
|
for (const issue of issues) {
|
|
this.addIssue(issue);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!Issue} issue
|
|
*/
|
|
addIssue(issue) {
|
|
this.dispatchEventToListeners(Events.IssueAdded, {issuesModel: this, issue});
|
|
}
|
|
|
|
/**
|
|
* Each issue reported by the backend can result in multiple {!Issue} instances.
|
|
* Handlers are simple functions hard-coded into a map.
|
|
* @param {!Protocol.Audits.InspectorIssue} inspectorIssue} inspectorIssue
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
_createIssuesFromProtocolIssue(inspectorIssue) {
|
|
const handler = issueCodeHandlers.get(inspectorIssue.code);
|
|
if (handler) {
|
|
return handler(this, inspectorIssue.details);
|
|
}
|
|
|
|
console.warn(`No handler registered for issue code ${inspectorIssue.code}`);
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* @override
|
|
*/
|
|
dispose() {
|
|
super.dispose();
|
|
this._disposed = true;
|
|
}
|
|
|
|
/**
|
|
* @returns {?Target}
|
|
*/
|
|
getTargetIfNotDisposed() {
|
|
if (!this._disposed) {
|
|
return this.target();
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForSameSiteCookieIssue(issuesModel, inspectorDetails) {
|
|
const sameSiteDetails = inspectorDetails.sameSiteCookieIssueDetails;
|
|
if (!sameSiteDetails) {
|
|
console.warn('SameSite issue without details received.');
|
|
return [];
|
|
}
|
|
|
|
return SameSiteCookieIssue.createIssuesFromSameSiteDetails(sameSiteDetails, issuesModel);
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForMixedContentIssue(issuesModel, inspectorDetails) {
|
|
const mixedContentDetails = inspectorDetails.mixedContentIssueDetails;
|
|
if (!mixedContentDetails) {
|
|
console.warn('Mixed content issue without details received.');
|
|
return [];
|
|
}
|
|
return [new MixedContentIssue(mixedContentDetails, issuesModel)];
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForContentSecurityPolicyIssue(issuesModel, inspectorDetails) {
|
|
const cspDetails = inspectorDetails.contentSecurityPolicyIssueDetails;
|
|
if (!cspDetails) {
|
|
console.warn('Content security policy issue without details received.');
|
|
return [];
|
|
}
|
|
return [new ContentSecurityPolicyIssue(cspDetails, issuesModel)];
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForHeavyAdIssue(issuesModel, inspectorDetails) {
|
|
const heavyAdIssueDetails = inspectorDetails.heavyAdIssueDetails;
|
|
if (!heavyAdIssueDetails) {
|
|
console.warn('Heavy Ad issue without details received.');
|
|
return [];
|
|
}
|
|
return [new HeavyAdIssue(heavyAdIssueDetails, issuesModel)];
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForBlockedByResponseIssue(issuesModel, inspectorDetails) {
|
|
const blockedByResponseIssueDetails = inspectorDetails.blockedByResponseIssueDetails;
|
|
if (!blockedByResponseIssueDetails) {
|
|
console.warn('BlockedByResponse issue without details received.');
|
|
return [];
|
|
}
|
|
if (isCrossOriginEmbedderPolicyIssue(blockedByResponseIssueDetails.reason)) {
|
|
return [new CrossOriginEmbedderPolicyIssue(blockedByResponseIssueDetails, issuesModel)];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForSharedArrayBufferIssue(issuesModel, inspectorDetails) {
|
|
const sabIssueDetails = inspectorDetails.sharedArrayBufferIssueDetails;
|
|
if (!sabIssueDetails) {
|
|
console.warn('SAB transfer issue without details received.');
|
|
return [];
|
|
}
|
|
return [new SharedArrayBufferIssue(sabIssueDetails, issuesModel)];
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForTrustedWebActivityIssue(issuesModel, inspectorDetails) {
|
|
const twaQualityEnforcementDetails = inspectorDetails.twaQualityEnforcementDetails;
|
|
if (!twaQualityEnforcementDetails) {
|
|
console.warn('TWA Quality Enforcement issue without details received.');
|
|
return [];
|
|
}
|
|
return [new TrustedWebActivityIssue(twaQualityEnforcementDetails)];
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForLowTextContrastIssue(issuesModel, inspectorDetails) {
|
|
const lowTextContrastIssueDetails = inspectorDetails.lowTextContrastIssueDetails;
|
|
if (!lowTextContrastIssueDetails) {
|
|
console.warn('LowTextContrast issue without details received.');
|
|
return [];
|
|
}
|
|
return [new LowTextContrastIssue(lowTextContrastIssueDetails)];
|
|
}
|
|
|
|
/**
|
|
* @param {!IssuesModel} issuesModel
|
|
* @param {!Protocol.Audits.InspectorIssueDetails} inspectorDetails
|
|
* @return {!Array<!Issue>}
|
|
*/
|
|
function createIssuesForCorsIssue(issuesModel, inspectorDetails) {
|
|
const corsIssueDetails = inspectorDetails.corsIssueDetails;
|
|
if (!corsIssueDetails) {
|
|
console.warn('Cors issue without details received.');
|
|
return [];
|
|
}
|
|
return [new CorsIssue(corsIssueDetails, issuesModel)];
|
|
}
|
|
|
|
/**
|
|
* @type {!Map<!Protocol.Audits.InspectorIssueCode, function(!IssuesModel, !Protocol.Audits.InspectorIssueDetails):!Array<!Issue>>}
|
|
*/
|
|
const issueCodeHandlers = new Map([
|
|
[Protocol.Audits.InspectorIssueCode.SameSiteCookieIssue, createIssuesForSameSiteCookieIssue],
|
|
[Protocol.Audits.InspectorIssueCode.MixedContentIssue, createIssuesForMixedContentIssue],
|
|
[Protocol.Audits.InspectorIssueCode.HeavyAdIssue, createIssuesForHeavyAdIssue],
|
|
[Protocol.Audits.InspectorIssueCode.ContentSecurityPolicyIssue, createIssuesForContentSecurityPolicyIssue],
|
|
[Protocol.Audits.InspectorIssueCode.BlockedByResponseIssue, createIssuesForBlockedByResponseIssue],
|
|
[Protocol.Audits.InspectorIssueCode.SharedArrayBufferIssue, createIssuesForSharedArrayBufferIssue],
|
|
[Protocol.Audits.InspectorIssueCode.TrustedWebActivityIssue, createIssuesForTrustedWebActivityIssue],
|
|
[Protocol.Audits.InspectorIssueCode.LowTextContrastIssue, createIssuesForLowTextContrastIssue],
|
|
[Protocol.Audits.InspectorIssueCode.CorsIssue, createIssuesForCorsIssue],
|
|
]);
|
|
|
|
/** @enum {symbol} */
|
|
export const Events = {
|
|
IssueAdded: Symbol('IssueAdded'),
|
|
};
|
|
|
|
SDKModel.register(IssuesModel, Capability.Audits, true);
|