Merge branch 'nostr-protocol:master' into nip42-auth-by-payment

This commit is contained in:
Arjen 2024-11-26 21:27:15 +01:00 committed by GitHub
commit 789011749e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 295 additions and 57 deletions

2
24.md
View File

@ -6,7 +6,7 @@ Extra metadata fields and tags
`draft` `optional` `draft` `optional`
This NIP defines extra optional fields added to events. This NIP keeps track of extra optional fields that can added to events which are not defined anywhere else but have become _de facto_ standards and other minor implementation possibilities that do not deserve their own NIP and do not have a place in other NIPs.
kind 0 kind 0
====== ======

46
29.md
View File

@ -22,15 +22,15 @@ Relays are supposed to generate the events that describe group metadata and grou
A group may be identified by a string in the format `<host>'<group-id>`. For example, a group with _id_ `abcdef` hosted at the relay `wss://groups.nostr.com` would be identified by the string `groups.nostr.com'abcdef`. A group may be identified by a string in the format `<host>'<group-id>`. For example, a group with _id_ `abcdef` hosted at the relay `wss://groups.nostr.com` would be identified by the string `groups.nostr.com'abcdef`.
Group identifiers must be strings restricted to the characters `a-z0-9-_`. Group identifiers must be strings restricted to the characters `a-z0-9-_`, and SHOULD be random in order to avoid name collisions.
When encountering just the `<host>` without the `'<group-id>`, clients can choose to connect to the group with id `_`, which is a special top-level group dedicated to relay-local discussions. When encountering just the `<host>` without the `'<group-id>`, clients MAY infer `_` as the group id, which is a special top-level group dedicated to relay-local discussions.
Group identifiers in most cases should be random or pseudo-random, as that mitigates message replay confusion and ensures they can be migrated or forked to other relays easily without risking conflicting with other groups using the same id in these new relays. This isn't a hard rule, as, for example, in `unmanaged` and/or ephemeral relays groups might not want to migrate ever, so they might not care about this. Notably, the `_` relay-local group isn't expected to be migrated ever.
## The `h` tag ## The `h` tag
Events sent by users to groups (chat messages, text notes, moderation events etc) must have an `h` tag with the value set to the group _id_. Events sent by users to groups (chat messages, text notes, moderation events etc) MUST have an `h` tag with the value set to the group _id_.
`h` tags MAY include the group's name as the second argument. This allows `unmanaged` groups to be assigned human-readable names without relay support.
## Timeline references ## Timeline references
@ -64,39 +64,7 @@ These are the events expected to be found in NIP-29 groups.
### Normal user-created events ### Normal user-created events
These events generally can be sent by all members of a group and they require the `h` tag to be present so they're attached to a specific group. Groups may accept any event kind, including chats, threads, long-form articles, calendar, livestreams, market announcements and so on. These should be as defined in their respective NIPs, with the addition of the `h` tag.
- _chat message_ (`kind:9`)
This is the basic unit of a _chat message_ sent to a group.
```jsonc
"kind": 9,
"content": "hello my friends lovers of pizza",
"tags": [
["h", "<group-id>"],
["previous", "<event-id-first-chars>", "<event-id-first-chars>", /*...*/]
]
// other fields...
```
- _thread root post_ (`kind:11`)
This is the basic unit of a forum-like root thread post sent to a group.
```jsonc
"kind": 11,
"content": "hello my friends lovers of pizza",
"tags": [
["h", "<group-id>"],
["previous", "<event-id-first-chars>", "<event-id-first-chars>", /*...*/]
]
// other fields...
```
- _other events_:
Groups may also accept other events, like [NIP-22](22.md) comments as threaded replies to both chats messages and threads, long-form articles, calendar, livestreams, market announcements and so on. These should be as defined in their respective NIPs, with the addition of the `h` tag.
### User-related group management events ### User-related group management events
@ -273,4 +241,4 @@ A definition for `kind:10009` was included in [NIP-51](51.md) that allows client
### Using `unmanaged` relays ### Using `unmanaged` relays
To prevent event leakage, replay and confusion, when using `unmanaged` relays, clients should include the [NIP-70](70.md) `-` tag, as just the `previous` tag won't be checked by other `unmanaged` relays. To prevent event leakage, when using `unmanaged` relays, clients should include the [NIP-70](70.md) `-` tag, as just the `previous` tag won't be checked by other `unmanaged` relays.

