1 // Copyright 2017 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/extensions/api/messaging/chrome_messaging_delegate.h"
6 
7 #include <memory>
8 
9 #include "base/callback.h"
10 #include "base/logging.h"
11 #include "build/build_config.h"
12 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
13 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
14 #include "chrome/browser/extensions/extension_tab_util.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "components/prefs/pref_service.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "extensions/browser/api/messaging/extension_message_port.h"
21 #include "extensions/browser/api/messaging/native_message_host.h"
22 #include "extensions/browser/extension_api_frame_id_map.h"
23 #include "extensions/browser/pref_names.h"
24 #include "extensions/common/api/messaging/port_id.h"
25 #include "extensions/common/extension.h"
26 #include "ui/gfx/native_widget_types.h"
27 #include "url/gurl.h"
28 
29 namespace extensions {
30 
31 ChromeMessagingDelegate::ChromeMessagingDelegate() = default;
32 ChromeMessagingDelegate::~ChromeMessagingDelegate() = default;
33 
34 MessagingDelegate::PolicyPermission
IsNativeMessagingHostAllowed(content::BrowserContext * browser_context,const std::string & native_host_name)35 ChromeMessagingDelegate::IsNativeMessagingHostAllowed(
36     content::BrowserContext* browser_context,
37     const std::string& native_host_name) {
38   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
39 
40   PrefService* pref_service =
41       Profile::FromBrowserContext(browser_context)->GetPrefs();
42 
43   PolicyPermission allow_result = PolicyPermission::ALLOW_ALL;
44   if (pref_service->IsManagedPreference(
45           pref_names::kNativeMessagingUserLevelHosts)) {
46     if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
47       allow_result = PolicyPermission::ALLOW_SYSTEM_ONLY;
48   }
49 
50   // All native messaging hosts are allowed if there is no blacklist.
51   if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist))
52     return allow_result;
53   const base::ListValue* blacklist =
54       pref_service->GetList(pref_names::kNativeMessagingBlacklist);
55   if (!blacklist)
56     return allow_result;
57 
58   // Check if the name or the wildcard is in the blacklist.
59   base::Value name_value(native_host_name);
60   base::Value wildcard_value("*");
61   if (blacklist->Find(name_value) == blacklist->end() &&
62       blacklist->Find(wildcard_value) == blacklist->end()) {
63     return allow_result;
64   }
65 
66   // The native messaging host is blacklisted. Check the whitelist.
67   if (pref_service->IsManagedPreference(
68           pref_names::kNativeMessagingWhitelist)) {
69     const base::ListValue* whitelist =
70         pref_service->GetList(pref_names::kNativeMessagingWhitelist);
71     if (whitelist && whitelist->Find(name_value) != whitelist->end())
72       return allow_result;
73   }
74 
75   return PolicyPermission::DISALLOW;
76 }
77 
MaybeGetTabInfo(content::WebContents * web_contents)78 std::unique_ptr<base::DictionaryValue> ChromeMessagingDelegate::MaybeGetTabInfo(
79     content::WebContents* web_contents) {
80   // Add info about the opener's tab (if it was a tab).
81   if (web_contents && ExtensionTabUtil::GetTabId(web_contents) >= 0) {
82     // Only the tab id is useful to platform apps for internal use. The
83     // unnecessary bits will be stripped out in
84     // MessagingBindings::DispatchOnConnect().
85     // Note: We don't bother scrubbing the tab object, because this is only
86     // reached as a result of a tab (or content script) messaging the extension.
87     // We need the extension to see the sender so that it can validate if it
88     // trusts it or not.
89     // TODO(tjudkins): Adjust scrubbing behavior in this situation to not scrub
90     // the last committed URL, but do scrub the pending URL based on
91     // permissions.
92     ExtensionTabUtil::ScrubTabBehavior scrub_tab_behavior = {
93         ExtensionTabUtil::kDontScrubTab, ExtensionTabUtil::kDontScrubTab};
94     return ExtensionTabUtil::CreateTabObject(web_contents, scrub_tab_behavior,
95                                              nullptr)
96         ->ToValue();
97   }
98   return nullptr;
99 }
100 
GetWebContentsByTabId(content::BrowserContext * browser_context,int tab_id)101 content::WebContents* ChromeMessagingDelegate::GetWebContentsByTabId(
102     content::BrowserContext* browser_context,
103     int tab_id) {
104   content::WebContents* contents = nullptr;
105   if (!ExtensionTabUtil::GetTabById(tab_id, browser_context,
106                                     /*incognito_enabled=*/true, &contents)) {
107     return nullptr;
108   }
109   return contents;
110 }
111 
CreateReceiverForTab(base::WeakPtr<MessagePort::ChannelDelegate> channel_delegate,const std::string & extension_id,const PortId & receiver_port_id,content::WebContents * receiver_contents,int receiver_frame_id)112 std::unique_ptr<MessagePort> ChromeMessagingDelegate::CreateReceiverForTab(
113     base::WeakPtr<MessagePort::ChannelDelegate> channel_delegate,
114     const std::string& extension_id,
115     const PortId& receiver_port_id,
116     content::WebContents* receiver_contents,
117     int receiver_frame_id) {
118   // Frame ID -1 is every frame in the tab.
119   bool include_child_frames = receiver_frame_id == -1;
120   content::RenderFrameHost* receiver_rfh =
121       include_child_frames ? receiver_contents->GetMainFrame()
122                            : ExtensionApiFrameIdMap::GetRenderFrameHostById(
123                                  receiver_contents, receiver_frame_id);
124   if (!receiver_rfh)
125     return nullptr;
126 
127   return std::make_unique<ExtensionMessagePort>(
128       channel_delegate, receiver_port_id, extension_id, receiver_rfh,
129       include_child_frames);
130 }
131 
132 std::unique_ptr<MessagePort>
CreateReceiverForNativeApp(content::BrowserContext * browser_context,base::WeakPtr<MessagePort::ChannelDelegate> channel_delegate,content::RenderFrameHost * source,const std::string & extension_id,const PortId & receiver_port_id,const std::string & native_app_name,bool allow_user_level,std::string * error_out)133 ChromeMessagingDelegate::CreateReceiverForNativeApp(
134     content::BrowserContext* browser_context,
135     base::WeakPtr<MessagePort::ChannelDelegate> channel_delegate,
136     content::RenderFrameHost* source,
137     const std::string& extension_id,
138     const PortId& receiver_port_id,
139     const std::string& native_app_name,
140     bool allow_user_level,
141     std::string* error_out) {
142   DCHECK(error_out);
143   gfx::NativeView native_view = source ? source->GetNativeView() : nullptr;
144   std::unique_ptr<NativeMessageHost> native_host =
145       NativeMessageHost::Create(browser_context, native_view, extension_id,
146                                 native_app_name, allow_user_level, error_out);
147   if (!native_host.get())
148     return nullptr;
149   return std::make_unique<NativeMessagePort>(channel_delegate, receiver_port_id,
150                                              std::move(native_host));
151 }
152 
QueryIncognitoConnectability(content::BrowserContext * context,const Extension * target_extension,content::WebContents * source_contents,const GURL & source_url,const base::Callback<void (bool)> & callback)153 void ChromeMessagingDelegate::QueryIncognitoConnectability(
154     content::BrowserContext* context,
155     const Extension* target_extension,
156     content::WebContents* source_contents,
157     const GURL& source_url,
158     const base::Callback<void(bool)>& callback) {
159   DCHECK(context->IsOffTheRecord());
160   IncognitoConnectability::Get(context)->Query(
161       target_extension, source_contents, source_url, callback);
162 }
163 
164 }  // namespace extensions
165