12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/extensions/extension_enable_flow.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" 120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 13ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/public/browser/notification_details.h" 14ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "content/public/browser/notification_source.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_prefs.h" 16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/browser/extension_registry.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionEnableFlow::ExtensionEnableFlow(Profile* profile, 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& extension_id, 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionEnableFlowDelegate* delegate) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : profile_(profile), 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension_id_(extension_id), 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delegate_(delegate), 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_contents_(NULL), 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) parent_window_(NULL), 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extension_registry_observer_(this) { 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionEnableFlow::~ExtensionEnableFlow() { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionEnableFlow::StartForWebContents( 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::WebContents* parent_contents) { 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_contents_ = parent_contents; 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_window_ = NULL; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Run(); 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionEnableFlow::StartForNativeWindow( 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::NativeWindow parent_window) { 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_contents_ = NULL; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent_window_ = parent_window; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Run(); 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void ExtensionEnableFlow::StartForCurrentlyNonexistentWindow( 5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::Callback<gfx::NativeWindow(void)> window_getter) { 5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) window_getter_ = window_getter; 5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) Run(); 5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionEnableFlow::Run() { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionService* service = 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::ExtensionSystem::Get(profile_)->extension_service(); 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = service->GetExtensionById(extension_id_, true); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) { 60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension = extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( 61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_id_, extensions::ExtensionRegistry::TERMINATED); 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // It's possible (though unlikely) the app could have been uninstalled since 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the user clicked on it. 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // If the app was terminated, reload it first. 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) service->ReloadExtension(extension_id_); 68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 69ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // ReloadExtension reallocates the Extension object. 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension = service->GetExtensionById(extension_id_, true); 71ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 72ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // |extension| could be NULL for asynchronous load, such as the case of 73ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // an unpacked extension. Wait for the load to continue the flow. 74ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!extension) { 75ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch StartObserving(); 76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return; 77ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 78ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 80ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch CheckPermissionAndMaybePromptUser(); 81ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 82ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 83ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() { 84ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ExtensionService* service = 85ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch extensions::ExtensionSystem::Get(profile_)->extension_service(); 86ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch const Extension* extension = service->GetExtensionById(extension_id_, true); 87ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!extension) { 88ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch delegate_->ExtensionEnableFlowAborted(false); // |delegate_| may delete us. 89ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return; 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_); 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!prefs->DidExtensionEscalatePermissions(extension_id_)) { 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Enable the extension immediately if its privileges weren't escalated. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This is a no-op if the extension was previously terminated. 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) service->EnableExtension(extension_id_); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us. 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreatePrompt(); 1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) prompt_->ConfirmReEnable(this, extension); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionEnableFlow::CreatePrompt() { 10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (!window_getter_.is_null()) 10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) parent_window_ = window_getter_.Run(); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) prompt_.reset(parent_contents_ ? 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new ExtensionInstallPrompt(parent_contents_) : 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new ExtensionInstallPrompt(profile_, parent_window_, this)); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 114ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ExtensionEnableFlow::StartObserving() { 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extension_registry_observer_.Add( 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extensions::ExtensionRegistry::Get(profile_)); 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) registrar_.Add(this, 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, 119ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch content::Source<Profile>(profile_)); 120ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 121ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 122ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ExtensionEnableFlow::StopObserving() { 123ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch registrar_.RemoveAll(); 12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) extension_registry_observer_.RemoveAll(); 125ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 126ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 127ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ExtensionEnableFlow::Observe(int type, 128ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch const content::NotificationSource& source, 129ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch const content::NotificationDetails& details) { 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR, type); 13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) StopObserving(); 13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) delegate_->ExtensionEnableFlowAborted(false); 133ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 134ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionEnableFlow::OnExtensionLoaded( 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::BrowserContext* browser_context, 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const Extension* extension) { 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (extension->id() == extension_id_) { 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) StopObserving(); 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) CheckPermissionAndMaybePromptUser(); 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionEnableFlow::OnExtensionUninstalled( 14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) content::BrowserContext* browser_context, 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Extension* extension, 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::UninstallReason reason) { 14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (extension->id() == extension_id_) { 14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) StopObserving(); 15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) delegate_->ExtensionEnableFlowAborted(false); 15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionEnableFlow::InstallUIProceed() { 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionService* service = 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::ExtensionSystem::Get(profile_)->extension_service(); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The extension can be uninstalled in another window while the UI was 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // showing. Treat it as a cancellation and notify |delegate_|. 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Extension* extension = service->GetExtensionById(extension_id_, true); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!extension) { 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delegate_->ExtensionEnableFlowAborted(true); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) service->GrantPermissionsAndEnableExtension(extension); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us. 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionEnableFlow::InstallUIAbort(bool user_initiated) { 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delegate_->ExtensionEnableFlowAborted(user_initiated); 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // |delegate_| may delete us. 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)content::WebContents* ExtensionEnableFlow::OpenURL( 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::OpenURLParams& params) { 1770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) chrome::ScopedTabbedBrowserDisplayer displayer( 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) profile_, chrome::GetActiveDesktop()); 1790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return displayer.browser()->OpenURL(params); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 181