blob: 189692a323520cfecbfe0a65fc66b023cbe8ec58 [file] [log] [blame]
// Copyright (c) 2012 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/management/management_api.h"
#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/management/management_api_constants.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_ui_util.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/extensions/launch_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/extensions/api/management.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/features/feature_channel.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_icon_set.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/url_pattern.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
#endif
using base::IntToString;
using content::BrowserThread;
using content::UtilityProcessHost;
using content::UtilityProcessHostClient;
namespace keys = extension_management_api_constants;
namespace extensions {
namespace management = api::management;
namespace {
typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList;
typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList;
enum AutoConfirmForTest {
DO_NOT_SKIP = 0,
PROCEED,
ABORT
};
AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
std::vector<std::string> CreateWarningsList(const Extension* extension) {
std::vector<std::string> warnings_list;
PermissionMessages warnings =
PermissionsData::GetPermissionMessages(extension);
for (PermissionMessages::const_iterator iter = warnings.begin();
iter != warnings.end(); ++iter) {
warnings_list.push_back(base::UTF16ToUTF8(iter->message()));
}
return warnings_list;
}
std::vector<management::LaunchType> GetAvailableLaunchTypes(
const Extension& extension) {
std::vector<management::LaunchType> launch_type_list;
if (extension.is_platform_app()) {
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
return launch_type_list;
}
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
#if !defined(OS_MACOSX)
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
#endif
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableStreamlinedHostedApps)) {
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB);
launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN);
}
return launch_type_list;
}
scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
const Extension& extension,
ExtensionSystem* system) {
scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo());
ExtensionService* service = system->extension_service();
info->id = extension.id();
info->name = extension.name();
info->short_name = extension.short_name();
info->enabled = service->IsExtensionEnabled(info->id);
info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
info->version = extension.VersionString();
info->description = extension.description();
info->options_url = ManifestURL::GetOptionsPage(&extension).spec();
info->homepage_url.reset(new std::string(
ManifestURL::GetHomepageURL(&extension).spec()));
info->may_disable = system->management_policy()->
UserMayModifySettings(&extension, NULL);
info->is_app = extension.is_app();
if (info->is_app) {
if (extension.is_legacy_packaged_app())
info->type = management::ExtensionInfo::TYPE_LEGACY_PACKAGED_APP;
else if (extension.is_hosted_app())
info->type = management::ExtensionInfo::TYPE_HOSTED_APP;
else
info->type = management::ExtensionInfo::TYPE_PACKAGED_APP;
} else if (extension.is_theme()) {
info->type = management::ExtensionInfo::TYPE_THEME;
} else {
info->type = management::ExtensionInfo::TYPE_EXTENSION;
}
if (info->enabled) {
info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE;
} else {
ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
if (prefs->DidExtensionEscalatePermissions(extension.id())) {
info->disabled_reason =
management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE;
} else {
info->disabled_reason =
management::ExtensionInfo::DISABLED_REASON_UNKNOWN;
}
}
if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
info->update_url.reset(new std::string(
ManifestURL::GetUpdateURL(&extension).spec()));
}
if (extension.is_app()) {
info->app_launch_url.reset(new std::string(
AppLaunchInfo::GetFullLaunchURL(&extension).spec()));
}
const ExtensionIconSet::IconMap& icons =
IconsInfo::GetIcons(&extension).map();
if (!icons.empty()) {
info->icons.reset(new IconInfoList());
ExtensionIconSet::IconMap::const_iterator icon_iter;
for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
management::IconInfo* icon_info = new management::IconInfo();
icon_info->size = icon_iter->first;
GURL url = ExtensionIconSource::GetIconURL(
&extension, icon_info->size, ExtensionIconSet::MATCH_EXACTLY, false,
NULL);
icon_info->url = url.spec();
info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info));
}
}
const std::set<std::string> perms =
extension.GetActivePermissions()->GetAPIsAsStrings();
if (!perms.empty()) {
std::set<std::string>::const_iterator perms_iter;
for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
info->permissions.push_back(*perms_iter);
}
if (!extension.is_hosted_app()) {
// Skip host permissions for hosted apps.
const URLPatternSet host_perms =
extension.GetActivePermissions()->explicit_hosts();
if (!host_perms.is_empty()) {
for (URLPatternSet::const_iterator iter = host_perms.begin();
iter != host_perms.end(); ++iter) {
info->host_permissions.push_back(iter->GetAsString());
}
}
}
switch (extension.location()) {
case Manifest::INTERNAL:
info->install_type = management::ExtensionInfo::INSTALL_TYPE_NORMAL;
break;
case Manifest::UNPACKED:
case Manifest::COMMAND_LINE:
info->install_type = management::ExtensionInfo::INSTALL_TYPE_DEVELOPMENT;
break;
case Manifest::EXTERNAL_PREF:
case Manifest::EXTERNAL_REGISTRY:
case Manifest::EXTERNAL_PREF_DOWNLOAD:
info->install_type = management::ExtensionInfo::INSTALL_TYPE_SIDELOAD;
break;
case Manifest::EXTERNAL_POLICY:
case Manifest::EXTERNAL_POLICY_DOWNLOAD:
info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN;
break;
case Manifest::NUM_LOCATIONS:
NOTREACHED();
case Manifest::INVALID_LOCATION:
case Manifest::COMPONENT:
case Manifest::EXTERNAL_COMPONENT:
info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER;
break;
}
info->launch_type = management::LAUNCH_TYPE_NONE;
if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV &&
extension.is_app()) {
LaunchType launch_type;
if (extension.is_platform_app()) {
launch_type = LAUNCH_TYPE_WINDOW;
} else {
launch_type =
GetLaunchType(ExtensionPrefs::Get(service->profile()), &extension);
}
switch (launch_type) {
case LAUNCH_TYPE_PINNED:
info->launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
break;
case LAUNCH_TYPE_REGULAR:
info->launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
break;
case LAUNCH_TYPE_FULLSCREEN:
info->launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
break;
case LAUNCH_TYPE_WINDOW:
info->launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
break;
case LAUNCH_TYPE_INVALID:
case NUM_LAUNCH_TYPES:
NOTREACHED();
}
info->available_launch_types.reset(new std::vector<management::LaunchType>(
GetAvailableLaunchTypes(extension)));
}
return info.Pass();
}
void AddExtensionInfo(const ExtensionSet& extensions,
ExtensionSystem* system,
ExtensionInfoList* extension_list,
content::BrowserContext* context) {
for (ExtensionSet::const_iterator iter = extensions.begin();
iter != extensions.end(); ++iter) {
const Extension& extension = *iter->get();
if (ui_util::ShouldNotBeVisible(&extension, context))
continue; // Skip built-in extensions/apps.
extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
CreateExtensionInfo(extension, system).release()));
}
}
} // namespace
ExtensionService* ManagementFunction::service() {
return GetProfile()->GetExtensionService();
}
ExtensionService* AsyncManagementFunction::service() {
return GetProfile()->GetExtensionService();
}
bool ManagementGetAllFunction::RunSync() {
ExtensionInfoList extensions;
ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
AddExtensionInfo(registry->enabled_extensions(),
system, &extensions, browser_context());
AddExtensionInfo(registry->disabled_extensions(),
system, &extensions, browser_context());
AddExtensionInfo(registry->terminated_extensions(),
system, &extensions, browser_context());
results_ = management::GetAll::Results::Create(extensions);
return true;
}
bool ManagementGetFunction::RunSync() {
scoped_ptr<management::Get::Params> params(
management::Get::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension = service()->GetExtensionById(params->id, true);
if (!extension) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
params->id);
return false;
}
scoped_ptr<management::ExtensionInfo> info =
CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
results_ = management::Get::Results::Create(*info);
return true;
}
bool ManagementGetPermissionWarningsByIdFunction::RunSync() {
scoped_ptr<management::GetPermissionWarningsById::Params> params(
management::GetPermissionWarningsById::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension = service()->GetExtensionById(params->id, true);
if (!extension) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
params->id);
return false;
}
std::vector<std::string> warnings = CreateWarningsList(extension);
results_ = management::GetPermissionWarningsById::Results::Create(warnings);
return true;
}
namespace {
// This class helps ManagementGetPermissionWarningsByManifestFunction manage
// sending manifest JSON strings to the utility process for parsing.
class SafeManifestJSONParser : public UtilityProcessHostClient {
public:
SafeManifestJSONParser(
ManagementGetPermissionWarningsByManifestFunction* client,
const std::string& manifest)
: client_(client),
manifest_(manifest) {}
void Start() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
}
void StartWorkOnIOThread() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
UtilityProcessHost* host = UtilityProcessHost::Create(
this, base::MessageLoopProxy::current().get());
host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
}
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
OnJSONParseSucceeded)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
OnJSONParseFailed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void OnJSONParseSucceeded(const base::ListValue& wrapper) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
const base::Value* value = NULL;
CHECK(wrapper.Get(0, &value));
if (value->IsType(base::Value::TYPE_DICTIONARY))
parsed_manifest_.reset(
static_cast<const base::DictionaryValue*>(value)->DeepCopy());
else
error_ = keys::kManifestParseError;
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
}
void OnJSONParseFailed(const std::string& error) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
error_ = error;
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
}
void ReportResultFromUIThread() {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (error_.empty() && parsed_manifest_.get())
client_->OnParseSuccess(parsed_manifest_.Pass());
else
client_->OnParseFailure(error_);
}
private:
virtual ~SafeManifestJSONParser() {}
// The client who we'll report results back to.
ManagementGetPermissionWarningsByManifestFunction* client_;
// Data to parse.
std::string manifest_;
// Results of parsing.
scoped_ptr<base::DictionaryValue> parsed_manifest_;
std::string error_;
};
} // namespace
bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() {
scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
management::GetPermissionWarningsByManifest::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
scoped_refptr<SafeManifestJSONParser> parser =
new SafeManifestJSONParser(this, params->manifest_str);
parser->Start();
// Matched with a Release() in OnParseSuccess/Failure().
AddRef();
// Response is sent async in OnParseSuccess/Failure().
return true;
}
void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
scoped_ptr<base::DictionaryValue> parsed_manifest) {
CHECK(parsed_manifest.get());
scoped_refptr<Extension> extension = Extension::Create(
base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest,
Extension::NO_FLAGS, &error_);
if (!extension.get()) {
OnParseFailure(keys::kExtensionCreateError);
return;
}
std::vector<std::string> warnings = CreateWarningsList(extension.get());
results_ =
management::GetPermissionWarningsByManifest::Results::Create(warnings);
SendResponse(true);
// Matched with AddRef() in RunAsync().
Release();
}
void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
const std::string& error) {
error_ = error;
SendResponse(false);
// Matched with AddRef() in RunAsync().
Release();
}
bool ManagementLaunchAppFunction::RunSync() {
scoped_ptr<management::LaunchApp::Params> params(
management::LaunchApp::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension = service()->GetExtensionById(params->id, true);
if (!extension) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
params->id);
return false;
}
if (!extension->is_app()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError,
params->id);
return false;
}
// Look at prefs to find the right launch container.
// If the user has not set a preference, the default launch value will be
// returned.
LaunchContainer launch_container =
GetLaunchContainer(ExtensionPrefs::Get(GetProfile()), extension);
OpenApplication(AppLaunchParams(
GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
#if !defined(OS_ANDROID)
CoreAppLauncherHandler::RecordAppLaunchType(
extension_misc::APP_LAUNCH_EXTENSION_API,
extension->GetType());
#endif
return true;
}
ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
}
ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
}
bool ManagementSetEnabledFunction::RunAsync() {
scoped_ptr<management::SetEnabled::Params> params(
management::SetEnabled::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
extension_id_ = params->id;
const Extension* extension =
ExtensionRegistry::Get(GetProfile())
->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
if (!extension || ui_util::ShouldNotBeVisible(extension, browser_context())) {
error_ = ErrorUtils::FormatErrorMessage(
keys::kNoExtensionError, extension_id_);
return false;
}
const ManagementPolicy* policy =
ExtensionSystem::Get(GetProfile())->management_policy();
if (!policy->UserMayModifySettings(extension, NULL) ||
(!params->enabled && policy->MustRemainEnabled(extension, NULL)) ||
(params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) {
error_ = ErrorUtils::FormatErrorMessage(
keys::kUserCantModifyError, extension_id_);
return false;
}
bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
if (!currently_enabled && params->enabled) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
if (!user_gesture()) {
error_ = keys::kGestureNeededForEscalationError;
return false;
}
AddRef(); // Matched in InstallUIProceed/InstallUIAbort
install_prompt_.reset(
new ExtensionInstallPrompt(GetAssociatedWebContents()));
install_prompt_->ConfirmReEnable(this, extension);
return true;
}
service()->EnableExtension(extension_id_);
} else if (currently_enabled && !params->enabled) {
service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION);
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true));
return true;
}
void ManagementSetEnabledFunction::InstallUIProceed() {
service()->EnableExtension(extension_id_);
SendResponse(true);
Release();
}
void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
error_ = keys::kUserDidNotReEnableError;
SendResponse(false);
Release();
}
ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
}
ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
}
bool ManagementUninstallFunctionBase::Uninstall(
const std::string& target_extension_id,
bool show_confirm_dialog) {
extension_id_ = target_extension_id;
const Extension* target_extension =
service()->GetExtensionById(extension_id_, true);
if (!target_extension ||
ui_util::ShouldNotBeVisible(target_extension, browser_context())) {
error_ = ErrorUtils::FormatErrorMessage(
keys::kNoExtensionError, extension_id_);
return false;
}
if (!ExtensionSystem::Get(GetProfile())
->management_policy()
->UserMayModifySettings(target_extension, NULL)) {
error_ = ErrorUtils::FormatErrorMessage(
keys::kUserCantModifyError, extension_id_);
return false;
}
if (auto_confirm_for_test == DO_NOT_SKIP) {
if (show_confirm_dialog) {
AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
GetProfile(), GetCurrentBrowser(), this));
if (extension_id() != target_extension_id) {
extension_uninstall_dialog_->ConfirmProgrammaticUninstall(
target_extension, GetExtension());
} else {
// If this is a self uninstall, show the generic uninstall dialog.
extension_uninstall_dialog_->ConfirmUninstall(target_extension);
}
} else {
Finish(true);
}
} else {
Finish(auto_confirm_for_test == PROCEED);
}
return true;
}
// static
void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
bool should_proceed) {
auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
}
void ManagementUninstallFunctionBase::Finish(bool should_uninstall) {
if (should_uninstall) {
// The extension can be uninstalled in another window while the UI was
// showing. Do nothing in that case.
ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
const Extension* extension = registry->GetExtensionById(
extension_id_, ExtensionRegistry::EVERYTHING);
if (!extension) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
extension_id_);
SendResponse(false);
} else {
bool success =
service()->UninstallExtension(extension_id_,
false, /* external uninstall */
NULL);
// TODO set error_ if !success
SendResponse(success);
}
} else {
error_ = ErrorUtils::FormatErrorMessage(
keys::kUninstallCanceledError, extension_id_);
SendResponse(false);
}
}
void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
Finish(true);
Release();
}
void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() {
Finish(false);
Release();
}
ManagementUninstallFunction::ManagementUninstallFunction() {
}
ManagementUninstallFunction::~ManagementUninstallFunction() {
}
bool ManagementUninstallFunction::RunAsync() {
scoped_ptr<management::Uninstall::Params> params(
management::Uninstall::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(extension_);
EXTENSION_FUNCTION_VALIDATE(params.get());
bool show_confirm_dialog = true;
// By default confirmation dialog isn't shown when uninstalling self, but this
// can be overridden with showConfirmDialog.
if (params->id == extension_->id()) {
show_confirm_dialog = params->options.get() &&
params->options->show_confirm_dialog.get() &&
*params->options->show_confirm_dialog;
}
if (show_confirm_dialog && !user_gesture()) {
error_ = keys::kGestureNeededForUninstallError;
return false;
}
return Uninstall(params->id, show_confirm_dialog);
}
ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
}
ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
}
bool ManagementUninstallSelfFunction::RunAsync() {
scoped_ptr<management::UninstallSelf::Params> params(
management::UninstallSelf::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
bool show_confirm_dialog = false;
if (params->options.get() && params->options->show_confirm_dialog.get())
show_confirm_dialog = *params->options->show_confirm_dialog;
return Uninstall(extension_->id(), show_confirm_dialog);
}
ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
}
ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
}
// static
void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
bool should_proceed) {
auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
}
void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
if (!created)
error_ = keys::kCreateShortcutCanceledError;
SendResponse(created);
Release();
}
bool ManagementCreateAppShortcutFunction::RunAsync() {
if (!user_gesture()) {
error_ = keys::kGestureNeededForCreateAppShortcutError;
return false;
}
scoped_ptr<management::CreateAppShortcut::Params> params(
management::CreateAppShortcut::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension = service()->GetExtensionById(params->id, true);
if (!extension) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
params->id);
return false;
}
if (!extension->is_app()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
return false;
}
#if defined(OS_MACOSX)
if (!extension->is_platform_app()) {
error_ = keys::kCreateOnlyPackagedAppShortcutMac;
return false;
}
#endif
Browser* browser = chrome::FindBrowserWithProfile(
GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
if (!browser) {
// Shouldn't happen if we have user gesture.
error_ = keys::kNoBrowserToCreateShortcut;
return false;
}
// Matched with a Release() in OnCloseShortcutPrompt().
AddRef();
if (auto_confirm_for_test == DO_NOT_SKIP) {
chrome::ShowCreateChromeAppShortcutsDialog(
browser->window()->GetNativeWindow(), browser->profile(), extension,
base::Bind(&ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt,
this));
} else {
OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
}
// Response is sent async in OnCloseShortcutPrompt().
return true;
}
bool ManagementSetLaunchTypeFunction::RunSync() {
if (!user_gesture()) {
error_ = keys::kGestureNeededForSetLaunchTypeError;
return false;
}
scoped_ptr<management::SetLaunchType::Params> params(
management::SetLaunchType::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
const Extension* extension = service()->GetExtensionById(params->id, true);
if (!extension) {
error_ =
ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
return false;
}
if (!extension->is_app()) {
error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
return false;
}
std::vector<management::LaunchType> available_launch_types =
GetAvailableLaunchTypes(*extension);
management::LaunchType app_launch_type = params->launch_type;
if (std::find(available_launch_types.begin(),
available_launch_types.end(),
app_launch_type) == available_launch_types.end()) {
error_ = keys::kLaunchTypeNotAvailableError;
return false;
}
LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
switch (app_launch_type) {
case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
launch_type = LAUNCH_TYPE_PINNED;
break;
case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
launch_type = LAUNCH_TYPE_REGULAR;
break;
case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
launch_type = LAUNCH_TYPE_FULLSCREEN;
break;
case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
launch_type = LAUNCH_TYPE_WINDOW;
break;
case management::LAUNCH_TYPE_NONE:
NOTREACHED();
}
SetLaunchType(service(), params->id, launch_type);
return true;
}
ManagementEventRouter::ManagementEventRouter(Profile* profile)
: profile_(profile) {
int types[] = {chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED,
chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED,
chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED};
CHECK(registrar_.IsEmpty());
for (size_t i = 0; i < arraysize(types); i++) {
registrar_.Add(this,
types[i],
content::Source<Profile>(profile_));
}
}
ManagementEventRouter::~ManagementEventRouter() {}
void ManagementEventRouter::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
const char* event_name = NULL;
const Extension* extension = NULL;
Profile* profile = content::Source<Profile>(source).ptr();
CHECK(profile);
CHECK(profile_->IsSameProfile(profile));
switch (type) {
case chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED:
event_name = management::OnInstalled::kEventName;
extension =
content::Details<const InstalledExtensionInfo>(details)->extension;
break;
case chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED:
event_name = management::OnUninstalled::kEventName;
extension = content::Details<const Extension>(details).ptr();
break;
case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED:
event_name = management::OnEnabled::kEventName;
extension = content::Details<const Extension>(details).ptr();
break;
case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED:
event_name = management::OnDisabled::kEventName;
extension =
content::Details<const UnloadedExtensionInfo>(details)->extension;
break;
default:
NOTREACHED();
return;
}
DCHECK(event_name);
DCHECK(extension);
if (ui_util::ShouldNotBeVisible(extension, profile_))
return; // Don't dispatch events for built-in extensions.
scoped_ptr<base::ListValue> args(new base::ListValue());
if (event_name == management::OnUninstalled::kEventName) {
args->Append(new base::StringValue(extension->id()));
} else {
scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
*extension, ExtensionSystem::Get(profile));
args->Append(info->ToValue().release());
}
scoped_ptr<Event> event(new Event(event_name, args.Pass()));
EventRouter::Get(profile)->BroadcastEvent(event.Pass());
}
ManagementAPI::ManagementAPI(content::BrowserContext* context)
: browser_context_(context) {
EventRouter* event_router = EventRouter::Get(browser_context_);
event_router->RegisterObserver(this, management::OnInstalled::kEventName);
event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
event_router->RegisterObserver(this, management::OnEnabled::kEventName);
event_router->RegisterObserver(this, management::OnDisabled::kEventName);
}
ManagementAPI::~ManagementAPI() {
}
void ManagementAPI::Shutdown() {
EventRouter::Get(browser_context_)->UnregisterObserver(this);
}
static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI> >
g_factory = LAZY_INSTANCE_INITIALIZER;
// static
BrowserContextKeyedAPIFactory<ManagementAPI>*
ManagementAPI::GetFactoryInstance() {
return g_factory.Pointer();
}
void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
management_event_router_.reset(
new ManagementEventRouter(Profile::FromBrowserContext(browser_context_)));
EventRouter::Get(browser_context_)->UnregisterObserver(this);
}
} // namespace extensions