Home | History | Annotate | Download | only in net_internals
      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