910e62b5创建于 1月15日历史提交
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/shell/browser/shell_permission_manager.h"

#include "base/command_line.h"
#include "base/functional/callback.h"
#include "components/content_settings/core/common/features.h"
#include "components/permissions/permission_util.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_result.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_switches.h"
#include "content/shell/common/shell_switches.h"
#include "media/base/media_switches.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "url/origin.h"

using blink::PermissionType;

namespace content {

namespace {

bool IsAllowlistedPermissionType(PermissionType permission) {
  switch (permission) {
    case PermissionType::GEOLOCATION:
    case PermissionType::SENSORS:
    case PermissionType::PAYMENT_HANDLER:
    case PermissionType::WAKE_LOCK_SCREEN:

    // Background Sync and Background Fetch browser tests require
    // permission to be granted by default.
    case PermissionType::BACKGROUND_SYNC:
    case PermissionType::BACKGROUND_FETCH:
    case PermissionType::PERIODIC_BACKGROUND_SYNC:

    case PermissionType::IDLE_DETECTION:

    // WebNFC browser tests require permission to be granted by default.
    case PermissionType::NFC:
      return true;

    case PermissionType::MIDI:
      if (base::FeatureList::IsEnabled(blink::features::kBlockMidiByDefault)) {
        return false;
      }
      return true;
    case PermissionType::MIDI_SYSEX:
    case PermissionType::NOTIFICATIONS:
    case PermissionType::PROTECTED_MEDIA_IDENTIFIER:
    case PermissionType::DURABLE_STORAGE:
    case PermissionType::AUDIO_CAPTURE:
    case PermissionType::VIDEO_CAPTURE:
    case PermissionType::CLIPBOARD_READ_WRITE:
    case PermissionType::CLIPBOARD_SANITIZED_WRITE:
    case PermissionType::NUM:
    case PermissionType::WAKE_LOCK_SYSTEM:
    case PermissionType::HAND_TRACKING:
    case PermissionType::VR:
    case PermissionType::AR:
    case PermissionType::STORAGE_ACCESS_GRANT:
    case PermissionType::CAMERA_PAN_TILT_ZOOM:
    case PermissionType::WINDOW_MANAGEMENT:
    case PermissionType::LOCAL_FONTS:
    case PermissionType::DISPLAY_CAPTURE:
    case PermissionType::TOP_LEVEL_STORAGE_ACCESS:
    case PermissionType::CAPTURED_SURFACE_CONTROL:
    case PermissionType::SMART_CARD:
    case PermissionType::WEB_PRINTING:
    case PermissionType::SPEAKER_SELECTION:
    case PermissionType::KEYBOARD_LOCK:
    case PermissionType::POINTER_LOCK:
    case PermissionType::AUTOMATIC_FULLSCREEN:
    case PermissionType::WEB_APP_INSTALLATION:
    case PermissionType::LOCAL_NETWORK_ACCESS:
      return false;
  }

  NOTREACHED();
}

}  // namespace

ShellPermissionManager::ShellPermissionManager() = default;

ShellPermissionManager::~ShellPermissionManager() = default;

void ShellPermissionManager::RequestPermissions(
    RenderFrameHost* render_frame_host,
    const PermissionRequestDescription& request_description,
    base::OnceCallback<void(const std::vector<PermissionResult>&)> callback) {
  if (render_frame_host->IsNestedWithinFencedFrame()) {
    std::move(callback).Run(std::vector<PermissionResult>(
        request_description.permissions.size(),
        PermissionResult(blink::mojom::PermissionStatus::DENIED,
                         PermissionStatusSource::FENCED_FRAME)));
    return;
  }
  std::vector<PermissionResult> result;
  for (const auto& permission : request_description.permissions) {
    result.emplace_back(
        IsAllowlistedPermissionType(
            blink::PermissionDescriptorToPermissionType(permission))
            ? blink::mojom::PermissionStatus::GRANTED
            : blink::mojom::PermissionStatus::DENIED);
  }
  std::move(callback).Run(result);
}

void ShellPermissionManager::ResetPermission(
    PermissionType permission,
    const GURL& requesting_origin,
    const GURL& embedding_origin) {
}

void ShellPermissionManager::RequestPermissionsFromCurrentDocument(
    content::RenderFrameHost* render_frame_host,
    const PermissionRequestDescription& request_description,
    base::OnceCallback<void(const std::vector<PermissionResult>&)> callback) {
  if (render_frame_host->IsNestedWithinFencedFrame()) {
    std::move(callback).Run(std::vector<PermissionResult>(
        request_description.permissions.size(),
        PermissionResult(blink::mojom::PermissionStatus::DENIED)));
    return;
  }
  std::vector<PermissionResult> result;
  blink::PermissionType permission_type;
  for (const auto& permission : request_description.permissions) {
    permission_type = blink::PermissionDescriptorToPermissionType(permission);
    // When the `ApproximateGeolocationPermission` feature is enabled, granting
    // geolocation requires more granular control via `GeolocationSetting`.
    if (base::FeatureList::IsEnabled(
            content_settings::features::kApproximateGeolocationPermission) &&
        permission_type == blink::PermissionType::GEOLOCATION &&
        IsAllowlistedPermissionType(permission_type)) {
      GeolocationSetting setting = {PermissionOption::kAllowed,
                                    PermissionOption::kAllowed};
      result.emplace_back(blink::mojom::PermissionStatus::GRANTED,
                          PermissionStatusSource::UNSPECIFIED, setting);
    } else {
      result.emplace_back(IsAllowlistedPermissionType(permission_type)
                              ? blink::mojom::PermissionStatus::GRANTED
                              : blink::mojom::PermissionStatus::DENIED);
    }
  }
  std::move(callback).Run(result);
}

blink::mojom::PermissionStatus ShellPermissionManager::GetPermissionStatus(
    const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
    const GURL& requesting_origin,
    const GURL& embedding_origin) {
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  const auto permission_type =
      blink::PermissionDescriptorToPermissionType(permission_descriptor);

  if ((permission_type == PermissionType::AUDIO_CAPTURE ||
       permission_type == PermissionType::VIDEO_CAPTURE) &&
      command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream) &&
      command_line->HasSwitch(switches::kUseFakeUIForMediaStream) &&
      command_line->GetSwitchValueASCII(
          switches::kUseFakeDeviceForMediaStream) != "deny") {
    return blink::mojom::PermissionStatus::GRANTED;
  }

