1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * HSTS is HTTPS Strict Transport Security: a way for sites to elect to always
7 * use HTTPS. See http://dev.chromium.org/sts
9 * This UI allows a user to query and update the browser's list of HSTS domains.
10 * It also allows users to query and update the browser's list of public key
14 var HSTSView
= (function() {
17 // We inherit from DivView.
18 var superClass
= DivView
;
24 assertFirstConstructorCall(HSTSView
);
26 // Call superclass's constructor.
27 superClass
.call(this, HSTSView
.MAIN_BOX_ID
);
29 this.addInput_
= $(HSTSView
.ADD_INPUT_ID
);
30 this.addStsCheck_
= $(HSTSView
.ADD_STS_CHECK_ID
);
31 this.addPkpCheck_
= $(HSTSView
.ADD_PKP_CHECK_ID
);
32 this.addPins_
= $(HSTSView
.ADD_PINS_ID
);
33 this.deleteInput_
= $(HSTSView
.DELETE_INPUT_ID
);
34 this.queryInput_
= $(HSTSView
.QUERY_INPUT_ID
);
35 this.queryOutputDiv_
= $(HSTSView
.QUERY_OUTPUT_DIV_ID
);
37 var form
= $(HSTSView
.ADD_FORM_ID
);
38 form
.addEventListener('submit', this.onSubmitAdd_
.bind(this), false);
40 form
= $(HSTSView
.DELETE_FORM_ID
);
41 form
.addEventListener('submit', this.onSubmitDelete_
.bind(this), false);
43 form
= $(HSTSView
.QUERY_FORM_ID
);
44 form
.addEventListener('submit', this.onSubmitQuery_
.bind(this), false);
46 g_browser
.addHSTSObserver(this);
49 HSTSView
.TAB_ID
= 'tab-handle-hsts';
50 HSTSView
.TAB_NAME
= 'HSTS';
51 HSTSView
.TAB_HASH
= '#hsts';
53 // IDs for special HTML elements in hsts_view.html
54 HSTSView
.MAIN_BOX_ID
= 'hsts-view-tab-content';
55 HSTSView
.ADD_INPUT_ID
= 'hsts-view-add-input';
56 HSTSView
.ADD_STS_CHECK_ID
= 'hsts-view-check-sts-input';
57 HSTSView
.ADD_PKP_CHECK_ID
= 'hsts-view-check-pkp-input';
58 HSTSView
.ADD_PINS_ID
= 'hsts-view-add-pins';
59 HSTSView
.ADD_FORM_ID
= 'hsts-view-add-form';
60 HSTSView
.ADD_SUBMIT_ID
= 'hsts-view-add-submit';
61 HSTSView
.DELETE_INPUT_ID
= 'hsts-view-delete-input';
62 HSTSView
.DELETE_FORM_ID
= 'hsts-view-delete-form';
63 HSTSView
.DELETE_SUBMIT_ID
= 'hsts-view-delete-submit';
64 HSTSView
.QUERY_INPUT_ID
= 'hsts-view-query-input';
65 HSTSView
.QUERY_OUTPUT_DIV_ID
= 'hsts-view-query-output';
66 HSTSView
.QUERY_FORM_ID
= 'hsts-view-query-form';
67 HSTSView
.QUERY_SUBMIT_ID
= 'hsts-view-query-submit';
69 cr
.addSingletonGetter(HSTSView
);
71 HSTSView
.prototype = {
72 // Inherit the superclass's methods.
73 __proto__
: superClass
.prototype,
75 onSubmitAdd_: function(event
) {
76 g_browser
.sendHSTSAdd(this.addInput_
.value
,
77 this.addStsCheck_
.checked
,
78 this.addPkpCheck_
.checked
,
80 g_browser
.sendHSTSQuery(this.addInput_
.value
);
81 this.queryInput_
.value
= this.addInput_
.value
;
82 this.addStsCheck_
.checked
= false;
83 this.addPkpCheck_
.checked
= false;
84 this.addInput_
.value
= '';
85 this.addPins_
.value
= '';
86 event
.preventDefault();
89 onSubmitDelete_: function(event
) {
90 g_browser
.sendHSTSDelete(this.deleteInput_
.value
);
91 this.deleteInput_
.value
= '';
92 event
.preventDefault();
95 onSubmitQuery_: function(event
) {
96 g_browser
.sendHSTSQuery(this.queryInput_
.value
);
97 event
.preventDefault();
100 onHSTSQueryResult: function(result
) {
101 if (result
.error
!= undefined) {
102 this.queryOutputDiv_
.innerHTML
= '';
103 var s
= addNode(this.queryOutputDiv_
, 'span');
104 s
.textContent
= result
.error
;
105 s
.style
.color
= '#e00';
106 yellowFade(this.queryOutputDiv_
);
110 if (result
.result
== false) {
111 this.queryOutputDiv_
.innerHTML
= '<b>Not found</b>';
112 yellowFade(this.queryOutputDiv_
);
116 this.queryOutputDiv_
.innerHTML
= '';
118 var s
= addNode(this.queryOutputDiv_
, 'span');
119 s
.innerHTML
= '<b>Found:</b><br/>';
122 'static_sts_domain', 'static_upgrade_mode',
123 'static_sts_include_subdomains', 'static_sts_observed',
124 'static_pkp_domain', 'static_pkp_include_subdomains',
125 'static_pkp_observed', 'static_spki_hashes', 'dynamic_sts_domain',
126 'dynamic_upgrade_mode', 'dynamic_sts_include_subdomains',
127 'dynamic_sts_observed', 'dynamic_pkp_domain',
128 'dynamic_pkp_include_subdomains', 'dynamic_pkp_observed',
129 'dynamic_spki_hashes',
132 var kStaticHashKeys
= [
133 'public_key_hashes', 'preloaded_spki_hashes', 'static_spki_hashes'
136 var staticHashes
= [];
137 for (var i
= 0; i
< kStaticHashKeys
.length
; ++i
) {
138 var staticHashValue
= result
[kStaticHashKeys
[i
]];
139 if (staticHashValue
!= undefined && staticHashValue
!= '')
140 staticHashes
.push(staticHashValue
);
143 for (var i
= 0; i
< keys
.length
; ++i
) {
145 var value
= result
[key
];
146 addTextNode(this.queryOutputDiv_
, ' ' + key
+ ': ');
148 // If there are no static_hashes, do not make it seem like there is a
149 // static PKP policy in place.
150 if (staticHashes
.length
== 0 && key
.indexOf('static_pkp_') == 0) {
151 addNode(this.queryOutputDiv_
, 'br');
155 if (key
=== 'static_spki_hashes') {
156 addNodeWithText(this.queryOutputDiv_
, 'tt', staticHashes
.join(','));
157 } else if (key
.indexOf('_upgrade_mode') >= 0) {
158 addNodeWithText(this.queryOutputDiv_
, 'tt', modeToString(value
));
160 addNodeWithText(this.queryOutputDiv_
, 'tt',
161 value
== undefined ? '' : value
);
163 addNode(this.queryOutputDiv_
, 'br');
166 yellowFade(this.queryOutputDiv_
);
170 function modeToString(m
) {
171 // These numbers must match those in
172 // TransportSecurityState::DomainState::UpgradeMode.
176 return 'OPPORTUNISTIC';
182 function yellowFade(element
) {
183 element
.style
.webkitTransitionProperty
= 'background-color';
184 element
.style
.webkitTransitionDuration
= '0';
185 element
.style
.backgroundColor
= '#fffccf';
186 setTimeout(function() {
187 element
.style
.webkitTransitionDuration
= '1000ms';
188 element
.style
.backgroundColor
= '#fff';