Commit 73b2202e authored by Pavel Feldman's avatar Pavel Feldman Committed by Commit Bot

DevTools: respect permission overrides on the chrome level.

This is a follow up to the content-side change, we need chrome
to respect these overrides as well when the check originates
outside of the web platform.

Bug: 631464
Change-Id: I8300a17d6b2b65140aef8232a58a694e56a709e3
Reviewed-on: https://chromium-review.googlesource.com/c/1308935
Commit-Queue: Pavel Feldman <pfeldman@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604815}
parent 6d232c64
......@@ -49,6 +49,9 @@ class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
// Resets |device_manager_|.
void ResetAndroidDeviceManagerForTesting();
std::vector<content::BrowserContext*> GetBrowserContexts() override;
content::BrowserContext* GetDefaultBrowserContext() override;
private:
friend class DevToolsManagerDelegateTest;
......@@ -62,8 +65,6 @@ class ChromeDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
std::string GetTargetType(content::WebContents* web_contents) override;
std::string GetTargetTitle(content::WebContents* web_contents) override;
std::vector<content::BrowserContext*> GetBrowserContexts() override;
content::BrowserContext* GetDefaultBrowserContext() override;
content::BrowserContext* CreateBrowserContext() override;
void DisposeBrowserContext(content::BrowserContext*,
DisposeCallback callback) override;
......
......@@ -13,7 +13,7 @@
},
{
"domain": "Browser",
"include": [ "getWindowForTarget", "getWindowBounds", "setWindowBounds", "close" ],
"include": [ "getWindowForTarget", "getWindowBounds", "setWindowBounds", "close", "grantPermissions", "resetPermissions" ],
"include_events": []
},
{
......
......@@ -4,8 +4,13 @@
#include "chrome/browser/devtools/protocol/browser_handler.h"
#include <set>
#include "base/task/post_task.h"
#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/permissions/permission_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
......@@ -14,6 +19,10 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host.h"
using PermissionOverrides = std::set<content::PermissionType>;
using protocol::Maybe;
using protocol::Response;
namespace {
BrowserWindow* GetBrowserWindow(int window_id) {
......@@ -48,6 +57,49 @@ std::unique_ptr<protocol::Browser::Bounds> GetBrowserWindowBounds(
.Build();
}
Response FromProtocolPermissionType(
const protocol::Browser::PermissionType& type,
content::PermissionType* out_type) {
if (type == protocol::Browser::PermissionTypeEnum::Notifications) {
*out_type = content::PermissionType::NOTIFICATIONS;
} else if (type == protocol::Browser::PermissionTypeEnum::Geolocation) {
*out_type = content::PermissionType::GEOLOCATION;
} else if (type ==
protocol::Browser::PermissionTypeEnum::ProtectedMediaIdentifier) {
*out_type = content::PermissionType::PROTECTED_MEDIA_IDENTIFIER;
} else if (type == protocol::Browser::PermissionTypeEnum::Midi) {
*out_type = content::PermissionType::MIDI;
} else if (type == protocol::Browser::PermissionTypeEnum::MidiSysex) {
*out_type = content::PermissionType::MIDI_SYSEX;
} else if (type == protocol::Browser::PermissionTypeEnum::DurableStorage) {
*out_type = content::PermissionType::DURABLE_STORAGE;
} else if (type == protocol::Browser::PermissionTypeEnum::AudioCapture) {
*out_type = content::PermissionType::AUDIO_CAPTURE;
} else if (type == protocol::Browser::PermissionTypeEnum::VideoCapture) {
*out_type = content::PermissionType::VIDEO_CAPTURE;
} else if (type == protocol::Browser::PermissionTypeEnum::BackgroundSync) {
*out_type = content::PermissionType::BACKGROUND_SYNC;
} else if (type == protocol::Browser::PermissionTypeEnum::Flash) {
*out_type = content::PermissionType::FLASH;
} else if (type == protocol::Browser::PermissionTypeEnum::Sensors) {
*out_type = content::PermissionType::SENSORS;
} else if (type ==
protocol::Browser::PermissionTypeEnum::AccessibilityEvents) {
*out_type = content::PermissionType::ACCESSIBILITY_EVENTS;
} else if (type == protocol::Browser::PermissionTypeEnum::ClipboardRead) {
*out_type = content::PermissionType::CLIPBOARD_READ;
} else if (type == protocol::Browser::PermissionTypeEnum::ClipboardWrite) {
*out_type = content::PermissionType::CLIPBOARD_WRITE;
} else if (type == protocol::Browser::PermissionTypeEnum::PaymentHandler) {
*out_type = content::PermissionType::PAYMENT_HANDLER;
} else if (type == protocol::Browser::PermissionTypeEnum::BackgroundFetch) {
*out_type = content::PermissionType::BACKGROUND_FETCH;
} else {
return Response::InvalidParams("Unknown permission type: " + type);
}
return Response::OK();
}
} // namespace
BrowserHandler::BrowserHandler(protocol::UberDispatcher* dispatcher) {
......@@ -58,16 +110,16 @@ BrowserHandler::BrowserHandler(protocol::UberDispatcher* dispatcher) {
BrowserHandler::~BrowserHandler() = default;
protocol::Response BrowserHandler::GetWindowForTarget(
Response BrowserHandler::GetWindowForTarget(
const std::string& target_id,
int* out_window_id,
std::unique_ptr<protocol::Browser::Bounds>* out_bounds) {
auto host = content::DevToolsAgentHost::GetForId(target_id);
if (!host)
return protocol::Response::Error("No target with given id");
return Response::Error("No target with given id");
content::WebContents* web_contents = host->GetWebContents();
if (!web_contents)
return protocol::Response::Error("No web contents in the target");
return Response::Error("No web contents in the target");
Browser* browser = nullptr;
for (auto* b : *BrowserList::GetInstance()) {
......@@ -76,37 +128,37 @@ protocol::Response BrowserHandler::GetWindowForTarget(
browser = b;
}
if (!browser)
return protocol::Response::Error("Browser window not found");
return Response::Error("Browser window not found");
BrowserWindow* window = browser->window();
*out_window_id = browser->session_id().id();
*out_bounds = GetBrowserWindowBounds(window);
return protocol::Response::OK();
return Response::OK();
}
protocol::Response BrowserHandler::GetWindowBounds(
Response BrowserHandler::GetWindowBounds(
int window_id,
std::unique_ptr<protocol::Browser::Bounds>* out_bounds) {
BrowserWindow* window = GetBrowserWindow(window_id);
if (!window)
return protocol::Response::Error("Browser window not found");
return Response::Error("Browser window not found");
*out_bounds = GetBrowserWindowBounds(window);
return protocol::Response::OK();
return Response::OK();
}
protocol::Response BrowserHandler::Close() {
Response BrowserHandler::Close() {
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce([]() { chrome::AttemptExit(); }));
return protocol::Response::OK();
return Response::OK();
}
protocol::Response BrowserHandler::SetWindowBounds(
Response BrowserHandler::SetWindowBounds(
int window_id,
std::unique_ptr<protocol::Browser::Bounds> window_bounds) {
BrowserWindow* window = GetBrowserWindow(window_id);
if (!window)
return protocol::Response::Error("Browser window not found");
return Response::Error("Browser window not found");
gfx::Rect bounds = window->GetBounds();
const bool set_bounds = window_bounds->HasLeft() || window_bounds->HasTop() ||
window_bounds->HasWidth() ||
......@@ -120,14 +172,14 @@ protocol::Response BrowserHandler::SetWindowBounds(
const std::string window_state = window_bounds->GetWindowState("normal");
if (set_bounds && window_state != "normal") {
return protocol::Response::Error(
return Response::Error(
"The 'minimized', 'maximized' and 'fullscreen' states cannot be "
"combined with 'left', 'top', 'width' or 'height'");
}
if (window_state == "fullscreen") {
if (window->IsMinimized()) {
return protocol::Response::Error(
return Response::Error(
"To make minimized window fullscreen, "
"restore it to normal state first.");
}
......@@ -135,14 +187,14 @@ protocol::Response BrowserHandler::SetWindowBounds(
GURL(), EXCLUSIVE_ACCESS_BUBBLE_TYPE_NONE);
} else if (window_state == "maximized") {
if (window->IsMinimized() || window->IsFullscreen()) {
return protocol::Response::Error(
return Response::Error(
"To maximize a minimized or fullscreen "
"window, restore it to normal state first.");
}
window->Maximize();
} else if (window_state == "minimized") {
if (window->IsFullscreen()) {
return protocol::Response::Error(
return Response::Error(
"To minimize a fullscreen window, restore it to normal "
"state first.");
}
......@@ -160,5 +212,85 @@ protocol::Response BrowserHandler::SetWindowBounds(
NOTREACHED();
}
return protocol::Response::OK();
return Response::OK();
}
Response BrowserHandler::Disable() {
for (auto& browser_context_id : contexts_with_overridden_permissions_) {
Profile* profile = nullptr;
Maybe<std::string> context_id =
browser_context_id == "" ? Maybe<std::string>()
: Maybe<std::string>(browser_context_id);
FindProfile(context_id, &profile);
if (profile) {
PermissionManager* permission_manager = PermissionManager::Get(profile);
permission_manager->ResetPermissionOverridesForDevTools();
}
}
contexts_with_overridden_permissions_.clear();
return Response::OK();
}
Response BrowserHandler::GrantPermissions(
const std::string& origin,
std::unique_ptr<protocol::Array<protocol::Browser::PermissionType>>
permissions,
Maybe<std::string> browser_context_id) {
Profile* profile = nullptr;
Response response = FindProfile(browser_context_id, &profile);
if (!response.isSuccess())
return response;
PermissionOverrides overrides;
for (size_t i = 0; i < permissions->length(); ++i) {
content::PermissionType type;
Response type_response =
FromProtocolPermissionType(permissions->get(i), &type);
if (!type_response.isSuccess())
return type_response;
overrides.insert(type);
}
PermissionManager* permission_manager = PermissionManager::Get(profile);
GURL url = GURL(origin).GetOrigin();
permission_manager->SetPermissionOverridesForDevTools(url,
std::move(overrides));
contexts_with_overridden_permissions_.insert(
browser_context_id.fromMaybe(""));
return Response::FallThrough();
}
Response BrowserHandler::ResetPermissions(
Maybe<std::string> browser_context_id) {
Profile* profile = nullptr;
Response response = FindProfile(browser_context_id, &profile);
if (!response.isSuccess())
return response;
PermissionManager* permission_manager = PermissionManager::Get(profile);
permission_manager->ResetPermissionOverridesForDevTools();
contexts_with_overridden_permissions_.erase(browser_context_id.fromMaybe(""));
return Response::FallThrough();
}
Response BrowserHandler::FindProfile(
const Maybe<std::string>& browser_context_id,
Profile** profile) {
auto* delegate = ChromeDevToolsManagerDelegate::GetInstance();
if (!browser_context_id.isJust()) {
*profile =
Profile::FromBrowserContext(delegate->GetDefaultBrowserContext());
if (*profile == nullptr)
return Response::Error("Browser context management is not supported.");
return Response::OK();
}
std::string context_id = browser_context_id.fromJust();
for (auto* context : delegate->GetBrowserContexts()) {
if (context->UniqueId() == context_id) {
*profile = Profile::FromBrowserContext(context);
return Response::OK();
}
}
return Response::InvalidParams("Failed to find browser context for id " +
context_id);
}
......@@ -5,8 +5,11 @@
#ifndef CHROME_BROWSER_DEVTOOLS_PROTOCOL_BROWSER_HANDLER_H_
#define CHROME_BROWSER_DEVTOOLS_PROTOCOL_BROWSER_HANDLER_H_
#include "base/containers/flat_set.h"
#include "chrome/browser/devtools/protocol/browser.h"
class Profile;
class BrowserHandler : public protocol::Browser::Backend {
public:
explicit BrowserHandler(protocol::UberDispatcher* dispatcher);
......@@ -24,8 +27,22 @@ class BrowserHandler : public protocol::Browser::Backend {
protocol::Response SetWindowBounds(
int window_id,
std::unique_ptr<protocol::Browser::Bounds> out_bounds) override;
protocol::Response Disable() override;
protocol::Response GrantPermissions(
const std::string& origin,
std::unique_ptr<protocol::Array<protocol::Browser::PermissionType>>
permissions,
protocol::Maybe<std::string> browser_context_id) override;
protocol::Response ResetPermissions(
protocol::Maybe<std::string> browser_context_id) override;
private:
protocol::Response FindProfile(
const protocol::Maybe<std::string>& browser_context_id,
Profile** profile);
base::flat_set<std::string> contexts_with_overridden_permissions_;
DISALLOW_COPY_AND_ASSIGN(BrowserHandler);
};
......
......@@ -396,10 +396,18 @@ int PermissionManager::RequestPermissions(
for (size_t i = 0; i < permissions.size(); ++i) {
const ContentSettingsType permission = permissions[i];
PermissionContextBase* context = GetPermissionContext(permission);
DCHECK(context);
auto callback =
std::make_unique<PermissionResponseCallback>(this, request_id, i);
auto status = GetPermissionOverrideForDevTools(canonical_requesting_origin,
permission);
if (status != CONTENT_SETTING_DEFAULT) {
callback->OnPermissionsRequestResponseStatus(CONTENT_SETTING_ALLOW);
continue;
}
PermissionContextBase* context = GetPermissionContext(permission);
DCHECK(context);
context->RequestPermission(
web_contents, request, canonical_requesting_origin, user_gesture,
base::Bind(
......@@ -676,6 +684,10 @@ PermissionResult PermissionManager::GetPermissionStatusHelper(
const GURL& embedding_origin) {
GURL canonical_requesting_origin =
GetCanonicalOrigin(requesting_origin, embedding_origin);
auto status =
GetPermissionOverrideForDevTools(canonical_requesting_origin, permission);
if (status != CONTENT_SETTING_DEFAULT)
return PermissionResult(status, PermissionStatusSource::UNSPECIFIED);
PermissionContextBase* context = GetPermissionContext(permission);
PermissionResult result = context->GetPermissionStatus(
render_frame_host, canonical_requesting_origin.GetOrigin(),
......@@ -685,3 +697,26 @@ PermissionResult PermissionManager::GetPermissionStatusHelper(
result.content_setting == CONTENT_SETTING_BLOCK);
return result;
}
void PermissionManager::SetPermissionOverridesForDevTools(
const GURL& origin,
const PermissionOverrides& overrides) {
ContentSettingsTypeOverrides result;
for (const auto& item : overrides)
result.insert(PermissionTypeToContentSetting(item));
devtools_permission_overrides_[origin] = std::move(result);
}
void PermissionManager::ResetPermissionOverridesForDevTools() {
devtools_permission_overrides_.clear();
}
ContentSetting PermissionManager::GetPermissionOverrideForDevTools(
const GURL& origin,
ContentSettingsType permission) {
auto it = devtools_permission_overrides_.find(origin);
if (it == devtools_permission_overrides_.end())
return CONTENT_SETTING_DEFAULT;
return it->second.count(permission) ? CONTENT_SETTING_ALLOW
: CONTENT_SETTING_BLOCK;
}
......@@ -15,15 +15,12 @@
#include "components/content_settings/core/common/content_settings.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/permission_controller_delegate.h"
#include "content/public/browser/permission_type.h"
class PermissionContextBase;
struct PermissionResult;
class Profile;
namespace content {
enum class PermissionType;
}; // namespace content
class PermissionManager : public KeyedService,
public content::PermissionControllerDelegate,
public content_settings::Observer {
......@@ -119,6 +116,14 @@ class PermissionManager : public KeyedService,
// denied due to the kill switch.
bool IsPermissionKillSwitchOn(ContentSettingsType);
using PermissionOverrides = std::set<content::PermissionType>;
// For the given |origin|, grant permissions that belong to |overrides|
// and reject all others.
void SetPermissionOverridesForDevTools(const GURL& origin,
const PermissionOverrides& overrides);
void ResetPermissionOverridesForDevTools();
private:
friend class PermissionManagerTest;
friend class GeolocationPermissionContextTests;
......@@ -158,6 +163,10 @@ class PermissionManager : public KeyedService,
const GURL& requesting_origin,
const GURL& embedding_origin);
ContentSetting GetPermissionOverrideForDevTools(
const GURL& origin,
ContentSettingsType permission);
Profile* profile_;
PendingRequestsMap pending_requests_;
SubscriptionsMap subscriptions_;
......@@ -166,6 +175,8 @@ class PermissionManager : public KeyedService,
std::unique_ptr<PermissionContextBase>,
ContentSettingsTypeHash>
permission_contexts_;
using ContentSettingsTypeOverrides = std::set<ContentSettingsType>;
std::map<GURL, ContentSettingsTypeOverrides> devtools_permission_overrides_;
DISALLOW_COPY_AND_ASSIGN(PermissionManager);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment