Bug 1375345 - Basic card payment implementation. r=baku

--HG--
extra : rebase_source : d581a1e117bdfc041940911487187620c5ed35ff
This commit is contained in:
Eden Chuang 2017-07-26 16:07:07 +08:00
Родитель 3061742432
Коммит 4a1f15b449
18 изменённых файлов: 897 добавлений и 26 удалений

Просмотреть файл

@ -5,6 +5,48 @@
#include "nsISupports.idl"
#include "nsIVariant.idl"
#include "nsIPaymentAddress.idl"
[builtinclass, scriptable, uuid(2a338575-c688-40ee-a157-7488ab292ef2)]
interface nsIPaymentResponseData: nsISupports
{
const uint32_t GENERAL_RESPONSE = 0;
const uint32_t BASICCARD_RESPONSE = 1;
readonly attribute uint32_t type;
void init(in uint32_t aType);
};
[builtinclass, scriptable, uuid(b986773e-2b30-4ed2-b8fe-6a96631c8000)]
interface nsIGeneralResponseData : nsIPaymentResponseData
{
readonly attribute AString data;
[implicit_jscontext]
void initData(in jsval aData);
};
/*
Since PaymentAddress is an no constructor interface type, UI code can not
easy create PaymentAddress by calling new PaymentAddress().
Unfortunately, BasicCardResponse has a PaymentAddress attribute, billingAddress
, it means UI can not create BsaicCardResponse by calling the init() with a
given JSObject directly, because PaymentAddress creation in JS code is hard.
To let UI code can create BasicCardResponse easier, nsIBasicCardResponse is
provided for UI by passing the raw data of BasicCardResponse,
*/
[builtinclass, scriptable, uuid(0d55a5e6-d185-44f0-b992-a8e1321e4bce)]
interface nsIBasicCardResponseData : nsIPaymentResponseData
{
readonly attribute AString data;
void initData(in AString aCardholderName,
in AString aCardNumber,
in AString aExpiryMonth,
in AString aExpiryYear,
in AString aCardSecurityCode,
in nsIPaymentAddress billingAddress);
};
[builtinclass, scriptable, uuid(a607c095-ef60-4a9b-a3d0-0506c60728b3)]
interface nsIPaymentActionResponse : nsISupports
@ -94,7 +136,7 @@ interface nsIPaymentShowActionResponse : nsIPaymentActionResponse
void init(in AString aRequestId,
in uint32_t aAcceptStatus,
in AString aMethodName,
in AString aData,
in nsIPaymentResponseData aData,
in AString aPayerName,
in AString aPayerEmail,
in AString aPayerPhone);
@ -142,6 +184,16 @@ interface nsIPaymentCompleteActionResponse : nsIPaymentActionResponse
};
%{C++
#define NS_GENERAL_RESPONSE_DATA_CID \
{ 0xb986773e, 0x2b30, 0x4ed2, { 0xb8, 0xfe, 0x6a, 0x96, 0x63, 0x1c, 0x80, 0x00 } }
#define NS_GENERAL_RESPONSE_DATA_CONTRACT_ID \
"@mozilla.org/dom/payments/general-response-data;1"
#define NS_BASICCARD_RESPONSE_DATA_CID \
{ 0x0d55a5e6, 0xd185, 0x44f0, { 0xb9, 0x92, 0xa8, 0xe1, 0x32, 0x1e, 0x4b, 0xce } }
#define NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID \
"@mozilla.org/dom/payments/basiccard-response-data;1"
#define NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CID \
{ 0x52fc3f9f, 0xc0cb, 0x4874, { 0xb3, 0xd4, 0xee, 0x4b, 0x6e, 0x9c, 0xbe, 0x9c } }
#define NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID \

Просмотреть файл

@ -12,7 +12,8 @@ interface nsIArray;
interface nsIPaymentMethodData : nsISupports
{
readonly attribute AString supportedMethods;
readonly attribute AString data;
[implicit_jscontext]
readonly attribute jsval data;
};
[scriptable, builtinclass, uuid(d22a6f5f-767b-4fea-bf92-68b0b8003eba)]
@ -36,7 +37,8 @@ interface nsIPaymentDetailsModifier : nsISupports
readonly attribute AString supportedMethods;
readonly attribute nsIPaymentItem total;
readonly attribute nsIArray additionalDisplayItems;
readonly attribute AString data;
[implicit_jscontext]
readonly attribute jsval data;
};
[scriptable, builtinclass, uuid(68341551-3605-4381-b936-41e830aa88fb)]

Просмотреть файл

