Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-29: Simple Groups #566

Merged
merged 24 commits into from
Feb 28, 2024
Merged

NIP-29: Simple Groups #566

merged 24 commits into from
Feb 28, 2024

Conversation

fiatjaf
Copy link
Member

@fiatjaf fiatjaf commented May 28, 2023

@fiatjaf fiatjaf force-pushed the simple-chat-groups branch 3 times, most recently from ac63c7d to 5549a7f Compare May 28, 2023 15:37
@arthurfranca
Copy link
Contributor

arthurfranca commented May 28, 2023

I'm still reading this NIP. But I found this written: "relays will use NIP-42 AUTH messages to control who can read from it".

Can we first "fix" NIP-42 while it is not widespread? By "fix I mean new WebSocket("wss://...?authorization=stringified_22242_event") -> close the socket if authentication fail -> or register pubkey to ws instance (relay instance)

29.md Outdated Show resolved Hide resolved
29.md Outdated Show resolved Hide resolved
@arthurfranca
Copy link
Contributor

It seems relay owner is the only one who can create a group (39000 metadata) and set its admins (39001). So one willing to own a group has to spin up a relay for this.

Wouldn't it be better if there was an event for the user client to ask to be the owner of a group (so get all the roles, maybe also needs edit-admin-list role) that by default would be only accepted by the relay if there is no 39001 event yet for the group path? Maybe the same event could optionally fill group metadata value.

Well, we could use the same metadata event for this. If a metadata for the channel path doesn't exist yet, the relay uses it's pubkey to create the metadata copied from the user event and also applies all the roles to him with a 39001 event. So the first user to claim ownership, gets it.

@fiatjaf
Copy link
Member Author

fiatjaf commented May 29, 2023

Yes, I thought about something like that (users can create groups by sending metadata events to the relays), but for now I'm leaving it open. If people want to implement it that way we can add to the NIP, but in my mind it is working by relays having a page where you can go and fill a dumb form or something like that, then your group gets created and you are made the admin. Once that group exists you can create subgroups by sending commands (moderation event, maybe this should be renamed to "group action").

There is a moderation event tag for editing the group metadata already -- but these are just suggestions at this point, made to illustrate how this could work.

@starbackr-dev
Copy link
Contributor

I'm surprised to see this NIP, as we went down a similar path for a group chat application and noted a few requirements and challenges that needed to be addressed. @Egge7 and I are glad to work on this, adding content and even creating a reference app to see how it works. Here are my initial thoughts on the differences and improvements. We can debate and add/update the NIP.

The main requirement is the ability to move the group from one relay to another with the click of a button. For example, I started the "pizza.com/flavors" group today. I reached 50 members, and everyone is talking about ice cream and not pizza anymore. The pizza.com relay says I need to get off the pizza.com relay. I should be able to set up my own or go to icecream.com/flavors, stream all historical events, metadata from pizza.com, and notify members to start using the new one. A non-technical group admin should be able to do this.

To achieve the above, we used a single metadata event based on NIP-51 lists to store group info and user info, like combining 39000 and 39001. This is a replaceable event, so every user added or removed will trigger a new event signed by the relay.

There are only 2 user roles: Admin - who can do everything, and User - who can only read and write. In the future, the relay can enforce rules such as requiring admin majority to change the group name or other fine-grained access. However, this is out of scope for this NIP.

Event kind 9000 is good and that is how users and admin request changes. When a 9000 event is received by relay it will either create a new 39000 to replace the old one or reject back to the user with a message.

There are only 2 types of groups: Paid or Free. You pay the relay to first register and perform NIP-42 AUTH into the relay. Then, you see the list of groups and join a group if you wish. Your pubkey needs to be in the 39000 event of that group as a user or admin to see all the posts and write to it.

Subgroups like /flavors/pepperoni will not have their own users and roles. They will inherit them from /flavors. They are mainly used as filters within the group.

Group names are unique within a relay.

Admin/group creation flow:

Goto relay webpage.
register/pay to get access
Click add to create a group
Fill in metadata info, add initial users
create/sign event 9000 and submit it to relay.
Relay takes info and signs it with its key and creates event 39000 and provides a nostr: id that can be shared with users.

User flow

Click on nostr: link and it will open the relay registration page. If the user pubkey is already registered then it can NIP-42 Auth and provide the list of all groups.
If not, user can register/pay for the relay to get NIP42-Authed.
Relay will then provide a list of all 39000 events
In the list of groups, click any group and join.
See list of events and also post new messages in the group.

Out of scope

Private groups where the group members are not visible to outside world
Admins can be 1 or many but access level is same
Payment split between relay and group admins
Requiring admin majority (like 6 out of 10) to change some group metadata

@earonesty
Copy link
Contributor

earonesty commented Jun 1, 2023

