Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(584)

Side by Side Diff: chrome/browser/resources/cryptotoken/enroller.js

Issue 2939273002: DO NOT SUBMIT: what chrome/browser/resources/ could eventually look like with clang-format (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * @fileoverview Handles web page requests for gnubby enrollment. 6 * @fileoverview Handles web page requests for gnubby enrollment.
7 */ 7 */
8 8
9 'use strict'; 9 'use strict';
10 10
11 /** 11 /**
12 * Handles a U2F enroll request. 12 * Handles a U2F enroll request.
13 * @param {MessageSender} messageSender The message sender. 13 * @param {MessageSender} messageSender The message sender.
14 * @param {Object} request The web page's enroll request. 14 * @param {Object} request The web page's enroll request.
15 * @param {Function} sendResponse Called back with the result of the enroll. 15 * @param {Function} sendResponse Called back with the result of the enroll.
16 * @return {Closeable} A handler object to be closed when the browser channel 16 * @return {Closeable} A handler object to be closed when the browser channel
17 * closes. 17 * closes.
18 */ 18 */
19 function handleU2fEnrollRequest(messageSender, request, sendResponse) { 19 function handleU2fEnrollRequest(messageSender, request, sendResponse) {
20 var sentResponse = false; 20 var sentResponse = false;
21 var closeable = null; 21 var closeable = null;
22 22
23 function sendErrorResponse(error) { 23 function sendErrorResponse(error) {
24 var response = makeU2fErrorResponse(request, error.errorCode, 24 var response =
25 error.errorMessage); 25 makeU2fErrorResponse(request, error.errorCode, error.errorMessage);
26 sendResponseOnce(sentResponse, closeable, response, sendResponse); 26 sendResponseOnce(sentResponse, closeable, response, sendResponse);
27 } 27 }
28 28
29 function sendSuccessResponse(u2fVersion, info, clientData) { 29 function sendSuccessResponse(u2fVersion, info, clientData) {
30 var enrollChallenges = request['registerRequests']; 30 var enrollChallenges = request['registerRequests'];
31 var enrollChallenge = 31 var enrollChallenge =
32 findEnrollChallengeOfVersion(enrollChallenges, u2fVersion); 32 findEnrollChallengeOfVersion(enrollChallenges, u2fVersion);
33 if (!enrollChallenge) { 33 if (!enrollChallenge) {
34 sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR}); 34 sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
35 return; 35 return;
(...skipping 22 matching lines...) Expand all
58 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); 58 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
59 return null; 59 return null;
60 } 60 }
61 61
62 var timeoutValueSeconds = getTimeoutValueFromRequest(request); 62 var timeoutValueSeconds = getTimeoutValueFromRequest(request);
63 // Attenuate watchdog timeout value less than the enroller's timeout, so the 63 // Attenuate watchdog timeout value less than the enroller's timeout, so the
64 // watchdog only fires after the enroller could reasonably have called back, 64 // watchdog only fires after the enroller could reasonably have called back,
65 // not before. 65 // not before.
66 var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds( 66 var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds(
67 timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2); 67 timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2);
68 var watchdog = new WatchdogRequestHandler(watchdogTimeoutValueSeconds, 68 var watchdog =
69 timeout); 69 new WatchdogRequestHandler(watchdogTimeoutValueSeconds, timeout);
70 var wrappedErrorCb = watchdog.wrapCallback(sendErrorResponse); 70 var wrappedErrorCb = watchdog.wrapCallback(sendErrorResponse);
71 var wrappedSuccessCb = watchdog.wrapCallback(sendSuccessResponse); 71 var wrappedSuccessCb = watchdog.wrapCallback(sendSuccessResponse);
72 72
73 var timer = createAttenuatedTimer( 73 var timer = createAttenuatedTimer(
74 FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds); 74 FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds);
75 var logMsgUrl = request['logMsgUrl']; 75 var logMsgUrl = request['logMsgUrl'];
76 var enroller = new Enroller(timer, sender, sendErrorResponse, 76 var enroller = new Enroller(
77 sendSuccessResponse, logMsgUrl); 77 timer, sender, sendErrorResponse, sendSuccessResponse, logMsgUrl);
78 watchdog.setCloseable(/** @type {!Closeable} */ (enroller)); 78 watchdog.setCloseable(/** @type {!Closeable} */ (enroller));
79 closeable = watchdog; 79 closeable = watchdog;
80 80
81 var registerRequests = request['registerRequests']; 81 var registerRequests = request['registerRequests'];
82 var signRequests = getSignRequestsFromEnrollRequest(request); 82 var signRequests = getSignRequestsFromEnrollRequest(request);
83 enroller.doEnroll(registerRequests, signRequests, request['appId']); 83 enroller.doEnroll(registerRequests, signRequests, request['appId']);
84 84
85 return closeable; 85 return closeable;
86 } 86 }
87 87
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 175
176 /** 176 /**
177 * Makes a responseData object for the enroll request with the given parameters. 177 * Makes a responseData object for the enroll request with the given parameters.
178 * @param {EnrollChallenge} enrollChallenge The enroll challenge used to 178 * @param {EnrollChallenge} enrollChallenge The enroll challenge used to
179 * register. 179 * register.
180 * @param {string} u2fVersion Version of gnubby that enrolled. 180 * @param {string} u2fVersion Version of gnubby that enrolled.
181 * @param {string} registrationData The registration data. 181 * @param {string} registrationData The registration data.
182 * @param {string=} opt_clientData The client data, if available. 182 * @param {string=} opt_clientData The client data, if available.
183 * @return {Object} The responseData object. 183 * @return {Object} The responseData object.
184 */ 184 */
185 function makeEnrollResponseData(enrollChallenge, u2fVersion, registrationData, 185 function makeEnrollResponseData(
186 opt_clientData) { 186 enrollChallenge, u2fVersion, registrationData, opt_clientData) {
187 var responseData = {}; 187 var responseData = {};
188 responseData['registrationData'] = registrationData; 188 responseData['registrationData'] = registrationData;
189 // Echo the used challenge back in the reply. 189 // Echo the used challenge back in the reply.
190 for (var k in enrollChallenge) { 190 for (var k in enrollChallenge) {
191 responseData[k] = enrollChallenge[k]; 191 responseData[k] = enrollChallenge[k];
192 } 192 }
193 if (u2fVersion == 'U2F_V2') { 193 if (u2fVersion == 'U2F_V2') {
194 // For U2F_V2, the challenge sent to the gnubby is modified to be the 194 // For U2F_V2, the challenge sent to the gnubby is modified to be the
195 // hash of the client data. Include the client data. 195 // hash of the client data. Include the client data.
196 responseData['clientData'] = opt_clientData; 196 responseData['clientData'] = opt_clientData;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 */ 271 */
272 Enroller.DEFAULT_TIMEOUT_MILLIS = 30 * 1000; 272 Enroller.DEFAULT_TIMEOUT_MILLIS = 30 * 1000;
273 273
274 /** 274 /**
275 * Performs an enroll request with the given enroll and sign challenges. 275 * Performs an enroll request with the given enroll and sign challenges.
276 * @param {Array<EnrollChallenge>} enrollChallenges A set of enroll challenges. 276 * @param {Array<EnrollChallenge>} enrollChallenges A set of enroll challenges.
277 * @param {Array<SignChallenge>} signChallenges A set of sign challenges for 277 * @param {Array<SignChallenge>} signChallenges A set of sign challenges for
278 * existing enrollments for this user and appId. 278 * existing enrollments for this user and appId.
279 * @param {string=} opt_appId The app id for the entire request. 279 * @param {string=} opt_appId The app id for the entire request.
280 */ 280 */
281 Enroller.prototype.doEnroll = function(enrollChallenges, signChallenges, 281 Enroller.prototype.doEnroll = function(
282 opt_appId) { 282 enrollChallenges, signChallenges, opt_appId) {
283 /** @private {Array<EnrollChallenge>} */ 283 /** @private {Array<EnrollChallenge>} */
284 this.enrollChallenges_ = enrollChallenges; 284 this.enrollChallenges_ = enrollChallenges;
285 /** @private {Array<SignChallenge>} */ 285 /** @private {Array<SignChallenge>} */
286 this.signChallenges_ = signChallenges; 286 this.signChallenges_ = signChallenges;
287 /** @private {(string|undefined)} */ 287 /** @private {(string|undefined)} */
288 this.appId_ = opt_appId; 288 this.appId_ = opt_appId;
289 var self = this; 289 var self = this;
290 getTabIdWhenPossible(this.sender_).then(function() { 290 getTabIdWhenPossible(this.sender_)
291 if (self.done_) return; 291 .then(
292 self.approveOrigin_(); 292 function() {
293 }, function() { 293 if (self.done_)
294 self.close(); 294 return;
295 self.notifyError_({errorCode: ErrorCodes.BAD_REQUEST}); 295 self.approveOrigin_();
296 }); 296 },
297 function() {
298 self.close();
299 self.notifyError_({errorCode: ErrorCodes.BAD_REQUEST});
300 });
297 }; 301 };
298 302
299 /** 303 /**
300 * Ensures the user has approved this origin to use security keys, sending 304 * Ensures the user has approved this origin to use security keys, sending
301 * to the request to the handler if/when the user has done so. 305 * to the request to the handler if/when the user has done so.
302 * @private 306 * @private
303 */ 307 */
304 Enroller.prototype.approveOrigin_ = function() { 308 Enroller.prototype.approveOrigin_ = function() {
305 var self = this; 309 var self = this;
306 FACTORY_REGISTRY.getApprovedOrigins() 310 FACTORY_REGISTRY.getApprovedOrigins()
307 .isApprovedOrigin(this.sender_.origin, this.sender_.tabId) 311 .isApprovedOrigin(this.sender_.origin, this.sender_.tabId)
308 .then(function(result) { 312 .then(function(result) {
309 if (self.done_) return; 313 if (self.done_)
314 return;
310 if (!result) { 315 if (!result) {
311 // Origin not approved: rather than give an explicit indication to 316 // Origin not approved: rather than give an explicit indication to
312 // the web page, let a timeout occur. 317 // the web page, let a timeout occur.
313 // NOTE: if you are looking at this in a debugger, this line will 318 // NOTE: if you are looking at this in a debugger, this line will
314 // always be false since the origin of the debugger is different 319 // always be false since the origin of the debugger is different
315 // than origin of requesting page 320 // than origin of requesting page
316 if (self.timer_.expired()) { 321 if (self.timer_.expired()) {
317 self.notifyTimeout_(); 322 self.notifyTimeout_();
318 return; 323 return;
319 } 324 }
(...skipping 19 matching lines...) Expand all
339 * by encoding them into a helper request and passing the resulting request to 344 * by encoding them into a helper request and passing the resulting request to
340 * the factory registry's helper. 345 * the factory registry's helper.
341 * @private 346 * @private
342 */ 347 */
343 Enroller.prototype.sendEnrollRequestToHelper_ = function() { 348 Enroller.prototype.sendEnrollRequestToHelper_ = function() {
344 var encodedEnrollChallenges = 349 var encodedEnrollChallenges =
345 this.encodeEnrollChallenges_(this.enrollChallenges_, this.appId_); 350 this.encodeEnrollChallenges_(this.enrollChallenges_, this.appId_);
346 // If the request didn't contain a sign challenge, provide one. The value 351 // If the request didn't contain a sign challenge, provide one. The value
347 // doesn't matter. 352 // doesn't matter.
348 var defaultSignChallenge = ''; 353 var defaultSignChallenge = '';
349 var encodedSignChallenges = 354 var encodedSignChallenges = encodeSignChallenges(
350 encodeSignChallenges(this.signChallenges_, defaultSignChallenge, 355 this.signChallenges_, defaultSignChallenge, this.appId_);
351 this.appId_);
352 var request = { 356 var request = {
353 type: 'enroll_helper_request', 357 type: 'enroll_helper_request',
354 enrollChallenges: encodedEnrollChallenges, 358 enrollChallenges: encodedEnrollChallenges,
355 signData: encodedSignChallenges, 359 signData: encodedSignChallenges,
356 logMsgUrl: this.logMsgUrl_ 360 logMsgUrl: this.logMsgUrl_
357 }; 361 };
358 if (!this.timer_.expired()) { 362 if (!this.timer_.expired()) {
359 request.timeout = this.timer_.millisecondsUntilExpired() / 1000.0; 363 request.timeout = this.timer_.millisecondsUntilExpired() / 1000.0;
360 request.timeoutSeconds = this.timer_.millisecondsUntilExpired() / 1000.0; 364 request.timeoutSeconds = this.timer_.millisecondsUntilExpired() / 1000.0;
361 } 365 }
362 366
363 // Begin fetching/checking the app ids. 367 // Begin fetching/checking the app ids.
364 var enrollAppIds = []; 368 var enrollAppIds = [];
365 if (this.appId_) { 369 if (this.appId_) {
366 enrollAppIds.push(this.appId_); 370 enrollAppIds.push(this.appId_);
367 } 371 }
368 for (var i = 0; i < this.enrollChallenges_.length; i++) { 372 for (var i = 0; i < this.enrollChallenges_.length; i++) {
369 if (this.enrollChallenges_[i].hasOwnProperty('appId')) { 373 if (this.enrollChallenges_[i].hasOwnProperty('appId')) {
370 enrollAppIds.push(this.enrollChallenges_[i]['appId']); 374 enrollAppIds.push(this.enrollChallenges_[i]['appId']);
371 } 375 }
372 } 376 }
373 // Sanity check 377 // Sanity check
374 if (!enrollAppIds.length) { 378 if (!enrollAppIds.length) {
375 console.warn(UTIL_fmt('empty enroll app ids?')); 379 console.warn(UTIL_fmt('empty enroll app ids?'));
376 this.notifyError_({errorCode: ErrorCodes.BAD_REQUEST}); 380 this.notifyError_({errorCode: ErrorCodes.BAD_REQUEST});
377 return; 381 return;
378 } 382 }
379 var self = this; 383 var self = this;
380 this.checkAppIds_(enrollAppIds, function(result) { 384 this.checkAppIds_(enrollAppIds, function(result) {
381 if (self.done_) return; 385 if (self.done_)
386 return;
382 if (result) { 387 if (result) {
383 self.handler_ = FACTORY_REGISTRY.getRequestHelper().getHandler(request); 388 self.handler_ = FACTORY_REGISTRY.getRequestHelper().getHandler(request);
384 if (self.handler_) { 389 if (self.handler_) {
385 var helperComplete = 390 var helperComplete =
386 /** @type {function(HelperReply)} */ 391 /** @type {function(HelperReply)} */
387 (self.helperComplete_.bind(self)); 392 (self.helperComplete_.bind(self));
388 self.handler_.run(helperComplete); 393 self.handler_.run(helperComplete);
389 } else { 394 } else {
390 self.notifyError_({errorCode: ErrorCodes.OTHER_ERROR}); 395 self.notifyError_({errorCode: ErrorCodes.OTHER_ERROR});
391 } 396 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 return /** @type {EnrollHelperChallenge} */ (encodedChallenge); 432 return /** @type {EnrollHelperChallenge} */ (encodedChallenge);
428 }; 433 };
429 434
430 /** 435 /**
431 * Encodes the given enroll challenges using this enroller's state. 436 * Encodes the given enroll challenges using this enroller's state.
432 * @param {Array<EnrollChallenge>} enrollChallenges The enroll challenges. 437 * @param {Array<EnrollChallenge>} enrollChallenges The enroll challenges.
433 * @param {string=} opt_appId The app id for the entire request. 438 * @param {string=} opt_appId The app id for the entire request.
434 * @return {!Array<EnrollHelperChallenge>} The encoded enroll challenges. 439 * @return {!Array<EnrollHelperChallenge>} The encoded enroll challenges.
435 * @private 440 * @private
436 */ 441 */
437 Enroller.prototype.encodeEnrollChallenges_ = function(enrollChallenges, 442 Enroller.prototype.encodeEnrollChallenges_ = function(
438 opt_appId) { 443 enrollChallenges, opt_appId) {
439 var challenges = []; 444 var challenges = [];
440 for (var i = 0; i < enrollChallenges.length; i++) { 445 for (var i = 0; i < enrollChallenges.length; i++) {
441 var enrollChallenge = enrollChallenges[i]; 446 var enrollChallenge = enrollChallenges[i];
442 var version = enrollChallenge.version; 447 var version = enrollChallenge.version;
443 if (!version) { 448 if (!version) {
444 // Version is implicitly V1 if not specified. 449 // Version is implicitly V1 if not specified.
445 version = 'U2F_V1'; 450 version = 'U2F_V1';
446 } 451 }
447 452
448 if (version == 'U2F_V2') { 453 if (version == 'U2F_V2') {
449 var modifiedChallenge = {}; 454 var modifiedChallenge = {};
450 for (var k in enrollChallenge) { 455 for (var k in enrollChallenge) {
451 modifiedChallenge[k] = enrollChallenge[k]; 456 modifiedChallenge[k] = enrollChallenge[k];
452 } 457 }
453 // V2 enroll responses contain signatures over a browser data object, 458 // V2 enroll responses contain signatures over a browser data object,
454 // which we're constructing here. The browser data object contains, among 459 // which we're constructing here. The browser data object contains, among
455 // other things, the server challenge. 460 // other things, the server challenge.
456 var serverChallenge = enrollChallenge['challenge']; 461 var serverChallenge = enrollChallenge['challenge'];
457 var browserData = makeEnrollBrowserData( 462 var browserData = makeEnrollBrowserData(
458 serverChallenge, this.sender_.origin, this.sender_.tlsChannelId); 463 serverChallenge, this.sender_.origin, this.sender_.tlsChannelId);
459 // Replace the challenge with the hash of the browser data. 464 // Replace the challenge with the hash of the browser data.
460 modifiedChallenge['challenge'] = 465 modifiedChallenge['challenge'] =
461 B64_encode(sha256HashOfString(browserData)); 466 B64_encode(sha256HashOfString(browserData));
462 this.browserData_[version] = 467 this.browserData_[version] = B64_encode(UTIL_StringToBytes(browserData));
463 B64_encode(UTIL_StringToBytes(browserData));
464 challenges.push(Enroller.encodeEnrollChallenge_( 468 challenges.push(Enroller.encodeEnrollChallenge_(
465 /** @type {EnrollChallenge} */ (modifiedChallenge), opt_appId)); 469 /** @type {EnrollChallenge} */ (modifiedChallenge), opt_appId));
466 } else { 470 } else {
467 challenges.push( 471 challenges.push(
468 Enroller.encodeEnrollChallenge_(enrollChallenge, opt_appId)); 472 Enroller.encodeEnrollChallenge_(enrollChallenge, opt_appId));
469 } 473 }
470 } 474 }
471 return challenges; 475 return challenges;
472 }; 476 };
473 477
(...skipping 21 matching lines...) Expand all
495 * @param {function(boolean)} cb Called with the result of the check. 499 * @param {function(boolean)} cb Called with the result of the check.
496 * @param {boolean} result Whether the origin could claim the app ids. 500 * @param {boolean} result Whether the origin could claim the app ids.
497 * @private 501 * @private
498 */ 502 */
499 Enroller.prototype.originChecked_ = function(appIds, cb, result) { 503 Enroller.prototype.originChecked_ = function(appIds, cb, result) {
500 if (!result) { 504 if (!result) {
501 this.notifyError_({errorCode: ErrorCodes.BAD_REQUEST}); 505 this.notifyError_({errorCode: ErrorCodes.BAD_REQUEST});
502 return; 506 return;
503 } 507 }
504 var appIdChecker = FACTORY_REGISTRY.getAppIdCheckerFactory().create(); 508 var appIdChecker = FACTORY_REGISTRY.getAppIdCheckerFactory().create();
505 appIdChecker. 509 appIdChecker
506 checkAppIds( 510 .checkAppIds(
507 this.timer_.clone(), this.sender_.origin, appIds, this.allowHttp_, 511 this.timer_.clone(), this.sender_.origin, appIds, this.allowHttp_,
508 this.logMsgUrl_) 512 this.logMsgUrl_)
509 .then(cb); 513 .then(cb);
510 }; 514 };
511 515
512 /** Closes this enroller. */ 516 /** Closes this enroller. */
513 Enroller.prototype.close = function() { 517 Enroller.prototype.close = function() {
514 if (this.handler_) { 518 if (this.handler_) {
515 this.handler_.close(); 519 this.handler_.close();
516 this.handler_ = null; 520 this.handler_ = null;
(...skipping 14 matching lines...) Expand all
531 this.errorCb_(error); 535 this.errorCb_(error);
532 }; 536 };
533 537
534 /** 538 /**
535 * Notifies the caller of success with the provided response data. 539 * Notifies the caller of success with the provided response data.
536 * @param {string} u2fVersion Protocol version 540 * @param {string} u2fVersion Protocol version
537 * @param {string} info Response data 541 * @param {string} info Response data
538 * @param {string|undefined} opt_browserData Browser data used 542 * @param {string|undefined} opt_browserData Browser data used
539 * @private 543 * @private
540 */ 544 */
541 Enroller.prototype.notifySuccess_ = 545 Enroller.prototype.notifySuccess_ = function(
542 function(u2fVersion, info, opt_browserData) { 546 u2fVersion, info, opt_browserData) {
543 if (this.done_) 547 if (this.done_)
544 return; 548 return;
545 this.close(); 549 this.close();
546 this.done_ = true; 550 this.done_ = true;
547 this.successCb_(u2fVersion, info, opt_browserData); 551 this.successCb_(u2fVersion, info, opt_browserData);
548 }; 552 };
549 553
550 /** 554 /**
551 * Called by the helper upon completion. 555 * Called by the helper upon completion.
552 * @param {EnrollHelperReply} reply The result of the enroll request. 556 * @param {EnrollHelperReply} reply The result of the enroll request.
553 * @private 557 * @private
554 */ 558 */
555 Enroller.prototype.helperComplete_ = function(reply) { 559 Enroller.prototype.helperComplete_ = function(reply) {
556 if (reply.code) { 560 if (reply.code) {
557 var reportedError = mapDeviceStatusCodeToU2fError(reply.code); 561 var reportedError = mapDeviceStatusCodeToU2fError(reply.code);
558 console.log(UTIL_fmt('helper reported ' + reply.code.toString(16) + 562 console.log(UTIL_fmt(
559 ', returning ' + reportedError.errorCode)); 563 'helper reported ' + reply.code.toString(16) + ', returning ' +
564 reportedError.errorCode));
560 this.notifyError_(reportedError); 565 this.notifyError_(reportedError);
561 } else { 566 } else {
562 console.log(UTIL_fmt('Gnubby enrollment succeeded!!!!!')); 567 console.log(UTIL_fmt('Gnubby enrollment succeeded!!!!!'));
563 var browserData; 568 var browserData;
564 569
565 if (reply.version == 'U2F_V2') { 570 if (reply.version == 'U2F_V2') {
566 // For U2F_V2, the challenge sent to the gnubby is modified to be the hash 571 // For U2F_V2, the challenge sent to the gnubby is modified to be the hash
567 // of the browser data. Include the browser data. 572 // of the browser data. Include the browser data.
568 browserData = this.browserData_[reply.version]; 573 browserData = this.browserData_[reply.version];
569 } 574 }
570 575
571 this.notifySuccess_(/** @type {string} */ (reply.version), 576 this.notifySuccess_(
572 /** @type {string} */ (reply.enrollData), 577 /** @type {string} */ (reply.version),
573 browserData); 578 /** @type {string} */ (reply.enrollData), browserData);
574 } 579 }
575 }; 580 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698