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. 4 5 /** 6 * HSTS is HTTPS Strict Transport Security: a way for sites to elect to always 7 * use HTTPS. See http://dev.chromium.org/sts 8 * 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 11 * pins. 12 */ 13 14 var HSTSView = (function() { 15 'use strict'; 16 17 // We inherit from DivView. 18 var superClass = DivView; 19 20 /** 21 * @constructor 22 */ 23 function HSTSView() { 24 assertFirstConstructorCall(HSTSView); 25 26 // Call superclass's constructor. 27 superClass.call(this, HSTSView.MAIN_BOX_ID); 28 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); 36 37 var form = $(HSTSView.ADD_FORM_ID); 38 form.addEventListener('submit', this.onSubmitAdd_.bind(this), false); 39 40 form = $(HSTSView.DELETE_FORM_ID); 41 form.addEventListener('submit', this.onSubmitDelete_.bind(this), false); 42 43 form = $(HSTSView.QUERY_FORM_ID); 44 form.addEventListener('submit', this.onSubmitQuery_.bind(this), false); 45 46 g_browser.addHSTSObserver(this); 47 } 48 49 HSTSView.TAB_ID = 'tab-handle-hsts'; 50 HSTSView.TAB_NAME = 'HSTS'; 51 HSTSView.TAB_HASH = '#hsts'; 52 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'; 68 69 cr.addSingletonGetter(HSTSView); 70 71 HSTSView.prototype = { 72 // Inherit the superclass's methods. 73 __proto__: superClass.prototype, 74 75 onSubmitAdd_: function(event) { 76 g_browser.sendHSTSAdd(this.addInput_.value, 77 this.addStsCheck_.checked, 78 this.addPkpCheck_.checked, 79 this.addPins_.value); 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(); 87 }, 88 89 onSubmitDelete_: function(event) { 90 g_browser.sendHSTSDelete(this.deleteInput_.value); 91 this.deleteInput_.value = ''; 92 event.preventDefault(); 93 }, 94 95 onSubmitQuery_: function(event) { 96 g_browser.sendHSTSQuery(this.queryInput_.value); 97 event.preventDefault(); 98 }, 99 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 = 'red'; 106 yellowFade(this.queryOutputDiv_); 107 return; 108 } 109 110 if (result.result == false) { 111 this.queryOutputDiv_.innerHTML = '<b>Not found</b>'; 112 yellowFade(this.queryOutputDiv_); 113 return; 114 } 115 116 this.queryOutputDiv_.innerHTML = ''; 117 118 var s = addNode(this.queryOutputDiv_, 'span'); 119 s.innerHTML = '<b>Found</b>: mode: '; 120 121 var t = addNode(this.queryOutputDiv_, 'tt'); 122 t.textContent = modeToString(result.mode); 123 124 addTextNode(this.queryOutputDiv_, ' sts_include_subdomains:'); 125 126 t = addNode(this.queryOutputDiv_, 'tt'); 127 t.textContent = result.sts_subdomains; 128 129 addTextNode(this.queryOutputDiv_, ' pkp_include_subdomains:'); 130 131 t = addNode(this.queryOutputDiv_, 'tt'); 132 t.textContent = result.pkp_subdomains; 133 134 addTextNode(this.queryOutputDiv_, ' domain:'); 135 136 t = addNode(this.queryOutputDiv_, 'tt'); 137 t.textContent = result.domain; 138 139 addTextNode(this.queryOutputDiv_, ' pubkey_hashes:'); 140 141 t = addNode(this.queryOutputDiv_, 'tt'); 142 143 // |public_key_hashes| is an old synonym for what is now 144 // |preloaded_spki_hashes|, which in turn is a legacy synonym for 145 // |static_spki_hashes|. Look for all three, and also for 146 // |dynamic_spki_hashes|. 147 if (typeof result.public_key_hashes === 'undefined') 148 result.public_key_hashes = ''; 149 if (typeof result.preloaded_spki_hashes === 'undefined') 150 result.preloaded_spki_hashes = ''; 151 if (typeof result.static_spki_hashes === 'undefined') 152 result.static_spki_hashes = ''; 153 if (typeof result.dynamic_spki_hashes === 'undefined') 154 result.dynamic_spki_hashes = ''; 155 156 var hashes = []; 157 if (result.public_key_hashes) 158 hashes.push(result.public_key_hashes); 159 if (result.preloaded_spki_hashes) 160 hashes.push(result.preloaded_spki_hashes); 161 if (result.static_spki_hashes) 162 hashes.push(result.static_spki_hashes); 163 if (result.dynamic_spki_hashes) 164 hashes.push(result.dynamic_spki_hashes); 165 166 t.textContent = hashes.join(','); 167 yellowFade(this.queryOutputDiv_); 168 } 169 }; 170 171 function modeToString(m) { 172 // These numbers must match those in 173 // TransportSecurityState::DomainState::UpgradeMode. 174 if (m == 0) { 175 return 'STRICT'; 176 } else if (m == 1) { 177 return 'OPPORTUNISTIC'; 178 } else { 179 return 'UNKNOWN'; 180 } 181 } 182 183 function yellowFade(element) { 184 element.style.webkitTransitionProperty = 'background-color'; 185 element.style.webkitTransitionDuration = '0'; 186 element.style.backgroundColor = '#fffccf'; 187 setTimeout(function() { 188 element.style.webkitTransitionDuration = '1000ms'; 189 element.style.backgroundColor = '#fff'; 190 }, 0); 191 } 192 193 return HSTSView; 194 })(); 195