On Feb 27, 2013, at 2:46 PM, Kumar McMillan <[email protected]> wrote:

> 
> On Feb 27, 2013, at 12:39 PM, Fernando Jiménez <[email protected]> wrote:
> 
>>>> 
>>>> 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.
> 
> Oh, right, I forgot that we added refund requests to mozPay(). The dilemma I 
> explained above is more for automated refunds where the user clicks some 
> button to get a refund *without* the developer knowing about it. In the case 
> you mention, the developer initiates the refund so that's fine; it's their 
> refund request on behalf of the customer.
> 
>> 
>> How is the Marketplace different to any other application using in-app 
>> payments in terms of API usage?
> 
> Again, this only applied to automated refunds. My bad.
> 
>>>> 
>>>> 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');
>> });
> 
> 
> Ah, ok. I am following you now! I agree. Once we come up with a prototype for 
> how it might work and we test it out then we could make it part of the 
> mozPay() API and ship an update to clients. I think the details of the API 
> calls will need some bikeshedding but there's no need for that on this thread.
> 

In talking with Daniel Buchner more about in-app payments without a server I 
developed an itch that had to be scratched. I built a quick and dirty 
prototype: https://github.com/kumar303/mozpay-catalog/

You can see the developer facing API here -- 
https://github.com/kumar303/mozpay-catalog/blob/1bb6dbc4e3d9694aa9b3815c0278d3f8c0741ddd/www/js/index.js#L56-L64
 -- but I didn't do much past simply getting it to work. It is currently 
working with simulated payments on Firefox Marketplace. 

This prototype should make it easy to try out a few things for the developer 
facing API. I'm still not sure how we would support multiple JWT audiences and 
I'm not sure how best to merge the old DOMRequest model (open/close payment 
window) with the new model of payment completed/failed. Perhaps we would need 
to move the DOMRequest to events where you listen specifically to each event 
(like XHR).

More as it happens.

-Kumar

_______________________________________________
dev-webapps mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-webapps

Reply via email to