File: IdentityCredentialRequestManager.cpp

package info (click to toggle)
firefox 143.0.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,617,328 kB
  • sloc: cpp: 7,478,492; javascript: 6,417,157; ansic: 3,720,058; python: 1,396,372; xml: 627,523; asm: 438,677; java: 186,156; sh: 63,477; makefile: 19,171; objc: 13,059; perl: 12,983; yacc: 4,583; cs: 3,846; pascal: 3,405; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (159 lines) | stat: -rw-r--r-- 6,352 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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 "IdentityCredentialRequestManager.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsContentUtils.h"

namespace mozilla {

NS_IMPL_ISUPPORTS0(IdentityCredentialRequestManager);

StaticRefPtr<IdentityCredentialRequestManager>
    IdentityCredentialRequestManager::sSingleton;

// static
IdentityCredentialRequestManager*
IdentityCredentialRequestManager::GetInstance() {
  if (!sSingleton) {
    sSingleton = new IdentityCredentialRequestManager();
    ClearOnShutdown(&sSingleton);
  }
  return sSingleton;
}

RefPtr<MozPromise<std::tuple<nsCString, Maybe<nsCString>>, nsresult, true>>
IdentityCredentialRequestManager::GetTokenFromPopup(
    dom::WebIdentityParent* aRelyingPartyWindow, nsIURI* aURLToOpen) {
  MOZ_ASSERT(aRelyingPartyWindow);
  MOZ_ASSERT(aURLToOpen);

  // Create the promise that will be resolved *after* the child process opens
  // the window
  RefPtr<MozPromise<std::tuple<nsCString, Maybe<nsCString>>, nsresult,
                    true>::Private>
      result = new MozPromise<std::tuple<nsCString, Maybe<nsCString>>, nsresult,
                              true>::Private(__func__);
  NotNull<nsIURI*> uri = WrapNotNull(aURLToOpen);
  RefPtr<IdentityCredentialRequestManager> self = this;

  // Tell the RP child to open an IDP popup.
  // It will either resolve with a failing nsresult or a BC ID of the popup.
  aRelyingPartyWindow->SendOpenContinuationWindow(
      uri,
      [result, self](const dom::OpenContinuationWindowResponse& response) {
        // If it failed, reject now, rejecting the RP child's initial call.
        if (response.type() == dom::OpenContinuationWindowResponse::Tnsresult) {
          result->Reject(response.get_nsresult(), __func__);
          return;
        }
        // If we have a BC ID, a popup opened.
        if (response.type() == dom::OpenContinuationWindowResponse::Tuint64_t) {
          RefPtr<dom::CanonicalBrowsingContext> bc =
              dom::CanonicalBrowsingContext::Get(response.get_uint64_t());
          if (!bc) {
            result->Reject(NS_ERROR_DOM_NETWORK_ERR, __func__);
          }
          // Transform the BC ID into its top-chrome-window-bc, so we have
          // something stable through navigation and can listen for the popup's
          // close.
          dom::CanonicalBrowsingContext* chromeBC =
              bc->TopCrossChromeBoundary();
          if (!chromeBC) {
            result->Reject(NS_ERROR_DOM_NETWORK_ERR, __func__);
          }

          // There really shouldn't be more than one request per top window
          MOZ_ASSERT(!self->mPendingTokenRequests.Contains(chromeBC->Id()));

          // Insert a refptr to the promise so we can settle it later, and we
          // can find it by the BC id!
          self->mPendingTokenRequests.InsertOrUpdate(chromeBC->Id(), result);

          // If the window closes before we have a chance to resolve it,
          // remove the promise from our map and reject it.
          chromeBC->AddFinalDiscardListener([self](uint64_t id) {
            Maybe<RefPtr<MozPromise<std::tuple<nsCString, Maybe<nsCString>>,
                                    nsresult, true>::Private>>
                pending = self->mPendingTokenRequests.Extract(id);
            // If it already settled before the window closed, just drop the
            // promise ref.
            if (pending.isNothing()) {
              return;
            }
            pending.value()->Reject(NS_ERROR_DOM_NETWORK_ERR, __func__);
          });
        }
      },
      [result](const ipc::ResponseRejectReason& rejection) {
        result->Reject(NS_ERROR_DOM_NETWORK_ERR, __func__);
      });
  return result.forget();
}

nsresult IdentityCredentialRequestManager::MaybeResolvePopup(
    dom::WebIdentityParent* aPopupWindow, const nsCString& aToken,
    const dom::IdentityResolveOptions& aOptions) {
  // aPopupWindow is (theoretically) a popup window opened by
  // SendOpenContinuationWindow. So try to get its top chrome bc so we can  look
  // into the map!
  dom::WindowGlobalParent* manager =
      static_cast<dom::WindowGlobalParent*>(aPopupWindow->Manager());
  if (!manager) {
    return NS_ERROR_DOM_NOT_ALLOWED_ERR;
  }
  dom::CanonicalBrowsingContext* bc = manager->BrowsingContext();
  if (!bc) {
    return NS_ERROR_DOM_NOT_ALLOWED_ERR;
  }
  dom::CanonicalBrowsingContext* chromeBC = bc->TopCrossChromeBoundary();
  if (!chromeBC) {
    return NS_ERROR_DOM_NOT_ALLOWED_ERR;
  }

  // Get its entry, removing it from the map.
  Maybe<RefPtr<MozPromise<std::tuple<nsCString, Maybe<nsCString>>, nsresult,
                          true>::Private>>
      pendingPromise = mPendingTokenRequests.Extract(chromeBC->Id());

  // This will be Nothing if the function was called on a window not opened by
  // SendOpenContinuationWindow. This error will be forwarded along to the JS
  // caller.
  if (!pendingPromise.isSome()) {
    return NS_ERROR_DOM_NOT_ALLOWED_ERR;
  }
  // Convert the Optional to a Maybe and send a successful response to the RP
  // window that opened this popup.
  Maybe<nsCString> overrideAccountId = Nothing();
  if (aOptions.mAccountId.WasPassed()) {
    overrideAccountId = Some(aOptions.mAccountId.Value());
  }
  pendingPromise.value()->Resolve(std::make_tuple(aToken, overrideAccountId),
                                  __func__);
  return NS_OK;
}

bool IdentityCredentialRequestManager::IsActivePopup(
    dom::WebIdentityParent* aPopupWindow) {
  dom::WindowGlobalParent* manager =
      static_cast<dom::WindowGlobalParent*>(aPopupWindow->Manager());
  if (!manager) {
    return false;
  }
  dom::CanonicalBrowsingContext* bc = manager->BrowsingContext();
  if (!bc) {
    return false;
  }
  // Transform the BC ID into its top-chrome-window-bc, so we have
  // something stable through navigation and can listen for the popup's close.
  dom::CanonicalBrowsingContext* chromeBC = bc->TopCrossChromeBoundary();
  if (!chromeBC) {
    return false;
  }
  return mPendingTokenRequests.Contains(chromeBC->Id());
}

}  // namespace mozilla