Commit 349247d2 authored by Toby Huang's avatar Toby Huang Committed by Commit Bot

Child users: Ask for parent permission or display error from launcher

Currently, if an app is disabled pending custodian approval, and the
supervised user tries to open it through the launcher, nothing
happens. This CL fixes this behavior by either asking for parent
permission or displaying an error dialog. If the parent has the
"Permissions for sites, apps and extensions" toggle enabled, then
launching the app will ask for parent permission. Otherwise, the user
will see an error dialog.

This CL also refactors some common logic between the ManagementAPI
and ExtensionEnableFlow into the SupervisedUserExtensionsDelegate for
determining which dialog to show when enabling extensions for
supervised users.

Bug: 1079415,1071255
Change-Id: I585238db5e9a9de96849b7a15dda120b13339b68
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2238408
Commit-Queue: Toby Huang <tobyhuang@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarDan S <danan@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Reviewed-by: default avatarYilkal Abe <yilkal@chromium.org>
Reviewed-by: default avatarNancy Wang <nancylingwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#785958}
parent 2da14605
...@@ -173,7 +173,7 @@ class ExtensionAppsEnableFlow : public ExtensionEnableFlowDelegate { ...@@ -173,7 +173,7 @@ class ExtensionAppsEnableFlow : public ExtensionEnableFlowDelegate {
if (!flow_) { if (!flow_) {
flow_ = std::make_unique<ExtensionEnableFlow>(profile_, app_id_, this); flow_ = std::make_unique<ExtensionEnableFlow>(profile_, app_id_, this);
flow_->StartForNativeWindow(nullptr); flow_->Start();
} }
} }
......
...@@ -205,6 +205,13 @@ void AppActivityRegistry::OnAppAvailable(const AppId& app_id) { ...@@ -205,6 +205,13 @@ void AppActivityRegistry::OnAppAvailable(const AppId& app_id) {
OnAppReinstalled(app_id); OnAppReinstalled(app_id);
} }
if (IsWebAppOrExtension(app_id) && app_id != GetChromeAppId() &&
base::Contains(activity_registry_, GetChromeAppId()) &&
GetAppState(app_id) == AppState::kBlocked) {
SetAppState(app_id, GetAppState(GetChromeAppId()));
return;
}
SetAppState(app_id, AppState::kAvailable); SetAppState(app_id, AppState::kAvailable);
} }
...@@ -241,7 +248,8 @@ void AppActivityRegistry::OnAppActive(const AppId& app_id, ...@@ -241,7 +248,8 @@ void AppActivityRegistry::OnAppActive(const AppId& app_id,
return; return;
} }
DCHECK(IsAppAvailable(app_id)); if (!IsAppAvailable(app_id))
return;
std::set<aura::Window*>& active_windows = app_details.active_windows; std::set<aura::Window*>& active_windows = app_details.active_windows;
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
#include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "chrome/browser/supervised_user/supervised_user_test_util.h" #include "chrome/browser/supervised_user/supervised_user_test_util.h"
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/gpu_data_manager.h"
#endif #endif
...@@ -852,56 +851,78 @@ class TestSupervisedUserExtensionsDelegate ...@@ -852,56 +851,78 @@ class TestSupervisedUserExtensionsDelegate
// SupervisedUserExtensionsDelegate: // SupervisedUserExtensionsDelegate:
bool IsChild(content::BrowserContext* context) const override { return true; } bool IsChild(content::BrowserContext* context) const override { return true; }
bool IsSupervisedChildWhoMayInstallExtensions(
content::BrowserContext* context) const override {
return is_supervised_child_who_may_install_extensions_;
}
bool IsExtensionAllowedByParent( bool IsExtensionAllowedByParent(
const extensions::Extension& extension, const extensions::Extension& extension,
content::BrowserContext* context) const override { content::BrowserContext* context) const override {
return false; SupervisedUserService* supervised_user_service =
SupervisedUserServiceFactory::GetForBrowserContext(context);
return supervised_user_service->IsExtensionAllowed(extension);
}
void PromptForParentPermissionOrShowError(
const extensions::Extension& extension,
content::BrowserContext* context,
content::WebContents* contents,
ParentPermissionDialogDoneCallback parent_permission_callback,
base::OnceClosure error_callback) override {
// Preconditions.
DCHECK(IsChild(context));
DCHECK(!IsExtensionAllowedByParent(extension, context));
if (CanInstallExtensions(context)) {
ShowParentPermissionDialogForExtension(
extension, context, contents, std::move(parent_permission_callback));
} else {
ShowExtensionEnableBlockedByParentDialogForExtension(
extension, contents, std::move(error_callback));
}
}
void set_next_parent_permission_dialog_result(
ParentPermissionDialogResult result) {
dialog_result_ = result;
} }
int show_dialog_count() const { return show_dialog_count_; }
int show_block_dialog_count() const { return show_block_dialog_count_; }
private:
// Returns true if |context| represents a supervised child account who may
// install extensions with parent permission.
bool CanInstallExtensions(content::BrowserContext* context) const {
SupervisedUserService* supervised_user_service =
SupervisedUserServiceFactory::GetForBrowserContext(context);
return supervised_user_service->CanInstallExtensions();
}
// Shows a parent permission dialog for |extension| and call |done_callback|
// when it completes.
void ShowParentPermissionDialogForExtension( void ShowParentPermissionDialogForExtension(
const extensions::Extension& extension, const extensions::Extension& extension,
content::BrowserContext* context, content::BrowserContext* context,
content::WebContents* contents, content::WebContents* contents,
ParentPermissionDialogDoneCallback done_callback) override { ParentPermissionDialogDoneCallback done_callback) {
++show_dialog_count_; ++show_dialog_count_;
std::move(done_callback).Run(dialog_result_); std::move(done_callback).Run(dialog_result_);
} }
// Shows a dialog indicating that |extension| has been blocked and call
// |done_callback| when it completes.
void ShowExtensionEnableBlockedByParentDialogForExtension( void ShowExtensionEnableBlockedByParentDialogForExtension(
const extensions::Extension* extension, const extensions::Extension& extension,
content::WebContents* contents, content::WebContents* contents,
base::OnceClosure done_callback) override { base::OnceClosure done_callback) {
show_block_dialog_count_++; show_block_dialog_count_++;
std::move(done_callback).Run();
}
void RecordExtensionEnableBlockedByParentDialogUmaMetric() override {
SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics( SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics(
SupervisedUserExtensionsMetricsRecorder::EnablementState:: SupervisedUserExtensionsMetricsRecorder::EnablementState::
kFailedToEnable); kFailedToEnable);
std::move(done_callback).Run();
} }
void set_next_parent_permission_dialog_result(
ParentPermissionDialogResult result) {
dialog_result_ = result;
}
void set_is_supervised_child_who_may_install_extensions(bool value) {
is_supervised_child_who_may_install_extensions_ = value;
}
int show_dialog_count() const { return show_dialog_count_; }
int show_block_dialog_count() const { return show_block_dialog_count_; }
private:
ParentPermissionDialogResult dialog_result_ = ParentPermissionDialogResult dialog_result_ =
ParentPermissionDialogResult::kParentPermissionFailed; ParentPermissionDialogResult::kParentPermissionFailed;
int show_dialog_count_ = 0; int show_dialog_count_ = 0;
int show_block_dialog_count_ = 0; int show_block_dialog_count_ = 0;
bool is_supervised_child_who_may_install_extensions_ = true;
}; };
// Tests for supervised users (child accounts). Supervised users are not allowed // Tests for supervised users (child accounts). Supervised users are not allowed
...@@ -975,11 +996,8 @@ TEST_F(ManagementApiSupervisedUserTest, SetEnabled_BlockedByParent) { ...@@ -975,11 +996,8 @@ TEST_F(ManagementApiSupervisedUserTest, SetEnabled_BlockedByParent) {
// Simulate disabling Permissions for sites, apps and extensions // Simulate disabling Permissions for sites, apps and extensions
// in the testing supervised user service delegate used by the Management API. // in the testing supervised user service delegate used by the Management API.
supervised_user_delegate_->set_is_supervised_child_who_may_install_extensions( GetSupervisedUserService()
false); ->SetSupervisedUserExtensionsMayRequestPermissionsPrefForTesting(false);
// Ensure that the web contents can be used to create a modal dialog.
web_modal::WebContentsModalDialogManager::CreateForWebContents(
web_contents_.get());
// The supervised user trying to enable while Permissions for sites, apps and // The supervised user trying to enable while Permissions for sites, apps and
// extensions is disabled should fail. // extensions is disabled should fail.
...@@ -1008,61 +1026,6 @@ TEST_F(ManagementApiSupervisedUserTest, SetEnabled_BlockedByParent) { ...@@ -1008,61 +1026,6 @@ TEST_F(ManagementApiSupervisedUserTest, SetEnabled_BlockedByParent) {
SupervisedUserExtensionsMetricsRecorder::kFailedToEnableActionName)); SupervisedUserExtensionsMetricsRecorder::kFailedToEnableActionName));
} }
TEST_F(ManagementApiSupervisedUserTest,
SetEnabled_BlockedByParentNoDialogWhenNoDialogManagerAvailable) {
// Preconditions.
ASSERT_TRUE(profile()->IsChild());
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
base::FilePath base_path = data_dir().AppendASCII("permissions_increase");
base::FilePath pem_path = base_path.AppendASCII("permissions.pem");
base::FilePath path = base_path.AppendASCII("v1");
const Extension* extension =
PackAndInstallCRX(path, pem_path, INSTALL_WITHOUT_LOAD);
ASSERT_TRUE(extension);
// The extension should be installed but disabled.
EXPECT_TRUE(registry()->disabled_extensions().Contains(extension->id()));
const std::string extension_id = extension->id();
ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
EXPECT_TRUE(prefs->HasDisableReason(
extension_id, disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED));
// Simulate disabling Permissions for sites, apps and extensions
// in the testing supervised user service delegate used by the Management API.
supervised_user_delegate_->set_is_supervised_child_who_may_install_extensions(
false);
// The supervised user trying to enable while Permissions for sites, apps and
// extensions is disabled should fail.
{
std::string error;
bool success = RunSetEnabledFunction(web_contents_.get(), extension_id,
/*use_user_gesture=*/true,
/*accept_dialog=*/true, &error);
EXPECT_FALSE(success);
EXPECT_FALSE(error.empty());
EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id));
// The block dialog should not have been shown.
EXPECT_EQ(supervised_user_delegate_->show_block_dialog_count(), 0);
}
histogram_tester.ExpectUniqueSample(
SupervisedUserExtensionsMetricsRecorder::kEnablementHistogramName,
SupervisedUserExtensionsMetricsRecorder::EnablementState::kFailedToEnable,
1);
histogram_tester.ExpectTotalCount(
SupervisedUserExtensionsMetricsRecorder::kEnablementHistogramName, 1);
EXPECT_EQ(
1,
user_action_tester.GetActionCount(
SupervisedUserExtensionsMetricsRecorder::kFailedToEnableActionName));
}
// Tests enabling an extension via management API after it was disabled due to // Tests enabling an extension via management API after it was disabled due to
// permission increase for supervised users. // permission increase for supervised users.
// Prevents a regression to crbug/1068660. // Prevents a regression to crbug/1068660.
......
...@@ -589,7 +589,7 @@ bool WebstorePrivateBeginInstallWithManifest3Function:: ...@@ -589,7 +589,7 @@ bool WebstorePrivateBeginInstallWithManifest3Function::
parent_permission_dialog_ = parent_permission_dialog_ =
ParentPermissionDialog::CreateParentPermissionDialogForExtension( ParentPermissionDialog::CreateParentPermissionDialogForExtension(
profile, web_contents, web_contents->GetTopLevelNativeWindow(), profile, web_contents->GetTopLevelNativeWindow(),
gfx::ImageSkia::CreateFrom1xBitmap(icon_), dummy_extension_.get(), gfx::ImageSkia::CreateFrom1xBitmap(icon_), dummy_extension_.get(),
std::move(done_callback)); std::move(done_callback));
parent_permission_dialog_->ShowDialog(); parent_permission_dialog_->ShowDialog();
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/supervised_user/supervised_user_extensions_metrics_recorder.h" #include "chrome/browser/supervised_user/supervised_user_extensions_metrics_recorder.h"
#include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service.h"
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/supervised_user/parent_permission_dialog.h" #include "chrome/browser/ui/supervised_user/parent_permission_dialog.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_dialog_auto_confirm.h"
namespace { namespace {
...@@ -54,27 +56,44 @@ bool SupervisedUserExtensionsDelegateImpl::IsChild( ...@@ -54,27 +56,44 @@ bool SupervisedUserExtensionsDelegateImpl::IsChild(
content::BrowserContext* context) const { content::BrowserContext* context) const {
SupervisedUserService* supervised_user_service = SupervisedUserService* supervised_user_service =
SupervisedUserServiceFactory::GetForBrowserContext(context); SupervisedUserServiceFactory::GetForBrowserContext(context);
return supervised_user_service->IsChild(); return supervised_user_service->IsChild();
} }
bool SupervisedUserExtensionsDelegateImpl:: bool SupervisedUserExtensionsDelegateImpl::IsExtensionAllowedByParent(
IsSupervisedChildWhoMayInstallExtensions( const extensions::Extension& extension,
content::BrowserContext* context) const { content::BrowserContext* context) const {
SupervisedUserService* supervised_user_service = SupervisedUserService* supervised_user_service =
SupervisedUserServiceFactory::GetForBrowserContext(context); SupervisedUserServiceFactory::GetForBrowserContext(context);
return supervised_user_service->IsExtensionAllowed(extension);
return supervised_user_service->IsChild() &&
supervised_user_service->CanInstallExtensions();
} }
bool SupervisedUserExtensionsDelegateImpl::IsExtensionAllowedByParent( void SupervisedUserExtensionsDelegateImpl::PromptForParentPermissionOrShowError(
const extensions::Extension& extension, const extensions::Extension& extension,
content::BrowserContext* browser_context,
content::WebContents* web_contents,
ParentPermissionDialogDoneCallback parent_permission_callback,
base::OnceClosure error_callback) {
DCHECK(IsChild(browser_context));
DCHECK(!IsExtensionAllowedByParent(extension, browser_context));
// Supervised users who can install extensions still require parent permission
// for installation or enablement. If the user isn't allowed to install
// extensions at all, then we will just show a "blocked" dialog.
if (CanInstallExtensions(browser_context)) {
ShowParentPermissionDialogForExtension(
extension, browser_context, web_contents,
std::move(parent_permission_callback));
} else {
ShowExtensionEnableBlockedByParentDialogForExtension(
extension, web_contents, std::move(error_callback));
}
}
bool SupervisedUserExtensionsDelegateImpl::CanInstallExtensions(
content::BrowserContext* context) const { content::BrowserContext* context) const {
SupervisedUserService* supervised_user_service = SupervisedUserService* supervised_user_service =
SupervisedUserServiceFactory::GetForBrowserContext(context); SupervisedUserServiceFactory::GetForBrowserContext(context);
return IsSupervisedChildWhoMayInstallExtensions(context) && return supervised_user_service->CanInstallExtensions();
supervised_user_service->IsExtensionAllowed(extension);
} }
void SupervisedUserExtensionsDelegateImpl:: void SupervisedUserExtensionsDelegateImpl::
...@@ -86,31 +105,32 @@ void SupervisedUserExtensionsDelegateImpl:: ...@@ -86,31 +105,32 @@ void SupervisedUserExtensionsDelegateImpl::
ParentPermissionDialog::DoneCallback inner_done_callback = base::BindOnce( ParentPermissionDialog::DoneCallback inner_done_callback = base::BindOnce(
&::OnParentPermissionDialogComplete, std::move(done_callback)); &::OnParentPermissionDialogComplete, std::move(done_callback));
gfx::NativeWindow parent_window =
contents ? contents->GetTopLevelNativeWindow() : nullptr;
parent_permission_dialog_ = parent_permission_dialog_ =
ParentPermissionDialog::CreateParentPermissionDialogForExtension( ParentPermissionDialog::CreateParentPermissionDialogForExtension(
Profile::FromBrowserContext(context), contents, Profile::FromBrowserContext(context), parent_window, gfx::ImageSkia(),
contents->GetTopLevelNativeWindow(), gfx::ImageSkia(), &extension, &extension, std::move(inner_done_callback));
std::move(inner_done_callback));
parent_permission_dialog_->ShowDialog(); parent_permission_dialog_->ShowDialog();
} }
void SupervisedUserExtensionsDelegateImpl:: void SupervisedUserExtensionsDelegateImpl::
ShowExtensionEnableBlockedByParentDialogForExtension( ShowExtensionEnableBlockedByParentDialogForExtension(
const extensions::Extension* extension, const extensions::Extension& extension,
content::WebContents* contents, content::WebContents* contents,
base::OnceClosure done_callback) { base::OnceClosure done_callback) {
DCHECK(contents);
chrome::ShowExtensionInstallBlockedByParentDialog(
chrome::ExtensionInstalledBlockedByParentDialogAction::kEnable, extension,
contents, std::move(done_callback));
}
void SupervisedUserExtensionsDelegateImpl::
RecordExtensionEnableBlockedByParentDialogUmaMetric() {
SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics( SupervisedUserExtensionsMetricsRecorder::RecordEnablementUmaMetrics(
SupervisedUserExtensionsMetricsRecorder::EnablementState:: SupervisedUserExtensionsMetricsRecorder::EnablementState::
kFailedToEnable); kFailedToEnable);
if (ScopedTestDialogAutoConfirm::GetAutoConfirmValue() !=
ScopedTestDialogAutoConfirm::NONE) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(done_callback));
return;
}
chrome::ShowExtensionInstallBlockedByParentDialog(
chrome::ExtensionInstalledBlockedByParentDialogAction::kEnable,
&extension, contents, std::move(done_callback));
} }
} // namespace extensions } // namespace extensions
...@@ -23,29 +23,37 @@ class SupervisedUserExtensionsDelegateImpl ...@@ -23,29 +23,37 @@ class SupervisedUserExtensionsDelegateImpl
// extensions::SupervisedUserExtensionsDelegate overrides // extensions::SupervisedUserExtensionsDelegate overrides
bool IsChild(content::BrowserContext* context) const override; bool IsChild(content::BrowserContext* context) const override;
bool IsSupervisedChildWhoMayInstallExtensions(
content::BrowserContext* context) const override;
bool IsExtensionAllowedByParent( bool IsExtensionAllowedByParent(
const extensions::Extension& extension, const extensions::Extension& extension,
content::BrowserContext* context) const override; content::BrowserContext* context) const override;
void PromptForParentPermissionOrShowError(
const extensions::Extension& extension,
content::BrowserContext* browser_context,
content::WebContents* web_contents,
ParentPermissionDialogDoneCallback parent_permission_callback,
base::OnceClosure error_callback) override;
private:
// Returns true if |context| represents a supervised child account who may
// install extensions with parent permission.
bool CanInstallExtensions(content::BrowserContext* context) const;
// Shows a parent permission dialog for |extension| and call |done_callback|
// when it completes.
void ShowParentPermissionDialogForExtension( void ShowParentPermissionDialogForExtension(
const extensions::Extension& extension, const extensions::Extension& extension,
content::BrowserContext* context, content::BrowserContext* context,
content::WebContents* contents, content::WebContents* contents,
extensions::SupervisedUserExtensionsDelegate:: extensions::SupervisedUserExtensionsDelegate::
ParentPermissionDialogDoneCallback done_callback) override; ParentPermissionDialogDoneCallback done_callback);
// Shows a dialog indicating that |extension| has been blocked and call
// |done_callback| when it completes.
void ShowExtensionEnableBlockedByParentDialogForExtension( void ShowExtensionEnableBlockedByParentDialogForExtension(
const extensions::Extension* extension, const extensions::Extension& extension,
content::WebContents* contents, content::WebContents* contents,
base::OnceClosure done_callback) override; base::OnceClosure done_callback);
void RecordExtensionEnableBlockedByParentDialogUmaMetric() override;
private:
std::unique_ptr<ParentPermissionDialog> parent_permission_dialog_; std::unique_ptr<ParentPermissionDialog> parent_permission_dialog_;
}; };
......
...@@ -22,6 +22,12 @@ ...@@ -22,6 +22,12 @@
#include "chrome/browser/ui/user_manager.h" #include "chrome/browser/ui/user_manager.h"
#endif // !defined(OS_CHROMEOS) #endif // !defined(OS_CHROMEOS)
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
#include "chrome/browser/supervised_user/supervised_user_service.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "extensions/browser/api/management/management_api.h"
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
using extensions::Extension; using extensions::Extension;
ExtensionEnableFlow::ExtensionEnableFlow(Profile* profile, ExtensionEnableFlow::ExtensionEnableFlow(Profile* profile,
...@@ -88,12 +94,39 @@ void ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() { ...@@ -88,12 +94,39 @@ void ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() {
const Extension* extension = const Extension* extension =
registry->disabled_extensions().GetByID(extension_id_); registry->disabled_extensions().GetByID(extension_id_);
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
extensions::SupervisedUserExtensionsDelegate*
supervised_user_extensions_delegate =
extensions::ManagementAPI::GetFactoryInstance()
->Get(profile_)
->GetSupervisedUserExtensionsDelegate();
DCHECK(supervised_user_extensions_delegate);
if (profile_->IsChild() && extension &&
// Only ask for parent approval if the extension still requires approval.
!supervised_user_extensions_delegate->IsExtensionAllowedByParent(
*extension, profile_)) {
// Either ask for parent permission or notify the child that their parent
// has disabled this action.
auto parent_permission_callback =
base::BindOnce(&ExtensionEnableFlow::OnParentPermissionDialogDone,
weak_ptr_factory_.GetWeakPtr());
auto error_callback =
base::BindOnce(&ExtensionEnableFlow::OnBlockedByParentDialogDone,
weak_ptr_factory_.GetWeakPtr());
supervised_user_extensions_delegate->PromptForParentPermissionOrShowError(
*extension, profile_, parent_contents_,
std::move(parent_permission_callback), std::move(error_callback));
return;
}
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
bool abort = !extension || bool abort = !extension ||
// The extension might be force-disabled by policy. // The extension might be force-disabled by policy.
system->management_policy()->MustRemainDisabled( system->management_policy()->MustRemainDisabled(
extension, nullptr, nullptr); extension, nullptr, nullptr);
if (abort) { if (abort) {
delegate_->ExtensionEnableFlowAborted(false); // |delegate_| may delete us. delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/false); // |delegate_| may delete us.
return; return;
} }
...@@ -133,6 +166,34 @@ void ExtensionEnableFlow::CreatePrompt() { ...@@ -133,6 +166,34 @@ void ExtensionEnableFlow::CreatePrompt() {
: new ExtensionInstallPrompt(profile_, nullptr)); : new ExtensionInstallPrompt(profile_, nullptr));
} }
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
void ExtensionEnableFlow::OnParentPermissionDialogDone(
extensions::SupervisedUserExtensionsDelegate::ParentPermissionDialogResult
result) {
switch (result) {
case extensions::SupervisedUserExtensionsDelegate::
ParentPermissionDialogResult::kParentPermissionReceived:
EnableExtension();
break;
case extensions::SupervisedUserExtensionsDelegate::
ParentPermissionDialogResult::kParentPermissionCanceled:
delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/true); // |delegate_| may delete us.
break;
case extensions::SupervisedUserExtensionsDelegate::
ParentPermissionDialogResult::kParentPermissionFailed:
delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/false); // |delegate_| may delete us.
break;
}
}
void ExtensionEnableFlow::OnBlockedByParentDialogDone() {
delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/false); // |delegate_| may delete us.
}
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
void ExtensionEnableFlow::StartObserving() { void ExtensionEnableFlow::StartObserving() {
extension_registry_observer_.Add( extension_registry_observer_.Add(
extensions::ExtensionRegistry::Get(profile_)); extensions::ExtensionRegistry::Get(profile_));
...@@ -151,7 +212,8 @@ void ExtensionEnableFlow::Observe(int type, ...@@ -151,7 +212,8 @@ void ExtensionEnableFlow::Observe(int type,
const content::NotificationDetails& details) { const content::NotificationDetails& details) {
DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, type); DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, type);
StopObserving(); StopObserving();
delegate_->ExtensionEnableFlowAborted(false); delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/false); // |delegate_| may delete us.
} }
void ExtensionEnableFlow::OnExtensionLoaded( void ExtensionEnableFlow::OnExtensionLoaded(
...@@ -169,33 +231,49 @@ void ExtensionEnableFlow::OnExtensionUninstalled( ...@@ -169,33 +231,49 @@ void ExtensionEnableFlow::OnExtensionUninstalled(
extensions::UninstallReason reason) { extensions::UninstallReason reason) {
if (extension->id() == extension_id_) { if (extension->id() == extension_id_) {
StopObserving(); StopObserving();
delegate_->ExtensionEnableFlowAborted(false); delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/false); // |delegate_| may delete us.
} }
} }
void ExtensionEnableFlow::EnableExtension() {
extensions::ExtensionService* service =
extensions::ExtensionSystem::Get(profile_)->extension_service();
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile_);
// The extension can be uninstalled in another window while the UI was
// showing. Treat it as a cancellation and notify |delegate_|.
const Extension* extension =
registry->disabled_extensions().GetByID(extension_id_);
if (!extension) {
delegate_->ExtensionEnableFlowAborted(
/*user_initiated=*/true); // |delegate_| may delete us.
return;
}
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
if (profile_->IsChild()) {
// We need to add parent approval first.
SupervisedUserService* supervised_user_service =
SupervisedUserServiceFactory::GetForProfile(profile_);
supervised_user_service->AddExtensionApproval(*extension);
supervised_user_service->RecordExtensionEnablementUmaMetrics(
/*enabled=*/true);
}
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
service->GrantPermissionsAndEnableExtension(extension);
DCHECK(service->IsExtensionEnabled(extension_id_));
delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us.
}
void ExtensionEnableFlow::InstallPromptDone( void ExtensionEnableFlow::InstallPromptDone(
ExtensionInstallPrompt::Result result) { ExtensionInstallPrompt::Result result) {
if (result == ExtensionInstallPrompt::Result::ACCEPTED) { if (result == ExtensionInstallPrompt::Result::ACCEPTED) {
extensions::ExtensionService* service = EnableExtension();
extensions::ExtensionSystem::Get(profile_)->extension_service();
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile_);
// The extension can be uninstalled in another window while the UI was
// showing. Treat it as a cancellation and notify |delegate_|.
const Extension* extension =
registry->disabled_extensions().GetByID(extension_id_);
if (!extension) {
delegate_->ExtensionEnableFlowAborted(true);
return;
}
service->GrantPermissionsAndEnableExtension(extension);
DCHECK(service->IsExtensionEnabled(extension_id_));
delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us.
} else { } else {
delegate_->ExtensionEnableFlowAborted( delegate_->ExtensionEnableFlowAborted(/*user_initiated=*/
result == ExtensionInstallPrompt::Result::USER_CANCELED); result == ExtensionInstallPrompt::
Result::USER_CANCELED);
// |delegate_| may delete us. // |delegate_| may delete us.
} }
} }
...@@ -14,11 +14,16 @@ ...@@ -14,11 +14,16 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "chrome/browser/extensions/extension_install_prompt.h" #include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/common/buildflags.h"
#include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_registrar.h"
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_registry_observer.h" #include "extensions/browser/extension_registry_observer.h"
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
#include "extensions/browser/supervised_user_extensions_delegate.h"
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
class ExtensionEnableFlowDelegate; class ExtensionEnableFlowDelegate;
namespace content { namespace content {
...@@ -69,6 +74,17 @@ class ExtensionEnableFlow : public content::NotificationObserver, ...@@ -69,6 +74,17 @@ class ExtensionEnableFlow : public content::NotificationObserver,
// Creates an ExtensionInstallPrompt in |prompt_|. // Creates an ExtensionInstallPrompt in |prompt_|.
void CreatePrompt(); void CreatePrompt();
#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
// Called when the user dismisses the Parent Permission Dialog.
void OnParentPermissionDialogDone(
extensions::SupervisedUserExtensionsDelegate::ParentPermissionDialogResult
result);
// Called when the user dismisses the Extension Install Blocked By Parent
// Dialog.
void OnBlockedByParentDialogDone();
#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
// Starts/stops observing extension load notifications. // Starts/stops observing extension load notifications.
void StartObserving(); void StartObserving();
void StopObserving(); void StopObserving();
...@@ -85,6 +101,8 @@ class ExtensionEnableFlow : public content::NotificationObserver, ...@@ -85,6 +101,8 @@ class ExtensionEnableFlow : public content::NotificationObserver,
const extensions::Extension* extension, const extensions::Extension* extension,
extensions::UninstallReason reason) override; extensions::UninstallReason reason) override;
void EnableExtension();
void InstallPromptDone(ExtensionInstallPrompt::Result result); void InstallPromptDone(ExtensionInstallPrompt::Result result);
Profile* const profile_; Profile* const profile_;
......
...@@ -4,12 +4,10 @@ ...@@ -4,12 +4,10 @@
#include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" #include "chrome/browser/ui/extensions/extension_enable_flow_test_delegate.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
...@@ -43,50 +41,18 @@ class TestManagementProvider : public extensions::ManagementPolicy::Provider { ...@@ -43,50 +41,18 @@ class TestManagementProvider : public extensions::ManagementPolicy::Provider {
DISALLOW_COPY_AND_ASSIGN(TestManagementProvider); DISALLOW_COPY_AND_ASSIGN(TestManagementProvider);
}; };
class TestDelegate : public ExtensionEnableFlowDelegate {
public:
TestDelegate() {}
~TestDelegate() override {}
enum Result {
ABORTED,
FINISHED,
};
void ExtensionEnableFlowFinished() override {
result_ = FINISHED;
run_loop_.Quit();
}
void ExtensionEnableFlowAborted(bool user_initiated) override {
result_ = ABORTED;
run_loop_.Quit();
}
void Wait() { run_loop_.Run(); }
const base::Optional<Result>& result() const { return result_; }
private:
base::Optional<Result> result_;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};
} // namespace } // namespace
using ExtensionEnableFlowBrowserTest = extensions::ExtensionBrowserTest; using ExtensionEnableFlowTest = extensions::ExtensionBrowserTest;
// Test that trying to enable an extension that's blocked by policy fails // Test that trying to enable an extension that's blocked by policy fails
// gracefully. See https://crbug.com/783831. // gracefully. See https://crbug.com/783831.
IN_PROC_BROWSER_TEST_F(ExtensionEnableFlowBrowserTest, IN_PROC_BROWSER_TEST_F(ExtensionEnableFlowTest,
TryEnablingPolicyForbiddenExtension) { TryEnablingPolicyForbiddenExtension) {
scoped_refptr<const extensions::Extension> extension = scoped_refptr<const extensions::Extension> extension =
extensions::ExtensionBuilder("extension").Build(); extensions::ExtensionBuilder("extension").Build();
extension_service()->AddExtension(extension.get()); extension_service()->AddExtension(extension.get());
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(profile());
{ {
extensions::ScopedTestDialogAutoConfirm auto_confirm( extensions::ScopedTestDialogAutoConfirm auto_confirm(
extensions::ScopedTestDialogAutoConfirm::ACCEPT); extensions::ScopedTestDialogAutoConfirm::ACCEPT);
...@@ -98,9 +64,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionEnableFlowBrowserTest, ...@@ -98,9 +64,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionEnableFlowBrowserTest,
management_policy->RegisterProvider(&test_provider); management_policy->RegisterProvider(&test_provider);
extension_service()->DisableExtension( extension_service()->DisableExtension(
extension->id(), extensions::disable_reason::DISABLE_BLOCKED_BY_POLICY); extension->id(), extensions::disable_reason::DISABLE_BLOCKED_BY_POLICY);
EXPECT_TRUE(registry->disabled_extensions().Contains(extension->id())); EXPECT_TRUE(
extension_registry()->disabled_extensions().Contains(extension->id()));
TestDelegate delegate; ExtensionEnableFlowTestDelegate delegate;
ExtensionEnableFlow enable_flow(profile(), extension->id(), &delegate); ExtensionEnableFlow enable_flow(profile(), extension->id(), &delegate);
...@@ -110,9 +77,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionEnableFlowBrowserTest, ...@@ -110,9 +77,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionEnableFlowBrowserTest,
delegate.Wait(); delegate.Wait();
ASSERT_TRUE(delegate.result()); ASSERT_TRUE(delegate.result());
EXPECT_EQ(TestDelegate::ABORTED, *delegate.result()); EXPECT_EQ(ExtensionEnableFlowTestDelegate::ABORTED, *delegate.result());
EXPECT_TRUE(registry->disabled_extensions().Contains(extension->id())); EXPECT_TRUE(
extension_registry()->disabled_extensions().Contains(extension->id()));
management_policy->UnregisterProvider(&test_provider); management_policy->UnregisterProvider(&test_provider);
} }
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/extensions/extension_enable_flow_test_delegate.h"
ExtensionEnableFlowTestDelegate::ExtensionEnableFlowTestDelegate() = default;
ExtensionEnableFlowTestDelegate::~ExtensionEnableFlowTestDelegate() = default;
void ExtensionEnableFlowTestDelegate::ExtensionEnableFlowFinished() {
result_ = FINISHED;
run_loop_.Quit();
}
void ExtensionEnableFlowTestDelegate::ExtensionEnableFlowAborted(
bool user_initiated) {
result_ = ABORTED;
run_loop_.Quit();
}
void ExtensionEnableFlowTestDelegate::Wait() {
run_loop_.Run();
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ENABLE_FLOW_TEST_DELEGATE_H_
#define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ENABLE_FLOW_TEST_DELEGATE_H_
#include "base/optional.h"
#include "base/run_loop.h"
#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
class ExtensionEnableFlowTestDelegate : public ExtensionEnableFlowDelegate {
public:
ExtensionEnableFlowTestDelegate();
~ExtensionEnableFlowTestDelegate() override;
ExtensionEnableFlowTestDelegate(const ExtensionEnableFlowTestDelegate&) =
delete;
ExtensionEnableFlowTestDelegate& operator=(
const ExtensionEnableFlowTestDelegate&) = delete;
enum Result {
ABORTED,
FINISHED,
};
// ExtensionEnableFlowDelegate:
void ExtensionEnableFlowFinished() override;
void ExtensionEnableFlowAborted(bool user_initiated) override;
// Wait for the extension enable flow to complete.
void Wait();
const base::Optional<Result>& result() const { return result_; }
private:
base::Optional<Result> result_;
base::RunLoop run_loop_;
};
#endif // CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_ENABLE_FLOW_TEST_DELEGATE_H_
...@@ -17,10 +17,6 @@ ...@@ -17,10 +17,6 @@
class Profile; class Profile;
namespace content {
class WebContents;
}
namespace extensions { namespace extensions {
class Extension; class Extension;
} }
...@@ -75,14 +71,12 @@ class ParentPermissionDialog { ...@@ -75,14 +71,12 @@ class ParentPermissionDialog {
// Creates a ParentPermissionDialog. // Creates a ParentPermissionDialog.
// |profile| is the child user's profile. // |profile| is the child user's profile.
// |web_contents| is the web_contents of the initiator. // |window| is the window to which the dialog will be modal. Can be nullptr.
// |window| is the window to which the dialog will be modal.
// |icon| will be displayed to the side of |message|. // |icon| will be displayed to the side of |message|.
// |message| will be displayed in the body of the dialog. // |message| will be displayed in the body of the dialog.
// |done_callback| will be called on dialog completion. // |done_callback| will be called on dialog completion.
static std::unique_ptr<ParentPermissionDialog> CreateParentPermissionDialog( static std::unique_ptr<ParentPermissionDialog> CreateParentPermissionDialog(
Profile* profile, Profile* profile,
content::WebContents* web_contents,
gfx::NativeWindow window, gfx::NativeWindow window,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const base::string16& message, const base::string16& message,
...@@ -91,14 +85,12 @@ class ParentPermissionDialog { ...@@ -91,14 +85,12 @@ class ParentPermissionDialog {
// Creates a ParentPermissionDialog customized for the installation of the // Creates a ParentPermissionDialog customized for the installation of the
// specified |extension|. // specified |extension|.
// |profile| is the child user's profile. // |profile| is the child user's profile.
// |web_contents| is the web_contents of the initiator. // |window| is the window to which the dialog will be modal. Can be nullptr.
// |window| is the window to which the dialog will be modal.
// |icon| will be used as a backup in case |extension| doesn't have a loaded // |icon| will be used as a backup in case |extension| doesn't have a loaded
// |done_callback| will be called on dialog completion. // |done_callback| will be called on dialog completion.
static std::unique_ptr<ParentPermissionDialog> static std::unique_ptr<ParentPermissionDialog>
CreateParentPermissionDialogForExtension( CreateParentPermissionDialogForExtension(
Profile* profile, Profile* profile,
content::WebContents* web_contents,
gfx::NativeWindow window, gfx::NativeWindow window,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const extensions::Extension* extension, const extensions::Extension* extension,
......
...@@ -39,10 +39,15 @@ void ShowExtensionInstallBlockedByParentDialog( ...@@ -39,10 +39,15 @@ void ShowExtensionInstallBlockedByParentDialog(
base::OnceClosure done_callback) { base::OnceClosure done_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto dialog = std::make_unique<ExtensionInstallBlockedByParentDialogView>( auto dialog = std::make_unique<ExtensionInstallBlockedByParentDialogView>(
action, extension, web_contents->GetTopLevelNativeWindow(), action, extension, std::move(done_callback));
std::move(done_callback)); gfx::NativeWindow parent_window =
constrained_window::ShowWebModalDialogViews(dialog.release(), web_contents) web_contents ? web_contents->GetTopLevelNativeWindow() : nullptr;
->Show(); views::Widget* widget =
parent_window ? constrained_window::CreateBrowserModalDialogViews(
dialog.release(), parent_window)
: views::DialogDelegate::CreateDialogWidget(
dialog.release(), nullptr, nullptr);
widget->Show();
} }
} // namespace chrome } // namespace chrome
...@@ -51,7 +56,6 @@ ExtensionInstallBlockedByParentDialogView:: ...@@ -51,7 +56,6 @@ ExtensionInstallBlockedByParentDialogView::
ExtensionInstallBlockedByParentDialogView( ExtensionInstallBlockedByParentDialogView(
chrome::ExtensionInstalledBlockedByParentDialogAction action, chrome::ExtensionInstalledBlockedByParentDialogAction action,
const extensions::Extension* extension, const extensions::Extension* extension,
gfx::NativeWindow window,
base::OnceClosure done_callback) base::OnceClosure done_callback)
: extension_(extension), : extension_(extension),
action_(action), action_(action),
...@@ -83,7 +87,7 @@ gfx::Size ExtensionInstallBlockedByParentDialogView::CalculatePreferredSize() ...@@ -83,7 +87,7 @@ gfx::Size ExtensionInstallBlockedByParentDialogView::CalculatePreferredSize()
} }
ui::ModalType ExtensionInstallBlockedByParentDialogView::GetModalType() const { ui::ModalType ExtensionInstallBlockedByParentDialogView::GetModalType() const {
return ui::MODAL_TYPE_CHILD; return ui::MODAL_TYPE_WINDOW;
} }
void ExtensionInstallBlockedByParentDialogView::ConfigureTitle() { void ExtensionInstallBlockedByParentDialogView::ConfigureTitle() {
......
...@@ -31,7 +31,6 @@ class ExtensionInstallBlockedByParentDialogView ...@@ -31,7 +31,6 @@ class ExtensionInstallBlockedByParentDialogView
ExtensionInstallBlockedByParentDialogView( ExtensionInstallBlockedByParentDialogView(
chrome::ExtensionInstalledBlockedByParentDialogAction action, chrome::ExtensionInstalledBlockedByParentDialogAction action,
const extensions::Extension* extension, const extensions::Extension* extension,
gfx::NativeWindow window,
base::OnceClosure done_callback); base::OnceClosure done_callback);
ExtensionInstallBlockedByParentDialogView( ExtensionInstallBlockedByParentDialogView(
const ExtensionInstallBlockedByParentDialogView&) = delete; const ExtensionInstallBlockedByParentDialogView&) = delete;
......
...@@ -28,17 +28,17 @@ ...@@ -28,17 +28,17 @@
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/image_loader.h" #include "extensions/browser/image_loader.h"
#include "extensions/common/constants.h" #include "extensions/common/constants.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h" #include "extensions/common/extension_icon_set.h"
#include "extensions/common/manifest.h" #include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/permissions/permission_set.h" #include "extensions/common/permissions/permission_set.h"
#include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_constants.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_types.h" #include "ui/base/ui_base_types.h"
...@@ -257,12 +257,9 @@ struct ParentPermissionDialogView::Params { ...@@ -257,12 +257,9 @@ struct ParentPermissionDialogView::Params {
// The user's profile // The user's profile
Profile* profile = nullptr; Profile* profile = nullptr;
// The parent window to this window. // The parent window to this window. This member may be nullptr.
gfx::NativeWindow window = nullptr; gfx::NativeWindow window = nullptr;
// The web contents that initiated the dialog.
content::WebContents* web_contents = nullptr;
// The callback to call on completion. // The callback to call on completion.
ParentPermissionDialog::DoneCallback done_callback; ParentPermissionDialog::DoneCallback done_callback;
}; };
...@@ -530,7 +527,10 @@ void ParentPermissionDialogView::ShowDialogInternal() { ...@@ -530,7 +527,10 @@ void ParentPermissionDialogView::ShowDialogInternal() {
CreateContents(); CreateContents();
chrome::RecordDialogCreation(chrome::DialogIdentifier::PARENT_PERMISSION); chrome::RecordDialogCreation(chrome::DialogIdentifier::PARENT_PERMISSION);
views::Widget* widget = views::Widget* widget =
constrained_window::CreateBrowserModalDialogViews(this, params_->window); params_->window
? constrained_window::CreateBrowserModalDialogViews(this,
params_->window)
: views::DialogDelegate::CreateDialogWidget(this, nullptr, nullptr);
widget->Show(); widget->Show();
if (test_view_observer) if (test_view_observer)
...@@ -581,23 +581,15 @@ void ParentPermissionDialogView::OnExtensionIconLoaded( ...@@ -581,23 +581,15 @@ void ParentPermissionDialogView::OnExtensionIconLoaded(
void ParentPermissionDialogView::LoadExtensionIcon() { void ParentPermissionDialogView::LoadExtensionIcon() {
DCHECK(params_->extension); DCHECK(params_->extension);
extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
params_->extension, extension_misc::EXTENSION_ICON_LARGE,
ExtensionIconSet::MATCH_BIGGER);
// Load the image asynchronously. The response will be sent to // Load the image asynchronously. The response will be sent to
// OnExtensionIconLoaded. // OnExtensionIconLoaded.
extensions::ImageLoader* loader = extensions::ImageLoader* loader =
extensions::ImageLoader::Get(params_->profile); extensions::ImageLoader::Get(params_->profile);
loader->LoadImageAtEveryScaleFactorAsync(
std::vector<extensions::ImageLoader::ImageRepresentation> images_list; params_->extension,
images_list.push_back(extensions::ImageLoader::ImageRepresentation( gfx::Size(extension_misc::EXTENSION_ICON_LARGE,
image, extensions::ImageLoader::ImageRepresentation::NEVER_RESIZE, extension_misc::EXTENSION_ICON_LARGE),
gfx::Size(),
ui::GetScaleFactorForNativeView(params_->web_contents->GetNativeView())));
loader->LoadImagesAsync(
params_->extension, images_list,
base::BindOnce(&ParentPermissionDialogView::OnExtensionIconLoaded, base::BindOnce(&ParentPermissionDialogView::OnExtensionIconLoaded,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
...@@ -808,7 +800,6 @@ void ParentPermissionDialogImpl::OnParentPermissionDialogViewDestroyed() { ...@@ -808,7 +800,6 @@ void ParentPermissionDialogImpl::OnParentPermissionDialogViewDestroyed() {
std::unique_ptr<ParentPermissionDialog> std::unique_ptr<ParentPermissionDialog>
ParentPermissionDialog::CreateParentPermissionDialog( ParentPermissionDialog::CreateParentPermissionDialog(
Profile* profile, Profile* profile,
content::WebContents* web_contents,
gfx::NativeWindow window, gfx::NativeWindow window,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const base::string16& message, const base::string16& message,
...@@ -817,7 +808,6 @@ ParentPermissionDialog::CreateParentPermissionDialog( ...@@ -817,7 +808,6 @@ ParentPermissionDialog::CreateParentPermissionDialog(
params->message = message; params->message = message;
params->icon = icon; params->icon = icon;
params->profile = profile; params->profile = profile;
params->web_contents = web_contents;
params->window = window; params->window = window;
params->done_callback = std::move(done_callback); params->done_callback = std::move(done_callback);
...@@ -828,7 +818,6 @@ ParentPermissionDialog::CreateParentPermissionDialog( ...@@ -828,7 +818,6 @@ ParentPermissionDialog::CreateParentPermissionDialog(
std::unique_ptr<ParentPermissionDialog> std::unique_ptr<ParentPermissionDialog>
ParentPermissionDialog::CreateParentPermissionDialogForExtension( ParentPermissionDialog::CreateParentPermissionDialogForExtension(
Profile* profile, Profile* profile,
content::WebContents* web_contents,
gfx::NativeWindow window, gfx::NativeWindow window,
const gfx::ImageSkia& icon, const gfx::ImageSkia& icon,
const extensions::Extension* extension, const extensions::Extension* extension,
...@@ -837,7 +826,6 @@ ParentPermissionDialog::CreateParentPermissionDialogForExtension( ...@@ -837,7 +826,6 @@ ParentPermissionDialog::CreateParentPermissionDialogForExtension(
params->extension = extension; params->extension = extension;
params->icon = icon; params->icon = icon;
params->profile = profile; params->profile = profile;
params->web_contents = web_contents;
params->window = window; params->window = window;
params->done_callback = std::move(done_callback); params->done_callback = std::move(done_callback);
......
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
#include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_auth_consumer.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/window/dialog_delegate.h"
class GaiaAuthFetcher; class GaiaAuthFetcher;
...@@ -41,7 +41,7 @@ class ParentPermissionInputSection; ...@@ -41,7 +41,7 @@ class ParentPermissionInputSection;
// asking them to enter their google account credentials. This is created only // asking them to enter their google account credentials. This is created only
// when the dialog is ready to be shown (after the state has been // when the dialog is ready to be shown (after the state has been
// asynchronously fetched). // asynchronously fetched).
class ParentPermissionDialogView : public views::BubbleDialogDelegateView, class ParentPermissionDialogView : public views::DialogDelegateView,
public GaiaAuthConsumer { public GaiaAuthConsumer {
public: public:
class Observer { class Observer {
......
...@@ -1232,6 +1232,8 @@ if (!is_android) { ...@@ -1232,6 +1232,8 @@ if (!is_android) {
"../browser/ui/extensions/application_launch_browsertest.cc", "../browser/ui/extensions/application_launch_browsertest.cc",
"../browser/ui/extensions/blocked_action_bubble_browsertest.cc", "../browser/ui/extensions/blocked_action_bubble_browsertest.cc",
"../browser/ui/extensions/extension_enable_flow_browsertest.cc", "../browser/ui/extensions/extension_enable_flow_browsertest.cc",
"../browser/ui/extensions/extension_enable_flow_test_delegate.cc",
"../browser/ui/extensions/extension_enable_flow_test_delegate.h",
"../browser/ui/extensions/extension_message_bubble_browsertest.cc", "../browser/ui/extensions/extension_message_bubble_browsertest.cc",
"../browser/ui/extensions/extension_message_bubble_browsertest.h", "../browser/ui/extensions/extension_message_bubble_browsertest.h",
"../browser/ui/extensions/hosted_app_browsertest.cc", "../browser/ui/extensions/hosted_app_browsertest.cc",
......
...@@ -82,7 +82,9 @@ views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog, ...@@ -82,7 +82,9 @@ views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
// ui::MODAL_TYPE_SYSTEM or ui::MODAL_TYPE_WINDOW. This places the dialog // ui::MODAL_TYPE_SYSTEM or ui::MODAL_TYPE_WINDOW. This places the dialog
// appropriately if |parent| is a valid browser window. Currently, |parent| may // appropriately if |parent| is a valid browser window. Currently, |parent| may
// be null for MODAL_TYPE_WINDOW, but that's a bug and callers shouldn't rely on // be null for MODAL_TYPE_WINDOW, but that's a bug and callers shouldn't rely on
// that working. See http://crbug.com/657293. // that working. See http://crbug.com/657293. Instead of calling this function
// with null |parent| and MODAL_TYPE_WINDOW, consider calling views::
// DialogDelegate::CreateDialogWidget(dialog, nullptr, nullptr) instead.
// For dialogs that may appear without direct user interaction (i.e., that may // For dialogs that may appear without direct user interaction (i.e., that may
// appear while a user is busily accomplishing some other task in the browser), // appear while a user is busily accomplishing some other task in the browser),
// consider providing an override of GetDefaultDialogButton on |dialog| to // consider providing an override of GetDefaultDialogButton on |dialog| to
......
...@@ -48,11 +48,6 @@ ...@@ -48,11 +48,6 @@
#include "url/gurl.h" #include "url/gurl.h"
#include "url/url_constants.h" #include "url/url_constants.h"
#if defined(OS_CHROMEOS)
#include "components/web_modal/web_contents_modal_dialog_manager.h"
#include "content/public/browser/web_contents.h"
#endif
using content::BrowserThread; using content::BrowserThread;
namespace keys = extension_management_api_constants; namespace keys = extension_management_api_constants;
...@@ -436,53 +431,42 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() { ...@@ -436,53 +431,42 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
bool should_enable = params->enabled; bool should_enable = params->enabled;
const SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate =
ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetSupervisedUserExtensionsDelegate();
const bool is_supervised_child_who_may_install_extensions =
supervised_user_extensions_delegate
? supervised_user_extensions_delegate
->IsSupervisedChildWhoMayInstallExtensions(browser_context())
: false;
const ManagementPolicy* policy = const ManagementPolicy* policy =
ExtensionSystem::Get(browser_context())->management_policy(); ExtensionSystem::Get(browser_context())->management_policy();
if (!policy->ExtensionMayModifySettings(extension(), target_extension, if (!policy->ExtensionMayModifySettings(extension(), target_extension,
nullptr)) { nullptr)) {
return RespondNow(Error(keys::kUserCantModifyError, extension_id_)); return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
} }
disable_reason::DisableReason reason = disable_reason::DISABLE_NONE; SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate =
bool disallow_enable = ManagementAPI::GetFactoryInstance()
should_enable && ->Get(browser_context())
policy->MustRemainDisabled(target_extension, &reason, nullptr); ->GetSupervisedUserExtensionsDelegate();
if (supervised_user_extensions_delegate &&
// Figure out if we should prompt for parental approval. supervised_user_extensions_delegate->IsChild(browser_context()) &&
bool prompt_parent_for_approval = // Don't prompt the user if the extension has unsupported requirements.
disallow_enable && is_supervised_child_who_may_install_extensions && // TODO(crbug/1071978): If OnRequirementsChecked() passes, the extension
reason == disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED; // will enable, bypassing parent approval.
!HasUnsupportedRequirements(extension_id_) &&
// If the extension can't be enabled, only continue if we plan to prompt for // Only ask for parent approval if the extension still requires approval.
// parental approval. For any child or other type of managed user, if !supervised_user_extensions_delegate->IsExtensionAllowedByParent(
// extension installation has been blocked, we stop the enabling of the *target_extension, browser_context())) {
// extension here. // Either ask for parent permission or notify the child that their parent
if (disallow_enable && !prompt_parent_for_approval) { // has disabled this action.
LOG(ERROR) << "ManagementSetEnabledFunction::Run: extension may not be " auto parent_permission_callback = base::BindOnce(
"enabled, and we're not prompting for parent approval"; &ManagementSetEnabledFunction::OnParentPermissionDialogDone, this);
auto error_callback = base::BindOnce(
&ManagementSetEnabledFunction::OnBlockedByParentDialogDone, this);
AddRef(); // Matched in OnParentPermissionDialogDone() or
// OnBlockedByParentDialogDone().
supervised_user_extensions_delegate->PromptForParentPermissionOrShowError(
*target_extension, browser_context(), GetSenderWebContents(),
std::move(parent_permission_callback), std::move(error_callback));
return RespondLater();
}
#if defined(OS_CHROMEOS) if (should_enable &&
// On ChromeOS, if this is a child, show the dialog indicating that enabling policy->MustRemainDisabled(target_extension, nullptr, nullptr)) {
// extensions has been blocked by a parent.
if (supervised_user_extensions_delegate &&
supervised_user_extensions_delegate->IsChild(browser_context())) {
AddRef(); // Matched in OnBlockedByParentDialogDone().
ShowBlockedByParentDialog(target_extension);
return RespondLater();
}
#endif
return RespondNow(Error(keys::kUserCantModifyError, extension_id_)); return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
} }
...@@ -492,8 +476,7 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() { ...@@ -492,8 +476,7 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
if (!currently_enabled && should_enable) { if (!currently_enabled && should_enable) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context()); ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
if (!prompt_parent_for_approval && if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
prefs->DidExtensionEscalatePermissions(extension_id_)) {
if (!user_gesture()) if (!user_gesture())
return RespondNow(Error(keys::kGestureNeededForEscalationError)); return RespondNow(Error(keys::kGestureNeededForEscalationError));
...@@ -503,8 +486,7 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() { ...@@ -503,8 +486,7 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
base::Bind(&ManagementSetEnabledFunction::OnInstallPromptDone, this)); base::Bind(&ManagementSetEnabledFunction::OnInstallPromptDone, this));
return RespondLater(); return RespondLater();
} }
if (prefs->GetDisableReasons(extension_id_) & if (HasUnsupportedRequirements(extension_id_)) {
disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT) {
// Recheck the requirements. // Recheck the requirements.
requirements_checker_ = requirements_checker_ =
std::make_unique<RequirementsChecker>(target_extension); std::make_unique<RequirementsChecker>(target_extension);
...@@ -513,18 +495,6 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() { ...@@ -513,18 +495,6 @@ ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
this)); // This bind creates a reference. this)); // This bind creates a reference.
return RespondLater(); return RespondLater();
} }
// Handle parental approval for child accounts that have the ability to
// install extensions.
if (prompt_parent_for_approval &&
// Don't re-prompt the parent for extensions that have already been
// approved for a child.
!supervised_user_extensions_delegate->IsExtensionAllowedByParent(
*target_extension, browser_context())) {
LOG(ERROR) << "ManagementSetEnabledFunction::Run: prompting for parent "
"approval";
return RequestParentPermission(target_extension);
}
delegate->EnableExtension(browser_context(), extension_id_); delegate->EnableExtension(browser_context(), extension_id_);
} else if (currently_enabled && !params->enabled) { } else if (currently_enabled && !params->enabled) {
delegate->DisableExtension( delegate->DisableExtension(
...@@ -551,6 +521,13 @@ void ManagementSetEnabledFunction::OnInstallPromptDone(bool did_accept) { ...@@ -551,6 +521,13 @@ void ManagementSetEnabledFunction::OnInstallPromptDone(bool did_accept) {
Release(); // Balanced in Run(). Release(); // Balanced in Run().
} }
bool ManagementSetEnabledFunction::HasUnsupportedRequirements(
const std::string& extension_id) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
return prefs->GetDisableReasons(extension_id) &
disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT;
}
void ManagementSetEnabledFunction::OnRequirementsChecked( void ManagementSetEnabledFunction::OnRequirementsChecked(
const PreloadCheck::Errors& errors) { const PreloadCheck::Errors& errors) {
if (errors.empty()) { if (errors.empty()) {
...@@ -564,28 +541,9 @@ void ManagementSetEnabledFunction::OnRequirementsChecked( ...@@ -564,28 +541,9 @@ void ManagementSetEnabledFunction::OnRequirementsChecked(
} }
} }
ExtensionFunction::ResponseAction void ManagementSetEnabledFunction::OnParentPermissionDialogDone(
ManagementSetEnabledFunction::RequestParentPermission(
const Extension* extension) {
content::WebContents* web_contents = GetSenderWebContents();
if (!web_contents)
return RespondNow(Error(keys::kWebContentsDisappearedError));
// Show parental approval prompt.
auto callback = base::BindOnce(
&ManagementSetEnabledFunction::OnParentPermissionDone, this);
SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate =
ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetSupervisedUserExtensionsDelegate();
DCHECK(supervised_user_extensions_delegate);
supervised_user_extensions_delegate->ShowParentPermissionDialogForExtension(
*extension, browser_context(), web_contents, std::move(callback));
return RespondLater();
}
void ManagementSetEnabledFunction::OnParentPermissionDone(
SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result) { SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result) {
#if defined(OS_CHROMEOS)
switch (result) { switch (result) {
case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult:: case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult::
kParentPermissionReceived: { kParentPermissionReceived: {
...@@ -610,37 +568,9 @@ void ManagementSetEnabledFunction::OnParentPermissionDone( ...@@ -610,37 +568,9 @@ void ManagementSetEnabledFunction::OnParentPermissionDone(
break; break;
} }
} }
} // Matches the AddRef in Run().
Release();
void ManagementSetEnabledFunction::ShowBlockedByParentDialog( #endif // defined(OS_CHROMEOS)
const Extension* extension) {
#if defined(OS_CHROMEOS)
DCHECK(extension);
SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate =
ManagementAPI::GetFactoryInstance()
->Get(browser_context())
->GetSupervisedUserExtensionsDelegate();
supervised_user_extensions_delegate
->RecordExtensionEnableBlockedByParentDialogUmaMetric();
content::WebContents* contents = GetSenderWebContents();
web_modal::WebContentsModalDialogManager* manager =
web_modal::WebContentsModalDialogManager::FromWebContents(contents);
if (!contents || !contents->GetTopLevelNativeWindow() || !manager) {
// If the contents are null, or there is no top level native window to
// anchor the dialog on, or no dialog manager, skip showing the dialog and
// return the error immediately.
OnBlockedByParentDialogDone();
return;
}
supervised_user_extensions_delegate
->ShowExtensionEnableBlockedByParentDialogForExtension(
extension, contents,
base::BindOnce(
&ManagementSetEnabledFunction::OnBlockedByParentDialogDone,
this));
#endif
} }
void ManagementSetEnabledFunction::OnBlockedByParentDialogDone() { void ManagementSetEnabledFunction::OnBlockedByParentDialogDone() {
...@@ -648,7 +578,7 @@ void ManagementSetEnabledFunction::OnBlockedByParentDialogDone() { ...@@ -648,7 +578,7 @@ void ManagementSetEnabledFunction::OnBlockedByParentDialogDone() {
Respond(Error(keys::kUserCantModifyError, extension_id_)); Respond(Error(keys::kUserCantModifyError, extension_id_));
// Matches the AddRef in Run(). // Matches the AddRef in Run().
Release(); Release();
#endif #endif // defined(OS_CHROMEOS)
} }
ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() = default; ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() = default;
......
...@@ -115,25 +115,18 @@ class ManagementSetEnabledFunction : public ExtensionFunction { ...@@ -115,25 +115,18 @@ class ManagementSetEnabledFunction : public ExtensionFunction {
private: private:
void OnInstallPromptDone(bool did_accept); void OnInstallPromptDone(bool did_accept);
void OnRequirementsChecked(const PreloadCheck::Errors& errors); bool HasUnsupportedRequirements(const std::string& extension_id);
ExtensionFunction::ResponseAction RequestParentPermission( void OnRequirementsChecked(const PreloadCheck::Errors& errors);
const Extension* extension);
void OnParentPermissionDone( // Called when the user dismisses the Parent Permission Dialog.
void OnParentPermissionDialogDone(
SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result); SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result);
// Shows the dialog that tells the user that the parent has blocked the // Called when the user dismisses the Extension Install Blocked By Parent
// installation of extensions, apps, etc. // Dialog.
void ShowBlockedByParentDialog(const Extension* extension);
// Called when the dialog shown by ShowBlockedByParentDialog() is dismissed.
void OnBlockedByParentDialogDone(); void OnBlockedByParentDialogDone();
std::unique_ptr<
SupervisedUserExtensionsDelegate::ParentPermissionDialogResult>
parental_permission_dialog_;
std::string extension_id_; std::string extension_id_;
std::unique_ptr<InstallPromptDelegate> install_prompt_; std::unique_ptr<InstallPromptDelegate> install_prompt_;
......
...@@ -63,8 +63,6 @@ const char kInstallReplacementAndroidAppNotFromWebstoreError[] = ...@@ -63,8 +63,6 @@ const char kInstallReplacementAndroidAppNotFromWebstoreError[] =
"Only extensions from the web store can install replacement Android apps."; "Only extensions from the web store can install replacement Android apps.";
const char kInstallReplacementAndroidAppCannotInstallApp[] = const char kInstallReplacementAndroidAppCannotInstallApp[] =
"Could not install Android App."; "Could not install Android App.";
const char kWebContentsDisappearedError[] =
"Web contents disappeared while attempting to enable extension.";
const char kParentPermissionFailedError[] = "Parent Permission Request Failed."; const char kParentPermissionFailedError[] = "Parent Permission Request Failed.";
} // namespace extension_management_api_constants } // namespace extension_management_api_constants
...@@ -44,7 +44,6 @@ extern const char kGestureNeededForInstallReplacementAndroidAppError[]; ...@@ -44,7 +44,6 @@ extern const char kGestureNeededForInstallReplacementAndroidAppError[];
extern const char kInstallReplacementAndroidAppCannotInstallApp[]; extern const char kInstallReplacementAndroidAppCannotInstallApp[];
extern const char kInstallReplacementAndroidAppInvalidContextError[]; extern const char kInstallReplacementAndroidAppInvalidContextError[];
extern const char kInstallReplacementAndroidAppNotFromWebstoreError[]; extern const char kInstallReplacementAndroidAppNotFromWebstoreError[];
extern const char kWebContentsDisappearedError[];
extern const char kParentPermissionFailedError[]; extern const char kParentPermissionFailedError[];
} // namespace extension_management_api_constants } // namespace extension_management_api_constants
......
...@@ -17,22 +17,6 @@ namespace extensions { ...@@ -17,22 +17,6 @@ namespace extensions {
class SupervisedUserExtensionsDelegate { class SupervisedUserExtensionsDelegate {
public: public:
virtual ~SupervisedUserExtensionsDelegate() = default;
// Returns true if |context| represents a supervised child account.
virtual bool IsChild(content::BrowserContext* context) const = 0;
// Returns true if |context| represents a supervised child account
// who may install extensions with parent permission.
virtual bool IsSupervisedChildWhoMayInstallExtensions(
content::BrowserContext* context) const = 0;
// Returns true if the current child user is allowed to install the specified
// |extension|.
virtual bool IsExtensionAllowedByParent(
const extensions::Extension& extension,
content::BrowserContext* context) const = 0;
// Result of the parent permission dialog invocation. // Result of the parent permission dialog invocation.
enum class ParentPermissionDialogResult { enum class ParentPermissionDialogResult {
kParentPermissionReceived, kParentPermissionReceived,
...@@ -43,24 +27,29 @@ class SupervisedUserExtensionsDelegate { ...@@ -43,24 +27,29 @@ class SupervisedUserExtensionsDelegate {
using ParentPermissionDialogDoneCallback = using ParentPermissionDialogDoneCallback =
base::OnceCallback<void(ParentPermissionDialogResult)>; base::OnceCallback<void(ParentPermissionDialogResult)>;
// Shows a parent permission dialog for |extension| and call |done_callback| virtual ~SupervisedUserExtensionsDelegate() = default;
// when it completes.
virtual void ShowParentPermissionDialogForExtension( // Returns true if |context| represents a supervised child account.
const extensions::Extension& extension, virtual bool IsChild(content::BrowserContext* context) const = 0;
content::BrowserContext* context,
content::WebContents* contents,
ParentPermissionDialogDoneCallback done_callback) = 0;
// Shows a dialog indicating that |extension| has been blocked and call // Returns true if the parent has already approved the |extension|.
// |done_callback| when it completes. virtual bool IsExtensionAllowedByParent(
virtual void ShowExtensionEnableBlockedByParentDialogForExtension( const extensions::Extension& extension,
const extensions::Extension* extension, content::BrowserContext* context) const = 0;
content::WebContents* contents,
base::OnceClosure done_callback) = 0;
// Records UMA metrics for supervised users trying to install or enable an // If the current user is a child, the child user has a custodian/parent, the
// extension when this action is blocked by the parent. // kSupervisedUserInitiatedExtensionInstall feature flag is enabled, and the
virtual void RecordExtensionEnableBlockedByParentDialogUmaMetric() = 0; // parent has enabled the "Permissions for sites, apps and extensions" toggle,
// then display the Parent Permission Dialog and call
// |parent_permission_callback|. Otherwise, display the Extension Install
// Blocked by Parent Dialog and call |error_callback|. The two paths are
// mutually exclusive.
virtual void PromptForParentPermissionOrShowError(
const extensions::Extension& extension,
content::BrowserContext* browser_context,
content::WebContents* web_contents,
ParentPermissionDialogDoneCallback parent_permission_callback,
base::OnceClosure error_callback) = 0;
}; };
} // namespace extensions } // namespace extensions
......
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