14
46.md
View File

@ -49,11 +49,21 @@ _user_ passes this token to _client_, which then sends `connect` request to _rem
### Direct connection initiated by the _client_ ### Direct connection initiated by the _client_
_client_ provides a connection token in the form: _client_ provides a connection token using `nostrconnect://` as the protocol, and `client-pubkey` as the origin. Additional information should be passed as query parameters:
- `relay` (required) - one or more relay urls on which the _client_ is listening for responses from the _remote-signer_.
- `secret` (required) - a short random string that the _remote-signer_ should return as the `result` field of its response.
- `perms` (optional) - a comma-separated list of permissions the _client_ is requesting be approved by the _remote-signer_
- `name` (optional) - the name of the _client_ application
- `url` (optional) - the canonical url of the _client_ application
- `image` (optional) - a small image representing the _client_ application
Here's an example:
``` ```
nostrconnect://<client-pubkey>?relay=<wss://relay-to-connect-on>&metadata=<json metadata: {"name":"...", "url": "...", "description": "...", "perms": "..."}>&secret=<required-secret-value> nostrconnect://83f3b2ae6aa368e8275397b9c26cf550101d63ebaab900d19dd4a4429f5ad8f5?relay=wss%3A%2F%2Frelay1.example.com&perms=nip44_encrypt%2Cnip44_decrypt%2Csign_event%3A13%2Csign_event%3A14%2Csign_event%3A1059&name=My+Client&secret=0s8j2djs&relay=wss%3A%2F%2Frelay2.example2.com
``` ```
_user_ passes this token to _remote-signer_, which then sends `connect` *response* event to the `client-pubkey` via the specified relays. Client discovers `remote-signer-pubkey` from connect response author. `secret` value MUST be provided to avoid connection spoofing, _client_ MUST validate the `secret` returned by `connect` response. _user_ passes this token to _remote-signer_, which then sends `connect` *response* event to the `client-pubkey` via the specified relays. Client discovers `remote-signer-pubkey` from connect response author. `secret` value MUST be provided to avoid connection spoofing, _client_ MUST validate the `secret` returned by `connect` response.
## Request Events `kind: 24133` ## Request Events `kind: 24133`

126
47.md
View File

