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