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