910e62b5创建于 1月15日历史提交
// 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/buildflags/buildflags.h"
#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "ui/gfx/native_ui_types.h"
#include "url/gurl.h"

static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));

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