зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1568974 - Adds error warning to certificate viewer. r=johannh,fluent-reviewers,flod
Differential Revision: https://phabricator.services.mozilla.com/D39531 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
93ddb7aece
Коммит
fe443d7006
|
@ -3645,6 +3645,10 @@ var BrowserOnClick = {
|
|||
let certsStringURL = certs.map(elem => `cert=${elem}`);
|
||||
certsStringURL = certsStringURL.join("&");
|
||||
let url = `about:certificate?${certsStringURL}`;
|
||||
let error = securityInfo.errorCodeString;
|
||||
if (error) {
|
||||
url = `${url}&error=${error}`;
|
||||
}
|
||||
openTrustedLinkIn(url, "tab", {
|
||||
triggeringPrincipal: browser.contentPrincipal,
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ var security = {
|
|||
viewCertHelper(window, cert);
|
||||
},
|
||||
|
||||
_getSecurityInfo() {
|
||||
async _getSecurityInfo() {
|
||||
// We don't have separate info for a frame, return null until further notice
|
||||
// (see bug 138479)
|
||||
if (!this.windowInfo.isTopWindow) {
|
||||
|
@ -56,9 +56,16 @@ var security = {
|
|||
Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT);
|
||||
var isInsecure = ui.state & Ci.nsIWebProgressListener.STATE_IS_INSECURE;
|
||||
var isEV = ui.state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
|
||||
var secInfo = ui.secInfo;
|
||||
|
||||
if (!isInsecure && secInfo) {
|
||||
let secInfo = await window.opener.gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getSecurityInfo();
|
||||
secInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
|
||||
let error = null;
|
||||
if (secInfo.errorCodeString) {
|
||||
error = secInfo.errorCodeString;
|
||||
}
|
||||
|
||||
if (secInfo) {
|
||||
var cert = secInfo.serverCert;
|
||||
var issuerName = cert.issuerOrganization || cert.issuerName;
|
||||
|
||||
|
@ -73,6 +80,7 @@ var security = {
|
|||
isEV,
|
||||
cert,
|
||||
certificateTransparency: undefined,
|
||||
error,
|
||||
};
|
||||
|
||||
var version;
|
||||
|
@ -132,6 +140,7 @@ var security = {
|
|||
isEV,
|
||||
cert: null,
|
||||
certificateTransparency: null,
|
||||
error,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -204,9 +213,9 @@ var security = {
|
|||
/**
|
||||
* Open the login manager window
|
||||
*/
|
||||
viewPasswords() {
|
||||
async viewPasswords() {
|
||||
LoginHelper.openPasswordManager(window, {
|
||||
filterString: this._getSecurityInfo().hostName,
|
||||
filterString: await this._getSecurityInfo().hostName,
|
||||
entryPoint: "pageinfo",
|
||||
});
|
||||
},
|
||||
|
@ -214,10 +223,11 @@ var security = {
|
|||
_cert: null,
|
||||
};
|
||||
|
||||
function securityOnLoad(uri, windowInfo) {
|
||||
async function securityOnLoad(uri, windowInfo) {
|
||||
security.init(uri, windowInfo);
|
||||
|
||||
var info = security._getSecurityInfo();
|
||||
var info = await security._getSecurityInfo();
|
||||
|
||||
if (
|
||||
!info ||
|
||||
(uri.scheme === "about" && !uri.spec.startsWith("about:certerror"))
|
||||
|
@ -276,6 +286,9 @@ function securityOnLoad(uri, windowInfo) {
|
|||
/* Manage the View Cert button*/
|
||||
var viewCert = document.getElementById("security-view-cert");
|
||||
if (info.cert) {
|
||||
if (info.error) {
|
||||
security.error = info.error;
|
||||
}
|
||||
security._cert = info.cert;
|
||||
viewCert.collapsed = false;
|
||||
} else {
|
||||
|
@ -384,21 +397,28 @@ function getCertificateChain(certChain, options = {}) {
|
|||
return certificates;
|
||||
}
|
||||
|
||||
function viewCertHelper(parent, cert) {
|
||||
async function viewCertHelper(parent, cert) {
|
||||
if (!cert) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("security.aboutcertificate.enabled")) {
|
||||
let ui = security._getSecurityUI();
|
||||
let securityInfo = ui.secInfo;
|
||||
let certChain = getCertificateChain(securityInfo.succeededCertChain);
|
||||
let securityInfo = await window.opener.gBrowser.selectedBrowser.browsingContext.currentWindowGlobal.getSecurityInfo();
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
|
||||
let certChain = securityInfo.succeededCertChain
|
||||
? securityInfo.succeededCertChain
|
||||
: securityInfo.failedCertChain;
|
||||
certChain = getCertificateChain(certChain);
|
||||
let certs = certChain.map(elem =>
|
||||
encodeURIComponent(elem.getBase64DERString())
|
||||
);
|
||||
let certsStringURL = certs.map(elem => `cert=${elem}`);
|
||||
certsStringURL = certsStringURL.join("&");
|
||||
let url = `about:certificate?${certsStringURL}`;
|
||||
if (security.error) {
|
||||
url = url + `&error=${security.error}`;
|
||||
}
|
||||
openTrustedLinkIn(url, "tab", {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
});
|
||||
|
|
|
@ -59,4 +59,16 @@ certificate-viewer-signature-scheme = Signature Scheme
|
|||
certificate-viewer-timestamp = Timestamp
|
||||
certificate-viewer-value = Value
|
||||
certificate-viewer-version = Version
|
||||
|
||||
## Error codes
|
||||
|
||||
certificate-viewer-warning-section-title = Warning
|
||||
certificate-viewer-sec-error-expired-certificate = This certificate has expired.
|
||||
certificate-viewer-ssl-error-bad-cert-domain = This certificate is not valid for this host.
|
||||
certificate-viewer-mozilla-pkix-error-self-signed-cert = This certificate is not trusted because it is self-signed.
|
||||
certificate-viewer-mozilla-pkix-error-key-pinning-failure = No trusted certificate chain could be constructed that matches the pinset.
|
||||
certificate-viewer-mozilla-pkix-error-mitm-detected = MITM software has been detected.
|
||||
certificate-viewer-sec-error-unknown-issuer = This certificate’s issuer is unknown.
|
||||
certificate-viewer-sec-error-revoked-certificate = Peer’s certificate has been revoked.
|
||||
certificate-viewer-sec-error-cert-signature-algorithm-disabled = The certificate is not trusted because it was signed using a signature algorithm that was disabled because that algorithm is not secure.
|
||||
certificate-viewer-business-category = Business Category
|
||||
|
|
|
@ -21,8 +21,9 @@
|
|||
<script defer="defer" type="module" src="chrome://global/content/certviewer/certviewer.js"></script>
|
||||
<script defer="defer" type="module" src="chrome://global/content/certviewer/components/info-group.js"></script>
|
||||
<script defer="defer" type="module" src="chrome://global/content/certviewer/components/info-item.js"></script>
|
||||
<script defer="defer" type="module" src="chrome://global/content/certviewer/components/certificate-section.js"></script>
|
||||
<script defer="defer" type="module" src="chrome://global/content/certviewer/components/warning-section.js"></script>
|
||||
<script defer="defer" type="module" src="chrome://global/content/certviewer/components/error-section.js"></script>
|
||||
<script defer="defer" type="module" src="chrome://global/content/certviewer/components/certificate-section.js"></script>
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" href="chrome://global/content/certviewer/certviewer.css">
|
||||
<title>about:certificate</title>
|
||||
|
@ -52,5 +53,13 @@
|
|||
<h1 class="title"></h1>
|
||||
<span class="error"></span>
|
||||
</template>
|
||||
|
||||
<template id="warning-section-template">
|
||||
<link rel="stylesheet" href="chrome://global/content/certviewer/components/warning-section.css">
|
||||
<div class="warning-container">
|
||||
<h2 class="warning-title" data-l10n-id="certificate-viewer-warning-section-title"></h1>
|
||||
<span class="warning-message"></span>
|
||||
</div>
|
||||
</template>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
import { parse } from "./certDecoder.js";
|
||||
import { pemToDER } from "./utils.js";
|
||||
|
||||
let errorCode;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async e => {
|
||||
let url = new URL(document.URL);
|
||||
let certInfo = url.searchParams.getAll("cert");
|
||||
|
@ -17,9 +19,71 @@ document.addEventListener("DOMContentLoaded", async e => {
|
|||
return;
|
||||
}
|
||||
certInfo = certInfo.map(cert => decodeURIComponent(cert));
|
||||
errorCode = url.searchParams.get("error");
|
||||
|
||||
await buildChain(certInfo);
|
||||
});
|
||||
|
||||
async function highlightErrorInfoItem(error) {
|
||||
let infoItems = [];
|
||||
switch (error) {
|
||||
case "SEC_ERROR_EXPIRED_CERTIFICATE":
|
||||
infoItems.push({
|
||||
group: "validity",
|
||||
infoItem: "not-after",
|
||||
});
|
||||
break;
|
||||
case "SSL_ERROR_BAD_CERT_DOMAIN":
|
||||
infoItems.push({
|
||||
group: "subject-name",
|
||||
infoItem: "common-name",
|
||||
});
|
||||
infoItems.push({
|
||||
group: "subject-alt-names",
|
||||
});
|
||||
break;
|
||||
case "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT":
|
||||
infoItems.push({
|
||||
group: "issuer-name",
|
||||
});
|
||||
break;
|
||||
case "SEC_ERROR_UNKNOWN_ISSUER":
|
||||
infoItems.push({
|
||||
group: "issuer-name",
|
||||
});
|
||||
break;
|
||||
case "SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED":
|
||||
infoItems.push({
|
||||
group: "embedded-scts",
|
||||
infoItem: "signature-algorithm",
|
||||
});
|
||||
break;
|
||||
case "MOZILLA_PKIX_ERROR_MITM_DETECTED":
|
||||
infoItems.push({
|
||||
group: "issuer-name",
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (infoItems.length) {
|
||||
customElements.whenDefined("info-group").then(() => {
|
||||
let certSection = document.querySelector("certificate-section");
|
||||
for (let i = 0; i < infoItems.length; i++) {
|
||||
let item = infoItems[i];
|
||||
let groupItem = certSection.shadowRoot.getElementById(item.group);
|
||||
if (item.infoItem) {
|
||||
let infoItem = groupItem.shadowRoot.querySelector(
|
||||
"." + item.infoItem
|
||||
);
|
||||
infoItem.classList.add("warning");
|
||||
} else {
|
||||
groupItem.classList.add("warning");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const updateSelectedItem = (() => {
|
||||
let state;
|
||||
return selectedItem => {
|
||||
|
@ -284,7 +348,14 @@ const adjustCertInformation = cert => {
|
|||
const render = async (certs, error) => {
|
||||
await customElements.whenDefined("certificate-section");
|
||||
const CertificateSection = customElements.get("certificate-section");
|
||||
document.querySelector("body").append(new CertificateSection(certs, error));
|
||||
if (errorCode) {
|
||||
document
|
||||
.querySelector("body")
|
||||
.append(new CertificateSection(certs, error, errorCode));
|
||||
highlightErrorInfoItem(errorCode);
|
||||
} else {
|
||||
document.querySelector("body").append(new CertificateSection(certs, error));
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,11 @@ h1 {
|
|||
display: contents;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid var(--in-content-box-border-color);
|
||||
}
|
||||
|
||||
.tab {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
import { updateSelectedItem } from "../certviewer.js";
|
||||
import { InfoGroup } from "./info-group.js";
|
||||
import { ErrorSection } from "./error-section.js";
|
||||
import { WarningSection } from "./warning-section.js";
|
||||
|
||||
class CertificateSection extends HTMLElement {
|
||||
constructor(certs, error) {
|
||||
constructor(certs, error, errorCode) {
|
||||
super();
|
||||
this.certs = certs;
|
||||
this.error = error;
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
@ -35,6 +37,10 @@ class CertificateSection extends HTMLElement {
|
|||
"certificate-viewer-certificate-section-title"
|
||||
);
|
||||
|
||||
if (this.errorCode) {
|
||||
this.shadowRoot.prepend(new WarningSection(this.errorCode));
|
||||
}
|
||||
|
||||
this.infoGroupContainer = this.shadowRoot.querySelector(".info-groups");
|
||||
|
||||
if (this.error) {
|
||||
|
|
|
@ -32,3 +32,7 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
:host(.warning) {
|
||||
border: 2px solid var(--yellow-50);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,13 @@ export class InfoGroup extends HTMLElement {
|
|||
let title = this.shadowRoot.querySelector(".info-group-title");
|
||||
title.textContent = this.item.sectionTitle;
|
||||
|
||||
// Adds an id with the section title's name, to make
|
||||
// it easier to find when highlighting errors.
|
||||
this.setAttribute(
|
||||
"id",
|
||||
this.item.sectionTitle.replace(/\s+/g, "-").toLowerCase()
|
||||
);
|
||||
|
||||
for (let i = 0; i < this.item.sectionItems.length; i++) {
|
||||
this.shadowRoot.append(new InfoItem(this.item.sectionItems[i]));
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ label {
|
|||
color: var(--in-content-text-color);
|
||||
font-weight: 700;
|
||||
font-size: 1em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
label:dir(rtl) {
|
||||
|
@ -26,3 +27,25 @@ label:dir(rtl) {
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:host(.warning) * {
|
||||
border: 2px solid var(--yellow-50);
|
||||
}
|
||||
|
||||
:host(.warning) label {
|
||||
border-right: 0;
|
||||
}
|
||||
:host(.warning) span {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
:host(.warning) label::after {
|
||||
content: "";
|
||||
display: inline;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 15px;
|
||||
border-top: 2px solid var(--yellow-50);
|
||||
border-bottom: 2px solid var(--yellow-50);
|
||||
top: -2px;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ export class InfoItem extends HTMLElement {
|
|||
.toLowerCase();
|
||||
label.setAttribute("data-l10n-id", "certificate-viewer-" + labelText);
|
||||
|
||||
this.classList.add(labelText);
|
||||
|
||||
let info = this.shadowRoot.querySelector(".info");
|
||||
info.textContent = this.item.info;
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.warning-container {
|
||||
background-image: url("chrome://browser/skin/cert-error.svg");
|
||||
background-position: left center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 30% 80%;
|
||||
display: grid;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 0;
|
||||
grid-template-columns: 30% 70%;
|
||||
}
|
||||
|
||||
.warning-title {
|
||||
margin: 5px 0;
|
||||
grid-column-start: 2;
|
||||
}
|
||||
|
||||
.warning-message {
|
||||
display: block;
|
||||
grid-column-start: 2;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
export class WarningSection extends HTMLElement {
|
||||
constructor(errorCode) {
|
||||
super();
|
||||
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
let template = document.getElementById("warning-section-template");
|
||||
let templateHtml = template.content.cloneNode(true);
|
||||
|
||||
this.attachShadow({ mode: "open" });
|
||||
|
||||
document.l10n.connectRoot(this.shadowRoot);
|
||||
|
||||
this.shadowRoot.appendChild(templateHtml);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
let warningMessage = this.errorCode.replace(/\s+/g, "-").toLowerCase();
|
||||
|
||||
let messageElement = this.shadowRoot.querySelector(".warning-message");
|
||||
warningMessage = warningMessage.replace(/_/g, "-");
|
||||
messageElement.setAttribute(
|
||||
"data-l10n-id",
|
||||
"certificate-viewer-" + warningMessage
|
||||
);
|
||||
}
|
||||
}
|
||||
customElements.define("warning-section", WarningSection);
|
|
@ -21,3 +21,5 @@ toolkit.jar:
|
|||
content/global/certviewer/pvutils_bundle.js (content/vendor/pvutils_bundle.js)
|
||||
content/global/certviewer/asn1js_bundle.js (content/vendor/asn1js_bundle.js)
|
||||
content/global/certviewer/pkijs_bundle.js (content/vendor/pkijs_bundle.js)
|
||||
content/global/certviewer/components/warning-section.css (content/components/warning-section.css)
|
||||
content/global/certviewer/components/warning-section.js (content/components/warning-section.js)
|
||||
|
|
Загрузка…
Ссылка в новой задаче