we're using nip-28 for public and optionally authenticated group chat, which basically does the same thing. except it doesn't say to use 1 relay. that's up to the user. i see no reason not to leave that as-is. i think nostr-chat uses nip-28 too. maybe this should just be a small modification of nip28 (recommend auth, say you can use 1 relay)?

@AtlantisPleb
Copy link
Contributor

AtlantisPleb commented Jun 1, 2023

Unclear why this is separate from NIP28 which already handles public (non-encrypted) multi-user chat channels.

Group membership can easily be added as optional kinds using kinds 45-49 which had previously been reserved for extending 28 and which are still available.

Having two non-encrypted chat NIPs seems duplicative and confusing.

Ideally any new group chat NIP would be an encrypted group chat NIP.

@starbackr-dev
Copy link
Contributor

I think the issue is not with Kind numbers. I think we need both NIP28 & 29. NIP28 is open to all multi-relay groups without permissions while NIP29 is moderated open or closed groups with group user tracking. Since we need to track add/remove users we need a kind in the 30000--39999 for Parameterized Replaceable Events

Having two non-encrypted chat NIPs seems duplicative and confusing.

Since the kind numbers are different they won't be duplicative. Clients can even support both at the same time.

@fiatjaf
Copy link
Member Author

fiatjaf commented Jun 1, 2023

This is not about adding new features. The approaches are completely different. NIP-28 is explicitly designed for purely client-side state management, while this is about delegating everything to the relay. From this small change many others ensue in a way that compatibility isn't possible. I've thought a lot about fitting this into NIP-28, but ultimately decided it isn't possible.

@staab
Copy link
Member

staab commented Jun 1, 2023

@fiatjaf did you see my blog post this morning?

I am now of the opinion that all the features to make groups already exist and this NIP is redundant. That's not to say my idea is the correct one, but @pablof7z seems to be thinking along the same lines. Certain things in this NIP are red flags for me, particularly the group admins bit where you re-define a bunch of functionality that already exists for an individual pubkey. I.e. add-user/ban-user are just special purpose NIP 51 events; add-metadata is just a kind 0. Broadening the concept of pubkeys to cover entities other than individuals seems like an elegant solution to the problem. 100% private (including metadata) groups are easy to build in that model too using the gift wrap proposal.

@arthurfranca
Copy link
Contributor

I see on nostr telegram group that people are pointing out the fact that NIP-28 could be updated to have all these features.

They aren't wrong. Admins sending actions like add-user and add-permission on NIP-29 are merely asking the chat owner account (in this case the relay account) to sign some events for them.

The "difference" is that the relay account is always online but, if you think about it, nothing prevents NIP-28 chat owner account to be always online using a client that will automatically act on the same above mentioned actions.

The delete-message action is the only one that currently isn't possible for NIP-28 owner to act on. But it could easily be made possible.

@fiatjaf
Copy link
Member Author

fiatjaf commented Jun 2, 2023

The "difference" is that the relay account is always online but, if you think about it, nothing prevents NIP-28 chat owner account to be always online using a client that will automatically act on the same above mentioned actions.

The difference is that the relay can actually enforce the moderation actions. How can a client prevent others from sending messages to a relay that doesn't care, for example?

Yes, your authorized pubkey deletion tag came to my mind too, but why would people voluntarily give deletion rights to their posts to others? Most people don't want to have their stuff deleted. Even if you could come up with a way to make it work (well, you can, like NIP-28, just filter everything on the client side) it would be complicated and slow.

@fiatjaf
Copy link
Member Author

fiatjaf commented Jun 2, 2023

@staab I think you are coming from a different place. These ideas you mention are good for actually distributed/decentralized environments. But chat groups are very centralized by nature, so this NIP is an attempt to embrace that and make it into a feature.

@arthurfranca
Copy link
Contributor

why would people voluntarily give deletion rights to their posts to others?

The chat client should load just chat messages that contain the tag ['!', <chat_owner_pubkey>]. So if user send messages without that tag, they will not show up to anyone using said client.

@AtlantisPleb
Copy link
Contributor

Asked my pal Claude to revise NIP-28 to incorporate ideas from 29. Not perfect, but directionally accurate?

This NIP defines new event kinds for public chat channels, private group channels, channel messages, and basic client-side moderation as well as relay-based access control and moderation.

For public channels (40-44), moderation is client-centric, giving clients discretion over content they want to include. For private groups (45-49), relays enforce access control and moderation actions.

40: Create public channel
41: Set public channel metadata
42: Send message to public channel
43: Hide public message (client-side)
44: Mute public user (client-side)
45: Create private group channel
46: Set private group channel metadata
47: Add user to private group (relay-enforced)
48: Remove user from private group (relay-enforced)
49: Delete message from private group (relay-enforced)

