1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/password_manager/password_generation_manager.h" 6 7 #include "base/prefs/pref_service.h" 8 #include "chrome/browser/password_manager/password_manager.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/sync/profile_sync_service.h" 11 #include "chrome/browser/sync/profile_sync_service_factory.h" 12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser_finder.h" 14 #include "chrome/browser/ui/browser_window.h" 15 #include "chrome/common/pref_names.h" 16 #include "components/autofill/core/browser/password_generator.h" 17 #include "components/autofill/core/common/autofill_messages.h" 18 #include "components/user_prefs/pref_registry_syncable.h" 19 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/render_view_host.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/common/password_form.h" 23 #include "ipc/ipc_message_macros.h" 24 #include "ui/gfx/rect.h" 25 26 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordGenerationManager); 27 28 PasswordGenerationManager::PasswordGenerationManager( 29 content::WebContents* contents) 30 : content::WebContentsObserver(contents), 31 enabled_(false), 32 weak_factory_(this) { 33 RegisterWithSyncService(); 34 } 35 36 PasswordGenerationManager::~PasswordGenerationManager() {} 37 38 // static 39 void PasswordGenerationManager::CreateForWebContents( 40 content::WebContents* contents) { 41 content::WebContentsUserData<PasswordGenerationManager>:: 42 CreateForWebContents(contents); 43 44 // Start observing changes to relevant prefs. This is not called in the 45 // constructor so that it's not enabled in testing. 46 FromWebContents(contents)->SetUpPrefChangeRegistrar(); 47 } 48 49 // static 50 void PasswordGenerationManager::RegisterProfilePrefs( 51 user_prefs::PrefRegistrySyncable* registry) { 52 registry->RegisterBooleanPref( 53 prefs::kPasswordGenerationEnabled, 54 true, 55 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 56 } 57 58 void PasswordGenerationManager::RegisterWithSyncService() { 59 Profile* profile = Profile::FromBrowserContext( 60 web_contents()->GetBrowserContext()); 61 ProfileSyncService* sync_service = 62 ProfileSyncServiceFactory::GetForProfile(profile); 63 if (sync_service) 64 sync_service->AddObserver(this); 65 } 66 67 void PasswordGenerationManager::SetUpPrefChangeRegistrar() { 68 registrar_.Init(Profile::FromBrowserContext( 69 web_contents()->GetBrowserContext())->GetPrefs()); 70 registrar_.Add( 71 prefs::kPasswordGenerationEnabled, 72 base::Bind(&PasswordGenerationManager::OnPrefStateChanged, 73 weak_factory_.GetWeakPtr())); 74 } 75 76 void PasswordGenerationManager::RenderViewCreated( 77 content::RenderViewHost* host) { 78 UpdateState(host, true); 79 } 80 81 bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) { 82 bool handled = true; 83 IPC_BEGIN_MESSAGE_MAP(PasswordGenerationManager, message) 84 IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup, 85 OnShowPasswordGenerationPopup) 86 IPC_MESSAGE_UNHANDLED(handled = false) 87 IPC_END_MESSAGE_MAP() 88 89 return handled; 90 } 91 92 void PasswordGenerationManager::WebContentsDestroyed( 93 content::WebContents* contents) { 94 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); 95 ProfileSyncService* sync_service = 96 ProfileSyncServiceFactory::GetForProfile(profile); 97 if (sync_service && sync_service->HasObserver(this)) 98 sync_service->RemoveObserver(this); 99 } 100 101 void PasswordGenerationManager::OnPrefStateChanged() { 102 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 103 if (web_contents() && web_contents()->GetRenderViewHost()) 104 UpdateState(web_contents()->GetRenderViewHost(), false); 105 } 106 107 void PasswordGenerationManager::OnStateChanged() { 108 // It is possible for sync state to change during tab contents destruction. 109 // In this case, we don't need to update the renderer since it's going away. 110 if (web_contents() && web_contents()->GetRenderViewHost()) 111 UpdateState(web_contents()->GetRenderViewHost(), false); 112 } 113 114 // In order for password generation to be enabled, we need to make sure: 115 // (1) Password sync is enabled, 116 // (2) Password manager is enabled, and 117 // (3) Password generation preference check box is checked. 118 void PasswordGenerationManager::UpdateState(content::RenderViewHost* host, 119 bool new_renderer) { 120 Profile* profile = Profile::FromBrowserContext( 121 web_contents()->GetBrowserContext()); 122 123 bool saving_passwords_enabled = 124 PasswordManager::FromWebContents(web_contents())->IsSavingEnabled(); 125 126 bool preference_checked = profile->GetPrefs()->GetBoolean( 127 prefs::kPasswordGenerationEnabled); 128 129 bool password_sync_enabled = false; 130 ProfileSyncService* sync_service = 131 ProfileSyncServiceFactory::GetForProfile(profile); 132 if (sync_service) { 133 syncer::ModelTypeSet sync_set = sync_service->GetActiveDataTypes(); 134 password_sync_enabled = (sync_service->HasSyncSetupCompleted() && 135 sync_set.Has(syncer::PASSWORDS)); 136 } 137 138 bool new_enabled = (password_sync_enabled && 139 saving_passwords_enabled && 140 preference_checked); 141 142 if (new_enabled != enabled_ || new_renderer) { 143 enabled_ = new_enabled; 144 SendStateToRenderer(host, enabled_); 145 } 146 } 147 148 void PasswordGenerationManager::SendStateToRenderer( 149 content::RenderViewHost* host, bool enabled) { 150 host->Send(new AutofillMsg_PasswordGenerationEnabled(host->GetRoutingID(), 151 enabled)); 152 } 153 154 void PasswordGenerationManager::OnShowPasswordGenerationPopup( 155 const gfx::Rect& bounds, 156 int max_length, 157 const content::PasswordForm& form) { 158 #if defined(OS_ANDROID) 159 NOTIMPLEMENTED(); 160 #else 161 password_generator_.reset(new autofill::PasswordGenerator(max_length)); 162 Browser* browser = chrome::FindBrowserWithWebContents(web_contents()); 163 browser->window()->ShowPasswordGenerationBubble(bounds, 164 form, 165 password_generator_.get()); 166 #endif // #if defined(OS_ANDROID) 167 } 168