Hi :)
On 27/02/2013, at 17:58, Kumar McMillan wrote:
> On Feb 27, 2013, at 5:01 AM, Fernando Jiménez <
ferjm...@gmail.com> wrote:
>
>>> First, this proposal would not require any changes to the underlying navigator.mozPay() API or the current JWT spec. No B2G client changes would be needed. It would be built on top of these existing APIs.
>>
>> Is there any reason why you are not considering these changes an option for the navigator.mozPay() API?
>
> I had a couple reasons in mind. First is that not changing the API means we could ship a server-less solution e.g. tomorrow or whenever it's ready.
Sorry, I am not sure that I am properly understanding you. How is that we can't ship a server-less solution *changing* the API? We can always include an API change in the next version of Firefox OS, right? I guess that you are talking about being tied to an specific date or client side version. In that case, the wrapper solution could be a temporary one, but that shouldn't be a reason to not changing the API if we feel that it can be improved.
> Another is that this feels to me more like a "helper library" solution rather than an API enhancement.
An API requiring a "helper library" is probably a symptom that the API needs to be improved. However, as I mentioned before, the helper library could be a completely valid temporary solution.
>>>
>>
>> I like your proposal, but I have a few concerns about it:
>>
>> 1. This seems to be very tied and dependent of the Mozilla Marketplace. It would be great if we could allow developers to build and use its own JWT signing service, while we still give them the chance to use the one exposed by the Mozilla Marketplace or any other market (in the end, we are trying to build the most open API as possible). You may say devs already have that chance with the current API, and I agree on that, but I think that we still can make the process easier (see my proposal below, please) and somehow provide an "standard" way of signing payment requests.
>
> How is it tied specifically to Mozilla's Marketplace? Do you mean that for whatever server it's hosted on, the implementation is tied to *that* server? Then, yes. That's the only way I could see it working from a security perspective.
>
> The key point is that the client has to fetch a signed payment request (JWT) in a way that does not compromise the integrity of the payment request. If the developer wants to lock down the product price, she has to refer to the product by some identifier. The server has to know what the price is and keep it secure.
I totally agree on this and it fits perfectly well with my suggestion too. The difference is the way that we allow the client to fetch the signed JWT (with a helper, or directly with our API).
>
> But, yes, of course, if we implement this for Firefox Marketplace then we could easily do it as a standalone, easy-to-install service. Anyone could run their own service on AWS/Heroku and pay their own server bills.
That's the idea! To keep it as much open as possible. Any market or developer should be able to expose and use its own JWT signing service (based on the one for Firefox Marketplace or not). I am not arguing about the server side, but the client one. My point is that there is no need to use any wrapper in the client as we can allow to communicate with a signing service extending the current API. Why forcing the server side to also expose a shim to allow the client to communicate with it when we can do it directly from the client API?
>
>>
>> 2. IMHO a wrapper around the current API adds unnecessary complexity. We should (and probably can) build what you are proposing extending the current navigator.mozPay API. I am not sure if you are proposing the wrapper as a long term solution though. Maybe you also have in mind modifying the API with these additions in the future.
>
> It is not clear to me how the current API could be modified to securely allow server-less payments. I'm open to ideas. I think we would need some kind of drastic API change, perhaps one that managed *public* keys per merchant so that a decentralized chain of trust can be established. Even in such a case, I think servers need to be involved in that for security.
I am proposing an idea :)
>>
>> 3. How would you manage refunds? I can't see how would you tell the web service that your intention is to get a JWT for a refund request and not for a payment one.
>
> That's a good question! However, refunds are so hard for in-app payments that we've pretty much already ignored them. The current API also has no reliable way to do refunds. Take the example of ad-hoc JWTs (in the current API). Let's say a customer paid to "unlock level 10" then she beat level 10 and decided to be sneaky and ask for a refund. How do we grant a refund? The current navigator.mozPay() has no memory of "the product." It cannot take away "Unlock level 10" after a refund because it doesn't know how. In this case, it would be impossible to take away Unlock level 10.
>
> For now we are not supporting refunds for in-app payments. In the future, maybe developers could opt-in to refunds and then our app reviewers would have to be sure that they *can* grant refunds before we allow them to.
>
> For Marketplace app purchases, it's easier to implement refunds because we know what the app logic is inside the Firefox Marketplace. We know how to take away apps.
The current API does not *do* refunds but provides a way to *request* refunds. The same way as it does for payments.
How is the Marketplace different to any other application using in-app payments in terms of API usage?
A developer is free to implement a mechanism to cancel the product that she is selling as soon as she gets the chargeback notification. Anyway, I am not going to discuss about refunds as I don't want to divert attention from the main topic, but IMHO we should leave that door open on the client side.
>
>>
>>
>> So my proposal, based on yours, would be extending the API this way:
>>
>> "DOMDOMRequest mozPay(DOMString signingService, jsval dataToBeSigned)"
>>
>> where:
>> - "signingService" would be the URL of the Mozilla web service or any other JWT signing web service.
>> - "dataToBeSigned" would be a JSON object containing whatever is expected by the signing service. It could be the identifier of the product being sold or refunded and a flag for setting a payment or a refund, for example.
>
> ok, let's say an app does this:
>
> nav.mozPay('
https://mkt/payments/signing-service', {
> request: {
> name: 'Rainbow Unicorn',
> pricePoint: 4 // USD $3.99
> }
> })
>
> What would that do? POST the raw JSON blob to the signing service and get backed a signed JWT? That would defeat the purpose of the signature because then anyone can sign anything. An attacker could just patch the app and change the JS to do this (note the price change):
>
> nav.mozPay('
https://mkt/payments/signing-service', {
> request: {
> name: 'Rainbow Unicorn',
> pricePoint: 1 // USD $0.99
> }
> })
>
> and they would get the product for whatever price they wanted. Am I missing something?
No.
Sorry if I didn't explained myself properly.
What an app should do depends on what the signing service expects and it is very similar to what you are proposing.
Let's say that the signing service is the one exposed by the Firefox Marketplace, which expects a "productId". Instead of doing:
var unicornId = 1234;
payment.start(unicornId, function(jwt, transaction) {
var request = navigator.mozPay([jwt]);
request.onsuccess = function() {
transaction.whenDone(function(error) {
if (!error) {
alert('You bought a Rainbow Unicorn!');
}
});
};
});
The developer could do something like:
var unicornId = 1234;
var req = navigator.mozPay('
https://mkt/payments/signing-service', {
productId: unicornId
});
req.onsuccess = function(evt) {
alert('Payment request done!);
// Use evt.target.result.transactionId to check that the product was paid for, as you suggest, polling something like: GET /payment/status/<transactionId>
});
req.onerror = function(evt) {
alert('Error');
});
Cheers!
/ Fernando