| 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 sign requests. | 6 * @fileoverview Handles web page requests for gnubby sign requests. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 'use strict'; | 9 'use strict'; |
| 10 | 10 |
| 11 var signRequestQueue = new OriginKeyedRequestQueue(); | 11 var signRequestQueue = new OriginKeyedRequestQueue(); |
| 12 | 12 |
| 13 /** | 13 /** |
| 14 * Handles a sign request. | 14 * Handles a sign request. |
| 15 * @param {!SignHelperFactory} factory Factory to create a sign helper. | 15 * @param {!SignHelperFactory} factory Factory to create a sign helper. |
| 16 * @param {MessageSender} sender The sender of the message. | 16 * @param {MessageSender} sender The sender of the message. |
| 17 * @param {Object} request The web page's sign request. | 17 * @param {Object} request The web page's sign request. |
| 18 * @param {boolean} enforceAppIdValid Whether to enforce that the app id in the | |
| 19 * request matches the sender's origin. | |
| 20 * @param {Function} sendResponse Called back with the result of the sign. | 18 * @param {Function} sendResponse Called back with the result of the sign. |
| 21 * @param {boolean} toleratesMultipleResponses Whether the sendResponse | 19 * @param {boolean} toleratesMultipleResponses Whether the sendResponse |
| 22 * callback can be called more than once, e.g. for progress updates. | 20 * callback can be called more than once, e.g. for progress updates. |
| 23 * @return {Closeable} Request handler that should be closed when the browser | 21 * @return {Closeable} Request handler that should be closed when the browser |
| 24 * message channel is closed. | 22 * message channel is closed. |
| 25 */ | 23 */ |
| 26 function handleSignRequest(factory, sender, request, enforceAppIdValid, | 24 function handleSignRequest(factory, sender, request, sendResponse, |
| 27 sendResponse, toleratesMultipleResponses) { | 25 toleratesMultipleResponses) { |
| 28 var sentResponse = false; | 26 var sentResponse = false; |
| 29 function sendResponseOnce(r) { | 27 function sendResponseOnce(r) { |
| 30 if (queuedSignRequest) { | 28 if (queuedSignRequest) { |
| 31 queuedSignRequest.close(); | 29 queuedSignRequest.close(); |
| 32 queuedSignRequest = null; | 30 queuedSignRequest = null; |
| 33 } | 31 } |
| 34 if (!sentResponse) { | 32 if (!sentResponse) { |
| 35 sentResponse = true; | 33 sentResponse = true; |
| 36 try { | 34 try { |
| 37 // If the page has gone away or the connection has otherwise gone, | 35 // If the page has gone away or the connection has otherwise gone, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 55 for (var k in challenge) { | 53 for (var k in challenge) { |
| 56 responseData[k] = challenge[k]; | 54 responseData[k] = challenge[k]; |
| 57 } | 55 } |
| 58 responseData['browserData'] = B64_encode(UTIL_StringToBytes(browserData)); | 56 responseData['browserData'] = B64_encode(UTIL_StringToBytes(browserData)); |
| 59 responseData['signatureData'] = info; | 57 responseData['signatureData'] = info; |
| 60 var response = formatWebPageResponse(GnubbyMsgTypes.SIGN_WEB_REPLY, | 58 var response = formatWebPageResponse(GnubbyMsgTypes.SIGN_WEB_REPLY, |
| 61 GnubbyCodeTypes.OK, responseData); | 59 GnubbyCodeTypes.OK, responseData); |
| 62 sendResponseOnce(response); | 60 sendResponseOnce(response); |
| 63 } | 61 } |
| 64 | 62 |
| 65 function sendNotification(code) { | |
| 66 console.log(UTIL_fmt('notification, code=' + code)); | |
| 67 // Can the callback handle progress updates? If so, send one. | |
| 68 if (toleratesMultipleResponses) { | |
| 69 var response = formatWebPageResponse( | |
| 70 GnubbyMsgTypes.SIGN_WEB_NOTIFICATION, code); | |
| 71 if (request['requestId']) { | |
| 72 response['requestId'] = request['requestId']; | |
| 73 } | |
| 74 sendResponse(response); | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 var origin = getOriginFromUrl(/** @type {string} */ (sender.url)); | 63 var origin = getOriginFromUrl(/** @type {string} */ (sender.url)); |
| 79 if (!origin) { | 64 if (!origin) { |
| 80 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); | 65 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); |
| 81 return null; | 66 return null; |
| 82 } | 67 } |
| 83 // More closure type inference fail. | 68 // More closure type inference fail. |
| 84 var nonNullOrigin = /** @type {string} */ (origin); | 69 var nonNullOrigin = /** @type {string} */ (origin); |
| 85 | 70 |
| 86 if (!isValidSignRequest(request)) { | 71 if (!isValidSignRequest(request)) { |
| 87 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); | 72 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); |
| 88 return null; | 73 return null; |
| 89 } | 74 } |
| 90 | 75 |
| 91 var signData = request['signData']; | 76 var signData = request['signData']; |
| 92 // A valid sign data has at least one challenge, so get the first appId from | 77 // A valid sign data has at least one challenge, so get the first appId from |
| 93 // the first challenge. | 78 // the first challenge. |
| 94 var firstAppId = signData[0]['appId']; | 79 var firstAppId = signData[0]['appId']; |
| 95 var timeoutMillis = Signer.DEFAULT_TIMEOUT_MILLIS; | 80 var timeoutMillis = Signer.DEFAULT_TIMEOUT_MILLIS; |
| 96 if (request['timeout']) { | 81 if (request['timeout']) { |
| 97 // Request timeout is in seconds. | 82 // Request timeout is in seconds. |
| 98 timeoutMillis = request['timeout'] * 1000; | 83 timeoutMillis = request['timeout'] * 1000; |
| 99 } | 84 } |
| 100 var timer = new CountdownTimer(timeoutMillis); | 85 var timer = new CountdownTimer(timeoutMillis); |
| 101 var logMsgUrl = request['logMsgUrl']; | 86 var logMsgUrl = request['logMsgUrl']; |
| 102 | 87 |
| 103 // Queue sign requests from the same origin, to protect against simultaneous | 88 // Queue sign requests from the same origin, to protect against simultaneous |
| 104 // sign-out on many tabs resulting in repeated sign-in requests. | 89 // sign-out on many tabs resulting in repeated sign-in requests. |
| 105 var queuedSignRequest = new QueuedSignRequest(signData, factory, timer, | 90 var queuedSignRequest = new QueuedSignRequest(signData, factory, timer, |
| 106 nonNullOrigin, enforceAppIdValid, sendErrorResponse, sendSuccessResponse, | 91 nonNullOrigin, sendErrorResponse, sendSuccessResponse, |
| 107 sendNotification, sender.tlsChannelId, logMsgUrl); | 92 sender.tlsChannelId, logMsgUrl); |
| 108 var requestToken = signRequestQueue.queueRequest(firstAppId, nonNullOrigin, | 93 var requestToken = signRequestQueue.queueRequest(firstAppId, nonNullOrigin, |
| 109 queuedSignRequest.begin.bind(queuedSignRequest), timer); | 94 queuedSignRequest.begin.bind(queuedSignRequest), timer); |
| 110 queuedSignRequest.setToken(requestToken); | 95 queuedSignRequest.setToken(requestToken); |
| 111 return queuedSignRequest; | 96 return queuedSignRequest; |
| 112 } | 97 } |
| 113 | 98 |
| 114 /** | 99 /** |
| 115 * Returns whether the request appears to be a valid sign request. | 100 * Returns whether the request appears to be a valid sign request. |
| 116 * @param {Object} request the request. | 101 * @param {Object} request the request. |
| 117 * @return {boolean} whether the request appears valid. | 102 * @return {boolean} whether the request appears valid. |
| 118 */ | 103 */ |
| 119 function isValidSignRequest(request) { | 104 function isValidSignRequest(request) { |
| 120 if (!request.hasOwnProperty('signData')) | 105 if (!request.hasOwnProperty('signData')) |
| 121 return false; | 106 return false; |
| 122 var signData = request['signData']; | 107 var signData = request['signData']; |
| 123 // If a sign request contains an empty array of challenges, it could never | 108 // If a sign request contains an empty array of challenges, it could never |
| 124 // be fulfilled. Fail. | 109 // be fulfilled. Fail. |
| 125 if (!signData.length) | 110 if (!signData.length) |
| 126 return false; | 111 return false; |
| 127 return isValidSignData(signData); | 112 return isValidSignData(signData); |
| 128 } | 113 } |
| 129 | 114 |
| 130 /** | 115 /** |
| 131 * Adapter class representing a queued sign request. | 116 * Adapter class representing a queued sign request. |
| 132 * @param {!SignData} signData Signature data | 117 * @param {!SignData} signData Signature data |
| 133 * @param {!SignHelperFactory} factory Factory for SignHelper instances | 118 * @param {!SignHelperFactory} factory Factory for SignHelper instances |
| 134 * @param {Countdown} timer Timeout timer | 119 * @param {Countdown} timer Timeout timer |
| 135 * @param {string} origin Signature origin | 120 * @param {string} origin Signature origin |
| 136 * @param {boolean} enforceAppIdValid If to enforce appId validity | |
| 137 * @param {function(number)} errorCb Error callback | 121 * @param {function(number)} errorCb Error callback |
| 138 * @param {function(SignChallenge, string, string)} successCb Success callback | 122 * @param {function(SignChallenge, string, string)} successCb Success callback |
| 139 * @param {(function(number)|undefined)} opt_progressCb Progress callback | |
| 140 * @param {string|undefined} opt_tlsChannelId TLS Channel Id | 123 * @param {string|undefined} opt_tlsChannelId TLS Channel Id |
| 141 * @param {string|undefined} opt_logMsgUrl Url to post log messages to | 124 * @param {string|undefined} opt_logMsgUrl Url to post log messages to |
| 142 * @constructor | 125 * @constructor |
| 143 * @implements {Closeable} | 126 * @implements {Closeable} |
| 144 */ | 127 */ |
| 145 function QueuedSignRequest(signData, factory, timer, origin, enforceAppIdValid, | 128 function QueuedSignRequest(signData, factory, timer, origin, errorCb, successCb, |
| 146 errorCb, successCb, opt_progressCb, opt_tlsChannelId, opt_logMsgUrl) { | 129 opt_tlsChannelId, opt_logMsgUrl) { |
| 147 /** @private {!SignData} */ | 130 /** @private {!SignData} */ |
| 148 this.signData_ = signData; | 131 this.signData_ = signData; |
| 149 /** @private {!SignHelperFactory} */ | 132 /** @private {!SignHelperFactory} */ |
| 150 this.factory_ = factory; | 133 this.factory_ = factory; |
| 151 /** @private {Countdown} */ | 134 /** @private {Countdown} */ |
| 152 this.timer_ = timer; | 135 this.timer_ = timer; |
| 153 /** @private {string} */ | 136 /** @private {string} */ |
| 154 this.origin_ = origin; | 137 this.origin_ = origin; |
| 155 /** @private {boolean} */ | |
| 156 this.enforceAppIdValid_ = enforceAppIdValid; | |
| 157 /** @private {function(number)} */ | 138 /** @private {function(number)} */ |
| 158 this.errorCb_ = errorCb; | 139 this.errorCb_ = errorCb; |
| 159 /** @private {function(SignChallenge, string, string)} */ | 140 /** @private {function(SignChallenge, string, string)} */ |
| 160 this.successCb_ = successCb; | 141 this.successCb_ = successCb; |
| 161 /** @private {(function(number)|undefined)} */ | |
| 162 this.progressCb_ = opt_progressCb; | |
| 163 /** @private {string|undefined} */ | 142 /** @private {string|undefined} */ |
| 164 this.tlsChannelId_ = opt_tlsChannelId; | 143 this.tlsChannelId_ = opt_tlsChannelId; |
| 165 /** @private {string|undefined} */ | 144 /** @private {string|undefined} */ |
| 166 this.logMsgUrl_ = opt_logMsgUrl; | 145 this.logMsgUrl_ = opt_logMsgUrl; |
| 167 /** @private {boolean} */ | 146 /** @private {boolean} */ |
| 168 this.begun_ = false; | 147 this.begun_ = false; |
| 169 /** @private {boolean} */ | 148 /** @private {boolean} */ |
| 170 this.closed_ = false; | 149 this.closed_ = false; |
| 171 } | 150 } |
| 172 | 151 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 191 }; | 170 }; |
| 192 | 171 |
| 193 /** | 172 /** |
| 194 * Called when this sign request may begin work. | 173 * Called when this sign request may begin work. |
| 195 * @param {QueuedRequestToken} token Token for this sign request. | 174 * @param {QueuedRequestToken} token Token for this sign request. |
| 196 */ | 175 */ |
| 197 QueuedSignRequest.prototype.begin = function(token) { | 176 QueuedSignRequest.prototype.begin = function(token) { |
| 198 this.begun_ = true; | 177 this.begun_ = true; |
| 199 this.setToken(token); | 178 this.setToken(token); |
| 200 this.signer_ = new Signer(this.factory_, this.timer_, this.origin_, | 179 this.signer_ = new Signer(this.factory_, this.timer_, this.origin_, |
| 201 this.enforceAppIdValid_, this.signerFailed_.bind(this), | 180 this.signerFailed_.bind(this), this.signerSucceeded_.bind(this), |
| 202 this.signerSucceeded_.bind(this), this.progressCb_, | |
| 203 this.tlsChannelId_, this.logMsgUrl_); | 181 this.tlsChannelId_, this.logMsgUrl_); |
| 204 if (!this.signer_.setChallenges(this.signData_)) { | 182 if (!this.signer_.setChallenges(this.signData_)) { |
| 205 token.complete(); | 183 token.complete(); |
| 206 this.errorCb_(GnubbyCodeTypes.BAD_REQUEST); | 184 this.errorCb_(GnubbyCodeTypes.BAD_REQUEST); |
| 207 } | 185 } |
| 208 }; | 186 }; |
| 209 | 187 |
| 210 /** | 188 /** |
| 211 * Called when this request's signer fails. | 189 * Called when this request's signer fails. |
| 212 * @param {number} code The failure code reported by the signer. | 190 * @param {number} code The failure code reported by the signer. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 228 function(challenge, info, browserData) { | 206 function(challenge, info, browserData) { |
| 229 this.token_.complete(); | 207 this.token_.complete(); |
| 230 this.successCb_(challenge, info, browserData); | 208 this.successCb_(challenge, info, browserData); |
| 231 }; | 209 }; |
| 232 | 210 |
| 233 /** | 211 /** |
| 234 * Creates an object to track signing with a gnubby. | 212 * Creates an object to track signing with a gnubby. |
| 235 * @param {!SignHelperFactory} helperFactory Factory to create a sign helper. | 213 * @param {!SignHelperFactory} helperFactory Factory to create a sign helper. |
| 236 * @param {Countdown} timer Timer for sign request. | 214 * @param {Countdown} timer Timer for sign request. |
| 237 * @param {string} origin The origin making the request. | 215 * @param {string} origin The origin making the request. |
| 238 * @param {boolean} enforceAppIdValid Whether to enforce that the appId in the | |
| 239 * request matches the sender's origin. | |
| 240 * @param {function(number)} errorCb Called when the sign operation fails. | 216 * @param {function(number)} errorCb Called when the sign operation fails. |
| 241 * @param {function(SignChallenge, string, string)} successCb Called when the | 217 * @param {function(SignChallenge, string, string)} successCb Called when the |
| 242 * sign operation succeeds. | 218 * sign operation succeeds. |
| 243 * @param {(function(number)|undefined)} opt_progressCb Called with progress | |
| 244 * updates to the sign request. | |
| 245 * @param {string=} opt_tlsChannelId the TLS channel ID, if any, of the origin | 219 * @param {string=} opt_tlsChannelId the TLS channel ID, if any, of the origin |
| 246 * making the request. | 220 * making the request. |
| 247 * @param {string=} opt_logMsgUrl The url to post log messages to. | 221 * @param {string=} opt_logMsgUrl The url to post log messages to. |
| 248 * @constructor | 222 * @constructor |
| 249 */ | 223 */ |
| 250 function Signer(helperFactory, timer, origin, enforceAppIdValid, | 224 function Signer(helperFactory, timer, origin, errorCb, successCb, |
| 251 errorCb, successCb, opt_progressCb, opt_tlsChannelId, opt_logMsgUrl) { | 225 opt_tlsChannelId, opt_logMsgUrl) { |
| 252 /** @private {Countdown} */ | 226 /** @private {Countdown} */ |
| 253 this.timer_ = timer; | 227 this.timer_ = timer; |
| 254 /** @private {string} */ | 228 /** @private {string} */ |
| 255 this.origin_ = origin; | 229 this.origin_ = origin; |
| 256 /** @private {boolean} */ | |
| 257 this.enforceAppIdValid_ = enforceAppIdValid; | |
| 258 /** @private {function(number)} */ | 230 /** @private {function(number)} */ |
| 259 this.errorCb_ = errorCb; | 231 this.errorCb_ = errorCb; |
| 260 /** @private {function(SignChallenge, string, string)} */ | 232 /** @private {function(SignChallenge, string, string)} */ |
| 261 this.successCb_ = successCb; | 233 this.successCb_ = successCb; |
| 262 /** @private {(function(number)|undefined)} */ | |
| 263 this.progressCb_ = opt_progressCb; | |
| 264 /** @private {string|undefined} */ | 234 /** @private {string|undefined} */ |
| 265 this.tlsChannelId_ = opt_tlsChannelId; | 235 this.tlsChannelId_ = opt_tlsChannelId; |
| 266 /** @private {string|undefined} */ | 236 /** @private {string|undefined} */ |
| 267 this.logMsgUrl_ = opt_logMsgUrl; | 237 this.logMsgUrl_ = opt_logMsgUrl; |
| 268 | 238 |
| 269 /** @private {boolean} */ | 239 /** @private {boolean} */ |
| 270 this.challengesSet_ = false; | 240 this.challengesSet_ = false; |
| 271 /** @private {Array.<SignHelperChallenge>} */ | 241 /** @private {Array.<SignHelperChallenge>} */ |
| 272 this.pendingChallenges_ = []; | 242 this.pendingChallenges_ = []; |
| 273 /** @private {boolean} */ | 243 /** @private {boolean} */ |
| 274 this.done_ = false; | 244 this.done_ = false; |
| 275 | 245 |
| 276 /** @private {Object.<string, string>} */ | 246 /** @private {Object.<string, string>} */ |
| 277 this.browserData_ = {}; | 247 this.browserData_ = {}; |
| 278 /** @private {Object.<string, SignChallenge>} */ | 248 /** @private {Object.<string, SignChallenge>} */ |
| 279 this.serverChallenges_ = {}; | 249 this.serverChallenges_ = {}; |
| 280 // Allow http appIds for http origins. (Broken, but the caller deserves | 250 // Allow http appIds for http origins. (Broken, but the caller deserves |
| 281 // what they get.) | 251 // what they get.) |
| 282 /** @private {boolean} */ | 252 /** @private {boolean} */ |
| 283 this.allowHttp_ = this.origin_ ? this.origin_.indexOf('http://') == 0 : false; | 253 this.allowHttp_ = this.origin_ ? this.origin_.indexOf('http://') == 0 : false; |
| 284 | 254 |
| 285 // Protect against helper failure with a watchdog. | 255 // Protect against helper failure with a watchdog. |
| 286 this.createWatchdog_(timer); | 256 this.createWatchdog_(timer); |
| 287 /** @private {SignHelper} */ | 257 /** @private {SignHelper} */ |
| 288 this.helper_ = helperFactory.createHelper( | 258 this.helper_ = helperFactory.createHelper( |
| 289 timer, this.helperError_.bind(this), this.helperSuccess_.bind(this), | 259 timer, this.helperError_.bind(this), this.helperSuccess_.bind(this), |
| 290 this.helperProgress_.bind(this), this.logMsgUrl_); | 260 this.logMsgUrl_); |
| 291 } | 261 } |
| 292 | 262 |
| 293 /** | 263 /** |
| 294 * Creates a timer with an expiry greater than the expiration time of the given | 264 * Creates a timer with an expiry greater than the expiration time of the given |
| 295 * timer. | 265 * timer. |
| 296 * @param {Countdown} timer Timeout timer | 266 * @param {Countdown} timer Timeout timer |
| 297 * @private | 267 * @private |
| 298 */ | 268 */ |
| 299 Signer.prototype.createWatchdog_ = function(timer) { | 269 Signer.prototype.createWatchdog_ = function(timer) { |
| 300 var millis = timer.millisecondsUntilExpired(); | 270 var millis = timer.millisecondsUntilExpired(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 314 * @return {boolean} Whether the challenges could be set. | 284 * @return {boolean} Whether the challenges could be set. |
| 315 */ | 285 */ |
| 316 Signer.prototype.setChallenges = function(signData) { | 286 Signer.prototype.setChallenges = function(signData) { |
| 317 if (this.challengesSet_ || this.done_) | 287 if (this.challengesSet_ || this.done_) |
| 318 return false; | 288 return false; |
| 319 /** @private {SignData} */ | 289 /** @private {SignData} */ |
| 320 this.signData_ = signData; | 290 this.signData_ = signData; |
| 321 /** @private {boolean} */ | 291 /** @private {boolean} */ |
| 322 this.challengesSet_ = true; | 292 this.challengesSet_ = true; |
| 323 | 293 |
| 324 // If app id enforcing isn't in effect, go ahead and start the helper with | |
| 325 // all of the incoming challenges. | |
| 326 var success = true; | |
| 327 if (!this.enforceAppIdValid_) { | |
| 328 success = this.addChallenges(signData, true /* finalChallenges */); | |
| 329 } | |
| 330 | |
| 331 this.checkAppIds_(); | 294 this.checkAppIds_(); |
| 332 return success; | 295 return true; |
| 333 }; | 296 }; |
| 334 | 297 |
| 335 /** | 298 /** |
| 336 * Adds new challenges to the challenges being signed. | 299 * Adds new challenges to the challenges being signed. |
| 337 * @param {SignData} signData Challenges to add. | 300 * @param {SignData} signData Challenges to add. |
| 338 * @param {boolean} finalChallenges Whether these are the final challenges. | 301 * @param {boolean} finalChallenges Whether these are the final challenges. |
| 339 * @return {boolean} Whether the challenge could be added. | 302 * @return {boolean} Whether the challenge could be added. |
| 340 */ | 303 */ |
| 341 Signer.prototype.addChallenges = function(signData, finalChallenges) { | 304 Signer.prototype.addChallenges = function(signData, finalChallenges) { |
| 342 var newChallenges = this.encodeSignChallenges_(signData); | 305 var newChallenges = this.encodeSignChallenges_(signData); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 /** @private {number} */ | 361 /** @private {number} */ |
| 399 this.validAppIds_ = 0; | 362 this.validAppIds_ = 0; |
| 400 for (var i = 0, appIdRequestsPair; i < this.orderedRequests_.length; i++) { | 363 for (var i = 0, appIdRequestsPair; i < this.orderedRequests_.length; i++) { |
| 401 var appIdRequestsPair = this.orderedRequests_[i]; | 364 var appIdRequestsPair = this.orderedRequests_[i]; |
| 402 var appId = appIdRequestsPair[0]; | 365 var appId = appIdRequestsPair[0]; |
| 403 var requests = appIdRequestsPair[1]; | 366 var requests = appIdRequestsPair[1]; |
| 404 if (appId == this.origin_) { | 367 if (appId == this.origin_) { |
| 405 // Trivially allowed. | 368 // Trivially allowed. |
| 406 this.fetchedAppIds_++; | 369 this.fetchedAppIds_++; |
| 407 this.validAppIds_++; | 370 this.validAppIds_++; |
| 408 // Only add challenges if in enforcing mode, i.e. they weren't added | 371 this.addChallenges(requests, |
| 409 // earlier. | 372 this.fetchedAppIds_ == this.orderedRequests_.length); |
| 410 if (this.enforceAppIdValid_) { | |
| 411 this.addChallenges(requests, | |
| 412 this.fetchedAppIds_ == this.orderedRequests_.length); | |
| 413 } | |
| 414 } else { | 373 } else { |
| 415 var start = new Date(); | 374 var start = new Date(); |
| 416 fetchAllowedOriginsForAppId(appId, this.allowHttp_, | 375 fetchAllowedOriginsForAppId(appId, this.allowHttp_, |
| 417 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, | 376 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, |
| 418 requests)); | 377 requests)); |
| 419 } | 378 } |
| 420 } | 379 } |
| 421 }; | 380 }; |
| 422 | 381 |
| 423 /** | 382 /** |
| (...skipping 18 matching lines...) Expand all Loading... |
| 442 fetchAllowedOriginsForAppId(appId, this.allowHttp_, | 401 fetchAllowedOriginsForAppId(appId, this.allowHttp_, |
| 443 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, | 402 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, |
| 444 challenges)); | 403 challenges)); |
| 445 } | 404 } |
| 446 return; | 405 return; |
| 447 } | 406 } |
| 448 this.fetchedAppIds_++; | 407 this.fetchedAppIds_++; |
| 449 var finalChallenges = (this.fetchedAppIds_ == this.orderedRequests_.length); | 408 var finalChallenges = (this.fetchedAppIds_ == this.orderedRequests_.length); |
| 450 if (isValidAppIdForOrigin(appId, this.origin_, allowedOrigins)) { | 409 if (isValidAppIdForOrigin(appId, this.origin_, allowedOrigins)) { |
| 451 this.validAppIds_++; | 410 this.validAppIds_++; |
| 452 // Only add challenges if in enforcing mode, i.e. they weren't added | 411 this.addChallenges(challenges, finalChallenges); |
| 453 // earlier. | |
| 454 if (this.enforceAppIdValid_) { | |
| 455 this.addChallenges(challenges, finalChallenges); | |
| 456 } | |
| 457 } else { | 412 } else { |
| 458 logInvalidOriginForAppId(this.origin_, appId, this.logMsgUrl_); | 413 logInvalidOriginForAppId(this.origin_, appId, this.logMsgUrl_); |
| 459 // If in enforcing mode and this is the final request, sign the valid | 414 // If this is the final request, sign the valid challenges. |
| 460 // challenges. | 415 if (finalChallenges) { |
| 461 if (this.enforceAppIdValid_ && finalChallenges) { | |
| 462 if (!this.helper_.doSign(this.pendingChallenges_)) { | 416 if (!this.helper_.doSign(this.pendingChallenges_)) { |
| 463 this.notifyError_(GnubbyCodeTypes.BAD_REQUEST); | 417 this.notifyError_(GnubbyCodeTypes.BAD_REQUEST); |
| 464 return; | 418 return; |
| 465 } | 419 } |
| 466 } | 420 } |
| 467 } | 421 } |
| 468 if (this.enforceAppIdValid_ && finalChallenges && !this.validAppIds_) { | 422 if (finalChallenges && !this.validAppIds_) { |
| 469 // If all app ids are invalid, notify the caller, otherwise implicitly | 423 // If all app ids are invalid, notify the caller, otherwise implicitly |
| 470 // allow the helper to report whether any of the valid challenges succeeded. | 424 // allow the helper to report whether any of the valid challenges succeeded. |
| 471 this.notifyError_(GnubbyCodeTypes.BAD_APP_ID); | 425 this.notifyError_(GnubbyCodeTypes.BAD_APP_ID); |
| 472 } | 426 } |
| 473 }; | 427 }; |
| 474 | 428 |
| 475 /** | 429 /** |
| 476 * Called when the timeout expires on this signer. | 430 * Called when the timeout expires on this signer. |
| 477 * @private | 431 * @private |
| 478 */ | 432 */ |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 */ | 464 */ |
| 511 Signer.prototype.notifySuccess_ = function(challenge, info, browserData) { | 465 Signer.prototype.notifySuccess_ = function(challenge, info, browserData) { |
| 512 if (this.done_) | 466 if (this.done_) |
| 513 return; | 467 return; |
| 514 this.close(); | 468 this.close(); |
| 515 this.done_ = true; | 469 this.done_ = true; |
| 516 this.successCb_(challenge, info, browserData); | 470 this.successCb_(challenge, info, browserData); |
| 517 }; | 471 }; |
| 518 | 472 |
| 519 /** | 473 /** |
| 520 * Notifies the caller of progress with the error code. | |
| 521 * @param {number} code Status code | |
| 522 * @private | |
| 523 */ | |
| 524 Signer.prototype.notifyProgress_ = function(code) { | |
| 525 if (this.done_) | |
| 526 return; | |
| 527 if (code != this.lastProgressUpdate_) { | |
| 528 this.lastProgressUpdate_ = code; | |
| 529 // If there is no progress callback, treat it like an error and clean up. | |
| 530 if (this.progressCb_) { | |
| 531 this.progressCb_(code); | |
| 532 } else { | |
| 533 this.notifyError_(code); | |
| 534 } | |
| 535 } | |
| 536 }; | |
| 537 | |
| 538 /** | |
| 539 * Maps a sign helper's error code namespace to the page's error code namespace. | 474 * Maps a sign helper's error code namespace to the page's error code namespace. |
| 540 * @param {number} code Error code from DeviceStatusCodes namespace. | 475 * @param {number} code Error code from DeviceStatusCodes namespace. |
| 541 * @param {boolean} anyGnubbies Whether any gnubbies were found. | 476 * @param {boolean} anyGnubbies Whether any gnubbies were found. |
| 542 * @return {number} A GnubbyCodeTypes error code. | 477 * @return {number} A GnubbyCodeTypes error code. |
| 543 * @private | 478 * @private |
| 544 */ | 479 */ |
| 545 Signer.mapError_ = function(code, anyGnubbies) { | 480 Signer.mapError_ = function(code, anyGnubbies) { |
| 546 var reportedError; | 481 var reportedError; |
| 547 switch (code) { | 482 switch (code) { |
| 548 case DeviceStatusCodes.WRONG_DATA_STATUS: | 483 case DeviceStatusCodes.WRONG_DATA_STATUS: |
| (...skipping 30 matching lines...) Expand all Loading... |
| 579 var reportedError = Signer.mapError_(code, anyGnubbies); | 514 var reportedError = Signer.mapError_(code, anyGnubbies); |
| 580 console.log(UTIL_fmt('helper reported ' + code.toString(16) + | 515 console.log(UTIL_fmt('helper reported ' + code.toString(16) + |
| 581 ', returning ' + reportedError)); | 516 ', returning ' + reportedError)); |
| 582 this.notifyError_(reportedError); | 517 this.notifyError_(reportedError); |
| 583 }; | 518 }; |
| 584 | 519 |
| 585 /** | 520 /** |
| 586 * Called by helper upon success. | 521 * Called by helper upon success. |
| 587 * @param {SignHelperChallenge} challenge The challenge that was signed. | 522 * @param {SignHelperChallenge} challenge The challenge that was signed. |
| 588 * @param {string} info The sign result. | 523 * @param {string} info The sign result. |
| 524 * @param {string=} opt_source The source, if any, if the signature. |
| 589 * @private | 525 * @private |
| 590 */ | 526 */ |
| 591 Signer.prototype.helperSuccess_ = function(challenge, info) { | 527 Signer.prototype.helperSuccess_ = function(challenge, info, opt_source) { |
| 592 // Got a good reply, kill timer. | 528 // Got a good reply, kill timer. |
| 593 this.clearTimeout_(); | 529 this.clearTimeout_(); |
| 594 | 530 |
| 531 if (this.logMsgUrl_ && opt_source) { |
| 532 var logMsg = 'signed&source=' + opt_source; |
| 533 logMessage(logMsg, this.logMsgUrl_); |
| 534 } |
| 535 |
| 595 var key = challenge['keyHandle'] + challenge['challengeHash']; | 536 var key = challenge['keyHandle'] + challenge['challengeHash']; |
| 596 var browserData = this.browserData_[key]; | 537 var browserData = this.browserData_[key]; |
| 597 // Notify with server-provided challenge, not the encoded one: the | 538 // Notify with server-provided challenge, not the encoded one: the |
| 598 // server-provided challenge contains additional fields it relies on. | 539 // server-provided challenge contains additional fields it relies on. |
| 599 var serverChallenge = this.serverChallenges_[key]; | 540 var serverChallenge = this.serverChallenges_[key]; |
| 600 this.notifySuccess_(serverChallenge, info, browserData); | 541 this.notifySuccess_(serverChallenge, info, browserData); |
| 601 }; | 542 }; |
| 602 | 543 |
| 603 /** | 544 /** |
| 604 * Called by helper to notify progress. | |
| 605 * @param {number} code Status code | |
| 606 * @param {boolean} anyGnubbies If any gnubbies were found | |
| 607 * @private | |
| 608 */ | |
| 609 Signer.prototype.helperProgress_ = function(code, anyGnubbies) { | |
| 610 var reportedError = Signer.mapError_(code, anyGnubbies); | |
| 611 console.log(UTIL_fmt('helper notified ' + code.toString(16) + | |
| 612 ', returning ' + reportedError)); | |
| 613 this.notifyProgress_(reportedError); | |
| 614 }; | |
| 615 | |
| 616 /** | |
| 617 * Clears the timeout for this signer. | 545 * Clears the timeout for this signer. |
| 618 * @private | 546 * @private |
| 619 */ | 547 */ |
| 620 Signer.prototype.clearTimeout_ = function() { | 548 Signer.prototype.clearTimeout_ = function() { |
| 621 if (this.watchdogTimer_) { | 549 if (this.watchdogTimer_) { |
| 622 this.watchdogTimer_.clearTimeout(); | 550 this.watchdogTimer_.clearTimeout(); |
| 623 this.watchdogTimer_ = undefined; | 551 this.watchdogTimer_ = undefined; |
| 624 } | 552 } |
| 625 }; | 553 }; |
| OLD | NEW |