signer.js revision 010d83a9304c5a91596085d917d248abff47903a
15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be 35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @fileoverview Handles web page requests for gnubby sign requests. 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu'use strict'; 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvar signRequestQueue = new OriginKeyedRequestQueue(); 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Handles a sign request. 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!SignHelperFactory} factory Factory to create a sign helper. 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {MessageSender} sender The sender of the message. 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Object} request The web page's sign request. 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {boolean} enforceAppIdValid Whether to enforce that the app id in the 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * request matches the sender's origin. 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Function} sendResponse Called back with the result of the sign. 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {boolean} toleratesMultipleResponses Whether the sendResponse 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * callback can be called more than once, e.g. for progress updates. 23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @return {Closeable} Request handler that should be closed when the browser 24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * message channel is closed. 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction handleSignRequest(factory, sender, request, enforceAppIdValid, 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendResponse, toleratesMultipleResponses) { 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var sentResponse = false; 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function sendResponseOnce(r) { 305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (queuedSignRequest) { 315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu queuedSignRequest.close(); 325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu queuedSignRequest = null; 335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!sentResponse) { 355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sentResponse = true; 365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu try { 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If the page has gone away or the connection has otherwise gone, 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // sendResponse fails. 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendResponse(r); 405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } catch (exception) { 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.warn('sendResponse failed: ' + exception); 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.warn(UTIL_fmt('Tried to reply more than once! Juan, FIX ME')); 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function sendErrorResponse(code) { 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var response = formatWebPageResponse(GnubbyMsgTypes.SIGN_WEB_REPLY, code); 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendResponseOnce(response); 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function sendSuccessResponse(challenge, info, browserData) { 545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var responseData = {}; 555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (var k in challenge) { 565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu responseData[k] = challenge[k]; 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu responseData['browserData'] = B64_encode(UTIL_StringToBytes(browserData)); 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu responseData['signatureData'] = info; 605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var response = formatWebPageResponse(GnubbyMsgTypes.SIGN_WEB_REPLY, 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu GnubbyCodeTypes.OK, responseData); 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendResponseOnce(response); 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function sendNotification(code) { 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.log(UTIL_fmt('notification, code=' + code)); 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Can the callback handle progress updates? If so, send one. 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (toleratesMultipleResponses) { 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var response = formatWebPageResponse( 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu GnubbyMsgTypes.SIGN_WEB_NOTIFICATION, code); 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (request['requestId']) { 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu response['requestId'] = request['requestId']; 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendResponse(response); 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var origin = getOriginFromUrl(/** @type {string} */ (sender.url)); 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!origin) { 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return null; 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // More closure type inference fail. 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var nonNullOrigin = /** @type {string} */ (origin); 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!isValidSignRequest(request)) { 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return null; 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var signData = request['signData']; 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // A valid sign data has at least one challenge, so get the first appId from 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // the first challenge. 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var firstAppId = signData[0]['appId']; 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var timeoutMillis = Signer.DEFAULT_TIMEOUT_MILLIS; 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (request['timeout']) { 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Request timeout is in seconds. 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu timeoutMillis = request['timeout'] * 1000; 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var timer = new CountdownTimer(timeoutMillis); 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var logMsgUrl = request['logMsgUrl']; 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Queue sign requests from the same origin, to protect against simultaneous 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // sign-out on many tabs resulting in repeated sign-in requests. 1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var queuedSignRequest = new QueuedSignRequest(signData, factory, timer, 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu nonNullOrigin, enforceAppIdValid, sendErrorResponse, sendSuccessResponse, 1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu sendNotification, sender.tlsChannelId, logMsgUrl); 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var requestToken = signRequestQueue.queueRequest(firstAppId, nonNullOrigin, 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu queuedSignRequest.begin.bind(queuedSignRequest), timer); 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu queuedSignRequest.setToken(requestToken); 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return queuedSignRequest; 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Returns whether the request appears to be a valid sign request. 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Object} request the request. 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {boolean} whether the request appears valid. 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction isValidSignRequest(request) { 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!request.hasOwnProperty('signData')) 1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var signData = request['signData']; 1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If a sign request contains an empty array of challenges, it could never 1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // be fulfilled. Fail. 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!signData.length) 1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return isValidSignData(signData); 1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Adapter class representing a queued sign request. 132010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {!SignData} signData Signature data 133010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {!SignHelperFactory} factory Factory for SignHelper instances 134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Countdown} timer Timeout timer 135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} origin Signature origin 136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {boolean} enforceAppIdValid If to enforce appId validity 137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {function(number)} errorCb Error callback 138010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {function(SignChallenge, string, string)} successCb Success callback 139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {(function(number)|undefined)} opt_progressCb Progress callback 140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string|undefined} opt_tlsChannelId TLS Channel Id 141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string|undefined} opt_logMsgUrl Url to post log messages to 1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @constructor 1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @implements {Closeable} 1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction QueuedSignRequest(signData, factory, timer, origin, enforceAppIdValid, 1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu errorCb, successCb, opt_progressCb, opt_tlsChannelId, opt_logMsgUrl) { 1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {!SignData} */ 1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signData_ = signData; 1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {!SignHelperFactory} */ 1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.factory_ = factory; 1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Countdown} */ 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timer_ = timer; 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {string} */ 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.origin_ = origin; 1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 1565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.enforceAppIdValid_ = enforceAppIdValid; 1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {function(number)} */ 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.errorCb_ = errorCb; 1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {function(SignChallenge, string, string)} */ 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.successCb_ = successCb; 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {(function(number)|undefined)} */ 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.progressCb_ = opt_progressCb; 1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {string|undefined} */ 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.tlsChannelId_ = opt_tlsChannelId; 1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {string|undefined} */ 1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.logMsgUrl_ = opt_logMsgUrl; 1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.begun_ = false; 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.closed_ = false; 1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Closes this sign request. */ 1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQueuedSignRequest.prototype.close = function() { 1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.closed_) return; 1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.begun_ && this.signer_) { 1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signer_.close(); 1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.token_) { 1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.token_.complete(); 1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.closed_ = true; 1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {QueuedRequestToken} token Token for this sign request. 1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQueuedSignRequest.prototype.setToken = function(token) { 1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {QueuedRequestToken} */ 1905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.token_ = token; 1915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when this sign request may begin work. 1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {QueuedRequestToken} token Token for this sign request. 1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQueuedSignRequest.prototype.begin = function(token) { 1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.begun_ = true; 1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.setToken(token); 2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signer_ = new Signer(this.factory_, this.timer_, this.origin_, 2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.enforceAppIdValid_, this.signerFailed_.bind(this), 2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signerSucceeded_.bind(this), this.progressCb_, 2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.tlsChannelId_, this.logMsgUrl_); 2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!this.signer_.setChallenges(this.signData_)) { 2055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu token.complete(); 2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.errorCb_(GnubbyCodeTypes.BAD_REQUEST); 2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when this request's signer fails. 2125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number} code The failure code reported by the signer. 2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQueuedSignRequest.prototype.signerFailed_ = function(code) { 2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.token_.complete(); 2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.errorCb_(code); 2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when this request's signer succeeds. 2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {SignChallenge} challenge The challenge that was signed. 2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} info The sign result. 224010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} browserData Browser data JSON 2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuQueuedSignRequest.prototype.signerSucceeded_ = 2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function(challenge, info, browserData) { 2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.token_.complete(); 2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.successCb_(challenge, info, browserData); 2315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Creates an object to track signing with a gnubby. 2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!SignHelperFactory} helperFactory Factory to create a sign helper. 2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Countdown} timer Timer for sign request. 2375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} origin The origin making the request. 2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {boolean} enforceAppIdValid Whether to enforce that the appId in the 2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * request matches the sender's origin. 2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {function(number)} errorCb Called when the sign operation fails. 2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {function(SignChallenge, string, string)} successCb Called when the 2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * sign operation succeeds. 2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {(function(number)|undefined)} opt_progressCb Called with progress 2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * updates to the sign request. 2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string=} opt_tlsChannelId the TLS channel ID, if any, of the origin 2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * making the request. 2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string=} opt_logMsgUrl The url to post log messages to. 2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @constructor 2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction Signer(helperFactory, timer, origin, enforceAppIdValid, 2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu errorCb, successCb, opt_progressCb, opt_tlsChannelId, opt_logMsgUrl) { 2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Countdown} */ 2535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.timer_ = timer; 2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {string} */ 2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.origin_ = origin; 2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 2575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.enforceAppIdValid_ = enforceAppIdValid; 2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {function(number)} */ 2595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.errorCb_ = errorCb; 2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {function(SignChallenge, string, string)} */ 2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.successCb_ = successCb; 2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {(function(number)|undefined)} */ 2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.progressCb_ = opt_progressCb; 2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {string|undefined} */ 2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.tlsChannelId_ = opt_tlsChannelId; 2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {string|undefined} */ 2675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.logMsgUrl_ = opt_logMsgUrl; 2685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 2705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.challengesSet_ = false; 2715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Array.<SignHelperChallenge>} */ 2725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.pendingChallenges_ = []; 2735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 2745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.done_ = false; 2755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Object.<string, string>} */ 2775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.browserData_ = {}; 2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Object.<string, SignChallenge>} */ 2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.serverChallenges_ = {}; 2805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Allow http appIds for http origins. (Broken, but the caller deserves 2815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // what they get.) 2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.allowHttp_ = this.origin_ ? this.origin_.indexOf('http://') == 0 : false; 2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Protect against helper failure with a watchdog. 2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.createWatchdog_(timer); 2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {SignHelper} */ 2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.helper_ = helperFactory.createHelper( 2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu timer, this.helperError_.bind(this), this.helperSuccess_.bind(this), 2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.helperProgress_.bind(this), this.logMsgUrl_); 2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 2925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Creates a timer with an expiry greater than the expiration time of the given 2955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * timer. 296010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Countdown} timer Timeout timer 2975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 2985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.createWatchdog_ = function(timer) { 3005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var millis = timer.millisecondsUntilExpired(); 3015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu millis += CountdownTimer.TIMER_INTERVAL_MILLIS; 3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Countdown|undefined} */ 3035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.watchdogTimer_ = new CountdownTimer(millis, this.timeout_.bind(this)); 3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 3055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Default timeout value in case the caller never provides a valid timeout. 3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.DEFAULT_TIMEOUT_MILLIS = 30 * 1000; 3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Sets the challenges to be signed. 3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {SignData} signData The challenges to set. 3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {boolean} Whether the challenges could be set. 3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.setChallenges = function(signData) { 3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.challengesSet_ || this.done_) 3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {SignData} */ 3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signData_ = signData; 3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.challengesSet_ = true; 3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If app id enforcing isn't in effect, go ahead and start the helper with 3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // all of the incoming challenges. 3265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var success = true; 3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!this.enforceAppIdValid_) { 3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu success = this.addChallenges(signData, true /* finalChallenges */); 3295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.checkAppIds_(); 3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return success; 3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 3345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Adds new challenges to the challenges being signed. 3375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {SignData} signData Challenges to add. 3385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {boolean} finalChallenges Whether these are the final challenges. 3395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {boolean} Whether the challenge could be added. 3405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.addChallenges = function(signData, finalChallenges) { 3425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var newChallenges = this.encodeSignChallenges_(signData); 3435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (var i = 0; i < newChallenges.length; i++) { 3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.pendingChallenges_.push(newChallenges[i]); 3455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!finalChallenges) { 3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 3485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return this.helper_.doSign(this.pendingChallenges_); 3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 3515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Creates challenges for helper from challenges. 3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Array.<SignChallenge>} challenges Challenges to add. 355010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @return {Array.<SignHelperChallenge>} Encoded challenges 3565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.encodeSignChallenges_ = function(challenges) { 3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var newChallenges = []; 3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (var i = 0; i < challenges.length; i++) { 3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var incomingChallenge = challenges[i]; 3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var serverChallenge = incomingChallenge['challenge']; 3635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var appId = incomingChallenge['appId']; 3645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var encodedKeyHandle = incomingChallenge['keyHandle']; 3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var version = incomingChallenge['version']; 3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var browserData = 3685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu makeSignBrowserData(serverChallenge, this.origin_, this.tlsChannelId_); 3695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var encodedChallenge = makeChallenge(browserData, appId, encodedKeyHandle, 3705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu version); 3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var key = encodedKeyHandle + encodedChallenge['challengeHash']; 3735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.browserData_[key] = browserData; 3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.serverChallenges_[key] = incomingChallenge; 3755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu newChallenges.push(encodedChallenge); 3775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return newChallenges; 3795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 3805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Checks the app ids of incoming requests, and, when this signer is enforcing 3835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * that app ids are valid, adds successful challenges to those being signed. 3845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 3855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.checkAppIds_ = function() { 3875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Check the incoming challenges' app ids. 3885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {Array.<[string, Array.<Request>]>} */ 3895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.orderedRequests_ = requestsByAppId(this.signData_); 3905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!this.orderedRequests_.length) { 3915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Safety check: if the challenges are somehow empty, the helper will never 3925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // be fed any data, so the request could never be satisfied. You lose. 3935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyError_(GnubbyCodeTypes.BAD_REQUEST); 3945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 3955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {number} */ 3975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.fetchedAppIds_ = 0; 3985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {number} */ 3995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.validAppIds_ = 0; 4005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (var i = 0, appIdRequestsPair; i < this.orderedRequests_.length; i++) { 4015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var appIdRequestsPair = this.orderedRequests_[i]; 4025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var appId = appIdRequestsPair[0]; 4035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var requests = appIdRequestsPair[1]; 4045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (appId == this.origin_) { 4055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Trivially allowed. 4065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.fetchedAppIds_++; 4075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.validAppIds_++; 4085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Only add challenges if in enforcing mode, i.e. they weren't added 4095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // earlier. 4105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.enforceAppIdValid_) { 4115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.addChallenges(requests, 4125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.fetchedAppIds_ == this.orderedRequests_.length); 4135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 4155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var start = new Date(); 4165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu fetchAllowedOriginsForAppId(appId, this.allowHttp_, 4175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, 4185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu requests)); 4195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 4225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 4245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called with the result of an app id fetch. 4255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} appId the app id that was fetched. 4265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Date} start the time the fetch request started. 4275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {Array.<SignChallenge>} challenges Challenges for this app id. 4285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number} rc The HTTP response code for the app id fetch. 4295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!Array.<string>} allowedOrigins The origins allowed for this app id. 4305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 4315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 4325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.fetchedAllowedOriginsForAppId_ = function(appId, start, 4335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu challenges, rc, allowedOrigins) { 4345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var end = new Date(); 4355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu logFetchAppIdResult(appId, end - start, allowedOrigins, this.logMsgUrl_); 4365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (rc != 200 && !(rc >= 400 && rc < 500)) { 4375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.timer_.expired()) { 4385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Act as though the helper timed out. 4395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.helperError_(DeviceStatusCodes.TIMEOUT_STATUS, false); 4405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 4415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu start = new Date(); 4425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu fetchAllowedOriginsForAppId(appId, this.allowHttp_, 4435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, 4445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu challenges)); 4455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 4475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.fetchedAppIds_++; 4495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var finalChallenges = (this.fetchedAppIds_ == this.orderedRequests_.length); 4505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (isValidAppIdForOrigin(appId, this.origin_, allowedOrigins)) { 4515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.validAppIds_++; 4525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Only add challenges if in enforcing mode, i.e. they weren't added 4535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // earlier. 4545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.enforceAppIdValid_) { 4555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.addChallenges(challenges, finalChallenges); 4565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 4585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu logInvalidOriginForAppId(this.origin_, appId, this.logMsgUrl_); 4595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If in enforcing mode and this is the final request, sign the valid 4605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // challenges. 4615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.enforceAppIdValid_ && finalChallenges) { 4625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!this.helper_.doSign(this.pendingChallenges_)) { 4635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyError_(GnubbyCodeTypes.BAD_REQUEST); 4645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 4655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.enforceAppIdValid_ && finalChallenges && !this.validAppIds_) { 4695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If all app ids are invalid, notify the caller, otherwise implicitly 4705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // allow the helper to report whether any of the valid challenges succeeded. 4715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyError_(GnubbyCodeTypes.BAD_APP_ID); 4725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 4735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 4745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 4765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when the timeout expires on this signer. 4775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 4785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 4795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.timeout_ = function() { 4805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.watchdogTimer_ = undefined; 4815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // The web page gets grumpy if it doesn't get WAIT_TOUCH within a reasonable 4825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // time. 4835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyError_(GnubbyCodeTypes.WAIT_TOUCH); 4845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 4855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Closes this signer. */ 4875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.close = function() { 4885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.helper_) this.helper_.close(); 4895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 4905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 4915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 4925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Notifies the caller of error with the given error code. 493010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {number} code Error code 4945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 4955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 4965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.notifyError_ = function(code) { 4975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.done_) 4985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 4995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.close(); 5005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.done_ = true; 5015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.errorCb_(code); 5025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 5035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 5055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Notifies the caller of success. 5065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {SignChallenge} challenge The challenge that was signed. 5075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} info The sign result. 508010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} browserData Browser data JSON 5095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 5105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 5115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.notifySuccess_ = function(challenge, info, browserData) { 5125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.done_) 5135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 5145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.close(); 5155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.done_ = true; 5165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.successCb_(challenge, info, browserData); 5175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 5185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 5205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Notifies the caller of progress with the error code. 521010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {number} code Status code 5225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 5235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 5245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.notifyProgress_ = function(code) { 5255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.done_) 5265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 5275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (code != this.lastProgressUpdate_) { 5285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.lastProgressUpdate_ = code; 5295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If there is no progress callback, treat it like an error and clean up. 5305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.progressCb_) { 5315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.progressCb_(code); 5325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 5335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyError_(code); 5345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 5355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 5365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 5375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 5395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Maps a sign helper's error code namespace to the page's error code namespace. 5405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number} code Error code from DeviceStatusCodes namespace. 5415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {boolean} anyGnubbies Whether any gnubbies were found. 5425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {number} A GnubbyCodeTypes error code. 5435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 5445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 5455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.mapError_ = function(code, anyGnubbies) { 5465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var reportedError; 5475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu switch (code) { 5485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.WRONG_DATA_STATUS: 5495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu reportedError = anyGnubbies ? GnubbyCodeTypes.NONE_PLUGGED_ENROLLED : 5505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu GnubbyCodeTypes.NO_GNUBBIES; 5515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 5525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.OK_STATUS: 5545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // If the error callback is called with OK, it means the signature was 5555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // empty, which we treat the same as... 5565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.WAIT_TOUCH_STATUS: 5575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu reportedError = GnubbyCodeTypes.WAIT_TOUCH; 5585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 5595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.BUSY_STATUS: 5615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu reportedError = GnubbyCodeTypes.BUSY; 5625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 5635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu default: 5655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu reportedError = GnubbyCodeTypes.UNKNOWN_ERROR; 5665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 5675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 5685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return reportedError; 5695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 5705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 5725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called by the helper upon error. 573010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {number} code Error code 574010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {boolean} anyGnubbies If any gnubbies were found 5755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 5765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 5775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.helperError_ = function(code, anyGnubbies) { 5785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.clearTimeout_(); 5795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var reportedError = Signer.mapError_(code, anyGnubbies); 5805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.log(UTIL_fmt('helper reported ' + code.toString(16) + 5815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ', returning ' + reportedError)); 5825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyError_(reportedError); 5835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 5845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 5865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called by helper upon success. 5875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {SignHelperChallenge} challenge The challenge that was signed. 5885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} info The sign result. 5895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 5905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 5915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.helperSuccess_ = function(challenge, info) { 5925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Got a good reply, kill timer. 5935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.clearTimeout_(); 5945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 5955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var key = challenge['keyHandle'] + challenge['challengeHash']; 5965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var browserData = this.browserData_[key]; 5975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Notify with server-provided challenge, not the encoded one: the 5985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // server-provided challenge contains additional fields it relies on. 5995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var serverChallenge = this.serverChallenges_[key]; 6005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifySuccess_(serverChallenge, info, browserData); 6015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 6025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 6035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 6045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called by helper to notify progress. 605010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {number} code Status code 606010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {boolean} anyGnubbies If any gnubbies were found 6075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 6085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 6095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.helperProgress_ = function(code, anyGnubbies) { 6105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var reportedError = Signer.mapError_(code, anyGnubbies); 6115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.log(UTIL_fmt('helper notified ' + code.toString(16) + 6125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ', returning ' + reportedError)); 6135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifyProgress_(reportedError); 6145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 6155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 6165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 6175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Clears the timeout for this signer. 6185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 6195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 6205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuSigner.prototype.clearTimeout_ = function() { 6215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.watchdogTimer_) { 6225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.watchdogTimer_.clearTimeout(); 6235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.watchdogTimer_ = undefined; 6245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 6255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 626