// 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. // Custom binding for the extension API. var binding = require('binding').Binding.create('extension'); var messaging = require('messaging'); var runtimeNatives = requireNative('runtime'); var GetExtensionViews = runtimeNatives.GetExtensionViews; var OpenChannelToExtension = runtimeNatives.OpenChannelToExtension; var OpenChannelToNativeApp = runtimeNatives.OpenChannelToNativeApp; var chrome = requireNative('chrome').GetChrome(); var inIncognitoContext = requireNative('process').InIncognitoContext(); var sendRequestIsDisabled = requireNative('process').IsSendRequestDisabled(); var contextType = requireNative('process').GetContextType(); var manifestVersion = requireNative('process').GetManifestVersion(); // This should match chrome.windows.WINDOW_ID_NONE. // // We can't use chrome.windows.WINDOW_ID_NONE directly because the // chrome.windows API won't exist unless this extension has permission for it; // which may not be the case. var WINDOW_ID_NONE = -1; binding.registerCustomHook(function(bindingsAPI, extensionId) { var extension = bindingsAPI.compiledApi; if (manifestVersion < 2) { chrome.self = extension; extension.inIncognitoTab = inIncognitoContext; } extension.inIncognitoContext = inIncognitoContext; var apiFunctions = bindingsAPI.apiFunctions; apiFunctions.setHandleRequest('getViews', function(properties) { var windowId = WINDOW_ID_NONE; var type = 'ALL'; if (properties) { if (properties.type != null) { type = properties.type; } if (properties.windowId != null) { windowId = properties.windowId; } } return GetExtensionViews(windowId, type); }); apiFunctions.setHandleRequest('getBackgroundPage', function() { return GetExtensionViews(-1, 'BACKGROUND')[0] || null; }); apiFunctions.setHandleRequest('getExtensionTabs', function(windowId) { if (windowId == null) windowId = WINDOW_ID_NONE; return GetExtensionViews(windowId, 'TAB'); }); apiFunctions.setHandleRequest('getURL', function(path) { path = String(path); if (!path.length || path[0] != '/') path = '/' + path; return 'chrome-extension://' + extensionId + path; }); // Alias several messaging deprecated APIs to their runtime counterparts. var mayNeedAlias = [ // Types 'Port', // Functions 'connect', 'sendMessage', 'connectNative', 'sendNativeMessage', // Events 'onConnect', 'onConnectExternal', 'onMessage', 'onMessageExternal' ]; $Array.forEach(mayNeedAlias, function(alias) { // Checking existence isn't enough since some functions are disabled via // getters that throw exceptions. Assume that any getter is such a function. if (chrome.runtime && $Object.hasOwnProperty(chrome.runtime, alias) && chrome.runtime.__lookupGetter__(alias) === undefined) { extension[alias] = chrome.runtime[alias]; } }); apiFunctions.setUpdateArgumentsPreValidate('sendRequest', $Function.bind(messaging.sendMessageUpdateArguments, null, 'sendRequest', false /* hasOptionsArgument */)); apiFunctions.setHandleRequest('sendRequest', function(targetId, request, responseCallback) { if (sendRequestIsDisabled) throw new Error(sendRequestIsDisabled); var port = chrome.runtime.connect(targetId || extensionId, {name: messaging.kRequestChannel}); messaging.sendMessageImpl(port, request, responseCallback); }); if (sendRequestIsDisabled) { extension.onRequest.addListener = function() { throw new Error(sendRequestIsDisabled); }; if (contextType == 'BLESSED_EXTENSION') { extension.onRequestExternal.addListener = function() { throw new Error(sendRequestIsDisabled); }; } } }); exports.binding = binding.generate();