upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/29.md
blob: 6232f8b65d2a9b61d70c7f56ac0453c59b985358 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
NIP-29
======

Relay-based Groups
------------------

`draft` `optional`

This NIP defines a standard for groups that are only writable by a closed set of users. They can be public for reading by external users or not.

Groups are identified by a random string of any length that serves as an _id_.

There is no way to create a group, what happens is just that relays (most likely when asked by users) will create rules around some specific ids so these ids can serve as an actual group, henceforth messages sent to that group will be subject to these rules.

Normally a group will originally belong to one specific relay, but the community may choose to move the group to other relays or even fork the group so it exists in different forms -- still using the same _id_ -- across different relays.

## Relay-generated events

Relays are supposed to generate the events that describe group metadata and group admins. These are _addressable_ events signed by the relay keypair directly, with the group _id_ as the `d` tag.

## Group identifier

A group may be identified by a string in the format `<host>'<group-id>`. For example, a group with _id_ `abcdef` hosted at the relay `wss://groups.nostr.com` would be identified by the string `groups.nostr.com'abcdef`.

## The `h` tag

Events sent by users to groups (chat messages, text notes, moderation events etc) must have an `h` tag with the value set to the group _id_.

## Timeline references

In order to not be used out of context, events sent to these groups may contain references to previous events seen from the same relay in the `previous` tag. The choice of which previous events to pick belongs to the clients. The references are to be made using the first 8 characters (4 bytes) of any event in the last 50 events seen by the user in the relay, excluding events by themselves. There can be any number of references (including zero), but it's recommended that clients include at least 3 and that relays enforce this.

This is a hack to prevent messages from being broadcasted to external relays that have forks of one group out of context. Relays are expected to reject any events that contain timeline references to events not found in their own database. Clients should also check these to keep relays honest about them.

## Late publication

Relays should prevent late publication (messages published now with a timestamp from days or even hours ago) unless they are open to receive a group forked or moved from another relay.

## Event definitions

- *text root note* (`kind:11`)

This is the basic unit of a "microblog" root text note sent to a group.

```jsonc
  "kind": 11,
  "content": "hello my friends lovers of pizza",
  "tags": [
    ["h", "<group-id>"],
    ["previous", "<event-id-first-chars>", "<event-id-first-chars>", /*...*/]
  ]
  // other fields...
```

- *threaded text reply* (`kind:12`)

This is the basic unit of a "microblog" reply note sent to a group. It's the same as `kind:11`, except for the fact that it must be used whenever it's in reply to some other note (either in reply to a `kind:11` or a `kind:12`). `kind:12` events SHOULD use NIP-10 markers, leaving an empty relay url:

* `["e", "<kind-11-root-id>", "", "root"]`
* `["e", "<kind-12-event-id>", "", "reply"]`

- *chat message* (`kind:9`)

This is the basic unit of a _chat message_ sent to a group.

```jsonc
  "kind": 9,
  "content": "hello my friends lovers of pizza",
  "tags": [
    ["h", "<group-id>"],
    ["previous", "<event-id-first-chars>", "<event-id-first-chars>", /*...*/]
  ]
  // other fields...
```

- *chat message threaded reply* (`kind:10`)

Similar to `kind:12`, this is the basic unit of a chat message sent to a group. This is intended for in-chat threads that may be hidden by default. Not all in-chat replies MUST use `kind:10`, only when the intention is to create a hidden thread that isn't part of the normal flow of the chat (although clients are free to display those by default too).

`kind:10` SHOULD use NIP-10 markers, just like `kind:12`.

- *join request* (`kind:9021`)

Any user can send one of these events to the relay in order to be automatically or manually added to the group. If the group is `open` the relay will automatically issue a `kind:9000` in response adding this user. Otherwise group admins may choose to query for these requests and act upon them.

```json
{
  "kind": 9021,
  "content": "optional reason",
  "tags": [
    ["h", "<group-id>"]
  ]
}
```

- *leave request* (`kind:9022`)

