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
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "BasicCardPayment.h"
8 #include "mozilla/ClearOnShutdown.h"
9 #include "mozilla/dom/BasicCardPaymentBinding.h"
10 #include "mozilla/dom/PaymentRequestParent.h"
11 #include "nsArrayUtils.h"
12 #include "nsComponentManagerUtils.h"
13 #include "nsCOMPtr.h"
14 #include "nsIMutableArray.h"
15 #include "nsServiceManagerUtils.h"
16 #include "nsSimpleEnumerator.h"
17 #include "PaymentRequestService.h"
18 
19 namespace mozilla::dom {
20 
21 StaticRefPtr<PaymentRequestService> gPaymentService;
22 
23 namespace {
24 
25 class PaymentRequestEnumerator final : public nsSimpleEnumerator {
26  public:
27   NS_DECL_NSISIMPLEENUMERATOR
28 
PaymentRequestEnumerator()29   PaymentRequestEnumerator() : mIndex(0) {}
30 
DefaultInterface()31   const nsID& DefaultInterface() override {
32     return NS_GET_IID(nsIPaymentRequest);
33   }
34 
35  private:
36   ~PaymentRequestEnumerator() override = default;
37   uint32_t mIndex;
38 };
39 
40 NS_IMETHODIMP
HasMoreElements(bool * aReturn)41 PaymentRequestEnumerator::HasMoreElements(bool* aReturn) {
42   NS_ENSURE_ARG_POINTER(aReturn);
43   *aReturn = false;
44   if (NS_WARN_IF(!gPaymentService)) {
45     return NS_ERROR_FAILURE;
46   }
47   RefPtr<PaymentRequestService> service = gPaymentService;
48   *aReturn = mIndex < service->NumPayments();
49   return NS_OK;
50 }
51 
52 NS_IMETHODIMP
GetNext(nsISupports ** aItem)53 PaymentRequestEnumerator::GetNext(nsISupports** aItem) {
54   NS_ENSURE_ARG_POINTER(aItem);
55   if (NS_WARN_IF(!gPaymentService)) {
56     return NS_ERROR_FAILURE;
57   }
58   RefPtr<payments::PaymentRequest> rowRequest =
59       gPaymentService->GetPaymentRequestByIndex(mIndex);
60   if (!rowRequest) {
61     return NS_ERROR_FAILURE;
62   }
63   mIndex++;
64   rowRequest.forget(aItem);
65   return NS_OK;
66 }
67 
68 }  // end of anonymous namespace
69 
70 /* PaymentRequestService */
71 
NS_IMPL_ISUPPORTS(PaymentRequestService,nsIPaymentRequestService)72 NS_IMPL_ISUPPORTS(PaymentRequestService, nsIPaymentRequestService)
73 
74 already_AddRefed<PaymentRequestService> PaymentRequestService::GetSingleton() {
75   MOZ_ASSERT(NS_IsMainThread());
76   if (!gPaymentService) {
77     gPaymentService = new PaymentRequestService();
78     ClearOnShutdown(&gPaymentService);
79   }
80   RefPtr<PaymentRequestService> service = gPaymentService;
81   return service.forget();
82 }
83 
NumPayments() const84 uint32_t PaymentRequestService::NumPayments() const {
85   return mRequestQueue.Length();
86 }
87 
88 already_AddRefed<payments::PaymentRequest>
GetPaymentRequestByIndex(const uint32_t aIndex)89 PaymentRequestService::GetPaymentRequestByIndex(const uint32_t aIndex) {
90   if (aIndex >= mRequestQueue.Length()) {
91     return nullptr;
92   }
93   RefPtr<payments::PaymentRequest> request = mRequestQueue[aIndex];
94   MOZ_ASSERT(request);
95   return request.forget();
96 }
97 
98 NS_IMETHODIMP
GetPaymentRequestById(const nsAString & aRequestId,nsIPaymentRequest ** aRequest)99 PaymentRequestService::GetPaymentRequestById(const nsAString& aRequestId,
100                                              nsIPaymentRequest** aRequest) {
101   NS_ENSURE_ARG_POINTER(aRequest);
102   *aRequest = nullptr;
103   RefPtr<payments::PaymentRequest> rowRequest;
104   nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(rowRequest));
105   if (NS_WARN_IF(NS_FAILED(rv))) {
106     return rv;
107   }
108   rowRequest.forget(aRequest);
109   return NS_OK;
110 }
111 
GetPaymentRequestById(const nsAString & aRequestId,payments::PaymentRequest ** aRequest)112 nsresult PaymentRequestService::GetPaymentRequestById(
113     const nsAString& aRequestId, payments::PaymentRequest** aRequest) {
114   NS_ENSURE_ARG_POINTER(aRequest);
115   *aRequest = nullptr;
116   uint32_t numRequests = mRequestQueue.Length();
117   for (uint32_t index = 0; index < numRequests; ++index) {
118     RefPtr<payments::PaymentRequest> request = mRequestQueue[index];
119     MOZ_ASSERT(request);
120     nsAutoString requestId;
121     nsresult rv = request->GetRequestId(requestId);
122     NS_ENSURE_SUCCESS(rv, rv);
123     if (requestId == aRequestId) {
124       request.forget(aRequest);
125       break;
126     }
127   }
128   return NS_OK;
129 }
130 
131 NS_IMETHODIMP
Enumerate(nsISimpleEnumerator ** aEnumerator)132 PaymentRequestService::Enumerate(nsISimpleEnumerator** aEnumerator) {
133   NS_ENSURE_ARG_POINTER(aEnumerator);
134   nsCOMPtr<nsISimpleEnumerator> enumerator = new PaymentRequestEnumerator();
135   enumerator.forget(aEnumerator);
136   return NS_OK;
137 }
138 
139 NS_IMETHODIMP
Cleanup()140 PaymentRequestService::Cleanup() {
141   mRequestQueue.Clear();
142   return NS_OK;
143 }
144 
145 NS_IMETHODIMP
SetTestingUIService(nsIPaymentUIService * aUIService)146 PaymentRequestService::SetTestingUIService(nsIPaymentUIService* aUIService) {
147   // aUIService can be nullptr
148   mTestingUIService = aUIService;
149   return NS_OK;
150 }
151 
LaunchUIAction(const nsAString & aRequestId,uint32_t aActionType)152 nsresult PaymentRequestService::LaunchUIAction(const nsAString& aRequestId,
153                                                uint32_t aActionType) {
154   nsCOMPtr<nsIPaymentUIService> uiService;
155   nsresult rv;
156   if (mTestingUIService) {
157     uiService = mTestingUIService;
158   } else {
159     uiService = do_GetService(NS_PAYMENT_UI_SERVICE_CONTRACT_ID, &rv);
160     if (NS_WARN_IF(NS_FAILED(rv))) {
161       return rv;
162     }
163   }
164   switch (aActionType) {
165     case IPCPaymentActionRequest::TIPCPaymentShowActionRequest: {
166       rv = uiService->ShowPayment(aRequestId);
167       break;
168     }
169     case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: {
170       rv = uiService->AbortPayment(aRequestId);
171       break;
172     }
173     case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: {
174       rv = uiService->CompletePayment(aRequestId);
175       break;
176     }
177     case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
178       rv = uiService->UpdatePayment(aRequestId);
179       break;
180     }
181     case IPCPaymentActionRequest::TIPCPaymentCloseActionRequest: {
182       rv = uiService->ClosePayment(aRequestId);
183       break;
184     }
185     default: {
186       return NS_ERROR_FAILURE;
187     }
188   }
189   if (NS_WARN_IF(NS_FAILED(rv))) {
190     return rv;
191   }
192   return NS_OK;
193 }
194 
RequestPayment(const nsAString & aRequestId,const IPCPaymentActionRequest & aAction,PaymentRequestParent * aIPC)195 nsresult PaymentRequestService::RequestPayment(
196     const nsAString& aRequestId, const IPCPaymentActionRequest& aAction,
197     PaymentRequestParent* aIPC) {
198   NS_ENSURE_ARG_POINTER(aIPC);
199 
200   nsresult rv = NS_OK;
201   uint32_t type = aAction.type();
202 
203   RefPtr<payments::PaymentRequest> request;
204   if (type != IPCPaymentActionRequest::TIPCPaymentCreateActionRequest) {
205     rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
206     if (NS_WARN_IF(NS_FAILED(rv))) {
207       return rv;
208     }
209     if (!request &&
210         type != IPCPaymentActionRequest::TIPCPaymentCloseActionRequest) {
211       return NS_ERROR_FAILURE;
212     }
213     if (request) {
214       request->SetIPC(aIPC);
215     }
216   }
217 
218   switch (type) {
219     case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
220       MOZ_ASSERT(!request);
221       const IPCPaymentCreateActionRequest& action = aAction;
222       nsCOMPtr<nsIMutableArray> methodData =
223           do_CreateInstance(NS_ARRAY_CONTRACTID);
224       MOZ_ASSERT(methodData);
225       for (IPCPaymentMethodData data : action.methodData()) {
226         nsCOMPtr<nsIPaymentMethodData> method;
227         rv = payments::PaymentMethodData::Create(data, getter_AddRefs(method));
228         NS_ENSURE_SUCCESS(rv, rv);
229         rv = methodData->AppendElement(method);
230         NS_ENSURE_SUCCESS(rv, rv);
231       }
232       nsCOMPtr<nsIPaymentDetails> details;
233       rv = payments::PaymentDetails::Create(action.details(),
234                                             getter_AddRefs(details));
235       NS_ENSURE_SUCCESS(rv, rv);
236       nsCOMPtr<nsIPaymentOptions> options;
237       rv = payments::PaymentOptions::Create(action.options(),
238                                             getter_AddRefs(options));
239       NS_ENSURE_SUCCESS(rv, rv);
240       RefPtr<payments::PaymentRequest> request = new payments::PaymentRequest(
241           action.topOuterWindowId(), aRequestId, action.topLevelPrincipal(),
242           methodData, details, options, action.shippingOption());
243 
244       if (!mRequestQueue.AppendElement(request, mozilla::fallible)) {
245         return NS_ERROR_OUT_OF_MEMORY;
246       }
247       break;
248     }
249     case IPCPaymentActionRequest::TIPCPaymentCanMakeActionRequest: {
250       nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
251           do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID);
252       MOZ_ASSERT(canMakeResponse);
253       rv = canMakeResponse->Init(aRequestId, CanMakePayment(aRequestId));
254       if (NS_WARN_IF(NS_FAILED(rv))) {
255         return rv;
256       }
257       rv = RespondPayment(canMakeResponse.get());
258       if (NS_WARN_IF(NS_FAILED(rv))) {
259         return rv;
260       }
261       break;
262     }
263     case IPCPaymentActionRequest::TIPCPaymentShowActionRequest: {
264       const IPCPaymentShowActionRequest& action = aAction;
265       rv = ShowPayment(aRequestId, action.isUpdating());
266       if (NS_WARN_IF(NS_FAILED(rv))) {
267         return rv;
268       }
269       break;
270     }
271     case IPCPaymentActionRequest::TIPCPaymentAbortActionRequest: {
272       MOZ_ASSERT(request);
273       request->SetState(payments::PaymentRequest::eInteractive);
274       rv = LaunchUIAction(aRequestId, type);
275       if (NS_WARN_IF(NS_FAILED(rv))) {
276         return rv;
277       }
278       break;
279     }
280     case IPCPaymentActionRequest::TIPCPaymentCompleteActionRequest: {
281       MOZ_ASSERT(request);
282       const IPCPaymentCompleteActionRequest& action = aAction;
283       request->SetCompleteStatus(action.completeStatus());
284       rv = LaunchUIAction(aRequestId, type);
285       if (NS_WARN_IF(NS_FAILED(rv))) {
286         return rv;
287       }
288       break;
289     }
290     case IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest: {
291       const IPCPaymentUpdateActionRequest& action = aAction;
292       nsCOMPtr<nsIPaymentDetails> details;
293       rv = payments::PaymentDetails::Create(action.details(),
294                                             getter_AddRefs(details));
295       if (NS_WARN_IF(NS_FAILED(rv))) {
296         return rv;
297       }
298       MOZ_ASSERT(request);
299       rv = request->UpdatePaymentDetails(details, action.shippingOption());
300       if (NS_WARN_IF(NS_FAILED(rv))) {
301         return rv;
302       }
303       nsAutoString completeStatus;
304       rv = request->GetCompleteStatus(completeStatus);
305       if (NS_WARN_IF(NS_FAILED(rv))) {
306         return rv;
307       }
308       if (completeStatus.Equals(u"initial"_ns)) {
309         request->SetCompleteStatus(u""_ns);
310       }
311       MOZ_ASSERT(mShowingRequest && mShowingRequest == request);
312       rv = LaunchUIAction(aRequestId, type);
313       if (NS_WARN_IF(NS_FAILED(rv))) {
314         return rv;
315       }
316       break;
317     }
318     case IPCPaymentActionRequest::TIPCPaymentCloseActionRequest: {
319       rv = LaunchUIAction(aRequestId, type);
320       if (NS_WARN_IF(NS_FAILED(rv))) {
321         return rv;
322       }
323       if (mShowingRequest == request) {
324         mShowingRequest = nullptr;
325       }
326       mRequestQueue.RemoveElement(request);
327       break;
328     }
329     case IPCPaymentActionRequest::TIPCPaymentRetryActionRequest: {
330       const IPCPaymentRetryActionRequest& action = aAction;
331       MOZ_ASSERT(request);
332       request->UpdateErrors(action.error(), action.payerErrors(),
333                             action.paymentMethodErrors(),
334                             action.shippingAddressErrors());
335       request->SetState(payments::PaymentRequest::eInteractive);
336       MOZ_ASSERT(mShowingRequest == request);
337       rv = LaunchUIAction(
338           aRequestId, IPCPaymentActionRequest::TIPCPaymentUpdateActionRequest);
339       break;
340     }
341     default: {
342       return NS_ERROR_FAILURE;
343     }
344   }
345   return NS_OK;
346 }
347 
348 NS_IMETHODIMP
RespondPayment(nsIPaymentActionResponse * aResponse)349 PaymentRequestService::RespondPayment(nsIPaymentActionResponse* aResponse) {
350   NS_ENSURE_ARG_POINTER(aResponse);
351   nsAutoString requestId;
352   nsresult rv = aResponse->GetRequestId(requestId);
353   NS_ENSURE_SUCCESS(rv, rv);
354 
355   RefPtr<payments::PaymentRequest> request;
356   rv = GetPaymentRequestById(requestId, getter_AddRefs(request));
357   if (NS_WARN_IF(NS_FAILED(rv))) {
358     return rv;
359   }
360   if (!request) {
361     return NS_ERROR_FAILURE;
362   }
363   uint32_t type;
364   rv = aResponse->GetType(&type);
365   NS_ENSURE_SUCCESS(rv, rv);
366 
367   // PaymentRequest can only be responded when
368   // 1. the state is eInteractive
369   // 2. the state is eClosed and response type is COMPLETE_ACTION
370   // 3. the state is eCreated and response type is CANMAKE_ACTION
371   payments::PaymentRequest::eState state = request->GetState();
372   bool canBeResponded = (state == payments::PaymentRequest::eInteractive) ||
373                         (state == payments::PaymentRequest::eClosed &&
374                          type == nsIPaymentActionResponse::COMPLETE_ACTION) ||
375                         (state == payments::PaymentRequest::eCreated &&
376                          type == nsIPaymentActionResponse::CANMAKE_ACTION);
377   if (!canBeResponded) {
378     return NS_ERROR_FAILURE;
379   }
380 
381   if (!request->GetIPC()) {
382     return NS_ERROR_FAILURE;
383   }
384   rv = request->GetIPC()->RespondPayment(aResponse);
385   if (NS_WARN_IF(NS_FAILED(rv))) {
386     return rv;
387   }
388 
389   // Remove PaymentRequest from mRequestQueue while receive succeeded abort
390   // response or complete response
391   switch (type) {
392     case nsIPaymentActionResponse::ABORT_ACTION: {
393       nsCOMPtr<nsIPaymentAbortActionResponse> response =
394           do_QueryInterface(aResponse);
395       MOZ_ASSERT(response);
396       bool isSucceeded;
397       rv = response->IsSucceeded(&isSucceeded);
398       NS_ENSURE_SUCCESS(rv, rv);
399       mShowingRequest = nullptr;
400       if (isSucceeded) {
401         mRequestQueue.RemoveElement(request);
402         request->SetState(payments::PaymentRequest::eClosed);
403       }
404       break;
405     }
406     case nsIPaymentActionResponse::SHOW_ACTION: {
407       request->SetState(payments::PaymentRequest::eClosed);
408       nsCOMPtr<nsIPaymentShowActionResponse> response =
409           do_QueryInterface(aResponse);
410       MOZ_ASSERT(response);
411       uint32_t acceptStatus;
412       rv = response->GetAcceptStatus(&acceptStatus);
413       NS_ENSURE_SUCCESS(rv, rv);
414       if (acceptStatus != nsIPaymentActionResponse::PAYMENT_ACCEPTED) {
415         // Check if rejecting the showing PaymentRequest.
416         // If yes, set mShowingRequest as nullptr.
417         if (mShowingRequest == request) {
418           mShowingRequest = nullptr;
419         }
420         mRequestQueue.RemoveElement(request);
421       }
422       break;
423     }
424     case nsIPaymentActionResponse::COMPLETE_ACTION: {
425       mShowingRequest = nullptr;
426       mRequestQueue.RemoveElement(request);
427       break;
428     }
429     default: {
430       break;
431     }
432   }
433   return NS_OK;
434 }
435 
436 NS_IMETHODIMP
ChangeShippingAddress(const nsAString & aRequestId,nsIPaymentAddress * aAddress)437 PaymentRequestService::ChangeShippingAddress(const nsAString& aRequestId,
438                                              nsIPaymentAddress* aAddress) {
439   RefPtr<payments::PaymentRequest> request;
440   nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
441   if (NS_WARN_IF(NS_FAILED(rv))) {
442     return rv;
443   }
444   if (!request) {
445     return NS_ERROR_FAILURE;
446   }
447   if (request->GetState() != payments::PaymentRequest::eInteractive) {
448     return NS_ERROR_FAILURE;
449   }
450   if (!request->GetIPC()) {
451     return NS_ERROR_FAILURE;
452   }
453   rv = request->GetIPC()->ChangeShippingAddress(aRequestId, aAddress);
454   if (NS_WARN_IF(NS_FAILED(rv))) {
455     return rv;
456   }
457   return NS_OK;
458 }
459 
460 NS_IMETHODIMP
ChangeShippingOption(const nsAString & aRequestId,const nsAString & aOption)461 PaymentRequestService::ChangeShippingOption(const nsAString& aRequestId,
462                                             const nsAString& aOption) {
463   RefPtr<payments::PaymentRequest> request;
464   nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
465   if (NS_WARN_IF(NS_FAILED(rv))) {
466     return rv;
467   }
468   if (!request) {
469     return NS_ERROR_FAILURE;
470   }
471   if (request->GetState() != payments::PaymentRequest::eInteractive) {
472     return NS_ERROR_FAILURE;
473   }
474   if (!request->GetIPC()) {
475     return NS_ERROR_FAILURE;
476   }
477   rv = request->GetIPC()->ChangeShippingOption(aRequestId, aOption);
478   if (NS_WARN_IF(NS_FAILED(rv))) {
479     return rv;
480   }
481   return NS_OK;
482 }
483 
484 NS_IMETHODIMP
ChangePayerDetail(const nsAString & aRequestId,const nsAString & aPayerName,const nsAString & aPayerEmail,const nsAString & aPayerPhone)485 PaymentRequestService::ChangePayerDetail(const nsAString& aRequestId,
486                                          const nsAString& aPayerName,
487                                          const nsAString& aPayerEmail,
488                                          const nsAString& aPayerPhone) {
489   RefPtr<payments::PaymentRequest> request;
490   nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
491   if (NS_WARN_IF(NS_FAILED(rv))) {
492     return rv;
493   }
494   MOZ_ASSERT(request);
495   if (!request->GetIPC()) {
496     return NS_ERROR_FAILURE;
497   }
498   rv = request->GetIPC()->ChangePayerDetail(aRequestId, aPayerName, aPayerEmail,
499                                             aPayerPhone);
500   if (NS_WARN_IF(NS_FAILED(rv))) {
501     return rv;
502   }
503   return NS_OK;
504 }
505 
506 NS_IMETHODIMP
ChangePaymentMethod(const nsAString & aRequestId,const nsAString & aMethodName,nsIMethodChangeDetails * aMethodDetails)507 PaymentRequestService::ChangePaymentMethod(
508     const nsAString& aRequestId, const nsAString& aMethodName,
509     nsIMethodChangeDetails* aMethodDetails) {
510   RefPtr<payments::PaymentRequest> request;
511   nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
512   if (NS_WARN_IF(NS_FAILED(rv))) {
513     return rv;
514   }
515   if (!request) {
516     return NS_ERROR_FAILURE;
517   }
518   if (request->GetState() != payments::PaymentRequest::eInteractive) {
519     return NS_ERROR_FAILURE;
520   }
521   if (!request->GetIPC()) {
522     return NS_ERROR_FAILURE;
523   }
524   rv = request->GetIPC()->ChangePaymentMethod(aRequestId, aMethodName,
525                                               aMethodDetails);
526   if (NS_WARN_IF(NS_FAILED(rv))) {
527     return rv;
528   }
529   return NS_OK;
530 }
531 
CanMakePayment(const nsAString & aRequestId)532 bool PaymentRequestService::CanMakePayment(const nsAString& aRequestId) {
533   /*
534    *  TODO: Check third party payment app support by traversing all
535    *        registered third party payment apps.
536    */
537   return IsBasicCardPayment(aRequestId);
538 }
539 
ShowPayment(const nsAString & aRequestId,bool aIsUpdating)540 nsresult PaymentRequestService::ShowPayment(const nsAString& aRequestId,
541                                             bool aIsUpdating) {
542   nsresult rv;
543   RefPtr<payments::PaymentRequest> request;
544   rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
545   if (NS_WARN_IF(NS_FAILED(rv))) {
546     return rv;
547   }
548   MOZ_ASSERT(request);
549   request->SetState(payments::PaymentRequest::eInteractive);
550   if (aIsUpdating) {
551     request->SetCompleteStatus(u"initial"_ns);
552   }
553 
554   if (mShowingRequest || !CanMakePayment(aRequestId)) {
555     uint32_t responseStatus;
556     if (mShowingRequest) {
557       responseStatus = nsIPaymentActionResponse::PAYMENT_REJECTED;
558     } else {
559       responseStatus = nsIPaymentActionResponse::PAYMENT_NOTSUPPORTED;
560     }
561     nsCOMPtr<nsIPaymentShowActionResponse> showResponse =
562         do_CreateInstance(NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID);
563     MOZ_ASSERT(showResponse);
564     rv = showResponse->Init(aRequestId, responseStatus, u""_ns, nullptr, u""_ns,
565                             u""_ns, u""_ns);
566     rv = RespondPayment(showResponse.get());
567     if (NS_WARN_IF(NS_FAILED(rv))) {
568       return rv;
569     }
570   } else {
571     mShowingRequest = request;
572     rv = LaunchUIAction(aRequestId,
573                         IPCPaymentActionRequest::TIPCPaymentShowActionRequest);
574     if (NS_WARN_IF(NS_FAILED(rv))) {
575       return rv;
576     }
577   }
578   return NS_OK;
579 }
580 
IsBasicCardPayment(const nsAString & aRequestId)581 bool PaymentRequestService::IsBasicCardPayment(const nsAString& aRequestId) {
582   RefPtr<payments::PaymentRequest> request;
583   nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(request));
584   NS_ENSURE_SUCCESS(rv, false);
585   nsCOMPtr<nsIArray> methods;
586   rv = request->GetPaymentMethods(getter_AddRefs(methods));
587   NS_ENSURE_SUCCESS(rv, false);
588   uint32_t length;
589   rv = methods->GetLength(&length);
590   NS_ENSURE_SUCCESS(rv, false);
591   RefPtr<BasicCardService> service = BasicCardService::GetService();
592   MOZ_ASSERT(service);
593   for (uint32_t index = 0; index < length; ++index) {
594     nsCOMPtr<nsIPaymentMethodData> method = do_QueryElementAt(methods, index);
595     MOZ_ASSERT(method);
596     nsAutoString supportedMethods;
597     rv = method->GetSupportedMethods(supportedMethods);
598     NS_ENSURE_SUCCESS(rv, false);
599     if (service->IsBasicCardPayment(supportedMethods)) {
600       return true;
601     }
602   }
603   return false;
604 }
605 
606 }  // namespace mozilla::dom
607