In this case 28 would cover all public (non-encrypted) chat, encompassing client-centric and relay-authoritative models, and 29 we could use for "simple encrypted group chat" (draft NIP in a day or two)

@fiatjaf
Copy link
Member Author

fiatjaf commented Jun 3, 2023

@ArcadeCityMayor your proposal there seems to be just to take whatever is in NIP-29 and shove into NIP-28.

@earonesty
Copy link
Contributor

earonesty commented Jun 3, 2023

see https://github.com/ArcadeLabsInc/arcade/wiki/NIP-112:-Encrypted-Group-Chat for metadata clean encrypted group chat using NIP44, NIP28, NIP59, and optional "forward secrecy"

this is the model we're using and the app is live and seems to work pretty well

trusting a single relay seems like it isn't nostr . it's something else

@AtlantisPleb
Copy link
Contributor

@ArcadeCityMayor your proposal there seems to be just to take whatever is in NIP-29 and shove into NIP-28.

Sure. NIP-28 already enables "simple group chat", so if there's a feature like relay-authoritative channel membership worth adding, it seems appropriate to extend the existing chat NIP than create a separate one.

If there's a good argument for a new separate NIP, I'd like to hear it.

@starbackr-dev
Copy link
Contributor

starbackr-dev commented Jun 5, 2023

Over the weekend I started modifying nostream relay code base to support this NIP-29 to see how it is working. Instead of simply debating which one is better, I prefer DIY. I noted down few changes to make it easier and simple to implement.

Here's the summary

  1. Make event kind 9000 as mandatory and have the relay store them for history. This makes it easier for a backup relay that ingest all 9000 events every 12 hours and confirm the 39000 event matches with the main relay. This is helpful in case main relay goes down or goes rogue. We can also add a "nonce" which is a number that increments from 1 to n... to order them or even include the id of previous event in the next event as tag and make it a blockchain... (Just kidding...)

  2. Added 'p' tag to 39001 event

{
  "kind": 39001,
  "content": "",
  "tags": [
    ["d", "/flavors"],
    ["p", "<pubkey1-as-hex>", "role1", "role2"...],
    ["p", "<pubkey2-as-hex>", "role1", "role2"...]
  ]
  ...
}
  1. Role 1 should have a minimum of two types such as "admin" and "user" where admin can modify metadata and users cannot. Fine grained controls can be added after role 1 to further define the user fine grained controls.
[ "p", "<pubkey1-as-hex>", "role1", "role2"...],

"pubkey1-as-hex" and "role 1" are mandatory
role2 and above are optional.

  1. For event 9000, there are only 3 types of actions. "add", "remove", "change".
{
  "kind": 9000,
  "content": "action description and/or reason",
  "tags": [
    ["g", "/flavors", "pizza.com"],
    ["action", "add", "<pubkey-to-add>", "user"],
    ["action", "remove", "<pubkey-to-remove>"],
    ["action", "change", "<pubkey-to-remove>", "admin"],  //change user role
    ["action", "change", "name",  "Iceream lovers"],  //if name need to change
    ["action", "change", "picture", "https://pizza.com/pizza2.png"],  
,
  ]
}
  1. In kind 39000, Make read/write explicit with default public & closed. which is similar to Telegram.
  {
    "kind": 39000,
    "content": "a nip-29 chat group for debating pizza flavors and other topics",
    "tags": [
      ["d", "/flavors"],
      ["name", "Pizza Lovers"],
      ["picture", "https://pizza.com/pizza.png"],
      ["read", "public" | "private"],  //default public
      ["write", "closed" | "open"],  //default closed

    ]
    ...
  }

All changes are documented here as well.

https://github.com/starbackr-dev/nips/blob/patch-1/29.md

@earonesty
Copy link
Contributor

yes, centralized systems are often easier to build quickly and maintain.

@starbackr-dev
Copy link
Contributor

yes, centralized systems are often easier to build quickly and maintain.

What if we can have best of both worlds.? Relay authority model will mimic centralized systems but since it is at the protocol level, you can easily pack and move to a different relay or host your own?

@arthurfranca
Copy link
Contributor

Regarding ["private"], // means the group cannot be read and relays will use NIP-42 AUTH messages to control who can read from it...

Would it be completly absurd asking for this behavior becoming generic (a separate NIP) so that other NIPs such as NIP-172 and NIP-28 could use it? This way there is no need for encrypted chats complexity for something not so serious (?) like private facebook-like groups or live stream chats.

Like all chat related events that want supporting relay to whitelist reading using a list of user pubkeys and NIP-42(or 43 xD) could add a private tag like:

{
  "kind": 9, // just chat related subset of kinds?
  "content": "hello my friends lovers of pizza",
  "tags": [
    ["g", "/flavors", "pizza.com"],
    ["private", "39001:pubkey:d-id"] // consider just the "p" tags from this parameterized event
  ]
  ...
}