Any user can send one of these events to the relay in order to be automatically removed from the group. The relay will automatically issue a `kind:9001` in response removing this user.

```json
{
  "kind": 9022,
  "content": "optional reason",
  "tags": [
    ["h", "<group-id>"]
  ]
}
```

- *moderation events* (`kinds:9000-9020`) (optional)

Clients can send these events to a relay in order to accomplish a moderation action. Relays must check if the pubkey sending the event is capable of performing the given action. The relay may discard the event after taking action or keep it as a moderation log.

```json
{
  "kind": 90xx,
  "content": "optional reason",
  "tags": [
    ["h", "<group-id>"],
    ["previous", /*...*/]
  ]
}
```

Each moderation action uses a different kind and requires different arguments, which are given as tags. These are defined in the following table:

| kind | name                | tags                                      |
| ---  | ---                 | ---                                       |
| 9000 | `add-user`          | `p` (pubkey hex)                          |
| 9001 | `remove-user`       | `p` (pubkey hex)                          |
| 9002 | `edit-metadata`     | `name`, `about`, `picture` (string)       |
| 9003 | `add-permission`    | `p` (pubkey), `permission` (name)         |
| 9004 | `remove-permission` | `p` (pubkey), `permission` (name)         |
| 9005 | `delete-event`      | `e` (id hex)                              |
| 9006 | `edit-group-status` | `public` or `private`, `open` or `closed` |
| 9007 | `create-group`      |                                           |
| 9008 | `delete-group`      |                                           |

- *group metadata* (`kind:39000`) (optional)

This event defines the metadata for the group -- basically how clients should display it. It must be generated and signed by the relay in which is found. Relays shouldn't accept these events if they're signed by anyone else.

If the group is forked and hosted in multiple relays, there will be multiple versions of this event in each different relay and so on.

```jsonc
{
  "kind": 39000,
  "content": "",
  "tags": [
    ["d", "<group-id>"],
    ["name", "Pizza Lovers"],
    ["picture", "https://pizza.com/pizza.png"],
    ["about", "a group for people who love pizza"],
    ["public"], // or ["private"]
    ["open"] // or ["closed"]
  ]
  // other fields...
}
```

`name`, `picture` and `about` are basic metadata for the group for display purposes. `public` signals the group can be _read_ by anyone, while `private` signals that only AUTHed users can read. `open` signals that anyone can request to join and the request will be automatically granted, while `closed` signals that members must be pre-approved or that requests to join will be manually handled.

- *group admins* (`kind:39001`) (optional)

Similar to the group metadata, this event is supposed to be generated by relays that host the group.

Each admin gets a label that is only used for display purposes, and a list of permissions it has are listed afterwards. These permissions can inform client building UI, but ultimately are evaluated by the relay in order to become effective.

The list of capabilities, as defined by this NIP, for now, is the following:

- `add-user`
- `edit-metadata`
- `delete-event`
- `remove-user`
- `add-permission`
- `remove-permission`
- `edit-group-status`
- `delete-group`

```json
{
  "kind": 39001,
  "content": "list of admins for the pizza lovers group",
  "tags": [
    ["d", "<group-id>"],
    ["p", "<pubkey1-as-hex>", "ceo", "add-user", "edit-metadata", "delete-event", "remove-user"],
    ["p", "<pubkey2-as-hex>", "secretary", "add-user", "delete-event"]
  ]
  // other fields...
}
```

- *group members* (`kind:39002`) (optional)

Similar to *group admins*, this event is supposed to be generated by relays that host the group.

It's a NIP-51-like list of pubkeys that are members of the group. Relays might choose to not to publish this information or to restrict what pubkeys can fetch it.

```json
{
  "kind": 39002,
  "content": "list of members for the pizza lovers group",
  "tags": [
    ["d", "<group-id>"],
    ["p", "<admin1>"],
    ["p", "<member-pubkey1>"],
    ["p", "<member-pubkey2>"],
  ]
}
```

## Storing the list of groups a user belongs to

A definition for kind `10009` was included in [NIP-51](51.md) that allows clients to store the list of groups a user wants to remember being in.