Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1246)

Unified Diff: Source/devtools/front_end/security/SecurityPanel.js

Issue 1301833003: Add origin views to the Security panel. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/devtools/front_end/security/SecurityPanel.js
diff --git a/Source/devtools/front_end/security/SecurityPanel.js b/Source/devtools/front_end/security/SecurityPanel.js
index 177a57d1c5e1420b2a55a6b601dc58f8ea2038bc..0009a7be72defaeed6ca13af97cc646858c762ac 100644
--- a/Source/devtools/front_end/security/SecurityPanel.js
+++ b/Source/devtools/front_end/security/SecurityPanel.js
@@ -7,7 +7,8 @@
* @extends {WebInspector.PanelWithSidebar}
* @implements {WebInspector.TargetManager.Observer}
*/
-WebInspector.SecurityPanel = function() {
+WebInspector.SecurityPanel = function()
+{
WebInspector.PanelWithSidebar.call(this, "security");
this.registerRequiredCSS("security/securityPanel.css");
this.registerRequiredCSS("security/lockIcon.css");
@@ -15,20 +16,24 @@ WebInspector.SecurityPanel = function() {
var sidebarTree = new TreeOutlineInShadow();
sidebarTree.element.classList.add("sidebar-tree");
this.panelSidebarElement().appendChild(sidebarTree.element);
+ sidebarTree.registerRequiredCSS("security/sidebar.css");
sidebarTree.registerRequiredCSS("security/lockIcon.css");
this.setDefaultFocusedElement(sidebarTree.element);
this._sidebarMainViewElement = new WebInspector.SecurityMainViewSidebarTreeElement(this);
sidebarTree.appendChild(this._sidebarMainViewElement);
+ // TODO(lgarron): Add a section for the main origin.
+ this._sidebarOriginSection = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("Origins"));
+ this._sidebarOriginSection.listItemElement.classList.add("security-sidebar-origins");
+ sidebarTree.appendChild(this._sidebarOriginSection);
+
this._mainView = new WebInspector.SecurityMainView();
- this.showMainView();
/** @type {!Map<string, !{securityState: !SecurityAgent.SecurityState, securityDetails: ?NetworkAgent.SecurityDetails}>} */
this._origins = new Map();
- WebInspector.targetManager.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._clear, this);
- WebInspector.targetManager.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._clear, this);
- WebInspector.targetManager.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._clear, this);
+ // TODO(lgarron): Until we can clear the panel properly (https://crbug.com/522762), don't trigger _clear().
+ // WebInspector.targetManager.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._clear, this);
dgozman 2015/08/21 19:44:36 Do not commit commented code. Better mention in co
lgarron 2015/08/21 21:50:06 I don't want to uncomment the MainFrameNavigated e
WebInspector.targetManager.observeTargets(this);
}
@@ -61,6 +66,25 @@ WebInspector.SecurityPanel.prototype = {
},
/**
+ * @param {!WebInspector.SecurityPanel.Origin} origin
+ */
+ showOrigin: function(origin)
+ {
+ var originData = this._origins.get(origin);
+ if (!originData.originView)
+ originData.originView = new WebInspector.SecurityOriginView(this, origin, originData.securityState, originData.securityDetails);
+
+ this._setVisibleView(originData.originView);
+ },
+
+ wasShown: function()
+ {
+ WebInspector.Panel.prototype.wasShown.call(this);
+ if (!this._visibleView)
+ this._sidebarMainViewElement.select();
+ },
+
+ /**
* @param {!WebInspector.VBox} view
*/
_setVisibleView: function(view)
@@ -88,7 +112,13 @@ WebInspector.SecurityPanel.prototype = {
if (this._origins.has(origin)) {
var originData = this._origins.get(origin);
- originData.securityState = this._securityStateMin(originData.securityState, securityState);
+ var oldSecurityState = originData.securityState;
+ originData.securityState = this._securityStateMin(oldSecurityState, securityState);
+ if (oldSecurityState != originData.securityState) {
+ originData.sidebarElement.setSecurityState(securityState);
+ if (originData.originView)
+ originData.originView.setSecurityState(securityState);
+ }
} else {
// TODO(lgarron): Store a (deduplicated) list of different security details we have seen.
var originData = {};
@@ -97,6 +127,12 @@ WebInspector.SecurityPanel.prototype = {
originData.securityDetails = data.securityDetails;
this._origins.set(origin, originData);
+
+ originData.sidebarElement = new WebInspector.SecurityOriginViewSidebarTreeElement(this, origin);
+ this._sidebarOriginSection.appendChild(originData.sidebarElement)
dgozman 2015/08/21 19:44:37 nit: semicolon
lgarron 2015/08/21 21:50:06 Done.
+ originData.sidebarElement.setSecurityState(securityState);
+
+ // Don't construct the origin view yet (let it happen lazily).
}
},
@@ -148,6 +184,8 @@ WebInspector.SecurityPanel.prototype = {
_clear: function()
{
this._updateSecurityState(SecurityAgent.SecurityState.Unknown, []);
+ this._sidebarMainViewElement.select();
+ this._sidebarOriginSection.removeChildren();
this._origins.clear();
},
@@ -164,6 +202,9 @@ WebInspector.SecurityPanel._instance = function()
return WebInspector.SecurityPanel._instanceObject;
}
+/** @typedef {string} */
+WebInspector.SecurityPanel.Origin;
dgozman 2015/08/21 19:44:36 nit: move to the top (before SecurityPanel.prototy
lgarron 2015/08/21 21:50:06 Done.
+
/**
* @constructor
* @extends {WebInspector.SidebarTreeElement}
@@ -172,8 +213,7 @@ WebInspector.SecurityPanel._instance = function()
WebInspector.SecurityMainViewSidebarTreeElement = function(panel)
{
this._panel = panel;
- this.small = true;
- WebInspector.SidebarTreeElement.call(this, "security-sidebar-tree-item", WebInspector.UIString("Overview"));
+ WebInspector.SidebarTreeElement.call(this, "security-main-view-sidebar-tree-item", WebInspector.UIString("Overview"));
this.iconElement.classList.add("lock-icon");
}
@@ -210,6 +250,47 @@ WebInspector.SecurityMainViewSidebarTreeElement.prototype = {
/**
* @constructor
+ * @extends {WebInspector.SidebarTreeElement}
+ * @param {!WebInspector.SecurityPanel} panel
+ * @param {!WebInspector.SecurityPanel.Origin} origin
+ */
+WebInspector.SecurityOriginViewSidebarTreeElement = function(panel, origin)
+{
+ this._panel = panel;
+ this._origin = origin;
+ this.small = true
dgozman 2015/08/21 19:44:37 nit: semicolon
lgarron 2015/08/21 21:50:06 Done.
+ WebInspector.SidebarTreeElement.call(this, "security-sidebar-tree-item", WebInspector.UIString(origin));
dgozman 2015/08/21 19:44:37 Don't use UIString for origin. It's meant for stri
lgarron 2015/08/21 21:50:06 Okay. So on user-originated strings, we don't do a
dgozman 2015/08/24 21:44:54 Using |textContent| is safe, it's not like |innerH
lgarron 2015/08/24 23:42:16 Cool, that matches what I expect. :-)
+ this.iconElement.classList.add("security-property");
+}
+
+WebInspector.SecurityOriginViewSidebarTreeElement.prototype = {
+ /**
+ * @override
+ * @return {boolean}
+ */
+ onselect: function()
+ {
+ this._panel.showOrigin(this._origin);
+ return true;
+ },
+
+ /**
+ * @param {!SecurityAgent.SecurityState} newSecurityState
+ */
+ setSecurityState: function(newSecurityState)
+ {
+ for (var className of this.iconElement.classList)
dgozman 2015/08/21 19:44:37 nit: use {} for more-than-one-liners
lgarron 2015/08/21 21:50:06 :-D (Done.)
+ if (className.indexOf("security-property-") === 0)
dgozman 2015/08/21 19:44:37 startsWith
lgarron 2015/08/21 21:50:06 Done.
+ this.iconElement.classList.remove(className);
dgozman 2015/08/21 19:44:37 Removing while iterating could be dangerous. Make
lgarron 2015/08/21 21:50:06 Done.
+
+ this.iconElement.classList.add("security-property-" + newSecurityState);
+ },
+
+ __proto__: WebInspector.SidebarTreeElement.prototype
+}
+
+/**
+ * @constructor
* @implements {WebInspector.PanelFactory}
*/
WebInspector.SecurityPanelFactory = function()
@@ -257,8 +338,8 @@ WebInspector.SecurityMainView.prototype = {
var explanationLockIcon = explanationDiv.createChild("div", "lock-icon");
explanationLockIcon.classList.add("lock-icon-" + explanation.securityState);
- explanationDiv.createChild("div", "explanation-title").textContent = explanation.summary;
- explanationDiv.createChild("div", "explanation-text").textContent = explanation.description;
+ explanationDiv.createChild("div", "explanation-title").textContent = WebInspector.UIString(explanation.summary);
+ explanationDiv.createChild("div", "explanation-text").textContent = WebInspector.UIString(explanation.description);
},
/**
@@ -283,3 +364,120 @@ WebInspector.SecurityMainView.prototype = {
__proto__: WebInspector.VBox.prototype
}
+
+/**
+ * @constructor
+ * @extends {WebInspector.VBox}
+ */
+WebInspector.SecurityOriginView = function(panel, origin, securityState, securityDetails)
dgozman 2015/08/21 19:44:37 - JSDoc for params; - why pass securityState and d
lgarron 2015/08/21 21:50:06 JSDoc: Done. Why pass? I wanted to keep all the b
+{
+ this._panel = panel;
+ WebInspector.VBox.call(this);
+ this.setMinimumSize(200, 100);
+
+ this.element.classList.add("security-origin-view");
+ this.registerRequiredCSS("security/originView.css");
+ this.registerRequiredCSS("security/lockIcon.css");
+
+ var titleSection = this.element.createChild("div", "origin-view-section title-section");
+ titleSection.createChild("h1").textContent = WebInspector.UIString("Origin");
+ var originDisplay = titleSection.createChild("div", "origin-display");
+ this._originLockIcon = originDisplay.createChild("span", "security-property");
+ this._originLockIcon.classList.add("security-property-" + securityState);
+ // TODO(lgarron): Highlight the origin scheme.
+ originDisplay.createChild("span", "origin").textContent = WebInspector.UIString(origin);
+
+ if (securityDetails && securityDetails.certificateDetails) {
+ var connectionSection = this.element.createChild("div", "origin-view-section");
+ connectionSection.createChild("h2").textContent = "Connection";
+
+ var table = connectionSection.createChild("table", "details-table");
+ this._addTableRow(table, "Protocol", securityDetails.protocol);
+ this._addTableRow(table, "Cipher Suite", securityDetails.cipher + (securityDetails.mac ? " with " + securityDetails.mac : ""));
+ this._addTableRow(table, "Key Exchange", securityDetails.keyExchange);
+ }
+
+ if (securityDetails) {
+ var certificateSection = this.element.createChild("div", "origin-view-section");
+ certificateSection.createChild("h2").textContent = "Certificate";
+
+ var sanDiv = this._createSanDiv(securityDetails);
+ var validFromString = new Date(1000 * securityDetails.certificateDetails.validFrom).toUTCString();
+ var validUntilString = new Date(1000 * securityDetails.certificateDetails.validTo).toUTCString();
+
+ var table = certificateSection.createChild("table", "details-table");
+ this._addTableRow(table, "Subject", securityDetails.certificateDetails.subject.name);
+ this._addTableRow(table, "SAN", sanDiv);
+ this._addTableRow(table, "Valid From", validFromString);
+ this._addTableRow(table, "Valid Until", validUntilString);
+ this._addTableRow(table, "Issuer", securityDetails.certificateDetails.issuer);
+ // TODO(lgarron): Make SCT status available in certificate details and show it here.
+
+ // TODO(lgarron): Implement a link to get certificateDetails
+
+ var noteSection = this.element.createChild("div", "origin-view-section");
+ noteSection.createChild("h2").textContent = "Development Note";
+ // TODO(lgarron): Fix the issue and then remove this section. See comment in _onResponseReceivedSecurityDetails
+ noteSection.createChild("div").textContent = WebInspector.UIString("At the moment, this view only shows security details from the first connection made to %s", origin);
+ }
+
+ if (!securityDetails) {
+ var notSecureSection = this.element.createChild("div", "origin-view-section");
+ notSecureSection.createChild("h2").textContent = "Not Secure";
+ notSecureSection.createChild("div").textContent = WebInspector.UIString("Your connection to this origin is not secure.");
+ }
+}
+
+WebInspector.SecurityOriginView.prototype = {
+ /**
+ * @param {!Element} table
+ * @param {string} key
+ * @param {string|!HTMLDivElement} value
+ */
+ _addTableRow: function(table, key, value)
+ {
+ var row = table.createChild("tr");
+ row.createChild("td").textContent = WebInspector.UIString(key);
+
+ var valueTd = row.createChild("td");
+ if (value instanceof HTMLDivElement) {
+ valueTd.appendChild(value);
+ } else {
+ valueTd.textContent = WebInspector.UIString(value);
+ }
+ },
+
+ /**
+ * @param {!NetworkAgent.SecurityDetails} securityDetails
+ * *return {!Element}
+ */
+ _createSanDiv: function(securityDetails)
+ {
+ // TODO(lgarron): Truncate the display of SAN entries and add a button to toggle the full list.
+ var sanDiv = createElement("div");
+ var sanList = securityDetails.certificateDetails.subject.sanDnsNames.concat(securityDetails.certificateDetails.subject.sanIpAddresses);
+ if (sanList.length === 0) {
+ sanDiv.textContent = WebInspector.UIString("(N/A)");
+ } else {
+ for (var sanEntry of sanList) {
+ var span = sanDiv.createChild("span", "san-entry");
+ span.textContent = WebInspector.UIString(sanEntry);
+ }
+ }
+ return sanDiv;
+ },
+
+ /**
+ * @param {!SecurityAgent.SecurityState} newSecurityState
+ */
+ setSecurityState: function(newSecurityState)
+ {
+ for (var className of this._originLockIcon.classList)
+ if (className.indexOf("security-property-") === 0)
+ this._originLockIcon.classList.remove(className);
+
+ this._originLockIcon.classList.add("security-property-" + newSecurityState);
+ },
+
+ __proto__: WebInspector.VBox.prototype
+}

Powered by Google App Engine
This is Rietveld 408576698