| OLD | NEW |
| 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 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR}); | 34 sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR}); |
| 35 return; | 35 return; |
| 36 } | 36 } |
| 37 var responseData = | 37 var responseData = |
| 38 makeEnrollResponseData(enrollChallenge, u2fVersion, | 38 makeEnrollResponseData(enrollChallenge, u2fVersion, |
| 39 'enrollData', info, 'browserData', browserData); | 39 'enrollData', info, 'browserData', browserData); |
| 40 var response = makeWebSuccessResponse(request, responseData); | 40 var response = makeWebSuccessResponse(request, responseData); |
| 41 sendResponseOnce(sentResponse, closeable, response, sendResponse); | 41 sendResponseOnce(sentResponse, closeable, response, sendResponse); |
| 42 } | 42 } |
| 43 | 43 |
| 44 function timeout() { |
| 45 sendErrorResponse({errorCode: ErrorCodes.TIMEOUT}); |
| 46 } |
| 47 |
| 44 var sender = createSenderFromMessageSender(messageSender); | 48 var sender = createSenderFromMessageSender(messageSender); |
| 45 if (!sender) { | 49 if (!sender) { |
| 46 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); | 50 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); |
| 47 return null; | 51 return null; |
| 48 } | 52 } |
| 49 | 53 |
| 50 var enroller = | 54 if (!isValidEnrollRequest(request, 'enrollChallenges', 'signData')) { |
| 51 validateEnrollRequest( | 55 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); |
| 52 sender, request, 'enrollChallenges', 'signData', | 56 return null; |
| 53 sendErrorResponse, sendSuccessResponse); | |
| 54 if (enroller) { | |
| 55 var registerRequests = request['enrollChallenges']; | |
| 56 var signRequests = getSignRequestsFromEnrollRequest(request, 'signData'); | |
| 57 closeable = /** @type {Closeable} */ (enroller); | |
| 58 enroller.doEnroll(registerRequests, signRequests, request['appId']); | |
| 59 } | 57 } |
| 58 |
| 59 var timeoutValueSeconds = getTimeoutValueFromRequest(request); |
| 60 // Attenuate watchdog timeout value less than the enroller's timeout, so the |
| 61 // watchdog only fires after the enroller could reasonably have called back, |
| 62 // not before. |
| 63 var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds( |
| 64 timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2); |
| 65 var watchdog = new WatchdogRequestHandler(watchdogTimeoutValueSeconds, |
| 66 timeout); |
| 67 var wrappedErrorCb = watchdog.wrapCallback(sendErrorResponse); |
| 68 var wrappedSuccessCb = watchdog.wrapCallback(sendSuccessResponse); |
| 69 |
| 70 var timer = createAttenuatedTimer( |
| 71 FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds); |
| 72 var logMsgUrl = request['logMsgUrl']; |
| 73 var enroller = new Enroller(timer, sender, wrappedErrorCb, wrappedSuccessCb, |
| 74 logMsgUrl); |
| 75 watchdog.setCloseable(/** @type {!Closeable} */ (enroller)); |
| 76 closeable = watchdog; |
| 77 |
| 78 var registerRequests = request['enrollChallenges']; |
| 79 var signRequests = getSignRequestsFromEnrollRequest(request, 'signData'); |
| 80 enroller.doEnroll(registerRequests, signRequests, request['appId']); |
| 81 |
| 60 return closeable; | 82 return closeable; |
| 61 } | 83 } |
| 62 | 84 |
| 63 /** | 85 /** |
| 64 * Handles a U2F enroll request. | 86 * Handles a U2F enroll request. |
| 65 * @param {MessageSender} messageSender The message sender. | 87 * @param {MessageSender} messageSender The message sender. |
| 66 * @param {Object} request The web page's enroll request. | 88 * @param {Object} request The web page's enroll request. |
| 67 * @param {Function} sendResponse Called back with the result of the enroll. | 89 * @param {Function} sendResponse Called back with the result of the enroll. |
| 68 * @return {Closeable} A handler object to be closed when the browser channel | 90 * @return {Closeable} A handler object to be closed when the browser channel |
| 69 * closes. | 91 * closes. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 86 sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR}); | 108 sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR}); |
| 87 return; | 109 return; |
| 88 } | 110 } |
| 89 var responseData = | 111 var responseData = |
| 90 makeEnrollResponseData(enrollChallenge, u2fVersion, | 112 makeEnrollResponseData(enrollChallenge, u2fVersion, |
| 91 'registrationData', info, 'clientData', browserData); | 113 'registrationData', info, 'clientData', browserData); |
| 92 var response = makeU2fSuccessResponse(request, responseData); | 114 var response = makeU2fSuccessResponse(request, responseData); |
| 93 sendResponseOnce(sentResponse, closeable, response, sendResponse); | 115 sendResponseOnce(sentResponse, closeable, response, sendResponse); |
| 94 } | 116 } |
| 95 | 117 |
| 118 function timeout() { |
| 119 sendErrorResponse({errorCode: ErrorCodes.TIMEOUT}); |
| 120 } |
| 121 |
| 96 var sender = createSenderFromMessageSender(messageSender); | 122 var sender = createSenderFromMessageSender(messageSender); |
| 97 if (!sender) { | 123 if (!sender) { |
| 98 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); | 124 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); |
| 99 return null; | 125 return null; |
| 100 } | 126 } |
| 101 | 127 |
| 102 var enroller = | 128 if (!isValidEnrollRequest(request, 'registerRequests', 'signRequests', |
| 103 validateEnrollRequest( | 129 'registeredKeys')) { |
| 104 sender, request, 'registerRequests', 'signRequests', | 130 sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); |
| 105 sendErrorResponse, sendSuccessResponse, 'registeredKeys'); | 131 return null; |
| 106 if (enroller) { | |
| 107 var registerRequests = request['registerRequests']; | |
| 108 var signRequests = getSignRequestsFromEnrollRequest(request, | |
| 109 'signRequests', 'registeredKeys'); | |
| 110 closeable = /** @type {Closeable} */ (enroller); | |
| 111 enroller.doEnroll(registerRequests, signRequests, request['appId']); | |
| 112 } | 132 } |
| 133 |
| 134 var timeoutValueSeconds = getTimeoutValueFromRequest(request); |
| 135 // Attenuate watchdog timeout value less than the enroller's timeout, so the |
| 136 // watchdog only fires after the enroller could reasonably have called back, |
| 137 // not before. |
| 138 var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds( |
| 139 timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2); |
| 140 var watchdog = new WatchdogRequestHandler(watchdogTimeoutValueSeconds, |
| 141 timeout); |
| 142 var wrappedErrorCb = watchdog.wrapCallback(sendErrorResponse); |
| 143 var wrappedSuccessCb = watchdog.wrapCallback(sendSuccessResponse); |
| 144 |
| 145 var timer = createAttenuatedTimer( |
| 146 FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds); |
| 147 var logMsgUrl = request['logMsgUrl']; |
| 148 var enroller = new Enroller(timer, sender, sendErrorResponse, |
| 149 sendSuccessResponse, logMsgUrl); |
| 150 watchdog.setCloseable(/** @type {!Closeable} */ (enroller)); |
| 151 closeable = watchdog; |
| 152 |
| 153 var registerRequests = request['registerRequests']; |
| 154 var signRequests = getSignRequestsFromEnrollRequest(request, |
| 155 'signRequests', 'registeredKeys'); |
| 156 enroller.doEnroll(registerRequests, signRequests, request['appId']); |
| 157 |
| 113 return closeable; | 158 return closeable; |
| 114 } | 159 } |
| 115 | 160 |
| 116 /** | 161 /** |
| 117 * Validates an enroll request using the given parameters. | |
| 118 * @param {WebRequestSender} sender The sender of the message. | |
| 119 * @param {Object} request The web page's enroll request. | |
| 120 * @param {string} enrollChallengesName The name of the enroll challenges value | |
| 121 * in the request. | |
| 122 * @param {string} signChallengesName The name of the sign challenges value in | |
| 123 * the request. | |
| 124 * @param {function(U2fError)} errorCb Error callback. | |
| 125 * @param {function(string, string, (string|undefined))} successCb Success | |
| 126 * callback. | |
| 127 * @param {string=} opt_registeredKeysName The name of the registered keys | |
| 128 * value in the request. | |
| 129 * @return {Enroller} Enroller object representing the request, if the request | |
| 130 * is valid, or null if the request is invalid. | |
| 131 */ | |
| 132 function validateEnrollRequest(sender, request, | |
| 133 enrollChallengesName, signChallengesName, errorCb, successCb, | |
| 134 opt_registeredKeysName) { | |
| 135 if (!isValidEnrollRequest(request, enrollChallengesName, | |
| 136 signChallengesName, opt_registeredKeysName)) { | |
| 137 errorCb({errorCode: ErrorCodes.BAD_REQUEST}); | |
| 138 return null; | |
| 139 } | |
| 140 | |
| 141 var timeoutValueSeconds = getTimeoutValueFromRequest(request); | |
| 142 var timer = createAttenuatedTimer( | |
| 143 FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds); | |
| 144 var logMsgUrl = request['logMsgUrl']; | |
| 145 var enroller = new Enroller(timer, sender, errorCb, successCb, logMsgUrl); | |
| 146 return enroller; | |
| 147 } | |
| 148 | |
| 149 /** | |
| 150 * Returns whether the request appears to be a valid enroll request. | 162 * Returns whether the request appears to be a valid enroll request. |
| 151 * @param {Object} request The request. | 163 * @param {Object} request The request. |
| 152 * @param {string} enrollChallengesName The name of the enroll challenges value | 164 * @param {string} enrollChallengesName The name of the enroll challenges value |
| 153 * in the request. | 165 * in the request. |
| 154 * @param {string} signChallengesName The name of the sign challenges value in | 166 * @param {string} signChallengesName The name of the sign challenges value in |
| 155 * the request. | 167 * the request. |
| 156 * @param {string=} opt_registeredKeysName The name of the registered keys | 168 * @param {string=} opt_registeredKeysName The name of the registered keys |
| 157 * value in the request. | 169 * value in the request. |
| 158 * @return {boolean} Whether the request appears valid. | 170 * @return {boolean} Whether the request appears valid. |
| 159 */ | 171 */ |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 * to the request to the handler if/when the user has done so. | 398 * to the request to the handler if/when the user has done so. |
| 387 * @private | 399 * @private |
| 388 */ | 400 */ |
| 389 Enroller.prototype.approveOrigin_ = function() { | 401 Enroller.prototype.approveOrigin_ = function() { |
| 390 var self = this; | 402 var self = this; |
| 391 FACTORY_REGISTRY.getApprovedOrigins() | 403 FACTORY_REGISTRY.getApprovedOrigins() |
| 392 .isApprovedOrigin(this.sender_.origin, this.sender_.tabId) | 404 .isApprovedOrigin(this.sender_.origin, this.sender_.tabId) |
| 393 .then(function(result) { | 405 .then(function(result) { |
| 394 if (self.done_) return; | 406 if (self.done_) return; |
| 395 if (!result) { | 407 if (!result) { |
| 396 // Origin not approved: fail the result. | 408 // Origin not approved: rather than give an explicit indication to |
| 397 self.notifyError_({errorCode: ErrorCodes.BAD_REQUEST}); | 409 // the web page, let a timeout occur. |
| 410 if (self.timer_.expired()) { |
| 411 self.notifyTimeout_(); |
| 412 return; |
| 413 } |
| 414 var newTimer = self.timer_.clone(self.notifyTimeout_.bind(self)); |
| 415 self.timer_.clearTimeout(); |
| 416 self.timer_ = newTimer; |
| 398 return; | 417 return; |
| 399 } | 418 } |
| 400 self.sendEnrollRequestToHelper_(); | 419 self.sendEnrollRequestToHelper_(); |
| 401 }); | 420 }); |
| 402 }; | 421 }; |
| 403 | 422 |
| 404 /** | 423 /** |
| 424 * Notifies the caller of a timeout error. |
| 425 * @private |
| 426 */ |
| 427 Enroller.prototype.notifyTimeout_ = function() { |
| 428 this.notifyError_({errorCode: ErrorCodes.TIMEOUT}); |
| 429 }; |
| 430 |
| 431 /** |
| 405 * Performs an enroll request with this instance's enroll and sign challenges, | 432 * Performs an enroll request with this instance's enroll and sign challenges, |
| 406 * by encoding them into a helper request and passing the resulting request to | 433 * by encoding them into a helper request and passing the resulting request to |
| 407 * the factory registry's helper. | 434 * the factory registry's helper. |
| 408 * @private | 435 * @private |
| 409 */ | 436 */ |
| 410 Enroller.prototype.sendEnrollRequestToHelper_ = function() { | 437 Enroller.prototype.sendEnrollRequestToHelper_ = function() { |
| 411 var encodedEnrollChallenges = | 438 var encodedEnrollChallenges = |
| 412 this.encodeEnrollChallenges_(this.enrollChallenges_, this.appId_); | 439 this.encodeEnrollChallenges_(this.enrollChallenges_, this.appId_); |
| 413 // If the request didn't contain a sign challenge, provide one. The value | 440 // If the request didn't contain a sign challenge, provide one. The value |
| 414 // doesn't matter. | 441 // doesn't matter. |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 // For U2F_V2, the challenge sent to the gnubby is modified to be the hash | 662 // For U2F_V2, the challenge sent to the gnubby is modified to be the hash |
| 636 // of the browser data. Include the browser data. | 663 // of the browser data. Include the browser data. |
| 637 browserData = this.browserData_[reply.version]; | 664 browserData = this.browserData_[reply.version]; |
| 638 } | 665 } |
| 639 | 666 |
| 640 this.notifySuccess_(/** @type {string} */ (reply.version), | 667 this.notifySuccess_(/** @type {string} */ (reply.version), |
| 641 /** @type {string} */ (reply.enrollData), | 668 /** @type {string} */ (reply.enrollData), |
| 642 browserData); | 669 browserData); |
| 643 } | 670 } |
| 644 }; | 671 }; |
| OLD | NEW |