diff options
Diffstat (limited to '17.md')
| -rw-r--r-- | 17.md | 52 |
1 files changed, 31 insertions, 21 deletions
| @@ -6,7 +6,7 @@ Private Direct Messages | |||
| 6 | 6 | ||
| 7 | `draft` `optional` | 7 | `draft` `optional` |
| 8 | 8 | ||
| 9 | This NIP defines an encrypted direct messaging scheme using [NIP-44](44.md) encryption and [NIP-59](59.md) seals and gift wraps. | 9 | This NIP defines an encrypted direct messaging scheme using [NIP-44](44.md) encryption and [NIP-59](59.md) seals and gift wraps. |
| 10 | 10 | ||
| 11 | ## Direct Message Kind | 11 | ## Direct Message Kind |
| 12 | 12 | ||
| @@ -18,7 +18,7 @@ Kind `14` is a chat message. `p` tags identify one or more receivers of the mess | |||
| 18 | "pubkey": "<sender-pubkey>", | 18 | "pubkey": "<sender-pubkey>", |
| 19 | "created_at": now(), | 19 | "created_at": now(), |
| 20 | "kind": 14, | 20 | "kind": 14, |
| 21 | "tags": [ | 21 | "tags": [ |
| 22 | ["p", "<receiver-1-pubkey>", "<relay-url>"], | 22 | ["p", "<receiver-1-pubkey>", "<relay-url>"], |
| 23 | ["p", "<receiver-2-pubkey>", "<relay-url>"], | 23 | ["p", "<receiver-2-pubkey>", "<relay-url>"], |
| 24 | ["e", "<kind-14-id>", "<relay-url>", "reply"] // if this is a reply | 24 | ["e", "<kind-14-id>", "<relay-url>", "reply"] // if this is a reply |
| @@ -29,19 +29,19 @@ Kind `14` is a chat message. `p` tags identify one or more receivers of the mess | |||
| 29 | } | 29 | } |
| 30 | ``` | 30 | ``` |
| 31 | 31 | ||
| 32 | `.content` MUST be plain text. Fields `id` and `created_at` are required. | 32 | `.content` MUST be plain text. Fields `id` and `created_at` are required. |
| 33 | 33 | ||
| 34 | Tags that mention, quote and assemble threading structures MUST follow [NIP-10](10.md). | 34 | Tags that mention, quote and assemble threading structures MUST follow [NIP-10](10.md). |
| 35 | 35 | ||
| 36 | Kind `14`s MUST never be signed. If it is signed, the message might leak to relays and become **fully public**. | 36 | Kind `14`s MUST never be signed. If it is signed, the message might leak to relays and become **fully public**. |
| 37 | 37 | ||
| 38 | ## Chat Rooms | 38 | ## Chat Rooms |
| 39 | 39 | ||
| 40 | The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or a current one is removed, a new room is created with clean message history. | 40 | The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or a current one is removed, a new room is created with clean message history. |
| 41 | 41 | ||
| 42 | Clients SHOULD render messages of the same room in a continuous thread. | 42 | Clients SHOULD render messages of the same room in a continuous thread. |
| 43 | 43 | ||
| 44 | 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. | 44 | 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. |
| 45 | 45 | ||
| 46 | ## Encrypting | 46 | ## Encrypting |
| 47 | 47 | ||
| @@ -51,7 +51,7 @@ Following [NIP-59](59.md), the **unsigned** `kind:14` chat message must be seale | |||
| 51 | { | 51 | { |
| 52 | "id": "<usual hash>", | 52 | "id": "<usual hash>", |
| 53 | "pubkey": randomPublicKey, | 53 | "pubkey": randomPublicKey, |
| 54 | "created_at": randomTimeUpTo2DaysInThePast(), | 54 | "created_at": randomTimeUpTo2DaysInThePast(), |
| 55 | "kind": 1059, // gift wrap | 55 | "kind": 1059, // gift wrap |
| 56 | "tags": [ | 56 | "tags": [ |
| 57 | ["p", receiverPublicKey, "<relay-url>"] // receiver | 57 | ["p", receiverPublicKey, "<relay-url>"] // receiver |
| @@ -60,7 +60,7 @@ Following [NIP-59](59.md), the **unsigned** `kind:14` chat message must be seale | |||
| 60 | { | 60 | { |
| 61 | "id": "<usual hash>", | 61 | "id": "<usual hash>", |
| 62 | "pubkey": senderPublicKey, | 62 | "pubkey": senderPublicKey, |
| 63 | "created_at": randomTimeUpTo2DaysInThePast(), | 63 | "created_at": randomTimeUpTo2DaysInThePast(), |
| 64 | "kind": 13, // seal | 64 | "kind": 13, // seal |
| 65 | "tags": [], // no tags | 65 | "tags": [], // no tags |
| 66 | "content": nip44Encrypt(unsignedKind14, senderPrivateKey, receiverPublicKey), | 66 | "content": nip44Encrypt(unsignedKind14, senderPrivateKey, receiverPublicKey), |
| @@ -72,17 +72,17 @@ Following [NIP-59](59.md), the **unsigned** `kind:14` chat message must be seale | |||
| 72 | } | 72 | } |
| 73 | ``` | 73 | ``` |
| 74 | 74 | ||
| 75 | The encryption algorithm MUST use the latest version of [NIP-44](44.md). | 75 | The encryption algorithm MUST use the latest version of [NIP-44](44.md). |
| 76 | 76 | ||
| 77 | Clients MUST verify if pubkey of the `kind:13` is the same pubkey on the `kind:14`, otherwise any sender can impersonate others by simply changing the pubkey on `kind:14`. | 77 | Clients MUST verify if pubkey of the `kind:13` is the same pubkey on the `kind:14`, otherwise any sender can impersonate others by simply changing the pubkey on `kind:14`. |
| 78 | 78 | ||
| 79 | 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. | 79 | 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. |
| 80 | 80 | ||
| 81 | 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. | 81 | 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. |
| 82 | 82 | ||
| 83 | 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 | 83 | 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 |
| 84 | 84 | ||
| 85 | ## Publishing | 85 | ## Publishing |
| 86 | 86 | ||
| 87 | Kind `10050` indicates the user's preferred relays to receive DMs. The event MUST include a list of `relay` tags with relay URIs. | 87 | Kind `10050` indicates the user's preferred relays to receive DMs. The event MUST include a list of `relay` tags with relay URIs. |
| 88 | 88 | ||
| @@ -98,16 +98,22 @@ Kind `10050` indicates the user's preferred relays to receive DMs. The event MUS | |||
| 98 | } | 98 | } |
| 99 | ``` | 99 | ``` |
| 100 | 100 | ||
| 101 | Clients SHOULD publish kind `14` events to the `10050`-listed relays, falling back to `read` relays of [NIP-65](65.md) if `kind:10050` is not available. | 101 | Clients SHOULD publish kind `14` events to the `10050`-listed relays. If that is not found that indicates the user is not ready to receive messages under this NIP and clients shouldn't try. |
| 102 | |||
| 103 | ## Relays | ||
| 104 | |||
| 105 | It's advisable that relays do not serve `kind:14` to clients other than the ones tagged in them. | ||
| 106 | |||
| 107 | It's advisable that users choose relays that conform to these practices. | ||
| 102 | 108 | ||
| 103 | Clients SHOULD guide users to keep `kind:10050` lists small (1-3 relays) and SHOULD spread it to as many relays as viable. | 109 | Clients SHOULD guide users to keep `kind:10050` lists small (1-3 relays) and SHOULD spread it to as many relays as viable. |
| 104 | 110 | ||
| 105 | ## Benefits & Limitations | 111 | ## Benefits & Limitations |
| 106 | 112 | ||
| 107 | This NIP offers the following privacy and security features: | 113 | This NIP offers the following privacy and security features: |
| 108 | 114 | ||
| 109 | 1. **No Metadata Leak**: Participant identities, each message's real date and time, event kinds, and other event tags are all hidden from the public. Senders and receivers cannot be linked with public information alone. | 115 | 1. **No Metadata Leak**: Participant identities, each message's real date and time, event kinds, and other event tags are all hidden from the public. Senders and receivers cannot be linked with public information alone. |
| 110 | 2. **No Public Group Identifiers**: There is no public central queue, channel or otherwise converging identifier to correlate or count all messages in the same group. | 116 | 2. **No Public Group Identifiers**: There is no public central queue, channel or otherwise converging identifier to correlate or count all messages in the same group. |
| 111 | 3. **No Moderation**: There are no group admins: no invitations or bans. | 117 | 3. **No Moderation**: There are no group admins: no invitations or bans. |
| 112 | 4. **No Shared Secrets**: No secret must be known to all members that can leak or be mistakenly shared | 118 | 4. **No Shared Secrets**: No secret must be known to all members that can leak or be mistakenly shared |
| 113 | 5. **Fully Recoverable**: Messages can be fully recoverable by any client with the user's private key | 119 | 5. **Fully Recoverable**: Messages can be fully recoverable by any client with the user's private key |
| @@ -115,13 +121,17 @@ This NIP offers the following privacy and security features: | |||
| 115 | 7. **Uses Public Relays**: Messages can flow through public relays without loss of privacy. Private relays can increase privacy further, but they are not required. | 121 | 7. **Uses Public Relays**: Messages can flow through public relays without loss of privacy. Private relays can increase privacy further, but they are not required. |
| 116 | 8. **Cold Storage**: Users can unilaterally opt-in to sharing their messages with a separate key that is exclusive for DM backup and recovery. | 122 | 8. **Cold Storage**: Users can unilaterally opt-in to sharing their messages with a separate key that is exclusive for DM backup and recovery. |
| 117 | 123 | ||
| 118 | The main limitation of this approach is having to send a separate encrypted event to each receiver. Group chats with more than 100 participants should find a more suitable messaging scheme. | 124 | The main limitation of this approach is having to send a separate encrypted event to each receiver. Group chats with more than 100 participants should find a more suitable messaging scheme. |
| 119 | 125 | ||
| 120 | ---- | 126 | ## Implementation |
| 127 | |||
| 128 | Clients implementing this NIP should by default only connect to the set of relays found in their `kind:10050` list. From that they should be able to load all messages both sent and received as well as get new live updates, making it for a very simple and lightweight implementation that should be fast. | ||
| 129 | |||
| 130 | When sending a message to anyone, clients must then connect to the relays in the receiver's `kind:10050` and send the events there, but can disconnect right after unless more messages are expected to be sent (e.g. the chat tab is still selected). Clients should also send a copy of their outgoing messages to their own `kind:10050` relay set. | ||
| 121 | 131 | ||
| 122 | ## Examples | 132 | ## Examples |
| 123 | 133 | ||
| 124 | This example sends the message `Hola, que tal?` from `nsec1w8udu59ydjvedgs3yv5qccshcj8k05fh3l60k9x57asjrqdpa00qkmr89m` to `nsec12ywtkplvyq5t6twdqwwygavp5lm4fhuang89c943nf2z92eez43szvn4dt`. | 134 | This example sends the message `Hola, que tal?` from `nsec1w8udu59ydjvedgs3yv5qccshcj8k05fh3l60k9x57asjrqdpa00qkmr89m` to `nsec12ywtkplvyq5t6twdqwwygavp5lm4fhuang89c943nf2z92eez43szvn4dt`. |
| 125 | 135 | ||
| 126 | The two final GiftWraps, one to the receiver and the other to the sender, are: | 136 | The two final GiftWraps, one to the receiver and the other to the sender, are: |
| 127 | 137 | ||
| @@ -138,7 +148,7 @@ The two final GiftWraps, one to the receiver and the other to the sender, are: | |||
| 138 | "sig":"a3c6ce632b145c0869423c1afaff4a6d764a9b64dedaf15f170b944ead67227518a72e455567ca1c2a0d187832cecbde7ed478395ec4c95dd3e71749ed66c480" | 148 | "sig":"a3c6ce632b145c0869423c1afaff4a6d764a9b64dedaf15f170b944ead67227518a72e455567ca1c2a0d187832cecbde7ed478395ec4c95dd3e71749ed66c480" |
| 139 | } | 149 | } |
| 140 | ``` | 150 | ``` |
| 141 | 151 | ||
| 142 | ```json | 152 | ```json |
| 143 | { | 153 | { |
| 144 | "id":"162b0611a1911cfcb30f8a5502792b346e535a45658b3a31ae5c178465509721", | 154 | "id":"162b0611a1911cfcb30f8a5502792b346e535a45658b3a31ae5c178465509721", |
| @@ -151,4 +161,4 @@ The two final GiftWraps, one to the receiver and the other to the sender, are: | |||
| 151 | "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", | 161 | "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", |
| 152 | "sig":"c94e74533b482aa8eeeb54ae72a5303e0b21f62909ca43c8ef06b0357412d6f8a92f96e1a205102753777fd25321a58fba3fb384eee114bd53ce6c06a1c22bab" | 162 | "sig":"c94e74533b482aa8eeeb54ae72a5303e0b21f62909ca43c8ef06b0357412d6f8a92f96e1a205102753777fd25321a58fba3fb384eee114bd53ce6c06a1c22bab" |
| 153 | } | 163 | } |
| 154 | ``` | 164 | ``` |