blob: ba1258e0f9e6bb2ee8bd4354bed18a4ebc428050 [file] [log] [blame]
// Copyright (c) 2012 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.
/**
* This UI allows a user to query and update the browser's list of per-domain
* security policies. These policies include:
* - HSTS: HTTPS Strict Transport Security. A way for sites to elect to always
* use HTTPS. See http://dev.chromium.org/sts
* - Expect-CT. A way for sites to elect to always require valid Certificate
* Transparency information to be present. See
* https://tools.ietf.org/html/draft-ietf-httpbis-expect-ct-01
*/
var DomainSecurityPolicyView = (function() {
'use strict';
// We inherit from DivView.
var superClass = DivView;
/**
* @constructor
*/
function DomainSecurityPolicyView() {
assertFirstConstructorCall(DomainSecurityPolicyView);
// Call superclass's constructor.
superClass.call(this, DomainSecurityPolicyView.MAIN_BOX_ID);
this.deleteInput_ = $(DomainSecurityPolicyView.DELETE_INPUT_ID);
this.addStsInput_ = $(DomainSecurityPolicyView.ADD_HSTS_INPUT_ID);
this.addStsCheck_ = $(DomainSecurityPolicyView.ADD_STS_CHECK_ID);
this.queryStsInput_ = $(DomainSecurityPolicyView.QUERY_HSTS_INPUT_ID);
this.queryStsOutputDiv_ =
$(DomainSecurityPolicyView.QUERY_HSTS_OUTPUT_DIV_ID);
this.addExpectCTInput_ = $(DomainSecurityPolicyView.ADD_EXPECT_CT_INPUT_ID);
this.addExpectCTReportUriInput_ =
$(DomainSecurityPolicyView.ADD_EXPECT_CT_REPORT_URI_INPUT_ID);
this.addExpectCTEnforceCheck_ =
$(DomainSecurityPolicyView.ADD_EXPECT_CT_ENFORCE_CHECK_ID);
this.queryExpectCTInput_ =
$(DomainSecurityPolicyView.QUERY_EXPECT_CT_INPUT_ID);
this.queryExpectCTOutputDiv_ =
$(DomainSecurityPolicyView.QUERY_EXPECT_CT_OUTPUT_DIV_ID);
this.testExpectCTReportInput_ =
$(DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_INPUT_ID);
this.testExpectCTOutputDiv_ =
$(DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_OUTPUT_DIV_ID);
var form = $(DomainSecurityPolicyView.DELETE_FORM_ID);
form.addEventListener('submit', this.onSubmitDelete_.bind(this), false);
form = $(DomainSecurityPolicyView.ADD_HSTS_FORM_ID);
form.addEventListener('submit', this.onSubmitHSTSAdd_.bind(this), false);
form = $(DomainSecurityPolicyView.QUERY_HSTS_FORM_ID);
form.addEventListener('submit', this.onSubmitHSTSQuery_.bind(this), false);
form = $(DomainSecurityPolicyView.ADD_EXPECT_CT_FORM_ID);
form.addEventListener(
'submit', this.onSubmitExpectCTAdd_.bind(this), false);
form = $(DomainSecurityPolicyView.QUERY_EXPECT_CT_FORM_ID);
form.addEventListener(
'submit', this.onSubmitExpectCTQuery_.bind(this), false);
form = $(DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_FORM_ID);
form.addEventListener(
'submit', this.onSubmitExpectCTTestReport_.bind(this), false);
g_browser.addHSTSObserver(this);
g_browser.addExpectCTObserver(this);
}
DomainSecurityPolicyView.TAB_ID = 'tab-handle-domain-security-policy';
DomainSecurityPolicyView.TAB_NAME = 'Domain Security Policy';
// This tab was originally limited to HSTS. Even though it now encompasses
// domain security policy more broadly, keep the hash as "#hsts" to preserve
// links/documentation that directs users to chrome://net-internals#hsts.
DomainSecurityPolicyView.TAB_HASH = '#hsts';
// IDs for special HTML elements in domain_security_policy_view.html
DomainSecurityPolicyView.MAIN_BOX_ID =
'domain-security-policy-view-tab-content';
DomainSecurityPolicyView.DELETE_INPUT_ID =
'domain-security-policy-view-delete-input';
DomainSecurityPolicyView.DELETE_FORM_ID =
'domain-security-policy-view-delete-form';
DomainSecurityPolicyView.DELETE_SUBMIT_ID =
'domain-security-policy-view-delete-submit';
// HSTS form elements
DomainSecurityPolicyView.ADD_HSTS_INPUT_ID = 'hsts-view-add-input';
DomainSecurityPolicyView.ADD_STS_CHECK_ID = 'hsts-view-check-sts-input';
DomainSecurityPolicyView.ADD_PINS_ID = 'hsts-view-add-pins';
DomainSecurityPolicyView.ADD_HSTS_FORM_ID = 'hsts-view-add-form';
DomainSecurityPolicyView.ADD_HSTS_SUBMIT_ID = 'hsts-view-add-submit';
DomainSecurityPolicyView.QUERY_HSTS_INPUT_ID = 'hsts-view-query-input';
DomainSecurityPolicyView.QUERY_HSTS_OUTPUT_DIV_ID = 'hsts-view-query-output';
DomainSecurityPolicyView.QUERY_HSTS_FORM_ID = 'hsts-view-query-form';
DomainSecurityPolicyView.QUERY_HSTS_SUBMIT_ID = 'hsts-view-query-submit';
// Expect-CT form elements
DomainSecurityPolicyView.ADD_EXPECT_CT_INPUT_ID = 'expect-ct-view-add-input';
DomainSecurityPolicyView.ADD_EXPECT_CT_REPORT_URI_INPUT_ID =
'expect-ct-view-add-report-uri-input';
DomainSecurityPolicyView.ADD_EXPECT_CT_ENFORCE_CHECK_ID =
'expect-ct-view-check-enforce-input';
DomainSecurityPolicyView.ADD_EXPECT_CT_FORM_ID = 'expect-ct-view-add-form';
DomainSecurityPolicyView.ADD_EXPECT_CT_SUBMIT_ID =
'expect-ct-view-add-submit';
DomainSecurityPolicyView.QUERY_EXPECT_CT_INPUT_ID =
'expect-ct-view-query-input';
DomainSecurityPolicyView.QUERY_EXPECT_CT_FORM_ID =
'expect-ct-view-query-form';
DomainSecurityPolicyView.QUERY_EXPECT_CT_SUBMIT_ID =
'expect-ct-view-query-submit';
DomainSecurityPolicyView.QUERY_EXPECT_CT_OUTPUT_DIV_ID =
'expect-ct-view-query-output';
DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_INPUT_ID =
'expect-ct-view-test-report-uri';
DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_FORM_ID =
'expect-ct-view-test-report-form';
DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_SUBMIT_ID =
'expect-ct-view-test-report-submit';
DomainSecurityPolicyView.TEST_REPORT_EXPECT_CT_OUTPUT_DIV_ID =
'expect-ct-view-test-report-output';
cr.addSingletonGetter(DomainSecurityPolicyView);
DomainSecurityPolicyView.prototype = {
// Inherit the superclass's methods.
__proto__: superClass.prototype,
onSubmitHSTSAdd_: function(event) {
g_browser.sendHSTSAdd(this.addStsInput_.value, this.addStsCheck_.checked);
g_browser.sendHSTSQuery(this.addStsInput_.value);
this.queryStsInput_.value = this.addStsInput_.value;
this.addStsCheck_.checked = false;
this.addStsInput_.value = '';
event.preventDefault();
},
onSubmitDelete_: function(event) {
g_browser.sendDomainSecurityPolicyDelete(this.deleteInput_.value);
this.deleteInput_.value = '';
event.preventDefault();
},
onSubmitHSTSQuery_: function(event) {
g_browser.sendHSTSQuery(this.queryStsInput_.value);
event.preventDefault();
},
onHSTSQueryResult: function(result) {
if (result.error != undefined) {
this.queryStsOutputDiv_.innerHTML = '';
var s = addNode(this.queryStsOutputDiv_, 'span');
s.textContent = result.error;
s.style.color = '#e00';
yellowFade(this.queryStsOutputDiv_);
return;
}
if (result.result == false) {
this.queryStsOutputDiv_.innerHTML = '<b>Not found</b>';
yellowFade(this.queryStsOutputDiv_);
return;
}
this.queryStsOutputDiv_.innerHTML = '';
var s = addNode(this.queryStsOutputDiv_, 'span');
s.innerHTML = '<b>Found:</b><br/>';
var keys = [
'static_sts_domain',
'static_upgrade_mode',
'static_sts_include_subdomains',
'static_sts_observed',
'static_pkp_domain',
'static_pkp_include_subdomains',
'static_pkp_observed',
'static_spki_hashes',
'dynamic_sts_domain',
'dynamic_upgrade_mode',
'dynamic_sts_include_subdomains',
'dynamic_sts_observed',
'dynamic_sts_expiry',
// TODO(crbug.com/779166): Remove these:
'dynamic_pkp_domain',
'dynamic_pkp_include_subdomains',
'dynamic_pkp_observed',
'dynamic_pkp_expiry',
'dynamic_spki_hashes',
];
var kStaticHashKeys =
['public_key_hashes', 'preloaded_spki_hashes', 'static_spki_hashes'];
var staticHashes = [];
for (var i = 0; i < kStaticHashKeys.length; ++i) {
var staticHashValue = result[kStaticHashKeys[i]];
if (staticHashValue != undefined && staticHashValue != '')
staticHashes.push(staticHashValue);
}
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var value = result[key];
addTextNode(this.queryStsOutputDiv_, ' ' + key + ': ');
// If there are no static_hashes, do not make it seem like there is a
// static PKP policy in place.
if (staticHashes.length == 0 && key.startsWith('static_pkp_')) {
addNode(this.queryStsOutputDiv_, 'br');
continue;
}
if (key === 'static_spki_hashes') {
addNodeWithText(
this.queryStsOutputDiv_, 'tt', staticHashes.join(','));
} else if (key.indexOf('_upgrade_mode') >= 0) {
addNodeWithText(this.queryStsOutputDiv_, 'tt', modeToString(value));
} else {
addNodeWithText(
this.queryStsOutputDiv_, 'tt', value == undefined ? '' : value);
}
addNode(this.queryStsOutputDiv_, 'br');
}
yellowFade(this.queryStsOutputDiv_);
},
onSubmitExpectCTAdd_: function(event) {
g_browser.sendExpectCTAdd(
this.addExpectCTInput_.value, this.addExpectCTReportUriInput_.value,
this.addExpectCTEnforceCheck_.checked);
g_browser.sendExpectCTQuery(this.addExpectCTInput_.value);
this.queryExpectCTInput_.value = this.addExpectCTInput_.value;
this.addExpectCTInput_.value = '';
this.addExpectCTReportUriInput_.value = '';
this.addExpectCTEnforceCheck_.checked = false;
event.preventDefault();
},
onSubmitExpectCTQuery_: function(event) {
g_browser.sendExpectCTQuery(this.queryExpectCTInput_.value);
event.preventDefault();
},
onExpectCTQueryResult: function(result) {
if (result.error != undefined) {
this.queryExpectCTOutputDiv_.innerHTML = '';
var s = addNode(this.queryExpectCTOutputDiv_, 'span');
s.textContent = result.error;
s.style.color = '#e00';
yellowFade(this.queryExpectCTOutputDiv_);
return;
}
if (result.result == false) {
this.queryExpectCTOutputDiv_.innerHTML = '<b>Not found</b>';
yellowFade(this.queryExpectCTOutputDiv_);
return;
}
this.queryExpectCTOutputDiv_.innerHTML = '';
var s = addNode(this.queryExpectCTOutputDiv_, 'span');
s.innerHTML = '<b>Found:</b><br/>';
var keys = [
'dynamic_expect_ct_domain',
'dynamic_expect_ct_observed',
'dynamic_expect_ct_expiry',
'dynamic_expect_ct_enforce',
'dynamic_expect_ct_report_uri',
];
for (var i in keys) {
var key = keys[i];
var value = result[key];
addTextNode(this.queryExpectCTOutputDiv_, ' ' + key + ': ');
addNodeWithText(
this.queryExpectCTOutputDiv_, 'tt',
value == undefined ? '' : value);
addNode(this.queryExpectCTOutputDiv_, 'br');
}
yellowFade(this.queryExpectCTOutputDiv_);
},
onSubmitExpectCTTestReport_: function(event) {
g_browser.sendExpectCTTestReport(this.testExpectCTReportInput_.value);
event.preventDefault();
},
onExpectCTTestReportResult: function(result) {
if (result == 'success') {
addTextNode(this.testExpectCTOutputDiv_, 'Test report succeeded');
} else {
addTextNode(this.testExpectCTOutputDiv_, 'Test report failed');
}
yellowFade(this.testExpectCTOutputDiv_);
},
};
function modeToString(m) {
// These numbers must match those in
// TransportSecurityState::STSState::UpgradeMode.
if (m == 0) {
return 'FORCE_HTTPS';
} else if (m == 1) {
return 'DEFAULT';
} else {
return 'UNKNOWN';
}
}
function yellowFade(element) {
element.style.transitionProperty = 'background-color';
element.style.transitionDuration = '0';
element.style.backgroundColor = '#fffccf';
setTimeout(function() {
element.style.transitionDuration = '1000ms';
element.style.backgroundColor = '#fff';
}, 0);
}
return DomainSecurityPolicyView;
})();