LoginDetectionService.cpp (5150B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "LoginDetectionService.h" 8 9 #include "mozilla/ClearOnShutdown.h" 10 #include "mozilla/StaticPrefs_fission.h" 11 #include "mozilla/dom/ProcessIsolation.h" 12 #include "nsILoginInfo.h" 13 #include "nsILoginManager.h" 14 #include "nsIObserver.h" 15 #include "nsIXULRuntime.h" 16 #include "nsServiceManagerUtils.h" 17 #include "nsXULAppAPI.h" 18 19 namespace mozilla::dom { 20 21 static StaticRefPtr<LoginDetectionService> gLoginDetectionService; 22 23 namespace { 24 25 void OnFissionPrefsChange(const char* aPrefName, void* aData) { 26 MOZ_ASSERT(gLoginDetectionService); 27 28 gLoginDetectionService->MaybeStartMonitoring(); 29 } 30 31 } // namespace 32 33 NS_IMPL_ISUPPORTS(LoginDetectionService, nsILoginDetectionService, 34 nsILoginSearchCallback, nsIObserver, nsISupportsWeakReference) 35 36 // static 37 already_AddRefed<LoginDetectionService> LoginDetectionService::GetSingleton() { 38 if (gLoginDetectionService) { 39 return do_AddRef(gLoginDetectionService); 40 } 41 42 gLoginDetectionService = new LoginDetectionService(); 43 ClearOnShutdown(&gLoginDetectionService); 44 45 return do_AddRef(gLoginDetectionService); 46 } 47 48 LoginDetectionService::LoginDetectionService() : mIsLoginsLoaded(false) {} 49 LoginDetectionService::~LoginDetectionService() { UnregisterObserver(); } 50 51 void LoginDetectionService::MaybeStartMonitoring() { 52 if (IsIsolateHighValueSiteEnabled()) { 53 // We want to isolate sites with a saved password, so fetch saved logins 54 // from the password manager, and then add the 'HighValue' permission. 55 56 // Note that we don't monitor whether a login is added or removed after 57 // logins are fetched. For adding logins, this will be covered by form 58 // submission detection heuristic. As for removing logins, it doesn't 59 // provide security benefit just to NOT isolate the removed site. The site 60 // will not be isolated when its permission expired. 61 FetchLogins(); 62 } 63 64 if (IsIsolateHighValueSiteEnabled() || 65 StaticPrefs::fission_highValue_login_monitor()) { 66 // When the pref is on, we monitor users' login attempt event when we 67 // are not isolating high value sites. This is because We can't detect the 68 // case where a user is already logged in to a site, and don't save a 69 // password for it. So we want to start monitoring login attempts prior 70 // to releasing the feature. 71 if (!mObs) { 72 mObs = mozilla::services::GetObserverService(); 73 mObs->AddObserver(this, "passwordmgr-form-submission-detected", false); 74 } 75 } else { 76 UnregisterObserver(); 77 } 78 } 79 80 void LoginDetectionService::FetchLogins() { 81 nsresult rv; 82 nsCOMPtr<nsILoginManager> loginManager = 83 do_GetService(NS_LOGINMANAGER_CONTRACTID, &rv); 84 if (NS_WARN_IF(!loginManager)) { 85 return; 86 } 87 88 (void)loginManager->GetAllLoginsWithCallback(this); 89 } 90 91 void LoginDetectionService::UnregisterObserver() { 92 if (mObs) { 93 mObs->RemoveObserver(this, "passwordmgr-form-submission-detected"); 94 mObs = nullptr; 95 } 96 } 97 98 /////////////////////////////////////////////////////////////////////////////// 99 // nsILoginDetectionService implementation 100 NS_IMETHODIMP LoginDetectionService::Init() { 101 if (XRE_IsContentProcess()) { 102 return NS_OK; 103 } 104 105 Preferences::RegisterCallback(OnFissionPrefsChange, "fission.autostart"); 106 Preferences::RegisterCallback(OnFissionPrefsChange, 107 "fission.webContentIsolationStrategy"); 108 109 MaybeStartMonitoring(); 110 111 return NS_OK; 112 } 113 114 NS_IMETHODIMP LoginDetectionService::IsLoginsLoaded(bool* aResult) { 115 if (IsIsolateHighValueSiteEnabled()) { 116 *aResult = mIsLoginsLoaded; 117 } else { 118 // When the feature is disabled, just returns true so testcases don't 119 // block on waiting for us to load logins. 120 *aResult = true; 121 } 122 return NS_OK; 123 } 124 125 /////////////////////////////////////////////////////////////////////////////// 126 // nsILoginSearchObserver implementation 127 NS_IMETHODIMP 128 LoginDetectionService::OnSearchComplete( 129 const nsTArray<RefPtr<nsILoginInfo>>& aLogins) { 130 // Add all origins with saved passwords to the permission manager. 131 for (const auto& login : aLogins) { 132 nsString origin; 133 login->GetOrigin(origin); 134 135 AddHighValuePermission(NS_ConvertUTF16toUTF8(origin), 136 mozilla::dom::kHighValueHasSavedLoginPermission); 137 } 138 139 mIsLoginsLoaded = true; 140 return NS_OK; 141 } 142 143 /////////////////////////////////////////////////////////////////////////////// 144 // nsIObserver implementation 145 NS_IMETHODIMP 146 LoginDetectionService::Observe(nsISupports* aSubject, const char* aTopic, 147 const char16_t* aData) { 148 if ("passwordmgr-form-submission-detected"_ns.Equals(aTopic)) { 149 nsDependentString origin(aData); 150 AddHighValuePermission(NS_ConvertUTF16toUTF8(origin), 151 mozilla::dom::kHighValueIsLoggedInPermission); 152 } 153 154 return NS_OK; 155 } 156 157 } // namespace mozilla::dom