mirror of
https://github.com/nostr-protocol/nips.git
synced 2025-12-08 16:18:50 +00:00
Compare commits
160 Commits
nip93-nson
...
staab-NIP-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a2977bcc5 | ||
|
|
2239f96541 | ||
|
|
c78bd4cef1 | ||
|
|
a1f8a82e73 | ||
|
|
3a37d7c8b9 | ||
|
|
06f8dbadc8 | ||
|
|
4d95efcf87 | ||
|
|
e2eeda5200 | ||
|
|
94330ffb10 | ||
|
|
30696049cc | ||
|
|
00a8f9532e | ||
|
|
95103569b5 | ||
|
|
a5047326d4 | ||
|
|
d87f86178b | ||
|
|
a4b35284c9 | ||
|
|
f91cb5ce66 | ||
|
|
ce7e6b2100 | ||
|
|
77b626d748 | ||
|
|
892fe9e400 | ||
|
|
507b0c20a5 | ||
|
|
7957880b48 | ||
|
|
f8aa3f4e51 | ||
|
|
73f2f24bbf | ||
|
|
135a2f5338 | ||
|
|
d42fc18fa5 | ||
|
|
3a01861ade | ||
|
|
63441099be | ||
|
|
2b53049c1a | ||
|
|
c07b5fa9b0 | ||
|
|
3ff40201bd | ||
|
|
4c7b728be1 | ||
|
|
856ed84776 | ||
|
|
0c3df0ee30 | ||
|
|
4e61eb4e46 | ||
|
|
bf84e733f3 | ||
|
|
6fbe488504 | ||
|
|
7f4970bb10 | ||
|
|
1912dacd33 | ||
|
|
33fcb7c9bc | ||
|
|
064a79f614 | ||
|
|
b4cdc1a73d | ||
|
|
5d63b1570c | ||
|
|
c2907f836d | ||
|
|
9e0be8467d | ||
|
|
7c5728e3b1 | ||
|
|
e58a40d2e7 | ||
|
|
4a386e645c | ||
|
|
461b4bb16f | ||
|
|
b503f8a92b | ||
|
|
2af496e363 | ||
|
|
fe2009b459 | ||
|
|
d0cb9d0c24 | ||
|
|
ad39e1f3ca | ||
|
|
00f9f5b049 | ||
|
|
8efa0e76b4 | ||
|
|
859bd471fe | ||
|
|
afcbef2bb0 | ||
|
|
b31d3077f6 | ||
|
|
b480624ac2 | ||
|
|
63718d6d89 | ||
|
|
629c787d28 | ||
|
|
d1814405be | ||
|
|
20b9bb787b | ||
|
|
dd4caf9c4c | ||
|
|
f065a40ee6 | ||
|
|
451c06a3c5 | ||
|
|
0b08cf545b | ||
|
|
1889ac792b | ||
|
|
f5a930c824 | ||
|
|
ed32c93c9f | ||
|
|
00ec0c83ac | ||
|
|
a1cd2bd809 | ||
|
|
7cd861c4d3 | ||
|
|
20b22e7079 | ||
|
|
52edccbbe3 | ||
|
|
3a32c0fd78 | ||
|
|
141197c564 | ||
|
|
e0fc913719 | ||
|
|
fab6a21a77 | ||
|
|
852bd7f872 | ||
|
|
1b35f1153d | ||
|
|
3893fa7f7c | ||
|
|
9ffd3638d7 | ||
|
|
73e93d09ad | ||
|
|
1f6c79f6d2 | ||
|
|
7668507cdf | ||
|
|
83cbd3e17a | ||
|
|
36e9fd59e9 | ||
|
|
c8c2ab60ab | ||
|
|
1412eb89c2 | ||
|
|
ece0dda45b | ||
|
|
b481651e81 | ||
|
|
58f1667479 | ||
|
|
992b045aa7 | ||
|
|
bef3e6c941 | ||
|
|
61849b5a6b | ||
|
|
92ce49dda0 | ||
|
|
363d112e33 | ||
|
|
114302517f | ||
|
|
057d097e74 | ||
|
|
4e8f3adf43 | ||
|
|
2372874b98 | ||
|
|
5b32def861 | ||
|
|
95f537e90d | ||
|
|
34910c8674 | ||
|
|
68b9331b62 | ||
|
|
621340e267 | ||
|
|
a9f2c6a2f1 | ||
|
|
3331b5610c | ||
|
|
2b34e9f417 | ||
|
|
fb5f5a1a97 | ||
|
|
4d0929b278 | ||
|
|
2e842b496a | ||
|
|
3e03b4b67f | ||
|
|
d435ffc39c | ||
|
|
75c05b547c | ||
|
|
6baacf6fb1 | ||
|
|
964bc5b5ce | ||
|
|
89b308d540 | ||
|
|
14a887d43b | ||
|
|
0d962cbe74 | ||
|
|
c78856d281 | ||
|
|
867c8bb334 | ||
|
|
fe9ed69dc3 | ||
|
|
cabbaadb69 | ||
|
|
3a38583c06 | ||
|
|
b12c93c452 | ||
|
|
4f04de2afd | ||
|
|
a56d1c2877 | ||
|
|
91bdf63b13 | ||
|
|
5834c05439 | ||
|
|
2f8be7c32b | ||
|
|
9c97736066 | ||
|
|
7c3e590247 | ||
|
|
dd5c9c54ae | ||
|
|
a56d650333 | ||
|
|
e4937befd6 | ||
|
|
0495931355 | ||
|
|
1c916953c1 | ||
|
|
ccbdfb95c1 | ||
|
|
835ec26141 | ||
|
|
d9caf9d7b4 | ||
|
|
4ea0e8e9f2 | ||
|
|
1457399664 | ||
|
|
00491aa9fa | ||
|
|
89e3c01b14 | ||
|
|
9076b8486d | ||
|
|
64ac0710de | ||
|
|
2619482200 | ||
|
|
4cbb672d1c | ||
|
|
2c1ed74c49 | ||
|
|
e5302f84c7 | ||
|
|
de1aec64d2 | ||
|
|
f75d91551c | ||
|
|
30620c8e54 | ||
|
|
2d31ddd38a | ||
|
|
29f26e72b5 | ||
|
|
b8aec7dad5 | ||
|
|
e91ce3409e | ||
|
|
1c728516df |
17
01.md
17
01.md
@@ -16,7 +16,7 @@ The only object type that exists is the `event`, which has the following format
|
||||
|
||||
```json
|
||||
{
|
||||
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>
|
||||
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>,
|
||||
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
|
||||
"created_at": <unix timestamp in seconds>,
|
||||
"kind": <integer>,
|
||||
@@ -55,7 +55,7 @@ Clients can send 3 types of messages, which must be JSON arrays, according to th
|
||||
* `["REQ", <subscription_id>, <filters JSON>...]`, used to request events and subscribe to new updates.
|
||||
* `["CLOSE", <subscription_id>]`, used to stop previous subscriptions.
|
||||
|
||||
`<subscription_id>` is an arbitrary, non-empty string of max length 64 chars, that should be used to represent a subscription.
|
||||
`<subscription_id>` is an arbitrary, non-empty string of max length 64 chars, that should be used to represent a subscription. Relays should manage `<subscription_id>`s independently for each WebSocket connection; even if `<subscription_id>`s are the same string, they should be treated as different subscriptions for different connections.
|
||||
|
||||
`<filters>` is a JSON object that determines what events will be sent in that subscription, it can have the following attributes:
|
||||
|
||||
@@ -66,8 +66,8 @@ Clients can send 3 types of messages, which must be JSON arrays, according to th
|
||||
"kinds": <a list of a kind numbers>,
|
||||
"#e": <a list of event ids that are referenced in an "e" tag>,
|
||||
"#p": <a list of pubkeys that are referenced in a "p" tag>,
|
||||
"since": <an integer unix timestamp, events must be newer than this to pass>,
|
||||
"until": <an integer unix timestamp, events must be older than this to pass>,
|
||||
"since": <an integer unix timestamp in seconds, events must be newer than this to pass>,
|
||||
"until": <an integer unix timestamp in seconds, events must be older than this to pass>,
|
||||
"limit": <maximum number of events to be returned in the initial query>
|
||||
}
|
||||
```
|
||||
@@ -78,11 +78,13 @@ Filter attributes containing lists (such as `ids`, `kinds`, or `#e`) are JSON ar
|
||||
|
||||
The `ids` and `authors` lists contain lowercase hexadecimal strings, which may either be an exact 64-character match, or a prefix of the event value. A prefix match is when the filter string is an exact string prefix of the event value. The use of prefixes allows for more compact filters where a large number of values are queried, and can provide some privacy for clients that may not want to disclose the exact authors or events they are searching for.
|
||||
|
||||
The `since` and `until` properties can be used to specify the time range of events returned in the subscription. If a filter includes the `since` property, events with `created_at` greater than or equal to `since` are considered to match the filter. The `until` property is similar except that `created_at` must be less than or equal to `until`. In short, an event matches a filter if `since <= created_at <= until` holds.
|
||||
|
||||
All conditions of a filter that are specified must match for an event for it to pass the filter, i.e., multiple conditions are interpreted as `&&` conditions.
|
||||
|
||||
A `REQ` message may contain multiple filters. In this case, events that match any of the filters are to be returned, i.e., multiple filters are to be interpreted as `||` conditions.
|
||||
|
||||
The `limit` property of a filter is only valid for the initial query and can be ignored afterward. When `limit: n` is present it is assumed that the events returned in the initial query will be the latest `n` events. It is safe to return less events than `limit` specifies, but it is expected that relays do not return (much) more events than requested so clients don't get unnecessarily overwhelmed by data.
|
||||
The `limit` property of a filter is only valid for the initial query and can be ignored afterward. When `limit: n` is present it is assumed that the events returned in the initial query will be the last `n` events ordered by the `created_at`. It is safe to return less events than `limit` specifies, but it is expected that relays do not return (much) more events than requested so clients don't get unnecessarily overwhelmed by data.
|
||||
|
||||
### From relay to client: sending events and notices
|
||||
|
||||
@@ -99,7 +101,7 @@ This NIP defines no rules for how `NOTICE` messages should be sent or treated.
|
||||
## Basic Event Kinds
|
||||
|
||||
- `0`: `set_metadata`: the `content` is set to a stringified JSON object `{name: <username>, about: <string>, picture: <url, string>}` describing the user who created the event. A relay may delete past `set_metadata` events once it gets a new one for the same pubkey.
|
||||
- `1`: `text_note`: the `content` is set to the plaintext content of a note (anything the user wants to say). Do not use Markdown! Clients should not have to guess how to interpret content like `[]()`. Use different event kinds for parsable content.
|
||||
- `1`: `text_note`: the `content` is set to the **plaintext** content of a note (anything the user wants to say). Content that must be parsed, such as Markdown and HTML, should not be used. Clients should also not parse content as those.
|
||||
- `2`: `recommend_server`: the `content` is set to the URL (e.g., `wss://somerelay.com`) of a relay the event creator wants to recommend to its followers.
|
||||
|
||||
A relay may choose to treat different message kinds differently, and it may or may not choose to have a default way to handle kinds it doesn't know about.
|
||||
@@ -107,6 +109,7 @@ A relay may choose to treat different message kinds differently, and it may or m
|
||||
## Other Notes:
|
||||
|
||||
- Clients should not open more than one websocket to each relay. One channel can support an unlimited number of subscriptions, so clients should do that.
|
||||
- The `tags` array can store a tag identifier as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](https://github.com/nostr-protocol/nips/blob/127d5518bfa9a4e4e7510490c0b8d95e342dfa4b/10.md) for a detailed description of "e" and "p" tags.
|
||||
- The `tags` array can store a case-sensitive tag name as the first element of each subarray, plus arbitrary information afterward (always as strings). This NIP defines `"p"` — meaning "pubkey", which points to a pubkey of someone that is referred to in the event —, and `"e"` — meaning "event", which points to the id of an event this event is quoting, replying to or referring to somehow. See [NIP-10](10.md) for a detailed description of "e" and "p" tags.
|
||||
- The `<recommended relay URL>` item present on the `"e"` and `"p"` tags is an optional (could be set to `""`) URL of a relay the client could attempt to connect to fetch the tagged event or other events from a tagged profile. It MAY be ignored, but it exists to increase censorship resistance and make the spread of relay addresses more seamless across clients.
|
||||
- Clients should use the created_at field to judge the age of a metadata event and completely replace older metadata events with newer metadata events regardless of the order in which they arrive. Clients should not merge any filled fields within older metadata events into empty fields of newer metadata events.
|
||||
- When a websocket is closed by the relay with a status code 4000 that means the client shouldn't try to connect again.
|
||||
|
||||
4
04.md
4
04.md
@@ -1,10 +1,12 @@
|
||||
> __Warning__ `unrecommended`: deprecated in favor of [NIP-44](44.md)
|
||||
|
||||
NIP-04
|
||||
======
|
||||
|
||||
Encrypted Direct Message
|
||||
------------------------
|
||||
|
||||
`final` `optional` `author:arcbtc`
|
||||
`final` `unrecommended` `author:arcbtc`
|
||||
|
||||
A special event with kind `4`, meaning "encrypted direct message". It is supposed to have the following attributes:
|
||||
|
||||
|
||||
6
05.md
6
05.md
@@ -6,7 +6,7 @@ Mapping Nostr keys to DNS-based internet identifiers
|
||||
|
||||
`final` `optional` `author:fiatjaf` `author:mikedilger`
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Upon seeing that, the client splits the identifier into `<local-part>` and `<domain>` and use these values to make a GET request to `https://<domain>/.well-known/nostr.json?name=<local-part>`.
|
||||
|
||||
@@ -50,7 +50,7 @@ or with the **optional** `"relays"` attribute:
|
||||
|
||||
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.
|
||||
|
||||
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 `"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 the specific 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.
|
||||
|
||||
## Finding users from their NIP-05 identifier
|
||||
|
||||
@@ -76,7 +76,7 @@ Clients may treat the identifier `_@domain` as the "root" identifier, and choose
|
||||
|
||||
### Reasoning for the `/.well-known/nostr.json?name=<local-part>` format
|
||||
|
||||
By adding the `<local-part>` as a query string instead of as part of the path the protocol can support both dynamic servers that can generate JSON on-demand and static servers with a JSON file in it that may contain multiple names.
|
||||
By adding the `<local-part>` as a query string instead of as part of the path, the protocol can support both dynamic servers that can generate JSON on-demand and static servers with a JSON file in it that may contain multiple names.
|
||||
|
||||
### Allowing access from JavaScript apps
|
||||
|
||||
|
||||
11
07.md
11
07.md
@@ -18,15 +18,20 @@ async window.nostr.signEvent(event: Event): Event // takes an event object, adds
|
||||
Aside from these two basic above, the following functions can also be implemented optionally:
|
||||
```
|
||||
async window.nostr.getRelays(): { [url: string]: {read: boolean, write: boolean} } // returns a basic map of relay urls to relay policies
|
||||
async window.nostr.nip04.encrypt(pubkey, plaintext): string // returns ciphertext and iv as specified in nip-04
|
||||
async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext and iv as specified in nip-04
|
||||
async window.nostr.nip04.encrypt(pubkey, plaintext): string // returns ciphertext and iv as specified in nip-04 (deprecated)
|
||||
async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext and iv as specified in nip-04 (deprecated)
|
||||
async window.nostr.nip44.encrypt(pubkey, plaintext, v): string // returns encrypted payload as specified in nip-44
|
||||
async window.nostr.nip44.decrypt(pubkey, payload): string // takes encrypted payload as specified in nip-44
|
||||
```
|
||||
|
||||
### Implementation
|
||||
|
||||
- [horse](https://github.com/fiatjaf/horse) (Chrome and derivatives)
|
||||
- [nos2x](https://github.com/fiatjaf/nos2x) (Chrome and derivatives)
|
||||
- [Alby](https://getalby.com) (Chrome and derivatives, Firefox, Safari)
|
||||
- [Alby](https://getalby.com) (Chrome and derivatives, Firefox)
|
||||
- [Blockcore](https://www.blockcore.net/wallet) (Chrome and derivatives)
|
||||
- [nos2x-fox](https://diegogurpegui.com/nos2x-fox/) (Firefox)
|
||||
- [Flamingo](https://www.getflamingo.org/) (Chrome and derivatives)
|
||||
- [AKA Profiles](https://github.com/neilck/aka-extension) (Chrome, stores multiple keys)
|
||||
- [TokenPocket](https://www.tokenpocket.pro/) (Android, IOS, Chrome and derivatives)
|
||||
- [Nostrmo](https://github.com/haorendashu/nostrmo_faq#download) (Android, IOS)
|
||||
|
||||
3
09.md
3
09.md
@@ -8,7 +8,7 @@ Event Deletion
|
||||
|
||||
A special event with kind `5`, meaning "deletion" is defined as having a list of one or more `e` tags, each referencing an event the author is requesting to be deleted.
|
||||
|
||||
Each tag entry must contain an "e" event id intended for deletion.
|
||||
Each tag entry must contain an "e" event id and/or NIP-33 `a` tags intended for deletion.
|
||||
|
||||
The event's `content` field MAY contain a text note describing the reason for the deletion.
|
||||
|
||||
@@ -21,6 +21,7 @@ For example:
|
||||
"tags": [
|
||||
["e", "dcd59..464a2"],
|
||||
["e", "968c5..ad7a4"],
|
||||
["a", "<kind>:<pubkey>:<d-identifier>"]
|
||||
],
|
||||
"content": "these posts were published by accident",
|
||||
...other fields
|
||||
|
||||
15
11.md
15
11.md
@@ -255,6 +255,18 @@ Relays that require payments may want to expose their fee schedules.
|
||||
}
|
||||
```
|
||||
|
||||
### Icon ###
|
||||
|
||||
A URL pointing to an image to be used as an icon for the relay. Recommended to be squared in shape.
|
||||
|
||||
```json
|
||||
{
|
||||
...
|
||||
"icon": "https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Examples ###
|
||||
As of 2 May 2023 the following `curl` command provided these results.
|
||||
|
||||
@@ -281,4 +293,5 @@ As of 2 May 2023 the following `curl` command provided these results.
|
||||
"payment_required":true},
|
||||
"payments_url":"https://eden.nostr.land/invoices",
|
||||
"fees":{"admission":[{"amount":5000000,"unit":"msats"}],
|
||||
"publication":[]}}
|
||||
"publication":[]}},
|
||||
"icon": "https://nostr.build/i/53866b44135a27d624e99c6165cabd76ac8f72797209700acb189fce75021f47.jpg"
|
||||
|
||||
2
12.md
2
12.md
@@ -8,7 +8,7 @@ Generic Tag Queries
|
||||
|
||||
Relays may support subscriptions over arbitrary tags. `NIP-01` requires relays to respond to queries for `e` and `p` tags. This NIP allows any single-letter tag present in an event to be queried.
|
||||
|
||||
The `<filters>` object described in `NIP-01` is expanded to contain arbitrary keys with a `#` prefix. Any single-letter key in a filter beginning with `#` is a tag query, and MUST have a value of an array of strings. The filter condition matches if the event has a tag with the same name, and there is at least one tag value in common with the filter and event. The tag name is the letter without the `#`, and the tag value is the second element. Subsequent elements are ignored for the purposes of tag queries.
|
||||
The `<filters>` object described in `NIP-01` is expanded to contain arbitrary keys with a `#` prefix. Any single-letter key in a filter beginning with `#` is a tag query, and MUST have a value of an array of strings. The filter condition matches if the event has a tag with the same name, and there is at least one tag value in common with the filter and event. The tag name is the letter without the `#`, and the tag value is the second element. Subsequent elements are ignored for the purposes of tag queries. Note that tag names are case-sensitive.
|
||||
|
||||
Example Subscription Filter
|
||||
---------------------------
|
||||
|
||||
4
14.md
4
14.md
@@ -1,8 +1,8 @@
|
||||
NIP-14
|
||||
======
|
||||
|
||||
Subject tag in Text events.
|
||||
---------------------------
|
||||
Subject tag in Text events
|
||||
--------------------------
|
||||
|
||||
`draft` `optional` `author:unclebobmartin`
|
||||
|
||||
|
||||
4
15.md
4
15.md
@@ -38,8 +38,8 @@ A merchant can publish these events:
|
||||
| `0 ` | `set_meta` | The merchant description (similar with any `nostr` public key). | [NIP01 ](https://github.com/nostr-protocol/nips/blob/master/01.md) |
|
||||
| `30017` | `set_stall` | Create or update a stall. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
|
||||
| `30018` | `set_product` | Create or update a product. | [NIP33](https://github.com/nostr-protocol/nips/blob/master/33.md) (Parameterized Replaceable Event) |
|
||||
| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) |
|
||||
| `5 ` | `delete` | Delete a product or a stall. | [NIP05](https://github.com/nostr-protocol/nips/blob/master/05.md) |
|
||||
| `4 ` | `direct_message` | Communicate with the customer. The messages can be plain-text or JSON. | [NIP04](https://github.com/nostr-protocol/nips/blob/master/04.md) |
|
||||
| `5 ` | `delete` | Delete a product or a stall. | [NIP09](https://github.com/nostr-protocol/nips/blob/master/09.md) |
|
||||
|
||||
### Event `30017`: Create or update a stall.
|
||||
|
||||
|
||||
2
16.md
2
16.md
@@ -20,6 +20,8 @@ Upon a replaceable event with a newer timestamp than the currently known latest
|
||||
effectively replacing what gets returned when querying for
|
||||
`author:kind` tuples.
|
||||
|
||||
If two events have the same timestamp, the event with the lowest id (first in lexical order) SHOULD be retained, and the other discarded.
|
||||
|
||||
Ephemeral Events
|
||||
----------------
|
||||
An *ephemeral event* is defined as an event with a kind `20000 <= n < 30000`.
|
||||
|
||||
21
18.md
21
18.md
@@ -6,11 +6,10 @@ Reposts
|
||||
|
||||
`draft` `optional` `author:jb55` `author:fiatjaf` `author:arthurfranca`
|
||||
|
||||
A repost is a `kind 6` note that is used to signal to followers
|
||||
that another event is worth reading.
|
||||
A repost is a `kind 6` event that is used to signal to followers
|
||||
that a `kind 1` text note is worth reading.
|
||||
|
||||
The `content` of a repost event is empty. Optionally, it MAY contain
|
||||
the stringified JSON of the reposted note event for quick look up.
|
||||
The `content` of a repost event is _the stringified JSON of the reposted note_. It MAY also be empty, but that is not recommended.
|
||||
|
||||
The repost event MUST include an `e` tag with the `id` of the note that is
|
||||
being reposted. That tag MUST include a relay URL as its third entry
|
||||
@@ -21,5 +20,15 @@ reposted.
|
||||
|
||||
## Quote Reposts
|
||||
|
||||
Quote reposts are `kind 1` events with an embedded `e` tag (see [NIP-08](08.md) and [NIP-27](27.md)).
|
||||
Because a quote repost includes an `e` tag, it may show up along replies to the reposted note.
|
||||
Quote reposts are `kind 1` events with an embedded `e` tag
|
||||
(see [NIP-08](08.md) and [NIP-27](27.md)). Because a quote repost includes
|
||||
an `e` tag, it may show up along replies to the reposted note.
|
||||
|
||||
## Generic Reposts
|
||||
|
||||
Since `kind 6` reposts are reserved for `kind 1` contents, we use `kind 16`
|
||||
as a "generic repost", that can include any kind of event inside other than
|
||||
`kind 1`.
|
||||
|
||||
`kind 16` reposts SHOULD contain a `k` tag with the stringified kind number
|
||||
of the reposted event as its value.
|
||||
|
||||
8
23.md
8
23.md
@@ -6,13 +6,17 @@ Long-form Content
|
||||
|
||||
`draft` `optional` `author:fiatjaf`
|
||||
|
||||
This NIP defines `kind:30023` (a parameterized replaceable event according to [NIP-33](33.md)) for long-form text content, generally referred to as "articles" or "blog posts".
|
||||
This NIP defines `kind:30023` (a parameterized replaceable event according to [NIP-33](33.md)) for long-form text content, generally referred to as "articles" or "blog posts". `kind:30024` has the same structure as `kind:30023` and is used to save long form drafts.
|
||||
|
||||
"Social" clients that deal primarily with `kind:1` notes should not be expected to implement this NIP.
|
||||
|
||||
### Format
|
||||
|
||||
The `.content` of these events should be a string text in Markdown syntax.
|
||||
The `.content` of these events should be a string text in Markdown syntax. To maximize compatibility and readability between different clients and devices, any client that is creating long form notes:
|
||||
|
||||
- MUST NOT hard line-break paragraphs of text, such as arbitrary line breaks at 80 column boundaries.
|
||||
|
||||
- MUST NOT support adding HTML to Markdown.
|
||||
|
||||
### Metadata
|
||||
|
||||
|
||||
27
25.md
27
25.md
@@ -18,8 +18,9 @@ downvote or dislike on a post. A client MAY also choose to tally likes against
|
||||
dislikes in a reddit-like system of upvotes and downvotes, or display them as
|
||||
separate tallies.
|
||||
|
||||
The `content` MAY be an emoji, in this case it MAY be interpreted as a "like" or "dislike",
|
||||
or the client MAY display this emoji reaction on the post.
|
||||
The `content` MAY be an emoji, or [NIP-30](30.md) custom emoji in this case it MAY be interpreted as a "like" or "dislike",
|
||||
or the client MAY display this emoji reaction on the post. If the `content` is an empty string then the client should
|
||||
consider it a "+".
|
||||
|
||||
Tags
|
||||
----
|
||||
@@ -47,3 +48,25 @@ func make_like_event(pubkey: String, privkey: String, liked: NostrEvent) -> Nost
|
||||
ev.sign(privkey: privkey)
|
||||
return ev
|
||||
}
|
||||
```
|
||||
|
||||
Custom Emoji Reaction
|
||||
---------------------
|
||||
|
||||
The client may specify a custom emoji ([NIP-30](30.md)) `:shortcode:` in the
|
||||
reaction content. The client should refer to the emoji tag and render the
|
||||
content as an emoji if shortcode is specified.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 7,
|
||||
"content": ":soapbox:",
|
||||
"tags": [
|
||||
["emoji", "soapbox", "https://gleasonator.com/emoji/Gleasonator/soapbox.png"]
|
||||
],
|
||||
"pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
|
||||
"created_at": 1682790000
|
||||
}
|
||||
```
|
||||
|
||||
The content can be set only one `:shortcode:`. And emoji tag should be one.
|
||||
|
||||
8
26.md
8
26.md
@@ -1,4 +1,4 @@
|
||||
NIP: 26
|
||||
NIP-26
|
||||
=======
|
||||
|
||||
Delegated Event Signing
|
||||
@@ -52,7 +52,9 @@ For example, the following condition strings are valid:
|
||||
- `kind=0&kind=1&created_at>1675721813`
|
||||
- `kind=1&created_at>1674777689&created_at<1675721813`
|
||||
|
||||
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.
|
||||
For the vast majority of use-cases, it is advisable that:
|
||||
1. 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.
|
||||
2. Query strings should include a `created_at` ***before*** condition that is not empty and is not some extremely distant time in the future. If delegations are not limited in time scope, they expose similar security risks to simply using the root key for authentication.
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -105,4 +107,4 @@ Clients should display the delegated note as if it was published directly by the
|
||||
|
||||
Relays should answer requests such as `["REQ", "", {"authors": ["A"]}]` by querying both the `pubkey` and delegation tags `[1]` value.
|
||||
|
||||
Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf).
|
||||
Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf).
|
||||
|
||||
2
28.md
2
28.md
@@ -37,7 +37,7 @@ In the channel creation `content` field, Client SHOULD include basic channel met
|
||||
|
||||
Update a channel's public metadata.
|
||||
|
||||
Clients and relays SHOULD handle kind 41 events similar to kind 0 `metadata` events.
|
||||
Clients and relays SHOULD handle kind 41 events similar to kind 33 replaceable events, where the information is used to update the metadata, without modifying the event id for the channel. Only the most recent kind 41 is needed to be stored.
|
||||
|
||||
Clients SHOULD ignore kind 41s from pubkeys other than the kind 40 pubkey.
|
||||
|
||||
|
||||
56
30.md
Normal file
56
30.md
Normal file
@@ -0,0 +1,56 @@
|
||||
NIP-30
|
||||
======
|
||||
|
||||
Custom Emoji
|
||||
------------
|
||||
|
||||
`draft` `optional` `author:alexgleason`
|
||||
|
||||
Custom emoji may be added to **kind 0** and **kind 1** events by including one or more `"emoji"` tags, in the form:
|
||||
|
||||
```
|
||||
["emoji", <shortcode>, <image-url>]
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `<shortcode>` is a name given for the emoji, which MUST be comprised of only alphanumeric characters and underscores.
|
||||
- `<image-url>` is a URL to the corresponding image file of the emoji.
|
||||
|
||||
For each emoji tag, clients should parse emoji shortcodes (aka "emojify") like `:shortcode:` in the event to display custom emoji.
|
||||
|
||||
Clients may allow users to add custom emoji to an event by including `:shortcode:` identifier in the event, and adding the relevant `"emoji"` tags.
|
||||
|
||||
### Kind 0 events
|
||||
|
||||
In kind 0 events, the `name` and `about` fields should be emojified.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 0,
|
||||
"content": "{\"name\":\"Alex Gleason :soapbox:\"}",
|
||||
"tags": [
|
||||
["emoji", "soapbox", "https://gleasonator.com/emoji/Gleasonator/soapbox.png"]
|
||||
],
|
||||
"pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
|
||||
"created_at": 1682790000
|
||||
}
|
||||
```
|
||||
|
||||
### Kind 1 events
|
||||
|
||||
In kind 1 events, the `content` should be emojified.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"content": "Hello :gleasonator: 😂 :ablobcatrainbow: :disputed: yolo",
|
||||
"tags": [
|
||||
["emoji", "ablobcatrainbow", "https://gleasonator.com/emoji/blobcat/ablobcatrainbow.png"],
|
||||
["emoji", "disputed", "https://gleasonator.com/emoji/Fun/disputed.png"],
|
||||
["emoji", "gleasonator", "https://gleasonator.com/emoji/Gleasonator/gleasonator.png"]
|
||||
],
|
||||
"pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
|
||||
"created_at": 1682630000
|
||||
}
|
||||
```
|
||||
15
31.md
Normal file
15
31.md
Normal file
@@ -0,0 +1,15 @@
|
||||
NIP-31
|
||||
======
|
||||
|
||||
Dealing with unknown event kinds
|
||||
--------------------------------
|
||||
|
||||
`draft` `optional` `author:pablof7z` `author:fiatjaf`
|
||||
|
||||
When creating a new custom event kind that is part of a custom protocol and isn't meant to be read as text (like `kind:1`), clients should use an `alt` tag to write a short human-readable plaintext summary of what that event is about.
|
||||
|
||||
The intent is that social clients, used to display only `kind:1` notes, can still show something in case a custom event pops up in their timelines. The content of the `alt` tag should provide enough context for a user that doesn't know anything about this event kind to understand what it is.
|
||||
|
||||
These clients that only know `kind:1` are not expected to ask relays for events of different kinds, but users could still reference these weird events on their notes, and without proper context these could be nonsensical notes. Having the fallback text makes that situation much better -- even if only for making the user aware that they should try to view that custom event elsewhere.
|
||||
|
||||
`kind:1`-centric clients can make interacting with these event kinds more functional by supporting [NIP-89](https://github.com/nostr-protocol/nips/blob/master/89.md).
|
||||
126
32.md
Normal file
126
32.md
Normal file
@@ -0,0 +1,126 @@
|
||||
NIP-32
|
||||
======
|
||||
|
||||
Labeling
|
||||
---------
|
||||
|
||||
`draft` `optional` `author:staab` `author:gruruya` `author:s3x-jay`
|
||||
|
||||
A label is a `kind 1985` event that is used to label other entities. This supports a number of use cases, from distributed moderation and content recommendations to reviews and ratings.
|
||||
|
||||
Label Target
|
||||
----
|
||||
|
||||
The label event MUST include one or more tags representing the object or objects being
|
||||
labeled: `e`, `p`, `a`, `r`, or `t` tags. This allows for labeling of events, people, relays,
|
||||
or topics respectively. As with NIP-01, a relay hint SHOULD be included when using `e` and
|
||||
`p` tags.
|
||||
|
||||
Label Tag
|
||||
----
|
||||
|
||||
This NIP introduces a new tag `l` which denotes a label, and a new `L` tag which denotes a label namespace.
|
||||
A label MUST include a mark matching an `L` tag. `L` tags refer to a tag type within nostr, or a nomenclature
|
||||
external to nostr defined either formally or by convention. Any string can be a namespace, but publishers SHOULD
|
||||
ensure they are unambiguous by using a well-defined namespace (such as an ISO standard) or reverse domain name notation.
|
||||
|
||||
Namespaces starting with `#` indicate that the label target should be associated with the label's value.
|
||||
This is a way of attaching standard nostr tags to events, pubkeys, relays, urls, etc.
|
||||
|
||||
Some examples:
|
||||
|
||||
- `["l", "footstr", "#t"]` - the publisher thinks the given entity should have the `footstr` topic applied.
|
||||
- `["l", "<pubkey>", "#p"]` - the publisher thinks the given entity is related to `<pubkey>`
|
||||
- `["l", "IT-MI", "ISO-3166-2"]` - Milano, Italy using ISO 3166-2.
|
||||
- `["l", "VI-hum", "com.example.ontology"]` - Violence toward a human being as defined by ontology.example.com.
|
||||
|
||||
`L` tags containing the label namespaces MUST be included in order to support searching by
|
||||
namespace rather than by a specific tag. The special `ugc` ("user generated content") namespace
|
||||
MAY be used when the label content is provided by an end user.
|
||||
|
||||
`l` and `L` tags MAY be added to other event kinds to support self-reporting. For events
|
||||
with a kind other than 1985, labels refer to the event itself.
|
||||
|
||||
Label Annotations
|
||||
-----
|
||||
|
||||
A label tag MAY include a 4th positional element detailing extra metadata about the label in question. This string
|
||||
should be a json-encoded object. Any key MAY be used, but the following are recommended:
|
||||
|
||||
- `quality` may have a value of 0 to 1. This allows for an absolute, granular scale that can be represented in any way (5 stars, color scale, etc).
|
||||
- `confidence` may have a value of 0 to 1. This indicates the certainty which the author has about their rating.
|
||||
- `context` may be an array of urls (including NIP-21 urls) indicating other context that should be considered when interpreting labels.
|
||||
|
||||
Content
|
||||
-------
|
||||
|
||||
Labels should be short, meaningful strings. Longer discussions, such as for a review, or an
|
||||
explanation of why something was labeled the way it was, should go in the event's `content` field.
|
||||
|
||||
Example events
|
||||
--------------
|
||||
|
||||
A suggestion that multiple pubkeys be associated with the `permies` topic.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1985,
|
||||
"tags": [
|
||||
["L", "#t"],
|
||||
["l", "permies", "#t"],
|
||||
["p", <pubkey1>, <relay_url>],
|
||||
["p", <pubkey2>, <relay_url>]
|
||||
],
|
||||
"content": "",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
A review of a relay.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1985,
|
||||
"tags": [
|
||||
["L", "com.example.ontology"],
|
||||
["l", "relay/review", "com.example.ontology", "{\"quality\": 0.1}"],
|
||||
["r", <relay_url>]
|
||||
],
|
||||
"content": "This relay is full of mean people.",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Publishers can self-label by adding `l` tags to their own non-1985 events.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"tags": [
|
||||
["L", "com.example.ontology"],
|
||||
["l", "IL-frd", "com.example.ontology"]
|
||||
],
|
||||
"content": "Send me 100 sats and I'll send you 200 back",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Other Notes
|
||||
-----------
|
||||
|
||||
When using this NIP to bulk-label many targets at once, events may be deleted and a replacement
|
||||
may be published. We have opted not to use parameterizable/replaceable events for this due to the
|
||||
complexity in coming up with a standard `d` tag. In order to avoid ambiguity when querying,
|
||||
publishers SHOULD limit labeling events to a single namespace.
|
||||
|
||||
Before creating a vocabulary, explore how your use case may have already been designed and
|
||||
imitate that design if possible. Reverse domain name notation is encouraged to avoid
|
||||
namespace clashes, but for the sake of interoperability all namespaces should be
|
||||
considered open for public use, and not proprietary. In other words, if there is a
|
||||
namespace that fits your use case, use it even if it points to someone else's domain name.
|
||||
|
||||
Vocabularies MAY choose to fully qualify all labels within a namespace (for example,
|
||||
`["l", "com.example.vocabulary:my-label"]`. This may be preferred when defining more
|
||||
formal vocabularies that should not be confused with another namespace when querying
|
||||
without an `L` tag. For these vocabularies, all labels SHOULD include the namespace
|
||||
(rather than mixing qualified and unqualified labels).
|
||||
4
33.md
4
33.md
@@ -10,7 +10,7 @@ This NIP adds a new event range that allows for replacement of events that have
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
The value of a tag is defined as the first parameter of a tag after the tag name.
|
||||
The value of a tag can be any string and is defined as the first parameter of a tag after the tag name.
|
||||
|
||||
A *parameterized replaceable event* is defined as an event with a kind `30000 <= n < 40000`.
|
||||
Upon a parameterized replaceable event with a newer timestamp than the currently known latest
|
||||
@@ -18,6 +18,8 @@ replaceable event with the same kind, author and first `d` tag value being recei
|
||||
SHOULD be discarded, effectively replacing what gets returned when querying for
|
||||
`author:kind:d-tag` tuples.
|
||||
|
||||
If two events have the same timestamp, the event with the lowest id (first in lexical order) SHOULD be retained, and the other discarded.
|
||||
|
||||
A missing or a `d` tag with no value should be interpreted equivalent to a `d` tag with the
|
||||
value as an empty string. Events from the same author with any of the following `tags`
|
||||
replace each other:
|
||||
|
||||
9
36.md
9
36.md
@@ -9,12 +9,15 @@ Sensitive Content / Content Warning
|
||||
The `content-warning` tag enables users to specify if the event's content needs to be approved by readers to be shown.
|
||||
Clients can hide the content until the user acts on it.
|
||||
|
||||
`l` and `L` tags MAY be also be used as defined in [NIP-32](32.md) with the `content-warning` or other namespace to support
|
||||
further qualification and querying.
|
||||
|
||||
#### Spec
|
||||
|
||||
```
|
||||
tag: content-warning
|
||||
options:
|
||||
- [reason]: optional
|
||||
- [reason]: optional
|
||||
```
|
||||
|
||||
#### Example
|
||||
@@ -26,6 +29,10 @@ options:
|
||||
"kind": 1,
|
||||
"tags": [
|
||||
["t", "hastag"],
|
||||
["L", "content-warning"],
|
||||
["l", "reason", "content-warning"],
|
||||
["L", "social.nos.ontology"],
|
||||
["l", "NS-nud", "social.nos.ontology"],
|
||||
["content-warning", "reason"] /* reason is optional */
|
||||
],
|
||||
"content": "sensitive content with #hastag\n",
|
||||
|
||||
162
44.md
Normal file
162
44.md
Normal file
@@ -0,0 +1,162 @@
|
||||
NIP-44
|
||||
======
|
||||
|
||||
Encrypted Payloads (Versioned)
|
||||
------------------------------
|
||||
|
||||
`optional` `author:paulmillr` `author:staab`
|
||||
|
||||
The NIP introduces a new data format for keypair-based encryption. This NIP is versioned to allow multiple algorithm choices to exist simultaneously.
|
||||
|
||||
An encrypted payload MUST be encoded as a JSON object. Different versions may have different parameters. Every format has a `v` field specifying its version.
|
||||
|
||||
Currently defined encryption algorithms:
|
||||
|
||||
- `0x00` - Reserved
|
||||
- `0x01` - XChaCha with same key `sha256(ecdh)` per conversation
|
||||
|
||||
# Version 1
|
||||
|
||||
Params:
|
||||
|
||||
1. `nonce`: base64-encoded xchacha nonce
|
||||
2. `ciphertext`: base64-encoded xchacha ciphertext, created from (key, nonce) against `plaintext`.
|
||||
|
||||
Example:
|
||||
|
||||
- Alice's private key: `5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a`
|
||||
- Bob's private key: `4b22aa260e4acb7021e32f38a6cdf4b673c6a277755bfce287e370c924dc936d`
|
||||
|
||||
Encrypting the message `hello` from Alice to Bob results in the base-64 encoded tlv payload:
|
||||
|
||||
```
|
||||
AZKyMIHbfVYFlAAK7Ci5wuM5GFOLaeI7LQKDzWJY
|
||||
```
|
||||
|
||||
# Other Notes
|
||||
|
||||
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 coordinates). We are using this exact implementation. In NIP-94, unhashed shared point was used.
|
||||
|
||||
This encryption scheme replaces the one described in NIP-04, which is not secure. It used bad cryptographic building blocks and must not be used.
|
||||
|
||||
# Code Samples
|
||||
|
||||
## Javascript
|
||||
|
||||
```javascript
|
||||
import {xchacha20} from "@noble/ciphers/chacha"
|
||||
import {secp256k1} from "@noble/curves/secp256k1"
|
||||
import {sha256} from "@noble/hashes/sha256"
|
||||
import {randomBytes} from "@noble/hashes/utils"
|
||||
import {base64} from "@scure/base"
|
||||
|
||||
export const utf8Decoder = new TextDecoder()
|
||||
|
||||
export const utf8Encoder = new TextEncoder()
|
||||
|
||||
export const getSharedSecret = (privkey: string, pubkey: string): Uint8Array =>
|
||||
sha256(secp256k1.getSharedSecret(privkey, "02" + pubkey).subarray(1, 33))
|
||||
|
||||
export function encrypt(privkey: string, pubkey: string, text: string, v = 1) {
|
||||
if (v !== 1) {
|
||||
throw new Error('NIP44: unknown encryption version')
|
||||
}
|
||||
|
||||
const key = getSharedSecret(privkey, pubkey)
|
||||
const nonce = randomBytes(24)
|
||||
const plaintext = utf8Encoder.encode(text)
|
||||
const ciphertext = xchacha20(key, nonce, plaintext)
|
||||
|
||||
const payload = new Uint8Array(1 + 24 + ciphertext.length)
|
||||
payload.set([version], 0)
|
||||
payload.set(nonce, 1)
|
||||
payload.set(ciphertext, 1 + 24)
|
||||
|
||||
return base64.encode(payload)
|
||||
}
|
||||
|
||||
export function decrypt(privkey: string, pubkey: string, blob: string) {
|
||||
const payload = base64.decode(blob)
|
||||
if (payload[0] !== 1) {
|
||||
throw new Error('NIP44: unknown encryption version')
|
||||
}
|
||||
|
||||
const nonce = payload.subarray(1, 25)
|
||||
const ciphertext = payload.subarray(25)
|
||||
|
||||
const key = getSharedSecret(privkey, pubkey)
|
||||
const plaintext = xchacha20(key, nonce, ciphertext)
|
||||
|
||||
return utf8Decoder.decode(plaintext)
|
||||
}
|
||||
```
|
||||
|
||||
## Kotlin
|
||||
|
||||
```kotlin
|
||||
// implementation 'fr.acinq.secp256k1:secp256k1-kmp-jni-android:0.10.1'
|
||||
// implementation "com.goterl:lazysodium-android:5.1.0@aar"
|
||||
// implementation "net.java.dev.jna:jna:5.12.1@aar"
|
||||
|
||||
fun getSharedSecretNIP44(privKey: ByteArray, pubKey: ByteArray): ByteArray =
|
||||
MessageDigest.getInstance("SHA-256").digest(
|
||||
Secp256k1.get().pubKeyTweakMul(
|
||||
Hex.decode("02") + pubKey,
|
||||
privKey
|
||||
).copyOfRange(1, 33)
|
||||
)
|
||||
|
||||
fun encryptNIP44(msg: String, privKey: ByteArray, pubKey: ByteArray): EncryptedInfo {
|
||||
val nonce = ByteArray(24).apply {
|
||||
SecureRandom.getInstanceStrong().nextBytes(this)
|
||||
}
|
||||
|
||||
val cipher = streamXChaCha20Xor(
|
||||
message = msg.toByteArray(),
|
||||
nonce = nonce,
|
||||
key = getSharedSecretNIP44(privKey, pubKey)
|
||||
)
|
||||
|
||||
return EncryptedInfo(
|
||||
ciphertext = Base64.getEncoder().encodeToString(cipher),
|
||||
nonce = Base64.getEncoder().encodeToString(nonce),
|
||||
v = Nip24Version.XChaCha20.code
|
||||
)
|
||||
}
|
||||
|
||||
fun decryptNIP44(encInfo: EncryptedInfo, privKey: ByteArray, pubKey: ByteArray): String? {
|
||||
require(encInfo.v == Nip24Version.XChaCha20.code) { "NIP44: unknown encryption version" }
|
||||
|
||||
return streamXChaCha20Xor(
|
||||
message = Base64.getDecoder().decode(encInfo.ciphertext),
|
||||
nonce = Base64.getDecoder().decode(encInfo.nonce),
|
||||
key = getSharedSecretNIP44(privKey, pubKey)
|
||||
)?.decodeToString()
|
||||
}
|
||||
|
||||
// This method is not exposed in AndroidSodium yet, but it will be in the next version.
|
||||
fun streamXChaCha20Xor(message: ByteArray, nonce: ByteArray, key: ByteArray): ByteArray? {
|
||||
return with (SodiumAndroid()) {
|
||||
val resultCipher = ByteArray(message.size)
|
||||
|
||||
val isSuccessful = crypto_stream_chacha20_xor_ic(
|
||||
resultCipher,
|
||||
message,
|
||||
message.size.toLong(),
|
||||
nonce.drop(16).toByteArray(), // chacha nonce is just the last 8 bytes.
|
||||
0,
|
||||
ByteArray(32).apply {
|
||||
crypto_core_hchacha20(this, nonce, key, null)
|
||||
}
|
||||
) == 0
|
||||
|
||||
if (isSuccessful) resultCipher else null
|
||||
}
|
||||
}
|
||||
|
||||
data class EncryptedInfo(val ciphertext: String, val nonce: String, val v: Int)
|
||||
|
||||
enum class Nip24Version(val code: Int) {
|
||||
Reserved(0),
|
||||
XChaCha20(1)
|
||||
}
|
||||
10
46.md
10
46.md
@@ -82,12 +82,18 @@ These are mandatory methods the remote signer app MUST implement:
|
||||
- **get_relays**
|
||||
- params []
|
||||
- result `{ [url: string]: {read: boolean, write: boolean} }`
|
||||
- **nip04_encrypt**
|
||||
- **nip04_encrypt** (deprecated)
|
||||
- params [`pubkey`, `plaintext`]
|
||||
- result `nip4 ciphertext`
|
||||
- **nip04_decrypt**
|
||||
- **nip04_decrypt** (deprecated)
|
||||
- params [`pubkey`, `nip4 ciphertext`]
|
||||
- result [`plaintext`]
|
||||
- **nip44_encrypt**
|
||||
- params [`pubkey`, `plaintext`, `v`]
|
||||
- result `nip44 encrypted payload`
|
||||
- **nip44_decrypt**
|
||||
- params [`pubkey`, `nip44 encrypted payload`]
|
||||
- result [`plaintext`]
|
||||
|
||||
|
||||
NOTICE: `pubkey` and `signature` are hex-encoded strings.
|
||||
|
||||
6
47.md
6
47.md
@@ -33,7 +33,7 @@ There are three event kinds:
|
||||
- `NIP-47 response`: 23195
|
||||
|
||||
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
|
||||
a plaintext string with the supported commands, space-seperated, eg. `pay_invoice get_balance`. Only the `pay_invoice` command is described in this NIP, but other commands might be defined in different NIPs.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -64,8 +64,8 @@ Response:
|
||||
```
|
||||
|
||||
The `result_type` field MUST contain the name of the method that this event is responding to.
|
||||
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 succesful.
|
||||
If the command was succesful, the `error` field must be null.
|
||||
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.
|
||||
|
||||
### Error codes
|
||||
- `RATE_LIMITED`: The client is sending commands too fast. It should retry in a few seconds.
|
||||
|
||||
60
48.md
Normal file
60
48.md
Normal file
@@ -0,0 +1,60 @@
|
||||
NIP-48
|
||||
======
|
||||
|
||||
Proxy Tags
|
||||
----------
|
||||
|
||||
`draft` `optional` `author:alexgleason`
|
||||
|
||||
Nostr events bridged from other protocols such as ActivityPub can link back to the source object by including a `"proxy"` tag, in the form:
|
||||
|
||||
```
|
||||
["proxy", <id>, <protocol>]
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `<id>` is the ID of the source object. The ID format varies depending on the protocol. The ID must be universally unique, regardless of the protocol.
|
||||
- `<protocol>` is the name of the protocol, e.g. `"activitypub"`.
|
||||
|
||||
Clients may use this information to reconcile duplicated content bridged from other protocols, or to display a link to the source object.
|
||||
|
||||
Proxy tags may be added to any event kind, and doing so indicates that the event did not originate on the Nostr protocol, and instead originated elsewhere on the web.
|
||||
|
||||
### Supported protocols
|
||||
|
||||
This list may be extended in the future.
|
||||
|
||||
| Protocol | ID format | Example |
|
||||
| -------- | --------- | ------- |
|
||||
| `activitypub` | URL | `https://gleasonator.com/objects/9f524868-c1a0-4ee7-ad51-aaa23d68b526` |
|
||||
| `atproto` | AT URI | `at://did:plc:zhbjlbmir5dganqhueg7y4i3/app.bsky.feed.post/3jt5hlibeol2i` |
|
||||
| `rss` | URL with guid fragment | `https://soapbox.pub/rss/feed.xml#https%3A%2F%2Fsoapbox.pub%2Fblog%2Fmostr-fediverse-nostr-bridge` |
|
||||
| `web` | URL | `https://twitter.com/jack/status/20` |
|
||||
|
||||
### Examples
|
||||
|
||||
ActivityPub object:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 1,
|
||||
"content": "I'm vegan btw",
|
||||
"tags": [
|
||||
[
|
||||
"proxy",
|
||||
"https://gleasonator.com/objects/8f6fac53-4f66-4c6e-ac7d-92e5e78c3e79",
|
||||
"activitypub"
|
||||
]
|
||||
],
|
||||
"pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
|
||||
"created_at": 1691091365,
|
||||
"id": "55920b758b9c7b17854b6e3d44e6a02a83d1cb49e1227e75a30426dea94d4cb2",
|
||||
"sig": "a72f12c08f18e85d98fb92ae89e2fe63e48b8864c5e10fbdd5335f3c9f936397a6b0a7350efe251f8168b1601d7012d4a6d0ee6eec958067cf22a14f5a5ea579"
|
||||
}
|
||||
```
|
||||
|
||||
### See also
|
||||
|
||||
- [FEP-fffd: Proxy Objects](https://codeberg.org/fediverse/fep/src/branch/main/fep/fffd/fep-fffd.md)
|
||||
- [Mostr bridge](https://mostr.pub/)
|
||||
209
52.md
Normal file
209
52.md
Normal file
@@ -0,0 +1,209 @@
|
||||
NIP-52
|
||||
======
|
||||
|
||||
Calendar Events
|
||||
---------------
|
||||
|
||||
`draft` `optional` `author:tyiu`
|
||||
|
||||
This specification defines calendar events representing an occurrence at a specific moment or between moments. These calendar events are replaceable and referenceable per [NIP-33](33.md) and deletable per [NIP-09](09.md).
|
||||
|
||||
Unlike the term `calendar event` specific to this NIP, the term `event` is used broadly in all the NIPs to describe any Nostr event. The distinction is being made here to discern between the two terms.
|
||||
|
||||
## Calendar Events
|
||||
|
||||
There are two types of calendar events represented by different kinds: date-based and time-based calendar events. Calendar events are not required to be part of a [calendar](#calendar).
|
||||
|
||||
### Date-Based Calendar Event
|
||||
|
||||
This kind of calendar event starts on a date and ends before a different date in the future. Its use is appropriate for all-day or multi-day events where time and time zone hold no significance. e.g., anniversary, public holidays, vacation days.
|
||||
|
||||
#### Format
|
||||
|
||||
The format uses a parameterized replaceable event kind `31922`.
|
||||
|
||||
The `.content` of these events is optional and should be a detailed description of the calendar event.
|
||||
|
||||
The list of tags are as follows:
|
||||
* `d` (required) universally unique identifier (UUID). Generated by the client creating the calendar event.
|
||||
* `name` (required) name of the calendar event
|
||||
* `start` (required) inclusive start date in ISO 8601 format (YYYY-MM-DD). Must be less than `end`, if it exists.
|
||||
* `end` (optional) exclusive end date in ISO 8601 format (YYYY-MM-DD). If omitted, the calendar event ends on the same date as `start`.
|
||||
* `location` (optional) location of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call
|
||||
* `g` (optional) [geohash](https://en.wikipedia.org/wiki/Geohash) to associate calendar event with a searchable physical location as suggested as an example by [NIP-12](12.md)
|
||||
* `p` (optional, repeated) 32-bytes hex pubkey of a participant, optional recommended relay URL, and participant's role in the meeting
|
||||
* `t` (optional, repeated) hashtag to categorize calendar event
|
||||
* `r` (optional, repeated) references / links to web pages, documents, video calls, recorded videos, etc.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": <32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>,
|
||||
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
|
||||
"created_at": <Unix timestamp in seconds>,
|
||||
"kind": "31922",
|
||||
"content": "<description of calendar event>",
|
||||
"tags": [
|
||||
["d", "<UUID>"],
|
||||
|
||||
["name", "<name of calendar event>"],
|
||||
|
||||
// Dates
|
||||
["start", "<YYYY-MM-DD>"],
|
||||
["end", "<YYYY-MM-DD>"],
|
||||
|
||||
// Location
|
||||
["location", "<location>"],
|
||||
["g", "<geohash>"],
|
||||
|
||||
// Participants
|
||||
["p", "<32-bytes hex of a pubkey>", "<optional recommended relay URL>", "<role>"],
|
||||
["p", "<32-bytes hex of a pubkey>", "<optional recommended relay URL>", "<role>"],
|
||||
|
||||
// Hashtags
|
||||
["t", "<tag>"],
|
||||
["t", "<tag>"],
|
||||
|
||||
// Reference links
|
||||
["r", "<url>"],
|
||||
["r", "<url>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Time-Based Calendar Event
|
||||
|
||||
This kind of calendar event spans between a start time and end time.
|
||||
|
||||
#### Format
|
||||
|
||||
The format uses a parameterized replaceable event kind `31923`.
|
||||
|
||||
The `.content` of these events is optional and should be a detailed description of the calendar event.
|
||||
|
||||
The list of tags are as follows:
|
||||
* `d` (required) universally unique identifier (UUID). Generated by the client creating the calendar event.
|
||||
* `name` (required) name of the calendar event
|
||||
* `start` (required) inclusive start Unix timestamp in seconds. Must be less than `end`, if it exists.
|
||||
* `end` (optional) exclusive end Unix timestamp in seconds. If omitted, the calendar event ends instantaneously.
|
||||
* `start_tzid` (optional) time zone of the start timestamp, as defined by the IANA Time Zone Database. e.g., `America/Costa_Rica`
|
||||
* `end_tzid` (optional) time zone of the end timestamp, as defined by the IANA Time Zone Database. e.g., `America/Costa_Rica`. If omitted and `start_tzid` is provided, the time zone of the end timestamp is the same as the start timestamp.
|
||||
* `location` (optional) location of the calendar event. e.g. address, GPS coordinates, meeting room name, link to video call
|
||||
* `g` (optional) [geohash](https://en.wikipedia.org/wiki/Geohash) to associate calendar event with a searchable physical location as suggested as an example by [NIP-12](12.md)
|
||||
* `p` (optional, repeated) 32-bytes hex pubkey of a participant, optional recommended relay URL, and participant's role in the meeting
|
||||
* `t` (optional, repeated) hashtag to categorize calendar event
|
||||
* `r` (optional, repeated) references / links to web pages, documents, video calls, recorded videos, etc.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": <32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>,
|
||||
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
|
||||
"created_at": <Unix timestamp in seconds>,
|
||||
"kind": "31923",
|
||||
"content": "<description of calendar event>",
|
||||
"tags": [
|
||||
["d", "<UUID>"],
|
||||
|
||||
["name", "<name of calendar event>"],
|
||||
|
||||
// Timestamps
|
||||
["start", "<Unix timestamp in seconds>"],
|
||||
["end", "<Unix timestamp in seconds>"],
|
||||
|
||||
["start_tzid", "<IANA Time Zone Database identifier>"],
|
||||
["end_tzid", "<IANA Time Zone Database identifier>"],
|
||||
|
||||
// Location
|
||||
["location", "<location>"],
|
||||
["g", "<geohash>"],
|
||||
|
||||
// Participants
|
||||
["p", "<32-bytes hex of a pubkey>", "<optional recommended relay URL>", "<role>"],
|
||||
["p", "<32-bytes hex of a pubkey>", "<optional recommended relay URL>", "<role>"],
|
||||
|
||||
// Hashtags
|
||||
["t", "<tag>"],
|
||||
["t", "<tag>"],
|
||||
|
||||
// Reference links
|
||||
["r", "<url>"],
|
||||
["r", "<url>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Calendar
|
||||
|
||||
A calendar is a collection of calendar events, represented as a custom replaceable list event using kind `31924`. A user can have multiple calendars. One may create a calendar to segment calendar events for specific purposes. e.g., personal, work, travel, meetups, and conferences.
|
||||
|
||||
### Format
|
||||
|
||||
The format uses a custom replaceable list of kind `31924` with a list of tags as described below:
|
||||
* `d` (required) calendar name
|
||||
* `a` (repeated) reference tag to kind `31922` or `31923` calendar event being responded to per [NIP-33](33.md)
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 31924,
|
||||
"tags": [
|
||||
["d", "<calendar name>"],
|
||||
["a", "<31922 or 31923>:<calendar event author pubkey>:<d-identifier of calendar event>", "<optional relay url>"],
|
||||
["a", "<31922 or 31923>:<calendar event author pubkey>:<d-identifier of calendar event>", "<optional relay url>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Calendar Event RSVP
|
||||
|
||||
A calendar event RSVP is a response to a calendar event to indicate a user's attendance intention.
|
||||
|
||||
If a calendar event tags a pubkey, that can be interpreted as the calendar event creator inviting that user to attend. Clients MAY choose to prompt the user to RSVP for the calendar event.
|
||||
|
||||
Any user may RSVP, even if they were not tagged on the calendar event. Clients MAY choose to prompt the calendar event creator to invite the user who RSVP'd. Clients also MAY choose to ignore these RSVPs.
|
||||
|
||||
This NIP is intentionally not defining who is authorized to attend a calendar event if the user who RSVP'd has not been tagged. It is up to the calendar event creator to determine the semantics.
|
||||
|
||||
This NIP is also intentionally not defining what happens if a calendar event changes after an RSVP is submitted.
|
||||
|
||||
### Format
|
||||
|
||||
The format uses a parameterized replaceable event kind `31925`.
|
||||
|
||||
The `.content` of these events is optional and should be a free-form note that adds more context to this calendar event response.
|
||||
|
||||
The list of tags are as follows:
|
||||
* `a` (required) reference tag to kind `31922` or `31923` calendar event being responded to per [NIP-33](33.md)
|
||||
* `d` (required) universally unique identifier. Generated by the client creating the calendar event RSVP.
|
||||
* `L` (required) label namespace of `status` per [NIP-32](32.md)
|
||||
* `l` (required) label of `accepted`, `declined`, or `tentative` under the label namespace of `status` per [NIP-32](32.md). Determines attendance status to the referenced calendar event.
|
||||
* `L` (optional) label namespace of `freebusy` per [NIP-32](32.md). Exists if and only if corresponding `l` tag under the same label namespace exists.
|
||||
* `l` (optional) label of `free` or `busy` under the label namespace of `freebusy` per [NIP-32](32.md). Determines if the user would be free or busy for the duration of the calendar event. This tag must be omitted or ignored if the `status` label is set to `declined`. Exists if and only if corresponding `l` tag under the same label namespace exists.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": <32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>,
|
||||
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
|
||||
"created_at": <Unix timestamp in seconds>,
|
||||
"kind": "31925",
|
||||
"content": "<note>",
|
||||
"tags": [
|
||||
["a", "<31922 or 31923>:<calendar event author pubkey>:<d-identifier of calendar event>", "<optional relay url>"],
|
||||
["d", "<UUID>"],
|
||||
["L", "status"],
|
||||
["l", "<accepted/declined/tentative>", "status"],
|
||||
["L", "freebusy"],
|
||||
["l", "<free/busy>", "freebusy"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Unsolved Limitations
|
||||
|
||||
* No private events
|
||||
|
||||
## Intentionally Unsupported Scenarios
|
||||
|
||||
### Recurring Calendar Events
|
||||
|
||||
Recurring calendar events come with a lot of complexity, making it difficult for software and humans to deal with. This complexity includes time zone differences between invitees, daylight savings, leap years, multiple calendar systems, one-off changes in schedule or other metadata, etc.
|
||||
|
||||
This NIP intentionally omits support for recurring calendar events and pushes that complexity up to clients to manually implement if they desire. i.e., individual calendar events with duplicated metadata represent recurring calendar events.
|
||||
125
53.md
Normal file
125
53.md
Normal file
@@ -0,0 +1,125 @@
|
||||
NIP-53
|
||||
======
|
||||
|
||||
Live Activities
|
||||
---------------
|
||||
|
||||
`draft` `optional` `author:vitorpamplona` `author:v0l`
|
||||
|
||||
## Abstract
|
||||
|
||||
Service providers want to offer live activities to the Nostr network in such a way that participants can easily logged and queried by clients. This NIP describes a general framework to advertise the involvement of pubkeys in such live activities.
|
||||
|
||||
# Live Event
|
||||
|
||||
A special event with `kind:30311` "Live Event" is defined as a [NIP-33: Parameterized Replaceable Events](33.md) of public `p` tags. Each `p` tag SHOULD have a **displayable** marker name for the current role (e.g. `Host`, `Speaker`, `Participant`) of the user in the event and the relay information MAY be empty. This event will be constantly updated as participants join and leave the activity.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
{
|
||||
"kind": 30311,
|
||||
"tags": [
|
||||
["d", "<unique identifier>"],
|
||||
["title", "<name of the event>"],
|
||||
["summary", "<description>"],
|
||||
["image", "<preview image url>"],
|
||||
["t", "hashtag"]
|
||||
["streaming", "<url>"],
|
||||
["recording", "<url>"], // used to place the edited video once the activity is over
|
||||
["starts", "<unix timestamp in seconds>"],
|
||||
["ends", "<unix timestamp in seconds>"],
|
||||
["status", "<planned, live, ended>"],
|
||||
["current_participants", "<number>"],
|
||||
["total_participants", "<number>"],
|
||||
["p", "91cf9..4e5ca", "wss://provider1.com/", "Host", "<proof>"],
|
||||
["p", "14aeb..8dad4", "wss://provider2.com/nostr", "Speaker"],
|
||||
["p", "612ae..e610f", "ws://provider3.com/ws", "Participant"],
|
||||
["relays", "wss://one.com", "wss://two.com", ...]
|
||||
],
|
||||
"content": "",
|
||||
...other fields
|
||||
}
|
||||
```
|
||||
|
||||
A distinct `d` tag should be used for each activity. All other tags are optional.
|
||||
|
||||
Providers SHOULD keep the participant list small (e.g. under 1000 users) and, when limits are reached, Providers SHOULD select which participants get named in the event. Clients should not expect a comprehensive list. Once the activity ends, the event can be deleted or updated to summarize the activity and provide async content (e.g. recording of the event).
|
||||
|
||||
Clients are expected to subscribe to `kind:30311` events in general or for given follow lists and statuses. Clients MAY display participants' roles in activities as well as access points to join the activity.
|
||||
|
||||
Live Activity management clients are expected to constantly update `kind:30311` during the event. Clients MAY choose to consider `status=live` events after 1hr without any update as `ended`. The `starts` and `ends` timestamp SHOULD be updated when the status changes to and from `live`
|
||||
|
||||
The activity MUST be linked to using the NIP-19 naddr code along with the "a" tag (see [NIP-33](33.md) and [NIP-19](19.md)).
|
||||
|
||||
## Proof of Agreement to Participate
|
||||
|
||||
Event owners can add proof as the 5th term in each `p` tag to clarify the participant's agreement in joining the event. The proof is a signed SHA256 of the complete `a` Tag of the event (`kind:pubkey:dTag`) by each `p`'s private key, encoded in hex.
|
||||
|
||||
Clients MAY only display participants if the proof is available or MAY display participants as "invited" if the proof is not available.
|
||||
|
||||
This feature is important to avoid malicious event owners adding large account holders to the event, without their knowledge, to lure their followers into the malicious owner's trap.
|
||||
|
||||
# Live Chat Message
|
||||
|
||||
Event `kind:1311` is live chat's channel message. Clients MUST include the `a` tag of the activity with a `root` marker. Other Kind-1 tags such as `reply` and `mention` can also be used.
|
||||
|
||||
```js
|
||||
{
|
||||
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
|
||||
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
|
||||
"created_at": "<Unix timestamp in seconds>",
|
||||
"kind": 1311,
|
||||
"tags": [
|
||||
["a", "30311:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>", "root"],
|
||||
],
|
||||
"content": "Zaps to live streams is beautiful."
|
||||
}
|
||||
```
|
||||
|
||||
# Use Cases
|
||||
|
||||
Common use cases include meeting rooms/workshops, watch-together activities, or event spaces, such as [live.snort.social](https://live.snort.social) and [nostrnests.com](https://nostrnests.com).
|
||||
|
||||
# Example
|
||||
|
||||
Live Streaming
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "57f28dbc264990e2c61e80a883862f7c114019804208b14da0bff81371e484d2",
|
||||
"pubkey": "1597246ac22f7d1375041054f2a4986bd971d8d196d7997e48973263ac9879ec",
|
||||
"created_at": 1687182672,
|
||||
"kind": 30311,
|
||||
"tags": [
|
||||
["d", "demo-cf-stream"],
|
||||
["title", "Adult Swim Metalocalypse"],
|
||||
["summary", "Live stream from IPTV-ORG collection"],
|
||||
["streaming", "https://adultswim-vodlive.cdn.turner.com/live/metalocalypse/stream.m3u8"],
|
||||
["starts", "1687182672"]
|
||||
["status", "live"],
|
||||
["t", "animation"],
|
||||
["t", "iptv"],
|
||||
["image", "https://i.imgur.com/CaKq6Mt.png"]
|
||||
],
|
||||
"content": "",
|
||||
"sig": "5bc7a60f5688effa5287244a24768cbe0dcd854436090abc3bef172f7f5db1410af4277508dbafc4f70a754a891c90ce3b966a7bc47e7c1eb71ff57640f3d389"
|
||||
}
|
||||
```
|
||||
|
||||
Live Streaming chat message
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "97aa81798ee6c5637f7b21a411f89e10244e195aa91cb341bf49f718e36c8188",
|
||||
"pubkey": "3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24",
|
||||
"created_at": 1687286726,
|
||||
"kind": 1311,
|
||||
"tags": [
|
||||
["a", "30311:1597246ac22f7d1375041054f2a4986bd971d8d196d7997e48973263ac9879ec:demo-cf-stream", "", "root"]
|
||||
],
|
||||
"content": "Zaps to live streams is beautiful.",
|
||||
"sig": "997f62ddfc0827c121043074d50cfce7a528e978c575722748629a4137c45b75bdbc84170bedc723ef0a5a4c3daebf1fef2e93f5e2ddb98e5d685d022c30b622"
|
||||
}
|
||||
````
|
||||
|
||||
20
56.md
20
56.md
@@ -10,7 +10,7 @@ Reporting
|
||||
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
|
||||
The `content` MAY contain additional information submitted by the entity
|
||||
reporting the content.
|
||||
|
||||
Tags
|
||||
@@ -32,6 +32,9 @@ being reported, which consists of the following report types:
|
||||
|
||||
Some report tags only make sense for profile reports, such as `impersonation`
|
||||
|
||||
`l` and `L` tags MAY be also be used as defined in [NIP-32](32.md) to support
|
||||
further qualification and querying.
|
||||
|
||||
Example events
|
||||
--------------
|
||||
|
||||
@@ -39,7 +42,9 @@ Example events
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
[ "p", <pubkey>, "nudity"]
|
||||
["p", <pubkey>, "nudity"],
|
||||
["L", "social.nos.ontology"],
|
||||
["l", "NS-nud", "social.nos.ontology"]
|
||||
],
|
||||
"content": "",
|
||||
...
|
||||
@@ -48,8 +53,8 @@ Example events
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
[ "e", <eventId>, "illegal"],
|
||||
[ "p", <pubkey>]
|
||||
["e", <eventId>, "illegal"],
|
||||
["p", <pubkey>]
|
||||
],
|
||||
"content": "He's insulting the king!",
|
||||
...
|
||||
@@ -58,10 +63,9 @@ Example events
|
||||
{
|
||||
"kind": 1984,
|
||||
"tags": [
|
||||
[ "p", <impersonator pubkey>, "impersonation"],
|
||||
[ "p", <victim pubkey>]
|
||||
["p", <impersonator pubkey>, "impersonation"]
|
||||
],
|
||||
"content": "Profile is imitating #[1]",
|
||||
"content": "Profile is impersonating nostr:<victim bech32 pubkey>",
|
||||
...
|
||||
}
|
||||
```
|
||||
@@ -70,7 +74,7 @@ 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,
|
||||
choose to. For instance, if 3+ of your friends report a profile for `nudity`,
|
||||
clients can have an option to automatically blur photos from said account.
|
||||
|
||||
|
||||
|
||||
56
57.md
56
57.md
@@ -6,21 +6,21 @@ Lightning Zaps
|
||||
|
||||
`draft` `optional` `author:jb55` `author:kieran`
|
||||
|
||||
This NIP defines two new event types for recording lightning payments between users. `9734` is a `zap request`, representing a payer's request to a recipient's lightning wallet for an invoice. `9735` is a `zap receipt`, representing the confirmation by the recipient's lightning wallet that the invoice issued in response to a zap request has been paid.
|
||||
This NIP defines two new event types for recording lightning payments between users. `9734` is a `zap request`, representing a payer's request to a recipient's lightning wallet for an invoice. `9735` is a `zap receipt`, representing the confirmation by the recipient's lightning wallet that the invoice issued in response to a `zap request` has been paid.
|
||||
|
||||
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.
|
||||
|
||||
## Protocol flow
|
||||
|
||||
1. Client calculates a recipient's lnurl pay request url from the `zap` tag on the event being zapped (see Appendix G), or by decoding their lud06 or lud16 field on their profile according to the [lnurl specifications](https://github.com/lnurl/luds). The client MUST send a GET request to this url and parse the response. If `allowsNostr` exists and it is `true`, and if `nostrPubkey` exists and is a valid BIP 340 public key in hex, the client should associate this information with the user, along with the response's `callback`, `minSendable`, and `maxSendable` values.
|
||||
2. Clients may choose to display a lightning zap button on each post or on a user's profile. If the user's lnurl pay request endpoint supports nostr, the client SHOULD use this NIP to request a zap receipt rather than a normal lnurl invoice.
|
||||
2. Clients may choose to display a lightning zap button on each post or on a user's profile. If the user's lnurl pay request endpoint supports nostr, the client SHOULD use this NIP to request a `zap receipt` rather than a normal lnurl invoice.
|
||||
3. When a user (the "sender") indicates they want to send a zap to another user (the "recipient"), the client should create a `zap request` event as described in Appendix A of this NIP and sign it.
|
||||
4. Instead of publishing the `zap request`, the `9734` event should instead be sent to the `callback` url received from the lnurl pay endpoint for the recipient using a GET request. See Appendix B for details and an example.
|
||||
5. The recipient's lnurl server will receive this request and validate it. See Appendix C for details on how to properly configure an lnurl server to support zaps, and Appendix D for details on how to validate the `nostr` query parameter.
|
||||
6. If the request is valid, the server should fetch a description hash invoice where the description is this note and this note only. No additional lnurl metadata is included in the description. This will be returned in the response according to [LUD06](https://github.com/lnurl/luds/blob/luds/06.md).
|
||||
5. The recipient's lnurl server will receive this `zap request` and validate it. See Appendix C for details on how to properly configure an lnurl server to support zaps, and Appendix D for details on how to validate the `nostr` query parameter.
|
||||
6. If the `zap request` is valid, the server should fetch a description hash invoice where the description is this `zap request` note and this note only. No additional lnurl metadata is included in the description. This will be returned in the response according to [LUD06](https://github.com/lnurl/luds/blob/luds/06.md).
|
||||
7. On receiving the invoice, the client MAY pay it or pass it to an app that can pay the invoice.
|
||||
8. Once the invoice is paid, the recipient's lnurl server MUST generate a `zap receipt` as described in Appendix E, and publish it to the `relays` specified in the `zap request`.
|
||||
9. Clients MAY fetch zap notes on posts and profiles, but MUST authorize their validity as described in Appendix F. 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.
|
||||
9. Clients MAY fetch `zap receipt`s on posts and profiles, but MUST authorize their validity as described in Appendix F. 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 receipt` to show "zap authorized by ..." but this is optional.
|
||||
|
||||
## Reference and examples
|
||||
|
||||
@@ -60,10 +60,10 @@ Example:
|
||||
|
||||
### Appendix B: Zap Request HTTP Request
|
||||
|
||||
A signed zap request event is not published, but is instead sent using a HTTP GET request to the recipient's `callback` url, which was provided by the recipient's lnurl pay endpoint. This request should have the following query parameters defined:
|
||||
A signed `zap request` event is not published, but is instead sent using a HTTP GET request to the recipient's `callback` url, which was provided by the recipient's lnurl pay endpoint. This request should have the following query parameters defined:
|
||||
|
||||
- `amount` is the amount in _millisats_ the sender intends to pay
|
||||
- `nostr` is the `9734` zap request event, JSON encoded then URI encoded
|
||||
- `nostr` is the `9734` `zap request` event, JSON encoded then URI encoded
|
||||
- `lnurl` is the lnurl pay url of the recipient, encoded using bech32 with the prefix `lnurl`
|
||||
|
||||
This request should return a JSON response with a `pr` key, which is the invoice the sender must pay to finalize his zap. Here is an example flow:
|
||||
@@ -97,18 +97,18 @@ const {pr: invoice} = await fetchJson(`${callback}?amount=${amount}&nostr=${even
|
||||
|
||||
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 your server will use to sign `zap receipt` events. Clients will use this to validate zap receipts.
|
||||
1. Add a `nostrPubkey` to the lnurl-pay static endpoint `/.well-known/lnurlp/<user>`, where `nostrPubkey` is the nostr pubkey your server will use to sign `zap receipt` events. Clients will use this to validate `zap receipt`s.
|
||||
2. Add an `allowsNostr` field and set it to true.
|
||||
|
||||
### Appendix D: LNURL Server Zap Request Validation
|
||||
|
||||
When a client sends a zap request event to a server's lnurl-pay callback URL, there will be a `nostr` query parameter where the contents of the event are URI- and JSON-encoded. If present, the zap request event must be validated in the following ways:
|
||||
When a client sends a `zap request` event to a server's lnurl-pay callback URL, there will be a `nostr` query parameter whose value is that event which is URI- and JSON-encoded. If present, the `zap request` event must be validated in the following ways:
|
||||
|
||||
1. It MUST have a valid nostr signature
|
||||
2. It MUST have tags
|
||||
3. It MUST have only one `p` tag
|
||||
4. It MUST have 0 or 1 `e` tags
|
||||
5. There should be a `relays` tag with the relays to send the `zap` note to.
|
||||
5. There should be a `relays` tag with the relays to send the `zap receipt` to.
|
||||
6. If there is an `amount` tag, it MUST be equal to the `amount` query parameter.
|
||||
7. If there is an `a` tag, it MUST be a valid NIP-33 event coordinate
|
||||
|
||||
@@ -116,29 +116,29 @@ The event MUST then be stored for use later, when the invoice is paid.
|
||||
|
||||
### Appendix E: Zap Receipt Event
|
||||
|
||||
A `zap receipt` is created by a lightning node when an invoice generated by a `zap request` is paid. Zap receipts are only created when the invoice description (committed to the description hash) contains a zap request note.
|
||||
A `zap receipt` is created by a lightning node when an invoice generated by a `zap request` is paid. `Zap receipt`s are only created when the invoice description (committed to the description hash) contains a `zap request` 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 event. This SHOULD be validated based on the requirements in Appendix D, either when it is received, or before the invoice is paid.
|
||||
3. Create a nostr event of kind `9735` as described below, and publish it to the `relays` declared in the zap request.
|
||||
3. Create a nostr event of kind `9735` as described below, and publish it to the `relays` declared in the `zap request`.
|
||||
|
||||
The following should be true of the zap receipt event:
|
||||
The following should be true of the `zap receipt` event:
|
||||
|
||||
- The content SHOULD be empty.
|
||||
- The `content` SHOULD be empty.
|
||||
- The `created_at` date SHOULD be set to the invoice `paid_at` date for idempotency.
|
||||
- `tags` MUST include the `p` tag AND optional `e` tag from the zap request.
|
||||
- The zap receipt MUST have a `bolt11` tag containing the description hash bolt11 invoice.
|
||||
- The zap receipt MUST contain a `description` tag which is the JSON-encoded invoice description.
|
||||
- `tags` MUST include the `p` tag AND optional `e` tag from the `zap request`.
|
||||
- The `zap receipt` MUST have a `bolt11` tag containing the description hash bolt11 invoice.
|
||||
- The `zap receipt` MUST contain a `description` tag which is the JSON-encoded invoice description.
|
||||
- `SHA256(description)` MUST match the description hash in the bolt11 invoice.
|
||||
- The zap receipt MAY contain a `preimage` tag 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 receipt for the legitimacy of the payment.
|
||||
- The `zap receipt` MAY contain a `preimage` tag 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 receipt` for the legitimacy of the payment.
|
||||
|
||||
The zap receipt is not a proof of payment, all it proves is that some nostr user fetched an invoice. The existence of the zap receipt implies the invoice as paid, but it could be a lie given a rogue implementation.
|
||||
The `zap receipt` is not a proof of payment, all it proves is that some nostr user fetched an invoice. The existence of the `zap receipt` implies the invoice as paid, but it could be a lie given a rogue implementation.
|
||||
|
||||
A reference implementation for a zap-enabled lnurl server can be found [here](https://github.com/jb55/cln-nostr-zapper).
|
||||
|
||||
Example zap receipt:
|
||||
Example `zap receipt`:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -160,24 +160,28 @@ Example zap receipt:
|
||||
|
||||
### Appendix F: Validating Zap Receipts
|
||||
|
||||
A client can retrieve `zap receipts` on events and pubkeys using a NIP-01 filter, for example `{"kinds": [9735], "#e": [...]}`. Zaps MUST be validated using the following steps:
|
||||
A client can retrieve `zap receipt`s on events and pubkeys using a NIP-01 filter, for example `{"kinds": [9735], "#e": [...]}`. Zaps MUST be validated using the following steps:
|
||||
|
||||
- The `zap receipt` event's `pubkey` MUST be the same as the recipient's lnurl provider's `nostrPubkey` (retrieved in step 1 of the protocol flow).
|
||||
- The `invoiceAmount` contained in the `bolt11` tag of the `zap receipt` MUST equal the `amount` tag of the `zap request` (if present).
|
||||
- The `lnurl` tag of the `zap request` (if present) SHOULD equal the recipient's `lnurl`.
|
||||
|
||||
### Appendix G: `zap` tag on zapped event
|
||||
### Appendix G: `zap` tag on other events
|
||||
|
||||
When an event includes a `zap` tag, clients SHOULD calculate the lnurl pay request based on it's value instead of the profile's field. An optional third argument on the tag specifies the type of value, either `lud06` or `lud16`.
|
||||
When an event includes one or more `zap` tags, clients wishing to zap it SHOULD calculate the lnurl pay request based on the tags value instead of the event author's profile field. The tag's second argument is the `hex` string of the receiver's pub key and the third argument is the relay to download the receiver's metadata (Kind-0). An optional fourth parameter specifies the weight (a generalization of a percentage) assigned to the respective receiver. Clients should parse all weights, calculate a sum, and then a percentage to each receiver. If weights are not present, CLIENTS should equally divide the zap amount to all receivers. If weights are only partially present, receivers without a weight should not be zapped (`weight = 0`).
|
||||
|
||||
```json
|
||||
```js
|
||||
{
|
||||
"tags": [
|
||||
[ "zap", "pablo@f7z.io", "lud16" ]
|
||||
[ "zap", "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2", "wss://nostr.oxtr.dev", "1" ], // 25%
|
||||
[ "zap", "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52", "wss://nostr.wine/", "1" ], // 25%
|
||||
[ "zap", "460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", "wss://nos.lol/", "2" ] // 50%
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Clients MAY display the zap split configuration in the note.
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
93
65.md
93
65.md
@@ -4,63 +4,13 @@ NIP-65
|
||||
Relay List Metadata
|
||||
-------------------
|
||||
|
||||
`draft` `optional` `author:mikedilger`
|
||||
`draft` `optional` `author:mikedilger` `author:vitorpamplona`
|
||||
|
||||
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.
|
||||
Defines a replaceable event using `kind:10002` to advertise preferred relays for discovering a user's content and receiving fresh content from others.
|
||||
|
||||
The primary purpose of this relay list is to advertise to others, not for configuring one's client.
|
||||
The event MUST include a list of `r` tags with relay URIs and a `read` or `write` marker. If the marker is omitted, the relay is used for both purposes.
|
||||
|
||||
The content is not used and SHOULD be an empty string.
|
||||
|
||||
The `r` tags can have a second parameter as either `read` or `write`. If it is omitted, it means the author uses the relay for both purposes.
|
||||
|
||||
Clients SHOULD, as with all replaceable events, use only the most recent kind-10002 event they can find.
|
||||
|
||||
### The meaning of read and write
|
||||
|
||||
Write relays are for events that are intended for anybody (e.g. your followers). Read relays are for events that address a particular person.
|
||||
|
||||
Clients SHOULD write feed-related events created by their user to their user's write relays.
|
||||
|
||||
Clients SHOULD read feed-related events created by another from at least some of that other person's write relays. Explicitly, they SHOULD NOT expect them to be available at their user's read relays. It SHOULD NOT be presumed that the user's read relays coincide with the write relays of the people the user follows.
|
||||
|
||||
Clients SHOULD read events that tag their user from their user's read relays.
|
||||
|
||||
Clients SHOULD write events that tag a person to at least some of that person's read relays. Explicitly, they SHOULD NOT expect that person will pick them up from their user's write relays. It SHOULD NOT be presumed that the user's write relays coincide with the read relays of the person being tagged.
|
||||
|
||||
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.
|
||||
|
||||
### 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, 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 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 "Relay List Metadata". For example, an author may want to reply to someone without all of their followers watching.
|
||||
|
||||
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
|
||||
- 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
|
||||
The `.content` is not used.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -74,3 +24,38 @@ Even though this is user related metadata, it is a separate event from kind `0`
|
||||
"content": "",
|
||||
...other fields
|
||||
```
|
||||
|
||||
This NIP doesn't fully replace relay lists that are designed to configure a client's usage of relays (such as `kind:3` style relay lists). Clients MAY use other relay lists in situations where a `kind:10002` relay list cannot be found.
|
||||
|
||||
## When to Use Read and Write
|
||||
|
||||
When seeking events **from** a user, Clients SHOULD use the WRITE relays of the user's `kind:10002`
|
||||
|
||||
When seeking events **about** a user, where the user was tagged, Clients SHOULD use the READ relays of the user's `kind:10002`
|
||||
|
||||
When broadcasting an event, Clients SHOULD:
|
||||
|
||||
- Broadcast the event to the WRITE relays of the author
|
||||
- Broadcast the event all READ relays of each tagged user.
|
||||
|
||||
## Motivation
|
||||
|
||||
The old model of using a fixed relay list per user centralizes in large relay operators:
|
||||
|
||||
- Most users submit their posts to the same highly popular relays, aiming to achieve greater visibility among a broader audience.
|
||||
- Many users are pulling events from a large number of relays in order to get more data at the expense of duplication
|
||||
- Events are being copied between relays, oftentimes to many different relays
|
||||
|
||||
This NIP allows Clients to connect directly with the most up-to-date relay set from each individual user, eliminating the need of broadcasting events to popular relays.
|
||||
|
||||
## Final Considerations
|
||||
|
||||
1. Clients SHOULD guide users to keep `kind:10002` lists small (2-4 relays).
|
||||
|
||||
2. Clients SHOULD spread an author's `kind:10002` events to as many relays as viable.
|
||||
|
||||
3. `kind:10002` events should primarily be used to advertise the user's preferred relays to others. A user's own client may use other heuristics for selecting relays for fetching data.
|
||||
|
||||
4. DMs SHOULD only be broadcasted to the author's WRITE relays and to the receiver's READ relays to keep maximum privacy.
|
||||
|
||||
5. If a relay signals support for this NIP in their [NIP-11](11.md) document that means they're willing to accept kind 10002 events from a broad range of users, not only their paying customers or whitelisted group.
|
||||
|
||||
101
72.md
Normal file
101
72.md
Normal file
@@ -0,0 +1,101 @@
|
||||
NIP-72
|
||||
======
|
||||
|
||||
Moderated Communities (Reddit Style)
|
||||
------------------------------------
|
||||
|
||||
`draft` `optional` `author:vitorpamplona` `author:arthurfranca`
|
||||
|
||||
The goal of this NIP is to create moderator-approved public communities around a topic. It defines the replaceable event `kind:34550` to define the community and the current list of moderators/administrators. Users that want to post into the community, simply tag any Nostr event with the community's `a` tag (See [NIP-33](33.md)). Moderators issue an approval event `kind:4550` that links the community with the new post.
|
||||
|
||||
# Community Definition
|
||||
|
||||
`Kind:34550` SHOULD include any field that helps define the community and the set of moderators. `relay` tags MAY be used to describe the preferred relay to download requests and approvals.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
|
||||
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
|
||||
"created_at": <Unix timestamp in seconds>,
|
||||
"kind": 34550,
|
||||
"tags": [
|
||||
["d", "<Community name>"],
|
||||
["description", "<Community description>"],
|
||||
["image", "<Community image url>", "<Width>x<Height>"],
|
||||
|
||||
//.. other tags relevant to defining the community
|
||||
|
||||
// moderators
|
||||
["p", "<32-bytes hex of a pubkey1>", "<optional recommended relay URL>", "moderator"],
|
||||
["p", "<32-bytes hex of a pubkey2>", "<optional recommended relay URL>", "moderator"],
|
||||
["p", "<32-bytes hex of a pubkey3>", "<optional recommended relay URL>", "moderator"],
|
||||
|
||||
// relays used by the community (w/optional marker)
|
||||
["relay", "<relay hosting author kind 0>", "author"],
|
||||
["relay", "<relay where to send and receive requests>", "requests"],
|
||||
["relay", "<relay where to send and receive approvals>", "approvals"],
|
||||
["relay", "<relay where to post requests to and fetch approvals from>"]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
# New Post Request
|
||||
|
||||
Any Nostr event can be a post request. Clients MUST add the community's `a` tag to the new post event in order to be presented for the moderator's approval.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
|
||||
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
|
||||
"created_at": <Unix timestamp in seconds>,
|
||||
"kind": 1,
|
||||
"tags": [
|
||||
["a", "34550:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>"],
|
||||
],
|
||||
"content": "<My content>"
|
||||
}
|
||||
```
|
||||
|
||||
Community management clients MAY filter all mentions to a given `kind:34550` event and request moderators to approve each submission. Moderators MAY delete his/her approval of a post at any time using event deletions (See [NIP-09](09.md)).
|
||||
|
||||
# Post Approval by moderators
|
||||
|
||||
The post-approval event MUST include `a` tags of the communities the moderator is posting into (one or more), the `e` tag of the post and `p` tag of the author of the post (for approval notifications). The event SHOULD also include the stringified `post request` event inside the `.content` ([NIP-18-style](18.md)) and a `k` tag with the original post's event kind to allow filtering of approved posts by kind.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "<32-bytes lowercase hex-encoded SHA-256 of the the serialized event data>",
|
||||
"pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>",
|
||||
"created_at": <Unix timestamp in seconds>,
|
||||
"kind": 4550,
|
||||
"tags": [
|
||||
["a", "34550:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>"],
|
||||
["e", "<Post Request ID>", "<Optional relay url>"],
|
||||
["p", "<Post Request Author ID>", "<Optional relay url>"],
|
||||
["k", "<New Post Request kind>"],
|
||||
],
|
||||
"content": "<New Post Request JSON>"
|
||||
}
|
||||
```
|
||||
|
||||
It's recommended that multiple moderators approve posts to avoid deleting them from the community when a moderator is removed from the owner's list. In case the full list of moderators must be rotated, the new moderator set must sign new approvals for posts in the past or the community will restart. The owner can also periodically copy and re-sign of each moderator's approval events to make sure posts don't disappear with moderators.
|
||||
|
||||
Post Approvals of replaceable events can be created in three ways: (i) by tagging the replaceable event as an `e` tag if moderators want to approve each individual change to the repleceable event; (ii) by tagging the replaceable event as an `a` tag if the moderator authorizes the replaceable event author to make changes without additional approvals and (iii) by tagging the replaceable event with both its `e` and `a` tag which empowers clients to display the original and updated versions of the event, with appropriate remarks in the UI. Since relays are instructed to delete old versions of a replaceable event, the `.content` of an `e`-approval MUST have the specific version of the event or Clients might not be able to find that version of the content anywhere.
|
||||
|
||||
Clients SHOULD evaluate any non-`34550:*` `a` tag as posts to be included in all `34550:*` `a` tags.
|
||||
|
||||
# Displaying
|
||||
|
||||
Community clients SHOULD display posts that have been approved by at least 1 moderator or by the community owner.
|
||||
|
||||
The following filter displays the approved posts.
|
||||
|
||||
```js
|
||||
{
|
||||
"authors": ["<Author pubkey>", "<Moderator1 pubkey>", "<Moderator2 pubkey>", "<Moderator3 pubkey>", ...],
|
||||
"kinds": [4550],
|
||||
"#a": ["34550:<Community event author pubkey>:<d-identifier of the community>"],
|
||||
}
|
||||
```
|
||||
|
||||
Clients MAY hide approvals by blocked moderators at the user's request.
|
||||
116
89.md
Normal file
116
89.md
Normal file
@@ -0,0 +1,116 @@
|
||||
NIP-89
|
||||
======
|
||||
|
||||
Recommended Application Handlers
|
||||
--------------------------------
|
||||
|
||||
`draft` `optional` `author:pablof7z`
|
||||
|
||||
This NIP describes `kind:31989` and `kind:31990`: a way to discover applications that can handle unknown event-kinds.
|
||||
|
||||
## Rationale
|
||||
Nostr's discoverability and transparent event interaction is one of its most interesting/novel mechanics.
|
||||
This NIP provides a simple way for clients to discover applications that handle events of a specific kind to ensure smooth cross-client and cross-kind interactions.
|
||||
|
||||
### Parties involved
|
||||
There are three actors to this workflow:
|
||||
|
||||
* application that handles a specific event kind (note that an application doesn't necessarily need to be a distinct entity and it could just be the same pubkey as user A)
|
||||
* Publishes `kind:31990`, detailing how apps should redirect to it
|
||||
* user A, who recommends an app that handles a specific event kind
|
||||
* Publishes `kind:31989`
|
||||
* user B, who seeks a recommendation for an app that handles a specific event kind
|
||||
* Queries for `kind:31989` and, based on results, queries for `kind:31990`
|
||||
|
||||
# Events
|
||||
|
||||
## Recommendation event
|
||||
```json
|
||||
{
|
||||
"kind": 31989,
|
||||
"pubkey": <recommender-user-pubkey>,
|
||||
"tags": [
|
||||
[ "d", <supported-event-kind> ],
|
||||
[ "a", "31990:app1-pubkey:<d-identifier>", "wss://relay1", "ios" ],
|
||||
[ "a", "31990:app2-pubkey:<d-identifier>", "wss://relay2", "web" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `d` tag in `kind:31989` is the supported event kind this event is recommending.
|
||||
|
||||
Multiple `a` tags can appear on the same `kind:31989`.
|
||||
|
||||
The second value of the tag SHOULD be a relay hint.
|
||||
The third value of the tag SHOULD be the platform where this recommendation might apply.
|
||||
|
||||
## Handler information
|
||||
```json
|
||||
{
|
||||
"kind": 31990,
|
||||
"pubkey": <pubkey>,
|
||||
"content": "<optional-kind:0-style-metadata>",
|
||||
"tags": [
|
||||
[ "d", <random-id> ],
|
||||
[ "k", <supported-event-kind> ],
|
||||
[ "web", "https://..../a/<bech32>", "nevent" ],
|
||||
[ "web", "https://..../p/<bech32>", "nprofile" ],
|
||||
[ "web", "https://..../e/<bech32>" ],
|
||||
[ "ios", ".../<bech32>" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
* `content` is an optional `set_metadata`-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the `kind:31990` is not an application. If `content` is empty, the `kind:0` of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.)
|
||||
|
||||
* `k` tags' value is the event kind that is supported by this `kind:31990`.
|
||||
Using a `k` tag(s) (instead of having the kind onf the NIP-33 `d` tag) provides:
|
||||
* Multiple `k` tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same.
|
||||
* The same pubkey can have multiple events with different apps that handle the same event kind.
|
||||
|
||||
* `bech32` in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application.
|
||||
|
||||
Multiple tags might be registered by the app, following NIP-19 nomenclature as the second value of the array.
|
||||
|
||||
A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag.
|
||||
|
||||
# User flow
|
||||
A user A who uses a non-`kind:1`-centric nostr app could choose to announce/recommend a certain kind-handler application.
|
||||
|
||||
When user B sees an unknown event kind, e.g. in a social-media centric nostr client, the client would allow user B to interact with the unknown-kind event (e.g. tapping on it).
|
||||
|
||||
The client MIGHT query for the user's and the user's follows handler.
|
||||
|
||||
# Example
|
||||
|
||||
## User A recommends a `kind:31337`-handler
|
||||
User A might be a user of Zapstr, a `kind:31337`-centric client (tracks). Using Zapstr, user A publishes an event recommending Zapstr as a `kind:31337`-handler.
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 31989,
|
||||
"tags": [
|
||||
[ "d", "31337" ],
|
||||
[ "a", "31990:1743058db7078661b94aaf4286429d97ee5257d14a86d6bfa54cb0482b876fb0:abcd", <relay-url>, "web" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## User B interacts with a `kind:31337`-handler
|
||||
User B might see in their timeline an event referring to a `kind:31337` event
|
||||
(e.g. a `kind:1` tagging a `kind:31337`).
|
||||
|
||||
User B's client, not knowing how to handle a `kind:31337` might display the event
|
||||
using its `alt` tag (as described in NIP-31). When the user clicks on the event,
|
||||
the application queries for a handler for this `kind`:
|
||||
|
||||
`["REQ", <id>, '[{ "kinds": [31989], "#d": ["31337"], 'authors': [<user>, <users-contact-list>] }]']`
|
||||
|
||||
User B, who follows User A, sees that `kind:31989` event and fetches the `a`-tagged event for the app and handler information.
|
||||
|
||||
User B's client sees the application's `kind:31990` which includes the information to redirect the user to the relevant URL with the desired entity replaced in the URL.
|
||||
|
||||
## Alternative query bypassing `kind:31989`
|
||||
Alternatively, users might choose to query directly for `kind:31990` for an event kind. Clients SHOULD be careful doing this and use spam-prevention mechanisms to avoid directing users to malicious handlers.
|
||||
|
||||
`["REQ", <id>, '[{ "kinds": [31990], "#k": [<desired-event-kind>], 'authors': [...] }]']`
|
||||
68
98.md
Normal file
68
98.md
Normal file
@@ -0,0 +1,68 @@
|
||||
NIP-98
|
||||
======
|
||||
|
||||
HTTP Auth
|
||||
-------------------------
|
||||
|
||||
`draft` `optional` `author:kieran` `author:melvincarvalho`
|
||||
|
||||
This NIP defines an ephemerial event used to authorize requests to HTTP servers using nostr events.
|
||||
|
||||
This is useful for HTTP services which are build for Nostr and deal with Nostr user accounts.
|
||||
|
||||
## Nostr event
|
||||
|
||||
A `kind 27235` (In reference to [RFC 7235](https://www.rfc-editor.org/rfc/rfc7235)) event is used.
|
||||
|
||||
The `content` SHOULD be empty.
|
||||
|
||||
The following tags are defined as REQUIRED.
|
||||
|
||||
* `u` - absolute URL
|
||||
* `method` - HTTP Request Method
|
||||
|
||||
Example event:
|
||||
```json
|
||||
{
|
||||
"id": "fe964e758903360f28d8424d092da8494ed207cba823110be3a57dfe4b578734",
|
||||
"pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed",
|
||||
"content": "",
|
||||
"kind": 27235,
|
||||
"created_at": 1682327852,
|
||||
"tags": [
|
||||
[
|
||||
"u",
|
||||
"https://api.snort.social/api/v1/n5sp/list"
|
||||
],
|
||||
[
|
||||
"method",
|
||||
"GET"
|
||||
]
|
||||
],
|
||||
"sig": "5ed9d8ec958bc854f997bdc24ac337d005af372324747efe4a00e24f4c30437ff4dd8308684bed467d9d6be3e5a517bb43b1732cc7d33949a3aaf86705c22184"
|
||||
}
|
||||
```
|
||||
|
||||
Servers MUST perform the following checks in order to validate the event:
|
||||
1. The `kind` MUST be `27235`.
|
||||
2. The `created_at` MUST be within a reasonable time window (suggestion 60 seconds).
|
||||
3. The `u` tag MUST be exactly the same as the absolute request URL (including query parameters).
|
||||
4. The `method` tag MUST be the same HTTP method used for the requested resource.
|
||||
|
||||
When the request contains a body (as in POST/PUT/PATCH methods) clients SHOULD include a SHA256 hash of the request body in a `payload` tag as hex (`["payload", "<sha256-hex>"]`), servers MAY check this to validate that the requested payload is authorized.
|
||||
|
||||
If one of the checks was to fail the server SHOULD respond with a 401 Unauthorized response code.
|
||||
|
||||
All other checks which server MAY do are OPTIONAL, and implementation specific.
|
||||
|
||||
## Request Flow
|
||||
|
||||
Using the `Authorization` header, the `kind 27235` event MUST be `base64` encoded and use the Authorization scheme `Nostr`
|
||||
|
||||
Example HTTP Authorization header:
|
||||
```
|
||||
Authorization: Nostr eyJpZCI6ImZlOTY0ZTc1ODkwMzM2MGYyOGQ4NDI0ZDA5MmRhODQ5NGVkMjA3Y2JhODIzMTEwYmUzYTU3ZGZlNGI1Nzg3MzQiLCJwdWJrZXkiOiI2M2ZlNjMxOGRjNTg1ODNjZmUxNjgxMGY4NmRkMDllMThiZmQ3NmFhYmMyNGEwMDgxY2UyODU2ZjMzMDUwNGVkIiwiY29udGVudCI6IiIsImtpbmQiOjI3MjM1LCJjcmVhdGVkX2F0IjoxNjgyMzI3ODUyLCJ0YWdzIjpbWyJ1cmwiLCJodHRwczovL2FwaS5zbm9ydC5zb2NpYWwvYXBpL3YxL241c3AvbGlzdCJdLFsibWV0aG9kIiwiR0VUIl1dLCJzaWciOiI1ZWQ5ZDhlYzk1OGJjODU0Zjk5N2JkYzI0YWMzMzdkMDA1YWYzNzIzMjQ3NDdlZmU0YTAwZTI0ZjRjMzA0MzdmZjRkZDgzMDg2ODRiZWQ0NjdkOWQ2YmUzZTVhNTE3YmI0M2IxNzMyY2M3ZDMzOTQ5YTNhYWY4NjcwNWMyMjE4NCJ9
|
||||
```
|
||||
|
||||
## Reference Implementations
|
||||
- C# ASP.NET `AuthenticationHandler` [NostrAuth.cs](https://gist.github.com/v0l/74346ae530896115bfe2504c8cd018d3)
|
||||
83
99.md
Normal file
83
99.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# NIP-99
|
||||
|
||||
## Classified Listings
|
||||
|
||||
`draft` `optional` `author:erskingardner`
|
||||
|
||||
This NIP defines `kind:30402`: a parameterized replaceable event to describe classified listings that list any arbitrary product, service, or other thing for sale or offer and includes enough structured metadata to make them useful.
|
||||
|
||||
The category of classifieds includes a very broad range of physical goods, services, work opportunities, rentals, free giveaways, personals, etc. and is distinct from the more strictly structured marketplaces defined in [NIP-15](https://github.com/nostr-protocol/nips/blob/master/15.md) that often sell many units of specific products through very specific channels.
|
||||
|
||||
The structure of these events is very similar to [NIP-23](https://github.com/nostr-protocol/nips/blob/master/23.md) long-form content events.
|
||||
|
||||
### Draft / Inactive Listings
|
||||
|
||||
`kind:30403` has the same structure as `kind:30402` and is used to save draft or inactive classified listings.
|
||||
|
||||
### Content
|
||||
|
||||
The `.content` field should be a description of what is being offered and by whom. These events should be a string in Markdown syntax.
|
||||
|
||||
### Author
|
||||
|
||||
The `.pubkey` field of these events are treated as the party creating the listing.
|
||||
|
||||
### Metadata
|
||||
|
||||
- For "tags"/"hashtags" (i.e. categories or keywords of relevance for the listing) the `"t"` event tag should be used, as per [NIP-12](https://github.com/nostr-protocol/nips/blob/master/12.md).
|
||||
- For images, whether included in the markdown content or not, clients SHOULD use `image` tags as described in [NIP-58](https://github.com/nostr-protocol/nips/blob/master/58.md). This allows clients to display images in carousel format more easily.
|
||||
|
||||
The following tags, used for structured metadata, are standardized and SHOULD be included. Other tags may be added as necessary.
|
||||
|
||||
- `"title"`, a title for the listing
|
||||
- `"summary"`, for short tagline or summary for the listing
|
||||
- `"published_at"`, for the timestamp (in unix seconds – converted to string) of the first time the listing was published.
|
||||
- `"location"`, for the location.
|
||||
- `"price"`, for the price of the thing being listed. This is an array in the format `[ "price", "<number>", "<currency>", "<frequency>" ]`.
|
||||
- `"price"` is the name of the tag
|
||||
- `"<number>"` is the amount in numeric format (but included in the tag as a string)
|
||||
- `"<currency>"` is the currency unit in 3-character ISO 4217 format or ISO 4217-like currency code (e.g. `"btc"`, `"eth"`).
|
||||
- `"<frequency>"` is optional and can be used to describe recurring payments. SHOULD be in noun format (hour, day, week, month, year, etc.)
|
||||
|
||||
#### `price` examples
|
||||
|
||||
- $50 one-time payment `["price", "50", "USD"]`
|
||||
- €15 per month `["price", "15", "EUR", "month"]`
|
||||
- £50,000 per year `["price", "50000", "GBP", "year"]`
|
||||
|
||||
Other standard tags that might be useful.
|
||||
|
||||
- `"g"`, a geohash for more precise location
|
||||
|
||||
## Example Event
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 30402,
|
||||
"created_at": 1675642635,
|
||||
// Markdown content
|
||||
"content": "Lorem [ipsum][nostr:nevent1qqst8cujky046negxgwwm5ynqwn53t8aqjr6afd8g59nfqwxpdhylpcpzamhxue69uhhyetvv9ujuetcv9khqmr99e3k7mg8arnc9] dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nRead more at nostr:naddr1qqzkjurnw4ksz9thwden5te0wfjkccte9ehx7um5wghx7un8qgs2d90kkcq3nk2jry62dyf50k0h36rhpdtd594my40w9pkal876jxgrqsqqqa28pccpzu.",
|
||||
"tags": [
|
||||
["d", "lorem-ipsum"],
|
||||
["title", "Lorem Ipsum"],
|
||||
["published_at", "1296962229"],
|
||||
["t", "electronics"],
|
||||
["image", "https://url.to.img", "256x256"],
|
||||
["summary", "More lorem ipsum that is a little more than the title"],
|
||||
["location", "NYC"],
|
||||
["price", "100", "USD"],
|
||||
[
|
||||
"e",
|
||||
"b3e392b11f5d4f28321cedd09303a748acfd0487aea5a7450b3481c60b6e4f87",
|
||||
"wss://relay.example.com"
|
||||
],
|
||||
[
|
||||
"a",
|
||||
"30023:a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919:ipsum",
|
||||
"wss://relay.nostr.org"
|
||||
]
|
||||
],
|
||||
"pubkey": "...",
|
||||
"id": "..."
|
||||
}
|
||||
```
|
||||
60
README.md
60
README.md
@@ -22,7 +22,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-01: Basic protocol flow description](01.md)
|
||||
- [NIP-02: Contact List and Petnames](02.md)
|
||||
- [NIP-03: OpenTimestamps Attestations for Events](03.md)
|
||||
- [NIP-04: Encrypted Direct Message](04.md)
|
||||
- [NIP-04: Encrypted Direct Message](04.md) --- **unrecommended**: deprecated in favor of [NIP-44](44.md)
|
||||
- [NIP-05: Mapping Nostr keys to DNS-based internet identifiers](05.md)
|
||||
- [NIP-06: Basic key derivation from mnemonic seed phrase](06.md)
|
||||
- [NIP-07: `window.nostr` capability for web browsers](07.md)
|
||||
@@ -32,19 +32,22 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-11: Relay Information Document](11.md)
|
||||
- [NIP-12: Generic Tag Queries](12.md)
|
||||
- [NIP-13: Proof of Work](13.md)
|
||||
- [NIP-14: Subject tag in text events.](14.md)
|
||||
- [NIP-14: Subject tag in text events](14.md)
|
||||
- [NIP-15: Nostr Marketplace (for resilient marketplaces)](15.md)
|
||||
- [NIP-16: Event Treatment](16.md)
|
||||
- [NIP-18: Reposts](18.md)
|
||||
- [NIP-19: bech32-encoded entities](19.md)
|
||||
- [NIP-20: Command Results](20.md)
|
||||
- [NIP-21: `nostr:` URL scheme](21.md)
|
||||
- [NIP-21: `nostr:` URI scheme](21.md)
|
||||
- [NIP-22: Event `created_at` Limits](22.md)
|
||||
- [NIP-23: Long-form Content](23.md)
|
||||
- [NIP-25: Reactions](25.md)
|
||||
- [NIP-26: Delegated Event Signing](26.md)
|
||||
- [NIP-27: Text Note References](27.md)
|
||||
- [NIP-28: Public Chat](28.md)
|
||||
- [NIP-30: Custom Emoji](30.md)
|
||||
- [NIP-31: Dealing with Unknown Events](31.md)
|
||||
- [NIP-32: Labeling](32.md)
|
||||
- [NIP-33: Parameterized Replaceable Events](33.md)
|
||||
- [NIP-36: Sensitive Content](36.md)
|
||||
- [NIP-39: External Identities in Profiles](39.md)
|
||||
@@ -53,14 +56,21 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-45: Counting results](45.md)
|
||||
- [NIP-46: Nostr Connect](46.md)
|
||||
- [NIP-47: Wallet Connect](47.md)
|
||||
- [NIP-48: Proxy Tags](48.md)
|
||||
- [NIP-50: Keywords filter](50.md)
|
||||
- [NIP-51: Lists](51.md)
|
||||
- [NIP-52: Calendar Events](52.md)
|
||||
- [NIP-53: Live Activities](53.md)
|
||||
- [NIP-56: Reporting](56.md)
|
||||
- [NIP-57: Lightning Zaps](57.md)
|
||||
- [NIP-58: Badges](58.md)
|
||||
- [NIP-65: Relay List Metadata](65.md)
|
||||
- [NIP-72: Moderated Communities](72.md)
|
||||
- [NIP-78: Application-specific data](78.md)
|
||||
- [NIP-89: Recommended Application Handlers](89.md)
|
||||
- [NIP-94: File Metadata](94.md)
|
||||
- [NIP-98: HTTP Auth](98.md)
|
||||
- [NIP-99: Classified Listings](99.md)
|
||||
|
||||
## Event Kinds
|
||||
|
||||
@@ -72,16 +82,20 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `3` | Contacts | [2](02.md) |
|
||||
| `4` | Encrypted Direct Messages | [4](04.md) |
|
||||
| `5` | Event Deletion | [9](09.md) |
|
||||
| `6` | Reposts | [18](18.md) |
|
||||
| `6` | Repost | [18](18.md) |
|
||||
| `7` | Reaction | [25](25.md) |
|
||||
| `8` | Badge Award | [58](58.md) |
|
||||
| `16` | Generic Repost | [18](18.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) |
|
||||
| `1063` | File Metadata | [94](94.md) |
|
||||
| `1311` | Live Chat Message | [53](53.md) |
|
||||
| `1984` | Reporting | [56](56.md) |
|
||||
| `1985` | Label | [32](32.md) |
|
||||
| `4550` | Community Post Approval | [72](72.md) |
|
||||
| `9734` | Zap Request | [57](57.md) |
|
||||
| `9735` | Zap | [57](57.md) |
|
||||
| `10000` | Mute List | [51](51.md) |
|
||||
@@ -92,6 +106,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `23194` | Wallet Request | [47](47.md) |
|
||||
| `23195` | Wallet Response | [47](47.md) |
|
||||
| `24133` | Nostr Connect | [46](46.md) |
|
||||
| `27235` | HTTP Auth | [98](98.md) |
|
||||
| `30000` | Categorized People List | [51](51.md) |
|
||||
| `30001` | Categorized Bookmark List | [51](51.md) |
|
||||
| `30008` | Profile Badges | [58](58.md) |
|
||||
@@ -99,7 +114,19 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `30017` | Create or update a stall | [15](15.md) |
|
||||
| `30018` | Create or update a product | [15](15.md) |
|
||||
| `30023` | Long-form Content | [23](23.md) |
|
||||
| `30024` | Draft Long-form Content | [23](23.md) |
|
||||
| `30078` | Application-specific Data | [78](78.md) |
|
||||
| `30311` | Live Event | [53](53.md) |
|
||||
| `30402` | Classified Listing | [99](99.md) |
|
||||
| `30403` | Draft Classified Listing | [99](99.md) |
|
||||
| `31922` | Date-Based Calendar Event | [52](52.md) |
|
||||
| `31923` | Time-Based Calendar Event | [52](52.md) |
|
||||
| `31924` | Calendar | [52](52.md) |
|
||||
| `31925` | Calendar Event RSVP | [52](52.md) |
|
||||
| `31989` | Handler recommendation | [89](89.md) |
|
||||
| `31990` | Handler information | [89](89.md) |
|
||||
| `34550` | Community Definition | [72](72.md) |
|
||||
|
||||
|
||||
### Event Kind Ranges
|
||||
|
||||
@@ -142,10 +169,14 @@ When experimenting with kinds, keep in mind the classification introduced by [NI
|
||||
| name | value | other parameters | NIP |
|
||||
| ----------------- | ------------------------------------ | -------------------- | ------------------------ |
|
||||
| `a` | coordinates to an event | relay URL | [33](33.md), [23](23.md) |
|
||||
| `alt` | Alt tag | -- | [31](31.md) |
|
||||
| `d` | identifier | -- | [33](33.md) |
|
||||
| `e` | event id (hex) | relay URL, marker | [1](01.md), [10](10.md) |
|
||||
| `g` | geohash | -- | [12](12.md) |
|
||||
| `g` | geohash | -- | [12](12.md), [52](52.md) |
|
||||
| `i` | identity | proof | [39](39.md) |
|
||||
| `k` | kind number (string) | -- | [18](18.md), [72](72.md) |
|
||||
| `l` | label, label namespace | annotations | [32](32.md) |
|
||||
| `L` | label namespace | -- | [32](32.md) |
|
||||
| `p` | pubkey (hex) | relay URL | [1](01.md) |
|
||||
| `r` | a reference (URL, etc) | -- | [12](12.md) |
|
||||
| `t` | hashtag | -- | [12](12.md) |
|
||||
@@ -156,12 +187,16 @@ When experimenting with kinds, keep in mind the classification introduced by [NI
|
||||
| `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) |
|
||||
| `description` | badge description | -- | [58](58.md) |
|
||||
| `description` | invoice description | -- | [57](57.md) |
|
||||
| `emoji` | shortcode, image URL | -- | [30](30.md) |
|
||||
| `expiration` | unix timestamp (string) | -- | [40](40.md) |
|
||||
| `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) |
|
||||
| `lnurl` | `bech32` encoded `lnurl` | -- | [57](57.md) |
|
||||
| `location` | location string | -- | [52](52.md), [99](99.md) |
|
||||
| `name` | badge name | -- | [58](58.md) |
|
||||
| `nonce` | random | -- | [13](13.md) |
|
||||
| `preimage` | hash of `bolt11` invoice | -- | [57](57.md) |
|
||||
| `price` | price | currency, frequency | [99](99.md) |
|
||||
| `proxy` | external ID | protocol | [48](48.md) |
|
||||
| `published_at` | unix timestamp (string) | -- | [23](23.md) |
|
||||
| `relay` | relay url | -- | [42](42.md) |
|
||||
| `relays` | relay list | -- | [57](57.md) |
|
||||
@@ -179,6 +214,21 @@ When experimenting with kinds, keep in mind the classification introduced by [NI
|
||||
4. There should be no more than one way of doing the same thing.
|
||||
5. Other rules will be made up when necessary.
|
||||
|
||||
## Mailing Lists
|
||||
|
||||
The nostr ecosystem is getting large with many different organizations, relays
|
||||
and clients. Following the nips repo on github is becoming more difficult and
|
||||
noisy. To coordinate on protocol development outside of github, there are
|
||||
mailing lists where you can work on NIPs before submitting them here:
|
||||
|
||||
* [w3c nostr community group][w3-nostr] - [public-nostr@w3.org][mailto-w3] - requires signup
|
||||
* [nostr-protocol google group][nostr-google-group] - [nostr-protocol@googlegroups.com][mailto-google] - no signup required
|
||||
|
||||
[w3-nostr]: https://www.w3.org/community/nostr/
|
||||
[mailto-w3]: mailto:public-nostr@w3.org
|
||||
[nostr-google-group]: https://groups.google.com/g/nostr-protocol
|
||||
[mailto-google]: mailto:nostr-protocol@googlegroups.com
|
||||
|
||||
## License
|
||||
|
||||
All NIPs are public domain.
|
||||
|
||||
Reference in New Issue
Block a user