Skip to content

Commit

Permalink
[DevTools] Creates new Browser.setPermissions command.
Browse files Browse the repository at this point in the history
Adds Browser.setPermissions command to chrome, while updating how
permission overrides are handled internally to allow for multiple
possible states instead of binary ALLOW or BLOCK. Does not
support oneRealm = true case, and returns error when this is
requested. Bug tracking this can be found: crbug.com/977612.
Bug tracking de-duplication of parsing logic: crbug.com/989983

Design: go/chromedriver-permissions-ext
Bug: 976308
Change-Id: I11580adbcacccc9282a757d047944d2734a8ed21
Tested: Added layout tests for basic set permission cases.
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1664643
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Balazs Engedy <engedy@chromium.org>
Commit-Queue: Rohan Pavone <rohpavone@chromium.org>
Cr-Commit-Position: refs/heads/master@{#684976}
  • Loading branch information
Rohan Pavone authored and Commit Bot committed Aug 7, 2019
1 parent ea00a40 commit b4de951
Show file tree
Hide file tree
Showing 14 changed files with 769 additions and 44 deletions.
120 changes: 120 additions & 0 deletions content/browser/devtools/protocol/browser_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,80 @@ std::unique_ptr<Browser::Histogram> Convert(base::HistogramBase& in_histogram,
.Build();
}

// Parses PermissionDescriptors (|descriptor|) into their appropriate
// PermissionType |permission_type| by duplicating the logic in the methods
// //third_party/blink/renderer/modules/permissions:permissions
// ::ParsePermission and
// //content/browser/permissions:permission_service_impl
// ::PermissionDescriptorToPermissionType, producing an error in
// |error_message| as necessary.
// TODO(crbug.com/989983): De-duplicate this logic.
Response PermissionDescriptorToPermissionType(
std::unique_ptr<protocol::Browser::PermissionDescriptor> descriptor,
PermissionType* permission_type) {
const std::string name = descriptor->GetName();

if (name == "geolocation") {
*permission_type = PermissionType::GEOLOCATION;
} else if (name == "camera") {
*permission_type = PermissionType::VIDEO_CAPTURE;
} else if (name == "microphone") {
*permission_type = PermissionType::AUDIO_CAPTURE;
} else if (name == "notifications") {
*permission_type = PermissionType::NOTIFICATIONS;
} else if (name == "persistent-storage") {
*permission_type = PermissionType::DURABLE_STORAGE;
} else if (name == "push") {
if (!descriptor->GetUserVisibleOnly(false)) {
return Response::InvalidParams(
"Push Permission without userVisibleOnly:true isn't supported");
}
*permission_type = PermissionType::NOTIFICATIONS;
} else if (name == "midi") {
if (descriptor->GetSysex(false))
*permission_type = PermissionType::MIDI_SYSEX;
else
*permission_type = PermissionType::MIDI;
} else if (name == "background-sync") {
*permission_type = PermissionType::BACKGROUND_SYNC;
} else if (name == "ambient-light-sensor" || name == "accelerometer" ||
name == "gyroscope" || name == "magnetometer") {
*permission_type = PermissionType::SENSORS;
} else if (name == "accessibility-events") {
*permission_type = PermissionType::ACCESSIBILITY_EVENTS;
} else if (name == "clipboard-read") {
*permission_type = PermissionType::CLIPBOARD_READ;
} else if (name == "clipboard-write") {
*permission_type = PermissionType::CLIPBOARD_WRITE;
} else if (name == "payment-handler") {
*permission_type = PermissionType::PAYMENT_HANDLER;
} else if (name == "background-fetch") {
*permission_type = PermissionType::BACKGROUND_FETCH;
} else if (name == "idle-detection") {
*permission_type = PermissionType::IDLE_DETECTION;
} else if (name == "periodic-background-sync") {
*permission_type = PermissionType::PERIODIC_BACKGROUND_SYNC;
} else if (name == "wake-lock") {
if (!descriptor->HasType()) {
return Response::InvalidParams(
"Could not parse WakeLockPermissionDescriptor with property type");
}
const std::string type = descriptor->GetType("");
if (type == "screen") {
*permission_type = PermissionType::WAKE_LOCK_SCREEN;
} else if (type == "system") {
*permission_type = PermissionType::WAKE_LOCK_SYSTEM;
} else {
return Response::InvalidParams("Invalid WakeLockType: " + type);
}
} else {
return Response::InvalidParams("Invalid PermissionDescriptor name: " +
name);
}

return Response::OK();
}

Response FromProtocolPermissionType(
const protocol::Browser::PermissionType& type,
PermissionType* out_type) {
Expand Down Expand Up @@ -157,6 +231,21 @@ Response FromProtocolPermissionType(
return Response::OK();
}

Response PermissionSettingToPermissionStatus(
const protocol::Browser::PermissionSetting& setting,
blink::mojom::PermissionStatus* out_status) {
if (setting == protocol::Browser::PermissionSettingEnum::Granted) {
*out_status = blink::mojom::PermissionStatus::GRANTED;
} else if (setting == protocol::Browser::PermissionSettingEnum::Denied) {
*out_status = blink::mojom::PermissionStatus::DENIED;
} else if (setting == protocol::Browser::PermissionSettingEnum::Prompt) {
*out_status = blink::mojom::PermissionStatus::ASK;
} else {
return Response::InvalidParams("Unknown permission setting: " + setting);
}
return Response::OK();
}

} // namespace

Response BrowserHandler::GetHistograms(
Expand Down Expand Up @@ -202,6 +291,37 @@ Response BrowserHandler::FindBrowserContext(
context_id);
}

Response BrowserHandler::SetPermission(
const std::string& origin,
std::unique_ptr<protocol::Browser::PermissionDescriptor> permission,
const protocol::Browser::PermissionSetting& setting,
Maybe<std::string> browser_context_id) {
BrowserContext* browser_context = nullptr;
Response response = FindBrowserContext(browser_context_id, &browser_context);
if (!response.isSuccess())
return response;

PermissionType type;
Response parse_response =
PermissionDescriptorToPermissionType(std::move(permission), &type);
if (!parse_response.isSuccess())
return parse_response;

blink::mojom::PermissionStatus permission_status;
Response setting_response =
PermissionSettingToPermissionStatus(setting, &permission_status);
if (!setting_response.isSuccess())
return setting_response;

PermissionControllerImpl* permission_controller =
PermissionControllerImpl::FromBrowserContext(browser_context);
GURL url = GURL(origin).GetOrigin();
permission_controller->SetOverrideForDevTools(url, type, permission_status);
contexts_with_overridden_permissions_.insert(
browser_context_id.fromMaybe(std::string()));
return Response::OK();
}

Response BrowserHandler::GrantPermissions(
const std::string& origin,
std::unique_ptr<protocol::Array<protocol::Browser::PermissionType>>
Expand Down
6 changes: 6 additions & 0 deletions content/browser/devtools/protocol/browser_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ class BrowserHandler : public DevToolsDomainHandler, public Browser::Backend {
Response GetBrowserCommandLine(
std::unique_ptr<protocol::Array<std::string>>* arguments) override;

Response SetPermission(
const std::string& origin,
std::unique_ptr<protocol::Browser::PermissionDescriptor> permission,
const protocol::Browser::PermissionSetting& setting,
Maybe<std::string> browser_context_id) override;

Response GrantPermissions(
const std::string& origin,
std::unique_ptr<protocol::Array<protocol::Browser::PermissionType>>
Expand Down
2 changes: 1 addition & 1 deletion content/browser/devtools/protocol_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
{
"domain": "Browser",
"include": ["getVersion", "getHistograms", "getHistogram", "getBrowserCommandLine", "grantPermissions", "resetPermissions", "crash", "crashGpuProcess"]
"include": ["getVersion", "getHistograms", "getHistogram", "getBrowserCommandLine", "grantPermissions", "resetPermissions", "crash", "crashGpuProcess", "setPermission"]
},
{
"domain": "DOM",
Expand Down
84 changes: 63 additions & 21 deletions content/browser/permissions/permission_controller_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,34 @@ void NotifySchedulerAboutPermissionRequest(RenderFrameHost* render_frame_host,
->OnSchedulerTrackedFeatureUsed(feature.value());
}

// Calls |original_cb|, a callback expecting the PermissionStatus of a set of
// permissions, after joining the results of overridden permissions and
// non-overridden permissions.
// |overridden_results| is an array of permissions that have already been
// overridden by DevTools.
// |delegated_results| contains results that did not have overrides - they
// were delegated - their results need to be inserted in order.
void MergeOverriddenAndDelegatedResults(
base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)>
original_cb,
std::vector<base::Optional<blink::mojom::PermissionStatus>>
overridden_results,
const std::vector<blink::mojom::PermissionStatus>& delegated_results) {
std::vector<blink::mojom::PermissionStatus> full_results;
full_results.reserve(overridden_results.size());
auto delegated_it = delegated_results.begin();
for (auto& status : overridden_results) {
if (!status.has_value()) {
CHECK(delegated_it != delegated_results.end());
status.emplace(*delegated_it++);
}
full_results.emplace_back(*status);
}
CHECK(delegated_it == delegated_results.end());

std::move(original_cb).Run(full_results);
}

} // namespace

PermissionControllerImpl::PermissionControllerImpl(
Expand Down Expand Up @@ -155,6 +183,19 @@ void PermissionControllerImpl::NotifyChangedSubscriptions(
callback.Run();
}

void PermissionControllerImpl::SetOverrideForDevTools(
const GURL& origin,
const PermissionType& permission,
const blink::mojom::PermissionStatus& status) {
const auto old_statuses = GetSubscriptionsStatuses(origin);

devtools_permission_overrides_.Set(url::Origin::Create(origin), permission,
status);
NotifyChangedSubscriptions(old_statuses);

UpdateDelegateOverridesForDevTools(origin);
}

void PermissionControllerImpl::GrantOverridesForDevTools(
const GURL& origin,
const std::vector<PermissionType>& permissions) {
Expand Down Expand Up @@ -232,36 +273,37 @@ int PermissionControllerImpl::RequestPermissions(
for (PermissionType permission : permissions)
NotifySchedulerAboutPermissionRequest(render_frame_host, permission);

const PermissionOverrides& overrides = devtools_permission_overrides_.GetAll(
url::Origin::Create(requesting_origin));
if (!overrides.empty()) {
std::vector<blink::mojom::PermissionStatus> results;
for (const auto& permission : permissions) {
auto it = overrides.find(permission);
// TODO(rohpavone): This approach will not work when using SetPermissions,
// because can no longer assume that all overrides are specified is
// removed.
if (it == overrides.end())
results.push_back(blink::mojom::PermissionStatus::DENIED);
else
results.push_back(it->second);
}
std::vector<PermissionType> permissions_without_overrides;
std::vector<base::Optional<blink::mojom::PermissionStatus>> results;
url::Origin origin = url::Origin::Create(requesting_origin);
for (const auto& permission : permissions) {
base::Optional<blink::mojom::PermissionStatus> override_status =
devtools_permission_overrides_.Get(origin, permission);
if (!override_status)
permissions_without_overrides.push_back(permission);
results.push_back(override_status);
}

callback.Run(results);
auto wrapper = base::BindOnce(&MergeOverriddenAndDelegatedResults,
std::move(callback), results);
if (permissions_without_overrides.empty()) {
std::move(wrapper).Run({});
return kNoPendingOperation;
}

// Use delegate to find statuses of other permissions that have been requested
// but do not have overrides.
PermissionControllerDelegate* delegate =
browser_context_->GetPermissionControllerDelegate();
if (!delegate) {
std::vector<blink::mojom::PermissionStatus> result(
permissions.size(), blink::mojom::PermissionStatus::DENIED);
callback.Run(result);
std::move(wrapper).Run(std::vector<blink::mojom::PermissionStatus>(
permissions_without_overrides.size(),
blink::mojom::PermissionStatus::DENIED));
return kNoPendingOperation;
}
return delegate->RequestPermissions(permissions, render_frame_host,
requesting_origin, user_gesture,
callback);
return delegate->RequestPermissions(permissions_without_overrides,
render_frame_host, requesting_origin,
user_gesture, std::move(wrapper));
}

blink::mojom::PermissionStatus PermissionControllerImpl::GetPermissionStatus(
Expand Down
3 changes: 3 additions & 0 deletions content/browser/permissions/permission_controller_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class CONTENT_EXPORT PermissionControllerImpl : public PermissionController {
void GrantOverridesForDevTools(
const GURL& origin,
const std::vector<PermissionType>& permissions);
void SetOverrideForDevTools(const GURL& origin,
const PermissionType& permission,
const blink::mojom::PermissionStatus& status);
void ResetOverridesForDevTools();

// PermissionController implementation.
Expand Down

0 comments on commit b4de951

Please sign in to comment.