diff --git a/dom/webauthn/WebAuthnManager.cpp b/dom/webauthn/WebAuthnManager.cpp index 8356802255791..93828caed49f0 100644 --- a/dom/webauthn/WebAuthnManager.cpp +++ b/dom/webauthn/WebAuthnManager.cpp @@ -42,7 +42,10 @@ StaticRefPtr gWebAuthnManager; static mozilla::LazyLogModule gWebAuthnManagerLog("webauthnmanager"); } -NS_IMPL_ISUPPORTS(WebAuthnManager, nsIIPCBackgroundChildCreateCallback); +NS_NAMED_LITERAL_STRING(kVisibilityChange, "visibilitychange"); + +NS_IMPL_ISUPPORTS(WebAuthnManager, nsIIPCBackgroundChildCreateCallback, + nsIDOMEventListener); /*********************************************************************** * Utility Functions @@ -131,6 +134,7 @@ nsresult GetOrigin(nsPIDOMWindowInner* aParent, /*out*/ nsAString& aOrigin, /*out*/ nsACString& aHost) { + MOZ_ASSERT(aParent); nsCOMPtr doc = aParent->GetDoc(); MOZ_ASSERT(doc); @@ -168,6 +172,7 @@ RelaxSameOrigin(nsPIDOMWindowInner* aParent, MOZ_ASSERT(aParent); nsCOMPtr doc = aParent->GetDoc(); MOZ_ASSERT(doc); + nsCOMPtr principal = doc->NodePrincipal(); nsCOMPtr uri; if (NS_FAILED(principal->GetURI(getter_AddRefs(uri)))) { @@ -212,6 +217,41 @@ RelaxSameOrigin(nsPIDOMWindowInner* aParent, return NS_OK; } +static void +ListenForVisibilityEvents(nsPIDOMWindowInner* aParent, + WebAuthnManager* aListener) +{ + MOZ_ASSERT(aParent); + MOZ_ASSERT(aListener); + + nsCOMPtr doc = aParent->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + return; + } + + nsresult rv = doc->AddSystemEventListener(kVisibilityChange, aListener, + /* use capture */ true, + /* wants untrusted */ false); + Unused << NS_WARN_IF(NS_FAILED(rv)); +} + +static void +StopListeningForVisibilityEvents(nsPIDOMWindowInner* aParent, + WebAuthnManager* aListener) +{ + MOZ_ASSERT(aParent); + MOZ_ASSERT(aListener); + + nsCOMPtr doc = aParent->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + return; + } + + nsresult rv = doc->RemoveSystemEventListener(kVisibilityChange, aListener, + /* use capture */ true); + Unused << NS_WARN_IF(NS_FAILED(rv)); +} + /*********************************************************************** * WebAuthnManager Implementation **********************************************************************/ @@ -227,6 +267,11 @@ WebAuthnManager::MaybeClearTransaction() mClientData.reset(); mInfo.reset(); mTransactionPromise = nullptr; + if (mCurrentParent) { + StopListeningForVisibilityEvents(mCurrentParent, this); + mCurrentParent = nullptr; + } + if (mChild) { RefPtr c; mChild.swap(c); @@ -503,6 +548,8 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, mClientData = Some(clientDataJSON); mCurrentParent = aParent; mInfo = Some(info); + ListenForVisibilityEvents(aParent, this); + return promise.forget(); } @@ -520,6 +567,13 @@ WebAuthnManager::StartSign() { } } +void +WebAuthnManager::StartCancel() { + if (mChild) { + mChild->SendRequestCancel(); + } +} + already_AddRefed WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent, const PublicKeyCredentialRequestOptions& aOptions) @@ -669,6 +723,8 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent, mClientData = Some(clientDataJSON); mCurrentParent = aParent; mInfo = Some(info); + ListenForVisibilityEvents(aParent, this); + return promise.forget(); } @@ -877,12 +933,41 @@ WebAuthnManager::FinishGetAssertion(nsTArray& aCredentialId, void WebAuthnManager::Cancel(const nsresult& aError) { + MOZ_ASSERT(NS_IsMainThread()); + if (mTransactionPromise) { mTransactionPromise->MaybeReject(aError); } + MaybeClearTransaction(); } +NS_IMETHODIMP +WebAuthnManager::HandleEvent(nsIDOMEvent* aEvent) +{ + MOZ_ASSERT(aEvent); + + nsAutoString type; + aEvent->GetType(type); + if (!type.Equals(kVisibilityChange)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr doc = + do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget()); + MOZ_ASSERT(doc); + + if (doc && doc->Hidden()) { + MOZ_LOG(gWebAuthnManagerLog, LogLevel::Debug, + ("Visibility change: WebAuthn window is hidden, cancelling job.")); + + StartCancel(); + Cancel(NS_ERROR_ABORT); + } + + return NS_OK; +} + void WebAuthnManager::ActorCreated(PBackgroundChild* aActor) { diff --git a/dom/webauthn/WebAuthnManager.h b/dom/webauthn/WebAuthnManager.h index 8e832742d70db..42efa7ae78633 100644 --- a/dom/webauthn/WebAuthnManager.h +++ b/dom/webauthn/WebAuthnManager.h @@ -8,7 +8,9 @@ #define mozilla_dom_WebAuthnManager_h #include "mozilla/MozPromise.h" +#include "mozilla/dom/Event.h" #include "mozilla/dom/PWebAuthnTransaction.h" +#include "nsIDOMEventListener.h" #include "nsIIPCBackgroundChildCreateCallback.h" /* @@ -61,10 +63,12 @@ class Promise; class WebAuthnTransactionChild; class WebAuthnTransactionInfo; -class WebAuthnManager final : public nsIIPCBackgroundChildCreateCallback +class WebAuthnManager final : public nsIIPCBackgroundChildCreateCallback, + public nsIDOMEventListener { public: NS_DECL_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER static WebAuthnManager* GetOrCreate(); static WebAuthnManager* Get(); @@ -88,6 +92,7 @@ class WebAuthnManager final : public nsIIPCBackgroundChildCreateCallback void StartRegister(); void StartSign(); + void StartCancel(); // nsIIPCbackgroundChildCreateCallback methods void ActorCreated(PBackgroundChild* aActor) override;