Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / test / data / webui / net_internals / hsts_view.js
blob414ee8485bbdceb5dc40809f4fc2404ce055400f
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.
5 // Include test fixture.
6 GEN_INCLUDE(['net_internals_test.js']);
8 // Anonymous namespace
9 (function() {
12  * A valid hash that can be set for a domain.
13  * @type {string}
14  */
15 var VALID_HASH = 'sha1/Guzek9lMwR3KeIS8wwS9gBvVtIg=';
18  * An invalid hash that can't be set for a domain.
19  * @type {string}
20  */
21 var INVALID_HASH = 'invalid';
24  * Possible results of an HSTS query.
25  * @enum {number}
26  */
27 var QueryResultType = {
28   SUCCESS: 0,
29   NOT_FOUND: 1,
30   ERROR: 2
33 /**
34  * A Task that waits for the results of an HSTS query.  Once the results are
35  * received, checks them before completing.  Does not initiate the query.
36  * @param {string} domain The domain expected in the returned results.
37  * @param {bool} stsSubdomains Whether or not the stsSubdomains flag is expected
38  *     to be set in the returned results.  Ignored on error and not found
39  *     results.
40  * @param {bool} pkpSubdomains Whether or not the pkpSubdomains flag is expected
41  *     to be set in the returned results.  Ignored on error and not found
42  *     results.
43  * @param {number} stsObserved The time the STS policy was observed.
44  * @param {number} pkpObserved The time the PKP policy was observed.
45  * @param {string} publicKeyHashes Expected public key hashes.  Ignored on error
46  *     error and not found results.
47  * @param {QueryResultType} queryResultType The expected result type of the
48  *     results of the query.
49  * @extends {NetInternalsTest.Task}
50  */
51 function CheckQueryResultTask(domain, stsSubdomains, pkpSubdomains,
52                               stsObserved, pkpObserved, publicKeyHashes,
53                               queryResultType) {
54   this.domain_ = domain;
55   this.stsSubdomains_ = stsSubdomains;
56   this.pkpSubdomains_ = pkpSubdomains;
57   this.stsObserved_ = stsObserved;
58   this.pkpObserved_ = pkpObserved;
59   this.publicKeyHashes_ = publicKeyHashes;
60   this.queryResultType_ = queryResultType;
61   NetInternalsTest.Task.call(this);
64 CheckQueryResultTask.prototype = {
65   __proto__: NetInternalsTest.Task.prototype,
67   /**
68    * Starts watching for the query results.
69    */
70   start: function() {
71     g_browser.addHSTSObserver(this);
72   },
74   /**
75    * Callback from the BrowserBridge.  Validates |result| and completes the
76    * task.
77    * @param {object} result Results from the query.
78    */
79   onHSTSQueryResult: function(result) {
80     // Ignore results after |this| is finished.
81     if (!this.isDone()) {
82       expectEquals(this.domain_, $(HSTSView.QUERY_INPUT_ID).value);
84       // Each case has its own validation function because of the design of the
85       // test reporting infrastructure.
86       if (result.error != undefined) {
87         this.checkError_(result);
88       } else if (!result.result) {
89         this.checkNotFound_(result);
90       } else {
91         this.checkSuccess_(result);
92       }
93       this.running_ = false;
95       // Start the next task asynchronously, so it can add another HSTS observer
96       // without getting the current result.
97       window.setTimeout(this.onTaskDone.bind(this), 1);
98     }
99   },
101   /**
102    * On errors, checks the result.
103    * @param {object} result Results from the query.
104    */
105   checkError_: function(result) {
106     expectEquals(QueryResultType.ERROR, this.queryResultType_);
107     expectEquals(result.error, $(HSTSView.QUERY_OUTPUT_DIV_ID).innerText);
108   },
110   /**
111    * Checks the result when the entry was not found.
112    * @param {object} result Results from the query.
113    */
114   checkNotFound_: function(result) {
115     expectEquals(QueryResultType.NOT_FOUND, this.queryResultType_);
116     expectEquals('Not found', $(HSTSView.QUERY_OUTPUT_DIV_ID).innerText);
117   },
119   /**
120    * Checks successful results.
121    * @param {object} result Results from the query.
122    */
123   checkSuccess_: function(result) {
124     expectEquals(QueryResultType.SUCCESS, this.queryResultType_);
125     expectEquals(this.stsSubdomains_, result.dynamic_sts_include_subdomains);
126     expectEquals(this.pkpSubdomains_, result.dynamic_pkp_include_subdomains);
127     // Disabled because of http://crbug.com/397639
128     // expectLE(this.stsObserved_, result.dynamic_sts_observed);
129     // expectLE(this.pkpObserved_, result.dynamic_pkp_observed);
131     // |public_key_hashes| is an old synonym for what is now
132     // |preloaded_spki_hashes|, which in turn is a legacy synonym for
133     // |static_spki_hashes|. Look for all three, and also for
134     // |dynamic_spki_hashes|.
135     if (typeof result.public_key_hashes === 'undefined')
136       result.public_key_hashes = '';
137     if (typeof result.preloaded_spki_hashes === 'undefined')
138       result.preloaded_spki_hashes = '';
139     if (typeof result.static_spki_hashes === 'undefined')
140       result.static_spki_hashes = '';
141     if (typeof result.dynamic_spki_hashes === 'undefined')
142       result.dynamic_spki_hashes = '';
144     var hashes = [];
145     if (result.public_key_hashes)
146       hashes.push(result.public_key_hashes);
147     if (result.preloaded_spki_hashes)
148       hashes.push(result.preloaded_spki_hashes);
149     if (result.static_spki_hashes)
150       hashes.push(result.static_spki_hashes);
151     if (result.dynamic_spki_hashes)
152       hashes.push(result.dynamic_spki_hashes);
154     expectEquals(this.publicKeyHashes_, hashes.join(','));
156     // Verify that the domain appears somewhere in the displayed text.
157     outputText = $(HSTSView.QUERY_OUTPUT_DIV_ID).innerText;
158     expectLE(0, outputText.search(this.domain_));
159   }
163  * A Task to try and add an HSTS domain via the HTML form. The task will wait
164  * until the results from the automatically sent query have been received, and
165  * then checks them against the expected values.
166  * @param {string} domain The domain to send and expected to be returned.
167  * @param {bool} stsSubdomains Whether the HSTS subdomain checkbox should be
168  *     selected. Also the corresponding expected return value, in the success
169  *     case.
170  * @param {bool} pkpSubdomains Whether the pinning subdomain checkbox should be
171  *     selected. Also the corresponding expected return value, in the success
172  *     case. When publicKeyHashes is INVALID_HASH, the corresponding key will
173  *     not be present in the result.
174  * @param {number} stsObserved The time the STS policy was observed.
175  * @param {number} pkpObserved The time the PKP policy was observed.
176  * @param {string} publicKeyHashes Public key hash to send.  Also the
177  *     corresponding expected return value, on success.  When this is the string
178  *     INVALID_HASH, an empty string is expected to be received instead.
179  * @param {QueryResultType} queryResultType Expected result type.
180  * @extends {CheckQueryResultTask}
181  */
182 function AddTask(domain, stsSubdomains, pkpSubdomains, publicKeyHashes,
183                  stsObserved, pkpObserved, queryResultType) {
184   this.requestedPublicKeyHashes_ = publicKeyHashes;
185   this.requestedPkpSubdomains_ = pkpSubdomains;
186   if (publicKeyHashes == INVALID_HASH || publicKeyHashes === '') {
187     // Although this tests with the pinning subdomain checkbox set, the
188     // pin itself is invalid, so no PKP entry will be stored. When queried,
189     // the key will not be present.
190     pkpSubdomains = undefined;
191     publicKeyHashes = '';
192   }
193   CheckQueryResultTask.call(this, domain, stsSubdomains, pkpSubdomains,
194                             stsObserved, pkpObserved, publicKeyHashes,
195                             queryResultType);
198 AddTask.prototype = {
199   __proto__: CheckQueryResultTask.prototype,
201   /**
202    * Fills out the add form, simulates a click to submit it, and starts
203    * listening for the results of the query that is automatically submitted.
204    */
205   start: function() {
206     $(HSTSView.ADD_INPUT_ID).value = this.domain_;
207     $(HSTSView.ADD_STS_CHECK_ID).checked = this.stsSubdomains_;
208     $(HSTSView.ADD_PKP_CHECK_ID).checked = this.requestedPkpSubdomains_;
209     $(HSTSView.ADD_PINS_ID).value = this.requestedPublicKeyHashes_;
210     $(HSTSView.ADD_SUBMIT_ID).click();
211     CheckQueryResultTask.prototype.start.call(this);
212   }
216  * A Task to query a domain and wait for the results.  Parameters mirror those
217  * of CheckQueryResultTask, except |domain| is also the name of the domain to
218  * query.
219  * @extends {CheckQueryResultTask}
220  */
221 function QueryTask(domain, stsSubdomains, pkpSubdomains, stsObserved,
222                    pkpObserved, publicKeyHashes, queryResultType) {
223   CheckQueryResultTask.call(this, domain, stsSubdomains, pkpSubdomains,
224                             stsObserved, pkpObserved, publicKeyHashes,
225                             queryResultType);
228 QueryTask.prototype = {
229   __proto__: CheckQueryResultTask.prototype,
231   /**
232    * Fills out the query form, simulates a click to submit it, and starts
233    * listening for the results.
234    */
235   start: function() {
236     CheckQueryResultTask.prototype.start.call(this);
237     $(HSTSView.QUERY_INPUT_ID).value = this.domain_;
238     $(HSTSView.QUERY_SUBMIT_ID).click();
239   }
243  * Task that deletes a single domain, then queries the deleted domain to make
244  * sure it's gone.
245  * @param {string} domain The domain to delete.
246  * @param {QueryResultType} queryResultType The result of the query.  Can be
247  *     QueryResultType.ERROR or QueryResultType.NOT_FOUND.
248  * @extends {QueryTask}
249  */
250 function DeleteTask(domain, queryResultType) {
251   expectNotEquals(queryResultType, QueryResultType.SUCCESS);
252   this.domain_ = domain;
253   QueryTask.call(this, domain, false, false, '', 0, 0, queryResultType);
256 DeleteTask.prototype = {
257   __proto__: QueryTask.prototype,
259   /**
260    * Fills out the delete form and simulates a click to submit it.  Then sends
261    * a query.
262    */
263   start: function() {
264     $(HSTSView.DELETE_INPUT_ID).value = this.domain_;
265     $(HSTSView.DELETE_SUBMIT_ID).click();
266     QueryTask.prototype.start.call(this);
267   }
271  * Checks that querying a domain that was never added fails.
272  */
273 TEST_F('NetInternalsTest', 'netInternalsHSTSViewQueryNotFound', function() {
274   NetInternalsTest.switchToView('hsts');
275   taskQueue = new NetInternalsTest.TaskQueue(true);
276   var now = new Date().getTime() / 1000.0;
277   taskQueue.addTask(new QueryTask('somewhere.com', false, false, now, now, '',
278                                   QueryResultType.NOT_FOUND));
279   taskQueue.run();
283  * Checks that querying a domain with an invalid name returns an error.
284  */
285 TEST_F('NetInternalsTest', 'netInternalsHSTSViewQueryError', function() {
286   NetInternalsTest.switchToView('hsts');
287   taskQueue = new NetInternalsTest.TaskQueue(true);
288   var now = new Date().getTime() / 1000.0;
289   taskQueue.addTask(new QueryTask('\u3024', false, false, now, now, '',
290                                   QueryResultType.ERROR));
291   taskQueue.run();
295  * Deletes a domain that was never added.
296  */
297 TEST_F('NetInternalsTest', 'netInternalsHSTSViewDeleteNotFound', function() {
298   NetInternalsTest.switchToView('hsts');
299   taskQueue = new NetInternalsTest.TaskQueue(true);
300   taskQueue.addTask(new DeleteTask('somewhere.com', QueryResultType.NOT_FOUND));
301   taskQueue.run();
305  * Deletes a domain that returns an error on lookup.
306  */
307 TEST_F('NetInternalsTest', 'netInternalsHSTSViewDeleteError', function() {
308   NetInternalsTest.switchToView('hsts');
309   taskQueue = new NetInternalsTest.TaskQueue(true);
310   taskQueue.addTask(new DeleteTask('\u3024', QueryResultType.ERROR));
311   taskQueue.run();
315  * Adds a domain and then deletes it.
316  */
317 TEST_F('NetInternalsTest', 'netInternalsHSTSViewAddDelete', function() {
318   NetInternalsTest.switchToView('hsts');
319   taskQueue = new NetInternalsTest.TaskQueue(true);
320   var now = new Date().getTime() / 1000.0;
321   taskQueue.addTask(new AddTask('somewhere.com', false, false, VALID_HASH,
322                                 now, now, QueryResultType.SUCCESS));
323   taskQueue.addTask(new DeleteTask('somewhere.com', QueryResultType.NOT_FOUND));
324   taskQueue.run();
328  * Tries to add a domain with an invalid name.
329  */
330 TEST_F('NetInternalsTest', 'netInternalsHSTSViewAddFail', function() {
331   NetInternalsTest.switchToView('hsts');
332   taskQueue = new NetInternalsTest.TaskQueue(true);
333   var now = new Date().getTime() / 1000.0;
334   taskQueue.addTask(new AddTask('0123456789012345678901234567890' +
335                                 '012345678901234567890123456789012345',
336                                 false, false, '', now, now,
337                                 QueryResultType.NOT_FOUND));
338   taskQueue.run();
342  * Tries to add a domain with a name that errors out on lookup due to having
343  * non-ASCII characters in it.
344  */
345 TEST_F('NetInternalsTest', 'netInternalsHSTSViewAddError', function() {
346   NetInternalsTest.switchToView('hsts');
347   taskQueue = new NetInternalsTest.TaskQueue(true);
348   var now = new Date().getTime() / 1000.0;
349   taskQueue.addTask(new AddTask('\u3024', false, false, '', now, now,
350                                 QueryResultType.ERROR));
351   taskQueue.run();
355  * Adds a domain with an invalid hash.
356  */
357 TEST_F('NetInternalsTest', 'netInternalsHSTSViewAddInvalidHash', function() {
358   NetInternalsTest.switchToView('hsts');
359   taskQueue = new NetInternalsTest.TaskQueue(true);
360   var now = new Date().getTime() / 1000.0;
361   taskQueue.addTask(new AddTask('somewhere.com', true, true, INVALID_HASH,
362                                 now, now, QueryResultType.SUCCESS));
363   taskQueue.addTask(new DeleteTask('somewhere.com', QueryResultType.NOT_FOUND));
364   taskQueue.run();
368  * Adds the same domain twice in a row, modifying some values the second time.
369  */
370 TEST_F('NetInternalsTest', 'netInternalsHSTSViewAddOverwrite', function() {
371   NetInternalsTest.switchToView('hsts');
372   taskQueue = new NetInternalsTest.TaskQueue(true);
373   var now = new Date().getTime() / 1000.0;
374   taskQueue.addTask(new AddTask('somewhere.com', true, true, VALID_HASH,
375                                 now, now, QueryResultType.SUCCESS));
376   taskQueue.addTask(new AddTask('somewhere.com', false, false, '',
377                                 now, now, QueryResultType.SUCCESS));
378   taskQueue.addTask(new DeleteTask('somewhere.com', QueryResultType.NOT_FOUND));
379   taskQueue.run();
383  * Adds two different domains and then deletes them.
384  */
385 TEST_F('NetInternalsTest', 'netInternalsHSTSViewAddTwice', function() {
386   NetInternalsTest.switchToView('hsts');
387   taskQueue = new NetInternalsTest.TaskQueue(true);
388   var now = new Date().getTime() / 1000.0;
389   taskQueue.addTask(new AddTask('somewhere.com', false, false, VALID_HASH,
390                                 now, now, QueryResultType.SUCCESS));
391   taskQueue.addTask(new QueryTask('somewhereelse.com', false, false, now, now,
392                                   '', QueryResultType.NOT_FOUND));
393   taskQueue.addTask(new AddTask('somewhereelse.com', true, false, '',
394                                 now, now, QueryResultType.SUCCESS));
395   taskQueue.addTask(new QueryTask('somewhere.com', false, false, now, now,
396                                   VALID_HASH, QueryResultType.SUCCESS));
397   taskQueue.addTask(new DeleteTask('somewhere.com', QueryResultType.NOT_FOUND));
398   taskQueue.addTask(new QueryTask('somewhereelse.com', true, undefined, now,
399                                   now, '', QueryResultType.SUCCESS));
400   taskQueue.addTask(new DeleteTask('somewhereelse.com',
401                                    QueryResultType.NOT_FOUND));
402   taskQueue.run(true);
405 })();  // Anonymous namespace