diff options
| -rw-r--r-- | 02.md | 2 | ||||
| -rw-r--r-- | 05.md | 23 | ||||
| -rw-r--r-- | 07.md | 7 | ||||
| -rw-r--r-- | 09.md | 4 | ||||
| -rw-r--r-- | 10.md | 4 | ||||
| -rw-r--r-- | 22.md | 16 | ||||
| -rw-r--r-- | 25.md | 2 | ||||
| -rw-r--r-- | 26.md | 46 | ||||
| -rw-r--r-- | 33.md | 32 | ||||
| -rw-r--r-- | 35.md | 43 | ||||
| -rw-r--r-- | README.md | 2 |
11 files changed, 102 insertions, 79 deletions
| @@ -38,7 +38,7 @@ A client may rely on the kind-3 event to display a list of followed people by pr | |||
| 38 | 38 | ||
| 39 | ### Relay sharing | 39 | ### Relay sharing |
| 40 | 40 | ||
| 41 | A client may publish a full list of contacts with good relays for each of their contacts so other clients may use these to update their internal relay lists if needed, increasing censorship-resistant. | 41 | A client may publish a full list of contacts with good relays for each of their contacts so other clients may use these to update their internal relay lists if needed, increasing censorship-resistance. |
| 42 | 42 | ||
| 43 | ### Petname scheme | 43 | ### Petname scheme |
| 44 | 44 | ||
| @@ -4,7 +4,7 @@ NIP-05 | |||
| 4 | Mapping Nostr keys to DNS-based internet identifiers | 4 | Mapping Nostr keys to DNS-based internet identifiers |
| 5 | ---------------------------------------------------- | 5 | ---------------------------------------------------- |
| 6 | 6 | ||
| 7 | `final` `optional` `author:fiatjaf` | 7 | `final` `optional` `author:fiatjaf` `author:mikedilger` |
| 8 | 8 | ||
| 9 | On events of kind `0` (`set_metadata`) one can specify the key `"nip05"` with an [internet identifier](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1) (an email-like address) as the value. Although there is a link to a very liberal "internet identifier" specification above, NIP-05 assumes the `<local-part>` part will be restricted to the characters `a-z0-9-_.`, case insensitive. | 9 | On events of kind `0` (`set_metadata`) one can specify the key `"nip05"` with an [internet identifier](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4.1) (an email-like address) as the value. Although there is a link to a very liberal "internet identifier" specification above, NIP-05 assumes the `<local-part>` part will be restricted to the characters `a-z0-9-_.`, case insensitive. |
| 10 | 10 | ||
| @@ -33,9 +33,24 @@ It will make a GET request to `https://example.com/.well-known/nostr.json?name=b | |||
| 33 | "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9" | 33 | "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9" |
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| 36 | ``` | 36 | ```` |
| 37 | |||
| 38 | or with the **optional** `"relays"` attribute: | ||
| 39 | |||
| 40 | ```json | ||
| 41 | { | ||
| 42 | "names": { | ||
| 43 | "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9" | ||
| 44 | }, | ||
| 45 | "relays": { | ||
| 46 | "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ] | ||
| 47 | } | ||
| 48 | } | ||
| 49 | ```` | ||
| 50 | |||
| 51 | If the pubkey matches the one given in `"names"` (as in the example above) that means the association is right and the `"nip05"` identifier is valid and can be displayed. | ||
| 37 | 52 | ||
| 38 | That will mean everything is alright. | 53 | 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 a 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. |
| 39 | 54 | ||
| 40 | ## Finding users from their NIP-05 identifier | 55 | ## Finding users from their NIP-05 identifier |
| 41 | 56 | ||
| @@ -68,7 +83,7 @@ By adding the `<local-part>` as a query string instead of as part of the path th | |||
| 68 | JavaScript Nostr apps may be restricted by browser [CORS][] policies that prevent them from accessing `/.well-known/nostr.json` on the user's domain. When CORS prevents JS from loading a resource, the JS program sees it as a network failure identical to the resource not existing, so it is not possible for a pure-JS app to tell the user for certain that the failure was caused by a CORS issue. JS Nostr apps that see network failures requesting `/.well-known/nostr.json` files may want to recommend to users that they check the CORS policy of their servers, e.g.: | 83 | JavaScript Nostr apps may be restricted by browser [CORS][] policies that prevent them from accessing `/.well-known/nostr.json` on the user's domain. When CORS prevents JS from loading a resource, the JS program sees it as a network failure identical to the resource not existing, so it is not possible for a pure-JS app to tell the user for certain that the failure was caused by a CORS issue. JS Nostr apps that see network failures requesting `/.well-known/nostr.json` files may want to recommend to users that they check the CORS policy of their servers, e.g.: |
| 69 | 84 | ||
| 70 | ```bash | 85 | ```bash |
| 71 | $ curl -sI https://example.com/.well-known/nostr.json?name=bob | grep ^Access-Control | 86 | $ curl -sI https://example.com/.well-known/nostr.json?name=bob | grep -i ^Access-Control |
| 72 | Access-Control-Allow-Origin: * | 87 | Access-Control-Allow-Origin: * |
| 73 | ``` | 88 | ``` |
| 74 | 89 | ||
| @@ -12,7 +12,7 @@ That object must define the following methods: | |||
| 12 | 12 | ||
| 13 | ``` | 13 | ``` |
| 14 | async window.nostr.getPublicKey(): string // returns a public key as hex | 14 | async window.nostr.getPublicKey(): string // returns a public key as hex |
| 15 | async window.nostr.signEvent(event: Event): Event // takes an event object and returns it with the `sig` | 15 | async window.nostr.signEvent(event: Event): Event // takes an event object, adds `id`, `pubkey` and `sig` and returns it |
| 16 | ``` | 16 | ``` |
| 17 | 17 | ||
| 18 | Aside from these two basic above, the following functions can also be implemented optionally: | 18 | Aside from these two basic above, the following functions can also be implemented optionally: |
| @@ -24,6 +24,7 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext | |||
| 24 | 24 | ||
| 25 | ### Implementation | 25 | ### Implementation |
| 26 | 26 | ||
| 27 | - [nos2x](https://github.com/fiatjaf/nos2x) is available as a Chromium extension that provides such capabilities. | 27 | - [nos2x](https://github.com/fiatjaf/nos2x) |
| 28 | - [Alby](https://getalby.com) is a Bitcoin extension that also provides a compatible `window.nostr`. | 28 | - [Alby](https://getalby.com) |
| 29 | - [Blockcore](https://www.blockcore.net/wallet) | 29 | - [Blockcore](https://www.blockcore.net/wallet) |
| 30 | - [nos2x-fox](https://diegogurpegui.com/nos2x-fox/) | ||
| @@ -27,13 +27,13 @@ For example: | |||
| 27 | } | 27 | } |
| 28 | ``` | 28 | ``` |
| 29 | 29 | ||
| 30 | Relays SHOULD delete or stop publishing any referenced events that have an identical `pubkey` as the deletion request. Clients SHOULD hide or otherwise indicate a deletion status for referenced events. | 30 | Relays SHOULD delete or stop publishing any referenced events that have an identical `id` as the deletion request. Clients SHOULD hide or otherwise indicate a deletion status for referenced events. |
| 31 | 31 | ||
| 32 | Relays SHOULD continue to publish/share the deletion events indefinitely, as clients may already have the event that's intended to be deleted. Additionally, clients SHOULD broadcast deletion events to other relays which don't have it. | 32 | Relays SHOULD continue to publish/share the deletion events indefinitely, as clients may already have the event that's intended to be deleted. Additionally, clients SHOULD broadcast deletion events to other relays which don't have it. |
| 33 | 33 | ||
| 34 | ## Client Usage | 34 | ## Client Usage |
| 35 | 35 | ||
| 36 | Clients MAY choose to fully hide any events that are referenced by valid deletion events. This includes text notes, direct messages, or other yet-to-be defined event kinds. Alternatively, they MAY show the event along with an icon or other indication that the author has "disowned" the event. The `content` field MAY also be used to replace the deleted events own content, although a user interface should clearly indicate that this is a deletion reason, not the original content. | 36 | Clients MAY choose to fully hide any events that are referenced by valid deletion events. This includes text notes, direct messages, or other yet-to-be defined event kinds. Alternatively, they MAY show the event along with an icon or other indication that the author has "disowned" the event. The `content` field MAY also be used to replace the deleted event's own content, although a user interface should clearly indicate that this is a deletion reason, not the original content. |
| 37 | 37 | ||
| 38 | A client MUST validate that each event `pubkey` referenced in the `e` tag of the deletion request is identical to the deletion request `pubkey`, before hiding or deleting any event. Relays can not, in general, perform this validation and should not be treated as authoritative. | 38 | A client MUST validate that each event `pubkey` referenced in the `e` tag of the deletion request is identical to the deletion request `pubkey`, before hiding or deleting any event. Relays can not, in general, perform this validation and should not be treated as authoritative. |
| 39 | 39 | ||
| @@ -44,9 +44,9 @@ Where: | |||
| 44 | 44 | ||
| 45 | * `<event-id>` is the id of the event being referenced. | 45 | * `<event-id>` is the id of the event being referenced. |
| 46 | * `<relay-url>` is the URL of a recommended relay associated with the reference. It is NOT optional. | 46 | * `<relay-url>` is the URL of a recommended relay associated with the reference. It is NOT optional. |
| 47 | * `<marker>` is optional and if present is one of `"reply"` or `"root"` | 47 | * `<marker>` is optional and if present is one of `"reply"`, `"root"`, or `"mention"` |
| 48 | 48 | ||
| 49 | **The order of marked "e" tags is not relevant.** Those marked with `"reply"` denote the `<reply-id>`. Those marked with `"root"` denote the root id of the reply thread. | 49 | **The order of marked "e" tags is not relevant.** Those marked with `"reply"` denote the id of the reply event being responded to. Those marked with `"root"` denote the root id of the reply thread being responded to. For top level replies (those replying directly to the root event), only the `"root"` marker should be used. Those marked with `"mention"` denote a quoted or reposted event id. |
| 50 | 50 | ||
| 51 | A direct reply to the root of a thread should have a single marked "e" tag of type "root". | 51 | A direct reply to the root of a thread should have a single marked "e" tag of type "root". |
| 52 | 52 | ||
| @@ -8,7 +8,7 @@ Event `created_at` Limits | |||
| 8 | 8 | ||
| 9 | Relays may define both upper and lower limits within which they will consider an event's `created_at` to be acceptable. Both the upper and lower limits MUST be unix timestamps in seconds as defined in [NIP-01](01.md). | 9 | Relays may define both upper and lower limits within which they will consider an event's `created_at` to be acceptable. Both the upper and lower limits MUST be unix timestamps in seconds as defined in [NIP-01](01.md). |
| 10 | 10 | ||
| 11 | If a relay supports this NIP, the relay SHOULD send the client a `NOTICE` message saying the event was not stored for the `created_at` timestamp not being within the permitted limits. | 11 | If a relay supports this NIP, the relay SHOULD send the client a [NIP-20](20.md) command result saying the event was not stored for the `created_at` timestamp not being within the permitted limits. |
| 12 | 12 | ||
| 13 | Client Behavior | 13 | Client Behavior |
| 14 | --------------- | 14 | --------------- |
| @@ -22,24 +22,24 @@ This NIP formalizes restrictions on event timestamps as accepted by a relay and | |||
| 22 | 22 | ||
| 23 | The event `created_at` field is just a unix timestamp and can be set to a time in the past or future. Relays accept and share events dated to 20 years ago or 50,000 years in the future. This NIP aims to define a way for relays that do not want to store events with *any* timestamp to set their own restrictions. | 23 | The event `created_at` field is just a unix timestamp and can be set to a time in the past or future. Relays accept and share events dated to 20 years ago or 50,000 years in the future. This NIP aims to define a way for relays that do not want to store events with *any* timestamp to set their own restrictions. |
| 24 | 24 | ||
| 25 | [Replaceable events](16.md#replaceable-events) can behave rather unexpected if the user wrote them - or tried to write them - with a wrong system clock. Persisting an update with a backdated system now would result in the update not getting persisted without a `NOTICE` and if they did the last update with a forward dated system, they will again fail to do another update with the now correct time. | 25 | [Replaceable events](16.md#replaceable-events) can behave rather unexpected if the user wrote them - or tried to write them - with a wrong system clock. Persisting an update with a backdated system now would result in the update not getting persisted without a notification and if they did the last update with a forward dated system, they will again fail to do another update with the now correct time. |
| 26 | 26 | ||
| 27 | A wide adoption of this nip could create a better user experience as it would decrease the amount of events that appear wildly out of order or even from impossible dates in the distant past or future. | 27 | A wide adoption of this NIP could create a better user experience as it would decrease the amount of events that appear wildly out of order or even from impossible dates in the distant past or future. |
| 28 | 28 | ||
| 29 | Keep in mind that there is a use case where a user migrates their old posts onto a new relay. If a relay rejects events that were not recently created, it cannot serve this use case. | 29 | Keep in mind that there is a use case where a user migrates their old posts onto a new relay. If a relay rejects events that were not recently created, it cannot serve this use case. |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | Python Example | 32 | Python (pseudocode) Example |
| 33 | -------------- | 33 | --------------------------- |
| 34 | 34 | ||
| 35 | ```python | 35 | ```python |
| 36 | import time | 36 | import time |
| 37 | 37 | ||
| 38 | TIME = int(time.now) | 38 | TIME = int(time.time()) |
| 39 | LOWER_LIMIT = TIME - (60 * 60 * 24) # Define lower limit as 1 day into the past | 39 | LOWER_LIMIT = TIME - (60 * 60 * 24) # Define lower limit as 1 day into the past |
| 40 | UPPER_LIMIT = TIME + (60 * 15) # Define upper limit as 15 minutes into the future | 40 | UPPER_LIMIT = TIME + (60 * 15) # Define upper limit as 15 minutes into the future |
| 41 | 41 | ||
| 42 | if event.created_at not in range(LOWER_LIMIT, UPPER_LIMIT): | 42 | if event.created_at not in range(LOWER_LIMIT, UPPER_LIMIT): |
| 43 | # NOTE: This is one example of a notice message. Relays can change this to notify clients however they like. | 43 | ws.send('["OK", event.id, False, "invalid: the event created_at field is out of the acceptable range (-24h, +15min) for this relay"]') |
| 44 | ws.send('["NOTICE", "The event created_at field is out of the acceptable range (-24h, +15min) for this relay and was not stored."]') | ||
| 45 | ``` | 44 | ``` |
| 45 | Note: These are just example limits, the relay operator can choose whatever limits they want. | ||
| @@ -18,7 +18,7 @@ downvote or dislike on a post. A client MAY also choose to tally likes against | |||
| 18 | dislikes in a reddit-like system of upvotes and downvotes, or display them as | 18 | dislikes in a reddit-like system of upvotes and downvotes, or display them as |
| 19 | separate tallys. | 19 | separate tallys. |
| 20 | 20 | ||
| 21 | The `content` MAY be an emoji, in this case it MAY be interpreted as a "like", | 21 | The `content` MAY be an emoji, in this case it MAY be interpreted as a "like" or "dislike", |
| 22 | or the client MAY display this emoji reaction on the post. | 22 | or the client MAY display this emoji reaction on the post. |
| 23 | 23 | ||
| 24 | Tags | 24 | Tags |
| @@ -25,41 +25,59 @@ This NIP introduces a new tag: `delegation` which is formatted as follows: | |||
| 25 | 25 | ||
| 26 | ##### Delegation Token | 26 | ##### Delegation Token |
| 27 | 27 | ||
| 28 | The **delegation token** should be a 64-bytes schnorr signature of the sha256 hash of the following string: | 28 | The **delegation token** should be a 64-byte Schnorr signature of the sha256 hash of the following string: |
| 29 | 29 | ||
| 30 | ``` | 30 | ``` |
| 31 | nostr:delegation:<pubkey of publisher (delegatee)>:<conditions query string> | 31 | nostr:delegation:<pubkey of publisher (delegatee)>:<conditions query string> |
| 32 | ``` | 32 | ``` |
| 33 | 33 | ||
| 34 | For example, the token `c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1` is signed by `86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e` and consists of: | ||
| 35 | 34 | ||
| 36 | ```json | 35 | #### Example |
| 37 | nostr:delegation:62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49:kind=1&created_at>1640995200 | 36 | |
| 38 | ``` | 37 | ``` |
| 38 | # Delegator: | ||
| 39 | privkey: ee35e8bb71131c02c1d7e73231daa48e9953d329a4b701f7133c8f46dd21139c | ||
| 40 | pubkey: 8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd | ||
| 39 | 41 | ||
| 40 | #### Example | 42 | # Delegatee: |
| 43 | privkey: 777e4f60b4aa87937e13acc84f7abcc3c93cc035cb4c1e9f7a9086dd78fffce1 | ||
| 44 | pubkey: 477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396 | ||
| 45 | ``` | ||
| 46 | |||
| 47 | Delegation string to grant note publishing authorization to the delegatee (477318cf) for the next 30 days. | ||
| 48 | ```json | ||
| 49 | nostr:delegation:477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396:kind=1&created_at<1675721885 | ||
| 50 | ``` | ||
| 41 | 51 | ||
| 42 | Below is an example of an event published by `62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49`, on behalf of `86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e`. | 52 | The delegator (8e0d3d3e) then signs the above delegation string, the result of which is the delegation token: |
| 53 | ``` | ||
| 54 | cbc49c65fe04a3181d72fb5a9f1c627e329d5f45d300a2dfed1c3e788b7834dad48a6d27d8e244af39c77381334ede97d4fd15abe80f35fda695fd9bd732aa1e | ||
| 55 | ``` | ||
| 43 | 56 | ||
| 57 | The delegatee (477318cf) can now construct an event on behalf of the delegator (8e0d3d3e). The delegatee then signs the event with its own private key and publishes. | ||
| 44 | ```json | 58 | ```json |
| 45 | { | 59 | { |
| 46 | "id": "a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc", | 60 | "id": "ac4c71e69c39b1bd605de812543ebfaf81d5af365354f061d48981fb61e00b8a", |
| 47 | "pubkey": "62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49", | 61 | "pubkey": "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", |
| 48 | "created_at": 1660896109, | 62 | "created_at": 1673129661, |
| 49 | "kind": 1, | 63 | "kind": 1, |
| 50 | "tags": [ | 64 | "tags": [ |
| 51 | [ | 65 | [ |
| 52 | "delegation", | 66 | "delegation", |
| 53 | "86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e", | 67 | "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", |
| 54 | "kind=1&created_at>1640995200", | 68 | "kind=1&created_at<1675721813", |
| 55 | "c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1" | 69 | "cbc49c65fe04a3181d72fb5a9f1c627e329d5f45d300a2dfed1c3e788b7834dad48a6d27d8e244af39c77381334ede97d4fd15abe80f35fda695fd9bd732aa1e" |
| 56 | ] | 70 | ] |
| 57 | ], | 71 | ], |
| 58 | "content": "Hello world", | 72 | "content": "Hello, world!", |
| 59 | "sig": "cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6" | 73 | "sig": "55ed9a78d6449b8c189b6dbc34bc4bcd34dcc79e6da6c9078268fe3d7c0cbe62b1b907ffb76ba591e83895b1329bf2e6e16f3b0cd5827272e420d419c6f0f0b5" |
| 60 | } | 74 | } |
| 61 | ``` | 75 | ``` |
| 62 | 76 | ||
| 77 | The event should be considered a valid delegation if the conditions are satisfied (`kind=1` and `created_at<1675721813` in this example) and, upon validation of the delegation token, are found to be unchanged from the conditions in the original delegation string. | ||
| 78 | |||
| 79 | Clients should display the delegated note as if it was published directly by the delegator (8e0d3d3e). | ||
| 80 | |||
| 63 | 81 | ||
| 64 | #### Relay & Client Querying Support | 82 | #### Relay & Client Querying Support |
| 65 | 83 | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | NIP-33 | ||
| 2 | ====== | ||
| 3 | |||
| 4 | Parameterized Replaceable Events | ||
| 5 | -------------------------------- | ||
| 6 | |||
| 7 | `draft` `optional` `author:Semisol` `author:Kukks` `author:Cameri` `author:Giszmo` | ||
| 8 | |||
| 9 | This NIP adds a new event range that allows for replacement of events that have the same `d` tag and kind unlike NIP-16 which only replaced by kind. | ||
| 10 | |||
| 11 | Implementation | ||
| 12 | -------------- | ||
| 13 | A *parameterized replaceable event* is defined as an event with a kind `30000 <= n < 40000`. | ||
| 14 | Upon a parameterized replaceable event with a newer timestamp than the currently known latest | ||
| 15 | replaceable event with the same kind and first `d` tag value being received, the old event | ||
| 16 | SHOULD be discarded and replaced with the newer event. | ||
| 17 | A missing or a `d` tag with no value should be interpreted equivalent to a `d` tag with the | ||
| 18 | value as an empty string. Events from the same author with any of the following `tags` | ||
| 19 | replace each other: | ||
| 20 | |||
| 21 | * `"tags":[["d",""]]` | ||
| 22 | * `"tags":[]`: implicit `d` tag with empty value | ||
| 23 | * `"tags":[["d"]]`: implicit empty value `""` | ||
| 24 | * `"tags":[["d",""],["d","not empty"]]`: only first `d` tag is considered | ||
| 25 | * `"tags":[["d"],["d","some value"]]`: only first `d` tag is considered | ||
| 26 | * `"tags":[["e"]]`: same as no tags | ||
| 27 | |||
| 28 | Client Behavior | ||
| 29 | --------------- | ||
| 30 | |||
| 31 | Clients SHOULD use the `supported_nips` field to learn if a relay supports this NIP. | ||
| 32 | Clients MAY send parameterized replaceable events to relays that may not support this NIP, and clients querying SHOULD be prepared for the relay to send multiple events and should use the latest one and are recommended to send a `#d` tag filter. Clients should account for the fact that missing `d` tags or ones with no value are not returned in tag filters, and are recommended to always include a `d` tag with a value. | ||
| @@ -1,43 +0,0 @@ | |||
| 1 | |||
| 2 | NIP-35 | ||
| 3 | ====== | ||
| 4 | |||
| 5 | User Discovery | ||
| 6 | -------------- | ||
| 7 | |||
| 8 | `draft` `optional` `author:mikedilger` | ||
| 9 | |||
| 10 | This NIP extends NIP-05 to facilitate a mechanism of user discovery that provides both public key information and relay information. | ||
| 11 | |||
| 12 | This NIP does not modify any data or events within the nostr protocol. It only extends the contents of `https://<domain>/.well-known/nostr.json?name=<local-part>` return values with additional relay information. | ||
| 13 | |||
| 14 | With this NIP implemented, clients may then attempt to discover users via email-like addresses (see NIP-05) and potentially find what relays they post to along with their public key. | ||
| 15 | |||
| 16 | ### nostr.json contents | ||
| 17 | |||
| 18 | NIP-05 specifies a `nostr.json` file with contents like this (refer to NIP-05): | ||
| 19 | |||
| 20 | ```json | ||
| 21 | { | ||
| 22 | "names": { | ||
| 23 | "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9" | ||
| 24 | } | ||
| 25 | } | ||
| 26 | ``` | ||
| 27 | |||
| 28 | This NIP proposes an optional additional key like this: | ||
| 29 | |||
| 30 | ```` | ||
| 31 | { | ||
| 32 | "names": { | ||
| 33 | "bob": "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9" | ||
| 34 | }, | ||
| 35 | "relays": { | ||
| 36 | "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9": [ "wss://relay.example.com", "wss://relay2.example.com" ] | ||
| 37 | } | ||
| 38 | } | ||
| 39 | ```` | ||
| 40 | |||
| 41 | The `relays` key contains an object with public keys as properties and arrays of relays as values. | ||
| 42 | |||
| 43 | Web servers which serve nostr.json files dynamically responding to the query string SHOULD also serve the relays data for any name they serve in the same reply. | ||
| @@ -25,7 +25,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh | |||
| 25 | - [NIP-25: Reactions](25.md) | 25 | - [NIP-25: Reactions](25.md) |
| 26 | - [NIP-26: Delegated Event Signing](26.md) | 26 | - [NIP-26: Delegated Event Signing](26.md) |
| 27 | - [NIP-28: Public Chat](28.md) | 27 | - [NIP-28: Public Chat](28.md) |
| 28 | - [NIP-35: User Discovery](35.md) | 28 | - [NIP-33: Parameterized Replaceable Events](33.md) |
| 29 | - [NIP-36: Sensitive Content](36.md) | 29 | - [NIP-36: Sensitive Content](36.md) |
| 30 | - [NIP-40: Expiration Timestamp](40.md) | 30 | - [NIP-40: Expiration Timestamp](40.md) |
| 31 | - [NIP-42: Authentication of clients to relays](42.md) | 31 | - [NIP-42: Authentication of clients to relays](42.md) |