From 69438fc3445490a7081a09f0de65ff8c6abe723b Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Fri, 3 Feb 2023 18:52:56 +1300 Subject: [PATCH 01/16] NIP-65 Feed Advertisements --- 65.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 60 insertions(+) create mode 100644 65.md diff --git a/65.md b/65.md new file mode 100644 index 0000000..1a947eb --- /dev/null +++ b/65.md @@ -0,0 +1,59 @@ +NIP-65 +====== + +Feed Advertisements +------------------- + +`draft` `optional` `author:mikedilger` + +A special replaceable event meaning "Feed Advertisement" is defined as an event with kind `10002` having a list of `r` tags, one for each relay the author posts their outgoing "feed" to. + +The content is not used. + +A feed consists of events that the author posts and wishes for their followers to "follow". Normally these would be kind-1 Text Note events but is not limited as such. + +Clients SHOULD, as with all replaceable events, use only the most recent kind-10002 event they can find. + +Clients SHOULD presume that if their user has a pubkey in their ContactList (kind 3) that it is because they wish to see this author's "feed" events. But clients MAY presume otherwise. + +Clients SHOULD interpret these Feed Advertisements as being the best relays to source the "feed" events from the author of the feed advertisement. + +### Motivation + +There is a common nostr use case where users wish to follow the content produced by other users. This is evidenced by the implicit meaning of the Contact List in [NIP-02](02.md) + +Because users don't often share the same sets of relays, ad-hoc solutions have arisen to get that content, but these solutions negatively impact scalability and decentralization: + + - Most people are sending their posts to the same most popular relays in order to be more widely seen + - Many people are pulling from a large number of relays (including many duplicate events) in order to get more data + - Events are being copied between relays, oftentimes to many different relays + +### Purposes + +The purpose of this NIP is to help clients find the events of the people they follow, and to help nostr scale better. + +### Suggestions + +It is suggested that people spread their kind-10002 events to many relays, but to post their normal feed notes to a much smaller number of relays. It is suggested that clients offer a way for users to spread their Feed Advertisements to many more relays than they normally post to. + +Authors may post events outside of the feed that they wish their followers to follow by posting them to relays outside of those listed in their "Feed Advertisement". For example, an author may want to reply to someone without all of their followers watching, but in many cases they want all their replies to show up in their "feed". + +It is suggsted that relays allow any user to write their own kind-10002 event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because + + - finding where someone posts is rather important + - these events do not have content that needs management + - relays only need to store one replaceable event per pubkey to offer this service + +### Example + +```json +{ + "kind": 10002, + "tags": [ + ["r", "wss://alicerelay.example.com"], + ["r", "wss://brando-relay.com"], + ["r", "wss://expensive-relay.example2.com"], + ], + "content": "", + ...other fields +``` diff --git a/README.md b/README.md index 829e61b..9767f0d 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | 43 | Channel Hide Message | [28](28.md) | | 44 | Channel Mute User | [28](28.md) | | 45-49 | Public Chat Reserved | [28](28.md) | +| 10002 | Feed Advertisement | [65](65.md) | | 22242 | Client Authentication | [42](42.md) | | 10000-19999 | Replaceable Events Reserved | [16](16.md) | | 20000-29999 | Ephemeral Events Reserved | [16](16.md) | From 251382552355258f19403c8ddc8bd63a7c74bd19 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 5 Feb 2023 03:50:26 +1300 Subject: [PATCH 02/16] Rename, recognize read relays --- 65.md | 33 ++++++++++++++++++++++----------- README.md | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/65.md b/65.md index 1a947eb..01c2723 100644 --- a/65.md +++ b/65.md @@ -1,22 +1,28 @@ NIP-65 ====== -Feed Advertisements +Relay List Metadata ------------------- `draft` `optional` `author:mikedilger` -A special replaceable event meaning "Feed Advertisement" is defined as an event with kind `10002` having a list of `r` tags, one for each relay the author posts their outgoing "feed" to. +A special replaceable event meaning "Relay List Metadata" is defined as an event with kind `10002` having a list of `r` tags, one for each relay the author uses to either read or write to. -The content is not used. +The primary purpose of this relay list is to advertise to others, not for configuring one's client. -A feed consists of events that the author posts and wishes for their followers to "follow". Normally these would be kind-1 Text Note events but is not limited as such. +The content is not used and SHOULD be blank. + +The `r` tags can have a second parameter as either `read` or `write`. If it is omitted, it means the author both reads from and writes to that relay. Clients SHOULD, as with all replaceable events, use only the most recent kind-10002 event they can find. -Clients SHOULD presume that if their user has a pubkey in their ContactList (kind 3) that it is because they wish to see this author's "feed" events. But clients MAY presume otherwise. +### The meaning of read and write -Clients SHOULD interpret these Feed Advertisements as being the best relays to source the "feed" events from the author of the feed advertisement. +If an author advertises a write relay in a kind `10002` event, that means that feed-related events created by the author, which the author wants their followers to see, will be posted there. Normally these would be kind-1 Text Note events, but are not limited as such. + +Clients SHOULD presume that if their user has a pubkey in their ContactList (kind 3) that it is because they wish to see that author's feed-related events. But clients MAY presume otherwise. + +If an author advertises a read relay in a kind `10002` event, that means that the author may be subscribed to events that tag them on such relays. Clients SHOULD publish events that tag someone on at least the read relays of the person being tagged. ### Motivation @@ -30,20 +36,24 @@ Because users don't often share the same sets of relays, ad-hoc solutions have a ### Purposes -The purpose of this NIP is to help clients find the events of the people they follow, and to help nostr scale better. +The purpose of this NIP is to help clients find the events of the people they follow, to help tagged events get to the people tagged, and to help nostr scale better. ### Suggestions -It is suggested that people spread their kind-10002 events to many relays, but to post their normal feed notes to a much smaller number of relays. It is suggested that clients offer a way for users to spread their Feed Advertisements to many more relays than they normally post to. +It is suggested that people spread their kind `10002` events to many relays, but write their normal feed-related events to a much smaller number of relays (between 2 to 6 relays). It is suggested that clients offer a way for users to spread their kind `10002` events to many more relays than they normally post to. -Authors may post events outside of the feed that they wish their followers to follow by posting them to relays outside of those listed in their "Feed Advertisement". For example, an author may want to reply to someone without all of their followers watching, but in many cases they want all their replies to show up in their "feed". +Authors may post events outside of the feed that they wish their followers to follow by posting them to relays outside of those listed in their "Relay List Metadata". For example, an author may want to reply to someone without all of their followers watching. -It is suggsted that relays allow any user to write their own kind-10002 event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because +It is suggsted that relays allow any user to write their own kind `10002` event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because - finding where someone posts is rather important - these events do not have content that needs management - relays only need to store one replaceable event per pubkey to offer this service +### Why not in kind `0` Metadata + +Even though this is user related metadata, it is a separate event from kind `0` in order to keep it small (as it should be widely spread) and to not have content that may require moderation by relay operators so that it is more acceptable to relays. + ### Example ```json @@ -52,7 +62,8 @@ It is suggsted that relays allow any user to write their own kind-10002 event (o "tags": [ ["r", "wss://alicerelay.example.com"], ["r", "wss://brando-relay.com"], - ["r", "wss://expensive-relay.example2.com"], + ["r", "wss://expensive-relay.example2.com", "write"], + ["r", "wss://nostr-relay.example.com", "read"], ], "content": "", ...other fields diff --git a/README.md b/README.md index 9767f0d..e7ab5ec 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | 43 | Channel Hide Message | [28](28.md) | | 44 | Channel Mute User | [28](28.md) | | 45-49 | Public Chat Reserved | [28](28.md) | -| 10002 | Feed Advertisement | [65](65.md) | +| 10002 | Relay List Metadata | [65](65.md) | | 22242 | Client Authentication | [42](42.md) | | 10000-19999 | Replaceable Events Reserved | [16](16.md) | | 20000-29999 | Ephemeral Events Reserved | [16](16.md) | From 870f96b988697d6ae59ea74223b6d3b549e6af83 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Sun, 5 Feb 2023 03:56:07 +1300 Subject: [PATCH 03/16] spelling and wording --- 65.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/65.md b/65.md index 01c2723..c4fc246 100644 --- a/65.md +++ b/65.md @@ -22,7 +22,7 @@ If an author advertises a write relay in a kind `10002` event, that means that f Clients SHOULD presume that if their user has a pubkey in their ContactList (kind 3) that it is because they wish to see that author's feed-related events. But clients MAY presume otherwise. -If an author advertises a read relay in a kind `10002` event, that means that the author may be subscribed to events that tag them on such relays. Clients SHOULD publish events that tag someone on at least the read relays of the person being tagged. +If an author advertises a read relay in a kind `10002` event, that means that the author may be subscribed to events that tag them on such relays. Clients SHOULD publish events that tag someone on at least some of the read relays of the person being tagged. ### Motivation @@ -44,7 +44,7 @@ It is suggested that people spread their kind `10002` events to many relays, but Authors may post events outside of the feed that they wish their followers to follow by posting them to relays outside of those listed in their "Relay List Metadata". For example, an author may want to reply to someone without all of their followers watching. -It is suggsted that relays allow any user to write their own kind `10002` event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because +It is suggested that relays allow any user to write their own kind `10002` event (optionally with AUTH to verify it is their own) even if they are not otherwise subscribed to the relay because - finding where someone posts is rather important - these events do not have content that needs management From cf053d2a418db8ea489f6857d017eacc12cc97b5 Mon Sep 17 00:00:00 2001 From: Erik Westra Date: Mon, 6 Feb 2023 10:11:26 +1300 Subject: [PATCH 04/16] Suggested additions to NIP-05 to enhance security Proposing a couple of changes to the NIP-05 protocol to reduce the chance of fraudulent use of "verified" public keys. At present, I could create an account on a well-known verifying server under a random name, and then send DMs pretending to be someone else, and there's no easy way for users to tell who the verifying account actually belongs to. As well as displaying the name of the account on the verifying server, this PR suggests an enhancement to the JSON data being returned so that clients can redirect the user to the user's profile page on the server. This will make it much easier for users to check that someone who claims to have verified their Nostr account is who they claim to be. --- 05.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/05.md b/05.md index 992983f..d042b30 100644 --- a/05.md +++ b/05.md @@ -35,7 +35,7 @@ It will make a GET request to `https://example.com/.well-known/nostr.json?name=b } ```` -or with the **optional** `"relays"` attribute: +or with the **optional** `"relays"` and/or `"account_uris"` attributes: ```json { @@ -44,6 +44,9 @@ or with the **optional** `"relays"` attribute: }, "relays": { "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ] + }, + "account_uris": { + "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": "https://bob.com/profile/bob" } } ```` @@ -52,6 +55,8 @@ If the pubkey matches the one given in `"names"` (as in the example above) that The optional `"relays"` attribute may contain an object with public keys as properties and arrays of relay URLs as values. When present, that can be used to help clients learn in which relays that user may be found. Web servers which serve `/.well-known/nostr.json` files dynamically based on the query string SHOULD also serve the relays data for any name they serve in the same reply when that is available. +The optional `"account_uris"` attribute may contain an object with public keys as properties and URIs as values. When present, this allows clients to direct their users to a URI which provides more information about the account on the server which was used to validate the given public key. Clients should ignore any URIs which don't include the server's ``. + ## Finding users from their NIP-05 identifier A client may implement support for finding users' public keys from _internet identifiers_, the flow is the same as above, but reversed: first the client fetches the _well-known_ URL and from there it gets the public key of the user, then it tries to fetch the kind `0` event for that user and check if it has a matching `"nip05"`. @@ -66,6 +71,10 @@ For example, if after finding that `bob@bob.com` has the public key `abc...def`, Keys must be returned in hex format. Keys in NIP-19 `npub` format are are only meant to be used for display in client UIs, not in this NIP. +### Clients should display the name used to verify the public key + +While users can choose their own Nostr username, displaying that username beside the "verified" icon and the name of the verifying server alone is an invitation for abuse. A malicious user could verify their public key using one account name, and then display a different account name within Nostr, misleading users into thinking they are someone else. To prevent this, clients should display the user's account name on the verifying server, rather than (or in addition to) their self-selected username within Nostr. + ### User Discovery implementation suggestion A client can also use this to allow users to search other profiles. If a client has a search box or something like that, a user may be able to type "bob@example.com" there and the client would recognize that and do the proper queries to obtain a pubkey and suggest that to the user. From 6a11f4d4cd0159c517414ffa6cfc646f8c7c9da3 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Mon, 6 Feb 2023 09:21:58 -0600 Subject: [PATCH 05/16] [NIP-26] Fix for multiple `kind`s in delegation conditions (#208) --- 26.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/26.md b/26.md index 955a043..0f8f64a 100644 --- a/26.md +++ b/26.md @@ -38,20 +38,34 @@ The following fields and operators are supported in the above query string: *Fields*: 1. `kind` - *Operators*: - - `=${KIND_NUMBER}` - delegatee may only sign events of this kind + - `=${KIND_NUMBERS}` - delegatee may only sign events of listed kind(s) (comma-separated) 2. `created_at` - *Operators*: - - `<${TIMESTAMP}` - delegatee may only sign events created ***before*** the specified timestamp - - `>${TIMESTAMP}` - delegatee may only sign events created ***after*** the specified timestamp + - `<${TIMESTAMP}` - delegatee may only sign events whose `created_at` is ***before*** the specified timestamp + - `>${TIMESTAMP}` - delegatee may only sign events whose `created_at` is ***after*** the specified timestamp -In order to create a single condition, you must use a supported field and operator. Multiple conditions can be used in a single query string, including on the same field. Conditions must be combined with `&`. +Multiple conditions can be used in a single query string, including on the same field. Conditions must be combined with `&`. + +Multiple conditions should be treated as `AND` requirements; all conditions must be true for the delegated event to be valid. + +Multiple comma-separated `kind` values should be interpreted as: +``` +# kind=0,1,3000 +... AND (kind == 0 OR kind == 1 OR kind == 3000) AND ... +``` For example, the following condition strings are valid: - +- `kind=1` +- `created_at<1675721813` - `kind=1&created_at<1675721813` -- `kind=0&kind=1&created_at>1675721813` +- `kind=0,1,3000&created_at>1675721813` - `kind=1&created_at>1674777689&created_at<1675721813` +However, specifying multiple _separate_ `kind` conditions is impossible to satisfy: +- `kind=1&kind=5` + +There is no way for an event to satisfy the `AND` requirement of being both `kind`s simultaneously. + For the vast majority of use-cases, it is advisable that query strings should include a `created_at` ***after*** condition reflecting the current time, to prevent the delegatee from publishing historic notes on the delegator's behalf. #### Example From 8c031aa710a8f0325620e6ac1d94e30f8a8f212b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lio=E6=9D=8E=E6=AD=90?= Date: Mon, 6 Feb 2023 16:15:08 -0800 Subject: [PATCH 06/16] Update README.md kind table (#226) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 829e61b..53f0aae 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | 44 | Channel Mute User | [28](28.md) | | 45-49 | Public Chat Reserved | [28](28.md) | | 22242 | Client Authentication | [42](42.md) | +| 1000-9999 | Regular Events Reserved | [16](16.md) | | 10000-19999 | Replaceable Events Reserved | [16](16.md) | | 20000-29999 | Ephemeral Events Reserved | [16](16.md) | | 30000-39999 | Param. Repl. Events Reserved| [33](33.md) | From b99ca748c8227d2723b5f856b004267b3c122c06 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Wed, 8 Feb 2023 08:52:35 +1300 Subject: [PATCH 07/16] Put NIP-65 in the readme contents --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 24ade62..f4ed3d2 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh - [NIP-40: Expiration Timestamp](40.md) - [NIP-42: Authentication of clients to relays](42.md) - [NIP-50: Keywords filter](50.md) +- [NIP-65: Relay List Metadata](65.md) ## Event Kinds From f9e38ed00f5b11694ff93c368aacbf47ec21437a Mon Sep 17 00:00:00 2001 From: William Casarin Date: Tue, 7 Feb 2023 13:15:38 -0800 Subject: [PATCH 08/16] NIP-56: Reporting (#205) Co-authored-by: Semisol <45574030+Semisol@users.noreply.github.com> Co-authored-by: Leo Wandersleb --- 56.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ 2 files changed, 84 insertions(+) create mode 100644 56.md diff --git a/56.md b/56.md new file mode 100644 index 0000000..55ee1a2 --- /dev/null +++ b/56.md @@ -0,0 +1,82 @@ + +NIP-56 +====== + +Reporting +--------- + +`draft` `optional` `author:jb55` + +A report is a `kind 1984` note that is used to report other notes for spam, +illegal and explicit content. + +The content MAY contain additional information submitted by the entity +reporting the content. + +Tags +---- + +The report event MUST include a `p` tag referencing the pubkey of the user you +are reporting. + +If reporting a note, an `e` tag MUST also be included referencing the note id. + +A `report type` string MUST be included as the 3rd entry to the `e` or `p` tag +being reported, which consists of the following report types: + +- `nudity` - depictions of nudity, porn, etc. +- `profanity` - profanity, hateful speech, etc. +- `illegal` - something which may be illegal in some jurisdiction +- `spam` - spam +- `impersonation` - someone pretending to be someone else + +Some report tags only make sense for profile reports, such as `impersonation` + +Example events +-------------- + +```json +{ + "kind": 1984, + "tags": [ + [ "p", , "nudity"] + ], + "content": "", + ... +} + +{ + "kind": 1984, + "tags": [ + [ "e", , "illegal"], + [ "p", ] + ], + "content": "He's insulting the king!", + ... +} + +{ + "kind": 1984, + "tags": [ + [ "p", , "impersonation"], + [ "p", ] + ], + "content": "Profile is imitating #[1]", + ... +} +``` + +Client behavior +--------------- + +Clients can use reports from friends to make moderation decisions if they +choose to. For instance, if 3+ of your friends report a profile as explicit, +clients can have an option to automatically blur photos from said account. + + +Relay behavior +-------------- + +It is not recommended that relays perform automatic moderation using reports, +as they can be easily gamed. Admins could use reports from trusted moderators to +takedown illegal or explicit content if the relay does not allow such things. diff --git a/README.md b/README.md index f4ed3d2..225379b 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh - [NIP-40: Expiration Timestamp](40.md) - [NIP-42: Authentication of clients to relays](42.md) - [NIP-50: Keywords filter](50.md) +- [NIP-56: Reporting](56.md) - [NIP-65: Relay List Metadata](65.md) ## Event Kinds @@ -49,6 +50,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | 43 | Channel Hide Message | [28](28.md) | | 44 | Channel Mute User | [28](28.md) | | 45-49 | Public Chat Reserved | [28](28.md) | +| 1984 | Reporting | [56](56.md) | | 10002 | Relay List Metadata | [65](65.md) | | 22242 | Client Authentication | [42](42.md) | | 1000-9999 | Regular Events Reserved | [16](16.md) | From 3f39a241b170a4e11d5c162c03f03da4fedb0756 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Wed, 8 Feb 2023 08:36:07 -0300 Subject: [PATCH 09/16] Revert "[NIP-26] Fix for multiple `kind`s in delegation conditions (#208)" This reverts commit 6a11f4d4cd0159c517414ffa6cfc646f8c7c9da3. --- 26.md | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/26.md b/26.md index 0f8f64a..955a043 100644 --- a/26.md +++ b/26.md @@ -38,34 +38,20 @@ The following fields and operators are supported in the above query string: *Fields*: 1. `kind` - *Operators*: - - `=${KIND_NUMBERS}` - delegatee may only sign events of listed kind(s) (comma-separated) + - `=${KIND_NUMBER}` - delegatee may only sign events of this kind 2. `created_at` - *Operators*: - - `<${TIMESTAMP}` - delegatee may only sign events whose `created_at` is ***before*** the specified timestamp - - `>${TIMESTAMP}` - delegatee may only sign events whose `created_at` is ***after*** the specified timestamp + - `<${TIMESTAMP}` - delegatee may only sign events created ***before*** the specified timestamp + - `>${TIMESTAMP}` - delegatee may only sign events created ***after*** the specified timestamp -Multiple conditions can be used in a single query string, including on the same field. Conditions must be combined with `&`. - -Multiple conditions should be treated as `AND` requirements; all conditions must be true for the delegated event to be valid. - -Multiple comma-separated `kind` values should be interpreted as: -``` -# kind=0,1,3000 -... AND (kind == 0 OR kind == 1 OR kind == 3000) AND ... -``` +In order to create a single condition, you must use a supported field and operator. Multiple conditions can be used in a single query string, including on the same field. Conditions must be combined with `&`. For example, the following condition strings are valid: -- `kind=1` -- `created_at<1675721813` + - `kind=1&created_at<1675721813` -- `kind=0,1,3000&created_at>1675721813` +- `kind=0&kind=1&created_at>1675721813` - `kind=1&created_at>1674777689&created_at<1675721813` -However, specifying multiple _separate_ `kind` conditions is impossible to satisfy: -- `kind=1&kind=5` - -There is no way for an event to satisfy the `AND` requirement of being both `kind`s simultaneously. - For the vast majority of use-cases, it is advisable that query strings should include a `created_at` ***after*** condition reflecting the current time, to prevent the delegatee from publishing historic notes on the delegator's behalf. #### Example From a9dd1ce7710bd801bdc0d09c233d087ca2d3c10d Mon Sep 17 00:00:00 2001 From: Jimmy Song Date: Wed, 8 Feb 2023 23:21:40 +0400 Subject: [PATCH 10/16] Added clarification for signature to be in hex --- 01.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01.md b/01.md index e1e9444..68efc6f 100644 --- a/01.md +++ b/01.md @@ -26,7 +26,7 @@ The only object type that exists is the `event`, which has the following format ... // other kinds of tags may be included later ], "content": , - "sig": <64-bytes signature of the sha256 hash of the serialized event data, which is the same as the "id" field> + "sig": <64-bytes hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field> } ``` From 643de1b7dac1d00ff8344e887da54ae9edd9ee82 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Thu, 9 Feb 2023 13:41:54 -0300 Subject: [PATCH 11/16] change kind:1 description on README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 225379b..72973c0 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | kind | description | NIP | |-------------|-----------------------------|------------------------| | 0 | Metadata | [1](01.md), [5](05.md) | -| 1 | Text | [1](01.md) | +| 1 | Short Text Note | [1](01.md) | | 2 | Recommend Relay | [1](01.md) | | 3 | Contacts | [2](02.md) | | 4 | Encrypted Direct Messages | [4](04.md) | From a1a090160b610c69513725ae871efdb346cbd82d Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Thu, 9 Feb 2023 13:43:53 -0300 Subject: [PATCH 12/16] rewrite ranges. --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 72973c0..54bb5d4 100644 --- a/README.md +++ b/README.md @@ -35,28 +35,28 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh ## Event Kinds -| kind | description | NIP | -|-------------|-----------------------------|------------------------| -| 0 | Metadata | [1](01.md), [5](05.md) | -| 1 | Short Text Note | [1](01.md) | -| 2 | Recommend Relay | [1](01.md) | -| 3 | Contacts | [2](02.md) | -| 4 | Encrypted Direct Messages | [4](04.md) | -| 5 | Event Deletion | [9](09.md) | -| 7 | Reaction | [25](25.md) | -| 40 | Channel Creation | [28](28.md) | -| 41 | Channel Metadata | [28](28.md) | -| 42 | Channel Message | [28](28.md) | -| 43 | Channel Hide Message | [28](28.md) | -| 44 | Channel Mute User | [28](28.md) | -| 45-49 | Public Chat Reserved | [28](28.md) | -| 1984 | Reporting | [56](56.md) | -| 10002 | Relay List Metadata | [65](65.md) | -| 22242 | Client Authentication | [42](42.md) | -| 1000-9999 | Regular Events Reserved | [16](16.md) | -| 10000-19999 | Replaceable Events Reserved | [16](16.md) | -| 20000-29999 | Ephemeral Events Reserved | [16](16.md) | -| 30000-39999 | Param. Repl. Events Reserved| [33](33.md) | +| kind | description | NIP | +| ------------- | -------------------------------- | ----------------------- | +| 0 | Metadata | [1](01.md), [5](05.md) | +| 1 | Short Text Note | [1](01.md) | +| 2 | Recommend Relay | [1](01.md) | +| 3 | Contacts | [2](02.md) | +| 4 | Encrypted Direct Messages | [4](04.md) | +| 5 | Event Deletion | [9](09.md) | +| 7 | Reaction | [25](25.md) | +| 40 | Channel Creation | [28](28.md) | +| 41 | Channel Metadata | [28](28.md) | +| 42 | Channel Message | [28](28.md) | +| 43 | Channel Hide Message | [28](28.md) | +| 44 | Channel Mute User | [28](28.md) | +| 45-49 | Public Chat Reserved | [28](28.md) | +| 1984 | Reporting | [56](56.md) | +| 10002 | Relay List Metadata | [65](65.md) | +| 22242 | Client Authentication | [42](42.md) | +| 1000-9999 | Regular Events | [16](16.md) | +| 10000-19999 | Replaceable Events | [16](16.md) | +| 20000-29999 | Ephemeral Events | [16](16.md) | +| 30000-39999 | Parameterized Replaceable Events | [33](33.md) | From d87763781dc1213d7c1b53ab0a4172f8237cbdf3 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Thu, 9 Feb 2023 17:13:35 -0300 Subject: [PATCH 13/16] clarify and change account account_uris to account_paths. --- 05.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/05.md b/05.md index d042b30..5a5b5f2 100644 --- a/05.md +++ b/05.md @@ -35,7 +35,7 @@ It will make a GET request to `https://example.com/.well-known/nostr.json?name=b } ```` -or with the **optional** `"relays"` and/or `"account_uris"` attributes: +or with the **optional** `"relays"` and/or `"account_paths"` attributes: ```json { @@ -45,8 +45,8 @@ or with the **optional** `"relays"` and/or `"account_uris"` attributes: "relays": { "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ] }, - "account_uris": { - "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": "https://bob.com/profile/bob" + "account_paths": { + "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": "/profile/bob" } } ```` @@ -55,7 +55,7 @@ If the pubkey matches the one given in `"names"` (as in the example above) that The optional `"relays"` attribute may contain an object with public keys as properties and arrays of relay URLs as values. When present, that can be used to help clients learn in which relays that user may be found. Web servers which serve `/.well-known/nostr.json` files dynamically based on the query string SHOULD also serve the relays data for any name they serve in the same reply when that is available. -The optional `"account_uris"` attribute may contain an object with public keys as properties and URIs as values. When present, this allows clients to direct their users to a URI which provides more information about the account on the server which was used to validate the given public key. Clients should ignore any URIs which don't include the server's ``. +The optional `"account_paths"` attribute may contain an object with public keys as properties and URIs as values. When present, this allows clients to direct their users to a URI that provides more information about the account on the same NIP-05 server -- for example, if the address is `"bob@example.com"` and the account_path for Bob's public key is `"/profile/bob"` the client may have a link to `https://example.com/profile/bob` at Bob's NIP-05 address. ## Finding users from their NIP-05 identifier From 9d0b59d381a3d70dcf9947fd6bb194b259b05f9e Mon Sep 17 00:00:00 2001 From: Matthew Lorentz Date: Thu, 9 Feb 2023 16:59:50 -0500 Subject: [PATCH 14/16] Revert "Merge pull request #227 from erikwestra/nip-05-security-proposal" This reverts commit 6d55463c89e6c944bcd49c93f90b16a0ce5fce1e, and d87763781dc1213d7c1b53ab0a4172f8237cbdf3 reversing changes made to a1a090160b610c69513725ae871efdb346cbd82d. --- 05.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/05.md b/05.md index 5a5b5f2..992983f 100644 --- a/05.md +++ b/05.md @@ -35,7 +35,7 @@ It will make a GET request to `https://example.com/.well-known/nostr.json?name=b } ```` -or with the **optional** `"relays"` and/or `"account_paths"` attributes: +or with the **optional** `"relays"` attribute: ```json { @@ -44,9 +44,6 @@ or with the **optional** `"relays"` and/or `"account_paths"` attributes: }, "relays": { "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ] - }, - "account_paths": { - "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": "/profile/bob" } } ```` @@ -55,8 +52,6 @@ If the pubkey matches the one given in `"names"` (as in the example above) that The optional `"relays"` attribute may contain an object with public keys as properties and arrays of relay URLs as values. When present, that can be used to help clients learn in which relays that user may be found. Web servers which serve `/.well-known/nostr.json` files dynamically based on the query string SHOULD also serve the relays data for any name they serve in the same reply when that is available. -The optional `"account_paths"` attribute may contain an object with public keys as properties and URIs as values. When present, this allows clients to direct their users to a URI that provides more information about the account on the same NIP-05 server -- for example, if the address is `"bob@example.com"` and the account_path for Bob's public key is `"/profile/bob"` the client may have a link to `https://example.com/profile/bob` at Bob's NIP-05 address. - ## Finding users from their NIP-05 identifier A client may implement support for finding users' public keys from _internet identifiers_, the flow is the same as above, but reversed: first the client fetches the _well-known_ URL and from there it gets the public key of the user, then it tries to fetch the kind `0` event for that user and check if it has a matching `"nip05"`. @@ -71,10 +66,6 @@ For example, if after finding that `bob@bob.com` has the public key `abc...def`, Keys must be returned in hex format. Keys in NIP-19 `npub` format are are only meant to be used for display in client UIs, not in this NIP. -### Clients should display the name used to verify the public key - -While users can choose their own Nostr username, displaying that username beside the "verified" icon and the name of the verifying server alone is an invitation for abuse. A malicious user could verify their public key using one account name, and then display a different account name within Nostr, misleading users into thinking they are someone else. To prevent this, clients should display the user's account name on the verifying server, rather than (or in addition to) their self-selected username within Nostr. - ### User Discovery implementation suggestion A client can also use this to allow users to search other profiles. If a client has a search box or something like that, a user may be able to type "bob@example.com" there and the client would recognize that and do the proper queries to obtain a pubkey and suggest that to the user. From ffe6a49557253a1f6227793787c6fcf58565a980 Mon Sep 17 00:00:00 2001 From: Jeff Thibault Date: Fri, 10 Feb 2023 08:18:40 -0500 Subject: [PATCH 15/16] NIP-04: clarify how shared secret is computed --- 04.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/04.md b/04.md index 723bd70..0ebcddb 100644 --- a/04.md +++ b/04.md @@ -14,6 +14,8 @@ A special event with kind `4`, meaning "encrypted direct message". It is suppose **`tags`** MAY contain an entry identifying the previous message in a conversation or a message we are explicitly replying to (such that contextual, more organized conversations may happen), in the form `["e", ""]`. +**Note**: By default in the [libsecp256k1](https://github.com/bitcoin-core/secp256k1) ECDH implementation, the secret is the SHA256 hash of the shared point (both X and Y coorinates). In Nostr, only the X coordinate of the shared point is used as the secret and it is NOT hashed. If using libsecp256k1, a custom function that copies the X coordinate must be passed as the `hashfp` argument in `secp256k1_ecdh`. See [here](https://github.com/bitcoin-core/secp256k1/blob/master/src/modules/ecdh/main_impl.h#L29). + Code sample for generating such an event in JavaScript: ```js From 17ffd3ee4efa33c3f6abb4304d1c4dd998efc523 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Mon, 13 Feb 2023 03:36:04 -0800 Subject: [PATCH 16/16] NIP-57: Lightning Zaps (#224) --- 57.md | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 3 ++ 2 files changed, 149 insertions(+) create mode 100644 57.md diff --git a/57.md b/57.md new file mode 100644 index 0000000..78a3fd6 --- /dev/null +++ b/57.md @@ -0,0 +1,146 @@ +NIP-57 +====== + +Lightning Zaps +-------------- + +`draft` `optional` `author:jb55` `author:kieran` + +This NIP defines a new note type called a lightning zap of kind `9735`. These represent paid lightning invoice receipts sent by a lightning node called the `zapper`. We also define another note type of kind `9734` which are `zap request` notes, which will be described in this document. + +Having lightning receipts on nostr allows clients to display lightning payments from entities on the network. These can be used for fun or for spam deterrence. + + +## Definitions + +`zapper` - the lightning node or service that sends zap notes (kind `9735`) + +`zap request` - a note of kind `9734` created by the person zapping + +`zap invoice` - the bolt11 invoice fetched from a custom lnurl endpoint which contains a `zap request` note + + +## Protocol flow + +### Client side + +1. Calculate the lnurl pay request url for a user from the lud06 or lud16 field on their profile + +2. Fetch the lnurl pay request static endpoint (`https://host.com/.well-known/lnurlp/user`) and gather the `allowsNostr` and `nostrPubkey` fields. If `allowsNostr` exists and it is `true`, and if `nostrPubkey` exists and is a valid BIP 340 public key, associate this information with the user. The `nostrPubkey` is the `zapper`'s pubkey, and it is used to authorize zaps sent to that user. + +3. Clients may choose to display a lightning zap button on each post or on the users profile, if the user's lnurl pay request endpoint supports nostr, the client SHOULD generate a `zap invoice` instead of a normal lnurl invoice. + +4. To generate a `zap invoice`, call the `callback` url with `amount` set to the milli-satoshi amount value. A `nostr` querystring value MUST be set as well. It is a uri-encoded `zap request` note signed by the user's key. The `zap request` note contains an `e` tag of the note it is zapping, and a `p` tag of the target user's pubkey. The `e` tag is optional which allows profile tipping. The `zap request` note must also have a `relays` tag, which is gathered from the user's configured relays. The `content` MAY be an additional comment from the user which can be displayed when listing zaps on posts and profiles. + +5. Pay this invoice or pass it to an app that can pay the invoice. Once it's paid, a `zap note` will be created by the `zapper`. + +### LNURL Server side + +The lnurl server will need some additional pieces of information so that clients can know that zap invoices are supported: + +1. Add a `nostrPubkey` to the lnurl-pay static endpoint `/.well-known/lnurlp/user`, where `nostrPubkey` is the nostr pubkey of the `zapper`, the entity that creates zap notes. Clients will use this to authorize zaps. + +2. Add an `allowsNostr` field and set it to true. + +3. In the lnurl-pay callback URL, watch for a `nostr` querystring, where the contents of the note is a uri-encoded `zap request` JSON. + +4. If present, the zap request note must be validated: + + a. It MUST have a valid nostr signature + + b. It MUST have tags + + c. It MUST have at least one p-tag + + d. It MUST have either 0 or 1 e-tag + + e. There should be a `relays` tag with the relays to send the `zap` note to. + +5. If valid, fetch a description hash invoice where the description is this note and this note only. No additional lnurl metadata is included in the description. + +At this point, the lightning node is ready to send the zap note once payment is received. + +## The zap note + +Zap notes are created by a lightning node reacting to paid invoices. Zap notes are only created when the invoice description (committed to the description hash) contains a `zap request` note. + +Example zap note: + +```json +{ + "id": "67b48a14fb66c60c8f9070bdeb37afdfcc3d08ad01989460448e4081eddda446", + "pubkey": "9630f464cca6a5147aa8a35f0bcdd3ce485324e732fd39e09233b1d848238f31", + "created_at": 1674164545, + "kind": 9735, + "tags": [ + [ + "p", + "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245" + ], + [ + "e", + "3624762a1274dd9636e0c552b53086d70bc88c165bc4dc0f9e836a1eaf86c3b8" + ], + [ + "bolt11", + "lnbc10u1p3unwfusp5t9r3yymhpfqculx78u027lxspgxcr2n2987mx2j55nnfs95nxnzqpp5jmrh92pfld78spqs78v9euf2385t83uvpwk9ldrlvf6ch7tpascqhp5zvkrmemgth3tufcvflmzjzfvjt023nazlhljz2n9hattj4f8jq8qxqyjw5qcqpjrzjqtc4fc44feggv7065fqe5m4ytjarg3repr5j9el35xhmtfexc42yczarjuqqfzqqqqqqqqlgqqqqqqgq9q9qxpqysgq079nkq507a5tw7xgttmj4u990j7wfggtrasah5gd4ywfr2pjcn29383tphp4t48gquelz9z78p4cq7ml3nrrphw5w6eckhjwmhezhnqpy6gyf0" + ], + [ + "description", + "{\"pubkey\":\"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\",\"content\":\"\",\"id\":\"d9cc14d50fcb8c27539aacf776882942c1a11ea4472f8cdec1dea82fab66279d\",\"created_at\":1674164539,\"sig\":\"77127f636577e9029276be060332ea565deaf89ff215a494ccff16ae3f757065e2bc59b2e8c113dd407917a010b3abd36c8d7ad84c0e3ab7dab3a0b0caa9835d\",\"kind\":9734,\"tags\":[[\"e\",\"3624762a1274dd9636e0c552b53086d70bc88c165bc4dc0f9e836a1eaf86c3b8\"],[\"p\",\"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\"],[\"relays\",\"wss://relay.damus.io\",\"wss://nostr-relay.wlvs.space\",\"wss://nostr.fmt.wiz.biz\",\"wss://relay.nostr.bg\",\"wss://nostr.oxtr.dev\",\"wss://nostr.v0l.io\",\"wss://brb.io\",\"wss://nostr.bitcoiner.social\",\"ws://monad.jb55.com:8080\",\"wss://relay.snort.social\"]]}" + ], + [ + "preimage", + "5d006d2cf1e73c7148e7519a4c68adc81642ce0e25a432b2434c99f97344c15f" + ] + ], + "content": "", + "sig": "b0a3c5c984ceb777ac455b2f659505df51585d5fd97a0ec1fdb5f3347d392080d4b420240434a3afd909207195dac1e2f7e3df26ba862a45afd8bfe101c2b1cc" + } +``` + +* The zap note MUST have a `bolt11` tag containing the description hash bolt11 invoice. + +* The zap note MUST contain a `description` tag which is the invoice description. + +* `SHA256(description)` MUST match the description hash in the bolt11 invoice. + +* The zap note MAY contain a `preimage` to match against the payment hash of the bolt11 invoice. This isn't really a payment proof, there is no real way to prove that the invoice is real or has been paid. You are trusting the author of the zap note for the legitimacy of the payment. + +The zap note is not a proof of payment, all it proves is that some nostr user fetched an invoice. The existence of the zap note implies the invoice as paid, but it could be a lie given a rogue implementation. + + +### Creating a zap note + +When receiving a payment, the following steps are executed: + +1. Get the description for the invoice. This needs to be saved somewhere during the generation of the description hash invoice. It is saved automatically for you with CLN, which is the reference implementation used here. + +2. Parse the bolt11 description as a JSON nostr note. You SHOULD check the signature of the parsed note to ensure that it is valid. This is the `zap request` note created by the entity who is zapping. + +4. The note MUST have only one `p` tag + +5. The note MUST have 0 or 1 `e` tag + +6. Create a nostr note of kind `9735` that includes the `p` tag AND optional `e` tag. The content SHOULD be empty. The created_at date SHOULD be set to the invoice paid_at date for idempotency. + +7. Send the note to the `relays` declared in the `zap request` note from the invoice description. + +A reference implementation for the zapper is here: [zapper][zapper] + +[zapper]: https://github.com/jb55/cln-nostr-zapper + + +## Client Behavior + +Clients MAY fetch zap notes on posts and profiles: + +`{"kinds": [9735], "#e": [...]}` + +To authorize these notes, clients MUST fetch the `nostrPubkey` from the users configured lightning address or lnurl and ensure that the zaps to their posts were created by this pubkey. If clients don't do this, anyone could forge unauthorized zaps. + +Once authorized, clients MAY tally zaps on posts, and list them on profiles. If the zap request note contains a non-empty `content`, it may display a zap comment. Generally clients should show users the `zap request` note, and use the `zap note` to show "zap authorized by ..." but this is optional. + +## Future Work + +Zaps can be extended to be more private by encrypting zap request notes to the target user, but for simplicity it has been left out of this initial draft. diff --git a/README.md b/README.md index 54bb5d4..d4e3c04 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh - [NIP-40: Expiration Timestamp](40.md) - [NIP-42: Authentication of clients to relays](42.md) - [NIP-50: Keywords filter](50.md) +- [NIP-57: Lightning Zaps](57.md) - [NIP-56: Reporting](56.md) - [NIP-65: Relay List Metadata](65.md) @@ -51,6 +52,8 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | 44 | Channel Mute User | [28](28.md) | | 45-49 | Public Chat Reserved | [28](28.md) | | 1984 | Reporting | [56](56.md) | +| 9734 | Zap Request | [57](57.md) | +| 9735 | Zap | [57](57.md) | | 10002 | Relay List Metadata | [65](65.md) | | 22242 | Client Authentication | [42](42.md) | | 1000-9999 | Regular Events | [16](16.md) |