Commit 541cc2f7 authored by John Rummell's avatar John Rummell Committed by Commit Bot

Suppress per-device provisioning permission prompt for same origin

If the per-device provisioning permission request happens multiple
times within a 15 minute window, use the same response as the user
choose before if the origin matches. This avoids problems where the
user is prompted multiple times for the same site.

BUG=950200
TEST=tested manually

Change-Id: I8fcb73ebeed5e7ab60b38ab6b7213889f991bbb5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1559491Reviewed-by: default avatarXiaohan Wang <xhwang@chromium.org>
Commit-Queue: John Rummell <jrummell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#652713}
parent 0ebda7c8
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/no_destructor.h"
#include "base/time/time.h"
#include "chrome/browser/android/android_theme_resources.h" #include "chrome/browser/android/android_theme_resources.h"
#include "chrome/browser/permissions/permission_request.h" #include "chrome/browser/permissions/permission_request.h"
#include "chrome/browser/permissions/permission_request_manager.h" #include "chrome/browser/permissions/permission_request_manager.h"
...@@ -23,6 +25,49 @@ ...@@ -23,6 +25,49 @@
namespace { namespace {
// Only keep track of the last response for a short period of time.
constexpr base::TimeDelta kLastRequestDelta = base::TimeDelta::FromMinutes(15);
// Keep track of the last response. This is only kept in memory, so once Chrome
// quits it is forgotten.
class LastResponse {
public:
// If |origin| matches the previously saved |origin_| and this request is
// before |expiry_time|, return true indicating that the previous value should
// be used, and update |allowed| with the previous response. If the origin
// doesn't match or the previous response was too long ago, return false.
bool Matches(const url::Origin& origin, bool* allowed) {
if (!origin_.IsSameOriginWith(origin) || base::Time::Now() > expiry_time_)
return false;
*allowed = allowed_;
return true;
}
// Updates this object with the latest |origin| and |response|.
void Update(const url::Origin& origin, bool response) {
origin_ = origin;
expiry_time_ = base::Time::Now() + kLastRequestDelta;
allowed_ = response;
}
private:
url::Origin origin_;
base::Time expiry_time_;
bool allowed_ = false;
};
// Returns an object containing the last response. We only keep track of one
// response (the latest). This is done for simplicity, as it is unlikely that
// there will different origins getting to this path at the same time. Requests
// could be from different |render_frame_host| objects, but this matches what
// normal permission requests do when the decision is persisted in user's
// profile.
LastResponse& GetLastResponse() {
static base::NoDestructor<LastResponse> s_last_response;
return *s_last_response;
}
// A PermissionRequest to allow MediaDrmBridge to use per-device provisioning. // A PermissionRequest to allow MediaDrmBridge to use per-device provisioning.
class PerDeviceProvisioningPermissionRequest : public PermissionRequest { class PerDeviceProvisioningPermissionRequest : public PermissionRequest {
public: public:
...@@ -50,15 +95,25 @@ class PerDeviceProvisioningPermissionRequest : public PermissionRequest { ...@@ -50,15 +95,25 @@ class PerDeviceProvisioningPermissionRequest : public PermissionRequest {
GURL GetOrigin() const final { return origin_.GetURL(); } GURL GetOrigin() const final { return origin_.GetURL(); }
void PermissionGranted() final { std::move(callback_).Run(true); } void PermissionGranted() final {
UpdateLastResponse(true);
std::move(callback_).Run(true);
}
void PermissionDenied() final { std::move(callback_).Run(false); } void PermissionDenied() final {
UpdateLastResponse(false);
std::move(callback_).Run(false);
}
void Cancelled() final { std::move(callback_).Run(false); } void Cancelled() final {
UpdateLastResponse(false);
std::move(callback_).Run(false);
}
void RequestFinished() final { void RequestFinished() final {
// The |callback_| may not have run if the prompt was ignored, e.g. the tab // The |callback_| may not have run if the prompt was ignored, e.g. the tab
// was closed while the prompt was displayed. // was closed while the prompt was displayed. Don't save this result as the
// last response since it wasn't really a user action.
if (callback_) if (callback_)
std::move(callback_).Run(false); std::move(callback_).Run(false);
...@@ -73,6 +128,10 @@ class PerDeviceProvisioningPermissionRequest : public PermissionRequest { ...@@ -73,6 +128,10 @@ class PerDeviceProvisioningPermissionRequest : public PermissionRequest {
// Can only be self-destructed. See RequestFinished(). // Can only be self-destructed. See RequestFinished().
~PerDeviceProvisioningPermissionRequest() final = default; ~PerDeviceProvisioningPermissionRequest() final = default;
void UpdateLastResponse(bool allowed) {
GetLastResponse().Update(origin_, allowed);
}
const url::Origin origin_; const url::Origin origin_;
base::OnceCallback<void(bool)> callback_; base::OnceCallback<void(bool)> callback_;
...@@ -92,6 +151,15 @@ void RequestPerDeviceProvisioningPermission( ...@@ -92,6 +151,15 @@ void RequestPerDeviceProvisioningPermission(
<< "RequestPerDeviceProvisioningPermission() should only be called when " << "RequestPerDeviceProvisioningPermission() should only be called when "
"per-origin provisioning is supported."; "per-origin provisioning is supported.";
// Return the previous response if it was for the same origin.
bool last_response = false;
if (GetLastResponse().Matches(render_frame_host->GetLastCommittedOrigin(),
&last_response)) {
DVLOG(1) << "Using previous response: " << last_response;
std::move(callback).Run(last_response);
return;
}
auto* web_contents = auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host); content::WebContents::FromRenderFrameHost(render_frame_host);
DCHECK(web_contents) << "WebContents not available."; DCHECK(web_contents) << "WebContents not available.";
......
...@@ -30,7 +30,9 @@ class RenderFrameHost; ...@@ -30,7 +30,9 @@ class RenderFrameHost;
// Requests permission to allow MediaDrmBridge to use per-device provisioning. // Requests permission to allow MediaDrmBridge to use per-device provisioning.
// The |callback| is guaranteed to be called with whether the permission was // The |callback| is guaranteed to be called with whether the permission was
// allowed by the user. The decision is not persisted and does not affect any // allowed by the user. The decision is not persisted and does not affect any
// persisted settings, e.g. content settings. // persisted settings, e.g. content settings. However, the last response is
// saved in memory, and if another request for the same origin happens within 15
// minutes, the previous response is used.
void RequestPerDeviceProvisioningPermission( void RequestPerDeviceProvisioningPermission(
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
base::OnceCallback<void(bool)> callback); base::OnceCallback<void(bool)> callback);
......
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