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 Does common handling for requests coming from web pages and 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * routes them to the provided handler. 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Gets the scheme + origin from a web url. 12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} url Input url 13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @return {?string} Scheme and origin part if url parses 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction getOriginFromUrl(url) { 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var re = new RegExp('^(https?://)[^/]*/?'); 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var originarray = re.exec(url); 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (originarray == null) return originarray; 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var origin = originarray[0]; 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu while (origin.charAt(origin.length - 1) == '/') { 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu origin = origin.substring(0, origin.length - 1); 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (origin == 'http:' || origin == 'https:') 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return null; 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return origin; 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Returns whether the registered key appears to be valid. 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Object} registeredKey The registered key object. 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean} appIdRequired Whether the appId property is required on 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * each challenge. 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {boolean} Whether the object appears valid. 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction isValidRegisteredKey(registeredKey, appIdRequired) { 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (appIdRequired && !registeredKey.hasOwnProperty('appId')) { 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!registeredKey.hasOwnProperty('keyHandle')) 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (registeredKey['version']) { 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (registeredKey['version'] != 'U2F_V1' && 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci registeredKey['version'] != 'U2F_V2') { 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Returns whether the array of registered keys appears to be valid. 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Array.<Object>} registeredKeys The array of registered keys. 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean} appIdRequired Whether the appId property is required on 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * each challenge. 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {boolean} Whether the array appears valid. 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction isValidRegisteredKeyArray(registeredKeys, appIdRequired) { 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return registeredKeys.every(function(key) { 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return isValidRegisteredKey(key, appIdRequired); 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }); 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Returns whether the array of SignChallenges appears to be valid. 656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Array.<SignChallenge>} signChallenges The array of sign challenges. 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {boolean} appIdRequired Whether the appId property is required on 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * each challenge. 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {boolean} Whether the array appears valid. 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction isValidSignChallengeArray(signChallenges, appIdRequired) { 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (var i = 0; i < signChallenges.length; i++) { 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var incomingChallenge = signChallenges[i]; 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!incomingChallenge.hasOwnProperty('challenge')) 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!isValidRegisteredKey(incomingChallenge, appIdRequired)) { 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return false; 775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return true; 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Posts the log message to the log url. 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string} logMsg the log message to post. 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {string=} opt_logMsgUrl the url to post log messages to. 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction logMessage(logMsg, opt_logMsgUrl) { 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.log(UTIL_fmt('logMessage("' + logMsg + '")')); 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!opt_logMsgUrl) { 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Image fetching is not allowed per packaged app CSP. 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // But video and audio is. 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var audio = new Audio(); 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu audio.src = opt_logMsgUrl + logMsg; 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Object} request Request object 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {MessageSender} sender Sender frame 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {Function} sendResponse Response callback 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {?Closeable} Optional handler object that should be closed when port 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * closes 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */ 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction handleWebPageRequest(request, sender, sendResponse) { 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci switch (request.type) { 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case GnubbyMsgTypes.ENROLL_WEB_REQUEST: 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return handleWebEnrollRequest(sender, request, sendResponse); 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case GnubbyMsgTypes.SIGN_WEB_REQUEST: 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return handleWebSignRequest(sender, request, sendResponse); 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case MessageTypes.U2F_REGISTER_REQUEST: 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return handleU2fEnrollRequest(sender, request, sendResponse); 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case MessageTypes.U2F_SIGN_REQUEST: 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return handleU2fSignRequest(sender, request, sendResponse); 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci default: 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sendResponse( 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci makeU2fErrorResponse(request, ErrorCodes.BAD_REQUEST, undefined, 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MessageTypes.U2F_REGISTER_RESPONSE)); 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return null; 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/** 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Makes a response to a request. 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} request The request to make a response to. 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {string} responseSuffix How to name the response's type. 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {string=} opt_defaultType The default response type, if none is 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * present in the request. 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {Object} The response object. 1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function makeResponseForRequest(request, responseSuffix, opt_defaultType) { 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var type; 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (request && request.type) { 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) type = request.type.replace(/_request$/, responseSuffix); 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else { 1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) type = opt_defaultType; 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var reply = { 'type': type }; 1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (request && request.requestId) { 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reply.requestId = request.requestId; 1456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return reply; 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Makes a response to a U2F request with an error code. 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} request The request to make a response to. 1526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {ErrorCodes} code The error code to return. 1536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {string=} opt_detail An error detail string. 1546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {string=} opt_defaultType The default response type, if none is 1556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * present in the request. 1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {Object} The U2F error. 1576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function makeU2fErrorResponse(request, code, opt_detail, opt_defaultType) { 1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var reply = makeResponseForRequest(request, '_response', opt_defaultType); 1606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var error = {'errorCode': code}; 1616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (opt_detail) { 1626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) error['errorMessage'] = opt_detail; 1636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reply['responseData'] = error; 1656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return reply; 1666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Makes a success response to a web request with a responseData object. 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} request The request to make a response to. 1716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} responseData The response data. 1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {Object} The web error. 1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function makeU2fSuccessResponse(request, responseData) { 1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var reply = makeResponseForRequest(request, '_response'); 1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reply['responseData'] = responseData; 1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return reply; 1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Makes a response to a web request with an error code. 1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} request The request to make a response to. 1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {GnubbyCodeTypes} code The error code to return. 1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {string=} opt_defaultType The default response type, if none is 1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * present in the request. 1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {Object} The web error. 1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function makeWebErrorResponse(request, code, opt_defaultType) { 1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var reply = makeResponseForRequest(request, '_reply', opt_defaultType); 1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reply['code'] = code; 1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return reply; 1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Makes a success response to a web request with a responseData object. 1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} request The request to make a response to. 1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Object} responseData The response data. 1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {Object} The web error. 1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function makeWebSuccessResponse(request, responseData) { 2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var reply = makeResponseForRequest(request, '_reply'); 2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reply['code'] = GnubbyCodeTypes.OK; 2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) reply['responseData'] = responseData; 2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return reply; 2056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 2086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Maps an error code from the ErrorCodes namespace to the GnubbyCodeTypes 2096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * namespace. 2106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {ErrorCodes} errorCode Error in the ErrorCodes namespace. 2116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {boolean} forSign Whether the error is for a sign request. 2126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {GnubbyCodeTypes} Error code in the GnubbyCodeTypes namespace. 2136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function mapErrorCodeToGnubbyCodeType(errorCode, forSign) { 2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var code; 2166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) switch (errorCode) { 2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case ErrorCodes.BAD_REQUEST: 2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return GnubbyCodeTypes.BAD_REQUEST; 2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case ErrorCodes.DEVICE_INELIGIBLE: 2216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return forSign ? GnubbyCodeTypes.NONE_PLUGGED_ENROLLED : 2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) GnubbyCodeTypes.ALREADY_ENROLLED; 2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case ErrorCodes.TIMEOUT: 2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return GnubbyCodeTypes.WAIT_TOUCH; 2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return GnubbyCodeTypes.UNKNOWN_ERROR; 2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Maps a helper's error code from the DeviceStatusCodes namespace to a 2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * U2fError. 2336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {number} code Error code from DeviceStatusCodes namespace. 2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @return {U2fError} An error. 2356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction mapDeviceStatusCodeToU2fError(code) { 2376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) switch (code) { 2386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case DeviceStatusCodes.WRONG_DATA_STATUS: 2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return {errorCode: ErrorCodes.DEVICE_INELIGIBLE}; 2406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case DeviceStatusCodes.TIMEOUT_STATUS: 2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case DeviceStatusCodes.WAIT_TOUCH_STATUS: 2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return {errorCode: ErrorCodes.TIMEOUT}; 2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci default: 2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci var reportedError = { 2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci errorCode: ErrorCodes.OTHER_ERROR, 2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci errorMessage: 'device status code: ' + code.toString(16) 2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci }; 2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return reportedError; 2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Sends a response, using the given sentinel to ensure at most one response is 2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * sent. Also closes the closeable, if it's given. 2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {boolean} sentResponse Whether a response has already been sent. 2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {?Closeable} closeable A thing to close. 2596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {*} response The response to send. 2606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Function} sendResponse A function to send the response. 2616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 2626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function sendResponseOnce(sentResponse, closeable, response, sendResponse) { 2636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (closeable) { 2646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) closeable.close(); 2656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (!sentResponse) { 2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) sentResponse = true; 2686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) try { 2696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If the page has gone away or the connection has otherwise gone, 2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // sendResponse fails. 2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) sendResponse(response); 2726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } catch (exception) { 2736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.warn('sendResponse failed: ' + exception); 2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else { 2766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) console.warn(UTIL_fmt('Tried to reply more than once! Juan, FIX ME')); 2776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {!string} string Input string 2825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {Array.<number>} SHA256 hash value of string. 2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction sha256HashOfString(string) { 2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var s = new SHA256(); 2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu s.update(UTIL_StringToBytes(string)); 2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return s.digest(); 2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Normalizes the TLS channel ID value: 2925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * 1. Converts semantically empty values (undefined, null, 0) to the empty 2935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * string. 2945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * 2. Converts valid JSON strings to a JS object. 2955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * 3. Otherwise, returns the input value unmodified. 296010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Object|string|undefined} opt_tlsChannelId TLS Channel id 2975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {Object|string} The normalized TLS channel ID value. 2985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction tlsChannelIdValue(opt_tlsChannelId) { 3005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!opt_tlsChannelId) { 3015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Case 1: Always set some value for TLS channel ID, even if it's the empty 3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // string: this browser definitely supports them. 3035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return ''; 3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (typeof opt_tlsChannelId === 'string') { 3065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu try { 3075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var obj = JSON.parse(opt_tlsChannelId); 3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!obj) { 3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Case 1: The string value 'null' parses as the Javascript object null, 3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // so return an empty string: the browser definitely supports TLS 3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // channel id. 3125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return ''; 3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Case 2: return the value as a JS object. 3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return /** @type {Object} */ (obj); 3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } catch (e) { 3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.warn('Unparseable TLS channel ID value ' + opt_tlsChannelId); 3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Case 3: return the value unmodified. 3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return opt_tlsChannelId; 3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Creates a browser data object with the given values. 3265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} type A string representing the "type" of this browser data 3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * object. 3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} serverChallenge The server's challenge, as a base64- 3295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * encoded string. 3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} origin The server's origin, as seen by the browser. 331010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Object|string|undefined} opt_tlsChannelId TLS Channel Id 3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {string} A string representation of the browser data object. 3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction makeBrowserData(type, serverChallenge, origin, opt_tlsChannelId) { 3355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var browserData = { 3365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'typ' : type, 3375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'challenge' : serverChallenge, 3385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'origin' : origin 3395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu }; 3405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu browserData['cid_pubkey'] = tlsChannelIdValue(opt_tlsChannelId); 3415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return JSON.stringify(browserData); 3425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Creates a browser data object for an enroll request with the given values. 3465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} serverChallenge The server's challenge, as a base64- 3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * encoded string. 3485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} origin The server's origin, as seen by the browser. 349010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Object|string|undefined} opt_tlsChannelId TLS Channel Id 3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {string} A string representation of the browser data object. 3515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction makeEnrollBrowserData(serverChallenge, origin, opt_tlsChannelId) { 3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return makeBrowserData( 3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'navigator.id.finishEnrollment', serverChallenge, origin, 3555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu opt_tlsChannelId); 3565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Creates a browser data object for a sign request with the given values. 3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} serverChallenge The server's challenge, as a base64- 3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * encoded string. 3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {!string} origin The server's origin, as seen by the browser. 363010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {Object|string|undefined} opt_tlsChannelId TLS Channel Id 3645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {string} A string representation of the browser data object. 3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liufunction makeSignBrowserData(serverChallenge, origin, opt_tlsChannelId) { 3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return makeBrowserData( 3685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 'navigator.id.getAssertion', serverChallenge, origin, opt_tlsChannelId); 3695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 3726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Encodes the sign data as an array of sign helper challenges. 3736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Array.<SignChallenge>} signChallenges The sign challenges to encode. 3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {string=} opt_defaultAppId The app id to use for each challenge, if 3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * the challenge contains none. 3766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {function(string, string): string=} opt_challengeHashFunction 3776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * A function that produces, from a key handle and a raw challenge, a hash 3786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * of the raw challenge. If none is provided, a default hash function is 3796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * used. 3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {!Array.<SignHelperChallenge>} The sign challenges, encoded. 3815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifunction encodeSignChallenges(signChallenges, opt_defaultAppId, 3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci opt_challengeHashFunction) { 3846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) function encodedSha256(keyHandle, challenge) { 3856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return B64_encode(sha256HashOfString(challenge)); 3866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 3876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var challengeHashFn = opt_challengeHashFunction || encodedSha256; 3886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var encodedSignChallenges = []; 3896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (signChallenges) { 3906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for (var i = 0; i < signChallenges.length; i++) { 3916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var challenge = signChallenges[i]; 3926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var challengeHash = 3936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) challengeHashFn(challenge['keyHandle'], challenge['challenge']); 3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci var appId; 3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (challenge.hasOwnProperty('appId')) { 3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci appId = challenge['appId']; 3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci appId = opt_defaultAppId; 3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var encodedChallenge = { 4016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'challengeHash': challengeHash, 4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'appIdHash': B64_encode(sha256HashOfString(appId)), 4036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'keyHandle': challenge['keyHandle'], 4046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'version': (challenge['version'] || 'U2F_V1') 4056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) }; 4066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) encodedSignChallenges.push(encodedChallenge); 4076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 4086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 4096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return encodedSignChallenges; 4105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 411116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 412116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/** 413116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * Makes a sign helper request from an array of challenges. 414116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {Array.<SignHelperChallenge>} challenges The sign challenges. 415116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {number=} opt_timeoutSeconds Timeout value. 416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {string=} opt_logMsgUrl URL to log to. 417116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @return {SignHelperRequest} The sign helper request. 418116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */ 419116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfunction makeSignHelperRequest(challenges, opt_timeoutSeconds, opt_logMsgUrl) { 420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var request = { 421116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'type': 'sign_helper_request', 422116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'signData': challenges, 4236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'timeout': opt_timeoutSeconds || 0, 4246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'timeoutSeconds': opt_timeoutSeconds || 0 425116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch }; 426116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (opt_logMsgUrl !== undefined) { 427116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch request.logMsgUrl = opt_logMsgUrl; 428116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 429116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return request; 430116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 431