nips icon indicating copy to clipboard operation
nips copied to clipboard

Relationship status

Open vitorpamplona opened this issue 2 years ago • 27 comments

Uses unbound lists to create events that define the relationship between two pubkeys in a public or private manner.

Read here

vitorpamplona avatar Sep 04 '23 15:09 vitorpamplona

cc @Semisol

jb55 avatar Sep 04 '23 16:09 jb55

Will this allow for Alex Gleason set their relationship status to "it's complicated" with X?

alexgleason avatar Sep 04 '23 16:09 alexgleason

Previous discussion regarding contact list at #349 tldr: see "kind X follow (by @vitorpamplona)" section here

arthurfranca avatar Sep 04 '23 18:09 arthurfranca

@alexgleason I think NIP-32 may be the best way to declare public relationship statuses.

fiatjaf avatar Sep 07 '23 00:09 fiatjaf

There are so many jokes here that I don't know if this proposal has any legs 😅

vitorpamplona avatar Sep 07 '23 00:09 vitorpamplona

Most "Relationship Status" lists will have few items so NIP-51 would be enough. Hopefully I expect my unbounded list PR #784 to be at a good enough state to suggest holding some ever growing data like subscriber list.

@vitorpamplona Please take a look at this example I just added there:

https://github.com/nostr-protocol/nips/blob/8ae2b5d61b47c3fe9ca6781dd76ced1693a550e6/61.md?plain=1#L53-L87

arthurfranca avatar Sep 21 '23 13:09 arthurfranca

So, the goal for Relationship Status is that most of us have over 10,000 contacts (not friends, not follows, just contacts). And a list with 10,000 people is quite a heavy list to be updated all the time. That was the reason to start this.

Like, an email client, for instance, can have a status group for every person that sent you an e-mail. Instead of updating the list in every new e-mail and blasting all relays with it, the client just adds a Relationship Status event.

vitorpamplona avatar Sep 21 '23 13:09 vitorpamplona

So, with my unbounded list proposal (basically the n tag and the 33118 kind for "people") it could be like this:

{
  "kind": 33118,
  "tags": [
    ["d", "random6467362966154779"]
    ["n", "contacts"]
  ],
  "content": "<NIP-44 encrypted Stringified TAG-List([
    ["p", "91cf9..4e5ca", "wss://alicerelay.com/", "Alice"],
    ["status", `<Known Face, Contact, Following, Coworker,
      Friend, Partner, Family, Extended family, Trusted,
      Competitor, Traitor, Used to Know, Scammer, NSFW,
      Unkown, etc>`],
    ["summary", "<summary of the relationship>"],
    ["email", "[email protected]"]
  ])>",
  ...other fields
}

The difference is that you can later add the same entry simultaneously to another unbounded list editing it and adding a new n tag.

Want all contacts, search by the n tag and author.

Edit: the event is supposed to hold just one p tag (encrypted) so you add other stuff there like the email adress tag, or a separate summary tag. Edited the above example.

arthurfranca avatar Sep 21 '23 13:09 arthurfranca

@vitorpamplona Added you as author and also the "contacts" example there at #784 Please check it out.

arthurfranca avatar Sep 21 '23 14:09 arthurfranca

The difference is that you can later add the same entry simultaneously to another unbounded list editing it and adding a new n tag.

I am confused. What does it do? Why would I add the entry to another unbounded list?

vitorpamplona avatar Sep 21 '23 14:09 vitorpamplona

I would separate the status example from a people list example. Otherwise, you have to link each status tag with each p tag (since you can have multiple p-tags in kind: 33118

So, an unbound list allows a client to search for multiple n tags in the same kind, while here you would get the "unbound" list by just getting everything with kind:30382.

You could turn the status into the unbound event's n tag. Then you can group people into one or more unbound status lists while still being able to get a single person's status by filtering by kind:30382, p tag and pubkey.

Wouldn't that be the right way to do this?

vitorpamplona avatar Sep 21 '23 14:09 vitorpamplona

you can have multiple p-tags in kind: 33118

A kind 33118 event was meant to have a single p tag (I have recently edited the description pointing that out), because an unbounded people list (with a specific n tag) is made of one to many of these events. There is another example there with two p tags but it is the NIP-51 kind 30000 with an n tag.

You could turn the status into the unbound event's n tag... to get a single person's status by filtering by kind:30382, p tag and pubkey.

Hmm got it you want to have kind 30382 with a p tag unencrypted (to able to use on filter). I encrypted the n tag content to hide the info there (edit: so you would have to encrypt "known_face" before using on filter).

{
  "kind": 30382, // can fetch all contacts
  "tags": [
    ["d", "91cf9..4e5ca"]
    ["n", <NIP-44 encrypted("known_face")>], // can fetch all "known_face"s but no one knows the status
    ["relay", "<recommended relay>"],
  ],
  "content": "<NIP-44 encrypted Stringified TAG-List([
    ["nickname", "<My buddy>"],
    ["summary", "<summary of the relationship>"],
    ["email", "[email protected]"]
  ])>",
  ...other fields
}

Is this it?

arthurfranca avatar Sep 21 '23 15:09 arthurfranca

