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']);
12 * A valid hash that can be set for a domain.
15 var VALID_HASH
= 'sha1/Guzek9lMwR3KeIS8wwS9gBvVtIg=';
18 * An invalid hash that can't be set for a domain.
21 var INVALID_HASH
= 'invalid';
24 * Possible results of an HSTS query.
27 var QueryResultType
= {
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
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
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}
51 function CheckQueryResultTask(domain
, stsSubdomains
, pkpSubdomains
,
52 stsObserved
, pkpObserved
, publicKeyHashes
,
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,
68 * Starts watching for the query results.
71 g_browser
.addHSTSObserver(this);
75 * Callback from the BrowserBridge. Validates |result| and completes the
77 * @param {object} result Results from the query.
79 onHSTSQueryResult: function(result
) {
80 // Ignore results after |this| is finished.
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
);
91 this.checkSuccess_(result
);
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);
102 * On errors, checks the result.
103 * @param {object} result Results from the query.
105 checkError_: function(result
) {
106 expectEquals(QueryResultType
.ERROR
, this.queryResultType_
);
107 expectEquals(result
.error
, $(HSTSView
.QUERY_OUTPUT_DIV_ID
).innerText
);
111 * Checks the result when the entry was not found.
112 * @param {object} result Results from the query.
114 checkNotFound_: function(result
) {
115 expectEquals(QueryResultType
.NOT_FOUND
, this.queryResultType_
);
116 expectEquals('Not found', $(HSTSView
.QUERY_OUTPUT_DIV_ID
).innerText
);
120 * Checks successful results.
121 * @param {object} result Results from the query.
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
= '';
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_
));
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
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}
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
= '';
193 CheckQueryResultTask
.call(this, domain
, stsSubdomains
, pkpSubdomains
,
194 stsObserved
, pkpObserved
, publicKeyHashes
,
198 AddTask
.prototype = {
199 __proto__
: CheckQueryResultTask
.prototype,
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.
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);
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
219 * @extends {CheckQueryResultTask}
221 function QueryTask(domain
, stsSubdomains
, pkpSubdomains
, stsObserved
,
222 pkpObserved
, publicKeyHashes
, queryResultType
) {
223 CheckQueryResultTask
.call(this, domain
, stsSubdomains
, pkpSubdomains
,
224 stsObserved
, pkpObserved
, publicKeyHashes
,
228 QueryTask
.prototype = {
229 __proto__
: CheckQueryResultTask
.prototype,
232 * Fills out the query form, simulates a click to submit it, and starts
233 * listening for the results.
236 CheckQueryResultTask
.prototype.start
.call(this);
237 $(HSTSView
.QUERY_INPUT_ID
).value
= this.domain_
;
238 $(HSTSView
.QUERY_SUBMIT_ID
).click();
243 * Task that deletes a single domain, then queries the deleted domain to make
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}
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,
260 * Fills out the delete form and simulates a click to submit it. Then sends
264 $(HSTSView
.DELETE_INPUT_ID
).value
= this.domain_
;
265 $(HSTSView
.DELETE_SUBMIT_ID
).click();
266 QueryTask
.prototype.start
.call(this);
271 * Checks that querying a domain that was never added fails.
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
));
283 * Checks that querying a domain with an invalid name returns an error.
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
));
295 * Deletes a domain that was never added.
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
));
305 * Deletes a domain that returns an error on lookup.
307 TEST_F('NetInternalsTest', 'netInternalsHSTSViewDeleteError', function() {
308 NetInternalsTest
.switchToView('hsts');
309 taskQueue
= new NetInternalsTest
.TaskQueue(true);
310 taskQueue
.addTask(new DeleteTask('\u3024', QueryResultType
.ERROR
));
315 * Adds a domain and then deletes it.
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
));
328 * Tries to add a domain with an invalid name.
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
));
342 * Tries to add a domain with a name that errors out on lookup due to having
343 * non-ASCII characters in it.
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
));
355 * Adds a domain with an invalid hash.
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
));
368 * Adds the same domain twice in a row, modifying some values the second time.
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
));
383 * Adds two different domains and then deletes them.
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
));
405 })(); // Anonymous namespace