Commit 4cb6da1d authored by meacer@chromium.org's avatar meacer@chromium.org

Require user confirmation for chrome.management.uninstall except when uninstalling self.

chrome.management.uninstall is changed as follows unless the extension is trying to
uninstall itself:
- The confirmation dialog is shown by default.
- A user gesture is required.

BUG=178319

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245457 0039d316-1c4b-4281-b951-d872f2087c98
parent 4a9c22c1
......@@ -604,12 +604,21 @@ ManagementUninstallFunction::~ManagementUninstallFunction() {
bool ManagementUninstallFunction::RunImpl() {
scoped_ptr<management::Uninstall::Params> params(
management::Uninstall::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(extension_);
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;
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);
}
......
......@@ -111,9 +111,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
const std::string id = extension->id();
scoped_refptr<Extension> empty_extension(
extension_function_test_utils::CreateEmptyExtension());
// Uninstall, then cancel via the confirm dialog.
scoped_refptr<ManagementUninstallFunction> uninstall_function(
new ManagementUninstallFunction());
uninstall_function->set_extension(empty_extension);
uninstall_function->set_user_gesture(true);
ManagementUninstallFunction::SetAutoConfirmForTest(false);
EXPECT_TRUE(MatchPattern(
......@@ -129,8 +133,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
// Uninstall, then accept via the confirm dialog.
uninstall_function = new ManagementUninstallFunction();
uninstall_function->set_extension(empty_extension);
ManagementUninstallFunction::SetAutoConfirmForTest(true);
uninstall_function->set_user_gesture(true);
util::RunFunctionAndReturnSingleResult(
uninstall_function.get(),
base::StringPrintf("[\"%s\", {\"showConfirmDialog\": true}]", id.c_str()),
......
......@@ -14,13 +14,16 @@ const char kExtensionCreateError[] =
"Failed to create extension from manifest.";
const char kGestureNeededForEscalationError[] =
"Re-enabling an extension disabled due to permissions increase "
"requires a user gesture";
"requires a user gesture.";
const char kGestureNeededForUninstallError[] =
"chrome.management.uninstall requires a user gesture.";
const char kManifestParseError[] = "Failed to parse manifest.";
const char kNoExtensionError[] = "Failed to find extension with id *";
const char kNotAnAppError[] = "Extension * is not an App";
const char kUserCantModifyError[] = "Extension * cannot be modified by user";
const char kUninstallCanceledError[] = "Extension * uninstall canceled by user";
const char kNoExtensionError[] = "Failed to find extension with id *.";
const char kNotAnAppError[] = "Extension * is not an App.";
const char kUserCantModifyError[] = "Extension * cannot be modified by user.";
const char kUninstallCanceledError[] =
"Extension * uninstall canceled by user.";
const char kUserDidNotReEnableError[] =
"The user did not accept the re-enable dialog";
"The user did not accept the re-enable dialog.";
} // namespace extension_management_api_constants
......@@ -16,6 +16,7 @@ extern const char kDisabledReasonPermissionsIncrease[];
// Error messages.
extern const char kExtensionCreateError[];
extern const char kGestureNeededForEscalationError[];
extern const char kGestureNeededForUninstallError[];
extern const char kManifestParseError[];
extern const char kNoExtensionError[];
extern const char kNotAnAppError[];
......
......@@ -5,6 +5,7 @@
#include <map>
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/management/management_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
......@@ -125,6 +126,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, NoPermission) {
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_Uninstall) {
LoadExtensions();
// Confirmation dialog will be shown for uninstallations except for self.
extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
ASSERT_TRUE(RunExtensionSubtest("management/test", "uninstall.html"));
}
......@@ -138,6 +141,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_Uninstall) {
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
MAYBE_ManagementPolicyAllowed) {
LoadExtensions();
extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
ExtensionService* service = extensions::ExtensionSystem::Get(
browser()->profile())->extension_service();
EXPECT_TRUE(service->GetExtensionById(extension_ids_["enabled_extension"],
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "chrome/browser/apps/app_browsertest_util.h"
#include "chrome/browser/extensions/api/management/management_api.h"
#include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
......@@ -28,6 +29,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeUnprivileged) {
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeRuntimeUninstallURL) {
// Auto-confirm the uninstall dialog.
extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("runtime").AppendASCII("uninstall_url").
AppendASCII("sets_uninstall_url")));
......
......@@ -9,6 +9,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/api/management/management_api.h"
#include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
......@@ -126,6 +127,8 @@ class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
// Navigates to |page| and runs the Extension API test there. Any downloads
// of extensions will return the contents of |crx_file|.
bool RunInstallTest(const std::string& page, const std::string& crx_file) {
// Auto-confirm the uninstallation dialog.
ManagementUninstallFunction::SetAutoConfirmForTest(true);
#if defined(OS_WIN) && !defined(NDEBUG)
// See http://crbug.com/177163 for details.
return true;
......
......@@ -64,10 +64,12 @@ var tests = [
chrome.test.assertEq(true, item.mayDisable);
var id = item.id;
chrome.management.uninstall(id, callback(function() {
chrome.test.assertNoLastError();
// The calling api test will verify that the item was uninstalled.
}));
chrome.test.runWithUserGesture(function() {
chrome.management.uninstall(id, callback(function() {
chrome.test.assertNoLastError();
// The calling api test will verify that the item was uninstalled.
}));
});
}));
}
];
......
......@@ -9,7 +9,7 @@ var ENABLED_NAME = 'enabled_extension';
var DISABLED_NAME = 'disabled_extension';
var UNINSTALL_NAME = 'enabled_extension';
var EXPECTED_ERROR = 'Extension * cannot be modified by user';
var EXPECTED_ERROR = 'Extension * cannot be modified by user.';
// Given a list of extension items, finds the one with the given name.
function findByName(items, name) {
......@@ -69,8 +69,10 @@ var tests = [
var id = item.id;
var expectedError = EXPECTED_ERROR.replace('*', id);
chrome.management.uninstall(id,
callback(function() { checkEnabled(id, true); }, expectedError));
chrome.test.runWithUserGesture(function() {
chrome.management.uninstall(id,
callback(function() { checkEnabled(id, true); }, expectedError));
});
}));
}
];
......
// 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.
var EXPECTED_ERROR = 'chrome.management.uninstall requires a user gesture.';
function uninstall(name) {
var expected_id;
listenOnce(chrome.management.onUninstalled, function(id) {
......@@ -11,18 +14,37 @@ function uninstall(name) {
var old_count = items.length;
var item = getItemNamed(items, name);
expected_id = item.id;
chrome.test.runWithUserGesture(function() {
chrome.management.uninstall(item.id, callback(function() {
chrome.management.getAll(callback(function(items2) {
assertEq(old_count - 1, items2.length);
for (var i = 0; i < items2.length; i++) {
assertFalse(items2[i].name == name);
}
}));
}));
});
}));
}
function uninstallWithoutUserGesture(name) {
chrome.management.getAll(callback(function(items) {
var old_count = items.length;
var item = getItemNamed(items, name);
chrome.management.uninstall(item.id, callback(function() {
chrome.management.getAll(callback(function(items2) {
assertEq(old_count - 1, items2.length);
for (var i = 0; i < items2.length; i++) {
assertFalse(items2[i].name == name);
}
assertEq(old_count, items2.length);
}));
}));
}, EXPECTED_ERROR));
}));
}
var tests = [
function uninstallEnabledAppWithoutUserGesture() {
uninstallWithoutUserGesture("enabled_app");
},
function uninstallEnabledApp() {
uninstall("enabled_app");
},
......
......@@ -12,13 +12,14 @@ var uninstalled = false;
chrome.test.runTests([
function uninstallURL() {
chrome.management.getAll(function(results) {
for(var i = 0;i<results.length;i++)
{
for(var i = 0; i < results.length; i++) {
if (results[i].name == sets_uninstall_url) {
chrome.management.uninstall(results[i].id, pass(function() {
chrome.tabs.query({'url': uninstall_url}, pass(function(tabs) {
chrome.test.assertEq(tabs.length, 1);
chrome.test.assertEq(tabs[0].url, uninstall_url);
chrome.test.runWithUserGesture(pass(function() {
chrome.management.uninstall(results[i].id, pass(function() {
chrome.tabs.query({'url': uninstall_url}, pass(function(tabs) {
chrome.test.assertEq(tabs.length, 1);
chrome.test.assertEq(tabs[0].url, uninstall_url);
}));
}));
}));
uninstalled = true;
......
......@@ -90,7 +90,9 @@ function installAndCleanUp(installOptions, whileInstalled) {
whileInstalled();
chrome.management.uninstall(extensionId, {}, callbackPass());
chrome.test.runWithUserGesture(callbackPass(function() {
chrome.management.uninstall(extensionId, {}, callbackPass());
}));
}));
}));
}
......@@ -11,7 +11,7 @@ window.onload = function() {
}
if (item.name == "simple_extension") {
// Try launching a non-app extension, which should fail.
var expected_error = "Extension " + item.id + " is not an App";
var expected_error = "Extension " + item.id + " is not an App.";
chrome.management.launchApp(item.id, function() {
if (chrome.runtime.lastError &&
chrome.runtime.lastError.message == expected_error) {
......
......@@ -11,11 +11,13 @@ chrome.management.getAll(function(items) {
if (item.name != EXPECTED_NAME) continue;
var id = item.id;
chrome.test.assertEq(false, item.mayDisable);
chrome.management.uninstall(id, function() {
// Check that the right error occured.
var expectedError = 'Extension ' + id + ' cannot be modified by user';
chrome.test.assertEq(expectedError, chrome.runtime.lastError.message);
chrome.test.sendMessage('ready');
chrome.test.runWithUserGesture(function() {
chrome.management.uninstall(id, function() {
// Check that the right error occured.
var expectedError = 'Extension ' + id + ' cannot be modified by user.';
chrome.test.assertEq(expectedError, chrome.runtime.lastError.message);
chrome.test.sendMessage('ready');
});
});
}
});
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