@ -0,0 +1,390 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "BasicCardPayment.h"
#include "PaymentAddress.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsArrayUtils.h"
#include "nsISupportsPrimitives.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsDataHashtable.h"
namespace mozilla {
namespace dom {
#ifndef PaymentBasicCardMacros
#define PaymentBasicCardMacros
#define AMEX NS_LITERAL_STRING("amex")
#define CARTEBANCAIRE NS_LITERAL_STRING("cartebancaire")
#define DINERS NS_LITERAL_STRING("diners")
#define DISCOVER NS_LITERAL_STRING("discover")
#define JCB NS_LITERAL_STRING("jcb")
#define MASTERCARD NS_LITERAL_STRING("mastercard")
#define MIR NS_LITERAL_STRING("mir")
#define UNIONPAY NS_LITERAL_STRING("unionpay")
#define VISA NS_LITERAL_STRING("visa")
#define CardholderName NS_LITERAL_STRING("cardholderName")
#define CardNumber NS_LITERAL_STRING("cardNumber")
#define ExpiryMonth NS_LITERAL_STRING("expiryMonth")
#define ExpiryYear NS_LITERAL_STRING("expiryYear")
#define CardSecurityCode NS_LITERAL_STRING("cardSecurityCode")
#define Country NS_LITERAL_STRING("country")
#define AddressLine NS_LITERAL_STRING("addressLine")
#define Region NS_LITERAL_STRING("region")
#define City NS_LITERAL_STRING("city")
#define DependentLocality NS_LITERAL_STRING("dependentLocality")
#define PostalCode NS_LITERAL_STRING("postalCode")
#define SortingCode NS_LITERAL_STRING("sortingCode")
#define LanguageCode NS_LITERAL_STRING("languageCode")
#define Organization NS_LITERAL_STRING("organization")
#define Recipient NS_LITERAL_STRING("recipient")
#define Phone NS_LITERAL_STRING("phone")
#define PropertySpliter NS_LITERAL_STRING(";")
#define KeyValueSpliter NS_LITERAL_STRING(":")
#define AddressLineSpliter NS_LITERAL_STRING("%")
#define EncodeBasicCardProperty(aPropertyName, aPropertyValue, aResult) \
do { \
if (!(aPropertyValue).IsEmpty()) { \
(aResult) += (aPropertyName) \
+ KeyValueSpliter \
+ (aPropertyValue) \
+ PropertySpliter; \
} \
} while(0)
#define EncodeAddressProperty(aAddress, aPropertyName, aResult) \
do { \
nsAutoString propertyValue; \
NS_ENSURE_SUCCESS((aAddress)->Get##aPropertyName(propertyValue), \
NS_ERROR_FAILURE); \
EncodeBasicCardProperty((aPropertyName) ,propertyValue , (aResult)); \
} while(0)
#define DecodeBasicCardProperty(aPropertyName, aPropertyValue, \
aMatchPropertyName, aResponse) \
do { \
if ((aPropertyName).Equals((aMatchPropertyName))) { \
(aResponse).m##aMatchPropertyName.Construct(); \
(aResponse).m##aMatchPropertyName.Value() = (aPropertyValue); \
} \
} while(0)
#define DecodeAddressProperty(aPropertyName, aPropertyValue, \
aMatchPropertyName, aMatchPropertyValue) \
do { \
if ((aPropertyName).Equals((aMatchPropertyName))) { \
(aMatchPropertyValue) = (aPropertyValue); \
} \
} while(0)
#endif
namespace {
bool IsValidNetwork(const nsAString& aNetwork)
{
return AMEX.Equals(aNetwork) ||
CARTEBANCAIRE.Equals(aNetwork) ||
DINERS.Equals(aNetwork) ||
DISCOVER.Equals(aNetwork) ||
JCB.Equals(aNetwork) ||
MASTERCARD.Equals(aNetwork) ||
MIR.Equals(aNetwork) ||
UNIONPAY.Equals(aNetwork) ||
VISA.Equals(aNetwork);
}
bool IsBasicCardKey(const nsAString& aKey)
{
return CardholderName.Equals(aKey) ||
CardNumber.Equals(aKey) ||
ExpiryMonth.Equals(aKey) ||
ExpiryYear.Equals(aKey) ||
CardSecurityCode.Equals(aKey);
}
bool IsAddressKey(const nsAString& aKey)
{
return Country.Equals(aKey) ||
AddressLine.Equals(aKey) ||
Region.Equals(aKey) ||
City.Equals(aKey) ||
DependentLocality.Equals(aKey) ||
PostalCode.Equals(aKey) ||
SortingCode.Equals(aKey) ||
LanguageCode.Equals(aKey) ||
Organization.Equals(aKey) ||
Recipient.Equals(aKey) ||
Phone.Equals(aKey);
}
} // end of namespace
StaticRefPtr<BasicCardService> gBasicCardService;
already_AddRefed<BasicCardService>
BasicCardService::GetService()
{
if (!gBasicCardService) {
gBasicCardService = new BasicCardService();
ClearOnShutdown(&gBasicCardService);
}
RefPtr<BasicCardService> service = gBasicCardService;
return service.forget();
}
bool
BasicCardService::IsBasicCardPayment(const nsAString& aSupportedMethods)
{
return aSupportedMethods.Equals(NS_LITERAL_STRING("basic-card"));
}
bool
BasicCardService::IsValidBasicCardRequest(JSContext* aCx,
JSObject* aData,
nsAString& aErrorMsg)
{
if (!aData) {
return true;
}
JS::RootedValue data(aCx, JS::ObjectValue(*aData));
BasicCardRequest request;
if (!request.Init(aCx, data)) {
aErrorMsg.AssignLiteral("Fail to convert methodData.data to BasicCardRequest.");
return false;
}
if (request.mSupportedNetworks.WasPassed()) {
for (const nsString& network : request.mSupportedNetworks.Value()) {
if (!IsValidNetwork(network)) {
aErrorMsg.Assign(network + NS_LITERAL_STRING(" is not an valid network."));
return false;
}
}
}
return true;
}
bool
BasicCardService::IsValidExpiryMonth(const nsAString& aExpiryMonth)
{
// ExpiryMonth can only be
// 1. empty string
// 2. 01 ~ 12
if (aExpiryMonth.IsEmpty()) {
return true;
}
if (aExpiryMonth.Length() != 2) {
return false;
}
// can only be 00 ~ 09
if (aExpiryMonth.CharAt(0) == '0') {
if (aExpiryMonth.CharAt(1) < '0' || aExpiryMonth.CharAt(1) > '9') {
return false;
}
return true;
}
// can only be 11 or 12
if (aExpiryMonth.CharAt(0) == '1') {
if (aExpiryMonth.CharAt(1) != '1' && aExpiryMonth.CharAt(1) != '2') {
return false;
}
return true;
}
return false;
}
bool
BasicCardService::IsValidExpiryYear(const nsAString& aExpiryYear)
{
// ExpiryYear can only be
// 1. empty string
// 2. 0000 ~ 9999
if (!aExpiryYear.IsEmpty()) {
if (aExpiryYear.Length() != 4) {
return false;
}
for (uint32_t index = 0; index < 4; ++index) {
if (aExpiryYear.CharAt(index) < '0' ||
aExpiryYear.CharAt(index) > '9') {
return false;
}
}
}
return true;
}
nsresult
BasicCardService::EncodeBasicCardData(const nsAString& aCardholderName,
const nsAString& aCardNumber,
const nsAString& aExpiryMonth,
const nsAString& aExpiryYear,
const nsAString& aCardSecurityCode,
nsIPaymentAddress* aBillingAddress,
nsAString& aResult)
{
// aBillingAddress can be nullptr
if (aCardNumber.IsEmpty()) {
return NS_ERROR_FAILURE;
}
EncodeBasicCardProperty(CardholderName, aCardholderName, aResult);
EncodeBasicCardProperty(CardNumber, aCardNumber, aResult);
EncodeBasicCardProperty(ExpiryMonth, aExpiryMonth, aResult);
EncodeBasicCardProperty(ExpiryYear, aExpiryYear, aResult);
EncodeBasicCardProperty(CardSecurityCode, aCardSecurityCode, aResult);
if (!aBillingAddress) {
return NS_OK;
}
EncodeAddressProperty(aBillingAddress, Country, aResult);
nsCOMPtr<nsIArray> addressLine;
NS_ENSURE_SUCCESS(aBillingAddress->GetAddressLine(getter_AddRefs(addressLine)),
NS_ERROR_FAILURE);
uint32_t length;
nsAutoString addressLineString;
NS_ENSURE_SUCCESS(addressLine->GetLength(&length), NS_ERROR_FAILURE);
for (uint32_t index = 0; index < length; ++index) {
nsCOMPtr<nsISupportsString> address = do_QueryElementAt(addressLine, index);
MOZ_ASSERT(address);
nsAutoString addressString;
NS_ENSURE_SUCCESS(address->GetData(addressString), NS_ERROR_FAILURE);
addressLineString += addressString + AddressLineSpliter;
}
EncodeBasicCardProperty(AddressLine ,addressLineString , aResult);
EncodeAddressProperty(aBillingAddress, Region, aResult);
EncodeAddressProperty(aBillingAddress, City, aResult);
EncodeAddressProperty(aBillingAddress, DependentLocality, aResult);
EncodeAddressProperty(aBillingAddress, PostalCode, aResult);
EncodeAddressProperty(aBillingAddress, SortingCode, aResult);
EncodeAddressProperty(aBillingAddress, LanguageCode, aResult);
EncodeAddressProperty(aBillingAddress, Organization, aResult);
EncodeAddressProperty(aBillingAddress, Recipient, aResult);
EncodeAddressProperty(aBillingAddress, Phone, aResult);
return NS_OK;
}
nsresult
BasicCardService::DecodeBasicCardData(const nsAString& aData,
nsPIDOMWindowInner* aWindow,
BasicCardResponse& aResponse)
{
// aWindow can be nullptr
bool isBillingAddressPassed = false;
nsTArray<nsString> addressLine;
nsAutoString country;
nsAutoString region;
nsAutoString city;
nsAutoString dependentLocality;
nsAutoString postalCode;
nsAutoString sortingCode;
nsAutoString languageCode;
nsAutoString organization;
nsAutoString recipient;
nsAutoString phone;
nsCharSeparatedTokenizer propertyTokenizer(aData, PropertySpliter.CharAt(0));
while (propertyTokenizer.hasMoreTokens()) {
nsDependentSubstring property = propertyTokenizer.nextToken();
nsCharSeparatedTokenizer keyValueTokenizer(property, KeyValueSpliter.CharAt(0));
MOZ_ASSERT(keyValueTokenizer.hasMoreTokens());
nsDependentSubstring key = keyValueTokenizer.nextToken();
nsDependentSubstring value = keyValueTokenizer.nextToken();
if (IsAddressKey(key) && !isBillingAddressPassed) {
isBillingAddressPassed = true;
}
if (!IsAddressKey(key) && !IsBasicCardKey(key)) {
return NS_ERROR_FAILURE;
}
if (key.Equals(CardNumber)) {
aResponse.mCardNumber = (value);
}
DecodeBasicCardProperty(key, value, CardholderName, aResponse);
DecodeBasicCardProperty(key, value, ExpiryMonth, aResponse);
DecodeBasicCardProperty(key, value, ExpiryYear, aResponse);
DecodeBasicCardProperty(key, value, CardSecurityCode, aResponse);
DecodeAddressProperty(key, value, Country, country);
DecodeAddressProperty(key, value, Region, region);
DecodeAddressProperty(key, value, City, city);
DecodeAddressProperty(key, value, DependentLocality, dependentLocality);
DecodeAddressProperty(key, value, PostalCode, postalCode);
DecodeAddressProperty(key, value, SortingCode, sortingCode);
DecodeAddressProperty(key, value, LanguageCode, languageCode);
DecodeAddressProperty(key, value, Organization, organization);
DecodeAddressProperty(key, value, Recipient, recipient);
DecodeAddressProperty(key, value, Phone, phone);
if ((key).Equals(AddressLine)) {
nsCharSeparatedTokenizer addressTokenizer(value, AddressLineSpliter.CharAt(0));
while (addressTokenizer.hasMoreTokens()) {
addressLine.AppendElement(addressTokenizer.nextToken());
}
}
}
if (isBillingAddressPassed) {
aResponse.mBillingAddress.Construct();
aResponse.mBillingAddress.Value() = new PaymentAddress(aWindow,
country,
addressLine,
region,
city,
dependentLocality,
postalCode,
sortingCode,
languageCode,
organization,
recipient,
phone);
}
return NS_OK;
}
#ifdef PaymentBasicCardMacros
#undef PaymentBasicCardMacros
#undef EncodeBasicCardProperty
#undef EncodeAddressProperty
#undef DecodeBasicCardProperty
#undef DecodeBasicCardCardNumber
#undef DecodeAddressProperty
#undef DecodeAddressLine
#undef AMEX
#undef CARTEBANCAIRE
#undef DINERS
#undef DISCOVER
#undef JCB
#undef MASTERCARD
#undef MIR
#undef UNIONPAY
#undef VISA
#undef CardholderName
#undef CardNumber
#undef ExpiryMonth
#undef ExpiryYear
#undef CardSecurityCode
#undef Country
#undef AddressLine
#undef Region
#undef City
#undef DependentLocality
#undef PostalCode
#undef SortingCode
#undef LanguageCode
#undef Organization
#undef Recipient
#undef Phone
#undef PropertySpliter
#undef KeyValueSpliter
#undef AddressLineSpliter
#endif
} // end of namespace dom
} // end of namespace mozilla

