blob: 1a7b98d601a111517b7171bb1b1fc9b8ee707dc5 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/messaging/chrome_messaging_delegate.h"
#include <memory>
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/functional/callback.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/api/messaging/native_message_host.h"
#include "extensions/browser/api/messaging/native_message_port.h"
#include "extensions/browser/pref_names.h"
#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "ui/gfx/native_widget_types.h"
#include "url/gurl.h"
namespace extensions {
ChromeMessagingDelegate::ChromeMessagingDelegate() = default;
ChromeMessagingDelegate::~ChromeMessagingDelegate() = default;
MessagingDelegate::PolicyPermission
ChromeMessagingDelegate::IsNativeMessagingHostAllowed(
content::BrowserContext* browser_context,
const std::string& native_host_name) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PrefService* pref_service =
Profile::FromBrowserContext(browser_context)->GetPrefs();
PolicyPermission allow_result = PolicyPermission::ALLOW_ALL;
if (pref_service->IsManagedPreference(
pref_names::kNativeMessagingUserLevelHosts)) {
if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
allow_result = PolicyPermission::ALLOW_SYSTEM_ONLY;
}
// All native messaging hosts are allowed if there is no blocklist.
if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlocklist))
return allow_result;
const base::Value::List& blocklist =
pref_service->GetList(pref_names::kNativeMessagingBlocklist);
// Check if the name or the wildcard is in the blocklist.
base::Value name_value(native_host_name);
base::Value wildcard_value("*");
if (!base::Contains(blocklist, name_value) &&
!base::Contains(blocklist, wildcard_value)) {
return allow_result;
}
// The native messaging host is blocklisted. Check the allowlist.
if (pref_service->IsManagedPreference(
pref_names::kNativeMessagingAllowlist)) {
const base::Value::List& allowlist =
pref_service->GetList(pref_names::kNativeMessagingAllowlist);
if (base::Contains(allowlist, name_value))
return allow_result;
}
return PolicyPermission::DISALLOW;
}
std::optional<base::Value::Dict> ChromeMessagingDelegate::MaybeGetTabInfo(
content::WebContents* web_contents) {
// Add info about the opener's tab (if it was a tab).
if (web_contents && ExtensionTabUtil::GetTabId(web_contents) >= 0) {
// Only the tab id is useful to platform apps for internal use. The
// unnecessary bits will be stripped out in
// MessagingBindings::DispatchOnConnect().
// Note: We don't bother scrubbing the tab object, because this is only
// reached as a result of a tab (or content script) messaging the extension.
// We need the extension to see the sender so that it can validate if it
// trusts it or not.
// TODO(tjudkins): Adjust scrubbing behavior in this situation to not scrub
// the last committed URL, but do scrub the pending URL based on
// permissions.
ExtensionTabUtil::ScrubTabBehavior scrub_tab_behavior = {
ExtensionTabUtil::kDontScrubTab, ExtensionTabUtil::kDontScrubTab};
return ExtensionTabUtil::CreateTabObject(web_contents, scrub_tab_behavior,
nullptr)
.ToValue();
}
return std::nullopt;
}
content::WebContents* ChromeMessagingDelegate::GetWebContentsByTabId(
content::BrowserContext* browser_context,
int tab_id) {
content::WebContents* contents = nullptr;
if (!ExtensionTabUtil::GetTabById(tab_id, browser_context,
/*incognito_enabled=*/true, &contents)) {
return nullptr;
}
return contents;
}
std::unique_ptr<MessagePort>
ChromeMessagingDelegate::CreateReceiverForNativeApp(
content::BrowserContext* browser_context,
base::WeakPtr<MessagePort::ChannelDelegate> channel_delegate,
content::RenderFrameHost* source,
const ExtensionId& extension_id,
const PortId& receiver_port_id,
const std::string& native_app_name,
bool allow_user_level,
std::string* error_out) {
DCHECK(error_out);
gfx::NativeView native_view =
source ? source->GetNativeView() : gfx::NativeView();
std::unique_ptr<NativeMessageHost> native_host =
NativeMessageHost::Create(browser_context, native_view, extension_id,
native_app_name, allow_user_level, error_out);
if (!native_host.get())
return nullptr;
return std::make_unique<NativeMessagePort>(channel_delegate, receiver_port_id,
std::move(native_host));
}
void ChromeMessagingDelegate::QueryIncognitoConnectability(
content::BrowserContext* context,
const Extension* target_extension,
content::WebContents* source_contents,
const GURL& source_url,
base::OnceCallback<void(bool)> callback) {
DCHECK(context->IsOffTheRecord());
IncognitoConnectability::Get(context)->Query(
target_extension, source_contents, source_url, std::move(callback));
}
} // namespace extensions