Then specialized chat client would read a ["private", "39001:pubkey:d-id"] tag from the chat metadata event (different event kind for each chat NIP) and auto add it to the chat related events.

@fiatjaf fiatjaf merged commit 5b2461e into master Feb 28, 2024
@vitorpamplona
Copy link
Collaborator

Who is implementing this? I need to test my code.

@fiatjaf
Copy link
Member Author

fiatjaf commented Feb 28, 2024

https://groups.fiatjaf.com/ is a public relay.
https://chat29.pages.dev/ is a public chat client.

@pablof7z and @lovvtide are working on separate implementations, but I think they haven't released them yet.

@pablof7z
Copy link
Member

pablof7z commented Feb 28, 2024

https://groups.fiatjaf.com/ is a public relay.

https://chat29.pages.dev/ is a public chat client.

@pablof7z and @lovvtide are working on separate implementations, but I think they haven't released them yet.

Mine is released, just unannounced but it's live and working but you gotta pay to join 😂

@sepehr-safari
Copy link
Contributor

(To create a new group you'll have to do it through the relay webpage for now.)

I don't understand why are we creating new groups outside of the Nostr? (through REST API calls)
isn't it better to replace API calls with some kind of ephemeral events between client and relay?
@fiatjaf

@fiatjaf
Copy link
Member Author

fiatjaf commented Apr 4, 2024

isn't it better to replace API calls with some kind of ephemeral events between client and relay?

we could do that, but I don't think it's necessarily better.

@pablof7z
Copy link
Member

pablof7z commented Apr 4, 2024

Are you referring to the rest thing on the relay29 implementation? I don't do those API calls and I'm against them, I just create the group when the owner says they want to add a member (e.g. themselves)

@sepehr-safari
Copy link
Contributor

what is obvious is that at first we need a reasonable way to create the group, then we can do other moderation stuff.
to keep things consistent and predictable, we may consider adding another "moderation action" (e.g. create-group) with a specific kind (e.g. 9010), so then we can execute other actions like add-user.

@fiatjaf
Copy link
Member Author

fiatjaf commented Apr 5, 2024

I just create the group when the owner says they want to add a member

If I'm not mistaken relay29 creates a group when the relay owner publishes a group metadata event or a group admins event, something like that.

the rest thing

An HTML form on a web page is not "rest".

I don't do those API calls and I'm against them

Nor is it an API.

The thing is that I don't want some automated way for any random person to create a group on my relay, I want the friction of having them go to the web page and click (which, I grant you, is not a lot of friction nor something that can't be automated). If someone wants to host a relay that anyone can create a group in then yes, we can have an event for that.

I think allowing anyone to publish a group metadata to inaugurate a group is more than enough. Or what Pablo does with groups that centered on user pubkeys.

@pablof7z
Copy link
Member

pablof7z commented Apr 5, 2024

I think allowing anyone to publish a group metadata to inaugurate a group is more than enough. Or what Pablo does with groups that centered on user pubkeys.
This. I don't think this needs to be complicated at all. If a relay operator wants to whitelist in some way who can create a group, that's perfectly fine, but we shouldn't mandate that in any nip as it can be done out of band in whatever way the relay chooses.

E.g. If a user sends an edit-metadata event and the relay wants to get paid or have a stupid captcha it could reject the event with an OK that gives a URL where the conditions are detailed.

@staab staab mentioned this pull request Apr 18, 2024
6 tasks
@AndrewRyanChama
Copy link

I'm a bit of a beginner so I may be wrong, but I'm seeing a few issues with this nip as currently specified:

relay keypair: This is introducing the concept of a relay keypair, doesn't seem to be part of any other nips. There isn't any way for clients to associate this keypair with the relay itself, so there's nothing for clients to verify this signature against.

Interaction with unsupported relays: This nip is optional for relays to implement, but clients have no way to know if a relay supports nip29. If someone sends 9xxx events to a relay that doesn't support nip29, then clients will believe those are valid nip29 groups, when they are in fact not

Centralization of event transmission: If someone sends an event (kind 9-11) with an h tag to a relay with no nip29 support, it will be passed on irregardless of the group membership rules. Clients subscribed to that relay may get that event if it incidentally matches any related filters, such as a filter for kind 11 from a particular user. So a client may receive the kind 11 event even though it was never checked.
In order to be compliant with nip29, a client must also filter out all events with an h tag that didn't come from a specific relay. This introduces a path dependence, where the same exact event with the same exact signature may be good or garbage, depending on which websocket it came from, which is something that doesn't seem to be present in any other nip.

How to fork a group: This nip calls for a way for a group to be forkable to a different relay while keeping history, but I'm not sure how this is supposed to work. Each kind 11 has the h tag pointing to the original group id, so I don't see any way for them to be associated with a new group.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet