Bug 1401019 - Cancel the current U2F API request before starting a new one r=jcj
authorTim Taubert <ttaubert@mozilla.com>
Tue, 19 Sep 2017 16:55:38 +0200
changeset 667086 8d3d707fe0485a8900c4794a0c55018ad722c6de
parent 667085 c8277ab2befdd4c5027741f12bc94a0870925542
child 667087 383a2f567cebe59b0212e414b9a27d46123040bf
push id80609
push userbmo:mstriemer@mozilla.com
push dateTue, 19 Sep 2017 17:59:49 +0000
reviewersjcj
bugs1401019
milestone57.0a1
Bug 1401019 - Cancel the current U2F API request before starting a new one r=jcj I wasn't sure what the right behavior for the U2F API is when `.sign()` or `.register()` is called but there's an ongoing request that wasn't fulfilled yet. I think it makes sense to deny the request (as we currently do) when a request of the same type is currently active. When however sign() -> register() or vice-versa is called then we should cancel the previous request and start the new one. From what I understand from reading the spec we definitely should call the callback before starting the new request. Bug #: 1401019 Differential Revision: https://phabricator.services.mozilla.com/D70
dom/u2f/U2F.cpp
dom/u2f/U2F.h
--- a/dom/u2f/U2F.cpp
+++ b/dom/u2f/U2F.cpp
@@ -218,17 +218,17 @@ U2F::Register(const nsAString& aAppId,
 
   RefPtr<U2FManager> mgr = U2FManager::GetOrCreate();
   MOZ_ASSERT(mgr);
   if (!mgr || mRegisterCallback.isSome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  MOZ_ASSERT(!mPromiseHolder.Exists());
+  Cancel();
   MOZ_ASSERT(mRegisterCallback.isNothing());
   mRegisterCallback = Some(nsMainThreadPtrHandle<U2FRegisterCallback>(
                         new nsMainThreadPtrHolder<U2FRegisterCallback>(
                             "U2F::Register::callback", &aCallback)));
 
   uint32_t adjustedTimeoutMillis = AdjustedTimeoutMillis(opt_aTimeoutSeconds);
 
   // Evaluate the AppID
@@ -315,17 +315,17 @@ U2F::Sign(const nsAString& aAppId,
 
   RefPtr<U2FManager> mgr = U2FManager::GetOrCreate();
   MOZ_ASSERT(mgr);
   if (!mgr || mSignCallback.isSome()) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  MOZ_ASSERT(!mPromiseHolder.Exists());
+  Cancel();
   MOZ_ASSERT(mSignCallback.isNothing());
   mSignCallback = Some(nsMainThreadPtrHandle<U2FSignCallback>(
                     new nsMainThreadPtrHolder<U2FSignCallback>(
                         "U2F::Sign::callback", &aCallback)));
 
   uint32_t adjustedTimeoutMillis = AdjustedTimeoutMillis(opt_aTimeoutSeconds);
 
   // Evaluate the AppID
@@ -380,10 +380,37 @@ U2F::Sign(const nsAString& aAppId,
               response.mErrorCode.Construct(static_cast<uint32_t>(aErrorCode));
 
               ExecuteCallback(response, localCb);
               localReqHolder.Complete();
           })
   ->Track(mPromiseHolder);
 }
 
+void
+U2F::Cancel()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  const ErrorCode errorCode = ErrorCode::OTHER_ERROR;
+
+  if (mRegisterCallback.isSome()) {
+    RegisterResponse response;
+    response.mErrorCode.Construct(static_cast<uint32_t>(errorCode));
+    ExecuteCallback(response, mRegisterCallback);
+  }
+
+  if (mSignCallback.isSome()) {
+    SignResponse response;
+    response.mErrorCode.Construct(static_cast<uint32_t>(errorCode));
+    ExecuteCallback(response, mSignCallback);
+  }
+
+  RefPtr<U2FManager> mgr = U2FManager::Get();
+  if (mgr) {
+    mgr->Cancel(NS_ERROR_DOM_OPERATION_ERR);
+  }
+
+  mPromiseHolder.DisconnectIfExists();
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/u2f/U2F.h
+++ b/dom/u2f/U2F.h
@@ -65,16 +65,19 @@ public:
   Sign(const nsAString& aAppId,
        const nsAString& aChallenge,
        const Sequence<RegisteredKey>& aRegisteredKeys,
        U2FSignCallback& aCallback,
        const Optional<Nullable<int32_t>>& opt_aTimeoutSeconds,
        ErrorResult& aRv);
 
 private:
+  void
+  Cancel();
+
   nsString mOrigin;
   nsCOMPtr<nsPIDOMWindowInner> mParent;
   nsCOMPtr<nsISerialEventTarget> mEventTarget;
   Maybe<nsMainThreadPtrHandle<U2FRegisterCallback>> mRegisterCallback;
   Maybe<nsMainThreadPtrHandle<U2FSignCallback>> mSignCallback;
   MozPromiseRequestHolder<U2FPromise> mPromiseHolder;
 
   ~U2F();