2012-08-30 01:41:35 +04:00
|
|
|
/* 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");
|
2015-01-19 16:50:32 +03:00
|
|
|
Cu.import("resource://gre/modules/Promise.jsm");
|
2012-08-30 01:41:35 +04:00
|
|
|
|
|
|
|
// Type of MozChromEvents to handle payment dialogs.
|
|
|
|
const kOpenPaymentConfirmationEvent = "open-payment-confirmation-dialog";
|
|
|
|
const kOpenPaymentFlowEvent = "open-payment-flow-dialog";
|
2015-01-19 16:50:32 +03:00
|
|
|
const kClosePaymentFlowEvent = "close-payment-flow-dialog";
|
|
|
|
|
|
|
|
// Observer notification topic for payment flow cancelation.
|
|
|
|
const kPaymentFlowCancelled = "payment-flow-cancelled";
|
2012-08-30 01:41:35 +04:00
|
|
|
|
2013-09-06 20:43:54 +04:00
|
|
|
const PREF_DEBUG = "dom.payment.debug";
|
|
|
|
|
2012-08-30 01:41:35 +04:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
|
|
|
"@mozilla.org/uuid-generator;1",
|
|
|
|
"nsIUUIDGenerator");
|
|
|
|
|
2014-04-07 17:59:48 +04:00
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
|
|
|
|
"resource://gre/modules/SystemAppProxy.jsm");
|
|
|
|
|
2012-08-30 01:41:35 +04:00
|
|
|
function PaymentUI() {
|
2013-09-06 20:43:54 +04:00
|
|
|
try {
|
|
|
|
this._debug =
|
|
|
|
Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
|
|
|
|
&& Services.prefs.getBoolPref(PREF_DEBUG);
|
|
|
|
} catch(e) {
|
|
|
|
this._debug = false;
|
|
|
|
}
|
2012-08-30 01:41:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
PaymentUI.prototype = {
|
|
|
|
|
2012-12-04 00:44:58 +04:00
|
|
|
confirmPaymentRequest: function confirmPaymentRequest(aRequestId,
|
|
|
|
aRequests,
|
2012-08-30 01:41:35 +04:00
|
|
|
aSuccessCb,
|
|
|
|
aErrorCb) {
|
2012-10-16 13:28:30 +04:00
|
|
|
let _error = function _error(errorMsg) {
|
|
|
|
if (aErrorCb) {
|
2012-12-04 00:44:58 +04:00
|
|
|
aErrorCb.onresult(aRequestId, errorMsg);
|
2012-10-16 13:28:30 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-08-30 01:41:35 +04:00
|
|
|
// The UI should listen for mozChromeEvent 'open-payment-confirmation-dialog'
|
|
|
|
// type in order to create and show the payment request confirmation frame
|
|
|
|
// embeded within a trusted dialog.
|
|
|
|
let id = kOpenPaymentConfirmationEvent + "-" + this.getRandomId();
|
|
|
|
let detail = {
|
|
|
|
type: kOpenPaymentConfirmationEvent,
|
|
|
|
id: id,
|
2013-01-22 15:29:54 +04:00
|
|
|
requestId: aRequestId,
|
2012-08-30 01:41:35 +04:00
|
|
|
paymentRequests: aRequests
|
|
|
|
};
|
|
|
|
|
|
|
|
// Once the user confirm the payment request and makes his choice, we get
|
|
|
|
// back to the DOM part to get the appropriate payment flow information
|
|
|
|
// based on the selected payment provider.
|
2013-11-26 15:13:57 +04:00
|
|
|
this._handleSelection = (function _handleSelection(evt) {
|
2012-08-30 01:41:35 +04:00
|
|
|
let msg = evt.detail;
|
|
|
|
if (msg.id != id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.userSelection && aSuccessCb) {
|
2012-12-04 00:44:58 +04:00
|
|
|
aSuccessCb.onresult(aRequestId, msg.userSelection);
|
2012-10-16 13:28:30 +04:00
|
|
|
} else if (msg.errorMsg) {
|
|
|
|
_error(msg.errorMsg);
|
2012-08-30 01:41:35 +04:00
|
|
|
}
|
|
|
|
|
2014-04-07 17:59:48 +04:00
|
|
|
SystemAppProxy.removeEventListener("mozContentEvent", this._handleSelection);
|
2013-11-26 15:13:57 +04:00
|
|
|
this._handleSelection = null;
|
|
|
|
}).bind(this);
|
2014-04-07 17:59:48 +04:00
|
|
|
SystemAppProxy.addEventListener("mozContentEvent", this._handleSelection);
|
2012-08-30 01:41:35 +04:00
|
|
|
|
2014-04-07 17:59:48 +04:00
|
|
|
SystemAppProxy.dispatchEvent(detail);
|
2012-08-30 01:41:35 +04:00
|
|
|
},
|
|
|
|
|
2012-12-04 00:44:58 +04:00
|
|
|
showPaymentFlow: function showPaymentFlow(aRequestId,
|
|
|
|
aPaymentFlowInfo,
|
|
|
|
aErrorCb) {
|
2015-01-19 16:50:32 +03:00
|
|
|
let _error = (errorMsg) => {
|
2012-10-16 13:28:30 +04:00
|
|
|
if (aErrorCb) {
|
2012-12-04 00:44:58 +04:00
|
|
|
aErrorCb.onresult(aRequestId, errorMsg);
|
2012-10-16 13:28:30 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-08-30 01:41:35 +04:00
|
|
|
// We ask the UI to browse to the selected payment flow.
|
|
|
|
let id = kOpenPaymentFlowEvent + "-" + this.getRandomId();
|
|
|
|
let detail = {
|
|
|
|
type: kOpenPaymentFlowEvent,
|
|
|
|
id: id,
|
2015-01-19 16:50:32 +03:00
|
|
|
requestId: aRequestId
|
2012-08-30 01:41:35 +04:00
|
|
|
};
|
|
|
|
|
2015-01-19 16:50:32 +03:00
|
|
|
this._setPaymentRequest = (event) => {
|
|
|
|
let message = event.detail;
|
|
|
|
if (message.id != id) {
|
2012-08-30 01:41:35 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-19 16:50:32 +03:00
|
|
|
let frame = message.frame;
|
|
|
|
let docshell = frame.contentWindow
|
|
|
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
|
|
.QueryInterface(Ci.nsIDocShell);
|
|
|
|
docshell.paymentRequestId = aRequestId;
|
|
|
|
frame.src = aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt;
|
|
|
|
SystemAppProxy.removeEventListener("mozContentEvent",
|
|
|
|
this._setPaymentRequest);
|
|
|
|
};
|
|
|
|
SystemAppProxy.addEventListener("mozContentEvent",
|
|
|
|
this._setPaymentRequest);
|
2012-10-16 13:28:30 +04:00
|
|
|
|
2015-01-19 16:50:32 +03:00
|
|
|
// We listen for UI notifications about a closed payment flow. The UI
|
2012-10-16 13:28:30 +04:00
|
|
|
// should provide the reason of the closure within the 'errorMsg' parameter
|
2015-01-19 16:50:32 +03:00
|
|
|
this._notifyPayFlowClosed = (evt) => {
|
2013-11-26 15:13:57 +04:00
|
|
|
let msg = evt.detail;
|
|
|
|
if (msg.id != id) {
|
2012-10-16 13:28:30 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-11-26 15:13:57 +04:00
|
|
|
|
|
|
|
if (msg.type != 'cancel') {
|
2012-10-16 13:28:30 +04:00
|
|
|
return;
|
|
|
|
}
|
2013-11-26 15:13:57 +04:00
|
|
|
|
|
|
|
if (msg.errorMsg) {
|
|
|
|
_error(msg.errorMsg);
|
|
|
|
}
|
2015-01-19 16:50:32 +03:00
|
|
|
|
2014-04-07 17:59:48 +04:00
|
|
|
SystemAppProxy.removeEventListener("mozContentEvent",
|
|
|
|
this._notifyPayFlowClosed);
|
2013-11-26 15:13:57 +04:00
|
|
|
this._notifyPayFlowClosed = null;
|
2015-01-19 16:50:32 +03:00
|
|
|
|
|
|
|
Services.obs.notifyObservers(null, kPaymentFlowCancelled, null);
|
|
|
|
};
|
2014-04-07 17:59:48 +04:00
|
|
|
SystemAppProxy.addEventListener("mozContentEvent",
|
2015-01-19 16:50:32 +03:00
|
|
|
this._notifyPayFlowClosed);
|
2012-08-30 01:41:35 +04:00
|
|
|
|
2014-04-07 17:59:48 +04:00
|
|
|
SystemAppProxy.dispatchEvent(detail);
|
2012-08-30 01:41:35 +04:00
|
|
|
},
|
|
|
|
|
2015-01-19 16:50:32 +03:00
|
|
|
closePaymentFlow: function(aRequestId) {
|
|
|
|
return new Promise((aResolve) => {
|
|
|
|
// After receiving the payment provider confirmation about the
|
|
|
|
// successful or failed payment flow, we notify the UI to close the
|
|
|
|
// payment flow dialog and return to the caller application.
|
|
|
|
let id = kClosePaymentFlowEvent + "-" + uuidgen.generateUUID().toString();
|
|
|
|
|
|
|
|
let detail = {
|
|
|
|
type: kClosePaymentFlowEvent,
|
|
|
|
id: id,
|
|
|
|
requestId: aRequestId
|
|
|
|
};
|
|
|
|
|
|
|
|
// In order to avoid race conditions, we wait for the UI to notify that
|
|
|
|
// it has successfully closed the payment flow and has recovered the
|
|
|
|
// caller app, before notifying the parent process to fire the success
|
|
|
|
// or error event over the DOMRequest.
|
|
|
|
SystemAppProxy.addEventListener("mozContentEvent",
|
|
|
|
(function closePaymentFlowReturn() {
|
|
|
|
SystemAppProxy.removeEventListener("mozContentEvent",
|
|
|
|
closePaymentFlowReturn);
|
|
|
|
this.cleanup();
|
|
|
|
aResolve();
|
|
|
|
}).bind(this));
|
|
|
|
|
|
|
|
SystemAppProxy.dispatchEvent(detail);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2012-10-16 13:28:30 +04:00
|
|
|
cleanup: function cleanup() {
|
2013-11-26 15:13:57 +04:00
|
|
|
if (this._handleSelection) {
|
2015-01-19 16:50:32 +03:00
|
|
|
SystemAppProxy.removeEventListener("mozContentEvent",
|
|
|
|
this._handleSelection);
|
2013-11-26 15:13:57 +04:00
|
|
|
this._handleSelection = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._notifyPayFlowClosed) {
|
2015-01-19 16:50:32 +03:00
|
|
|
SystemAppProxy.removeEventListener("mozContentEvent",
|
|
|
|
this._notifyPayFlowClosed);
|
2013-11-26 15:13:57 +04:00
|
|
|
this._notifyPayFlowClosed = null;
|
|
|
|
}
|
2012-10-16 13:28:30 +04:00
|
|
|
},
|
|
|
|
|
2012-08-30 01:41:35 +04:00
|
|
|
getRandomId: function getRandomId() {
|
|
|
|
return uuidgen.generateUUID().toString();
|
|
|
|
},
|
|
|
|
|
|
|
|
classID: Components.ID("{8b83eabc-7929-47f4-8b48-4dea8d887e4b}"),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue])
|
|
|
|
}
|
|
|
|
|
2012-10-31 20:13:28 +04:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);
|