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

Side by Side Diff: chrome/browser/resources/cryptotoken/gnubby.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 Provides a client view of a gnubby, aka USB security key. 6 * @fileoverview Provides a client view of a gnubby, aka USB security key.
7 */ 7 */
8 'use strict'; 8 'use strict';
9 9
10 /** 10 /**
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 /** @private {Gnubbies} */ 42 /** @private {Gnubbies} */
43 Gnubby.gnubbies_ = gnubbies; 43 Gnubby.gnubbies_ = gnubbies;
44 }; 44 };
45 45
46 /** 46 /**
47 * Return cid as hex string. 47 * Return cid as hex string.
48 * @param {number} cid to convert. 48 * @param {number} cid to convert.
49 * @return {string} hexadecimal string. 49 * @return {string} hexadecimal string.
50 */ 50 */
51 Gnubby.hexCid = function(cid) { 51 Gnubby.hexCid = function(cid) {
52 var tmp = [(cid >>> 24) & 255, 52 var tmp = [
53 (cid >>> 16) & 255, 53 (cid >>> 24) & 255, (cid >>> 16) & 255, (cid >>> 8) & 255, (cid >>> 0) & 255
54 (cid >>> 8) & 255, 54 ];
55 (cid >>> 0) & 255];
56 return UTIL_BytesToHex(tmp); 55 return UTIL_BytesToHex(tmp);
57 }; 56 };
58 57
59 /** 58 /**
60 * Cancels open attempt for this gnubby, if available. 59 * Cancels open attempt for this gnubby, if available.
61 */ 60 */
62 Gnubby.prototype.cancelOpen = function() { 61 Gnubby.prototype.cancelOpen = function() {
63 if (this.which) 62 if (this.which)
64 Gnubby.gnubbies_.cancelAddClient(this.which); 63 Gnubby.gnubbies_.cancelAddClient(this.which);
65 }; 64 };
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 if (this.dev) { 164 if (this.dev) {
166 console.log(UTIL_fmt('Gnubby.close()')); 165 console.log(UTIL_fmt('Gnubby.close()'));
167 this.rxframes = []; 166 this.rxframes = [];
168 this.rxcb = null; 167 this.rxcb = null;
169 var dev = this.dev; 168 var dev = this.dev;
170 this.dev = null; 169 this.dev = null;
171 var self = this; 170 var self = this;
172 // Wait a bit in case simpleton client tries open next gnubby. 171 // Wait a bit in case simpleton client tries open next gnubby.
173 // Without delay, gnubbies would drop all idle devices, before client 172 // Without delay, gnubbies would drop all idle devices, before client
174 // gets to the next one. 173 // gets to the next one.
175 window.setTimeout( 174 window.setTimeout(function() {
176 function() { 175 Gnubby.gnubbies_.removeClient(dev, self);
177 Gnubby.gnubbies_.removeClient(dev, self); 176 }, 300);
178 }, 300);
179 } 177 }
180 }; 178 };
181 179
182 /** 180 /**
183 * Asks this gnubby to close when it gets a chance. 181 * Asks this gnubby to close when it gets a chance.
184 * @param {Function=} cb called back when closed. 182 * @param {Function=} cb called back when closed.
185 */ 183 */
186 Gnubby.prototype.closeWhenIdle = function(cb) { 184 Gnubby.prototype.closeWhenIdle = function(cb) {
187 if (!this.inUse_()) { 185 if (!this.inUse_()) {
188 this.close(); 186 this.close();
189 if (cb) cb(); 187 if (cb)
188 cb();
190 return; 189 return;
191 } 190 }
192 this.closingWhenIdle = true; 191 this.closingWhenIdle = true;
193 if (cb) this.notifyOnClose.push(cb); 192 if (cb)
193 this.notifyOnClose.push(cb);
194 }; 194 };
195 195
196 /** 196 /**
197 * Sets a callback that will get called when this gnubby is closed. 197 * Sets a callback that will get called when this gnubby is closed.
198 * @param {function() : ?Promise} cb Called back when closed. Callback 198 * @param {function() : ?Promise} cb Called back when closed. Callback
199 * may yield a promise that resolves when the close hook completes. 199 * may yield a promise that resolves when the close hook completes.
200 */ 200 */
201 Gnubby.prototype.setCloseHook = function(cb) { 201 Gnubby.prototype.setCloseHook = function(cb) {
202 this.closeHook_ = cb; 202 this.closeHook_ = cb;
203 }; 203 };
(...skipping 11 matching lines...) Expand all
215 }; 215 };
216 216
217 /** 217 /**
218 * Notify callback for every frame received. 218 * Notify callback for every frame received.
219 * @param {function()} cb Callback 219 * @param {function()} cb Callback
220 * @private 220 * @private
221 */ 221 */
222 Gnubby.prototype.notifyFrame_ = function(cb) { 222 Gnubby.prototype.notifyFrame_ = function(cb) {
223 if (this.rxframes.length != 0) { 223 if (this.rxframes.length != 0) {
224 // Already have frames; continue. 224 // Already have frames; continue.
225 if (cb) window.setTimeout(cb, 0); 225 if (cb)
226 window.setTimeout(cb, 0);
226 } else { 227 } else {
227 this.rxcb = cb; 228 this.rxcb = cb;
228 } 229 }
229 }; 230 };
230 231
231 /** 232 /**
232 * Called by low level driver with a frame. 233 * Called by low level driver with a frame.
233 * @param {ArrayBuffer|Uint8Array} frame Data frame 234 * @param {ArrayBuffer|Uint8Array} frame Data frame
234 * @return {boolean} Whether this client is still interested in receiving 235 * @return {boolean} Whether this client is still interested in receiving
235 * frames from its device. 236 * frames from its device.
236 */ 237 */
237 Gnubby.prototype.receivedFrame = function(frame) { 238 Gnubby.prototype.receivedFrame = function(frame) {
238 if (this.closed) return false; // No longer interested. 239 if (this.closed)
240 return false; // No longer interested.
239 241
240 if (!this.checkCID_(frame)) { 242 if (!this.checkCID_(frame)) {
241 // Not for me, ignore. 243 // Not for me, ignore.
242 return true; 244 return true;
243 } 245 }
244 246
245 this.rxframes.push(frame); 247 this.rxframes.push(frame);
246 248
247 // Callback self in case we were waiting. Once. 249 // Callback self in case we were waiting. Once.
248 var cb = this.rxcb; 250 var cb = this.rxcb;
249 this.rxcb = null; 251 this.rxcb = null;
250 if (cb) window.setTimeout(cb, 0); 252 if (cb)
253 window.setTimeout(cb, 0);
251 254
252 return true; 255 return true;
253 }; 256 };
254 257
255 /** 258 /**
256 * @return {number|undefined} The last read error seen by this device. 259 * @return {number|undefined} The last read error seen by this device.
257 */ 260 */
258 Gnubby.prototype.getLastReadError = function() { 261 Gnubby.prototype.getLastReadError = function() {
259 return this.lastReadError_; 262 return this.lastReadError_;
260 }; 263 };
261 264
262 /** 265 /**
263 * @return {ArrayBuffer|Uint8Array} oldest received frame. Throw if none. 266 * @return {ArrayBuffer|Uint8Array} oldest received frame. Throw if none.
264 * @private 267 * @private
265 */ 268 */
266 Gnubby.prototype.readFrame_ = function() { 269 Gnubby.prototype.readFrame_ = function() {
267 if (this.rxframes.length == 0) throw 'rxframes empty!'; 270 if (this.rxframes.length == 0)
271 throw 'rxframes empty!';
268 272
269 var frame = this.rxframes.shift(); 273 var frame = this.rxframes.shift();
270 return frame; 274 return frame;
271 }; 275 };
272 276
273 /** Poll from rxframes[]. 277 /** Poll from rxframes[].
274 * @param {number} cmd Command 278 * @param {number} cmd Command
275 * @param {number} timeout timeout in seconds. 279 * @param {number} timeout timeout in seconds.
276 * @param {?function(...)} cb Callback 280 * @param {?function(...)} cb Callback
277 * @private 281 * @private
278 */ 282 */
279 Gnubby.prototype.read_ = function(cmd, timeout, cb) { 283 Gnubby.prototype.read_ = function(cmd, timeout, cb) {
280 if (this.closed) { cb(-GnubbyDevice.GONE); return; } 284 if (this.closed) {
281 if (!this.dev) { cb(-GnubbyDevice.GONE); return; } 285 cb(-GnubbyDevice.GONE);
286 return;
287 }
288 if (!this.dev) {
289 cb(-GnubbyDevice.GONE);
290 return;
291 }
282 292
283 var tid = null; // timeout timer id. 293 var tid = null; // timeout timer id.
284 var callback = cb; 294 var callback = cb;
285 var self = this; 295 var self = this;
286 296
287 var msg = null; 297 var msg = null;
288 var seqno = 0; 298 var seqno = 0;
289 var count = 0; 299 var count = 0;
290 300
291 /** 301 /**
292 * Schedule call to cb if not called yet. 302 * Schedule call to cb if not called yet.
293 * @param {number} a Return code. 303 * @param {number} a Return code.
294 * @param {Object=} b Optional data. 304 * @param {Object=} b Optional data.
295 */ 305 */
296 function schedule_cb(a, b) { 306 function schedule_cb(a, b) {
297 self.commandPending = false; 307 self.commandPending = false;
298 if (tid) { 308 if (tid) {
299 // Cancel timeout timer. 309 // Cancel timeout timer.
300 window.clearTimeout(tid); 310 window.clearTimeout(tid);
301 tid = null; 311 tid = null;
302 } 312 }
303 self.lastReadError_ = /** @private {number|undefined} */ (a); 313 self.lastReadError_ = /** @private {number|undefined} */ (a);
304 var c = callback; 314 var c = callback;
305 if (c) { 315 if (c) {
306 callback = null; 316 callback = null;
307 window.setTimeout(function() { c(a, b); }, 0); 317 window.setTimeout(function() {
318 c(a, b);
319 }, 0);
308 } 320 }
309 if (self.closingWhenIdle) self.idleClose_(); 321 if (self.closingWhenIdle)
322 self.idleClose_();
310 } 323 }
311 324
312 function read_timeout() { 325 function read_timeout() {
313 if (!callback || !tid) return; // Already done. 326 if (!callback || !tid)
327 return; // Already done.
314 328
315 console.error(UTIL_fmt( 329 console.error(UTIL_fmt('[' + Gnubby.hexCid(self.cid) + '] timeout!'));
316 '[' + Gnubby.hexCid(self.cid) + '] timeout!'));
317 330
318 if (self.dev) { 331 if (self.dev) {
319 self.dev.destroy(); // Stop pretending this thing works. 332 self.dev.destroy(); // Stop pretending this thing works.
320 } 333 }
321 334
322 tid = null; 335 tid = null;
323 336
324 schedule_cb(-GnubbyDevice.TIMEOUT); 337 schedule_cb(-GnubbyDevice.TIMEOUT);
325 } 338 }
326 339
327 function cont_frame() { 340 function cont_frame() {
328 if (!callback || !tid) return; // Already done. 341 if (!callback || !tid)
342 return; // Already done.
329 343
330 var f = new Uint8Array(self.readFrame_()); 344 var f = new Uint8Array(self.readFrame_());
331 var rcmd = f[4]; 345 var rcmd = f[4];
332 var totalLen = (f[5] << 8) + f[6]; 346 var totalLen = (f[5] << 8) + f[6];
333 347
334 if (rcmd == GnubbyDevice.CMD_ERROR && totalLen == 1) { 348 if (rcmd == GnubbyDevice.CMD_ERROR && totalLen == 1) {
335 // Error from device; forward. 349 // Error from device; forward.
336 console.log(UTIL_fmt( 350 console.log(UTIL_fmt(
337 '[' + Gnubby.hexCid(self.cid) + '] error frame ' + 351 '[' + Gnubby.hexCid(self.cid) + '] error frame ' +
338 UTIL_BytesToHex(f))); 352 UTIL_BytesToHex(f)));
(...skipping 30 matching lines...) Expand all
369 if (count == msg.length) { 383 if (count == msg.length) {
370 // Done. 384 // Done.
371 schedule_cb(-GnubbyDevice.OK, msg.buffer); 385 schedule_cb(-GnubbyDevice.OK, msg.buffer);
372 } else { 386 } else {
373 // Need more CONT frame(s). 387 // Need more CONT frame(s).
374 self.notifyFrame_(cont_frame); 388 self.notifyFrame_(cont_frame);
375 } 389 }
376 } 390 }
377 391
378 function init_frame() { 392 function init_frame() {
379 if (!callback || !tid) return; // Already done. 393 if (!callback || !tid)
394 return; // Already done.
380 395
381 var f = new Uint8Array(self.readFrame_()); 396 var f = new Uint8Array(self.readFrame_());
382 397
383 var rcmd = f[4]; 398 var rcmd = f[4];
384 var totalLen = (f[5] << 8) + f[6]; 399 var totalLen = (f[5] << 8) + f[6];
385 400
386 if (rcmd == GnubbyDevice.CMD_ERROR && totalLen == 1) { 401 if (rcmd == GnubbyDevice.CMD_ERROR && totalLen == 1) {
387 // Error from device; forward. 402 // Error from device; forward.
388 // Don't log busy frames, they're "normal". 403 // Don't log busy frames, they're "normal".
389 if (f[7] != GnubbyDevice.BUSY) { 404 if (f[7] != GnubbyDevice.BUSY) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 } 447 }
433 448
434 // Start timeout timer. 449 // Start timeout timer.
435 tid = window.setTimeout(read_timeout, 1000.0 * timeout); 450 tid = window.setTimeout(read_timeout, 1000.0 * timeout);
436 451
437 // Schedule read of first frame. 452 // Schedule read of first frame.
438 self.notifyFrame_(init_frame); 453 self.notifyFrame_(init_frame);
439 }; 454 };
440 455
441 /** 456 /**
442 * @const 457 * @const
443 */ 458 */
444 Gnubby.NOTIFICATION_CID = 0; 459 Gnubby.NOTIFICATION_CID = 0;
445 460
446 /** 461 /**
447 * @const 462 * @const
448 */ 463 */
449 Gnubby.BROADCAST_CID = (0xff << 24) | (0xff << 16) | (0xff << 8) | 0xff; 464 Gnubby.BROADCAST_CID = (0xff << 24) | (0xff << 16) | (0xff << 8) | 0xff;
450 465
451 /** 466 /**
452 * @param {ArrayBuffer|Uint8Array} frame Data frame 467 * @param {ArrayBuffer|Uint8Array} frame Data frame
453 * @return {boolean} Whether frame is for my channel. 468 * @return {boolean} Whether frame is for my channel.
454 * @private 469 * @private
455 */ 470 */
456 Gnubby.prototype.checkCID_ = function(frame) { 471 Gnubby.prototype.checkCID_ = function(frame) {
457 var f = new Uint8Array(frame); 472 var f = new Uint8Array(frame);
458 var c = (f[0] << 24) | 473 var c = (f[0] << 24) | (f[1] << 16) | (f[2] << 8) | (f[3]);
459 (f[1] << 16) | 474 return c === this.cid || c === Gnubby.NOTIFICATION_CID;
460 (f[2] << 8) |
461 (f[3]);
462 return c === this.cid ||
463 c === Gnubby.NOTIFICATION_CID;
464 }; 475 };
465 476
466 /** 477 /**
467 * Queue command for sending. 478 * Queue command for sending.
468 * @param {number} cmd The command to send. 479 * @param {number} cmd The command to send.
469 * @param {ArrayBuffer|Uint8Array} data Command data 480 * @param {ArrayBuffer|Uint8Array} data Command data
470 * @private 481 * @private
471 */ 482 */
472 Gnubby.prototype.write_ = function(cmd, data) { 483 Gnubby.prototype.write_ = function(cmd, data) {
473 if (this.closed) return; 484 if (this.closed)
474 if (!this.dev) return; 485 return;
486 if (!this.dev)
487 return;
475 488
476 this.commandPending = true; 489 this.commandPending = true;
477 490
478 this.dev.queueCommand(this.cid, cmd, data); 491 this.dev.queueCommand(this.cid, cmd, data);
479 }; 492 };
480 493
481 /** 494 /**
482 * Writes the command, and calls back when the command's reply is received. 495 * Writes the command, and calls back when the command's reply is received.
483 * @param {number} cmd The command to send. 496 * @param {number} cmd The command to send.
484 * @param {ArrayBuffer|Uint8Array} data Command data 497 * @param {ArrayBuffer|Uint8Array} data Command data
(...skipping 28 matching lines...) Expand all
513 */ 526 */
514 Gnubby.SYS_TIMER_ = new WindowTimer(); 527 Gnubby.SYS_TIMER_ = new WindowTimer();
515 528
516 /** Default callback for commands. Simply logs to console. 529 /** Default callback for commands. Simply logs to console.
517 * @param {number} rc Result status code 530 * @param {number} rc Result status code
518 * @param {(ArrayBuffer|Uint8Array|Array<number>|null)} data Result data 531 * @param {(ArrayBuffer|Uint8Array|Array<number>|null)} data Result data
519 */ 532 */
520 Gnubby.defaultCallback = function(rc, data) { 533 Gnubby.defaultCallback = function(rc, data) {
521 var msg = 'defaultCallback(' + rc; 534 var msg = 'defaultCallback(' + rc;
522 if (data) { 535 if (data) {
523 if (typeof data == 'string') msg += ', ' + data; 536 if (typeof data == 'string')
524 else msg += ', ' + UTIL_BytesToHex(new Uint8Array(data)); 537 msg += ', ' + data;
538 else
539 msg += ', ' + UTIL_BytesToHex(new Uint8Array(data));
525 } 540 }
526 msg += ')'; 541 msg += ')';
527 console.log(UTIL_fmt(msg)); 542 console.log(UTIL_fmt(msg));
528 }; 543 };
529 544
530 /** 545 /**
531 * Ensures this device has temporary ownership of the USB device, by: 546 * Ensures this device has temporary ownership of the USB device, by:
532 * 1. Using the INIT command to allocate an unique channel id, if one hasn't 547 * 1. Using the INIT command to allocate an unique channel id, if one hasn't
533 * been retrieved before, or 548 * been retrieved before, or
534 * 2. Sending a nonce to device, flushing read queue until match. 549 * 2. Sending a nonce to device, flushing read queue until match.
535 * @param {?function(...)} cb Callback 550 * @param {?function(...)} cb Callback
536 */ 551 */
537 Gnubby.prototype.sync = function(cb) { 552 Gnubby.prototype.sync = function(cb) {
538 if (!cb) cb = Gnubby.defaultCallback; 553 if (!cb)
554 cb = Gnubby.defaultCallback;
539 if (this.closed) { 555 if (this.closed) {
540 cb(-GnubbyDevice.GONE); 556 cb(-GnubbyDevice.GONE);
541 return; 557 return;
542 } 558 }
543 559
544 var done = false; 560 var done = false;
545 var trycount = 6; 561 var trycount = 6;
546 var tid = null; 562 var tid = null;
547 var self = this; 563 var self = this;
548 564
549 function returnValue(rc) { 565 function returnValue(rc) {
550 done = true; 566 done = true;
551 window.setTimeout(cb.bind(null, rc), 0); 567 window.setTimeout(cb.bind(null, rc), 0);
552 if (self.closingWhenIdle) self.idleClose_(); 568 if (self.closingWhenIdle)
569 self.idleClose_();
553 } 570 }
554 571
555 function callback(rc, opt_frame) { 572 function callback(rc, opt_frame) {
556 self.commandPending = false; 573 self.commandPending = false;
557 if (tid) { 574 if (tid) {
558 window.clearTimeout(tid); 575 window.clearTimeout(tid);
559 tid = null; 576 tid = null;
560 } 577 }
561 completionAction(rc, opt_frame); 578 completionAction(rc, opt_frame);
562 } 579 }
563 580
564 function sendSyncSentinel() { 581 function sendSyncSentinel() {
565 var cmd = GnubbyDevice.CMD_SYNC; 582 var cmd = GnubbyDevice.CMD_SYNC;
566 var data = new Uint8Array(1); 583 var data = new Uint8Array(1);
567 data[0] = ++self.synccnt; 584 data[0] = ++self.synccnt;
568 self.dev.queueCommand(self.cid, cmd, data.buffer); 585 self.dev.queueCommand(self.cid, cmd, data.buffer);
569 } 586 }
570 587
571 function syncSentinelEquals(f) { 588 function syncSentinelEquals(f) {
572 return (f[4] == GnubbyDevice.CMD_SYNC && 589 return (
590 f[4] == GnubbyDevice.CMD_SYNC &&
573 (f.length == 7 || /* fw pre-0.2.1 bug: does not echo sentinel */ 591 (f.length == 7 || /* fw pre-0.2.1 bug: does not echo sentinel */
574 f[7] == self.synccnt)); 592 f[7] == self.synccnt));
575 } 593 }
576 594
577 function syncCompletionAction(rc, opt_frame) { 595 function syncCompletionAction(rc, opt_frame) {
578 if (rc) console.warn(UTIL_fmt('sync failed: ' + rc)); 596 if (rc)
597 console.warn(UTIL_fmt('sync failed: ' + rc));
579 returnValue(rc); 598 returnValue(rc);
580 } 599 }
581 600
582 function sendInitSentinel() { 601 function sendInitSentinel() {
583 var cid = self.cid; 602 var cid = self.cid;
584 // If we do not have a specific CID yet, reset to BROADCAST for init. 603 // If we do not have a specific CID yet, reset to BROADCAST for init.
585 if (self.cid == Gnubby.defaultChannelId_(self.gnubbyInstance, self.which)) { 604 if (self.cid == Gnubby.defaultChannelId_(self.gnubbyInstance, self.which)) {
586 self.cid = Gnubby.BROADCAST_CID; 605 self.cid = Gnubby.BROADCAST_CID;
587 cid = self.cid; 606 cid = self.cid;
588 } 607 }
589 var cmd = GnubbyDevice.CMD_INIT; 608 var cmd = GnubbyDevice.CMD_INIT;
590 self.dev.queueCommand(cid, cmd, nonce); 609 self.dev.queueCommand(cid, cmd, nonce);
591 } 610 }
592 611
593 function initSentinelEquals(f) { 612 function initSentinelEquals(f) {
594 return (f[4] == GnubbyDevice.CMD_INIT && 613 return (
595 f.length >= nonce.length + 7 && 614 f[4] == GnubbyDevice.CMD_INIT && f.length >= nonce.length + 7 &&
596 UTIL_equalArrays(f.subarray(7, nonce.length + 7), nonce)); 615 UTIL_equalArrays(f.subarray(7, nonce.length + 7), nonce));
597 } 616 }
598 617
599 function initCmdUnsupported(rc) { 618 function initCmdUnsupported(rc) {
600 // Different firmwares fail differently on different inputs, so treat any 619 // Different firmwares fail differently on different inputs, so treat any
601 // of the following errors as indicating the INIT command isn't supported. 620 // of the following errors as indicating the INIT command isn't supported.
602 return rc == -GnubbyDevice.INVALID_CMD || 621 return rc == -GnubbyDevice.INVALID_CMD || rc == -GnubbyDevice.INVALID_PAR ||
603 rc == -GnubbyDevice.INVALID_PAR ||
604 rc == -GnubbyDevice.INVALID_LEN; 622 rc == -GnubbyDevice.INVALID_LEN;
605 } 623 }
606 624
607 function initCompletionAction(rc, opt_frame) { 625 function initCompletionAction(rc, opt_frame) {
608 // Actual failures: bail out. 626 // Actual failures: bail out.
609 if (rc && !initCmdUnsupported(rc)) { 627 if (rc && !initCmdUnsupported(rc)) {
610 console.warn(UTIL_fmt('init failed: ' + rc)); 628 console.warn(UTIL_fmt('init failed: ' + rc));
611 returnValue(rc); 629 returnValue(rc);
612 } 630 }
613 631
614 var HEADER_LENGTH = 7; 632 var HEADER_LENGTH = 7;
615 var MIN_LENGTH = HEADER_LENGTH + 4; // 4 bytes for the channel id 633 var MIN_LENGTH = HEADER_LENGTH + 4; // 4 bytes for the channel id
616 if (rc || !opt_frame || opt_frame.length < nonce.length + MIN_LENGTH) { 634 if (rc || !opt_frame || opt_frame.length < nonce.length + MIN_LENGTH) {
617 // INIT command not supported or is missing the returned channel id: 635 // INIT command not supported or is missing the returned channel id:
618 // Pick a random cid to try to prevent collisions on the USB bus. 636 // Pick a random cid to try to prevent collisions on the USB bus.
619 var rnd = UTIL_getRandom(2); 637 var rnd = UTIL_getRandom(2);
620 self.cid = Gnubby.defaultChannelId_(self.gnubbyInstance, self.which); 638 self.cid = Gnubby.defaultChannelId_(self.gnubbyInstance, self.which);
621 self.cid ^= (rnd[0] << 16) | (rnd[1] << 8); 639 self.cid ^= (rnd[0] << 16) | (rnd[1] << 8);
622 // Now sync with that cid, to make sure we've got it. 640 // Now sync with that cid, to make sure we've got it.
623 setSync(); 641 setSync();
624 timeoutLoop(); 642 timeoutLoop();
625 return; 643 return;
626 } 644 }
627 // Accept the provided cid. 645 // Accept the provided cid.
628 var offs = HEADER_LENGTH + nonce.length; 646 var offs = HEADER_LENGTH + nonce.length;
629 self.cid = (opt_frame[offs] << 24) | 647 self.cid = (opt_frame[offs] << 24) | (opt_frame[offs + 1] << 16) |
630 (opt_frame[offs + 1] << 16) | 648 (opt_frame[offs + 2] << 8) | opt_frame[offs + 3];
631 (opt_frame[offs + 2] << 8) |
632 opt_frame[offs + 3];
633 returnValue(rc); 649 returnValue(rc);
634 } 650 }
635 651
636 function checkSentinel() { 652 function checkSentinel() {
637 var f = new Uint8Array(self.readFrame_()); 653 var f = new Uint8Array(self.readFrame_());
638 654
639 // Stop on errors and return them. 655 // Stop on errors and return them.
640 if (f[4] == GnubbyDevice.CMD_ERROR && 656 if (f[4] == GnubbyDevice.CMD_ERROR && f[5] == 0 && f[6] == 1) {
641 f[5] == 0 && f[6] == 1) {
642 if (f[7] == GnubbyDevice.BUSY) { 657 if (f[7] == GnubbyDevice.BUSY) {
643 // Not spec but some devices do this; retry. 658 // Not spec but some devices do this; retry.
644 sendSentinel(); 659 sendSentinel();
645 self.notifyFrame_(checkSentinel); 660 self.notifyFrame_(checkSentinel);
646 return; 661 return;
647 } 662 }
648 if (f[7] == GnubbyDevice.GONE) { 663 if (f[7] == GnubbyDevice.GONE) {
649 // Device disappeared on us. 664 // Device disappeared on us.
650 self.closed = true; 665 self.closed = true;
651 } 666 }
652 callback(-f[7]); 667 callback(-f[7]);
653 return; 668 return;
654 } 669 }
655 670
656 // Eat everything else but expected sentinel reply. 671 // Eat everything else but expected sentinel reply.
657 if (!sentinelEquals(f)) { 672 if (!sentinelEquals(f)) {
658 // Read more. 673 // Read more.
659 self.notifyFrame_(checkSentinel); 674 self.notifyFrame_(checkSentinel);
660 return; 675 return;
661 } 676 }
662 677
663 // Done. 678 // Done.
664 callback(-GnubbyDevice.OK, f); 679 callback(-GnubbyDevice.OK, f);
665 } 680 }
666 681
667 function timeoutLoop() { 682 function timeoutLoop() {
668 if (done) return; 683 if (done)
684 return;
669 685
670 if (trycount == 0) { 686 if (trycount == 0) {
671 // Failed. 687 // Failed.
672 callback(-GnubbyDevice.TIMEOUT); 688 callback(-GnubbyDevice.TIMEOUT);
673 return; 689 return;
674 } 690 }
675 691
676 --trycount; // Try another one. 692 --trycount; // Try another one.
677 sendSentinel(); 693 sendSentinel();
678 self.notifyFrame_(checkSentinel); 694 self.notifyFrame_(checkSentinel);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
713 // Make our application level tolerance a little longer. 729 // Make our application level tolerance a little longer.
714 /** Maximum timeout in seconds */ 730 /** Maximum timeout in seconds */
715 Gnubby.MAX_TIMEOUT = 31; 731 Gnubby.MAX_TIMEOUT = 31;
716 732
717 /** Blink led 733 /** Blink led
718 * @param {number|ArrayBuffer|Uint8Array} data Command data or number 734 * @param {number|ArrayBuffer|Uint8Array} data Command data or number
719 * of seconds to blink 735 * of seconds to blink
720 * @param {?function(...)} cb Callback 736 * @param {?function(...)} cb Callback
721 */ 737 */
722 Gnubby.prototype.blink = function(data, cb) { 738 Gnubby.prototype.blink = function(data, cb) {
723 if (!cb) cb = Gnubby.defaultCallback; 739 if (!cb)
740 cb = Gnubby.defaultCallback;
724 if (typeof data == 'number') { 741 if (typeof data == 'number') {
725 var d = new Uint8Array([data]); 742 var d = new Uint8Array([data]);
726 data = d.buffer; 743 data = d.buffer;
727 } 744 }
728 this.exchange_(GnubbyDevice.CMD_PROMPT, data, Gnubby.NORMAL_TIMEOUT, cb); 745 this.exchange_(GnubbyDevice.CMD_PROMPT, data, Gnubby.NORMAL_TIMEOUT, cb);
729 }; 746 };
730 747
731 /** Lock the gnubby 748 /** Lock the gnubby
732 * @param {number|ArrayBuffer|Uint8Array} data Command data 749 * @param {number|ArrayBuffer|Uint8Array} data Command data
733 * @param {?function(...)} cb Callback 750 * @param {?function(...)} cb Callback
734 */ 751 */
735 Gnubby.prototype.lock = function(data, cb) { 752 Gnubby.prototype.lock = function(data, cb) {
736 if (!cb) cb = Gnubby.defaultCallback; 753 if (!cb)
754 cb = Gnubby.defaultCallback;
737 if (typeof data == 'number') { 755 if (typeof data == 'number') {
738 var d = new Uint8Array([data]); 756 var d = new Uint8Array([data]);
739 data = d.buffer; 757 data = d.buffer;
740 } 758 }
741 this.exchange_(GnubbyDevice.CMD_LOCK, data, Gnubby.NORMAL_TIMEOUT, cb); 759 this.exchange_(GnubbyDevice.CMD_LOCK, data, Gnubby.NORMAL_TIMEOUT, cb);
742 }; 760 };
743 761
744 /** Unlock the gnubby 762 /** Unlock the gnubby
745 * @param {?function(...)} cb Callback 763 * @param {?function(...)} cb Callback
746 */ 764 */
747 Gnubby.prototype.unlock = function(cb) { 765 Gnubby.prototype.unlock = function(cb) {
748 if (!cb) cb = Gnubby.defaultCallback; 766 if (!cb)
767 cb = Gnubby.defaultCallback;
749 var data = new Uint8Array([0]); 768 var data = new Uint8Array([0]);
750 this.exchange_(GnubbyDevice.CMD_LOCK, data.buffer, 769 this.exchange_(GnubbyDevice.CMD_LOCK, data.buffer, Gnubby.NORMAL_TIMEOUT, cb);
751 Gnubby.NORMAL_TIMEOUT, cb);
752 }; 770 };
753 771
754 /** Request system information data. 772 /** Request system information data.
755 * @param {?function(...)} cb Callback 773 * @param {?function(...)} cb Callback
756 */ 774 */
757 Gnubby.prototype.sysinfo = function(cb) { 775 Gnubby.prototype.sysinfo = function(cb) {
758 if (!cb) cb = Gnubby.defaultCallback; 776 if (!cb)
759 this.exchange_(GnubbyDevice.CMD_SYSINFO, new ArrayBuffer(0), 777 cb = Gnubby.defaultCallback;
760 Gnubby.NORMAL_TIMEOUT, cb); 778 this.exchange_(
779 GnubbyDevice.CMD_SYSINFO, new ArrayBuffer(0), Gnubby.NORMAL_TIMEOUT, cb);
761 }; 780 };
762 781
763 /** Send wink command 782 /** Send wink command
764 * @param {?function(...)} cb Callback 783 * @param {?function(...)} cb Callback
765 */ 784 */
766 Gnubby.prototype.wink = function(cb) { 785 Gnubby.prototype.wink = function(cb) {
767 if (!cb) cb = Gnubby.defaultCallback; 786 if (!cb)
768 this.exchange_(GnubbyDevice.CMD_WINK, new ArrayBuffer(0), 787 cb = Gnubby.defaultCallback;
769 Gnubby.NORMAL_TIMEOUT, cb); 788 this.exchange_(
789 GnubbyDevice.CMD_WINK, new ArrayBuffer(0), Gnubby.NORMAL_TIMEOUT, cb);
770 }; 790 };
771 791
772 /** Send DFU (Device firmware upgrade) command 792 /** Send DFU (Device firmware upgrade) command
773 * @param {ArrayBuffer|Uint8Array} data Command data 793 * @param {ArrayBuffer|Uint8Array} data Command data
774 * @param {?function(...)} cb Callback 794 * @param {?function(...)} cb Callback
775 */ 795 */
776 Gnubby.prototype.dfu = function(data, cb) { 796 Gnubby.prototype.dfu = function(data, cb) {
777 if (!cb) cb = Gnubby.defaultCallback; 797 if (!cb)
798 cb = Gnubby.defaultCallback;
778 this.exchange_(GnubbyDevice.CMD_DFU, data, Gnubby.NORMAL_TIMEOUT, cb); 799 this.exchange_(GnubbyDevice.CMD_DFU, data, Gnubby.NORMAL_TIMEOUT, cb);
779 }; 800 };
780 801
781 /** Ping the gnubby 802 /** Ping the gnubby
782 * @param {number|ArrayBuffer|Uint8Array} data Command data 803 * @param {number|ArrayBuffer|Uint8Array} data Command data
783 * @param {?function(...)} cb Callback 804 * @param {?function(...)} cb Callback
784 */ 805 */
785 Gnubby.prototype.ping = function(data, cb) { 806 Gnubby.prototype.ping = function(data, cb) {
786 if (!cb) cb = Gnubby.defaultCallback; 807 if (!cb)
808 cb = Gnubby.defaultCallback;
787 if (typeof data == 'number') { 809 if (typeof data == 'number') {
788 var d = new Uint8Array(data); 810 var d = new Uint8Array(data);
789 window.crypto.getRandomValues(d); 811 window.crypto.getRandomValues(d);
790 data = d.buffer; 812 data = d.buffer;
791 } 813 }
792 this.exchange_(GnubbyDevice.CMD_PING, data, Gnubby.NORMAL_TIMEOUT, cb); 814 this.exchange_(GnubbyDevice.CMD_PING, data, Gnubby.NORMAL_TIMEOUT, cb);
793 }; 815 };
794 816
795 /** Send a raw APDU command 817 /** Send a raw APDU command
796 * @param {ArrayBuffer|Uint8Array} data Command data 818 * @param {ArrayBuffer|Uint8Array} data Command data
797 * @param {?function(...)} cb Callback 819 * @param {?function(...)} cb Callback
798 */ 820 */
799 Gnubby.prototype.apdu = function(data, cb) { 821 Gnubby.prototype.apdu = function(data, cb) {
800 if (!cb) cb = Gnubby.defaultCallback; 822 if (!cb)
823 cb = Gnubby.defaultCallback;
801 this.exchange_(GnubbyDevice.CMD_APDU, data, Gnubby.MAX_TIMEOUT, cb); 824 this.exchange_(GnubbyDevice.CMD_APDU, data, Gnubby.MAX_TIMEOUT, cb);
802 }; 825 };
803 826
804 /** Reset gnubby 827 /** Reset gnubby
805 * @param {?function(...)} cb Callback 828 * @param {?function(...)} cb Callback
806 */ 829 */
807 Gnubby.prototype.reset = function(cb) { 830 Gnubby.prototype.reset = function(cb) {
808 if (!cb) cb = Gnubby.defaultCallback; 831 if (!cb)
809 this.exchange_(GnubbyDevice.CMD_ATR, new ArrayBuffer(0), 832 cb = Gnubby.defaultCallback;
810 Gnubby.MAX_TIMEOUT, cb); 833 this.exchange_(
834 GnubbyDevice.CMD_ATR, new ArrayBuffer(0), Gnubby.MAX_TIMEOUT, cb);
811 }; 835 };
812 836
813 // byte args[3] = [delay-in-ms before disabling interrupts, 837 // byte args[3] = [delay-in-ms before disabling interrupts,
814 // delay-in-ms before disabling usb (aka remove), 838 // delay-in-ms before disabling usb (aka remove),
815 // delay-in-ms before reboot (aka insert)] 839 // delay-in-ms before reboot (aka insert)]
816 /** Send usb test command 840 /** Send usb test command
817 * @param {ArrayBuffer|Uint8Array} args Command data 841 * @param {ArrayBuffer|Uint8Array} args Command data
818 * @param {?function(...)} cb Callback 842 * @param {?function(...)} cb Callback
819 */ 843 */
820 Gnubby.prototype.usb_test = function(args, cb) { 844 Gnubby.prototype.usb_test = function(args, cb) {
821 if (!cb) cb = Gnubby.defaultCallback; 845 if (!cb)
846 cb = Gnubby.defaultCallback;
822 var u8 = new Uint8Array(args); 847 var u8 = new Uint8Array(args);
823 this.exchange_(GnubbyDevice.CMD_USB_TEST, u8.buffer, 848 this.exchange_(
824 Gnubby.NORMAL_TIMEOUT, cb); 849 GnubbyDevice.CMD_USB_TEST, u8.buffer, Gnubby.NORMAL_TIMEOUT, cb);
825 }; 850 };
826 851
827 /** APDU command with reply 852 /** APDU command with reply
828 * @param {ArrayBuffer|Uint8Array} request The request 853 * @param {ArrayBuffer|Uint8Array} request The request
829 * @param {?function(...)} cb Callback 854 * @param {?function(...)} cb Callback
830 * @param {boolean=} opt_nowink Do not wink 855 * @param {boolean=} opt_nowink Do not wink
831 */ 856 */
832 Gnubby.prototype.apduReply = function(request, cb, opt_nowink) { 857 Gnubby.prototype.apduReply = function(request, cb, opt_nowink) {
833 if (!cb) cb = Gnubby.defaultCallback; 858 if (!cb)
859 cb = Gnubby.defaultCallback;
834 var self = this; 860 var self = this;
835 861
836 this.apdu(request, function(rc, data) { 862 this.apdu(request, function(rc, data) {
837 if (rc == 0) { 863 if (rc == 0) {
838 var r8 = new Uint8Array(data); 864 var r8 = new Uint8Array(data);
839 if (r8[r8.length - 2] == 0x90 && r8[r8.length - 1] == 0x00) { 865 if (r8[r8.length - 2] == 0x90 && r8[r8.length - 1] == 0x00) {
840 // strip trailing 9000 866 // strip trailing 9000
841 var buf = new Uint8Array(r8.subarray(0, r8.length - 2)); 867 var buf = new Uint8Array(r8.subarray(0, r8.length - 2));
842 cb(-GnubbyDevice.OK, buf.buffer); 868 cb(-GnubbyDevice.OK, buf.buffer);
843 return; 869 return;
844 } else { 870 } else {
845 // return non-9000 as rc 871 // return non-9000 as rc
846 rc = r8[r8.length - 2] * 256 + r8[r8.length - 1]; 872 rc = r8[r8.length - 2] * 256 + r8[r8.length - 1];
847 // wink gnubby at hand if it needs touching. 873 // wink gnubby at hand if it needs touching.
848 if (rc == 0x6985 && !opt_nowink) { 874 if (rc == 0x6985 && !opt_nowink) {
849 self.wink(function() { cb(rc); }); 875 self.wink(function() {
876 cb(rc);
877 });
850 return; 878 return;
851 } 879 }
852 } 880 }
853 } 881 }
854 // Warn on errors other than waiting for touch, wrong data, and 882 // Warn on errors other than waiting for touch, wrong data, and
855 // unrecognized command. 883 // unrecognized command.
856 if (rc != 0x6985 && rc != 0x6a80 && rc != 0x6d00) { 884 if (rc != 0x6985 && rc != 0x6a80 && rc != 0x6d00) {
857 console.warn(UTIL_fmt('apduReply_ fail: ' + rc.toString(16))); 885 console.warn(UTIL_fmt('apduReply_ fail: ' + rc.toString(16)));
858 } 886 }
859 cb(rc); 887 cb(rc);
860 }); 888 });
861 }; 889 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698