| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview CryptoToken background page |
| */ |
| |
| 'use strict'; |
| |
| /** @const */ |
| var BROWSER_SUPPORTS_TLS_CHANNEL_ID = true; |
| |
| /** @const */ |
| var HTTP_ORIGINS_ALLOWED = false; |
| |
| /** @const */ |
| var LOG_SAVER_EXTENSION_ID = 'fjajfjhkeibgmiggdfehjplbhmfkialk'; |
| |
| // Singleton tracking available devices. |
| var gnubbies = new Gnubbies(); |
| HidGnubbyDevice.register(gnubbies); |
| UsbGnubbyDevice.register(gnubbies); |
| |
| var FACTORY_REGISTRY = (function() { |
| var windowTimer = new WindowTimer(); |
| var xhrTextFetcher = new XhrTextFetcher(); |
| return new FactoryRegistry( |
| new XhrAppIdCheckerFactory(xhrTextFetcher), |
| new CryptoTokenApprovedOrigin(), new CountdownTimerFactory(windowTimer), |
| new CryptoTokenOriginChecker(), new UsbHelper(), windowTimer, |
| xhrTextFetcher); |
| })(); |
| |
| var DEVICE_FACTORY_REGISTRY = new DeviceFactoryRegistry( |
| new UsbGnubbyFactory(gnubbies), FACTORY_REGISTRY.getCountdownFactory(), |
| new GoogleCorpIndividualAttestation()); |
| |
| /** |
| * @param {*} request The received request |
| * @return {boolean} Whether the request is a register/enroll request. |
| */ |
| function isRegisterRequest(request) { |
| if (!request) { |
| return false; |
| } |
| switch (request.type) { |
| case MessageTypes.U2F_REGISTER_REQUEST: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Default response callback to deliver a response to a request. |
| * @param {*} request The received request. |
| * @param {function(*): void} sendResponse A callback that delivers a response. |
| * @param {*} response The response to return. |
| */ |
| function defaultResponseCallback(request, sendResponse, response) { |
| response['requestId'] = request['requestId']; |
| try { |
| sendResponse(response); |
| } catch (e) { |
| console.warn(UTIL_fmt('caught: ' + e.message)); |
| } |
| } |
| |
| /** |
| * Response callback that delivers a response to a request only when the |
| * sender is a foreground tab. |
| * @param {*} request The received request. |
| * @param {!MessageSender} sender The message sender. |
| * @param {function(*): void} sendResponse A callback that delivers a response. |
| * @param {*} response The response to return. |
| */ |
| function sendResponseToActiveTabOnly(request, sender, sendResponse, response) { |
| tabInForeground(sender.tab.id).then(function(result) { |
| // If the tab is no longer in the foreground, drop the result: the user |
| // is no longer interacting with the tab that originated the request. |
| if (result) { |
| defaultResponseCallback(request, sendResponse, response); |
| } |
| }); |
| } |
| |
| /** |
| * Common handler for messages received from chrome.runtime.sendMessage and |
| * chrome.runtime.connect + postMessage. |
| * @param {*} request The received request |
| * @param {!MessageSender} sender The message sender |
| * @param {function(*): void} sendResponse A callback that delivers a response |
| * @return {Closeable} A Closeable request handler. |
| */ |
| function messageHandler(request, sender, sendResponse) { |
| var responseCallback; |
| if (isRegisterRequest(request)) { |
| responseCallback = |
| sendResponseToActiveTabOnly.bind(null, request, sender, sendResponse); |
| } else { |
| responseCallback = |
| defaultResponseCallback.bind(null, request, sendResponse); |
| } |
| var closeable = handleWebPageRequest( |
| /** @type {Object} */ (request), sender, responseCallback); |
| return closeable; |
| } |
| |
| /** |
| * Listen to individual messages sent from (whitelisted) webpages via |
| * chrome.runtime.sendMessage |
| * @param {*} request The received request |
| * @param {!MessageSender} sender The message sender |
| * @param {function(*): void} sendResponse A callback that delivers a response |
| * @return {boolean} |
| */ |
| function messageHandlerExternal(request, sender, sendResponse) { |
| if (sender.id && sender.id === LOG_SAVER_EXTENSION_ID) { |
| return handleLogSaverMessage(request); |
| } |
| |
| messageHandler(request, sender, sendResponse); |
| return true; // Tell Chrome not to destroy sendResponse yet |
| } |
| chrome.runtime.onMessageExternal.addListener(messageHandlerExternal); |
| |
| // Listen to direct connection events, and wire up a message handler on the port |
| chrome.runtime.onConnectExternal.addListener(function(port) { |
| function sendResponse(response) { |
| port.postMessage(response); |
| } |
| |
| var closeable; |
| port.onMessage.addListener(function(request) { |
| var sender = /** @type {!MessageSender} */ (port.sender); |
| closeable = messageHandler(request, sender, sendResponse); |
| }); |
| port.onDisconnect.addListener(function() { |
| if (closeable) { |
| closeable.close(); |
| } |
| }); |
| }); |
| |
| /** |
| * Handles messages from the log-saver app. Temporarily replaces UTIL_fmt with |
| * a wrapper that also sends formatted messages to the app. |
| * @param {*} request The message received from the app |
| * @return {boolean} Used as chrome.runtime.onMessage handler return value |
| */ |
| function handleLogSaverMessage(request) { |
| if (request === 'start') { |
| if (originalUtilFmt) { |
| // We're already sending |
| return false; |
| } |
| originalUtilFmt = UTIL_fmt; |
| UTIL_fmt = function(s) { |
| var line = originalUtilFmt(s); |
| chrome.runtime.sendMessage(LOG_SAVER_EXTENSION_ID, line); |
| return line; |
| }; |
| } else if (request === 'stop') { |
| if (originalUtilFmt) { |
| UTIL_fmt = originalUtilFmt; |
| originalUtilFmt = null; |
| } |
| } |
| return false; |
| } |
| |
| /** @private */ |
| var originalUtilFmt = null; |