chrome_extension_message_filter.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/renderer_host/chrome_extension_message_filter.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/files/file_path.h" 10#include "base/strings/utf_string_conversions.h" 11#include "chrome/browser/browser_process.h" 12#include "chrome/browser/extensions/activity_log/activity_action_constants.h" 13#include "chrome/browser/extensions/activity_log/activity_actions.h" 14#include "chrome/browser/extensions/activity_log/activity_log.h" 15#include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h" 16#include "chrome/browser/extensions/api/messaging/message_service.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/browser/profiles/profile_manager.h" 19#include "chrome/common/extensions/api/i18n/default_locale_handler.h" 20#include "chrome/common/render_messages.h" 21#include "content/public/browser/render_process_host.h" 22#include "extensions/browser/extension_system.h" 23#include "extensions/common/constants.h" 24#include "extensions/common/extension_messages.h" 25#include "extensions/common/file_util.h" 26#include "extensions/common/message_bundle.h" 27 28using content::BrowserThread; 29using extensions::APIPermission; 30 31namespace { 32 33const uint32 kFilteredMessageClasses[] = { 34 ChromeMsgStart, 35 ExtensionMsgStart, 36}; 37 38// Logs an action to the extension activity log for the specified profile. Can 39// be called from any thread. 40void AddActionToExtensionActivityLog( 41 Profile* profile, 42 scoped_refptr<extensions::Action> action) { 43 // The ActivityLog can only be accessed from the main (UI) thread. If we're 44 // running on the wrong thread, re-dispatch from the main thread. 45 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 46 BrowserThread::PostTask( 47 BrowserThread::UI, FROM_HERE, 48 base::Bind(&AddActionToExtensionActivityLog, profile, action)); 49 } else { 50 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 51 return; 52 // If the action included a URL, check whether it is for an incognito 53 // profile. The check is performed here so that it can safely be done from 54 // the UI thread. 55 if (action->page_url().is_valid() || !action->page_title().empty()) 56 action->set_page_incognito(profile->IsOffTheRecord()); 57 extensions::ActivityLog* activity_log = 58 extensions::ActivityLog::GetInstance(profile); 59 activity_log->LogAction(action); 60 } 61} 62 63} // namespace 64 65ChromeExtensionMessageFilter::ChromeExtensionMessageFilter( 66 int render_process_id, 67 Profile* profile) 68 : BrowserMessageFilter(kFilteredMessageClasses, 69 arraysize(kFilteredMessageClasses)), 70 render_process_id_(render_process_id), 71 profile_(profile), 72 extension_info_map_( 73 extensions::ExtensionSystem::Get(profile)->info_map()) { 74} 75 76ChromeExtensionMessageFilter::~ChromeExtensionMessageFilter() { 77} 78 79bool ChromeExtensionMessageFilter::OnMessageReceived( 80 const IPC::Message& message) { 81 bool handled = true; 82 IPC_BEGIN_MESSAGE_MAP(ChromeExtensionMessageFilter, message) 83 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardRead, 84 OnCanTriggerClipboardRead) 85 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardWrite, 86 OnCanTriggerClipboardWrite) 87 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToExtension, 88 OnOpenChannelToExtension) 89 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab) 90 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToNativeApp, 91 OnOpenChannelToNativeApp) 92 IPC_MESSAGE_HANDLER_DELAY_REPLY(ExtensionHostMsg_GetMessageBundle, 93 OnGetExtMessageBundle) 94 IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel) 95 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddAPIActionToActivityLog, 96 OnAddAPIActionToExtensionActivityLog); 97 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddDOMActionToActivityLog, 98 OnAddDOMActionToExtensionActivityLog); 99 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddEventToActivityLog, 100 OnAddEventToExtensionActivityLog); 101 IPC_MESSAGE_UNHANDLED(handled = false) 102 IPC_END_MESSAGE_MAP() 103 104 return handled; 105} 106 107void ChromeExtensionMessageFilter::OverrideThreadForMessage( 108 const IPC::Message& message, BrowserThread::ID* thread) { 109 switch (message.type()) { 110 case ExtensionHostMsg_CloseChannel::ID: 111 *thread = BrowserThread::UI; 112 break; 113 default: 114 break; 115 } 116} 117 118void ChromeExtensionMessageFilter::OnCanTriggerClipboardRead( 119 const GURL& origin, bool* allowed) { 120 *allowed = extension_info_map_->SecurityOriginHasAPIPermission( 121 origin, render_process_id_, APIPermission::kClipboardRead); 122} 123 124void ChromeExtensionMessageFilter::OnCanTriggerClipboardWrite( 125 const GURL& origin, bool* allowed) { 126 // Since all extensions could historically write to the clipboard, preserve it 127 // for compatibility. 128 *allowed = (origin.SchemeIs(extensions::kExtensionScheme) || 129 extension_info_map_->SecurityOriginHasAPIPermission( 130 origin, render_process_id_, APIPermission::kClipboardWrite)); 131} 132 133void ChromeExtensionMessageFilter::OnOpenChannelToExtension( 134 int routing_id, 135 const ExtensionMsg_ExternalConnectionInfo& info, 136 const std::string& channel_name, 137 bool include_tls_channel_id, 138 int* port_id) { 139 int port2_id; 140 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id); 141 142 BrowserThread::PostTask( 143 BrowserThread::UI, FROM_HERE, 144 base::Bind( 145 &ChromeExtensionMessageFilter::OpenChannelToExtensionOnUIThread, 146 this, render_process_id_, routing_id, port2_id, info, 147 channel_name, include_tls_channel_id)); 148} 149 150void ChromeExtensionMessageFilter::OpenChannelToExtensionOnUIThread( 151 int source_process_id, int source_routing_id, 152 int receiver_port_id, 153 const ExtensionMsg_ExternalConnectionInfo& info, 154 const std::string& channel_name, 155 bool include_tls_channel_id) { 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 157 extensions::MessageService::Get(profile_)->OpenChannelToExtension( 158 source_process_id, source_routing_id, receiver_port_id, 159 info.source_id, info.target_id, info.source_url, channel_name, 160 include_tls_channel_id); 161} 162 163void ChromeExtensionMessageFilter::OnOpenChannelToNativeApp( 164 int routing_id, 165 const std::string& source_extension_id, 166 const std::string& native_app_name, 167 int* port_id) { 168 int port2_id; 169 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id); 170 171 BrowserThread::PostTask( 172 BrowserThread::UI, FROM_HERE, 173 base::Bind( 174 &ChromeExtensionMessageFilter::OpenChannelToNativeAppOnUIThread, 175 this, routing_id, port2_id, source_extension_id, native_app_name)); 176} 177 178void ChromeExtensionMessageFilter::OpenChannelToNativeAppOnUIThread( 179 int source_routing_id, 180 int receiver_port_id, 181 const std::string& source_extension_id, 182 const std::string& native_app_name) { 183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 184 extensions::MessageService::Get(profile_)->OpenChannelToNativeApp( 185 render_process_id_, source_routing_id, receiver_port_id, 186 source_extension_id, native_app_name); 187} 188 189void ChromeExtensionMessageFilter::OnOpenChannelToTab( 190 int routing_id, int tab_id, const std::string& extension_id, 191 const std::string& channel_name, int* port_id) { 192 int port2_id; 193 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id); 194 195 BrowserThread::PostTask( 196 BrowserThread::UI, FROM_HERE, 197 base::Bind(&ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread, 198 this, render_process_id_, routing_id, port2_id, tab_id, 199 extension_id, channel_name)); 200} 201 202void ChromeExtensionMessageFilter::OpenChannelToTabOnUIThread( 203 int source_process_id, int source_routing_id, 204 int receiver_port_id, 205 int tab_id, 206 const std::string& extension_id, 207 const std::string& channel_name) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 209 extensions::MessageService::Get(profile_)->OpenChannelToTab( 210 source_process_id, source_routing_id, receiver_port_id, 211 tab_id, extension_id, channel_name); 212} 213 214void ChromeExtensionMessageFilter::OnGetExtMessageBundle( 215 const std::string& extension_id, IPC::Message* reply_msg) { 216 const extensions::Extension* extension = 217 extension_info_map_->extensions().GetByID(extension_id); 218 base::FilePath extension_path; 219 std::string default_locale; 220 if (extension) { 221 extension_path = extension->path(); 222 default_locale = extensions::LocaleInfo::GetDefaultLocale(extension); 223 } 224 225 BrowserThread::PostBlockingPoolTask( 226 FROM_HERE, 227 base::Bind( 228 &ChromeExtensionMessageFilter::OnGetExtMessageBundleOnBlockingPool, 229 this, extension_path, extension_id, default_locale, reply_msg)); 230} 231 232void ChromeExtensionMessageFilter::OnGetExtMessageBundleOnBlockingPool( 233 const base::FilePath& extension_path, 234 const std::string& extension_id, 235 const std::string& default_locale, 236 IPC::Message* reply_msg) { 237 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 238 239 scoped_ptr<extensions::MessageBundle::SubstitutionMap> dictionary_map( 240 extensions::file_util::LoadMessageBundleSubstitutionMap( 241 extension_path, extension_id, default_locale)); 242 243 ExtensionHostMsg_GetMessageBundle::WriteReplyParams(reply_msg, 244 *dictionary_map); 245 Send(reply_msg); 246} 247 248void ChromeExtensionMessageFilter::OnExtensionCloseChannel( 249 int port_id, 250 const std::string& error_message) { 251 if (!content::RenderProcessHost::FromID(render_process_id_)) 252 return; // To guard against crash in browser_tests shutdown. 253 254 extensions::MessageService* message_service = 255 extensions::MessageService::Get(profile_); 256 if (message_service) 257 message_service->CloseChannel(port_id, error_message); 258} 259 260void ChromeExtensionMessageFilter::OnAddAPIActionToExtensionActivityLog( 261 const std::string& extension_id, 262 const ExtensionHostMsg_APIActionOrEvent_Params& params) { 263 scoped_refptr<extensions::Action> action = new extensions::Action( 264 extension_id, base::Time::Now(), extensions::Action::ACTION_API_CALL, 265 params.api_call); 266 action->set_args(make_scoped_ptr(params.arguments.DeepCopy())); 267 if (!params.extra.empty()) { 268 action->mutable_other()->SetString( 269 activity_log_constants::kActionExtra, params.extra); 270 } 271 AddActionToExtensionActivityLog(profile_, action); 272} 273 274void ChromeExtensionMessageFilter::OnAddDOMActionToExtensionActivityLog( 275 const std::string& extension_id, 276 const ExtensionHostMsg_DOMAction_Params& params) { 277 scoped_refptr<extensions::Action> action = new extensions::Action( 278 extension_id, base::Time::Now(), extensions::Action::ACTION_DOM_ACCESS, 279 params.api_call); 280 action->set_args(make_scoped_ptr(params.arguments.DeepCopy())); 281 action->set_page_url(params.url); 282 action->set_page_title(base::UTF16ToUTF8(params.url_title)); 283 action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb, 284 params.call_type); 285 AddActionToExtensionActivityLog(profile_, action); 286} 287 288void ChromeExtensionMessageFilter::OnAddEventToExtensionActivityLog( 289 const std::string& extension_id, 290 const ExtensionHostMsg_APIActionOrEvent_Params& params) { 291 scoped_refptr<extensions::Action> action = new extensions::Action( 292 extension_id, base::Time::Now(), extensions::Action::ACTION_API_EVENT, 293 params.api_call); 294 action->set_args(make_scoped_ptr(params.arguments.DeepCopy())); 295 if (!params.extra.empty()) { 296 action->mutable_other()->SetString(activity_log_constants::kActionExtra, 297 params.extra); 298 } 299 AddActionToExtensionActivityLog(profile_, action); 300} 301