From 36775a196971768c31b20d759a7c5f834f8b4831 Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Mon, 26 Oct 2015 10:25:42 -0600 Subject: [PATCH] only load polyfill in Chrome --- u2f-api.js | 516 +++++++++++++++++++++++++++-------------------------- 1 file changed, 259 insertions(+), 257 deletions(-) diff --git a/u2f-api.js b/u2f-api.js index d974df9..c3bc998 100644 --- a/u2f-api.js +++ b/u2f-api.js @@ -10,289 +10,291 @@ 'use strict'; -/** Namespace for the U2F api. - * @type {Object} - */ -var u2f = u2f || {}; +if (!('u2f' in window) && 'chrome' in window && chrome.runtime) { + /** Namespace for the U2F api. + * @type {Object} + */ + var u2f = {}; -/** - * The U2F extension id - * @type {string} - * @const - */ -u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd'; + /** + * The U2F extension id + * @type {string} + * @const + */ + u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd'; -/** - * Message types for messsages to/from the extension - * @const - * @enum {string} - */ -u2f.MessageTypes = { - 'U2F_REGISTER_REQUEST': 'u2f_register_request', - 'U2F_SIGN_REQUEST': 'u2f_sign_request', - 'U2F_REGISTER_RESPONSE': 'u2f_register_response', - 'U2F_SIGN_RESPONSE': 'u2f_sign_response' -}; + /** + * Message types for messsages to/from the extension + * @const + * @enum {string} + */ + u2f.MessageTypes = { + 'U2F_REGISTER_REQUEST': 'u2f_register_request', + 'U2F_SIGN_REQUEST': 'u2f_sign_request', + 'U2F_REGISTER_RESPONSE': 'u2f_register_response', + 'U2F_SIGN_RESPONSE': 'u2f_sign_response' + }; -/** - * Response status codes - * @const - * @enum {number} - */ -u2f.ErrorCodes = { - 'OK': 0, - 'OTHER_ERROR': 1, - 'BAD_REQUEST': 2, - 'CONFIGURATION_UNSUPPORTED': 3, - 'DEVICE_INELIGIBLE': 4, - 'TIMEOUT': 5 -}; + /** + * Response status codes + * @const + * @enum {number} + */ + u2f.ErrorCodes = { + 'OK': 0, + 'OTHER_ERROR': 1, + 'BAD_REQUEST': 2, + 'CONFIGURATION_UNSUPPORTED': 3, + 'DEVICE_INELIGIBLE': 4, + 'TIMEOUT': 5 + }; -/** - * A message type for registration requests - * @typedef {{ - * type: u2f.MessageTypes, - * signRequests: Array., - * registerRequests: ?Array., - * timeoutSeconds: ?number, - * requestId: ?number - * }} - */ -u2f.Request; + /** + * A message type for registration requests + * @typedef {{ + * type: u2f.MessageTypes, + * signRequests: Array., + * registerRequests: ?Array., + * timeoutSeconds: ?number, + * requestId: ?number + * }} + */ + u2f.Request; -/** - * A message for registration responses - * @typedef {{ - * type: u2f.MessageTypes, - * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse), - * requestId: ?number - * }} - */ -u2f.Response; + /** + * A message for registration responses + * @typedef {{ + * type: u2f.MessageTypes, + * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse), + * requestId: ?number + * }} + */ + u2f.Response; -/** - * An error object for responses - * @typedef {{ - * errorCode: u2f.ErrorCodes, - * errorMessage: ?string - * }} - */ -u2f.Error; + /** + * An error object for responses + * @typedef {{ + * errorCode: u2f.ErrorCodes, + * errorMessage: ?string + * }} + */ + u2f.Error; -/** - * Data object for a single sign request. - * @typedef {{ - * version: string, - * challenge: string, - * keyHandle: string, - * appId: string - * }} - */ -u2f.SignRequest; + /** + * Data object for a single sign request. + * @typedef {{ + * version: string, + * challenge: string, + * keyHandle: string, + * appId: string + * }} + */ + u2f.SignRequest; -/** - * Data object for a sign response. - * @typedef {{ - * keyHandle: string, - * signatureData: string, - * clientData: string - * }} - */ -u2f.SignResponse; + /** + * Data object for a sign response. + * @typedef {{ + * keyHandle: string, + * signatureData: string, + * clientData: string + * }} + */ + u2f.SignResponse; -/** - * Data object for a registration request. - * @typedef {{ - * version: string, - * challenge: string, - * appId: string - * }} - */ -u2f.RegisterRequest; + /** + * Data object for a registration request. + * @typedef {{ + * version: string, + * challenge: string, + * appId: string + * }} + */ + u2f.RegisterRequest; -/** - * Data object for a registration response. - * @typedef {{ - * registrationData: string, - * clientData: string - * }} - */ -u2f.RegisterResponse; + /** + * Data object for a registration response. + * @typedef {{ + * registrationData: string, + * clientData: string + * }} + */ + u2f.RegisterResponse; -// Low level MessagePort API support + // Low level MessagePort API support -/** - * Sets up a MessagePort to the U2F extension using the - * available mechanisms. - * @param {function(u2f.WrappedChromeRuntimePort_)} callback - */ -u2f.getMessagePort = function(callback) { - var port = chrome.runtime.connect(u2f.EXTENSION_ID, - {'includeTlsChannelId': true}); - setTimeout(function() { - callback(new u2f.WrappedChromeRuntimePort_(port)); - }, 0); -}; + /** + * Sets up a MessagePort to the U2F extension using the + * available mechanisms. + * @param {function(u2f.WrappedChromeRuntimePort_)} callback + */ + u2f.getMessagePort = function(callback) { + var port = chrome.runtime.connect(u2f.EXTENSION_ID, + {'includeTlsChannelId': true}); + setTimeout(function() { + callback(new u2f.WrappedChromeRuntimePort_(port)); + }, 0); + }; -/** - * A wrapper for chrome.runtime.Port that is compatible with MessagePort. - * @param {Port} port - * @constructor - * @private - */ -u2f.WrappedChromeRuntimePort_ = function(port) { - this.port_ = port; -}; + /** + * A wrapper for chrome.runtime.Port that is compatible with MessagePort. + * @param {Port} port + * @constructor + * @private + */ + u2f.WrappedChromeRuntimePort_ = function(port) { + this.port_ = port; + }; -/** - * Posts a message on the underlying channel. - * @param {Object} message - */ -u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) { - this.port_.postMessage(message); -}; + /** + * Posts a message on the underlying channel. + * @param {Object} message + */ + u2f.WrappedChromeRuntimePort_.prototype.postMessage = function(message) { + this.port_.postMessage(message); + }; -/** - * Emulates the HTML 5 addEventListener interface. Works only for the - * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage. - * @param {string} eventName - * @param {function({data: Object})} handler - */ -u2f.WrappedChromeRuntimePort_.prototype.addEventListener = - function(eventName, handler) { - var name = eventName.toLowerCase(); - if (name == 'message' || name == 'onmessage') { - this.port_.onMessage.addListener(function(message) { - // Emulate a minimal MessageEvent object - handler({'data': message}); - }); - } else { - console.error('WrappedChromeRuntimePort only supports onMessage'); - } -}; + /** + * Emulates the HTML 5 addEventListener interface. Works only for the + * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage. + * @param {string} eventName + * @param {function({data: Object})} handler + */ + u2f.WrappedChromeRuntimePort_.prototype.addEventListener = + function(eventName, handler) { + var name = eventName.toLowerCase(); + if (name == 'message' || name == 'onmessage') { + this.port_.onMessage.addListener(function(message) { + // Emulate a minimal MessageEvent object + handler({'data': message}); + }); + } else { + console.error('WrappedChromeRuntimePort only supports onMessage'); + } + }; -// High-level JS API + // High-level JS API -/** - * Default extension response timeout in seconds. - * @const - */ -u2f.EXTENSION_TIMEOUT_SEC = 30; + /** + * Default extension response timeout in seconds. + * @const + */ + u2f.EXTENSION_TIMEOUT_SEC = 30; -/** - * A singleton instance for a MessagePort to the extension. - * @type {MessagePort|u2f.WrappedChromeRuntimePort_} - * @private - */ -u2f.port_ = null; + /** + * A singleton instance for a MessagePort to the extension. + * @type {MessagePort|u2f.WrappedChromeRuntimePort_} + * @private + */ + u2f.port_ = null; -/** - * Callbacks waiting for a port - * @type {Array.} - * @private - */ -u2f.waitingForPort_ = []; + /** + * Callbacks waiting for a port + * @type {Array.} + * @private + */ + u2f.waitingForPort_ = []; -/** - * A counter for requestIds. - * @type {number} - * @private - */ -u2f.reqCounter_ = 0; + /** + * A counter for requestIds. + * @type {number} + * @private + */ + u2f.reqCounter_ = 0; -/** - * A map from requestIds to client callbacks - * @type {Object.} - * @private - */ -u2f.callbackMap_ = {}; + /** + * A map from requestIds to client callbacks + * @type {Object.} + * @private + */ + u2f.callbackMap_ = {}; -/** - * Creates or retrieves the MessagePort singleton to use. - * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback - * @private - */ -u2f.getPortSingleton_ = function(callback) { - if (u2f.port_) { - callback(u2f.port_); - } else { - if (u2f.waitingForPort_.length == 0) { - u2f.getMessagePort(function(port) { - u2f.port_ = port; - u2f.port_.addEventListener('message', - /** @type {function(Event)} */ (u2f.responseHandler_)); + /** + * Creates or retrieves the MessagePort singleton to use. + * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback + * @private + */ + u2f.getPortSingleton_ = function(callback) { + if (u2f.port_) { + callback(u2f.port_); + } else { + if (u2f.waitingForPort_.length == 0) { + u2f.getMessagePort(function(port) { + u2f.port_ = port; + u2f.port_.addEventListener('message', + /** @type {function(Event)} */ (u2f.responseHandler_)); - // Careful, here be async callbacks. Maybe. - while (u2f.waitingForPort_.length) - u2f.waitingForPort_.shift()(u2f.port_); - }); + // Careful, here be async callbacks. Maybe. + while (u2f.waitingForPort_.length) + u2f.waitingForPort_.shift()(u2f.port_); + }); + } + u2f.waitingForPort_.push(callback); } - u2f.waitingForPort_.push(callback); - } -}; + }; -/** - * Handles response messages from the extension. - * @param {MessageEvent.} message - * @private - */ -u2f.responseHandler_ = function(message) { - var response = message.data; - var reqId = response['requestId']; - if (!reqId || !u2f.callbackMap_[reqId]) { - console.error('Unknown or missing requestId in response.'); - return; - } - var cb = u2f.callbackMap_[reqId]; - delete u2f.callbackMap_[reqId]; - cb(response['responseData']); -}; + /** + * Handles response messages from the extension. + * @param {MessageEvent.} message + * @private + */ + u2f.responseHandler_ = function(message) { + var response = message.data; + var reqId = response['requestId']; + if (!reqId || !u2f.callbackMap_[reqId]) { + console.error('Unknown or missing requestId in response.'); + return; + } + var cb = u2f.callbackMap_[reqId]; + delete u2f.callbackMap_[reqId]; + cb(response['responseData']); + }; -/** - * Dispatches an array of sign requests to available U2F tokens. - * @param {Array.} signRequests - * @param {function((u2f.Error|u2f.SignResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.sign = function(signRequests, callback, opt_timeoutSeconds) { - u2f.getPortSingleton_(function(port) { - var reqId = ++u2f.reqCounter_; - u2f.callbackMap_[reqId] = callback; - var req = { - type: u2f.MessageTypes.U2F_SIGN_REQUEST, - signRequests: signRequests, - timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? - opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), - requestId: reqId - }; - port.postMessage(req); - }); -}; + /** + * Dispatches an array of sign requests to available U2F tokens. + * @param {Array.} signRequests + * @param {function((u2f.Error|u2f.SignResponse))} callback + * @param {number=} opt_timeoutSeconds + */ + u2f.sign = function(signRequests, callback, opt_timeoutSeconds) { + u2f.getPortSingleton_(function(port) { + var reqId = ++u2f.reqCounter_; + u2f.callbackMap_[reqId] = callback; + var req = { + type: u2f.MessageTypes.U2F_SIGN_REQUEST, + signRequests: signRequests, + timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? + opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), + requestId: reqId + }; + port.postMessage(req); + }); + }; -/** - * Dispatches register requests to available U2F tokens. An array of sign - * requests identifies already registered tokens. - * @param {Array.} registerRequests - * @param {Array.} signRequests - * @param {function((u2f.Error|u2f.RegisterResponse))} callback - * @param {number=} opt_timeoutSeconds - */ -u2f.register = function(registerRequests, signRequests, - callback, opt_timeoutSeconds) { - u2f.getPortSingleton_(function(port) { - var reqId = ++u2f.reqCounter_; - u2f.callbackMap_[reqId] = callback; - var req = { - type: u2f.MessageTypes.U2F_REGISTER_REQUEST, - signRequests: signRequests, - registerRequests: registerRequests, - timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? - opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), - requestId: reqId - }; - port.postMessage(req); - }); -}; + /** + * Dispatches register requests to available U2F tokens. An array of sign + * requests identifies already registered tokens. + * @param {Array.} registerRequests + * @param {Array.} signRequests + * @param {function((u2f.Error|u2f.RegisterResponse))} callback + * @param {number=} opt_timeoutSeconds + */ + u2f.register = function(registerRequests, signRequests, + callback, opt_timeoutSeconds) { + u2f.getPortSingleton_(function(port) { + var reqId = ++u2f.reqCounter_; + u2f.callbackMap_[reqId] = callback; + var req = { + type: u2f.MessageTypes.U2F_REGISTER_REQUEST, + signRequests: signRequests, + registerRequests: registerRequests, + timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ? + opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC), + requestId: reqId + }; + port.postMessage(req); + }); + }; +}