-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updated HTTP-ILP (Continuation of #149) #306
Changes from all commits
8829cf9
bce7f81
a4bf6cf
dad2e30
19866ef
ce37e55
58d8dcb
4c04e7e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
--- | ||
title: HTTP-ILP | ||
draft: 1 | ||
--- | ||
# HTTP-ILP | ||
|
||
> A standard for paid HTTP requests. | ||
|
||
# Design Goals | ||
|
||
Design a protocol to pay for HTTP requests. | ||
|
||
Criteria: | ||
|
||
* Minimum number of roundtrips | ||
* Interaction with HTTP server is via HTTP (actually HTTPS) calls only - we want to tie into the existing load balancing and security infrastructure (HTTPS), no need to run any JavaScript/Websocket client on the HTTP server or other shenanigans | ||
|
||
# Flows | ||
|
||
## 1. Setup | ||
|
||
###### Scenario | ||
|
||
**Ankita** is a *server admin* who owns a file hosting service at `myservice.example` and would like to provide an API where her users can upload files without having to register first. In order to enable this in a standards-compliant way, she decides to use HTTP-ILP. | ||
|
||
### 1.1. Server admin installs an ILP payment module | ||
|
||
After deciding to use HTTP-ILP, Ankita searches the web on instructions on how to set this up. She finds an open-source HTTP-ILP server module which is compatible with the REST framework ([Koa](https://koajs.com)) that she is already using, for instance [koa-ilp](https://github.com/justmoon/koa-ilp). | ||
|
||
She installs the HTTP-ILP server module. The module provides middleware which she adds to the different API endpoints in order to set prices for each one. | ||
|
||
According to the documentation of the HTTP-ILP server module, she learns that she can pass an [Interledgerjs plugin](../0004-ledger-plugin-interface/0004-ledger-plugin-interface.md) to the module, to receive payments. | ||
|
||
### 1.2. Server admin sets up a new receiver | ||
|
||
|
||
Ankita creates a dedicated subaccount under her account at her Interledger service provider, and takes a note of that subaccount's credentials. | ||
|
||
### 1.3. Server admin enters credentials into the HTTP-ILP server module config | ||
|
||
Next, Ankita logs back into her server and edits a config file of the HTTP-ILP server module to enter the plugin type and credentials she obtained: | ||
|
||
```sh | ||
export PLUGIN_NAME=ilp-plugin-btp-client | ||
export PLUGIN_CONFIG={"server":"btp+wss://ankita+filepay:fxPERNaS4FGlC8H7eg6UfYVlglmFynFc8nh5la9PBGM@nexus.justmoon.com"} | ||
``` | ||
|
||
Next, she restarts her server to load the new configuration. | ||
|
||
### 1.4. Paid HTTP server fetches receiver information | ||
|
||
When the HTTP-ILP server module loads up, it calls [plugin#connect](../0004-ledger-plugin-interface/0004-ledger-plugin-interface.md#connect) so that the plugin | ||
gets a subscription to its ledger. Through this subscription, the plugin can listen for incoming payments. | ||
The module then uses [plugin#getAccount](../0004-ledger-plugin-interface/0004-ledger-plugin-interface.md#getaccount) to look up the Interledger address from the plugin | ||
and caches it in memory for a certain period. | ||
|
||
This completes the setup process. The server is now ready to receive paid API requests. | ||
|
||
## 2. Client interaction | ||
|
||
###### Scenario | ||
|
||
**Marat** is a *graphic designer* who would like to upload a mockup image to share with a client. His friend recommended a tool which doesn't require any signup or configuration and uses his existing ILP account to pay for the storage and bandwidth fees. | ||
|
||
![Sequence Diagram](sequence.png) | ||
|
||
### 2.1. Client generates a server-specific token from the hostname and its local secret: | ||
|
||
The uploader tool contains an HTTP-ILP client module | ||
like [superagent-ilp](https://github.com/justmoon/superagent-ilp) or [ilp-curl](https://github.com/sharafian/ilp-curl). | ||
This client module may for instance generate and locally save a `client_secret` using 256 bits of cryptographically secure randomness. | ||
|
||
Before making the paid HTTP request, the HTTP-ILP client module generates a **token**, for instance using such a `client_secret` and the `hostname` of the server it is about to make a request to: | ||
|
||
* Token: `HMAC(SHA256, client_secret, hostname)` | ||
|
||
### 2.1. Client attempts to call API using token | ||
|
||
The paid HTTP request is fired off: | ||
|
||
``` http | ||
OPTIONS /upload HTTP/1.1 | ||
Host: myservice.example | ||
Pay-Token: 7y0SfeN7lCuq0GFF5UsMYZofIjJ7LrvPvsePVWSv450 | ||
Unhash-Content-Length: 123 | ||
``` | ||
|
||
Note that the client hasn't paid at this point and is only making the request to solicit a response from the server, that's why the OPTIONS verb is used. In this example, | ||
`Unhash-Content-Length` is an application-specific header which describes the request which the client intends to make. | ||
|
||
### 2.2. Server responds with payment details | ||
|
||
The server returns an HTTP code of `204 No Content` and includes response headers showing the amount, an ILP address and a shared secret. | ||
The amount expresses how much the request would have cost, as a decimal string and counted in the base unit of the ledger to which the ILP address belongs. | ||
|
||
``` http | ||
HTTP/1.1 204 No Content | ||
Pay: 10 us.nexus.ankita.~recv.filepay SkTcFTZCBKgP6A6QOUVcwWCCgYIP4rJPHlIzreavHdU | ||
Pay-Balance: 0 | ||
``` | ||
|
||
The client can now use the shared secret to create a condition to pay this host. The shared secret may for instance be generated by the server as follows: | ||
|
||
* Shared Secret: `HMAC(SHA256, receiver_secret, token)` | ||
|
||
The shared_secret is now a shared secret between the client and server, but will be unknown to any third-party connectors between them. | ||
|
||
### 2.3. Client initiates an ILP payment to refill its balance | ||
|
||
In order to refill its balance, the client now creates an ILP payment with the following properties: | ||
|
||
* Destination: `us.nexus.ankita.~recv.filepay` | ||
* Amount: `100` | ||
* Condition: `SHA256(fulfillment)` | ||
* Memo: `pay_token` | ||
|
||
The `fulfillment` is generated from the shared secret using [PSK](../0016-pre-shared-key/0016-pre-shared-key.md). | ||
|
||
When the prepared payment reaches the server, it is fulfilled and the token's balance is increased. | ||
|
||
There is a chance that the HTTP-ILP server module will process the payment, but the fulfillment doesn't make it all the way back to the sender. | ||
|
||
### 2.6. Sender/client receives the fulfillment. | ||
|
||
Once the HTTP-ILP client module receives the fulfillment, it will now retry its original request: | ||
|
||
``` http | ||
POST /upload HTTP/1.1 | ||
Host: myservice.example | ||
Pay-Token: 7y0SfeN7lCuq0GFF5UsMYZofIjJ7LrvPvsePVWSv450 | ||
``` | ||
``` | ||
[...] | ||
``` | ||
|
||
The request succeeds: | ||
|
||
``` http | ||
HTTP/1.1 200 OK | ||
Pay: 10 us.nexus.ankita.~recv.filepay SkTcFTZCBKgP6A6QOUVcwWCCgYIP4rJPHlIzreavHdU | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unhash might make a better example application, because we know exactly what the API calls look like for it. For instance, an Unhash There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, I'll add |
||
Pay-Balance: 90 | ||
``` | ||
|
||
Notice how the 100 units credit from the payment was added to the balance and the 10 unit cost for the current request was subtracted. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
sequenceDiagram | ||
participant Payer | ||
participant Interledger | ||
participant PayeeWallet | ||
participant Payee | ||
activate Payer | ||
Payer->>+Payee: OPTIONS preflight | ||
Payee-->>-Payer: 204 preflight response | ||
Payer->>Interledger: Quote Request | ||
activate Interledger | ||
Interledger->>Payer: Quote Response | ||
deactivate Interledger | ||
Payer->>Interledger: Prepare Payment | ||
activate Interledger | ||
Interledger->>PayeeWallet: Prepare Payment | ||
deactivate Interledger | ||
activate PayeeWallet | ||
PayeeWallet->>+Payee: Webhook Request | ||
deactivate PayeeWallet | ||
Payee-->>-PayeeWallet: Webhook Response | ||
activate PayeeWallet | ||
PayeeWallet-->>Interledger: Fulfill Payment | ||
deactivate PayeeWallet | ||
activate Interledger | ||
Interledger-->>Payer: Payment Fulfilled | ||
deactivate Interledger | ||
Payer->>+Payee: POST Paid Request | ||
Payee-->>-Payer: 200 OK | ||
deactivate Payer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should explain that the destinationAccount and sharedSecret are used as the parameters to PSK