nips/29.md
2024-02-23 20:52:12 -03:00

6.4 KiB

NIP-29

Relay-based Groups

draft optional author:fiatjaf

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 parameterized replaceable events signed by the relay keypair directly, with the group id as the d tag.

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.

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 must 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.

Trimmed signatures

Relays must strip the signature of messages in groups that are private so they do not leak.

Event definitions

  • text note (kind:11)

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

  "kind": 11,
  "content": "hello my friends lovers of pizza",
  "tags": [
    ["h", "<group-id>"],
    ["previous", "<event-id>", "<event-id>", ...]
  ]
  ...
  • chat message (kind:9)

Similar to kind:11, this is the basic unit of a chat message sent to a group.

  "kind": 9,
  "content": "hello my friends lovers of pizza",
  "tags": [
    ["h", "<group-id>"],
    ["previous", "<event-id>", "<event-id>", ...]
  ]
  ...
  • 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.

{
  "kind": 9021,
  "content": "optional reason",
  "tags": [
    ["h", "<group-id>"],
    ["alt", "optional action description"]
  ]
}
  • 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.

{
  "kind": 90xx,
  "content": "optional reason",
  "tags": [
    ["h", "<group-id>"],
    ["alt", "optional action description"],
    ["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
  • 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.

{
  "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"]
  ]
  ...
}

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.

The NIP-19 naddr pointer for this event including with a mandatory relay can be used as the canonical group identifier.

  • 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
{
  "kind": 39001,
  "content": "list of admins for the pizza lovers group",
  "tags": [
    ["d", "<group-id>"],
    ["<pubkey1-as-hex>", "ceo", "add-user", "edit-metadata", "delete-event", "remove-user"],
    ["<pubkey2-as-hex>", "secretary", "add-user", "delete-event"]
  ]
  ...
}