  return IsAllowlistedPermissionType(permission_type)
             ? blink::mojom::PermissionStatus::GRANTED
             : blink::mojom::PermissionStatus::DENIED;
}

PermissionResult
ShellPermissionManager::GetPermissionResultForOriginWithoutContext(
    const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
    const url::Origin& requesting_origin,
    const url::Origin& embedding_origin) {
  blink::mojom::PermissionStatus status =
      GetPermissionStatus(permission_descriptor, requesting_origin.GetURL(),
                          embedding_origin.GetURL());

  return PermissionResult(status);
}

PermissionResult ShellPermissionManager::GetPermissionResultForCurrentDocument(
    const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
    content::RenderFrameHost* render_frame_host,
    bool should_include_device_status) {
  if (render_frame_host->IsNestedWithinFencedFrame())
    return PermissionResult(blink::mojom::PermissionStatus::DENIED);
  return PermissionResult(GetPermissionStatus(
      permission_descriptor,
      permissions::PermissionUtil::GetLastCommittedOriginAsURL(
          render_frame_host),
      permissions::PermissionUtil::GetLastCommittedOriginAsURL(
          render_frame_host->GetMainFrame())));
}

PermissionResult ShellPermissionManager::GetPermissionResultForWorker(
    const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
    content::RenderProcessHost* render_process_host,
    const GURL& worker_origin) {
  return PermissionResult(
      GetPermissionStatus(permission_descriptor, worker_origin, worker_origin));
}

PermissionResult
ShellPermissionManager::GetPermissionResultForEmbeddedRequester(
    const blink::mojom::PermissionDescriptorPtr& permission_descriptor,
    content::RenderFrameHost* render_frame_host,
    const url::Origin& overridden_origin) {
  if (render_frame_host->IsNestedWithinFencedFrame()) {
    return PermissionResult(blink::mojom::PermissionStatus::DENIED);
  }
  return PermissionResult(GetPermissionStatus(
      permission_descriptor, overridden_origin.GetURL(),
      permissions::PermissionUtil::GetLastCommittedOriginAsURL(
          render_frame_host->GetMainFrame())));
}

}  // namespace content