1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142

fuchsia_web / webengine / browser / frame_permission_controller.cc [blame]

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "fuchsia_web/webengine/browser/frame_permission_controller.h"

#include "base/check_op.h"
#include "components/permissions/permission_util.h"
#include "content/public/browser/web_contents.h"
#include "url/origin.h"

using PermissionStatus = blink::mojom::PermissionStatus;
using PermissionType = blink::PermissionType;

namespace {

size_t GetPermissionIndex(PermissionType type) {
  size_t index = static_cast<size_t>(type);
  DCHECK_LT(index, static_cast<size_t>(PermissionType::NUM));
  return index;
}

constexpr PermissionStatus kDefaultPerOriginStatus = PermissionStatus::ASK;

// Converts from |url|'s actual origin to the "canonical origin" that should
// be used for the purpose of requesting permissions.
const url::Origin& GetCanonicalOrigin(PermissionType permission,
                                      const url::Origin& requesting_origin,
                                      const url::Origin& embedding_origin) {
  // Logic in this function should match the logic in
  // permissions::PermissionManager::GetCanonicalOrigin(). Currently it always
  // returns embedding origin, which is correct for all permissions supported by
  // WebEngine (AUDIO_CAPTURE, VIDEO_CAPTURE, PROTECTED_MEDIA_IDENTIFIER,
  // DURABLE_STORAGE).
  //
  // TODO(crbug.com/40680523): Update this function when other permissions are
  // added.
  return embedding_origin;
}

}  // namespace

FramePermissionController::PermissionSet::PermissionSet(
    PermissionStatus initial_state) {
  for (auto& permission : permission_states) {
    permission = initial_state;
  }
}

FramePermissionController::PermissionSet::PermissionSet(
    const PermissionSet& other) = default;

FramePermissionController::PermissionSet&
FramePermissionController::PermissionSet::operator=(
    const PermissionSet& other) = default;

FramePermissionController::FramePermissionController(
    content::WebContents* web_contents)
    : web_contents_(web_contents) {}

FramePermissionController::~FramePermissionController() = default;

void FramePermissionController::SetPermissionState(PermissionType permission,
                                                   const url::Origin& origin,
                                                   PermissionStatus state) {
  // Currently only the following permissions are supported by WebEngine. Others
  // may not be handled correctly by this class.
  //
  // TODO(crbug.com/40680523): This check is necessary mainly because
  // GetCanonicalOrigin() may not work correctly for other permission. See
  // comemnts in GetCanonicalOrigin(). Remove it once that issue is resolved.
  DCHECK(permission == PermissionType::AUDIO_CAPTURE ||
         permission == PermissionType::VIDEO_CAPTURE ||
         permission == PermissionType::PROTECTED_MEDIA_IDENTIFIER ||
         permission == PermissionType::DURABLE_STORAGE);

  auto it = per_origin_permissions_.find(origin);
  if (it == per_origin_permissions_.end()) {
    // Don't create a PermissionSet for |origin| if |state| is set to the
    // per-origin default, since that would have no effect.
    if (state == kDefaultPerOriginStatus)
      return;

    it = per_origin_permissions_
             .insert(
                 std::make_pair(origin, PermissionSet(kDefaultPerOriginStatus)))
             .first;
  }

  it->second.permission_states[GetPermissionIndex(permission)] = state;
}

void FramePermissionController::SetDefaultPermissionState(
    PermissionType permission,
    PermissionStatus state) {
  DCHECK(state != PermissionStatus::ASK);
  default_permissions_.permission_states[GetPermissionIndex(permission)] =
      state;
}

PermissionStatus FramePermissionController::GetPermissionState(
    PermissionType permission,
    const url::Origin& requesting_origin) {
  url::Origin embedding_origin = url::Origin::Create(
      permissions::PermissionUtil::GetLastCommittedOriginAsURL(
          web_contents_->GetPrimaryMainFrame()));
  const url::Origin& canonical_origin =
      GetCanonicalOrigin(permission, requesting_origin, embedding_origin);

  PermissionSet effective = GetEffectivePermissionsForOrigin(canonical_origin);
  return effective.permission_states[GetPermissionIndex(permission)];
}

void FramePermissionController::RequestPermissions(
    const std::vector<PermissionType>& permissions,
    const url::Origin& requesting_origin,
    base::OnceCallback<void(const std::vector<PermissionStatus>&)> callback) {
  std::vector<PermissionStatus> result;
  result.reserve(permissions.size());

  for (auto& permission : permissions) {
    result.push_back(GetPermissionState(permission, requesting_origin));
  }

  std::move(callback).Run(result);
}

FramePermissionController::PermissionSet
FramePermissionController::GetEffectivePermissionsForOrigin(
    const url::Origin& origin) {
  PermissionSet result = default_permissions_;
  auto it = per_origin_permissions_.find(origin);
  if (it != per_origin_permissions_.end()) {
    // Apply per-origin GRANTED and DENIED states. Permissions with the ASK
    // state defer to the defaults.
    for (size_t i = 0; i < it->second.permission_states.size(); ++i) {
      if (it->second.permission_states[i] != kDefaultPerOriginStatus)
        result.permission_states[i] = it->second.permission_states[i];
    }
  }
  return result;
}