| Index: third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
|
| index 2bc3e5f51ccdabe1cbaf2892e73c393dae294821..9e015868b06bbc841af5be6cdc46785b6ebe43a9 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/security/SecurityPanel.js
|
| @@ -44,6 +44,7 @@ WebInspector.SecurityPanel.Origin;
|
| * @property {?NetworkAgent.SecurityDetails} securityDetails - Security details of the origin, if available.
|
| * @property {?Promise<!NetworkAgent.CertificateDetails>} certificateDetailsPromise - Certificate details of the origin. Only available if securityDetails are available.
|
| * @property {?WebInspector.SecurityOriginView} originView - Current SecurityOriginView corresponding to origin.
|
| + * @property {?WebInspector.CSPParser} cspDetails - Content Security Policy details
|
| */
|
| WebInspector.SecurityPanel.OriginState;
|
|
|
| @@ -180,6 +181,17 @@ WebInspector.SecurityPanel.prototype = {
|
| originState.certificateDetailsPromise = request.target().networkManager.certificateDetailsPromise(securityDetails.certificateId);
|
| }
|
|
|
| + if (Runtime.experiments.isEnabled("cspDetailsInSecurityPanel")) {
|
| + var cspHeader = request.responseHeaders.filter(header => header.name.toLowerCase().includes("content-security-policy"))[0];
|
| + if (cspHeader) {
|
| + originState.cspDetails =
|
| + WebInspector.CSPParser.buildFromString(
|
| + cspHeader.value,
|
| + cspHeader.name.toLowerCase().includes("report-only")
|
| + );
|
| + }
|
| + }
|
| +
|
| this._origins.set(origin, originState);
|
|
|
| this._sidebarTree.addOrigin(origin, securityState);
|
| @@ -821,6 +833,125 @@ WebInspector.SecurityOriginView = function(panel, origin, originState)
|
| noInfoSection.createChild("div", "origin-view-section-title").textContent = WebInspector.UIString("No Security Information");
|
| noInfoSection.createChild("div").textContent = WebInspector.UIString("No security details are available for this origin.");
|
| }
|
| +
|
| + if (Runtime.experiments.isEnabled("cspDetailsInSecurityPanel") && originState.cspDetails) {
|
| + let contentSecurityPolicySection = this.element.createChild("div", "origin-view-section");
|
| + contentSecurityPolicySection.createChild("div", "origin-view-section-title").textContent = WebInspector.UIString("Content Security Policy");
|
| + let toggleButton = createElement("button");
|
| + toggleButton.textContent = "Collapse All Policies";
|
| + toggleButton.dataset.showing = true;
|
| + toggleButton.className = "collapse-policies";
|
| + contentSecurityPolicySection.appendChild(toggleButton);
|
| +
|
| + let reportUri = createElement("p");
|
| + reportUri.innerHTML = `<b>Report URI</b> <span>${originState.cspDetails.reportUri ? originState.cspDetails.reportUri : "Not Set"}</span>`;
|
| + contentSecurityPolicySection.appendChild(reportUri);
|
| +
|
| + toggleButton.addEventListener("click", () => {
|
| + let headings = contentSecurityPolicySection.querySelectorAll(".csp-rule-heading");
|
| + if (toggleButton.dataset.showing === "true") {
|
| + Array.prototype.forEach.call(headings, item => {
|
| + item.closeSection();
|
| + });
|
| + toggleButton.textContent = "Show All Policies";
|
| + toggleButton.dataset.showing = false;
|
| + } else {
|
| + Array.prototype.forEach.call(headings, item => {
|
| + item.showSection();
|
| + });
|
| + toggleButton.textContent = "Collapse Policies";
|
| + toggleButton.dataset.showing = true;
|
| + }
|
| + });
|
| +
|
| + /**
|
| + * Create the sections for the CSP display.
|
| + *
|
| + * @param {!WebInspector.CSPParser.Policy} policy The CSP Policy to create a section for.
|
| + */
|
| + function createPolicySection(policy) {
|
| +
|
| + // Since for some reason a blank policy may get made sometimes.
|
| + if (!policy.name) {
|
| + return;
|
| + }
|
| +
|
| + /**
|
| + * Create table row for a CSP Rule
|
| + * @param {!WebInspector.CSPParser.Rule} rule The rule to create a table entry for.
|
| + * @return {string}
|
| + */
|
| + function createRuleRow(rule) {
|
| + return `
|
| + <tr class="csp-rule csp-security-state-${rule.securityState}">
|
| + <th><span class="lock-icon lock-icon-${rule.securityState}"></span><p>${rule.value}</p></th>
|
| + <td>
|
| + <p><b>Security Level</b> <span>${rule.humanReadableSecurityState}</span></p>
|
| + ${rule.reason ? `<p><b>Reason</b> <span>${rule.reason}</span></p>` : ""}
|
| + <p><b>Report Only</b> <span>${rule.reportOnly ? "Yes" : "No"}</span></p>
|
| + </td>
|
| + </tr>`;
|
| + }
|
| + let heading = createElement("h4");
|
| + heading.dataset.rule = policy.name;
|
| + heading.className = `csp-rule csp-rule-heading csp-security-state-${policy.securityState}`;
|
| + heading.textContent = policy.name;
|
| + heading.innerHTML += `<span class="icon"></span>`;
|
| + contentSecurityPolicySection.appendChild(heading);
|
| +
|
| + let policyStateArea = createElement("p");
|
| + policyStateArea.innerHTML = `<b>Policy state</b> ${policy.humanReadableSecurityState}`;
|
| + if (policy.securityStateReason) {
|
| + policyStateArea.innerHTML += `<br><b>Reason</b> ${policy.securityStateReason}`;
|
| + }
|
| + contentSecurityPolicySection.appendChild(policyStateArea);
|
| +
|
| + let table = createElementWithClass("table", `csp-directive csp-rule-list-${policy.name}`);
|
| + table.innerHTML += `
|
| + <tbody>
|
| + ${policy.rules.sort((a, b) => a.value.localeCompare(b.value)).map(createRuleRow).join('')}
|
| + </tbody>
|
| + </table>`;
|
| + contentSecurityPolicySection.appendChild(table);
|
| +
|
| + /**
|
| + * @this {Element}
|
| + */
|
| + heading.toggleSection = function() {
|
| + contentSecurityPolicySection
|
| + .querySelector(`.csp-rule-list-${policy.name}`)
|
| + .classList
|
| + .toggle("csp-directive_hidden");
|
| + this.classList.toggle("directive-is-hidden");
|
| + };
|
| + /**
|
| + * @this {Element}
|
| + */
|
| + heading.closeSection = function() {
|
| + contentSecurityPolicySection
|
| + .querySelector(`.csp-rule-list-${policy.name}`)
|
| + .classList
|
| + .add("csp-directive_hidden");
|
| + this.classList.add("directive-is-hidden");
|
| + };
|
| + /**
|
| + * @this {Element}
|
| + */
|
| + heading.showSection = function () {
|
| + contentSecurityPolicySection
|
| + .querySelector(`.csp-rule-list-${policy.name}`)
|
| + .classList
|
| + .remove("csp-directive_hidden");
|
| + this.classList.remove("directive-is-hidden");
|
| + };
|
| + heading.addEventListener("click", event => {
|
| + if (event.target.toggleSection)
|
| + event.target.toggleSection();
|
| + });
|
| + }
|
| +
|
| + originState.cspDetails.policies.forEach(createPolicySection);
|
| + }
|
| }
|
|
|
| WebInspector.SecurityOriginView.prototype = {
|
|
|