Bug 1407878 - P1. Check URLs against the login reputation service when a password field is focused. r?francois
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1110,20 +1110,19 @@ BrowserGlue.prototype = {
}, 3000);
// It's important that SafeBrowsing is initialized reasonably
// early, so we use a maximum timeout for it.
Services.tm.idleDispatchToMainThread(() => {
SafeBrowsing.init();
// Login reputation depends on the Safe Browsing API.
- if (Services.prefs.getBoolPref("browser.safebrowsing.passwords.enabled")) {
- Cc["@mozilla.org/reputationservice/login-reputation-service;1"]
+ let reputationService = Cc["@mozilla.org/reputationservice/login-reputation-service;1"]
.getService(Ci.ILoginReputationService);
- }
+ reputationService.init();
}, 5000);
if (AppConstants.MOZ_CRASHREPORTER) {
UnsubmittedCrashHandler.scheduleCheckForUnsubmittedCrashReports();
}
if (AppConstants.platform == "win") {
Services.tm.idleDispatchToMainThread(() => {
deleted file mode 100644
--- a/toolkit/components/reputationservice/ILoginReputation.idl
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-[scriptable, uuid(b527be1e-8fbb-41d9-bee4-267a71236368)]
-interface ILoginReputationQueryCallback : nsISupports {
- void onQueryComplete();
-};
-
-[scriptable, uuid(1b3f1dfe-ce3a-486b-953e-ce5ac863eff9)]
-interface ILoginReputationService : nsISupports {
- // XXX : Add QueryReputation interface
-};
--- a/toolkit/components/reputationservice/LoginReputation.cpp
+++ b/toolkit/components/reputationservice/LoginReputation.cpp
@@ -1,24 +1,64 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LoginReputation.h"
+#include "nsIDOMHTMLInputElement.h"
+#include "mozilla/Preferences.h"
using namespace mozilla;
+using namespace mozilla::dom;
+
+#define PREF_PP_ENABLED "browser.safebrowsing.passwords.enabled"
+static bool sPasswordProtectionEnabled = false;
// MOZ_LOG=LoginReputation:5
-LazyLogModule LoginReputationService::prlog("LoginReputation");
-#define LR_LOG(args) MOZ_LOG(LoginReputationService::prlog, mozilla::LogLevel::Debug, args)
-#define LR_LOG_ENABLED() MOZ_LOG_TEST(LoginReputationService::prlog, mozilla::LogLevel::Debug)
+LazyLogModule gLoginReputationLogModule("LoginReputation");
+#define LR_LOG(args) MOZ_LOG(gLoginReputationLogModule, mozilla::LogLevel::Debug, args)
+#define LR_LOG_ENABLED() MOZ_LOG_TEST(gLoginReputationLogModule, mozilla::LogLevel::Debug)
+
+// -------------------------------------------------------------------------
+// ReputationQueryParam
+//
+// Concrete class for nsILoginReputationQuery to hold query parameters
+//
+class ReputationQueryParam final : public nsILoginReputationQuery
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSILOGINREPUTATIONQUERY
+
+ explicit ReputationQueryParam(nsIURI* aURI)
+ : mURI(aURI)
+ {
+ };
+private:
+ ~ReputationQueryParam() = default;
+
+ nsCOMPtr<nsIURI> mURI;
+};
+
+NS_IMPL_ISUPPORTS(ReputationQueryParam, nsILoginReputationQuery)
+
+NS_IMETHODIMP
+ReputationQueryParam::GetFormURI(nsIURI** aURI)
+{
+ NS_IF_ADDREF(*aURI = mURI);
+ return NS_OK;
+}
+
+// -------------------------------------------------------------------------
+// LoginReputationService
+//
NS_IMPL_ISUPPORTS(LoginReputationService,
- ILoginReputationService)
+ nsILoginReputationService)
LoginReputationService*
LoginReputationService::gLoginReputationService = nullptr;
already_AddRefed<LoginReputationService>
LoginReputationService::GetSingleton()
{
if (!gLoginReputationService) {
@@ -31,8 +71,88 @@ LoginReputationService::LoginReputationS
{
LR_LOG(("Login reputation service starting up"));
}
LoginReputationService::~LoginReputationService()
{
LR_LOG(("Login reputation service shutting down"));
}
+
+NS_IMETHODIMP
+LoginReputationService::Init()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ switch (XRE_GetProcessType()) {
+ case GeckoProcessType_Default:
+ LR_LOG(("Init login reputation service in parent"));
+ break;
+ case GeckoProcessType_Content:
+ LR_LOG(("Init login reputation service in child"));
+ break;
+ default:
+ // No other process type is supported!
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ Preferences::AddBoolVarCache(&sPasswordProtectionEnabled, PREF_PP_ENABLED, true);
+
+ return NS_OK;
+}
+
+// static
+already_AddRefed<nsILoginReputationQuery>
+LoginReputationService::ConstructQueryParam(nsIURI* aURI)
+{
+ RefPtr<ReputationQueryParam> param = new ReputationQueryParam(aURI);
+ return param.forget();
+}
+
+NS_IMETHODIMP
+LoginReputationService::QueryReputationAsync(nsIDOMHTMLInputElement* aInput,
+ nsILoginReputationQueryCallback* aCallback)
+{
+ NS_ENSURE_ARG_POINTER(aInput);
+
+ LR_LOG(("QueryReputationAsync() [this=%p]", this));
+
+ if (!sPasswordProtectionEnabled) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
+ NS_ENSURE_STATE(node);
+
+ nsIURI* documentURI = node->OwnerDoc()->GetDocumentURI();
+ NS_ENSURE_STATE(documentURI);
+
+ if (XRE_IsContentProcess()) {
+ } else {
+ nsCOMPtr<nsILoginReputationQuery> query =
+ LoginReputationService::ConstructQueryParam(documentURI);
+
+ nsresult rv = QueryReputation(query, aCallback);
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+LoginReputationService::QueryReputation(nsILoginReputationQuery* aQuery,
+ nsILoginReputationQueryCallback* aCallback)
+{
+ NS_ENSURE_ARG_POINTER(aQuery);
+
+ LR_LOG(("QueryReputation() [this=%p]", this));
+
+ if (!sPasswordProtectionEnabled) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Return SAFE until we add support for the remote service (bug 1413732).
+ if (aCallback) {
+ aCallback->OnQueryComplete(nsILoginReputationResult::SAFE);
+ }
+
+ return NS_OK;
+}
--- a/toolkit/components/reputationservice/LoginReputation.h
+++ b/toolkit/components/reputationservice/LoginReputation.h
@@ -1,36 +1,35 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef LoginReputation_h__
#define LoginReputation_h__
-#include "ILoginReputation.h"
+#include "nsILoginReputation.h"
#include "mozilla/Logging.h"
-class LoginReputationService final : public ILoginReputationService
+class LoginReputationService final : public nsILoginReputationService
{
public:
NS_DECL_ISUPPORTS
- NS_DECL_ILOGINREPUTATIONSERVICE
+ NS_DECL_NSILOGINREPUTATIONSERVICE
public:
- static already_AddRefed<LoginReputationService> GetSingleton();
+ static
+ already_AddRefed<LoginReputationService> GetSingleton();
+
+ static
+ already_AddRefed<nsILoginReputationQuery> ConstructQueryParam(nsIURI* aURI);
private:
/**
* Global singleton object for holding this factory service.
*/
static LoginReputationService* gLoginReputationService;
- /**
- * MOZ_LOG=LoginReputation:5
- */
- static mozilla::LazyLogModule prlog;
-
LoginReputationService();
~LoginReputationService();
};
#endif // LoginReputation_h__
--- a/toolkit/components/reputationservice/moz.build
+++ b/toolkit/components/reputationservice/moz.build
@@ -5,18 +5,18 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
with Files('*'):
BUG_COMPONENT = ('Toolkit', 'Safe Browsing')
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
XPIDL_SOURCES += [
- 'ILoginReputation.idl',
'nsIApplicationReputation.idl',
+ 'nsILoginReputation.idl',
]
XPIDL_MODULE = 'reputationservice'
UNIFIED_SOURCES += [
'ApplicationReputation.cpp',
'chromium/chrome/common/safe_browsing/csd.pb.cc',
'LoginReputation.cpp',
new file mode 100644
--- /dev/null
+++ b/toolkit/components/reputationservice/nsILoginReputation.idl
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIDOMHTMLInputElement;
+interface nsIURI;
+
+[scriptable, uuid(6219f9da-297e-446d-8d47-ccdd8e72a1d5)]
+interface nsILoginReputationResult : nsISupports {
+
+ // These should sync with 'VerdictType' defined in
+ // LoginReputationClientResponse in csd.proto.
+ const uint16_t UNSPECIFIED = 0;
+ const uint16_t SAFE = 1;
+ const uint16_t LOW_REPUTATION = 2;
+ const uint16_t PHISHING = 3;
+};
+
+[scriptable, uuid(c21ffe59-595f-46c8-9052-fefb639e196e)]
+interface nsILoginReputationQuery : nsISupports {
+ readonly attribute nsIURI formURI;
+};
+
+[scriptable, uuid(b527be1e-8fbb-41d9-bee4-267a71236368)]
+interface nsILoginReputationQueryCallback : nsISupports {
+ // aResult should be one of the const value defined in nsILoginReputationResult
+ // interface.
+ void onQueryComplete(in uint16_t aResult);
+};
+
+[scriptable, uuid(1b3f1dfe-ce3a-486b-953e-ce5ac863eff9)]
+interface nsILoginReputationService : nsISupports {
+ void init();
+
+ // If QueryReputationAsync is called from child, it will make a IPC call
+ // to parent.
+ void queryReputationAsync(in nsIDOMHTMLInputElement aInput,
+ in nsILoginReputationQueryCallback aCallback);
+
+ // QueryReputation can only be called from parent
+ void queryReputation(in nsILoginReputationQuery aQuery,
+ in nsILoginReputationQueryCallback aCallback);
+};
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -67,18 +67,19 @@ GetFormAutoComplete()
ClearOnShutdown(&sInstance);
sInitialized = true;
}
}
return sInstance;
}
NS_IMPL_CYCLE_COLLECTION(nsFormFillController,
- mController, mLoginManager, mFocusedPopup, mDocShells,
- mPopups, mLastListener, mLastFormAutoComplete)
+ mController, mLoginManager, mLoginReputationService,
+ mFocusedPopup, mDocShells, mPopups, mLastListener,
+ mLastFormAutoComplete)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormFillController)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFormFillController)
NS_INTERFACE_MAP_ENTRY(nsIFormFillController)
NS_INTERFACE_MAP_ENTRY(nsIAutoCompleteInput)
NS_INTERFACE_MAP_ENTRY(nsIAutoCompleteSearch)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIFormAutoCompleteObserver)
@@ -892,16 +893,34 @@ nsFormFillController::StopSearch()
mLastFormAutoComplete->StopAutoCompleteSearch();
mLastFormAutoComplete = nullptr;
} else if (mLoginManager) {
mLoginManager->StopSearch();
}
return NS_OK;
}
+nsresult
+nsFormFillController::StartQueryLoginReputation(nsIDOMHTMLInputElement *aInput)
+{
+ if (!mLoginReputationService) {
+ mLoginReputationService =
+ do_GetService(NS_LOGIN_REPUTATION_SERVICE_CONTRACTID);
+ if (NS_WARN_IF(!mLoginReputationService)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mLoginReputationService->Init();
+ }
+
+ mLoginReputationService->QueryReputationAsync(aInput, nullptr);
+
+ return NS_OK;
+}
+
////////////////////////////////////////////////////////////////////////
//// nsIFormAutoCompleteObserver
NS_IMETHODIMP
nsFormFillController::OnSearchCompletion(nsIAutoCompleteResult *aResult)
{
nsAutoString searchString;
aResult->GetSearchString(searchString);
@@ -1070,16 +1089,25 @@ nsFormFillController::MaybeStartControll
bool isAutofillInput = false;
if (mAutofillInputs.Get(inputNode)) {
isAutofillInput = true;
}
if (isAutofillInput || isPwmgrInput || hasList || autocomplete) {
StartControllingInput(aInput);
}
+
+#ifdef NIGHTLY_BUILD
+ // Trigger an asynchronous login reputation query when user focuses on the
+ // password field.
+ if (formControl->ControlType() == NS_FORM_INPUT_PASSWORD) {
+ StartQueryLoginReputation(aInput);
+ }
+#endif
+
}
nsresult
nsFormFillController::Focus(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(
aEvent->InternalDOMEvent()->GetTarget());
MaybeStartControllingInput(input);
--- a/toolkit/components/satchel/nsFormFillController.h
+++ b/toolkit/components/satchel/nsFormFillController.h
@@ -16,16 +16,17 @@
#include "nsCOMPtr.h"
#include "nsDataHashtable.h"
#include "nsIDocShell.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsILoginManager.h"
#include "nsIMutationObserver.h"
#include "nsTArray.h"
#include "nsCycleCollectionParticipant.h"
+#include "nsILoginReputation.h"
// X.h defines KeyPress
#ifdef KeyPress
#undef KeyPress
#endif
class nsFormHistory;
class nsINode;
@@ -84,20 +85,23 @@ protected:
void MaybeRemoveMutationObserver(nsINode* aNode);
void RemoveForDocument(nsIDocument* aDoc);
bool IsEventTrusted(nsIDOMEvent *aEvent);
bool IsTextControl(nsINode* aNode);
+ nsresult StartQueryLoginReputation(nsIDOMHTMLInputElement *aInput);
+
// members //////////////////////////////////////////
nsCOMPtr<nsIAutoCompleteController> mController;
nsCOMPtr<nsILoginManager> mLoginManager;
+ nsCOMPtr<nsILoginReputationService> mLoginReputationService;
nsIDOMHTMLInputElement* mFocusedInput;
nsINode* mFocusedInputNode;
// mListNode is a <datalist> element which, is set, has the form fill controller
// as a mutation observer for it.
nsINode* mListNode;
nsCOMPtr<nsIAutoCompletePopup> mFocusedPopup;