If the above ["n", <NIP-44 encrypted("known_face")>] is a good idea, maybe you should standardize a NIP-51 list holding all used n statuses?

I encrypted it because someone may get mad if it discovers his friend labeled him as a "scammer" or something worse =o

arthurfranca avatar Sep 21 '23 15:09 arthurfranca

ohh interesting.. i didn't know the 33118 was supposed to be for just one person. I thought it would be a list of lists of people. Which is probably useful in some use cases.

["n", <NIP-44 encrypted("known_face")>]

Maybe using status for n is not a good idea. I am not sure if the encryption is deterministic to make sure all known_faces map to the same base64.

vitorpamplona avatar Sep 21 '23 17:09 vitorpamplona

Maybe using status for n is not a good idea. I am not sure if the encryption is deterministic to make sure all known_faces map to the same base64.

Just tested it. It is not deterministic =(

nip44.encrypt(hexToBytes(sk1), 'scammer') // 'AU9OCx1Rn7PAA5TxDqgi5Up7bK+cNAgI2bU5/BhQmg0='
nip44.encrypt(hexToBytes(sk1), 'scammer') // 'AfCaDG/6jzFvQKEAVkaKzlgKIsPddNWXaynDPPNb/64='

arthurfranca avatar Sep 21 '23 18:09 arthurfranca

maybe you should standardize a NIP-51 list holding all used n statuses?

If searching by the status at n tag was a must have feature, it could still be done if such NIP-51 list (holding all used n statuses) had tags like this:

[
  ["status", "<status 1>", "random string 1"],
  ["status", "Big Time Scammer", "6064460175057025"]
]

Then the n tag would be "6064460175057025"

arthurfranca avatar Sep 21 '23 18:09 arthurfranca

@arthurfranca I am back to this, changed it to a private status (hash of the key as d-tag) and changed it to your unbound list idea.

I will be using this to document a list of Patients a doctor is taking care of. People can count how many patients a doctor has, but the relationship between them should be fully private.

vitorpamplona avatar Feb 07 '24 23:02 vitorpamplona

I'm in favor of this NIP.

Corny Chat implemented basic support for NIP-81, kind 30382 on 2024-05-06 for petnames. This is an exceptionally useful feature so that users can actually start giving personal names to pubkeys which helps resolve who's who amongst the Dans, and acts as a defence against impersonation. NIP-44 encryption is used for those whose extensions support it. Otherwise it falls back to plain text.

vicariousdrama avatar May 14 '24 13:05 vicariousdrama

@alexgleason did you add 30382 based on this NIP?

@vicariousdrama @alexgleason can you check if the NIP text matches your implementations? If not, I can change the text.

vitorpamplona avatar Jun 13 '24 19:06 vitorpamplona

@vitorpamplona You can run nak req -k 30382 -a db0e60d10b9555a39050c258d460c5c461f6d18f467aa9f62de1a728b8a891a4 wss://gleasonator.dev/relay to see my events.

I am using custom n values, none of which are described here. Example:

{
  "kind": 30382,
  "id": "3a7f95cb6b72a2ebdac6c3f1410e33685efb2644ae18e7be1f5f8933a8f4d59b",
  "pubkey": "db0e60d10b9555a39050c258d460c5c461f6d18f467aa9f62de1a728b8a891a4",
  "created_at": 1718215730,
  "tags": [
    ["d", "932614571afcbad4d17a191ee281e39eebbb41b93fac8fd87829622aeb112f4d"],
    ["n", "admin"],
    ["n", "suggest"],
    ["n", "suggested"]
  ],
  "content": "",
  "sig": "ca77c7313785f39434c1b944865fcce73f1053947e69ef6667e7c76a2ef8af70af6d1d37cd6cc8e530907868ffeec85412d0e6e9c7f973b29a5de6b2cc3be2b7"
}
  • admin - the user is granted admin permission of the ditto server, since this event is signed by the Ditto nsec
  • suggested - the user is globally suggested in the UI
  • suggest (deprecated) - I decided to go with suggested (even though it doesn't match the tense of follow) and forgot to remove the tag from existing events.

I am using this in a slightly unconventional way, but it all makes sense. I intend for regular users to also create kind 30382 events for things like private notes about users, and for users to suggest other users in future updates.

alexgleason avatar Jun 13 '24 19:06 alexgleason

Nice!

I am not sure if the ns should be defined here. I am just making sure the rest of it is like we described. :)

vitorpamplona avatar Jun 13 '24 20:06 vitorpamplona

Fixing kind numbers

:+1:

arthurfranca avatar Jun 20 '24 19:06 arthurfranca

@alexgleason did you add 30382 based on this NIP?

@vicariousdrama @alexgleason can you check if the NIP text matches your implementations? If not, I can change the text.

I've checked how I've implemented this in Corny Chat, and only use kind 30382. The petname tag is used, as a tag, or in encrypted content via nip44 if the client signer supports it. This appears to match how your nip is written

vicariousdrama avatar Jun 21 '24 17:06 vicariousdrama

ACK. Looks good to me.

Giszmo avatar Aug 17 '24 16:08 Giszmo