mirror of
https://github.com/nostr-protocol/nips.git
synced 2025-12-09 00:28:51 +00:00
Compare commits
2 Commits
nip11clean
...
bigger-nip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8782df594 | ||
|
|
4de6a69931 |
4
01.md
4
01.md
@@ -14,7 +14,7 @@ Each user has a keypair. Signatures, public key, and encodings are done accordin
|
||||
|
||||
The only object type that exists is the `event`, which has the following format on the wire:
|
||||
|
||||
```yaml
|
||||
```jsonc
|
||||
{
|
||||
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>,
|
||||
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
|
||||
@@ -120,7 +120,7 @@ Clients can send 3 types of messages, which must be JSON arrays, according to th
|
||||
|
||||
`<filtersX>` is a JSON object that determines what events will be sent in that subscription, it can have the following attributes:
|
||||
|
||||
```yaml
|
||||
```json
|
||||
{
|
||||
"ids": <a list of event ids>,
|
||||
"authors": <a list of lowercase pubkeys, the pubkey of an event must be one of these>,
|
||||
|
||||
260
11.md
260
11.md
@@ -6,7 +6,7 @@ Relay Information Document
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
Relays may provide server metadata to clients to inform them of capabilities, administrative contacts, and various server attributes. This is made available as a JSON document over HTTP, on the same URI as the relay's websocket.
|
||||
Relays may provide server metadata to clients to inform them of capabilities, administrative contacts, and various server attributes. This is made available as a JSON document over HTTP, on the same URI as the relay's websocket.
|
||||
|
||||
When a relay receives an HTTP(s) request with an `Accept` header of `application/nostr+json` to a URI supporting WebSocket upgrades, they SHOULD return a document with the following structure.
|
||||
|
||||
@@ -20,9 +20,11 @@ When a relay receives an HTTP(s) request with an `Accept` header of `application
|
||||
"contact": <administrative alternate contact>,
|
||||
"supported_nips": <a list of NIP numbers supported by the relay>,
|
||||
"software": <string identifying relay software URL>,
|
||||
"version": <string version identifier>,
|
||||
"version": <string version identifier>
|
||||
"privacy_policy": <a link to a text file describing the relay's privacy policy>,
|
||||
"terms_of_service": <a link to a text file describing the relay's term of service>,
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@@ -33,11 +35,11 @@ Field Descriptions
|
||||
|
||||
### Name
|
||||
|
||||
A relay may select a `name` for use in client software. This is a string, and SHOULD be less than 30 characters to avoid client truncation.
|
||||
A relay may select a `name` for use in client software. This is a string, and SHOULD be less than 30 characters to avoid client truncation.
|
||||
|
||||
### Description
|
||||
|
||||
Detailed plain-text information about the relay may be contained in the `description` string. It is recommended that this contain no markup, formatting or line breaks for word wrapping, and simply use double newline characters to separate paragraphs. There are no limitations on length.
|
||||
Detailed plain-text information about the relay may be contained in the `description` string. It is recommended that this contain no markup, formatting or line breaks for word wrapping, and simply use double newline characters to separate paragraphs. There are no limitations on length.
|
||||
|
||||
### Banner
|
||||
|
||||
@@ -56,29 +58,35 @@ Icon is a compact visual representation of the relay for use in UI with limited
|
||||
|
||||
### Pubkey
|
||||
|
||||
An administrative contact may be listed with a `pubkey`, in the same format as Nostr events (32-byte hex for a `secp256k1` public key). If a contact is listed, this provides clients with a recommended address to send encrypted direct messages (See [NIP-17](17.md)) to a system administrator. Expected uses of this address are to report abuse or illegal content, file bug reports, or request other technical assistance.
|
||||
An administrative contact may be listed with a `pubkey`, in the same format as Nostr events (32-byte hex for a `secp256k1` public key). If a contact is listed, this provides clients with a recommended address to send encrypted direct messages (See [NIP-17](17.md)) to a system administrator. Expected uses of this address are to report abuse or illegal content, file bug reports, or request other technical assistance.
|
||||
|
||||
Relay operators have no obligation to respond to direct messages.
|
||||
|
||||
### Contact
|
||||
|
||||
An alternative contact may be listed under the `contact` field as well, with the same purpose as `pubkey`. Use of a Nostr public key and direct message SHOULD be preferred over this. Contents of this field SHOULD be a URI, using schemes such as `mailto` or `https` to provide users with a means of contact.
|
||||
An alternative contact may be listed under the `contact` field as well, with the same purpose as `pubkey`. Use of a Nostr public key and direct message SHOULD be preferred over this. Contents of this field SHOULD be a URI, using schemes such as `mailto` or `https` to provide users with a means of contact.
|
||||
|
||||
### Supported NIPs
|
||||
|
||||
As the Nostr protocol evolves, some functionality may only be available by relays that implement a specific `NIP`. This field is an array of the integer identifiers of `NIP`s that are implemented in the relay. Examples would include `1`, for `"NIP-01"` and `9`, for `"NIP-09"`. Client-side `NIPs` SHOULD NOT be advertised, and can be ignored by clients.
|
||||
As the Nostr protocol evolves, some functionality may only be available by relays that implement a specific `NIP`. This field is an array of the integer identifiers of `NIP`s that are implemented in the relay. Examples would include `1`, for `"NIP-01"` and `9`, for `"NIP-09"`. Client-side `NIPs` SHOULD NOT be advertised, and can be ignored by clients.
|
||||
|
||||
### Software
|
||||
|
||||
The relay server implementation MAY be provided in the `software` attribute. If present, this MUST be a URL to the project's homepage.
|
||||
The relay server implementation MAY be provided in the `software` attribute. If present, this MUST be a URL to the project's homepage.
|
||||
|
||||
### Version
|
||||
|
||||
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
|
||||
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
|
||||
|
||||
### Privacy Policy
|
||||
|
||||
The relay owner/admin MAY choose to link to a privacy policy document, which describes how the relay utilizes user data. Data collection, data usage, data retention, monetization of data, and third party data sharing SHOULD be included.
|
||||
|
||||
### Terms of Service
|
||||
|
||||
The relay MAY choose to publish its software version as a string attribute. The string format is defined by the relay implementation. It is recommended this be a version number or commit identifier.
|
||||
The relay owner/admin MAY choose to link to a terms of service document.
|
||||
|
||||
|
||||
|
||||
Extra Fields
|
||||
------------
|
||||
@@ -154,7 +162,113 @@ a specific niche kind or content. Normal anti-spam heuristics, for example, do n
|
||||
|
||||
- `created_at_upper_limit`: 'created_at' upper limit
|
||||
|
||||
- `default_limit`: The maximum returned events if you send a filter without a limit.
|
||||
- `default_limit`: The maximum returned events if you send a filter with the limit set to 0.
|
||||
|
||||
### Event Retention
|
||||
|
||||
There may be a cost associated with storing data forever, so relays
|
||||
may wish to state retention times. The values stated here are defaults
|
||||
for unauthenticated users and visitors. Paid users would likely have
|
||||
other policies.
|
||||
|
||||
Retention times are given in seconds, with `null` indicating infinity.
|
||||
If zero is provided, this means the event will not be stored at
|
||||
all, and preferably an error will be provided when those are received.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"retention": [
|
||||
{"kinds": [0, 1, [5, 7], [40, 49]], "time": 3600},
|
||||
{"kinds": [[40000, 49999]], "time": 100},
|
||||
{"kinds": [[30000, 39999]], "count": 1000},
|
||||
{"time": 3600, "count": 10000}
|
||||
],
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
`retention` is a list of specifications: each will apply to either all kinds, or
|
||||
a subset of kinds. Ranges may be specified for the kind field as a tuple of inclusive
|
||||
start and end values. Events of indicated kind (or all) are then limited to a `count`
|
||||
and/or time period.
|
||||
|
||||
It is possible to effectively blacklist Nostr-based protocols that rely on
|
||||
a specific `kind` number, by giving a retention time of zero for those `kind` values.
|
||||
While that is unfortunate, it does allow clients to discover servers that will
|
||||
support their protocol quickly via a single HTTP fetch.
|
||||
|
||||
There is no need to specify retention times for _ephemeral events_ since they are not retained.
|
||||
|
||||
### Content Limitations
|
||||
|
||||
Some relays may be governed by the arbitrary laws of a nation state. This
|
||||
may limit what content can be stored in clear-text on those relays. All
|
||||
clients are encouraged to use encryption to work around this limitation.
|
||||
|
||||
It is not possible to describe the limitations of each country's laws
|
||||
and policies which themselves are typically vague and constantly shifting.
|
||||
|
||||
Therefore, this field allows the relay operator to indicate which
|
||||
countries' laws might end up being enforced on them, and then
|
||||
indirectly on their users' content.
|
||||
|
||||
Users should be able to avoid relays in countries they don't like,
|
||||
and/or select relays in more favorable zones. Exposing this
|
||||
flexibility is up to the client software.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"relay_countries": [ "CA", "US" ],
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
- `relay_countries`: a list of two-level ISO country codes (ISO 3166-1 alpha-2) whose
|
||||
laws and policies may affect this relay. `EU` may be used for European Union countries. A `*` can be used for global relays.
|
||||
|
||||
Remember that a relay may be hosted in a country which is not the
|
||||
country of the legal entities who own the relay, so it's very
|
||||
likely a number of countries are involved.
|
||||
|
||||
|
||||
### Community Preferences
|
||||
|
||||
For public text notes at least, a relay may try to foster a
|
||||
local community. This would encourage users to follow the global
|
||||
feed on that relay, in addition to their usual individual follows.
|
||||
To support this goal, relays MAY specify some of the following values.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"language_tags": ["en", "en-419"],
|
||||
"tags": ["sfw-only", "bitcoin-only", "anime"],
|
||||
"posting_policy": "https://example.com/posting-policy.html",
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
- `language_tags` is an ordered list
|
||||
of [IETF language tags](https://en.wikipedia.org/wiki/IETF_language_tag) indicating
|
||||
the major languages spoken on the relay. A `*` can be used for global relays.
|
||||
|
||||
- `tags` is a list of limitations on the topics to be discussed.
|
||||
For example `sfw-only` indicates that only "Safe For Work" content
|
||||
is encouraged on this relay. This relies on assumptions of what the
|
||||
"work" "community" feels "safe" talking about. In time, a common
|
||||
set of tags may emerge that allow users to find relays that suit
|
||||
their needs, and client software will be able to parse these tags easily.
|
||||
The `bitcoin-only` tag indicates that any *altcoin*, *"crypto"* or *blockchain*
|
||||
comments will be ridiculed without mercy.
|
||||
|
||||
- `posting_policy` is a link to a human-readable page which specifies the
|
||||
community policies for the relay. In cases where `sfw-only` is True, it's
|
||||
important to link to a page which gets into the specifics of your posting policy.
|
||||
|
||||
The `description` field should be used to describe your community
|
||||
goals and values, in brief. The `posting_policy` is for additional
|
||||
detail and legal terms. Use the `tags` field to signify limitations
|
||||
on content, or topics to be discussed, which could be machine
|
||||
processed by appropriate client software.
|
||||
|
||||
### Pay-to-Relay
|
||||
|
||||
@@ -174,68 +288,82 @@ Relays that require payments may want to expose their fee schedules.
|
||||
|
||||
### Examples
|
||||
|
||||
```yaml
|
||||
~> curl -H "Accept: application/nostr+json" https://nostr.wine | jq
|
||||
{
|
||||
"contact": "wino@nostr.wine",
|
||||
"description": "A paid nostr relay for wine enthusiasts and everyone else.",
|
||||
"fees": {
|
||||
"admission": [
|
||||
{
|
||||
"amount": 18888000,
|
||||
"unit": "msats"
|
||||
}
|
||||
]
|
||||
},
|
||||
"icon": "https://image.nostr.build/30acdce4a81926f386622a07343228ae99fa68d012d54c538c0b2129dffe400c.png",
|
||||
"limitation": {
|
||||
"auth_required": false,
|
||||
"created_at_lower_limit": 94608000,
|
||||
"created_at_upper_limit": 300,
|
||||
"max_event_tags": 4000,
|
||||
"max_limit": 1000,
|
||||
"max_message_length": 524288,
|
||||
"max_subid_length": 71,
|
||||
"max_subscriptions": 50,
|
||||
"min_pow_difficulty": 0,
|
||||
"payment_required": true,
|
||||
"restricted_writes": true
|
||||
},
|
||||
"name": "nostr.wine",
|
||||
"payments_url": "https://nostr.wine/invoices",
|
||||
"pubkey": "4918eb332a41b71ba9a74b1dc64276cfff592e55107b93baae38af3520e55975",
|
||||
"software": "https://nostr.wine",
|
||||
"supported_nips": [ 1, 2, 4, 9, 11, 40, 42, 50, 70, 77 ],
|
||||
"terms_of_service": "https://nostr.wine/terms",
|
||||
"version": "0.3.3"
|
||||
}
|
||||
As of 25 March 2025 the following command provided these results:
|
||||
|
||||
~> curl -H "Accept: application/nostr+json" https://nostr.land | jq
|
||||
```bash
|
||||
curl -H "Accept: application/nostr+json" https://jellyfish.land | jq
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "[✨ NFDB] nostr.land family of relays (fi-01 [tiger])",
|
||||
"name": "[✨ NFDB] nostr.land",
|
||||
"pubkey": "52b4a076bcbbbdc3a1aefa3735816cf74993b1b8db202b01c883c58be7fad8bd",
|
||||
"software": "NFDB",
|
||||
"icon": "https://i.nostr.build/b3thno790aodH8lE.jpg",
|
||||
"supported_nips": [ 1, 2, 4, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 42, 44, 46, 47, 48, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 65, 68, 69, 71, 72, 73, 75, 78, 84, 88, 89, 90, 92, 99 ],
|
||||
"version": "1.0.0",
|
||||
"limitation": {
|
||||
"payment_required": true,
|
||||
"max_message_length": 65535,
|
||||
"max_event_tags": 2000,
|
||||
"max_subscriptions": 200,
|
||||
"auth_required": false
|
||||
},
|
||||
"payments_url": "https://nostr.land",
|
||||
"name": "JellyFish",
|
||||
"description": "Stay Immortal!",
|
||||
"banner": "https://image.nostr.build/7fdefea2dec1f1ec25b8ce69362566c13b2b7f13f1726c2e4584f05f64f62496.jpg",
|
||||
"pubkey": "bf2bee5281149c7c350f5d12ae32f514c7864ff10805182f4178538c2c421007",
|
||||
"contact": "hi@dezh.tech",
|
||||
"software": "https://github.com/dezh-tech/immortal",
|
||||
"supported_nips": [
|
||||
1,
|
||||
9,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
40,
|
||||
42,
|
||||
59,
|
||||
62,
|
||||
70
|
||||
],
|
||||
"version": "immortal - 0.0.9",
|
||||
"relay_countries": [
|
||||
"*"
|
||||
],
|
||||
"language_tags": [
|
||||
"*"
|
||||
],
|
||||
"tags": [],
|
||||
"posting_policy": "https://jellyfish.land/tos.txt",
|
||||
"payments_url": "https://jellyfish.land/relay",
|
||||
"icon": "https://image.nostr.build/2547e9ec4b23589e09bc7071e0806c3d4293f76284c58ff331a64bce978aaee8.jpg",
|
||||
"retention": [],
|
||||
"fees": {
|
||||
"subscription": [
|
||||
{
|
||||
"amount": 4000000,
|
||||
"unit": "msats",
|
||||
"period": 2592000
|
||||
"amount": 3000,
|
||||
"period": 2628003,
|
||||
"unit": "sats"
|
||||
},
|
||||
{
|
||||
"amount": 8000,
|
||||
"period": 7884009,
|
||||
"unit": "sats"
|
||||
},
|
||||
{
|
||||
"amount": 15000,
|
||||
"period": 15768018,
|
||||
"unit": "sats"
|
||||
},
|
||||
{
|
||||
"amount": 28000,
|
||||
"period": 31536036,
|
||||
"unit": "sats"
|
||||
}
|
||||
]
|
||||
},
|
||||
"terms_of_service": "https://nostr.land/terms"
|
||||
"limitation": {
|
||||
"auth_required": false,
|
||||
"max_message_length": 70000,
|
||||
"max_subid_length": 256,
|
||||
"max_subscriptions": 350,
|
||||
"min_pow_difficulty": 0,
|
||||
"payment_required": true,
|
||||
"restricted_writes": true,
|
||||
"max_event_tags": 2000,
|
||||
"max_content_length": 70000,
|
||||
"created_at_lower_limit": 0,
|
||||
"created_at_upper_limit": 2147483647,
|
||||
"default_limit": 500,
|
||||
"max_limit": 5000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
79
17.md
79
17.md
@@ -15,17 +15,17 @@ Kind `14` is a chat message. `p` tags identify one or more receivers of the mess
|
||||
```jsonc
|
||||
{
|
||||
"id": "<usual hash>",
|
||||
"pubkey": "<sender-pubkey>",
|
||||
"pubkey": "<sender-pubkey>",
|
||||
"created_at": "<current-time>",
|
||||
"kind": 14,
|
||||
"tags": [
|
||||
["p", "<receiver-1-pubkey>", "<relay-url>"],
|
||||
["p", "<receiver-2-pubkey>", "<relay-url>"],
|
||||
["e", "<kind-14-id>", "<relay-url>"] // if this is a reply
|
||||
"kind": 14,
|
||||
"tags": [
|
||||
["p", "<receiver-1-pubkey>", "<relay-url>"],
|
||||
["p", "<receiver-2-pubkey>", "<relay-url>"],
|
||||
["e", "<kind-14-id>", "<relay-url>"] // if this is a reply
|
||||
["subject", "<conversation-title>"],
|
||||
// rest of tags...
|
||||
],
|
||||
"content": "<message-in-plain-text>",
|
||||
// rest of tags...
|
||||
],
|
||||
"content": "<message-in-plain-text>",
|
||||
}
|
||||
```
|
||||
|
||||
@@ -65,22 +65,21 @@ Kind `14`s MUST never be signed. If it is signed, the message might leak to rela
|
||||
}
|
||||
```
|
||||
|
||||
Kind `15` is used for sending encrypted file event messages:
|
||||
Kind 15 is used for sending encrypted file event messages:
|
||||
|
||||
- `file-type`: Specifies the MIME type of the attached file (e.g., `image/jpeg`, `audio/mpeg`, etc.) before encryption.
|
||||
- `encryption-algorithm`: Indicates the encryption algorithm used for encrypting the file. Supported algorithms: `aes-gcm`.
|
||||
- `file-type`: Specifies the MIME type of the attached file (e.g., `image/jpeg`, `audio/mpeg`, etc.).
|
||||
- `encryption-algorithm`: Indicates the encryption algorithm used for encrypting the file. Supported algorithms may include `aes-gcm`, `chacha20-poly1305`,`aes-cbc` etc.
|
||||
- `decryption-key`: The decryption key that will be used by the recipient to decrypt the file.
|
||||
- `decryption-nonce`: The decryption nonce that will be used by the recipient to decrypt the file.
|
||||
- `content`: The URL of the file (`<file-url>`).
|
||||
- `x` containing the SHA-256 hexencoded string of the encrypted file.
|
||||
- `ox` containing the SHA-256 hexencoded string of the file before encryption.
|
||||
- `size` (optional) size of the encrypted file in bytes
|
||||
- `dim` (optional) size in pixels in the form `<width>x<height>`
|
||||
- `x` containing the SHA-256 hexencoded string of the file.
|
||||
- `size` (optional) size of file in bytes
|
||||
- `dim` (optional) size of the file in pixels in the form `<width>x<height>`
|
||||
- `blurhash`(optional) the [blurhash](https://github.com/woltapp/blurhash) to show while the client is loading the file
|
||||
- `thumb` (optional) URL of thumbnail with same aspect ratio (encrypted with the same key, nonce)
|
||||
- `fallback` (optional) zero or more fallback file sources in case `url` fails (encrypted with the same key, nonce)
|
||||
- `fallback` (optional) zero or more fallback file sources in case `url` fails
|
||||
|
||||
Just like kind `14`, kind `15`s MUST never be signed.
|
||||
Just like kind 14, kind `15`s MUST never be signed.
|
||||
|
||||
## Chat Rooms
|
||||
|
||||
@@ -88,34 +87,34 @@ The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or
|
||||
|
||||
Clients SHOULD render messages of the same room in a continuous thread.
|
||||
|
||||
An optional `subject` tag defines the current name/topic of the conversation. Any member can change the topic by simply submitting a new `subject` to an existing `pubkey` + `p` tags room. There is no need to send `subject` in every message. The newest `subject` in the chat room is the subject of the conversation.
|
||||
An optional `subject` tag defines the current name/topic of the conversation. Any member can change the topic by simply submitting a new `subject` to an existing `pubkey` + `p`-tags room. There is no need to send `subject` in every message. The newest `subject` in the thread is the subject of the conversation.
|
||||
|
||||
## Encrypting
|
||||
|
||||
Following [NIP-59](59.md), the **unsigned** `kind:14` & `kind:15` chat messages must be sealed (`kind:13`) and then gift-wrapped (`kind:1059`) to each receiver and the sender individually.
|
||||
|
||||
```js
|
||||
```jsonc
|
||||
{
|
||||
"id": "<usual hash>",
|
||||
"pubkey": randomPublicKey,
|
||||
"created_at": randomTimeUpTo2DaysInThePast(),
|
||||
"pubkey": randomPublicKey,
|
||||
"created_at": randomTimeUpTo2DaysInThePast(),
|
||||
"kind": 1059, // gift wrap
|
||||
"tags": [
|
||||
["p", receiverPublicKey, "<relay-url>"] // receiver
|
||||
],
|
||||
"content": nip44Encrypt(
|
||||
{
|
||||
"tags": [
|
||||
["p", receiverPublicKey, "<relay-url>"] // receiver
|
||||
],
|
||||
"content": nip44Encrypt(
|
||||
{
|
||||
"id": "<usual hash>",
|
||||
"pubkey": senderPublicKey,
|
||||
"created_at": randomTimeUpTo2DaysInThePast(),
|
||||
"kind": 13, // seal
|
||||
"tags": [], // no tags
|
||||
"content": nip44Encrypt(unsignedKind14, senderPrivateKey, receiverPublicKey),
|
||||
"sig": "<signed by senderPrivateKey>"
|
||||
},
|
||||
randomPrivateKey, receiverPublicKey
|
||||
),
|
||||
"sig": "<signed by randomPrivateKey>"
|
||||
"pubkey": senderPublicKey,
|
||||
"created_at": randomTimeUpTo2DaysInThePast(),
|
||||
"kind": 13, // seal
|
||||
"tags": [], // no tags
|
||||
"content": nip44Encrypt(unsignedKind14, senderPrivateKey, receiverPublicKey),
|
||||
"sig": "<signed by senderPrivateKey>"
|
||||
},
|
||||
randomPrivateKey, receiverPublicKey
|
||||
),
|
||||
"sig": "<signed by randomPrivateKey>"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -125,7 +124,7 @@ Clients MUST verify if pubkey of the `kind:13` is the same pubkey on the `kind:1
|
||||
|
||||
Clients SHOULD randomize `created_at` in up to two days in the past in both the seal and the gift wrap to make sure grouping by `created_at` doesn't reveal any metadata.
|
||||
|
||||
The gift wrap's `p` tag can be the receiver's main pubkey or an alias key created to receive DMs without exposing the receiver's identity.
|
||||
The gift wrap's `p`-tag can be the receiver's main pubkey or an alias key created to receive DMs without exposing the receiver's identity.
|
||||
|
||||
Clients CAN offer disappearing messages by setting an `expiration` tag in the gift wrap of each receiver or by not generating a gift wrap to the sender's public key
|
||||
|
||||
@@ -189,7 +188,7 @@ The two final GiftWraps, one to the receiver and the other to the sender, respec
|
||||
"created_at":1703128320,
|
||||
"kind":1059,
|
||||
"tags":[
|
||||
["p", "918e2da906df4ccd12c8ac672d8335add131a4cf9d27ce42b3bb3625755f0788"]
|
||||
[ "p", "918e2da906df4ccd12c8ac672d8335add131a4cf9d27ce42b3bb3625755f0788"]
|
||||
],
|
||||
"content":"AsqzdlMsG304G8h08bE67dhAR1gFTzTckUUyuvndZ8LrGCvwI4pgC3d6hyAK0Wo9gtkLqSr2rT2RyHlE5wRqbCOlQ8WvJEKwqwIJwT5PO3l2RxvGCHDbd1b1o40ZgIVwwLCfOWJ86I5upXe8K5AgpxYTOM1BD+SbgI5jOMA8tgpRoitJedVSvBZsmwAxXM7o7sbOON4MXHzOqOZpALpS2zgBDXSAaYAsTdEM4qqFeik+zTk3+L6NYuftGidqVluicwSGS2viYWr5OiJ1zrj1ERhYSGLpQnPKrqDaDi7R1KrHGFGyLgkJveY/45y0rv9aVIw9IWF11u53cf2CP7akACel2WvZdl1htEwFu/v9cFXD06fNVZjfx3OssKM/uHPE9XvZttQboAvP5UoK6lv9o3d+0GM4/3zP+yO3C0NExz1ZgFmbGFz703YJzM+zpKCOXaZyzPjADXp8qBBeVc5lmJqiCL4solZpxA1865yPigPAZcc9acSUlg23J1dptFK4n3Tl5HfSHP+oZ/QS/SHWbVFCtq7ZMQSRxLgEitfglTNz9P1CnpMwmW/Y4Gm5zdkv0JrdUVrn2UO9ARdHlPsW5ARgDmzaxnJypkfoHXNfxGGXWRk0sKLbz/ipnaQP/eFJv/ibNuSfqL6E4BnN/tHJSHYEaTQ/PdrA2i9laG3vJti3kAl5Ih87ct0w/tzYfp4SRPhEF1zzue9G/16eJEMzwmhQ5Ec7jJVcVGa4RltqnuF8unUu3iSRTQ+/MNNUkK6Mk+YuaJJs6Fjw6tRHuWi57SdKKv7GGkr0zlBUU2Dyo1MwpAqzsCcCTeQSv+8qt4wLf4uhU9Br7F/L0ZY9bFgh6iLDCdB+4iABXyZwT7Ufn762195hrSHcU4Okt0Zns9EeiBOFxnmpXEslYkYBpXw70GmymQfJlFOfoEp93QKCMS2DAEVeI51dJV1e+6t3pCSsQN69Vg6jUCsm1TMxSs2VX4BRbq562+VffchvW2BB4gMjsvHVUSRl8i5/ZSDlfzSPXcSGALLHBRzy+gn0oXXJ/447VHYZJDL3Ig8+QW5oFMgnWYhuwI5QSLEyflUrfSz+Pdwn/5eyjybXKJftePBD9Q+8NQ8zulU5sqvsMeIx/bBUx0fmOXsS3vjqCXW5IjkmSUV7q54GewZqTQBlcx+90xh/LSUxXex7UwZwRnifvyCbZ+zwNTHNb12chYeNjMV7kAIr3cGQv8vlOMM8ajyaZ5KVy7HpSXQjz4PGT2/nXbL5jKt8Lx0erGXsSsazkdoYDG3U",
|
||||
"sig":"a3c6ce632b145c0869423c1afaff4a6d764a9b64dedaf15f170b944ead67227518a72e455567ca1c2a0d187832cecbde7ed478395ec4c95dd3e71749ed66c480"
|
||||
@@ -203,7 +202,7 @@ The two final GiftWraps, one to the receiver and the other to the sender, respec
|
||||
"created_at":1702711587,
|
||||
"kind":1059,
|
||||
"tags":[
|
||||
["p", "44900586091b284416a0c001f677f9c49f7639a55c3f1e2ec130a8e1a7998e1b"]
|
||||
[ "p", "44900586091b284416a0c001f677f9c49f7639a55c3f1e2ec130a8e1a7998e1b"]
|
||||
],
|
||||
"content":"AsTClTzr0gzXXji7uye5UB6LYrx3HDjWGdkNaBS6BAX9CpHa+Vvtt5oI2xJrmWLen+Fo2NBOFazvl285Gb3HSM82gVycrzx1HUAaQDUG6HI7XBEGqBhQMUNwNMiN2dnilBMFC3Yc8ehCJT/gkbiNKOpwd2rFibMFRMDKai2mq2lBtPJF18oszKOjA+XlOJV8JRbmcAanTbEK5nA/GnG3eGUiUzhiYBoHomj3vztYYxc0QYHOx0WxiHY8dsC6jPsXC7f6k4P+Hv5ZiyTfzvjkSJOckel1lZuE5SfeZ0nduqTlxREGeBJ8amOykgEIKdH2VZBZB+qtOMc7ez9dz4wffGwBDA7912NFS2dPBr6txHNxBUkDZKFbuD5wijvonZDvfWq43tZspO4NutSokZB99uEiRH8NAUdGTiNb25m9JcDhVfdmABqTg5fIwwTwlem5aXIy8b66lmqqz2LBzJtnJDu36bDwkILph3kmvaKPD8qJXmPQ4yGpxIbYSTCohgt2/I0TKJNmqNvSN+IVoUuC7ZOfUV9lOV8Ri0AMfSr2YsdZ9ofV5o82ClZWlWiSWZwy6ypa7CuT1PEGHzywB4CZ5ucpO60Z7hnBQxHLiAQIO/QhiBp1rmrdQZFN6PUEjFDloykoeHe345Yqy9Ke95HIKUCS9yJurD+nZjjgOxZjoFCsB1hQAwINTIS3FbYOibZnQwv8PXvcSOqVZxC9U0+WuagK7IwxzhGZY3vLRrX01oujiRrevB4xbW7Oxi/Agp7CQGlJXCgmRE8Rhm+Vj2s+wc/4VLNZRHDcwtfejogjrjdi8p6nfUyqoQRRPARzRGUnnCbh+LqhigT6gQf3sVilnydMRScEc0/YYNLWnaw9nbyBa7wFBAiGbJwO40k39wj+xT6HTSbSUgFZzopxroO3f/o4+ubx2+IL3fkev22mEN38+dFmYF3zE+hpE7jVxrJpC3EP9PLoFgFPKCuctMnjXmeHoiGs756N5r1Mm1ffZu4H19MSuALJlxQR7VXE/LzxRXDuaB2u9days/6muP6gbGX1ASxbJd/ou8+viHmSC/ioHzNjItVCPaJjDyc6bv+gs1NPCt0qZ69G+JmgHW/PsMMeL4n5bh74g0fJSHqiI9ewEmOG/8bedSREv2XXtKV39STxPweceIOh0k23s3N6+wvuSUAJE7u1LkDo14cobtZ/MCw/QhimYPd1u5HnEJvRhPxz0nVPz0QqL/YQeOkAYk7uzgeb2yPzJ6DBtnTnGDkglekhVzQBFRJdk740LEj6swkJ",
|
||||
"sig":"c94e74533b482aa8eeeb54ae72a5303e0b21f62909ca43c8ef06b0357412d6f8a92f96e1a205102753777fd25321a58fba3fb384eee114bd53ce6c06a1c22bab"
|
||||
|
||||
31
44.md
31
44.md
@@ -84,10 +84,12 @@ NIP-44 version 2 has the following design characteristics:
|
||||
- Slice 76-byte HKDF output into: `chacha_key` (bytes 0..32), `chacha_nonce` (bytes 32..44), `hmac_key` (bytes 44..76)
|
||||
4. Add padding
|
||||
- Content must be encoded from UTF-8 into byte array
|
||||
- Validate plaintext length. Minimum is 1 byte, maximum is 65535 bytes
|
||||
- Validate plaintext length. Minimum is 1 byte, maximum is 4294967296 bytes
|
||||
- Padding format is: `[plaintext_length: u16][plaintext][zero_bytes]`
|
||||
- Padding algorithm is related to powers-of-two, with min padded msg size of 32 bytes
|
||||
- Plaintext length is encoded in big-endian as first 2 bytes of the padded blob
|
||||
- Plaintext length is encoded in big-endian:
|
||||
- if smaller than 65536, as a u16 in the first 2 bytes of the padded blob;
|
||||
- if greater than 65536, the first 6 bytes of the padded blob, the first 2 being zero and the other 4 being the actual encoded length as u32
|
||||
5. Encrypt padded content
|
||||
- Use ChaCha20, with key and nonce from step 3
|
||||
6. Calculate MAC (message authentication code)
|
||||
@@ -124,7 +126,9 @@ validation rules, refer to BIP-340.
|
||||
6. Decrypt ciphertext
|
||||
- Use ChaCha20 with key and nonce from step 3
|
||||
7. Remove padding
|
||||
- Read the first two BE bytes of plaintext that correspond to plaintext length
|
||||
- Read the first 2 bytes,
|
||||
- if they're zero, read the next 4 bytes as the u32 big-endian plaintext length;
|
||||
- otherwise interpret those 2 bytes as the u16 plaintext length
|
||||
- Verify that the length of sliced plaintext matches the value of the two BE bytes
|
||||
- Verify that calculated padding from step 3 of the [encryption](#Encryption) process matches the actual padding
|
||||
|
||||
@@ -148,8 +152,6 @@ validation rules, refer to BIP-340.
|
||||
- `x[i:j]`, where `x` is a byte array and `i, j <= 0` returns a `(j - i)`-byte array with a copy of the
|
||||
`i`-th byte (inclusive) to the `j`-th byte (exclusive) of `x`.
|
||||
- Constants `c`:
|
||||
- `min_plaintext_size` is 1. 1 byte msg is padded to 32 bytes.
|
||||
- `max_plaintext_size` is 65535 (64kB - 1). It is padded to 65536 bytes.
|
||||
- Functions
|
||||
- `base64_encode(string)` and `base64_decode(bytes)` are Base64 ([RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648), with padding)
|
||||
- `concat` refers to byte array concatenation
|
||||
@@ -182,16 +184,27 @@ def calc_padded_len(unpadded_len):
|
||||
def pad(plaintext):
|
||||
unpadded = utf8_encode(plaintext)
|
||||
unpadded_len = len(plaintext)
|
||||
if (unpadded_len < c.min_plaintext_size or
|
||||
unpadded_len > c.max_plaintext_size): raise Exception('invalid plaintext length')
|
||||
prefix = write_u16_be(unpadded_len)
|
||||
if (unpadded_len < 1 or
|
||||
unpadded_len > 4294967295): raise Exception('invalid plaintext length')
|
||||
if unpadded_len > 65536:
|
||||
prefix = concat(
|
||||
[0, 0],
|
||||
write_u32_be(unpadded_len),
|
||||
)
|
||||
else:
|
||||
prefix = write_u16_be(unpadded_len)
|
||||
suffix = zeros(calc_padded_len(unpadded_len) - unpadded_len)
|
||||
return concat(prefix, unpadded, suffix)
|
||||
|
||||
# Converts padded bytearray to unpadded plaintext
|
||||
def unpad(padded):
|
||||
unpadded_len = read_uint16_be(padded[0:2])
|
||||
unpadded = padded[2:2+unpadded_len]
|
||||
if unpadded_len == 0:
|
||||
unpadded_len = read_uint32_be(padded[2:6])
|
||||
unpadded = padded[6:6+unpadded_len]
|
||||
else:
|
||||
unpadded = padded[2:2+unpadded_len]
|
||||
|
||||
if (unpadded_len == 0 or
|
||||
len(unpadded) != unpadded_len or
|
||||
len(padded) != 2 + calc_padded_len(unpadded_len)): raise Exception('invalid padding')
|
||||
|
||||
5
51.md
5
51.md
@@ -22,7 +22,6 @@ For example, _mute list_ can contain the public keys of spammers and bad actors
|
||||
|
||||
| name | kind | description | expected tag items |
|
||||
| --- | --- | --- | --- |
|
||||
| Follow list | 3 | microblogging basic follow list, see [NIP-02](02.md) | `"p"` (pubkeys -- with optional relay hint and petname) |
|
||||
| Mute list | 10000 | things the user doesn't want to see in their feeds | `"p"` (pubkeys), `"t"` (hashtags), `"word"` (lowercase string), `"e"` (threads) |
|
||||
| Pinned notes | 10001 | events the user intends to showcase in their profile page | `"e"` (kind:1 notes) |
|
||||
| Read/write relays | 10002 | where a user publishes to and where they expect mentions | see [NIP-65](65.md) |
|
||||
@@ -32,9 +31,7 @@ For example, _mute list_ can contain the public keys of spammers and bad actors
|
||||
| Blocked relays | 10006 | relays clients should never connect to | `"relay"` (relay URLs) |
|
||||
| Search relays | 10007 | relays clients should use when performing search queries | `"relay"` (relay URLs) |
|
||||
| Simple groups | 10009 | [NIP-29](29.md) groups the user is in | `"group"` ([NIP-29](29.md) group id + relay URL + optional group name), `"r"` for each relay in use |
|
||||
| Favorite relays | 10012 | user favorite relays and pointers to relay sets | `"relay"` (relay URLs) and `"a"` (kind:30002 relay set) |
|
||||
| Interests | 10015 | topics a user may be interested in and pointers | `"t"` (hashtags) and `"a"` (kind:30015 interest set) |
|
||||
| Media follows | 10020 | multimedia (photos, short video) follow list | `"p"` (pubkeys -- with optional relay hint and petname) |
|
||||
| Emojis | 10030 | user preferred emojis and pointers to emoji sets | `"emoji"` (see [NIP-30](30.md)) and `"a"` (kind:30030 emoji set) |
|
||||
| DM relays | 10050 | Where to receive [NIP-17](17.md) direct messages | `"relay"` (see [NIP-17](17.md)) |
|
||||
| Good wiki authors | 10101 | [NIP-54](54.md) user recommended wiki authors | `"p"` (pubkeys) |
|
||||
@@ -60,8 +57,6 @@ Aside from their main identifier, the `"d"` tag, sets can optionally have a `"ti
|
||||
| Emoji sets | 30030 | categorized emoji groups | `"emoji"` (see [NIP-30](30.md)) |
|
||||
| Release artifact sets | 30063 | group of artifacts of a software release | `"e"` (kind:1063 [file metadata](94.md) events), `"a"` (software application event) |
|
||||
| App curation sets | 30267 | references to multiple software applications | `"a"` (software application event) |
|
||||
| Starter packs | 39089 | a named set of profiles to be shared around with the goal of being followed together | `"p"` (pubkeys) |
|
||||
| Media starter packs | 39092 | same as above, but specific to multimedia (photos, short video) clients | `"p"` (pubkeys) |
|
||||
|
||||
### Deprecated standard lists
|
||||
|
||||
|
||||
12
52.md
12
52.md
@@ -25,7 +25,7 @@ The format uses an _addressable event_ of `kind:31922`.
|
||||
The `.content` of these events should be a detailed description of the calendar event. It is required but can be an empty string.
|
||||
|
||||
The list of tags are as follows:
|
||||
* `d` (required) a short unique string identifier. Generated by the client creating the calendar event.
|
||||
* `d` (required) universally unique identifier (UUID). Generated by the client creating the calendar event.
|
||||
* `title` (required) title 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`.
|
||||
@@ -46,7 +46,7 @@ The following tags are deprecated:
|
||||
"kind": 31922,
|
||||
"content": "<description of calendar event>",
|
||||
"tags": [
|
||||
["d", "<random-identifier>"],
|
||||
["d", "<UUID>"],
|
||||
|
||||
["title", "<title of calendar event>"],
|
||||
|
||||
@@ -84,7 +84,7 @@ The format uses an _addressable event_ kind `31923`.
|
||||
The `.content` of these events should be a detailed description of the calendar event. It is required but can be an empty string.
|
||||
|
||||
The list of tags are as follows:
|
||||
* `d` (required) a short unique string identifier. Generated by the client creating the calendar event.
|
||||
* `d` (required) universally unique identifier (UUID). Generated by the client creating the calendar event.
|
||||
* `title` (required) title 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.
|
||||
@@ -110,7 +110,7 @@ The following tags are deprecated:
|
||||
"kind": 31923,
|
||||
"content": "<description of calendar event>",
|
||||
"tags": [
|
||||
["d", "<random-identifier>"],
|
||||
["d", "<UUID>"],
|
||||
|
||||
["title", "<title of calendar event>"],
|
||||
["summary", "<brief description of the calendar event>"],
|
||||
@@ -167,7 +167,7 @@ The format uses a custom replaceable list of kind `31924` with a list of tags as
|
||||
"kind": 31924,
|
||||
"content": "<description of calendar>",
|
||||
"tags": [
|
||||
["d", "<random-identifier>"],
|
||||
["d", "<UUID>"],
|
||||
["title", "<calendar title>"],
|
||||
["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>"]
|
||||
@@ -215,7 +215,7 @@ The list of tags are as follows:
|
||||
"tags": [
|
||||
["e", "<kind 31922 or 31923 event id", "<optional recommended relay URL>"]
|
||||
["a", "<31922 or 31923>:<calendar event author pubkey>:<d-identifier of calendar event>", "<optional recommended relay URL>"],
|
||||
["d", "<random-identifier>"],
|
||||
["d", "<UUID>"],
|
||||
["status", "<accepted/declined/tentative>"],
|
||||
["fb", "<free/busy>"],
|
||||
["p", "<hex pubkey of kind 31922 or 31923 event>", "<optional recommended relay URL>"]
|
||||
|
||||
@@ -187,11 +187,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `10006` | Blocked relays list | [51](51.md) |
|
||||
| `10007` | Search relays list | [51](51.md) |
|
||||
| `10009` | User groups | [51](51.md), [29](29.md) |
|
||||
| `10012` | Favorite relays list | [51](51.md) |
|
||||
| `10013` | Private event relay list | [37](37.md) |
|
||||
| `10015` | Interests list | [51](51.md) |
|
||||
| `10019` | Nutzap Mint Recommendation | [61](61.md) |
|
||||
| `10020` | Media follows | [51](51.md) |
|
||||
| `10030` | User emoji list | [51](51.md) |
|
||||
| `10050` | Relay list to receive DMs | [51](51.md), [17](17.md) |
|
||||
| `10063` | User server list | [Blossom][blossom] |
|
||||
@@ -251,8 +249,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `34550` | Community Definition | [72](72.md) |
|
||||
| `38383` | Peer-to-peer Order events | [69](69.md) |
|
||||
| `39000-9` | Group metadata events | [29](29.md) |
|
||||
| `39089` | Starter packs | [51](51.md) |
|
||||
| `39092` | Media starter packs | [51](51.md) |
|
||||
| `39701` | Web bookmarks | [B0](B0.md) |
|
||||
|
||||
[NUD: Custom Feeds]: https://wikifreedia.xyz/cip-01/
|
||||
|
||||
Reference in New Issue
Block a user