Here is a principle for a social web that should be kept in mind:
Users should not sign documents
Everyone makes mistakes. We are all human after all. The difference between a mistake and a signed mistake could be huge.
Suppose that we have 2 wonderful people, Alice and Bob. Alice and Bob are friends. So Alice shared some photos with Bob, by signing a document saying that Bob has access to her photos.
However, their friendship ends when Alice realizes that Bob is not a wonderful person, and a rather mean one too. So she revokes that document.
Bob is furious, and makes a post saying that Alice is hysterical and publishes the document as a proof that she liked him at some point, and everyone can confirm that it is genuine. Now Alice is some kind of an emotionally unstable person with sketchy motives.
Of course, she could unlink her signing key from her profile, but then she loses all other relations based on that public key. Will she choose to do that?
If we want a web that works for anyone, this abuse should not be possible. So, what can we do? I think that it is OK for apps or your self-hosted identity provider to sign on behalf of yourself, because you can delete the app key whenever you want without losing your access to your friends. It is somewhat OK to sign things as part of connection metadata, because these informations will typically not be saved forever (except for the NSA). However, we should take a firm stand against users signing documents as a basis for linking of social data.
I think it depends on what kind of social network. For just a general chat then probably it should be off by default. But other social networks may want to have it on by default, or want it easy to turn on or off.
I’ve developed Solidarity with @jucole, an implementation of a Solid Chat. One mistake we encountered and is not resolved yet .
The data was stored on a Pod, in a folder where everyone could write, something like
idxxx type Message
idxxx content "the content of the message"
idxxx author webIdOfAuthor
But @aveltens who is a funny guy posted some message saying that it was posted by @timbl…
So what is a good way to be sure who posted what if document are not signed. What mechanism must be implemented to know who made what ?
0 - Do nothing When you notice a new message from an author, pull the webid of the supposed author and check for news while discarding the info in the inbox. Pros: cannot be forged, no work to do. Cons: @timbl will have his server go down as @jucole spams everyone with fake notifications.
1 - Hack the server to automatically add authorship triples to the .meta of the POSTed resource. The .meta file describes metadata for files that are not RDF resources, this could be a good place to store the author of a resource. When you search through the inbox, look up the .meta and check who send it. Pros: cannot be forged, no additional work for the client. Cons: need to work on the server.
2 - Same, but add the authorship directly to the resource. Pros: even simpler than above, because no .meta. Cons: what if there are 2 authors?
3 - Add a constraint on the server to only accept resources where the ActivityStream author matches the client. Pros: no work to do on the app. Cons: I’m not familiar with shape languages, but I think it needs some specialized work on the server to do this.
But note that signing in this context is OK: it’s not the user that signs the notification, it’s the ActivityPub server. So, with proper key hygiene (change keys regularly on the AP server), it is possible to avoid the problem while still keeping your links to your friends, because friendship is not based on the trust of the public key. This is the beauty of linked data
Well it’s not so easy I think, because according to the Solid Chat Spec, data of message are stored day by day, it seems that all the message of one day are stored in the same turtle file ex: /2020/05/29/index.ttl
Hard to say in the index.ttl.meta file who do what in the index.ttl and if the usurper can write to index.ttl I think he could write to .meta to say he is the author…
In fact something must be done in the server ?
Well, the .meta documentation is pretty sparse and I can’t seem to find it again. I had the impression that it was somehow a copy of the filesystem stats, so it makes no sense to let users write its contents, but of course I could be wrong.
So, well, that situation is not great. I don’t know the solid chat spec, but if it is possible to use a different key for different chats, then it would be OK too to sign chat messages, but I think that the chat should be spread over the pods of all participants, with each participant publishing their respective messages, and each archiving all the replies in a private history if they fear one of the pods could go down. So, no need for signatures if I guess correctly. I will read the spec though, because I don’t know it yet.
I’m not familiar enough with the specs, but the way I understand signing being turned off by default, is that messages can’t be traced to a person (not a pseudonym) with verifiable credentials. I assume messages sent to a chat from a pseudonymous WebId could still be traced to that WebId.
The problem arises when you sign something with a key that you cannot afford to delete. If you need your key to access data on your friends’ pods, you should not sign anything with that. However, with current ActivityPub and Solid, all platform-level keys are temporary and you can change them without losing anything.
In the web of trust, this is not so. You need to exchange keys in order to communicate with someone else. So you cannot delete the key: everything you signed with it is tied to everything else you signed. With the capabilities, if you delete your key then you lose all the accesses to your friends’ pods, so you need to request them again.
Chats are not part of the platform, they are apps. So you could use whatever you want, but I would myself prefer an implementation creating a new independent key pair for each conversation, and if two conversations reference each other, link the keys (with linked data, not signing) so that the other participants know I am the same person in both conversations.
So, my linked data solution for the Github issue (I will write it more clearly tomorrow ^^):
Each participant store their messages on their pods, and when you load the chat, you load the message of all participants and merge them in the app view, sorting by date. Joining the chat means adding a chat to your profile linking to the chat counterparts of all other participants, and send a LD notification to their inbox. When they receive the notification, they look up your webid, look up your (most recent) chats, and if your chat links to theirs, then they get a pop-up. “Do you want @Smag0 to join the chat?” If they click yes, then their chats will link back to yours. If they click “no”, then they won’t read your answers.
I’m looking at that now, very interesting. Sorry but I’m a little confused. I get that a contribution is a collection of notes from one author or contributor, but I’m confused about what an extension is. Can you explain? Thanks
I should think more about this but so far I’m thinking that an Extension is just another Contribution, so I wonder why you need another class for it. Then Contribution:extendedBy could be renamed to Contribution:corresondence and the range would be a Contribution.
After thinking a bit about it, you are right. We need to keep some state with the link between contributions (the author, and whether it is accepted), but we could as well attach these properties to the target contribution.
I updated it.
Thank you, this is way simpler and cleaner like that