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 "mozilla/dom/MerchantValidationEvent.h"
8 #include "nsNetCID.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/dom/PaymentRequest.h"
11 #include "mozilla/dom/Location.h"
12 #include "mozilla/dom/URL.h"
13 #include "mozilla/ResultExtensions.h"
14 #include "nsIURI.h"
15 #include "nsNetUtil.h"
16 
17 namespace mozilla::dom {
18 
NS_IMPL_CYCLE_COLLECTION_INHERITED(MerchantValidationEvent,Event,mValidationURL,mRequest)19 NS_IMPL_CYCLE_COLLECTION_INHERITED(MerchantValidationEvent, Event,
20                                    mValidationURL, mRequest)
21 
22 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MerchantValidationEvent, Event)
23 NS_IMPL_CYCLE_COLLECTION_TRACE_END
24 
25 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MerchantValidationEvent)
26 NS_INTERFACE_MAP_END_INHERITING(Event)
27 
28 NS_IMPL_ADDREF_INHERITED(MerchantValidationEvent, Event)
29 NS_IMPL_RELEASE_INHERITED(MerchantValidationEvent, Event)
30 
31 // User-land code constructor
32 already_AddRefed<MerchantValidationEvent> MerchantValidationEvent::Constructor(
33     const GlobalObject& aGlobal, const nsAString& aType,
34     const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv) {
35   // validate passed URL
36   nsCOMPtr<mozilla::dom::EventTarget> owner =
37       do_QueryInterface(aGlobal.GetAsSupports());
38   return Constructor(owner, aType, aEventInitDict, aRv);
39 }
40 
41 // Internal JS object constructor
Constructor(EventTarget * aOwner,const nsAString & aType,const MerchantValidationEventInit & aEventInitDict,ErrorResult & aRv)42 already_AddRefed<MerchantValidationEvent> MerchantValidationEvent::Constructor(
43     EventTarget* aOwner, const nsAString& aType,
44     const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv) {
45   RefPtr<MerchantValidationEvent> e = new MerchantValidationEvent(aOwner);
46   bool trusted = e->Init(aOwner);
47   e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
48   e->init(aEventInitDict, aRv);
49   if (aRv.Failed()) {
50     return nullptr;
51   }
52   e->SetTrusted(trusted);
53   e->SetComposed(aEventInitDict.mComposed);
54   return e.forget();
55 }
56 
init(const MerchantValidationEventInit & aEventInitDict,ErrorResult & aRv)57 void MerchantValidationEvent::init(
58     const MerchantValidationEventInit& aEventInitDict, ErrorResult& aRv) {
59   // Check methodName is valid
60   if (!aEventInitDict.mMethodName.IsEmpty()) {
61     PaymentRequest::IsValidPaymentMethodIdentifier(aEventInitDict.mMethodName,
62                                                    aRv);
63     if (aRv.Failed()) {
64       return;
65     }
66   }
67   SetMethodName(aEventInitDict.mMethodName);
68   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetParentObject());
69   auto doc = window->GetExtantDoc();
70   if (!doc) {
71     aRv.ThrowAbortError("The owner document does not exist");
72     return;
73   }
74 
75   Result<OwningNonNull<nsIURI>, nsresult> rv =
76       doc->ResolveWithBaseURI(aEventInitDict.mValidationURL);
77   if (rv.isErr()) {
78     aRv.ThrowTypeError("validationURL cannot be parsed");
79     return;
80   }
81   mValidationURL = rv.unwrap();
82 }
83 
MerchantValidationEvent(EventTarget * aOwner)84 MerchantValidationEvent::MerchantValidationEvent(EventTarget* aOwner)
85     : Event(aOwner, nullptr, nullptr), mWaitForUpdate(false) {
86   MOZ_ASSERT(aOwner);
87 }
88 
ResolvedCallback(JSContext * aCx,JS::Handle<JS::Value> aValue)89 void MerchantValidationEvent::ResolvedCallback(JSContext* aCx,
90                                                JS::Handle<JS::Value> aValue) {
91   MOZ_ASSERT(aCx);
92   MOZ_ASSERT(mRequest);
93 
94   if (!mWaitForUpdate) {
95     return;
96   }
97   mWaitForUpdate = false;
98 
99   // If we eventually end up supporting merchant validation
100   // we would validate `aValue` here, as per:
101   // https://w3c.github.io/payment-request/#validate-merchant-s-details-algorithm
102   //
103   // Right now, MerchantValidationEvent is only implemented for standards
104   // conformance, which is why at this point we throw a
105   // NS_ERROR_DOM_NOT_SUPPORTED_ERR.
106 
107   ErrorResult result;
108   result.ThrowNotSupportedError(
109       "complete() is not supported by Firefox currently");
110   mRequest->AbortUpdate(result);
111   mRequest->SetUpdating(false);
112 }
113 
RejectedCallback(JSContext * aCx,JS::Handle<JS::Value> aValue)114 void MerchantValidationEvent::RejectedCallback(JSContext* aCx,
115                                                JS::Handle<JS::Value> aValue) {
116   MOZ_ASSERT(mRequest);
117   if (!mWaitForUpdate) {
118     return;
119   }
120   mWaitForUpdate = false;
121   ErrorResult result;
122   result.ThrowAbortError(
123       "The promise for MerchantValidtaionEvent.complete() is rejected");
124   mRequest->AbortUpdate(result);
125   mRequest->SetUpdating(false);
126 }
127 
Complete(Promise & aPromise,ErrorResult & aRv)128 void MerchantValidationEvent::Complete(Promise& aPromise, ErrorResult& aRv) {
129   if (!IsTrusted()) {
130     aRv.ThrowInvalidStateError("Called on an untrusted event");
131     return;
132   }
133 
134   MOZ_ASSERT(mRequest);
135 
136   if (mWaitForUpdate) {
137     aRv.ThrowInvalidStateError(
138         "The MerchantValidationEvent is waiting for update");
139     return;
140   }
141 
142   if (!mRequest->ReadyForUpdate()) {
143     aRv.ThrowInvalidStateError(
144         "The PaymentRequest state is not eInteractive or the PaymentRequest is "
145         "updating");
146     return;
147   }
148 
149   aPromise.AppendNativeHandler(this);
150 
151   StopPropagation();
152   StopImmediatePropagation();
153   mWaitForUpdate = true;
154   mRequest->SetUpdating(true);
155 }
156 
SetRequest(PaymentRequest * aRequest)157 void MerchantValidationEvent::SetRequest(PaymentRequest* aRequest) {
158   MOZ_ASSERT(IsTrusted());
159   MOZ_ASSERT(!mRequest);
160   MOZ_ASSERT(aRequest);
161 
162   mRequest = aRequest;
163 }
164 
GetValidationURL(nsAString & aValidationURL)165 void MerchantValidationEvent::GetValidationURL(nsAString& aValidationURL) {
166   nsAutoCString utf8href;
167   nsresult rv = mValidationURL->GetSpec(utf8href);
168   MOZ_ASSERT(NS_SUCCEEDED(rv));
169   Unused << rv;
170   aValidationURL.Assign(NS_ConvertUTF8toUTF16(utf8href));
171 }
172 
GetMethodName(nsAString & aMethodName)173 void MerchantValidationEvent::GetMethodName(nsAString& aMethodName) {
174   aMethodName.Assign(mMethodName);
175 }
176 
SetMethodName(const nsAString & aMethodName)177 void MerchantValidationEvent::SetMethodName(const nsAString& aMethodName) {
178   mMethodName.Assign(aMethodName);
179 }
180 
181 MerchantValidationEvent::~MerchantValidationEvent() = default;
182 
WrapObjectInternal(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)183 JSObject* MerchantValidationEvent::WrapObjectInternal(
184     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
185   return MerchantValidationEvent_Binding::Wrap(aCx, this, aGivenProto);
186 }
187 
188 }  // namespace mozilla::dom
189