Contacts v0

    Problem

      In order to help people combat spam and discover relevant content to them in the system, we need to introduce a mechanism in which they can take advantage of their social connections. We introduce the idea of Contacts and Verifications to achieve that.

      Currently we are using the Home Document's metadata to give names to users, but it seems that the idea of Spaces and their Home Documents may not work well for representing people and their relationships. We need a new entity in the system that enables users share their profiles and store contacts in a way that let them create a "web of trust". We've already recently created a Profile blob type for doing device linking and identity aliases, but we haven't used it for the actual profile data. We still need some extra tools for doing identity verifications and contacts management.

    Glossary

      There has been a lot of confusion about the various terms that we keep using: Contact, Account, Profile, Space, Site, Key, etc. In some contexts these terms could probably be used interchangeably, but in others the difference is important, albeit subtle. Some of these terms are different facets of the same logical global concept.

      Please see our current understanding of the terms in the Glossary.

    Solution

      Profile Blob

        Profile blob should be used as the main representation of the account's profile metadata. We should still fallback to home documents when Profile blob doesn't exist. We should migrate existing accounts to use Profile during the app update.

        Currently the Profile blob would contain the following fields (most fields are optional, but either name or alias must exist):

          name: The self-proclaimed human-readable name of an account. Can be a real name, an alias, or something else.

          icon: The URL to an image for the avatar.

          description: Short human-readable string of text with no formatting. For bio or anything else.

          alias: The public key of some other account.

            Used for "redirecting" one Account's profile to another Account's profile. The account that's claiming the alias must be an Agent of the mentioned account.

          subject: Optional public key of the account whose Profile is being updated. Used when the Profile is signed by an agent.

        We don't support adding any user-defined fields for now, although eventually we might.

        Profile blobs are snapshots of the profile data. This is for simplicity, and performance reasons — we want to resolve profile data quickly in the UI without having to download long chains of obsolete information. Granted, we also want to resolve documents quickly, but because they are collaborative, can be embedded, and their version history is more valuable — modeling them as Changes seems worth it.

        An observer of some Profile data could be keeping previous snapshots to preserve history, but it's not required for resolving the current state of the profile.

        Because Profiles are snapshots, and Agents can update profiles of their "parents", we should probably keep the latest profiles from all the signers and "merge" them at query time on the client, similar to how we do with Refs.

        When updating Profiles we should do our best to refresh it before updating, at least by syncing with the gateway server first.

        To be clear, the old metadata on the home document can live along with the profile data — e.g. some people may want to use different images for their profile picture and their home documents, or use a different title on the home document, etc.

        In this picture it's clear the separation between profile info and home document, although it doesn't reflect that names and pictures could be different, but they could.

      Verifiable Third-Party Accounts

        For a long time we've been seeing Keybase as the ideal approach for verifying third-party platforms and creating proofs of ownership. I came to think that full-blown Keybase approach for signing data on the third-party platforms could be an overkill for us, and it gets especially complicated with multi-device in the mix.

        I claim that third-party accounts can be verified independently (by each user) in a trustworthy way as long as the following criteria are met:

          Claims on HM Profiles are cryptographically authenticated (signed) — always true.

          Communication with the third-party platform is authenticated to some identifier that we trust, e.g. a web domain. Simply said — it has to be HTTPS with a valid cert for the domain.

          There's a way for anybody to check whether the account on the third-party platform claims a HM Account. E.g. a string of some format in an X bio, a Gist on GitHub, or something like that.

          There exist a reciprocal mention between the HM Account and the third-party account. E.g. an HM Account z6MkuFulanito claims @fulanito handle on X, and the bio of this handle claims the same HM Account reciprocally.

        So, as long as those conditions are met, anybody should be able to trustworthily verify the relationship between an HM account and a third-party account. We already relate DNS names to HM spaces this way. Things like phone numbers and email addresses cannot be verified this way (or any other way) — hope it's clear why. It's possible to verify those with some trusted intermediary though.

        Each platform would need its own way of proving the relationship, and I propose that we worry about it at some other time. For now, we may let you just add your third-party handles on your Seed profile, but we won't verify anything automatically yet — let's let people decide for themselves whether they trust the information or not.

      Petnames

        Petnames are local names for your contacts, much like names in the contact list of your phone.

        As much as I like this idea, before implementing it we should probably have private multi-device sync, so you wouldn't need to manually duplicate your petnames across your devices. This sync is also needed for syncing subscriptions and other private information, but it's way beyond the scope of this project.

        When we have this kind of syncing we can get back to this subject.

      Contacts and Edge Names

        Our idea of contacts is a mix of the idea of edge names, and identity verification (like in Bluesky or X). I like calling them Contacts though, because "Edge Name" is too nerdy, and Identity Verification is too long and too pompous.

        So, we introduce a new blob type — Contact which is a signed statement saying that we recognize someone else's profile under a certain name.

        It's tempting to make this system very sophisticated and complex, where we'd verify each individual statement of a contact, like their Twitter handle or email address, but I propose to keep it simple for now — this Contact blob would have very few fields (beyond the common type, signature, etc.):

          name: The name under which we recognize this account. It's public, so we should make it clear for the user to keep it non-offensive, and useful to other people. This is basically the edge name.

          subject: The public key of the account that will be our contact. If this account starts redirecting to other accounts (using profile aliases), we probably should advice users to reissue their contact statements.

          genesis: Optional. The CID of the initial contact record if this is a replacement.

        When we add a contact we should start keeping an eye on what they do. Eventually our app could be prompting to review certain things contacts do, to potentially dispute or disprove them (something similar to WhatsApp's "Security code changed" warning).

        We presume contacts being innocent until they are proven guilty or suspicious, so we trust whatever they do about their identity, and keep it in check ourselves, raising concerns if/when necessary. If something happens — we could remove them contact or come up with a way to dispute their actions more specifically.

        To delete a contact we can issue a Contact blob with the same genesis and no name nor account fields. Similar to how we tombstone Ref blobs now.

        So, the logical "primary key" for the contact is a tuple of (spaceID, contactGenesisCID). Hence, we could end up having same name being assigned to different accounts, and same account having multiple names. Same thing can happen in your phone's address book, so it's probably OK. But maybe we should surface those situations to the users in the app.

      Trust and Verifications

        Bluesky has introduced the idea of Trusted Verifiers for identity verification, which is basically a hard-coded list of those accounts who's contacts we can trust. AT Proto allows anybody to issue verifications, but the Bluesky app would only show blue checkmarks on those from trusted verifiers.

        I propose that we leave this for some other time, and instead adapt our UI to be able to render third-party contacts (i.e. someone else's claims about someone else), maybe as something like this:

        So, when we render someone else's name we'd prioritize the list of all the known names to us:

          Our own Contact for that account if we have one.

          Self-proclaimed name for that account from their own Profile blob.

          Third-party Contact blobs about that account. Maybe rank this list to put those from our own contacts first.

      Gating Comments and User Lists

        Bluesky has Thread Gates which lets you control who can reply to your posts. There're 3 rules:

          Only those who I follow can reply.

          Only those who I mention in this post can reply.

          Only those who are in a particular user list can reply.

        We should implement something similar for controlling which comments appear on the site, and who's allowed to reply to certain comments.

        The actual implementation of this is probably beyond the scope of this project, but having Contacts could help very much implementing those policies.

        We don't have user lists with that, but we could easily implement them by adding a simple listName property to the Contact blob or something like that.

      Addressability of Contacts

      No Gos

        Petnames. Needs multi-device private sync.

        Granular verification of contact information.

          Third-party platform verifications.