1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/navigation_extension_enabler.h"
#include <memory>
#include "base/functional/bind.h"
#include "chrome/browser/extensions/extension_service.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_system.h"
namespace extensions {
NavigationExtensionEnabler::NavigationExtensionEnabler(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
content::WebContentsUserData<NavigationExtensionEnabler>(*web_contents) {
extension_registry_observation_.Observe(
ExtensionRegistry::Get(web_contents->GetBrowserContext()));
}
NavigationExtensionEnabler::~NavigationExtensionEnabler() = default;
void NavigationExtensionEnabler::NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) {
PromptToEnableExtensionIfNecessary(load_details.entry->GetURL());
}
void NavigationExtensionEnabler::PromptToEnableExtensionIfNecessary(
const GURL& url) {
// Bail out if we're already running a prompt.
if (!in_progress_prompt_extension_id_.empty()) {
return;
}
// NOTE: We only consider chrome-extension:// urls, and deliberately don't
// consider hosted app urls. This is because it's really annoying to visit the
// site associated with a hosted app (like calendar.google.com or
// drive.google.com) and have it repeatedly prompt you to re-enable an item.
// Visiting a chrome-extension:// url is a much stronger signal, and, without
// the item enabled, we won't show anything.
// TODO(devlin): While true, I still wonder how useful this is. We should get
// metrics.
if (!url.SchemeIs(kExtensionScheme)) {
return;
}
const Extension* extension =
ExtensionRegistry::Get(web_contents()->GetBrowserContext())
->disabled_extensions()
.GetExtensionOrAppByURL(url);
if (!extension) {
return;
}
ExtensionPrefs* extension_prefs =
ExtensionPrefs::Get(web_contents()->GetBrowserContext());
// TODO(devlin): Why do we only consider extensions that escalate permissions?
// Maybe because it's the only one we have a good prompt for?
if (!extension_prefs->DidExtensionEscalatePermissions(extension->id())) {
return;
}
// Keep track of the extension id we're prompting for. These must be reset in
// OnInstallPromptDone.
in_progress_prompt_extension_id_ = extension->id();
extension_install_prompt_ =
std::make_unique<ExtensionInstallPrompt>(web_contents());
ExtensionInstallPrompt::PromptType type =
ExtensionInstallPrompt::GetReEnablePromptTypeForExtension(
web_contents()->GetBrowserContext(), extension);
extension_install_prompt_->ShowDialog(
base::BindRepeating(&NavigationExtensionEnabler::OnInstallPromptDone,
weak_factory_.GetWeakPtr()),
extension, nullptr,
std::make_unique<ExtensionInstallPrompt::Prompt>(type),
ExtensionInstallPrompt::GetDefaultShowDialogCallback());
}
void NavigationExtensionEnabler::OnInstallPromptDone(
ExtensionInstallPrompt::DoneCallbackPayload payload) {
// This dialog doesn't support the "withhold permissions" checkbox.
DCHECK_NE(payload.result,
ExtensionInstallPrompt::Result::ACCEPTED_WITH_WITHHELD_PERMISSIONS);
// The extension was already uninstalled.
if (in_progress_prompt_extension_id_.empty()) {
return;
}
ExtensionRegistry* extension_registry =
ExtensionRegistry::Get(web_contents()->GetBrowserContext());
const Extension* extension = extension_registry->GetExtensionById(
in_progress_prompt_extension_id_, ExtensionRegistry::EVERYTHING);
CHECK(extension);
if (payload.result == ExtensionInstallPrompt::Result::ACCEPTED) {
ExtensionRegistrar* extension_registrar =
ExtensionRegistrar::Get(web_contents()->GetBrowserContext());
// Grant permissions, re-enable the extension, and then reload the tab.
extension_registrar->GrantPermissionsAndEnableExtension(*extension);
web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
}
in_progress_prompt_extension_id_.clear();
extension_install_prompt_.reset();
}
void NavigationExtensionEnabler::OnExtensionUninstalled(
content::BrowserContext* browser_context,
const Extension* extension,
UninstallReason reason) {
if (in_progress_prompt_extension_id_.empty() ||
in_progress_prompt_extension_id_ != extension->id()) {
return;
}
in_progress_prompt_extension_id_ = std::string();
extension_install_prompt_.reset();
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(NavigationExtensionEnabler);
} // namespace extensions
|