Просмотреть файл

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef mozilla_dom_BasicCardPayment_h
#define mozilla_dom_BasicCardPayment_h
#include "mozilla/dom/BasicCardPaymentBinding.h"
#include "nsPIDOMWindow.h"
#include "nsIPaymentAddress.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class BasicCardService final
{
public:
NS_INLINE_DECL_REFCOUNTING(BasicCardService)
static already_AddRefed<BasicCardService> GetService();
bool IsBasicCardPayment(const nsAString& aSupportedMethods);
bool IsValidBasicCardRequest(JSContext* aCx, JSObject* aData, nsAString& aErrorMsg);
bool IsValidExpiryMonth(const nsAString& aExpiryMonth);
bool IsValidExpiryYear(const nsAString& aExpiryYear);
/*
To let BasicCardResponse using the same data type with non-BasicCard response
in IPC transferring, following two methods is used to Encode/Decode the raw
data of BasicCardResponse.
*/
nsresult EncodeBasicCardData(const nsAString& aCardholderName,
const nsAString& aCardNumber,
const nsAString& aExpiryMonth,
const nsAString& aExpiryYear,
const nsAString& aCardSecurityCode,
nsIPaymentAddress* aBillingAddress,
nsAString& aResult);
nsresult DecodeBasicCardData(const nsAString& aData,
nsPIDOMWindowInner* aWindow,
BasicCardResponse& aResponse);
private:
BasicCardService() = default;
~BasicCardService() = default;
};
} // end of namespace dom
} // end of namespace mozilla
#endif

