// 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 Provides a representation of a web request sender, and * utility functions for creating them. */ 'use strict'; /** * @typedef {{ * origin: string, * tabId: (number|undefined) * frameId: (number|undefined) * }} */ var WebRequestSender; /** * Creates an object representing the sender's origin, and, if available, * tab. * @param {MessageSender} messageSender The message sender. * @return {?WebRequestSender} The sender's origin and tab, or null if the * sender is invalid. */ function createSenderFromMessageSender(messageSender) { var origin = getOriginFromUrl(/** @type {string} */ (messageSender.url)); if (!origin) { return null; } var sender = {origin: origin}; if (messageSender.tab) { sender.tabId = messageSender.tab.id; sender.frameId = messageSender.frameId; } return sender; } /** * Checks whether the given tab could have sent a message from the given * origin. * @param {Tab} tab The tab to match * @param {string} origin The origin to check. * @return {Promise} A promise resolved with the tab id if it the tab could, * have sent the request, and rejected if it can't. */ function tabMatchesOrigin(tab, origin) { // If the tab's origin matches, trust that the request came from this tab. if (getOriginFromUrl(tab.url) == origin) { return Promise.resolve(tab.id); } return Promise.reject(false); } /** * Attempts to ensure that the tabId of the sender is set, using chrome.tabs * when available. * @param {WebRequestSender} sender The request sender. * @return {Promise} A promise resolved once the tabId retrieval is done. * The promise is rejected if the tabId is untrustworthy, e.g. if the * user rapidly switched tabs. */ function getTabIdWhenPossible(sender) { if (sender.tabId) { // Already got it? Done. return Promise.resolve(true); } else if (!chrome.tabs) { // Can't get it? Done. (This happens to packaged apps, which can't access // chrome.tabs.) return Promise.resolve(true); } else { return new Promise(function(resolve, reject) { chrome.tabs.query( {active: true, lastFocusedWindow: true}, function(tabs) { if (!tabs.length) { // Safety check. reject(false); return; } var tab = tabs[0]; tabMatchesOrigin(tab, sender.origin) .then( function(tabId) { sender.tabId = tabId; resolve(true); }, function() { // Didn't match? Check if the debugger is open. if (tab.url.indexOf('devtools://') != 0) { reject(false); return; } // Debugger active: find first tab with the sender's // origin. chrome.tabs.query({active: true}, function(tabs) { if (!tabs.length) { // Safety check. reject(false); return; } var numRejected = 0; for (var i = 0; i < tabs.length; i++) { tab = tabs[i]; tabMatchesOrigin(tab, sender.origin) .then( function(tabId) { sender.tabId = tabId; resolve(true); }, function() { if (++numRejected >= tabs.length) { // None matches: reject. reject(false); } }); } }); }); }); }); } } /** * Checks whether the given tab is in the foreground, i.e. is the active tab * of the focused window. * @param {number} tabId The tab id to check. * @return {Promise} A promise for the result of the check. */ function tabInForeground(tabId) { return new Promise(function(resolve, reject) { if (!chrome.tabs || !chrome.tabs.get) { reject(); return; } if (!chrome.windows || !chrome.windows.get) { reject(); return; } chrome.tabs.get(tabId, function(tab) { if (chrome.runtime.lastError) { resolve(false); return; } if (!tab.active) { resolve(false); return; } chrome.windows.get(tab.windowId, function(aWindow) { resolve(aWindow && aWindow.focused); }); }); }); }