From 0e9c43b39fbb754d35102e7885cc450ad86040b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez?= Date: Wed, 29 Aug 2012 18:41:34 -0300 Subject: [PATCH] Bug 767818 - Implement navigator.pay. Part 3 - DOM implementation; r=fabrice --- dom/payment/Makefile.in | 26 ++ dom/payment/Payment.js | 88 +++++++ dom/payment/Payment.jsm | 370 +++++++++++++++++++++++++++++ dom/payment/Payment.manifest | 15 ++ dom/payment/PaymentFlowInfo.js | 22 ++ dom/payment/PaymentRequestInfo.js | 136 +++++++++++ dom/payment/interfaces/Makefile.in | 20 ++ 7 files changed, 677 insertions(+) create mode 100644 dom/payment/Makefile.in create mode 100644 dom/payment/Payment.js create mode 100644 dom/payment/Payment.jsm create mode 100644 dom/payment/PaymentFlowInfo.js create mode 100644 dom/payment/PaymentRequestInfo.js create mode 100644 dom/payment/interfaces/Makefile.in diff --git a/dom/payment/Makefile.in b/dom/payment/Makefile.in new file mode 100644 index 00000000000..6b9bafacf27 --- /dev/null +++ b/dom/payment/Makefile.in @@ -0,0 +1,26 @@ +# 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/. + +DEPTH = @DEPTH@ +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +PARALLEL_DIRS = interfaces + +EXTRA_COMPONENTS = \ + Payment.js \ + PaymentFlowInfo.js \ + PaymentRequestInfo.js \ + Payment.manifest \ + $(NULL) + +EXTRA_JS_MODULES += \ + Payment.jsm \ + $(NULL) + +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/config/rules.mk diff --git a/dom/payment/Payment.js b/dom/payment/Payment.js new file mode 100644 index 00000000000..98d1ed623ac --- /dev/null +++ b/dom/payment/Payment.js @@ -0,0 +1,88 @@ +/* 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/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); + +const PAYMENTCONTENTHELPER_CID = + Components.ID("{a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0}"); + +const PAYMENT_IPC_MSG_NAMES = ["Payment:Success", + "Payment:Failed"]; + +XPCOMUtils.defineLazyServiceGetter(this, "cpmm", + "@mozilla.org/childprocessmessagemanager;1", + "nsIMessageSender"); + +function debug (s) { + //dump("-*- PaymentContentHelper: " + s + "\n"); +}; + +function PaymentContentHelper() { +}; + +PaymentContentHelper.prototype = { + __proto__: DOMRequestIpcHelper.prototype, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMNavigatorPayment, + Ci.nsIDOMGlobalPropertyInitializer]), + classID: PAYMENTCONTENTHELPER_CID, + classInfo: XPCOMUtils.generateCI({ + classID: PAYMENTCONTENTHELPER_CID, + contractID: "@mozilla.org/payment/content-helper;1", + classDescription: "Payment Content Helper", + flags: Ci.nsIClassInfo.DOM_OBJECT, + interfaces: [Ci.nsIDOMNavigatorPayment] + }), + + // nsIDOMNavigatorPayment + + pay: function pay(aJwts) { + let request = this.createRequest(); + let requestId = this.getRequestId(request); + if (!Array.isArray(aJwts)) { + aJwts = [aJwts]; + } + cpmm.sendAsyncMessage("Payment:Pay", { + jwts: aJwts, + requestId: requestId + }); + return request; + }, + + // nsIDOMGlobalPropertyInitializer + + init: function(aWindow) { + this.initHelper(aWindow, PAYMENT_IPC_MSG_NAMES); + return this.pay.bind(this); + }, + + // nsIFrameMessageListener + + receiveMessage: function receiveMessage(aMessage) { + let name = aMessage.name; + let msg = aMessage.json; + debug("Received message '" + name + "': " + JSON.stringify(msg)); + let requestId = msg.requestId; + let request = this.takeRequest(requestId); + if (!request) { + return; + } + switch (name) { + case "Payment:Success": + Services.DOMRequest.fireSuccess(request, msg.result); + break; + case "Payment:Failed": + Services.DOMRequest.fireError(request, msg.errorMsg); + break; + } + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentContentHelper]); diff --git a/dom/payment/Payment.jsm b/dom/payment/Payment.jsm new file mode 100644 index 00000000000..b14dd0f7f7e --- /dev/null +++ b/dom/payment/Payment.jsm @@ -0,0 +1,370 @@ +/* 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/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +let EXPORTED_SYMBOLS = []; + +const PAYMENT_IPC_MSG_NAMES = ["Payment:Pay", + "Payment:Success", + "Payment:Failed"]; + +const PREF_PAYMENTPROVIDERS_BRANCH = "dom.payment.provider."; + +XPCOMUtils.defineLazyServiceGetter(this, "ppmm", + "@mozilla.org/parentprocessmessagemanager;1", + "nsIMessageListenerManager"); + +XPCOMUtils.defineLazyServiceGetter(this, "prefService", + "@mozilla.org/preferences-service;1", + "nsIPrefService"); + +function debug (s) { + //dump("-*- PaymentManager: " + s + "\n"); +}; + +let PaymentManager = { + init: function init() { + this.requestId = null; + + // Payment providers data are stored as a preference. + this.registeredProviders = null; + + this.messageManagers = {}; + + for each (let msgname in PAYMENT_IPC_MSG_NAMES) { + ppmm.addMessageListener(msgname, this); + } + + Services.obs.addObserver(this, "xpcom-shutdown", false); + }, + + /** + * Process a message from the content process. + */ + receiveMessage: function receiveMessage(aMessage) { + let name = aMessage.name; + let msg = aMessage.json; + debug("Received '" + name + "' message from content process"); + + if (msg.requestId) { + this.requestId = msg.requestId; + } + + switch (name) { + case "Payment:Pay": { + // First of all, we register the payment providers. + if (!this.registeredProviders) { + this.registeredProviders = {}; + this.registerPaymentProviders(); + } + + // We save the message target message manager so we can later dispatch + // back messages without broadcasting to all child processes. + this.messageManagers[this.requestId] = aMessage.target; + + // We check the jwt type and look for a match within the + // registered payment providers to get the correct payment request + // information. + let paymentRequests = []; + let jwtTypes = []; + for (let i in msg.jwts) { + let pr = this.getPaymentRequestInfo(msg.jwts[i]); + if (!pr) { + continue; + } + // We consider jwt type repetition an error. + if (jwtTypes[pr.type]) { + this.paymentFailed("DUPLICATE_JWT_TYPE"); + return; + } + jwtTypes[pr.type] = true; + paymentRequests.push(pr); + } + + if (!paymentRequests.length) { + this.paymentFailed("NO_VALID_PAYMENT_REQUEST"); + return; + } + + // After getting the list of valid payment requests, we ask the user + // for confirmation before sending any request to any payment provider. + // If there is more than one choice, we also let the user select the one + // that he prefers. + let glue = Cc["@mozilla.org/payment/ui-glue;1"] + .createInstance(Ci.nsIPaymentUIGlue); + if (!glue) { + debug("Could not create nsIPaymentUIGlue instance"); + this.paymentFailed("CREATE_PAYMENT_GLUE_FAILED"); + return; + } + + let confirmPaymentSuccessCb = function successCb(aResult) { + // Get the appropriate payment provider data based on user's choice. + let selectedProvider = this.registeredProviders[aResult]; + if (!selectedProvider || !selectedProvider.uri) { + debug("Could not retrieve a valid provider based on user's " + + "selection"); + this.paymentFailed("NO_VALID_SELECTED_PROVIDER"); + return; + } + + let jwt; + for (let i in paymentRequests) { + if (paymentRequests[i].type == aResult) { + jwt = paymentRequests[i].jwt; + break; + } + } + if (!jwt) { + debug("The selected request has no JWT information associated"); + this.paymentFailed("NO_JWT_ASSOCIATED_TO_REQUEST"); + return; + } + + this.showPaymentFlow(selectedProvider, jwt); + }; + + let confirmPaymentErrorCb = this.paymentFailed; + + glue.confirmPaymentRequest(paymentRequests, + confirmPaymentSuccessCb.bind(this), + confirmPaymentErrorCb.bind(this)); + break; + } + case "Payment:Success": + case "Payment:Failed": { + let mm = this.messageManagers[this.requestId]; + mm.sendAsyncMessage(name, { + requestId: this.requestId, + result: msg.result, + errorMsg: msg.errorMsg + }); + break; + } + } + }, + + /** + * Helper function to register payment providers stored as preferences. + */ + registerPaymentProviders: function registerPaymentProviders() { + let paymentProviders = prefService + .getBranch(PREF_PAYMENTPROVIDERS_BRANCH) + .getChildList(""); + + // First get the numbers of the providers by getting all ###.uri prefs. + let nums = []; + for (let i in paymentProviders) { + let match = /^(\d+)\.uri$/.exec(paymentProviders[i]); + if (!match) { + continue; + } else { + nums.push(match[1]); + } + } + + // Now register the payment providers. + for (let i in nums) { + let branch = prefService + .getBranch(PREF_PAYMENTPROVIDERS_BRANCH + nums[i] + "."); + let vals = branch.getChildList(""); + if (vals.length == 0) { + return; + } + try { + let type = branch.getCharPref("type"); + if (type in this.registeredProviders) { + continue; + } + this.registeredProviders[type] = { + name: branch.getCharPref("name"), + uri: branch.getCharPref("uri"), + description: branch.getCharPref("description"), + requestMethod: branch.getCharPref("requestMethod") + }; + debug("Registered Payment Providers: " + + JSON.stringify(this.registeredProviders[type])); + } catch (ex) { + debug("An error ocurred registering a payment provider. " + ex); + } + } + }, + + /** + * Helper for sending a Payment:Failed message to the parent process. + */ + paymentFailed: function paymentFailed(aErrorMsg) { + let mm = this.messageManagers[this.requestId]; + mm.sendAsyncMessage("Payment:Failed", { + requestId: this.requestId, + errorMsg: aErrorMsg + }); + }, + + /** + * Helper function to get the payment request info according to the jwt + * type. Payment provider's data is stored as a preference. + */ + getPaymentRequestInfo: function getPaymentRequestInfo(aJwt) { + if (!aJwt) { + return null; + } + + // First thing, we check that the jwt type is an allowed type and has a + // payment provider flow information associated. + + // A jwt string consists in three parts separated by period ('.'): header, + // payload and signature. + let segments = aJwt.split('.'); + if (segments.length !== 3) { + debug("Error getting payment provider's uri. " + + "Not enough or too many segments"); + return null; + } + + let payloadObject; + try { + // We only care about the payload segment, which contains the jwt type + // that should match with any of the stored payment provider's data and + // the payment request information to be shown to the user. + let payload = atob(segments[1]); + debug("Payload " + payload); + + // We get rid off the quotes and backslashes so we can parse the JSON + // object. + if (payload.charAt(0) === '"') { + payload = payload.substr(1); + } + if (payload.charAt(payload.length - 1) === '"') { + payload = payload.slice(0, -1); + } + payload = payload.replace(/\\/g, ''); + + payloadObject = JSON.parse(payload); + } catch (e) { + debug("Error decoding jwt " + e); + return null; + } + + if (!payloadObject || !payloadObject.typ || !payloadObject.request) { + debug("Error decoding jwt. Not valid jwt. " + + "No payload or jwt type or request found"); + return null; + } + + // Once we got the jwt 'typ' value we look for a match within the payment + // providers stored preferences. + let provider = this.registeredProviders[payloadObject.typ]; + if (!provider || !provider.uri || !provider.name) { + debug("Not registered payment provider for jwt type: " + + payloadObject.typ); + return null; + } + + // We only allow https for payment providers uris. + if (!/^https/.exec(provider.uri.toLowerCase())) { + debug("Payment provider uris must be https: " + provider.uri); + return null; + } + + let pldRequest = payloadObject.request; + let request; + if (pldRequest.refund) { + // The request is a refund request. + request = Cc["@mozilla.org/payment/request-refund-info;1"] + .createInstance(Ci.nsIDOMPaymentRequestRefundInfo); + + // Refund request should contain a refund reason. + if (!request || !pldRequest.reason) { + debug("Not valid refund request"); + return null; + } + request.wrappedJSObject.init(aJwt, + payloadObject.typ, + provider.name, + pldRequest.reason); + } else { + // The request is a payment request. + request = Cc["@mozilla.org/payment/request-payment-info;1"] + .createInstance(Ci.nsIDOMPaymentRequestPaymentInfo); + + // The payment request should contain at least a 'name', 'description' and + // 'price' parameters. + if (!request || !pldRequest.name || !pldRequest.description || + !pldRequest.price) { + debug("Not valid payment request"); + return null; + } + + // The payment request 'price' parameter is a collection of objects with + // 'country', 'currency' and 'amount' members. + let productPrices = []; + if (!Array.isArray(pldRequest.price)) { + pldRequest.price = [pldRequest.price]; + } + + for (let i in pldRequest.price) { + if (!pldRequest.price[i].country || !pldRequest.price[i].currency || + !pldRequest.price[i].amount) { + debug("Not valid payment request. " + + "Price parameter is not well formed"); + return null; + } + let price = Cc["@mozilla.org/payment/product-price;1"] + .createInstance(Ci.nsIDOMPaymentProductPrice); + price.wrappedJSObject.init(pldRequest.price[i].country, + pldRequest.price[i].currency, + pldRequest.price[i].amount); + productPrices.push(price); + } + request.wrappedJSObject.init(aJwt, + payloadObject.typ, + provider.name, + pldRequest.name, + pldRequest.description, + productPrices); + } + + return request; + }, + + showPaymentFlow: function showPaymentFlow(aPaymentProvider, aJwt) { + let paymentFlowInfo = Cc["@mozilla.org/payment/flow-info;1"] + .createInstance(Ci.nsIPaymentFlowInfo); + paymentFlowInfo.uri = aPaymentProvider.uri; + paymentFlowInfo.requestMethod = aPaymentProvider.requestMethod; + paymentFlowInfo.jwt = aJwt; + + let glue = Cc["@mozilla.org/payment/ui-glue;1"] + .createInstance(Ci.nsIPaymentUIGlue); + if (!glue) { + debug("Could not create nsIPaymentUIGlue instance"); + this.paymentFailed("CREATE_PAYMENT_GLUE_FAILED"); + return false; + } + glue.showPaymentFlow(paymentFlowInfo, this.paymentFailed); + }, + + // nsIObserver + + observe: function observe(subject, topic, data) { + if (topic == "xpcom-shutdown") { + for each (let msgname in PAYMENT_IPC_MSG_NAMES) { + ppmm.removeMessageListener(msgname, this); + } + this.registeredProviders = null; + this.messageManagers = null; + + Services.obs.removeObserver(this, "xpcom-shutdown"); + } + }, +}; + +PaymentManager.init(); diff --git a/dom/payment/Payment.manifest b/dom/payment/Payment.manifest index 4bc8ba4efad..b729e618231 100644 --- a/dom/payment/Payment.manifest +++ b/dom/payment/Payment.manifest @@ -1,3 +1,18 @@ component {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0} Payment.js contract @mozilla.org/payment/content-helper;1 {a920adc0-c36e-4fd0-8de0-aac1ac6ebbd0} category JavaScript-navigator-property mozPay @mozilla.org/payment/content-helper;1 + +component {b8bce4e7-fbf0-4719-a634-b1bf9018657c} PaymentFlowInfo.js +contract @mozilla.org/payment/flow-info;1 {b8bce4e7-fbf0-4719-a634-b1bf9018657c} + +component {3d7dcabf-b77c-4bb3-b225-46011898ec32} PaymentRequestInfo.js +contract @mozilla.org/payment/product-price;1 {3d7dcabf-b77c-4bb3-b225-46011898ec32} + +component {0a58c67d-f003-48da-81d1-bd8f605f4b1c} PaymentRequestInfo.js +contract @mozilla.org/payment/request-info;1 {0a58c67d-f003-48da-81d1-bd8f605f4b1c} + +component {7f2e3274-3956-42e1-b7ce-59b8cd23d177} PaymentRequestInfo.js +contract @mozilla.org/payment/request-payment-info;1 {7f2e3274-3956-42e1-b7ce-59b8cd23d177} + +component {e75566c6-dfb1-4f6b-b21d-078536c883b0} PaymentRequestInfo.js +contract @mozilla.org/payment/request-refund-info;1 {e75566c6-dfb1-4f6b-b21d-078536c883b0} diff --git a/dom/payment/PaymentFlowInfo.js b/dom/payment/PaymentFlowInfo.js new file mode 100644 index 00000000000..175edceccb9 --- /dev/null +++ b/dom/payment/PaymentFlowInfo.js @@ -0,0 +1,22 @@ +/* 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/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +function PaymentFlowInfo() { +}; + +PaymentFlowInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentFlowInfo]), + classID: Components.ID("{b8bce4e7-fbf0-4719-a634-b1bf9018657c}"), + uri: null, + jwt: null, + requestMethod: null +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentFlowInfo]); diff --git a/dom/payment/PaymentRequestInfo.js b/dom/payment/PaymentRequestInfo.js new file mode 100644 index 00000000000..a03014de0f2 --- /dev/null +++ b/dom/payment/PaymentRequestInfo.js @@ -0,0 +1,136 @@ +/* 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/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const PAYMENTREQUESTINFO_CID = + Components.ID("{0a58c67d-f003-48da-81d1-bd8f605f4b1c}"); +const PAYMENTPRODUCTPRICE_CID = + Components.ID("{3d7dcabf-b77c-4bb3-b225-46011898ec32}"); +const PAYMENTREQUESTPAYMENTINFO_CID = + Components.ID("{7f2e3274-3956-42e1-b7ce-59b8cd23d177}"); +const PAYMENTREQUESTREFUNDINFO_CID = + Components.ID("{e75566c6-dfb1-4f6b-b21d-078536c883b0}"); + +// nsIDOMPaymentProductPrice + +function PaymentProductPrice() { + this.wrappedJSObject = this; +}; + +PaymentProductPrice.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentProductPrice]), + classID: PAYMENTPRODUCTPRICE_CID, + classInfo: XPCOMUtils.generateCI({ + classID: PAYMENTPRODUCTPRICE_CID, + contractID: "@mozilla.org/payment/product-price;1", + classDescription: "Payment product price", + flags: Ci.nsIClassInfo.DOM_OBJECT, + interfaces: [Ci.nsIDOMPaymentProductPrice] + }), + country: null, + currency: null, + amount: null, + + init: function init(aCountry, aCurrency, aAmount) { + this.country = aCountry; + this.currency = aCurrency; + this.amount = aAmount; + } +}; + + +// nsIDOMPaymentRequestInfo + +function PaymentRequestInfo() { +}; + +PaymentRequestInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestInfo]), + classID: PAYMENTREQUESTINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: PAYMENTREQUESTINFO_CID, + contractID: "@mozilla.org/payment/request-info;1", + classDescription: "Payment request information", + flags: Ci.nsIClassInfo.DOM_OBJECT, + interfaces: [Ci.nsIDOMPaymentRequestInfo] + }), + jwt: null, + type: null, + providerName: null, + + initRequest: function initRequest(aJwt, aType, aProviderName) { + this.jwt = aJwt; + this.type = aType; + this.providerName = aProviderName; + } +}; + +// nsIDOMPaymentRequestPaymentInfo + +function PaymentRequestPaymentInfo() { + this.wrappedJSObject = this; +}; + +PaymentRequestPaymentInfo.prototype = { + __proto__: PaymentRequestInfo.prototype, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestPaymentInfo]), + classID: PAYMENTREQUESTPAYMENTINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: PAYMENTREQUESTPAYMENTINFO_CID, + contractID: "@mozilla.org/payment/request-payment-info;1", + classDescription: "Payment request payment information", + flags: Ci.nsIClassInfo.DOM_OBJECT, + interfaces: [Ci.nsIDOMPaymentRequestPaymentInfo] + }), + productName: null, + productDescription: null, + productPrice: null, + + init: function init(aJwt, aType, aProviderName, + aProductName, aProductDescription, aProductPrice) { + this.__proto__.initRequest.call(this, aJwt, aType, aProviderName); + this.productName = aProductName; + this.productDescription = aProductDescription; + this.productPrice = aProductPrice; + } +}; + +// nsIDOMPaymentRequestRefundInfo + +function PaymentRequestRefundInfo() { + this.wrappedJSObject = this; +}; + +PaymentRequestRefundInfo.prototype = { + __proto__: PaymentRequestInfo.prototype, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMPaymentRequestRefundInfo]), + classID: PAYMENTREQUESTREFUNDINFO_CID, + classInfo: XPCOMUtils.generateCI({ + classID: PAYMENTREQUESTREFUNDINFO_CID, + contractID: "@mozilla.org/payment/request-refund-info;1", + classDescription: "Payment request refund information", + flags: Ci.nsIClassInfo.DOM_OBJECT, + interfaces: [Ci.nsIDOMPaymentRequestRefundInfo] + }), + reason: null, + + init: function init(aJwt, aType, aProviderName, aReason) { + this.__proto__.initRequest.call(this, aJwt, aType, aProviderName); + this.reason = aReason; + } +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([ + PaymentProductPrice, + PaymentRequestInfo, + PaymentRequestPaymentInfo, + PaymentRequestRefundInfo +]); diff --git a/dom/payment/interfaces/Makefile.in b/dom/payment/interfaces/Makefile.in new file mode 100644 index 00000000000..a362f3e9c08 --- /dev/null +++ b/dom/payment/interfaces/Makefile.in @@ -0,0 +1,20 @@ +# 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/. + +DEPTH = @DEPTH@ +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +XPIDL_MODULE = dom_payment + +XPIDLSRCS = nsIDOMNavigatorPayment.idl \ + nsIDOMPaymentRequestInfo.idl \ + nsIPaymentFlowInfo.idl \ + nsIPaymentUIGlue.idl \ + $(NULL) + +include $(topsrcdir)/config/rules.mk