@ -8,32 +8,42 @@ Nostr Wallet Connect
## Rationale ## Rationale
This NIP describes a way for clients to access a remote Lightning wallet through a standardized protocol. Custodians may implement this, or the user may run a bridge that bridges their wallet/node and the Nostr Wallet Connect protocol. This NIP describes a way for clients to access a remote lightning wallet through a standardized protocol. Custodians may implement this, or the user may run a bridge that bridges their wallet/node and the Nostr Wallet Connect protocol.
## Terms ## Terms
* **client**: Nostr app on any platform that wants to pay Lightning invoices. * **client**: Nostr app on any platform that wants to interact with a lightning wallet.
* **user**: The person using the **client**, and want's to connect their wallet app to their **client**. * **user**: The person using the **client**, and wants to connect their wallet to their **client**.
* **wallet service**: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi). This app has access to the APIs of the wallets it serves. * **wallet service**: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi). This app has access to the APIs of the wallets it serves.
## Theory of Operation ## Theory of Operation
1. **Users** who wish to use this NIP to send lightning payments to other nostr users must first acquire a special "connection" URI from their NIP-47 compliant wallet application. The wallet application may provide this URI using a QR screen, or a pasteable string, or some other means. 1. **Users** who wish to use this NIP to allow **client(s)** to interact with their wallet must first acquire a special "connection" URI from their NIP-47 compliant wallet application. The wallet application may provide this URI using a QR screen, or a pasteable string, or some other means.
2. The **user** should then copy this URI into their **client(s)** by pasting, or scanning the QR, etc. The **client(s)** should save this URI and use it later whenever the **user** makes a payment. The **client** should then request an `info` (13194) event from the relay(s) specified in the URI. The **wallet service** will have sent that event to those relays earlier, and the relays will hold it as a replaceable event. 2. The **user** should then copy this URI into their **client(s)** by pasting, or scanning the QR, etc. The **client(s)** should save this URI and use it later whenever the **user** (or the **client** on the user's behalf) wants to interact with the wallet. The **client** should then request an `info` (13194) event from the relay(s) specified in the URI. The **wallet service** will have sent that event to those relays earlier, and the relays will hold it as a replaceable event.
3. When the **user** initiates a payment their nostr **client** create a `pay_invoice` request, encrypts it using a token from the URI, and sends it (kind 23194) to the relay(s) specified in the connection URI. The **wallet service** will be listening on those relays and will decrypt the request and then contact the **user's** wallet application to send the payment. The **wallet service** will know how to talk to the wallet application because the connection URI specified relay(s) that have access to the wallet app API. 3. When the **user** initiates a payment their nostr **client** create a `pay_invoice` request, encrypts it using a token from the URI, and sends it (kind 23194) to the relay(s) specified in the connection URI. The **wallet service** will be listening on those relays and will decrypt the request and then contact the **user's** wallet application to send the payment. The **wallet service** will know how to talk to the wallet application because the connection URI specified relay(s) that have access to the wallet app API.
4. Once the payment is complete the **wallet service** will send an encrypted `response` (kind 23195) to the **user** over the relay(s) in the URI. 4. Once the payment is complete the **wallet service** will send an encrypted `response` (kind 23195) to the **user** over the relay(s) in the URI.
5. The **wallet service** may send encrypted notifications (kind 23196) of wallet events (such as a received payment) to the **client**.
## Events ## Events
There are three event kinds: There are four event kinds:
- `NIP-47 info event`: 13194 - `NIP-47 info event`: 13194
- `NIP-47 request`: 23194 - `NIP-47 request`: 23194
- `NIP-47 response`: 23195 - `NIP-47 response`: 23195
- `NIP-47 notification event`: 23196
The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which commands it supports. The content should be ### Info Event
a plaintext string with the supported commands, space-separated, eg. `pay_invoice get_balance`. Only the `pay_invoice` command is described in this NIP, but other commands might be defined in different NIPs.
The info event should be a replaceable event that is published by the **wallet service** on the relay to indicate which capabilities it supports.
The content should be a plaintext string with the supported capabilities space-separated, eg. `pay_invoice get_balance notifications`.
If the **wallet service** supports notifications, the info event SHOULD contain a `notifications` tag with the supported notification types space-separated, eg. `payment_received payment_sent`.
### Request and Response Events
Both the request and response events SHOULD contain one `p` tag, containing the public key of the **wallet service** if this is a request, and the public key of the **user** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to. Both the request and response events SHOULD contain one `p` tag, containing the public key of the **wallet service** if this is a request, and the public key of the **user** if this is a response. The response event SHOULD contain an `e` tag with the id of the request event it is responding to.
Optionally, a request can have an `expiration` tag that has a unix timestamp in seconds. If the request is received after this timestamp, it should be ignored. Optionally, a request can have an `expiration` tag that has a unix timestamp in seconds. If the request is received after this timestamp, it should be ignored.
@ -68,6 +78,22 @@ The `result_type` field MUST contain the name of the method that this event is r
The `error` field MUST contain a `message` field with a human readable error message and a `code` field with the error code if the command was not successful. The `error` field MUST contain a `message` field with a human readable error message and a `code` field with the error code if the command was not successful.
If the command was successful, the `error` field must be null. If the command was successful, the `error` field must be null.
### Notification Events
The notification event SHOULD contain one `p` tag, the public key of the **user**.
The content of notifications is encrypted with [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md), and is a JSON-RPCish object with a semi-fixed structure:
```jsonc
{
"notification_type": "payment_received", //indicates the structure of the notification field
"notification": {
"payment_hash": "0123456789abcdef..." // notification-related data
}
}
```
### Error codes ### Error codes
- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds. - `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds.
- `NOT_IMPLEMENTED`: The command is not known or is intentionally not implemented. - `NOT_IMPLEMENTED`: The command is not known or is intentionally not implemented.
@ -120,7 +146,8 @@ Response:
{ {
"result_type": "pay_invoice", "result_type": "pay_invoice",
"result": { "result": {
"preimage": "0123456789abcdef..." // preimage of the payment "preimage": "0123456789abcdef...", // preimage of the payment
"fees_paid": 123, // value in msats, optional
} }
} }
``` ```
@ -155,7 +182,8 @@ payment hash of the invoice should be used.
{ {
"result_type": "multi_pay_invoice", "result_type": "multi_pay_invoice",
"result": { "result": {
"preimage": "0123456789abcdef..." // preimage of the payment "preimage": "0123456789abcdef...", // preimage of the payment
"fees_paid": 123, // value in msats, optional
} }
} }
``` ```
@ -189,6 +217,7 @@ Response:
"result_type": "pay_keysend", "result_type": "pay_keysend",
"result": { "result": {
"preimage": "0123456789abcdef...", // preimage of the payment "preimage": "0123456789abcdef...", // preimage of the payment
"fees_paid": 123, // value in msats, optional
} }
} }
``` ```
@ -225,7 +254,8 @@ pubkey should be used.
{ {
"result_type": "multi_pay_keysend", "result_type": "multi_pay_keysend",
"result": { "result": {
"preimage": "0123456789abcdef..." // preimage of the payment "preimage": "0123456789abcdef...", // preimage of the payment
"fees_paid": 123, // value in msats, optional
} }
} }
``` ```
@ -394,6 +424,59 @@ Response:
"block_height": 1, "block_height": 1,
"block_hash": "hex string", "block_hash": "hex string",
"methods": ["pay_invoice", "get_balance", "make_invoice", "lookup_invoice", "list_transactions", "get_info"], // list of supported methods for this connection "methods": ["pay_invoice", "get_balance", "make_invoice", "lookup_invoice", "list_transactions", "get_info"], // list of supported methods for this connection
"notifications": ["payment_received", "payment_sent"], // list of supported notifications for this connection, optional.
}
}
```
## Notifications
### `payment_received`
Description: A payment was successfully received by the wallet.
Notification:
```jsonc
{
"notification_type": "payment_received",
"notification": {
"type": "incoming",
"invoice": "string", // encoded invoice
"description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional
"preimage": "string", // payment's preimage
"payment_hash": "string", // Payment hash for the payment
"amount": 123, // value in msats
"fees_paid": 123, // value in msats
"created_at": unixtimestamp, // invoice/payment creation time
"expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
"settled_at": unixtimestamp, // invoice/payment settlement time
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
}
}
```
### `payment_sent`
Description: A payment was successfully sent by the wallet.
Notification:
```jsonc
{
"notification_type": "payment_sent",
"notification": {
"type": "outgoing",
"invoice": "string", // encoded invoice
"description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional
"preimage": "string", // payment's preimage
"payment_hash": "string", // Payment hash for the payment
"amount": 123, // value in msats
"fees_paid": 123, // value in msats
"created_at": unixtimestamp, // invoice/payment creation time
"expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
"settled_at": unixtimestamp, // invoice/payment settlement time
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
} }
} }
``` ```
@ -407,3 +490,24 @@ Response:
## Using a dedicated relay ## Using a dedicated relay
This NIP does not specify any requirements on the type of relays used. However, if the user is using a custodial service it might make sense to use a relay that is hosted by the custodial service. The relay may then enforce authentication to prevent metadata leaks. Not depending on a 3rd party relay would also improve reliability in this case. This NIP does not specify any requirements on the type of relays used. However, if the user is using a custodial service it might make sense to use a relay that is hosted by the custodial service. The relay may then enforce authentication to prevent metadata leaks. Not depending on a 3rd party relay would also improve reliability in this case.
## Appendix
### Example NIP-47 info event
```jsonc
{
"id": "df467db0a9f9ec77ffe6f561811714ccaa2e26051c20f58f33c3d66d6c2b4d1c",
"pubkey": "c04ccd5c82fc1ea3499b9c6a5c0a7ab627fbe00a0116110d4c750faeaecba1e2",
"created_at": 1713883677,
"kind": 13194,
"tags": [
[
"notifications",
"payment_received payment_sent"
]
],
"content": "pay_invoice pay_keysend get_balance get_info make_invoice lookup_invoice list_transactions multi_pay_invoice multi_pay_keysend sign_message notifications",
"sig": "31f57b369459b5306a5353aa9e03be7fbde169bc881c3233625605dd12f53548179def16b9fe1137e6465d7e4d5bb27ce81fd6e75908c46b06269f4233c845d8"
}
```

34
7D.md Normal file
View File

@ -0,0 +1,34 @@
NIP-7D
======
Threads
-------
`draft` `optional`
A thread is a `kind 11` event. Threads SHOULD include a `subject` with a summary
of the thread's topic.
```json
{
"kind": 11,
"content": "Good morning",
"tags": [
["subject", "GM"]
]
}
```
Replies to `kind 11` MUST use [NIP-22](./22.md) `kind 1111` comments. Replies should
always be to the root `kind 11` to avoid arbitrarily nested reply hierarchies.
```json
{
"kind": 1111,
"content": "Cool beans",
"tags": [
["K", "11"],
["E", <event-id>, <relay-url>, <pubkey>]
]
}
```

90
86.md Normal file
View File

@ -0,0 +1,90 @@
NIP-86
======
Relay Management API
--------------------
`draft` `optional`
Relays may provide an API for performing management tasks. This is made available as a JSON-RPC-like request-response protocol over HTTP, on the same URI as the relay's websocket.
When a relay receives an HTTP(s) request with a `Content-Type` header of `application/nostr+json+rpc` to a URI supporting WebSocket upgrades, it should parse the request as a JSON document with the following fields:
```json
{
"method": "<method-name>",
"params": ["<array>", "<of>", "<parameters>"]
}
```
Then it should return a response in the format
```json
{
"result": {"<arbitrary>": "<value>"},
"error": "<optional error message, if the call has errored>"
}
```
This is the list of **methods** that may be supported:
* `supportedmethods`:
- params: `[]`
- result: `["<method-name>", "<method-name>", ...]` (an array with the names of all the other supported methods)
* `banpubkey`:
- params: `["<32-byte-hex-public-key>", "<optional-reason>"]`
- result: `true` (a boolean always set to `true`)
* `listbannedpubkeys`:
- params: `[]`
- result: `[{"pubkey": "<32-byte-hex>", "reason": "<optional-reason>"}, ...]`, an array of objects
* `allowpubkey`:
- params: `["<32-byte-hex-public-key>", "<optional-reason>"]`
- result: `true` (a boolean always set to `true`)
* `listallowedpubkeys`:
- params: `[]`
- result: `[{"pubkey": "<32-byte-hex>", "reason": "<optional-reason>"}, ...]`, an array of objects
* `listeventsneedingmoderation`:
- params: `[]`
- result: `[{"id": "<32-byte-hex>", "reason": "<optional-reason>"}]`, an array of objects
* `allowevent`:
- params: `["<32-byte-hex-event-id>", "<optional-reason>"]`
- result: `true` (a boolean always set to `true`)
* `banevent`:
- params: `["<32-byte-hex-event-id>", "<optional-reason>"]`
- result: `true` (a boolean always set to `true`)
* `listbannedevents`:
- params: `[]`
- result: `[{"id": "<32-byte hex>", "reason": "<optional-reason>"}, ...]`, an array of objects
* `changerelayname`:
- params: `["<new-name>"]`
- result: `true` (a boolean always set to `true`)
* `changerelaydescription`:
- params: `["<new-description>"]`
- result: `true` (a boolean always set to `true`)
* `changerelayicon`:
- params: `["<new-icon-url>"]`
- result: `true` (a boolean always set to `true`)
* `allowkind`:
- params: `[<kind-number>]`
- result: `true` (a boolean always set to `true`)
* `disallowkind`:
- params: `[<kind-number>]`
- result: `true` (a boolean always set to `true`)
* `listallowedkinds`:
- params: `[]`
- result: `[<kind-number>, ...]`, an array of numbers
* `blockip`:
- params: `["<ip-address>", "<optional-reason>"]`
- result: `true` (a boolean always set to `true`)
* `unblockip`:
- params: `["<ip-address>"]`
- result: `true` (a boolean always set to `true`)
* `listblockedips`:
- params: `[]`
- result: `[{"ip": "<ip-address>", "reason": "<optional-reason>"}, ...]`, an array of objects
### Authorization
The request must contain an `Authorization` header with a valid [NIP-98](./98.md) event, except the `payload` tag is required. The `u` tag is the relay URL.
If `Authorization` is not provided or is invalid, the endpoint should return a 401 response.

29
C7.md Normal file
View File

@ -0,0 +1,29 @@
NIP-C7
======
Chats
-----
`draft` `optional`
A chat message is a `kind 9` event.
```json
{
"kind": 9,
"content": "GM",
"tags": []
}
```
A reply to a `kind 9` is an additional `kind 9` which quotes the parent using a `q` tag.
```json
{
"kind": 9,
"content": "nostr:nevent1...\nyes",
"tags": [
["q", <event-id>, <relay-url>, <pubkey>]
]
}
```

View File

@ -86,6 +86,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-75: Zap Goals](75.md) - [NIP-75: Zap Goals](75.md)
- [NIP-78: Application-specific data](78.md) - [NIP-78: Application-specific data](78.md)
- [NIP-84: Highlights](84.md) - [NIP-84: Highlights](84.md)
- [NIP-86: Relay Management API](86.md)
- [NIP-89: Recommended Application Handlers](89.md) - [NIP-89: Recommended Application Handlers](89.md)
- [NIP-90: Data Vending Machines](90.md) - [NIP-90: Data Vending Machines](90.md)
- [NIP-92: Media Attachments](92.md) - [NIP-92: Media Attachments](92.md)
@ -93,6 +94,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-96: HTTP File Storage Integration](96.md) - [NIP-96: HTTP File Storage Integration](96.md)
- [NIP-98: HTTP Auth](98.md) - [NIP-98: HTTP Auth](98.md)
- [NIP-99: Classified Listings](99.md) - [NIP-99: Classified Listings](99.md)
- [NIP-7D: Threads](7D.md)
- [NIP-C7: Chats](C7.md)
## Event Kinds ## Event Kinds
@ -107,9 +110,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `6` | Repost | [18](18.md) | | `6` | Repost | [18](18.md) |
| `7` | Reaction | [25](25.md) | | `7` | Reaction | [25](25.md) |
| `8` | Badge Award | [58](58.md) | | `8` | Badge Award | [58](58.md) |
| `9` | Group Chat Message | [29](29.md) | | `9` | Chat Message | [C7](C7.md) |
| `10` | Group Chat Threaded Reply | 29 (deprecated) | | `10` | Group Chat Threaded Reply | 29 (deprecated) |
| `11` | Group Thread | [29](29.md) | | `11` | Thread | [7D](7D.md) |
| `12` | Group Thread Reply | 29 (deprecated) | | `12` | Group Thread Reply | 29 (deprecated) |
| `13` | Seal | [59](59.md) | | `13` | Seal | [59](59.md) |
| `14` | Direct Message | [17](17.md) | | `14` | Direct Message | [17](17.md) |