Просмотреть файл

@ -5,11 +5,121 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PaymentActionResponse.h"
#include "nsIRunnable.h"
#include "PaymentRequestUtils.h"
#include "BasicCardPayment.h"
namespace mozilla {
namespace dom {
/* PaymentResponseData */
NS_IMPL_ISUPPORTS(PaymentResponseData, nsIPaymentResponseData)
NS_IMETHODIMP
PaymentResponseData::GetType(uint32_t* aType)
{
NS_ENSURE_ARG_POINTER(aType);
*aType = mType;
return NS_OK;
}
NS_IMETHODIMP
PaymentResponseData::Init(const uint32_t aType)
{
if (aType != nsIPaymentResponseData::GENERAL_RESPONSE &&
aType != nsIPaymentResponseData::BASICCARD_RESPONSE) {
return NS_ERROR_FAILURE;
}
mType = aType;
return NS_OK;
}
/* GeneralResponseData */
NS_IMPL_ISUPPORTS_INHERITED(GeneralResponseData,
PaymentResponseData,
nsIGeneralResponseData)
GeneralResponseData::GeneralResponseData()
: mData(NS_LITERAL_STRING("{}"))
{
Init(nsIPaymentResponseData::GENERAL_RESPONSE);
}
NS_IMETHODIMP
GeneralResponseData::GetData(nsAString& aData)
{
aData = mData;
return NS_OK;
}
NS_IMETHODIMP
GeneralResponseData::InitData(JS::HandleValue aValue, JSContext* aCx)
{
if (aValue.isNullOrUndefined()) {
return NS_ERROR_FAILURE;
}
nsresult rv = SerializeFromJSVal(aCx, aValue, mData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
/* BasicCardResponseData */
NS_IMPL_ISUPPORTS_INHERITED(BasicCardResponseData,
PaymentResponseData,
nsIBasicCardResponseData)
BasicCardResponseData::BasicCardResponseData()
{
Init(nsIPaymentResponseData::BASICCARD_RESPONSE);
}
NS_IMETHODIMP
BasicCardResponseData::GetData(nsAString& aData)
{
aData = mData;
return NS_OK;
}
NS_IMETHODIMP
BasicCardResponseData::InitData(const nsAString& aCardholderName,
const nsAString& aCardNumber,
const nsAString& aExpiryMonth,
const nsAString& aExpiryYear,
const nsAString& aCardSecurityCode,
nsIPaymentAddress* aBillingAddress)
{
// cardNumber is a required attribute, cannot be empty;
if (aCardNumber.IsEmpty()) {
return NS_ERROR_FAILURE;
}
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
if (!service->IsValidExpiryMonth(aExpiryMonth)) {
return NS_ERROR_FAILURE;
}
if (!service->IsValidExpiryYear(aExpiryYear)) {
return NS_ERROR_FAILURE;
}
nsresult rv = service->EncodeBasicCardData(aCardholderName,
aCardNumber,
aExpiryMonth,
aExpiryYear,
aCardSecurityCode,
aBillingAddress,
mData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
/* PaymentActionResponse */
NS_IMPL_ISUPPORTS(PaymentActionResponse,
@ -121,15 +231,49 @@ NS_IMETHODIMP
PaymentShowActionResponse::Init(const nsAString& aRequestId,
const uint32_t aAcceptStatus,
const nsAString& aMethodName,
const nsAString& aData,
nsIPaymentResponseData* aData,
const nsAString& aPayerName,
const nsAString& aPayerEmail,
const nsAString& aPayerPhone)
{
NS_ENSURE_ARG_POINTER(aData);
mRequestId = aRequestId;
mAcceptStatus = aAcceptStatus;
mMethodName = aMethodName;
mData = aData;
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
bool isBasicCardPayment = service->IsBasicCardPayment(mMethodName);
uint32_t responseType;
NS_ENSURE_SUCCESS(aData->GetType(&responseType), NS_ERROR_FAILURE);
switch (responseType) {
case nsIPaymentResponseData::GENERAL_RESPONSE: {
if (isBasicCardPayment) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIGeneralResponseData> data = do_QueryInterface(aData);
MOZ_ASSERT(data);
NS_ENSURE_SUCCESS(data->GetData(mData), NS_ERROR_FAILURE);
break;
}
case nsIPaymentResponseData::BASICCARD_RESPONSE: {
if (!isBasicCardPayment) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIBasicCardResponseData> data = do_QueryInterface(aData);
MOZ_ASSERT(data);
NS_ENSURE_SUCCESS(data->GetData(mData), NS_ERROR_FAILURE);
break;
}
default: {
return NS_ERROR_FAILURE;
}
}
if (mData.IsEmpty()) {
return NS_ERROR_FAILURE;
}
mPayerName = aPayerName;
mPayerEmail = aPayerEmail;
mPayerPhone = aPayerPhone;

Просмотреть файл

@ -14,6 +14,53 @@ namespace dom {
class PaymentRequestParent;
class PaymentResponseData : public nsIPaymentResponseData
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPAYMENTRESPONSEDATA
PaymentResponseData() = default;
protected:
virtual ~PaymentResponseData() = default;
uint32_t mType;
};
class GeneralResponseData final : public PaymentResponseData
, public nsIGeneralResponseData
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIPAYMENTRESPONSEDATA(PaymentResponseData::)
NS_DECL_NSIGENERALRESPONSEDATA
GeneralResponseData();
private:
~GeneralResponseData() = default;
nsString mData;
};
class BasicCardResponseData final : public nsIBasicCardResponseData
, public PaymentResponseData
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIPAYMENTRESPONSEDATA(PaymentResponseData::)
NS_DECL_NSIBASICCARDRESPONSEDATA
BasicCardResponseData();
private:
~BasicCardResponseData() = default;
nsString mData;
nsCOMPtr<nsIPaymentAddress> mBillingAddress;
};
class PaymentActionResponse : public nsIPaymentActionResponse
{
public:

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/dom/PaymentRequest.h"
#include "mozilla/dom/PaymentResponse.h"
#include "nsContentUtils.h"
#include "BasicCardPayment.h"
#include "PaymentRequestManager.h"
namespace mozilla {
@ -52,7 +53,8 @@ PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
}
bool
PaymentRequest::IsValidMethodData(const Sequence<PaymentMethodData>& aMethodData,
PaymentRequest::IsValidMethodData(JSContext* aCx,
const Sequence<PaymentMethodData>& aMethodData,
nsAString& aErrorMsg)
{
if (!aMethodData.Length()) {
@ -61,11 +63,24 @@ PaymentRequest::IsValidMethodData(const Sequence<PaymentMethodData>& aMethodData
}
for (const PaymentMethodData& methodData : aMethodData) {
if (!methodData.mSupportedMethods.Length()) {
if (methodData.mSupportedMethods.IsEmpty()) {
aErrorMsg.AssignLiteral(
"At least one payment method identifier is required.");
"Payment method identifier is required.");
return false;
}
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
if (service->IsBasicCardPayment(methodData.mSupportedMethods)) {
if (!methodData.mData.WasPassed()) {
continue;
}
MOZ_ASSERT(aCx);
if (!service->IsValidBasicCardRequest(aCx,
methodData.mData.Value(),
aErrorMsg)) {
return false;
}
}
}
return true;
@ -259,7 +274,9 @@ PaymentRequest::Constructor(const GlobalObject& aGlobal,
// Check payment methods and details
nsAutoString message;
if (!IsValidMethodData(aMethodData, message) ||
if (!IsValidMethodData(nsContentUtils::GetCurrentJSContext(),
aMethodData,
message) ||
!IsValidDetailsInit(aDetails, message)) {
aRv.ThrowTypeError<MSG_ILLEGAL_PR_CONSTRUCTOR>(message);
return nullptr;

Просмотреть файл

@ -36,7 +36,8 @@ public:
static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
static bool IsValidMethodData(const Sequence<PaymentMethodData>& aMethodData,
static bool IsValidMethodData(JSContext* aCx,
const Sequence<PaymentMethodData>& aMethodData,
nsAString& aErrorMsg);
static bool

Просмотреть файл

@ -44,9 +44,16 @@ PaymentMethodData::GetSupportedMethods(nsAString& aSupportedMethods)
}
NS_IMETHODIMP
PaymentMethodData::GetData(nsAString& aData)
PaymentMethodData::GetData(JSContext* aCx, JS::MutableHandleValue aData)
{
aData = mData;
if (mData.IsEmpty()) {
aData.set(JS::NullValue());
return NS_OK;
}
nsresult rv = DeserializeToJSValue(mData, aCx ,aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
@ -222,9 +229,16 @@ PaymentDetailsModifier::GetAdditionalDisplayItems(nsIArray** aAdditionalDisplayI
}
NS_IMETHODIMP
PaymentDetailsModifier::GetData(nsAString& aData)
PaymentDetailsModifier::GetData(JSContext* aCx, JS::MutableHandleValue aData)
{
aData = mData;
if (mData.IsEmpty()) {
aData.set(JS::NullValue());
return NS_OK;
}
nsresult rv = DeserializeToJSValue(mData, aCx ,aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}

Просмотреть файл

@ -10,6 +10,8 @@
#include "PaymentRequestData.h"
#include "PaymentRequestService.h"
using mozilla::dom::GeneralResponseData;
using mozilla::dom::BasicCardResponseData;
using mozilla::dom::PaymentActionRequest;
using mozilla::dom::PaymentCreateActionRequest;
using mozilla::dom::PaymentCompleteActionRequest;
@ -21,6 +23,8 @@ using mozilla::dom::PaymentCompleteActionResponse;
using mozilla::dom::payments::PaymentAddress;
using mozilla::dom::PaymentRequestService;
NS_GENERIC_FACTORY_CONSTRUCTOR(GeneralResponseData)
NS_GENERIC_FACTORY_CONSTRUCTOR(BasicCardResponseData)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest)
NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCompleteActionRequest)
@ -33,6 +37,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentAddress)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
PaymentRequestService::GetSingleton)
NS_DEFINE_NAMED_CID(NS_GENERAL_RESPONSE_DATA_CID);
NS_DEFINE_NAMED_CID(NS_BASICCARD_RESPONSE_DATA_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_COMPLETE_ACTION_REQUEST_CID);
@ -45,6 +51,8 @@ NS_DEFINE_NAMED_CID(NS_PAYMENT_ADDRESS_CID);
NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
{ &kNS_GENERAL_RESPONSE_DATA_CID, false, nullptr, GeneralResponseDataConstructor},
{ &kNS_BASICCARD_RESPONSE_DATA_CID, false, nullptr, BasicCardResponseDataConstructor},
{ &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor},
{ &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor},
{ &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID, false, nullptr, PaymentCompleteActionRequestConstructor},
@ -59,6 +67,8 @@ static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
};
static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
{ NS_GENERAL_RESPONSE_DATA_CONTRACT_ID, &kNS_GENERAL_RESPONSE_DATA_CID },
{ NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID, &kNS_BASICCARD_RESPONSE_DATA_CID },
{ NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID },
{ NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID },
{ NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_COMPLETE_ACTION_REQUEST_CID },
@ -73,6 +83,8 @@ static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
};
static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
{ "payment-request", "GeneralResponseData", NS_GENERAL_RESPONSE_DATA_CONTRACT_ID },
{ "payment-request", "BasicCardResponseData", NS_BASICCARD_RESPONSE_DATA_CONTRACT_ID },
{ "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID },
{ "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID },
{ "payment-request", "PaymentCompleteActionRequest", NS_PAYMENT_COMPLETE_ACTION_REQUEST_CONTRACT_ID },

Просмотреть файл

@ -7,6 +7,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "PaymentRequestData.h"
#include "PaymentRequestService.h"
#include "BasicCardPayment.h"
namespace mozilla {
namespace dom {
@ -300,16 +301,29 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
break;
}
/*
* TODO: 1. Check basic card support once the Basic Card Payment spec is
* implemented.
* https://www.w3.org/TR/payment-method-basic-card/
* 2. Check third party payment app support by traversing all
* TODO: 1. Check third party payment app support by traversing all
* registered third party payment apps.
*/
case nsIPaymentActionRequest::CANMAKE_ACTION: {
rv = CallTestingUIAction(requestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
if (IsBasicCardPayment(requestId)) {
nsCOMPtr<nsIPaymentCanMakeActionResponse> canMakeResponse =
do_CreateInstance(NS_PAYMENT_CANMAKE_ACTION_RESPONSE_CONTRACT_ID);
MOZ_ASSERT(canMakeResponse);
rv = canMakeResponse->Init(requestId, true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIPaymentActionResponse> response = do_QueryInterface(canMakeResponse);
MOZ_ASSERT(response);
rv = RespondPayment(response);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
rv = CallTestingUIAction(requestId, type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
}
break;
}
@ -318,13 +332,16 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
*/
case nsIPaymentActionRequest::SHOW_ACTION: {
if (mShowingRequest) {
nsCOMPtr<nsIPaymentResponseData> responseData =
do_CreateInstance(NS_GENERAL_RESPONSE_DATA_CONTRACT_ID);
MOZ_ASSERT(responseData);
nsCOMPtr<nsIPaymentShowActionResponse> showResponse =
do_CreateInstance(NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID);
MOZ_ASSERT(showResponse);
rv = showResponse->Init(requestId,
nsIPaymentActionResponse::PAYMENT_REJECTED,
EmptyString(),
EmptyString(),
responseData,
EmptyString(),
EmptyString(),
EmptyString());
@ -519,5 +536,32 @@ PaymentRequestService::RemoveActionCallback(const nsAString& aRequestId)
return NS_OK;
}
bool
PaymentRequestService::IsBasicCardPayment(const nsAString& aRequestId)
{
nsCOMPtr<nsIPaymentRequest> payment;
nsresult rv = GetPaymentRequestById(aRequestId, getter_AddRefs(payment));
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIArray> methods;
rv = payment->GetPaymentMethods(getter_AddRefs(methods));
NS_ENSURE_SUCCESS(rv, false);
uint32_t length;
rv = methods->GetLength(&length);
NS_ENSURE_SUCCESS(rv, false);
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
for (uint32_t index = 0; index < length; ++index) {
nsCOMPtr<nsIPaymentMethodData> method = do_QueryElementAt(methods, index);
MOZ_ASSERT(method);
nsAutoString supportedMethods;
rv = method->GetSupportedMethods(supportedMethods);
NS_ENSURE_SUCCESS(rv, false);
if (service->IsBasicCardPayment(supportedMethods)) {
return true;
}
}
return false;
}
} // end of namespace dom
} // end of namespace mozilla

Просмотреть файл

@ -46,6 +46,9 @@ private:
nsresult
CallTestingUIAction(const nsAString& aRequestId, uint32_t aActionType);
bool
IsBasicCardPayment(const nsAString& aRequestId);
FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
nsInterfaceHashtable<nsStringHashKey, nsIPaymentActionCallback> mCallbackHashtable;

Просмотреть файл

@ -14,7 +14,9 @@ namespace mozilla {
namespace dom {
nsresult
SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSerializedObject) {
SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSerializedObject)
{
MOZ_ASSERT(aCx);
nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
if (NS_WARN_IF(!serializer)) {
return NS_ERROR_FAILURE;
@ -24,7 +26,21 @@ SerializeFromJSObject(JSContext* aCx, JS::HandleObject aObject, nsAString& aSeri
}
nsresult
DeserializeToJSObject(const nsAString& aSerializedObject, JSContext* aCx, JS::MutableHandleObject aObject) {
SerializeFromJSVal(JSContext* aCx, JS::HandleValue aValue, nsAString& aSerializedValue)
{
MOZ_ASSERT(aCx);
nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
if (NS_WARN_IF(!serializer)) {
return NS_ERROR_FAILURE;
}
JS::RootedValue value(aCx, aValue.get());
return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedValue);
}
nsresult
DeserializeToJSObject(const nsAString& aSerializedObject, JSContext* aCx, JS::MutableHandleObject aObject)
{
MOZ_ASSERT(aCx);
nsCOMPtr<nsIJSON> deserializer = do_CreateInstance("@mozilla.org/dom/json;1");
if (NS_WARN_IF(!deserializer)) {
return NS_ERROR_FAILURE;
@ -43,5 +59,20 @@ DeserializeToJSObject(const nsAString& aSerializedObject, JSContext* aCx, JS::Mu
return NS_OK;
}
nsresult
DeserializeToJSValue(const nsAString& aSerializedObject, JSContext* aCx, JS::MutableHandleValue aValue)
{
MOZ_ASSERT(aCx);
nsCOMPtr<nsIJSON> deserializer = do_CreateInstance("@mozilla.org/dom/json;1");
if (NS_WARN_IF(!deserializer)) {
return NS_ERROR_FAILURE;
}
nsresult rv = deserializer->DecodeToJSVal(aSerializedObject, aCx, aValue);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
} // end of namespace dom
} // end of namespace mozilla

Просмотреть файл

@ -18,11 +18,21 @@ SerializeFromJSObject(JSContext* aCx,
JS::HandleObject aObject,
nsAString& aSerializedObject);
nsresult
SerializeFromJSVal(JSContext* aCx,
JS::HandleValue aValue,
nsAString& aSerializedValue);
nsresult
DeserializeToJSObject(const nsAString& aSerializedObject,
JSContext* aCx,
JS::MutableHandleObject aObject);
nsresult
DeserializeToJSValue(const nsAString& aSerializedObject,
JSContext* aCx,
JS::MutableHandleValue aValue);
} // end of namespace dom
} // end of namespace mozilla

Просмотреть файл

@ -5,6 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/PaymentResponse.h"
#include "mozilla/dom/BasicCardPaymentBinding.h"
#include "BasicCardPayment.h"
#include "PaymentAddress.h"
#include "PaymentRequestUtils.h"
namespace mozilla {
@ -73,7 +76,25 @@ PaymentResponse::GetMethodName(nsString& aRetVal) const
void
PaymentResponse::GetDetails(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const
{
DeserializeToJSObject(mDetails, aCx, aRetVal);
RefPtr<BasicCardService> service = BasicCardService::GetService();
MOZ_ASSERT(service);
if (!service->IsBasicCardPayment(mMethodName)) {
DeserializeToJSObject(mDetails, aCx, aRetVal);
} else {
BasicCardResponse response;
nsresult rv = service->DecodeBasicCardData(mDetails, mOwner, response);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
MOZ_ASSERT(aCx);
JS::RootedValue value(aCx);
JS::MutableHandleValue handleValue(&value);
if (NS_WARN_IF(!response.ToObjectInternal(aCx, handleValue))) {
return;
}
aRetVal.set(&handleValue.toObject());
}
}
void

Просмотреть файл

@ -22,6 +22,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
'BasicCardPayment.cpp',
'PaymentActionRequest.cpp',
'PaymentActionResponse.cpp',
'PaymentAddress.cpp',

Просмотреть файл

@ -0,0 +1,27 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this WebIDL file is
* https://www.w3.org/TR/payment-request/#paymentrequest-interface
*/
enum BasicCardType {
"credit",
"debit",
"prepaid"
};
dictionary BasicCardRequest {
sequence<DOMString> supportedNetworks;
sequence<BasicCardType> supportedTypes;
};
dictionary BasicCardResponse {
DOMString cardholderName;
required DOMString cardNumber;
DOMString expiryMonth;
DOMString expiryYear;
DOMString cardSecurityCode;
PaymentAddress? billingAddress;
};

Просмотреть файл

@ -411,6 +411,7 @@ WEBIDL_FILES = [
'BarProp.webidl',
'BaseAudioContext.webidl',
'BaseKeyframeTypes.webidl',
'BasicCardPayment.webidl',
'BatteryManager.webidl',
'BeforeUnloadEvent.webidl',
'BiquadFilterNode.webidl',