• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
14var 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 = '#e00';
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><br/>';
120
121      var keys = [
122        'domain', 'static_upgrade_mode', 'static_sts_include_subdomains',
123        'static_pkp_include_subdomains', 'static_sts_observed',
124        'static_pkp_observed', 'static_spki_hashes', 'dynamic_upgrade_mode',
125        'dynamic_sts_include_subdomains', 'dynamic_pkp_include_subdomains',
126        'dynamic_sts_observed', 'dynamic_pkp_observed', 'dynamic_spki_hashes'
127      ];
128
129      var kStaticHashKeys = [
130        'public_key_hashes', 'preloaded_spki_hashes', 'static_spki_hashes'
131      ];
132
133      var staticHashes = [];
134      for (var i = 0; i < kStaticHashKeys.length; ++i) {
135        var staticHashValue = result[kStaticHashKeys[i]];
136        if (staticHashValue != undefined && staticHashValue != '')
137          staticHashes.push(staticHashValue);
138      }
139
140      for (var i = 0; i < keys.length; ++i) {
141        var key = keys[i];
142        var value = result[key];
143        addTextNode(this.queryOutputDiv_, ' ' + key + ': ');
144
145        // If there are no static_hashes, do not make it seem like there is a
146        // static PKP policy in place.
147        if (staticHashes.length == 0 && key.indexOf('static_pkp_') == 0) {
148          addNode(this.queryOutputDiv_, 'br');
149          continue;
150        }
151
152        if (key === 'static_spki_hashes') {
153          addNodeWithText(this.queryOutputDiv_, 'tt', staticHashes.join(','));
154        } else if (key.indexOf('_upgrade_mode') >= 0) {
155          addNodeWithText(this.queryOutputDiv_, 'tt', modeToString(value));
156        } else {
157          addNodeWithText(this.queryOutputDiv_, 'tt',
158                          value == undefined ? '' : value);
159        }
160        addNode(this.queryOutputDiv_, 'br');
161      }
162
163      yellowFade(this.queryOutputDiv_);
164    }
165  };
166
167  function modeToString(m) {
168    // These numbers must match those in
169    // TransportSecurityState::DomainState::UpgradeMode.
170    if (m == 0) {
171      return 'STRICT';
172    } else if (m == 1) {
173      return 'OPPORTUNISTIC';
174    } else {
175      return 'UNKNOWN';
176    }
177  }
178
179  function yellowFade(element) {
180    element.style.webkitTransitionProperty = 'background-color';
181    element.style.webkitTransitionDuration = '0';
182    element.style.backgroundColor = '#fffccf';
183    setTimeout(function() {
184      element.style.webkitTransitionDuration = '1000ms';
185      element.style.backgroundColor = '#fff';
186    }, 0);
187  }
188
189  return HSTSView;
190})();
191