# HTTP Messages

A specification for sending/receiving HTTP messages (request/response) via a remote server. Header / Body etc are encrypted, either in the `content` (small messages) or via a blossom server (larger requests).

![](./http.png)

## Overview

Enables a local client to make and receive http requests (PUT, POST, GET, PATCH etc) from a remote computer.  Requires:

* A trusted machine to process the messages (can be a home PC or Raspberry Pi)
* A relay (can be untrusted)
* A blossom server (can be untrusted)


## Architecture

```mermaid
architecture-beta
group user(internet)[Nostr Client]
group cloud(cloud)[Untrusted Servers]
group home(server)[Trusted Device]
service client(internet) in user
service blossom(database)[Blossom Storage] in cloud
service relay(logos:aws-ec2)[Relays] in cloud
service pc(logos:aws-elb) in home
service bbi[Big Bad Internet]

client:R -- L:blossom
client:B -- L:relay
pc:L -- R:blossom
pc:L -- R:relay
pc:B <--> T:bbi

```

## Sequence Diagram

```mermaid
sequenceDiagram
    autoNumber
    participant c as Nostr Client
    participant r as Nostr Relay
    participant b as Blossom Server
    participant s as HTTP Server

    Note over c: Convert <br>HTTP Request<br>into kind 21120
    c-->>b: Encrypt & push payload (if large)
    c->>r: Publish <br>Event
    r<<-->>s: Fetch event
    Note over s: Decrypt event
    s<<-->>b: Fetch payload <br>(if large)
    Note over s: Make HTTP REQUEST
    Note over s: Get HTTP RESPONSE
    s-->>b: Encrypt & push <br>payload (if large)
    Note over s: Create kind<br>21120 (Response)
    s->>r: Publish Event
    r<<-->>c: Fetch event
    Note over c: Decrypt event
    b<<-->>c: Fetch payload (if large)
    Note over c: Convert<br> kind 21120 into<br> HTTP Response
    c-->>b: Delete REQUEST blob (if exists)
    c->>r: Delete REQUEST event
    
```

The remote server should periodically scan for expired RESPONSE events (and associated blossom blobs) and delete them.


## Server Advertisement Event (Kind 31120)

To facilitate discovery of HTTP-over-Nostr servers, a dedicated event kind is used to advertise server availability.

```jsonc
{
  "kind": 31120,
  "pubkey": "<pubkey of server operator>",
  "content": "HTTP-over-Nostr server",  // Optional markdown description of the http server(s)
  "tags": [
    ["d", "<hex pubkey of server>"],  // Server pubkey that will be listening for requests
    ["relay", "wss://relay.one"],  // Relay where server is listening (can have multiple)
    ["relay", "wss://relay.two"],
    ["expiry", "<unix timestamp>"],  // How long this server will be online
  ],
  // other fields...
}
```

Explanations:

* `kind:31120` - BIP39 word #1120 ([message](https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt#L1120)) plus 30000 to make it addressable.
* `"content"` - Optional description of the server in markdown
* `"d"` - The hex pubkey of the HTTP server that will be processing requests
* `"relay"` - Relays where this server is listening for kind 21120 events (can have multiple)
* `"expiry"` - Timestamp after which this server advertisement should be considered expired.  Can update this to 0 to indicate an expired event.


Clients looking to use HTTP over Nostr can query for these kind 31120 events to discover available servers and may communicate with the server operator to get permission to use them.




## HTTP Requests - Kind 21120

Example **request** with a small payload.  Payload is in `content` and `P` tag is the npub of the remote HTTP server.

```jsonc
{
  "kind": 21120,
  "pubkey": "<pubkey>",
  "content": "$encryptedPayload",
  "tags": [
    ["p", "<pubkey of remote server>"], // P tag entry, this is a REQUEST
    ["key","nip44Encrypt($decryptkey)"],
    ["r", "https://relay.one"],
    ["expiration",<unix timestamp>]
  ],
  // other fields...
}
```

Explanations:

 * `kind:21120` - BIP39 word #1120 ([message](https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt#L1120)), plus 20,000 to be treated as ephemeral (not stored by relays).
 * `"content"` - encrypted JSON with location of blob **OR** the content itself (if under a threshold).  NIP-44 is NOT used as the payload may be large, affecting bunker signing stability.
* `"p"` - the pubkey of the remote HTTP server.  
 * `"key"` - the decryption key for the `content` field, also the key for the blossom blob (if used).
 * `"expiration"` - remote servers should not process requests after this time.  Relays SHOULD delete events after this time.
 * `"r"` - (optional) relay on which the response should be sent.  

### HTTP Response - Kind 21121

Example **response** with a large payload.  Valid JSON is in `content` and `E` tag is populated.  For privacy, the requestor npub is NOT shown - the requestor instead should be fetching the response using the `E` tag.

```jsonc
{
  "kind": 21121,
  "pubkey": "<pubkey>",
  "content": "encrypt({'url':'blossom.one','hash':'xx'},$decryptkey)",
  "tags": [
    ["key","nip44Encrypt($decryptkey)"],
    ["E", "<request event id>"], // E tag entry, this is a RESPONSE
    ["expiration",<unix timestamp>]
  ],
  // other fields...
}
```

Explanations:

 * `kind:21121` - A different kind is used for responses, to help with filtering and other use cases.  
 * `"content"` - encrypted JSON with location of blob **OR** the content itself (if under a threshold).  NIP-44 is NOT used as the payload may be large, affecting bunker signing stability.
 * `"key"` - the decryption key for the `content` field, also the key for the blossom blob (if used).
 * `"E"` - ID of the request event.  Enables a response to be identified, and fetched.
 * `"expiration"` - remote servers should not process requests after this time.  Relays SHOULD delete events after this time.

There is no "p" tag as the "E" tag already identifies the request.


## Considerations

This approach only makes sense in cases where privacy and anonymity are important, or if censorship is a concern.

There are a number of drawbacks to the approach:

 - Complexity.  Many more moving parts than a direct request.
 - Speed.  Each request/response now requires:
    - Encrypting the payload
    - Loading to blossom (if large)
    - Signing event
    - broadcasting event
    - remote server fetching event
    - remote server decrypting event
    - remote server fetching blossom blob (if large)
    - remote server decrypting blossom blob (if used)
    - making the actual request

And the same flow in reverse.

So why would you use it?  Several reasons:

- enables a plethora of open source apps to be made available from inside private networks (localhost) but over nostr 
- maximum server privacy (no domain needed, or port forwarding)
- Make regular API calls over Nostr