Commit 927c9f42 authored by rdevlin.cronin's avatar rdevlin.cronin Committed by Commit bot

[Extensions UI] Update extensions page to use api methods for permissions prompt

Update the chrome://extensions page to use the developerPrivate api in order
to show the permissions prompt.
Also convert the function to a UIThreadExtensionFunction, and update it to
(if possible) use the new app info dialog.

BUG=461039

Review URL: https://codereview.chromium.org/1008973002

Cr-Commit-Position: refs/heads/master@{#320801}
parent 2b7b3c8c
......@@ -4,8 +4,6 @@
#include "chrome/browser/extensions/api/developer_private/developer_private_api.h"
#include "apps/app_load_service.h"
#include "apps/saved_files_service.h"
#include "base/base64.h"
#include "base/bind.h"
#include "base/files/file_util.h"
......@@ -17,6 +15,7 @@
#include "chrome/browser/extensions/api/developer_private/developer_private_mangle.h"
#include "chrome/browser/extensions/api/developer_private/entry_picker.h"
#include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
#include "chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h"
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/devtools_util.h"
#include "chrome/browser/extensions/extension_service.h"
......@@ -39,7 +38,6 @@
#include "content/public/browser/site_instance.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/extension_error.h"
......@@ -88,6 +86,8 @@ const char kNoSuchRendererError[] = "No such renderer.";
const char kInvalidPathError[] = "Invalid path.";
const char kManifestKeyIsRequiredError[] =
"The 'manifestKey' argument is required for manifest files.";
const char kCouldNotFindWebContentsError[] =
"Could not find a valid web contents.";
const char kUnpackedAppsFolder[] = "apps_target";
const char kManifestFile[] = "manifest.json";
......@@ -540,6 +540,8 @@ DeveloperPrivateAllowIncognitoFunction::Run() {
DeveloperPrivateAllowIncognitoFunction::
~DeveloperPrivateAllowIncognitoFunction() {}
DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
ExtensionFunction::ResponseAction DeveloperPrivateReloadFunction::Run() {
scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
......@@ -563,71 +565,39 @@ ExtensionFunction::ResponseAction DeveloperPrivateReloadFunction::Run() {
return RespondNow(NoArguments());
}
bool DeveloperPrivateShowPermissionsDialogFunction::RunSync() {
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
CHECK(!extension_id_.empty());
AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
DCHECK(registry);
AppWindow* app_window =
registry->GetAppWindowForRenderViewHost(render_view_host());
prompt_.reset(new ExtensionInstallPrompt(app_window->web_contents()));
const Extension* extension =
ExtensionRegistry::Get(GetProfile())
->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
DeveloperPrivateShowPermissionsDialogFunction::
DeveloperPrivateShowPermissionsDialogFunction() {}
if (!extension)
return false;
DeveloperPrivateShowPermissionsDialogFunction::
~DeveloperPrivateShowPermissionsDialogFunction() {}
// Released by InstallUIAbort or InstallUIProceed.
AddRef();
std::vector<base::FilePath> retained_file_paths;
if (extension->permissions_data()->HasAPIPermission(
APIPermission::kFileSystem)) {
std::vector<apps::SavedFileEntry> retained_file_entries =
apps::SavedFilesService::Get(GetProfile())
->GetAllFileEntries(extension_id_);
for (size_t i = 0; i < retained_file_entries.size(); i++) {
retained_file_paths.push_back(retained_file_entries[i].path);
}
}
std::vector<base::string16> retained_device_messages;
if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
retained_device_messages =
extensions::DevicePermissionsManager::Get(GetProfile())
->GetPermissionMessageStrings(extension_id_);
}
prompt_->ReviewPermissions(
this, extension, retained_file_paths, retained_device_messages);
return true;
}
ExtensionFunction::ResponseAction
DeveloperPrivateShowPermissionsDialogFunction::Run() {
scoped_ptr<developer::ShowPermissionsDialog::Params> params(
developer::ShowPermissionsDialog::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
const Extension* target_extension = GetExtensionById(params->extension_id);
if (!target_extension)
return RespondNow(Error(kNoSuchExtensionError));
// This is called when the user clicks "Revoke File Access."
void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
Profile* profile = GetProfile();
extensions::DevicePermissionsManager::Get(profile)->Clear(extension_id_);
const Extension* extension = ExtensionRegistry::Get(
profile)->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
apps::SavedFilesService::Get(profile)->ClearQueue(extension);
apps::AppLoadService::Get(profile)
->RestartApplicationIfRunning(extension_id_);
SendResponse(true);
Release();
content::WebContents* web_contents = GetSenderWebContents();
if (!web_contents)
return RespondNow(Error(kCouldNotFindWebContentsError));
ShowPermissionsDialogHelper::Show(
browser_context(),
web_contents,
target_extension,
source_context_type() == Feature::WEBUI_CONTEXT,
base::Bind(&DeveloperPrivateShowPermissionsDialogFunction::Finish, this));
return RespondLater();
}
void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
bool user_initiated) {
SendResponse(true);
Release();
void DeveloperPrivateShowPermissionsDialogFunction::Finish() {
Respond(NoArguments());
}
DeveloperPrivateShowPermissionsDialogFunction::
DeveloperPrivateShowPermissionsDialogFunction() {}
DeveloperPrivateShowPermissionsDialogFunction::
~DeveloperPrivateShowPermissionsDialogFunction() {}
ExtensionFunction::ResponseAction DeveloperPrivateInspectFunction::Run() {
scoped_ptr<developer::Inspect::Params> params(
developer::Inspect::Params::Create(*args_));
......
......@@ -13,7 +13,6 @@
#include "chrome/browser/extensions/api/file_system/file_system_api.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/error_console/error_console.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/extensions/pack_extension_job.h"
#include "content/public/browser/notification_observer.h"
......@@ -278,25 +277,20 @@ class DeveloperPrivateReloadFunction : public DeveloperPrivateAPIFunction {
};
class DeveloperPrivateShowPermissionsDialogFunction
: public ChromeSyncExtensionFunction,
public ExtensionInstallPrompt::Delegate {
: public DeveloperPrivateAPIFunction {
public:
DECLARE_EXTENSION_FUNCTION("developerPrivate.showPermissionsDialog",
DEVELOPERPRIVATE_PERMISSIONS);
DeveloperPrivateShowPermissionsDialogFunction();
protected:
// DeveloperPrivateAPIFunction:
~DeveloperPrivateShowPermissionsDialogFunction() override;
ResponseAction Run() override;
// ExtensionFunction:
bool RunSync() override;
// Overridden from ExtensionInstallPrompt::Delegate
void InstallUIProceed() override;
void InstallUIAbort(bool user_initiated) override;
void Finish();
scoped_ptr<ExtensionInstallPrompt> prompt_;
std::string extension_id_;
DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateShowPermissionsDialogFunction);
};
class DeveloperPrivateChooseEntryFunction : public UIThreadExtensionFunction,
......
// Copyright 2015 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/extensions/api/developer_private/show_permissions_dialog_helper.h"
#include "apps/app_load_service.h"
#include "apps/saved_files_service.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/apps/app_info_dialog.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/api/device_permissions_manager.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/permissions/permissions_data.h"
namespace extensions {
ShowPermissionsDialogHelper::ShowPermissionsDialogHelper(
Profile* profile,
const base::Closure& on_complete)
: profile_(profile),
on_complete_(on_complete) {
}
ShowPermissionsDialogHelper::~ShowPermissionsDialogHelper() {
}
// static
void ShowPermissionsDialogHelper::Show(content::BrowserContext* browser_context,
content::WebContents* web_contents,
const Extension* extension,
bool from_webui,
const base::Closure& on_complete) {
Profile* profile = Profile::FromBrowserContext(browser_context);
// Show the new-style extensions dialog when it is available. It is currently
// unavailable by default on Mac.
if (CanShowAppInfoDialog()) {
if (from_webui) {
UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialog.Launches",
AppInfoLaunchSource::FROM_EXTENSIONS_PAGE,
AppInfoLaunchSource::NUM_LAUNCH_SOURCES);
}
ShowAppInfoInNativeDialog(
web_contents->GetTopLevelNativeWindow(),
GetAppInfoNativeDialogSize(),
profile,
extension,
on_complete);
return; // All done.
}
// ShowPermissionsDialogHelper manages its own lifetime.
ShowPermissionsDialogHelper* helper =
new ShowPermissionsDialogHelper(profile, on_complete);
helper->ShowPermissionsDialog(web_contents, extension);
}
void ShowPermissionsDialogHelper::ShowPermissionsDialog(
content::WebContents* web_contents,
const Extension* extension) {
extension_id_ = extension->id();
prompt_.reset(new ExtensionInstallPrompt(web_contents));
std::vector<base::FilePath> retained_file_paths;
if (extension->permissions_data()->HasAPIPermission(
APIPermission::kFileSystem)) {
std::vector<apps::SavedFileEntry> retained_file_entries =
apps::SavedFilesService::Get(profile_)
->GetAllFileEntries(extension_id_);
for (const apps::SavedFileEntry& entry : retained_file_entries)
retained_file_paths.push_back(entry.path);
}
std::vector<base::string16> retained_device_messages;
if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
retained_device_messages =
DevicePermissionsManager::Get(profile_)
->GetPermissionMessageStrings(extension_id_);
}
prompt_->ReviewPermissions(
this, extension, retained_file_paths, retained_device_messages);
}
// This is called when the user clicks "Revoke File Access."
void ShowPermissionsDialogHelper::InstallUIProceed() {
const Extension* extension =
ExtensionRegistry::Get(profile_)->GetExtensionById(
extension_id_, ExtensionRegistry::EVERYTHING);
if (extension)
apps::SavedFilesService::Get(profile_)->ClearQueue(extension);
apps::AppLoadService::Get(profile_)
->RestartApplicationIfRunning(extension_id_);
on_complete_.Run();
delete this;
}
void ShowPermissionsDialogHelper::InstallUIAbort(bool user_initiated) {
on_complete_.Run();
delete this;
}
} // namespace extensions
// Copyright 2015 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_EXTENSIONS_API_DEVELOPER_PRIVATE_SHOW_PERMISSIONS_DIALOG_HELPER_H_
#define CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_SHOW_PERMISSIONS_DIALOG_HELPER_H_
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
class Profile;
namespace content {
class BrowserContext;
class WebContents;
}
namespace extensions {
class Extension;
// Helper class to handle showing a permissions dialog for an extension. Will
// show either the newer AppInfo-style permissions dialog, or the traditional,
// install-prompt style dialog.
class ShowPermissionsDialogHelper : public ExtensionInstallPrompt::Delegate {
public:
static void Show(content::BrowserContext* browser_context,
content::WebContents* web_contents,
const Extension* extension,
bool from_webui,
const base::Closure& on_complete);
private:
ShowPermissionsDialogHelper(Profile* profile,
const base::Closure& on_complete);
~ShowPermissionsDialogHelper() override; // Manages its own lifetime.
// Shows the old-style (not AppInfo) permissions dialog.
void ShowPermissionsDialog(content::WebContents* web_contents,
const Extension* extension);
// ExtensionInstallPrompt::Delegate:
void InstallUIProceed() override;
void InstallUIAbort(bool user_initiated) override;
scoped_ptr<ExtensionInstallPrompt> prompt_;
Profile* profile_;
base::Closure on_complete_;
std::string extension_id_;
DISALLOW_COPY_AND_ASSIGN(ShowPermissionsDialogHelper);
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_DEVELOPER_PRIVATE_SHOW_PERMISSIONS_DIALOG_HELPER_H_
......@@ -172,11 +172,16 @@ cr.define('extensions', function() {
/**
* Indicates whether an uninstall dialog is being shown to prevent multiple
* dialogs from being displayed.
* @type {boolean}
* @private
* @private {boolean}
*/
uninstallIsShowing_: false,
/**
* Indicates whether a permissions prompt is showing.
* @private {boolean}
*/
permissionsPromptIsShowing_: false,
/**
* Necessary to only show the butterbar once.
* @private {boolean}
......@@ -375,7 +380,13 @@ cr.define('extensions', function() {
// The 'Permissions' link.
row.setupColumn('.permissions-link', 'details', 'click', function(e) {
chrome.send('extensionSettingsPermissions', [extension.id]);
if (!this.permissionsPromptIsShowing_) {
chrome.developerPrivate.showPermissionsDialog(extension.id,
function() {
this.permissionsPromptIsShowing_ = false;
}.bind(this));
this.permissionsPromptIsShowing_ = true;
}
e.preventDefault();
});
......
......@@ -6,8 +6,6 @@
#include <vector>
#include "apps/app_load_service.h"
#include "apps/saved_files_service.h"
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
......@@ -90,45 +88,6 @@ const char kAppsDeveloperToolsExtensionId[] =
namespace extensions {
// The install prompt is not necessarily modal (e.g. Mac, Linux Unity). This
// means that the user can navigate while the dialog is up, causing the dialog
// handler to outlive the ExtensionSettingsHandler. That's a problem because the
// dialog framework will try to contact us back once the dialog is closed, which
// causes a crash. This class is designed to broker the message between the two
// objects, while managing its own lifetime so that it can outlive the
// ExtensionSettingsHandler and (when doing so) gracefully ignore the message
// from the dialog.
class BrokerDelegate : public ExtensionInstallPrompt::Delegate {
public:
explicit BrokerDelegate(
const base::WeakPtr<ExtensionSettingsHandler>& delegate)
: delegate_(delegate) {}
// ExtensionInstallPrompt::Delegate implementation.
void InstallUIProceed() override {
if (delegate_)
delegate_->InstallUIProceed();
delete this;
};
void InstallUIAbort(bool user_initiated) override {
if (delegate_)
delegate_->InstallUIAbort(user_initiated);
delete this;
};
void AppInfoDialogClosed() {
if (delegate_)
delegate_->AppInfoDialogClosed();
delete this;
}
private:
base::WeakPtr<ExtensionSettingsHandler> delegate_;
DISALLOW_COPY_AND_ASSIGN(BrokerDelegate);
};
///////////////////////////////////////////////////////////////////////////////
//
// ExtensionSettingsHandler
......@@ -407,9 +366,6 @@ void ExtensionSettingsHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("extensionSettingsOptions",
base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage,
AsWeakPtr()));
web_ui()->RegisterMessageCallback("extensionSettingsPermissions",
base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage,
AsWeakPtr()));
web_ui()->RegisterMessageCallback("extensionSettingsShowButton",
base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage,
AsWeakPtr()));
......@@ -514,26 +470,6 @@ void ExtensionSettingsHandler::ExtensionWarningsChanged() {
MaybeUpdateAfterNotification();
}
// This is called when the user clicks "Revoke File/Device Access."
void ExtensionSettingsHandler::InstallUIProceed() {
Profile* profile = Profile::FromWebUI(web_ui());
extensions::DevicePermissionsManager::Get(profile)
->Clear(extension_id_prompting_);
apps::SavedFilesService::Get(profile)->ClearQueue(
extension_service_->GetExtensionById(extension_id_prompting_, true));
apps::AppLoadService::Get(profile)
->RestartApplicationIfRunning(extension_id_prompting_);
extension_id_prompting_.clear();
}
void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) {
extension_id_prompting_.clear();
}
void ExtensionSettingsHandler::AppInfoDialogClosed() {
extension_id_prompting_.clear();
}
void ExtensionSettingsHandler::ReloadUnpackedExtensions() {
ExtensionRegistry* registry =
ExtensionRegistry::Get(extension_service_->profile());
......@@ -673,62 +609,6 @@ void ExtensionSettingsHandler::HandleOptionsMessage(
chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
}
void ExtensionSettingsHandler::HandlePermissionsMessage(
const base::ListValue* args) {
std::string extension_id(base::UTF16ToUTF8(ExtractStringValue(args)));
CHECK(!extension_id.empty());
const Extension* extension =
ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))
->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
if (!extension)
return;
if (!extension_id_prompting_.empty())
return; // Only one prompt at a time.
extension_id_prompting_ = extension->id();
// The BrokerDelegate manages its own lifetime.
BrokerDelegate* broker_delegate = new BrokerDelegate(AsWeakPtr());
// Show the new-style extensions dialog when it is available. It is currently
// unavailable by default on Mac.
if (CanShowAppInfoDialog()) {
UMA_HISTOGRAM_ENUMERATION("Apps.AppInfoDialog.Launches",
AppInfoLaunchSource::FROM_EXTENSIONS_PAGE,
AppInfoLaunchSource::NUM_LAUNCH_SOURCES);
// Display the dialog at a size similar to the app list.
ShowAppInfoInNativeDialog(
web_contents()->GetTopLevelNativeWindow(),
GetAppInfoNativeDialogSize(),
Profile::FromWebUI(web_ui()), extension,
base::Bind(&BrokerDelegate::AppInfoDialogClosed,
base::Unretained(broker_delegate)));
} else {
prompt_.reset(new ExtensionInstallPrompt(web_contents()));
std::vector<base::FilePath> retained_file_paths;
if (extension->permissions_data()->HasAPIPermission(
APIPermission::kFileSystem)) {
std::vector<apps::SavedFileEntry> retained_file_entries =
apps::SavedFilesService::Get(Profile::FromWebUI(web_ui()))
->GetAllFileEntries(extension_id_prompting_);
for (size_t i = 0; i < retained_file_entries.size(); ++i) {
retained_file_paths.push_back(retained_file_entries[i].path);
}
}
std::vector<base::string16> retained_device_messages;
if (extension->permissions_data()->HasAPIPermission(APIPermission::kUsb)) {
retained_device_messages =
extensions::DevicePermissionsManager::Get(
Profile::FromWebUI(web_ui()))
->GetPermissionMessageStrings(extension_id_prompting_);
}
prompt_->ReviewPermissions(broker_delegate, extension, retained_file_paths,
retained_device_messages);
}
}
void ExtensionSettingsHandler::HandleShowButtonMessage(
const base::ListValue* args) {
const Extension* extension = GetActiveExtension(args);
......
......@@ -9,9 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/scoped_observer.h"
#include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h"
#include "chrome/browser/extensions/error_console/error_console.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/common/extensions/webstore_install_result.h"
#include "content/public/browser/navigation_controller.h"
......@@ -50,7 +48,6 @@ class ExtensionSettingsHandler
public content::NotificationObserver,
public content::WebContentsObserver,
public ErrorConsole::Observer,
public ExtensionInstallPrompt::Delegate,
public ExtensionManagement::Observer,
public ExtensionPrefsObserver,
public ExtensionRegistryObserver,
......@@ -65,8 +62,6 @@ class ExtensionSettingsHandler
void GetLocalizedValues(content::WebUIDataSource* source);
private:
friend class BrokerDelegate;
// content::WebContentsObserver implementation.
void RenderViewDeleted(content::RenderViewHost* render_view_host) override;
void DidStartNavigationToPendingEntry(
......@@ -104,13 +99,6 @@ class ExtensionSettingsHandler
// WarningService::Observer implementation.
void ExtensionWarningsChanged() override;
// ExtensionInstallPrompt::Delegate implementation.
void InstallUIProceed() override;
void InstallUIAbort(bool user_initiated) override;
// Called after the App Info Dialog has closed.
virtual void AppInfoDialogClosed();
// Helper method that reloads all unpacked extensions.
void ReloadUnpackedExtensions();
......@@ -168,9 +156,6 @@ class ExtensionSettingsHandler
// Our model. Outlives us since it's owned by our containing profile.
ExtensionService* extension_service_;
// The id of the extension we are prompting the user about.
std::string extension_id_prompting_;
// If true, we will ignore notifications in ::Observe(). This is needed
// to prevent reloading the page when we were the cause of the
// notification.
......@@ -194,9 +179,6 @@ class ExtensionSettingsHandler
content::NotificationRegistrar registrar_;
// The UI for showing what permissions the extension has.
scoped_ptr<ExtensionInstallPrompt> prompt_;
ScopedObserver<WarningService, WarningService::Observer>
warning_service_observer_;
......
......@@ -192,6 +192,8 @@
'browser/extensions/api/declarative_content/content_constants.h',
'browser/extensions/api/desktop_capture/desktop_capture_api.cc',
'browser/extensions/api/desktop_capture/desktop_capture_api.h',
'browser/extensions/api/developer_private/show_permissions_dialog_helper.cc',
'browser/extensions/api/developer_private/show_permissions_dialog_helper.h',
'browser/extensions/api/developer_private/developer_private_api.cc',
'browser/extensions/api/developer_private/developer_private_api.h',
'browser/extensions/api/developer_private/developer_private_mangle.cc',
......
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