[w3c/payment-request] Refactoring PaymentRequest (#914)

`PaymentRequest` was primarily designed to offer:
- A standardized Web-based payment API for **Merchants**.
- Browser-generated lists of _matching payment alternatives_ for **Users** to select from.

In retrospect it has become evident that there are many "standards" in the payment world and there is rather little the W3C can do about that. In addition, most providers of mobile phone based payment solutions like the [EMPSA](https://empsa.org/) members, are targeting quite different payment scenarios with the same native mode "wallet" _making Web-only solutions somewhat less useful_.

Rather than dumping all the good work that has gone into the `PaymentRequest` API, this issue outlines an update which permits the existing API to be "mapped" to a new API that universalizes the core functionality of `PaymentRequest` which simply is enabling Web applications to securely interact with installed applications which do not necessarily follow the general Web security model (SOP).

The proposed API would effectively create a bi-directional, asynchronous "channel" to installed applications (native or Web-based) which are specifically crafted to be "Web-callable". This API would inherit a bunch of things from `PaymentRequest` including:
- User gesture for invocation. 
- Payment method URL which would now be an application ID.
- `show()` as now.
- Web Manifests.

### Security Considerations
Wouldn't such an API introduce insurmountable security and privacy issues like the nowadays deprecated `NPAPI` and `ActiveX` solutions once did? No, the latter ran _inside_ of browsers with full access to browser internals which created all sorts of problems. _From what I can deduct the existing PaymentRequest API does not (in itself) stop potential misuses_. In fact, native payment handlers in Android have access to **everything** offered by the operating system and granted by the user!

Obviously "Web-callable" applications **must** be designed with great care and ideally be subjected to a more thorough vetting process than "ordinary" applications.

See also [Calling "Apps" from the Web](https://cyberphone.github.io/doc/web/calling-apps-from-the-web.pdf).  

### Desktop Web to Mobile Wallet
A drawback with the current `PaymentRequest` API is that it doesn't address the quite popular scenario where a mobile phone "wallet" is used to together with a Web application running in a desktop computer.  This scenario is fully supported by FIDO2 standards but can only be used for FIDO2. To cope with this the "channel" API (in similarity to FIDO2), should also be exposable via BLE and USB. For a calling Web application, this distinction should be close to transparent. It is worth noting that in the BLE and USB configurations, security measures (with gestures as the sole exception), are moved to the attached mobile devices which thus **must** be "intelligent".

The "channel" itself would be based on **binary streams** to cope with all formats in the wild, including those that are yet to be invented.

### Mapping `PaymentRequest`
For "mapping" `PaymentRequest` into "channel" based payment handler applications, JSON would be the intermediary transport format since it readily translates back and forth into JavaScript. This change would be invisible on the Web but require revised payment handler code.

### Further Enhancements Enabled by the Proposed API
In a proof-of-concept system called [Saturn](https://cyberphone.github.io/doc/saturn), the very same JSON message set are used both at the PoS terminal and on the Web. The only difference is the invocation which is based on QR holding an invocation URL respectively `PaymentRequest` (in "emulator" mode as shown in the next section), making the "wallet" comparatively simple as well as easier to integrate for **Merchants** and **Payment Providers**.

For **Users** this arrangement leads to a more uniform way of dealing with payments compared to systems like Apple Pay which at the PoS terminal is limited to EMV (card) level messaging.

The very same system is also used for enrollment of payment credentials which is performed via the 10-pass [KeyGen2](https://cyberphone.github.io/doc/security/keygen2.html) protocol.

### Emulating "Web-callable" APIs Using Android
**JavaScript Invocation**
```js
const dummyDetails = {total:{label:'total',amount:{currency:'USD',value:'1.00'}}};
const methodData = [{
  supportedMethods: 'https://methodhost/proxy',
  data: ['customCodedUrl']
}];
const w3cPaymentRequest = new PaymentRequest(methodData, dummyDetails);
```
The `customCodedUrl` tells the receiving proxy code which particular sub API that is requested.  The `customCodedUrl` also contains an encoded parameter holding a URL which is used to fetch the JSON request data.  By relying on the skip-the-sheet mode, the browser `PaymentRequest` UI is never shown.

Using a URL may look a bit quirky; it was only used to maintain compatibility with the URL handler scheme.

**AndroidManifest.xml**
```xml
<activity
    android:name=".ProxyActivity"
    android:exported="true">
    <intent-filter>
       <action android:name="org.chromium.intent.action.PAY"/>
    </intent-filter>
    <meta-data android:name="org.chromium.default_payment_method_name"
       android:value="https://methodhost/proxy"/>
</activity>
```
**Android Java Code**
```java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_proxy);
    final Bundle extras = getIntent().getExtras();
    if (extras == null) {
        bad("Missing extras");
        return;
    }
    ArrayList<String> methodNames = extras.getStringArrayList("methodNames");
    if (methodNames == null || methodNames.size() != 1) {
        bad("Missing or too many methodNames");
        return;
    }
    Bundle methodData = extras.getBundle("methodData");
    if (methodData == null) {
        bad("Missing methodData");
        return;
    }
    String jsonString = methodData.getString(methodNames.get(0));
    if (jsonString == null) {
        bad("Missing 'data'");
        return;
    }
    // ["the url we are looking for"]
    final Uri proxyUrl = Uri.parse(jsonString.substring(2, jsonString.length() - 2));
    // Core decoding, now over to the parameters...
}
```
### Enhancing `PaymentHandler`
It would be cool if the universalized API also could be applied to the W3C `PaymentHandler` but that is outside of my competence and interest.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/payment-request/issues/914

Received on Saturday, 9 May 2020 05:15:00 UTC