| 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 A multiple gnubby signer wraps the process of opening a number | 6 * @fileoverview A multiple gnubby signer wraps the process of opening a number |
| 7 * of gnubbies, signing each challenge in an array of challenges until a | 7 * of gnubbies, signing each challenge in an array of challenges until a |
| 8 * success condition is satisfied, and yielding each succeeding gnubby. | 8 * success condition is satisfied, and yielding each succeeding gnubby. |
| 9 * | 9 * |
| 10 */ | 10 */ |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 * whether this signer expects to produce more results. The boolean is a | 34 * whether this signer expects to produce more results. The boolean is a |
| 35 * hint rather than a promise: it's possible for this signer to produce | 35 * hint rather than a promise: it's possible for this signer to produce |
| 36 * further results after saying it doesn't expect more, or to fail to | 36 * further results after saying it doesn't expect more, or to fail to |
| 37 * produce further results after saying it does. | 37 * produce further results after saying it does. |
| 38 * @param {number} timeoutMillis A timeout value, beyond whose expiration the | 38 * @param {number} timeoutMillis A timeout value, beyond whose expiration the |
| 39 * signer will not attempt any new operations, assuming the caller is no | 39 * signer will not attempt any new operations, assuming the caller is no |
| 40 * longer interested in the outcome. | 40 * longer interested in the outcome. |
| 41 * @param {string=} opt_logMsgUrl A URL to post log messages to. | 41 * @param {string=} opt_logMsgUrl A URL to post log messages to. |
| 42 * @constructor | 42 * @constructor |
| 43 */ | 43 */ |
| 44 function MultipleGnubbySigner(forEnroll, allCompleteCb, gnubbyCompleteCb, | 44 function MultipleGnubbySigner( |
| 45 timeoutMillis, opt_logMsgUrl) { | 45 forEnroll, allCompleteCb, gnubbyCompleteCb, timeoutMillis, opt_logMsgUrl) { |
| 46 /** @private {boolean} */ | 46 /** @private {boolean} */ |
| 47 this.forEnroll_ = forEnroll; | 47 this.forEnroll_ = forEnroll; |
| 48 /** @private {function(boolean)} */ | 48 /** @private {function(boolean)} */ |
| 49 this.allCompleteCb_ = allCompleteCb; | 49 this.allCompleteCb_ = allCompleteCb; |
| 50 /** @private {function(MultipleSignerResult, boolean)} */ | 50 /** @private {function(MultipleSignerResult, boolean)} */ |
| 51 this.gnubbyCompleteCb_ = gnubbyCompleteCb; | 51 this.gnubbyCompleteCb_ = gnubbyCompleteCb; |
| 52 /** @private {string|undefined} */ | 52 /** @private {string|undefined} */ |
| 53 this.logMsgUrl_ = opt_logMsgUrl; | 53 this.logMsgUrl_ = opt_logMsgUrl; |
| 54 | 54 |
| 55 /** @private {Array<SignHelperChallenge>} */ | 55 /** @private {Array<SignHelperChallenge>} */ |
| 56 this.challenges_ = []; | 56 this.challenges_ = []; |
| 57 /** @private {boolean} */ | 57 /** @private {boolean} */ |
| 58 this.challengesSet_ = false; | 58 this.challengesSet_ = false; |
| 59 /** @private {boolean} */ | 59 /** @private {boolean} */ |
| 60 this.complete_ = false; | 60 this.complete_ = false; |
| 61 /** @private {number} */ | 61 /** @private {number} */ |
| 62 this.numComplete_ = 0; | 62 this.numComplete_ = 0; |
| 63 /** @private {!Object<string, GnubbyTracker>} */ | 63 /** @private {!Object<string, GnubbyTracker>} */ |
| 64 this.gnubbies_ = {}; | 64 this.gnubbies_ = {}; |
| 65 /** @private {Countdown} */ | 65 /** @private {Countdown} */ |
| 66 this.timer_ = DEVICE_FACTORY_REGISTRY.getCountdownFactory() | 66 this.timer_ = |
| 67 .createTimer(timeoutMillis); | 67 DEVICE_FACTORY_REGISTRY.getCountdownFactory().createTimer(timeoutMillis); |
| 68 /** @private {Countdown} */ | 68 /** @private {Countdown} */ |
| 69 this.reenumerateTimer_ = DEVICE_FACTORY_REGISTRY.getCountdownFactory() | 69 this.reenumerateTimer_ = |
| 70 .createTimer(timeoutMillis); | 70 DEVICE_FACTORY_REGISTRY.getCountdownFactory().createTimer(timeoutMillis); |
| 71 } | 71 } |
| 72 | 72 |
| 73 /** | 73 /** |
| 74 * @typedef {{ | 74 * @typedef {{ |
| 75 * index: string, | 75 * index: string, |
| 76 * signer: SingleGnubbySigner, | 76 * signer: SingleGnubbySigner, |
| 77 * stillGoing: boolean, | 77 * stillGoing: boolean, |
| 78 * errorStatus: number | 78 * errorStatus: number |
| 79 * }} | 79 * }} |
| 80 */ | 80 */ |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 * @const | 176 * @const |
| 177 */ | 177 */ |
| 178 MultipleGnubbySigner.PASSIVE_REENUMERATE_INTERVAL_MILLIS = 3000; | 178 MultipleGnubbySigner.PASSIVE_REENUMERATE_INTERVAL_MILLIS = 3000; |
| 179 | 179 |
| 180 /** | 180 /** |
| 181 * Reenumerates gnubbies if there's still time. | 181 * Reenumerates gnubbies if there's still time. |
| 182 * @param {boolean} activeScan Whether to poll more aggressively, e.g. if | 182 * @param {boolean} activeScan Whether to poll more aggressively, e.g. if |
| 183 * there are no devices present. | 183 * there are no devices present. |
| 184 * @private | 184 * @private |
| 185 */ | 185 */ |
| 186 MultipleGnubbySigner.prototype.maybeReEnumerateGnubbies_ = | 186 MultipleGnubbySigner.prototype.maybeReEnumerateGnubbies_ = function( |
| 187 function(activeScan) { | 187 activeScan) { |
| 188 if (this.reenumerateTimer_.expired()) { | 188 if (this.reenumerateTimer_.expired()) { |
| 189 // If the timer is expired, call timeout_ if there aren't any still-running | 189 // If the timer is expired, call timeout_ if there aren't any still-running |
| 190 // gnubbies. (If there are some still running, the last will call timeout_ | 190 // gnubbies. (If there are some still running, the last will call timeout_ |
| 191 // itself.) | 191 // itself.) |
| 192 if (!this.anyPending_()) { | 192 if (!this.anyPending_()) { |
| 193 this.timeout_(false); | 193 this.timeout_(false); |
| 194 } | 194 } |
| 195 return; | 195 return; |
| 196 } | 196 } |
| 197 // Reenumerate more aggressively if there are no gnubbies present than if | 197 // Reenumerate more aggressively if there are no gnubbies present than if |
| (...skipping 26 matching lines...) Expand all Loading... |
| 224 * @param {GnubbyDeviceId} gnubbyId The id of the gnubby to add. | 224 * @param {GnubbyDeviceId} gnubbyId The id of the gnubby to add. |
| 225 * @return {boolean} Whether the gnubby was added successfully. | 225 * @return {boolean} Whether the gnubby was added successfully. |
| 226 * @private | 226 * @private |
| 227 */ | 227 */ |
| 228 MultipleGnubbySigner.prototype.addGnubby_ = function(gnubbyId) { | 228 MultipleGnubbySigner.prototype.addGnubby_ = function(gnubbyId) { |
| 229 var index = JSON.stringify(gnubbyId); | 229 var index = JSON.stringify(gnubbyId); |
| 230 if (this.gnubbies_.hasOwnProperty(index)) { | 230 if (this.gnubbies_.hasOwnProperty(index)) { |
| 231 // Can't add the same gnubby twice. | 231 // Can't add the same gnubby twice. |
| 232 return false; | 232 return false; |
| 233 } | 233 } |
| 234 var tracker = { | 234 var tracker = {index: index, errorStatus: 0, stillGoing: false, signer: null}; |
| 235 index: index, | |
| 236 errorStatus: 0, | |
| 237 stillGoing: false, | |
| 238 signer: null | |
| 239 }; | |
| 240 tracker.signer = new SingleGnubbySigner( | 235 tracker.signer = new SingleGnubbySigner( |
| 241 gnubbyId, | 236 gnubbyId, this.forEnroll_, |
| 242 this.forEnroll_, | 237 this.signCompletedCallback_.bind(this, tracker), this.timer_.clone(), |
| 243 this.signCompletedCallback_.bind(this, tracker), | |
| 244 this.timer_.clone(), | |
| 245 this.logMsgUrl_); | 238 this.logMsgUrl_); |
| 246 this.gnubbies_[index] = tracker; | 239 this.gnubbies_[index] = tracker; |
| 247 this.gnubbies_[index].stillGoing = | 240 this.gnubbies_[index].stillGoing = tracker.signer.doSign(this.challenges_); |
| 248 tracker.signer.doSign(this.challenges_); | |
| 249 if (!this.gnubbies_[index].errorStatus) { | 241 if (!this.gnubbies_[index].errorStatus) { |
| 250 this.gnubbies_[index].errorStatus = 0; | 242 this.gnubbies_[index].errorStatus = 0; |
| 251 } | 243 } |
| 252 return true; | 244 return true; |
| 253 }; | 245 }; |
| 254 | 246 |
| 255 /** | 247 /** |
| 256 * Called by a SingleGnubbySigner upon completion. | 248 * Called by a SingleGnubbySigner upon completion. |
| 257 * @param {GnubbyTracker} tracker The tracker object of the gnubby whose result | 249 * @param {GnubbyTracker} tracker The tracker object of the gnubby whose result |
| 258 * this is. | 250 * this is. |
| 259 * @param {SingleSignerResult} result The result of the sign operation. | 251 * @param {SingleSignerResult} result The result of the sign operation. |
| 260 * @private | 252 * @private |
| 261 */ | 253 */ |
| 262 MultipleGnubbySigner.prototype.signCompletedCallback_ = | 254 MultipleGnubbySigner.prototype.signCompletedCallback_ = function( |
| 263 function(tracker, result) { | 255 tracker, result) { |
| 264 console.log( | 256 console.log(UTIL_fmt( |
| 265 UTIL_fmt((result.code ? 'failure.' : 'success!') + | 257 (result.code ? 'failure.' : 'success!') + ' gnubby ' + tracker.index + |
| 266 ' gnubby ' + tracker.index + | 258 ' got code ' + result.code.toString(16))); |
| 267 ' got code ' + result.code.toString(16))); | |
| 268 if (!tracker.stillGoing) { | 259 if (!tracker.stillGoing) { |
| 269 console.log(UTIL_fmt('gnubby ' + tracker.index + ' no longer running!')); | 260 console.log(UTIL_fmt('gnubby ' + tracker.index + ' no longer running!')); |
| 270 // Shouldn't ever happen? Disregard. | 261 // Shouldn't ever happen? Disregard. |
| 271 return; | 262 return; |
| 272 } | 263 } |
| 273 tracker.stillGoing = false; | 264 tracker.stillGoing = false; |
| 274 tracker.errorStatus = result.code; | 265 tracker.errorStatus = result.code; |
| 275 var moreExpected = this.tallyCompletedGnubby_(); | 266 var moreExpected = this.tallyCompletedGnubby_(); |
| 276 switch (result.code) { | 267 switch (result.code) { |
| 277 case DeviceStatusCodes.GONE_STATUS: | 268 case DeviceStatusCodes.GONE_STATUS: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 MultipleGnubbySigner.prototype.anyPending_ = function() { | 301 MultipleGnubbySigner.prototype.anyPending_ = function() { |
| 311 return this.numComplete_ < Object.keys(this.gnubbies_).length; | 302 return this.numComplete_ < Object.keys(this.gnubbies_).length; |
| 312 }; | 303 }; |
| 313 | 304 |
| 314 /** | 305 /** |
| 315 * Called upon timeout. | 306 * Called upon timeout. |
| 316 * @param {boolean} anyPending Whether any gnubbies are awaiting results. | 307 * @param {boolean} anyPending Whether any gnubbies are awaiting results. |
| 317 * @private | 308 * @private |
| 318 */ | 309 */ |
| 319 MultipleGnubbySigner.prototype.timeout_ = function(anyPending) { | 310 MultipleGnubbySigner.prototype.timeout_ = function(anyPending) { |
| 320 if (this.complete_) return; | 311 if (this.complete_) |
| 312 return; |
| 321 this.complete_ = true; | 313 this.complete_ = true; |
| 322 // Defer notifying the caller that all are complete, in case the caller is | 314 // Defer notifying the caller that all are complete, in case the caller is |
| 323 // doing work in response to a gnubbyFound callback and has an inconsistent | 315 // doing work in response to a gnubbyFound callback and has an inconsistent |
| 324 // view of the state of this signer. | 316 // view of the state of this signer. |
| 325 var self = this; | 317 var self = this; |
| 326 window.setTimeout(function() { | 318 window.setTimeout(function() { |
| 327 self.allCompleteCb_(anyPending); | 319 self.allCompleteCb_(anyPending); |
| 328 }, 0); | 320 }, 0); |
| 329 }; | 321 }; |
| 330 | 322 |
| 331 /** | 323 /** |
| 332 * @param {GnubbyTracker} tracker The tracker object of the gnubby whose result | 324 * @param {GnubbyTracker} tracker The tracker object of the gnubby whose result |
| 333 * this is. | 325 * this is. |
| 334 * @param {SingleSignerResult} result Result object. | 326 * @param {SingleSignerResult} result Result object. |
| 335 * @param {boolean} moreExpected Whether more gnubbies may still produce an | 327 * @param {boolean} moreExpected Whether more gnubbies may still produce an |
| 336 * outcome. | 328 * outcome. |
| 337 * @private | 329 * @private |
| 338 */ | 330 */ |
| 339 MultipleGnubbySigner.prototype.notifyGnubbyComplete_ = | 331 MultipleGnubbySigner.prototype.notifyGnubbyComplete_ = function( |
| 340 function(tracker, result, moreExpected) { | 332 tracker, result, moreExpected) { |
| 341 console.log(UTIL_fmt('gnubby ' + tracker.index + ' complete (' + | 333 console.log(UTIL_fmt( |
| 342 result.code.toString(16) + ')')); | 334 'gnubby ' + tracker.index + ' complete (' + result.code.toString(16) + |
| 335 ')')); |
| 343 var signResult = { | 336 var signResult = { |
| 344 'code': result.code, | 337 'code': result.code, |
| 345 'gnubby': result.gnubby, | 338 'gnubby': result.gnubby, |
| 346 'gnubbyId': tracker.signer.getDeviceId() | 339 'gnubbyId': tracker.signer.getDeviceId() |
| 347 }; | 340 }; |
| 348 if (result['challenge']) | 341 if (result['challenge']) |
| 349 signResult['challenge'] = result['challenge']; | 342 signResult['challenge'] = result['challenge']; |
| 350 if (result['info']) | 343 if (result['info']) |
| 351 signResult['info'] = result['info']; | 344 signResult['info'] = result['info']; |
| 352 this.gnubbyCompleteCb_(signResult, moreExpected); | 345 this.gnubbyCompleteCb_(signResult, moreExpected); |
| 353 }; | 346 }; |
| OLD | NEW |