What is a forge user and how is it persisted?

Bonjour,

A user is a developer and they have accounts on multiple forges, either because they created them or because fedeproxy did on their behalf. Assuming a fedeproxy instance is responsible for a single forge, the internal representation of a user is:

  • the emails
  • the username
  • the password
  • the API token that fedeproxy obtained to act on behalf of the user

If fedeproxy has root access to the forge, this information is obtained without any action from the user. If fedeproxy does not have root access, the user needs to provide a token to fedeproxy as a first step (see this example).

Since fedeproxy is stateless, the token is stored on disk during a few weeks when fedeproxy does not have root access to the forge. Otherwise the users would be forced to renew the token whenever the fedeproxy service is restarted.

For a given software project, it is assumed the user will use a single forge (let’s call it the primary forge). But fedeproxy will need to obtain credentials (user/password or token) for each forge where it needs to act on behalf of the user. Since fedeproxy is stateless and this information needs to be preserved, it is stored in a private project of the primary forge. When fedeproxy needs access to another forge, it can retrieve the credentials (user/password or token) from this private repository.

An issue can be created by fedeproxy in the private repository of the primary forge whenever its token is about to expire as a reminder for the user that it needs to renew it, with a link to the page where OAuth2 will obtain authorization.

The private repository is encrypted with the private key of the fedeproxy instance that created the repository. An issue is created every month with a link valid 24h from which the user can download a decrypted version of the repository for safe keeping on their local machine. When a user migrates to another forge, the content of the repository is encrypted by the source fedeproxy instance with the public key of the destination fedeproxy instance.

Cheers

If the credentials for accounts representing a given user on all forges tare permanently stored in a central place, the threat model is the same as a password manager (bitwarden, psono, etc.). There however are two kind of accounts:

  • The accounts manually created by the user
  • The accounts created by fedeproxy on behalf of the user

For accounts manually created by the user, fedeproxy will only get an application token but will not own the account. The user is responsible for it and fedeproxy must not interfere, nor is it responsible for ensuring the credentials for this account are safely preserved.

For accounts created by fedeproxy the situation is different: the user has no idea they even exist. However fedeproxy must guarantee that whenever the user wants to manually manage this account, fedeproxy will yield.

:warning: brain dump, won’t make much sense to anyone but me at this point :warning:

User (username, mails, owned, token, password, staged, identities*)
Identity (forge URL, fedeproxy URL, username, mails, trusted)

An identity is trusted for a given period of time when the fedeproxy URL is able to create a well-known content on the forge URL on behalf of username
When an ActivityPub message originating from username is received from a fedeproxy URL that is trusted for this identity, the message is acted upon.

When fedeproxy creates a user it does it with the root token. It associates the user with a fedeproxy mail as well as a mail controlled by the user.
The root token is only used to obtain user tokens and create/delete users.
If the local user is owned by fedeproxy, a token is obtained by impersonating the user with a root token.
If the local user is not owned by fedeproxy, the token is obtained via a web form (OAuth2 challenge, entering the application token manually, etc.).

Fedeproxy does not find a local user that is mapped to the identity of a user sending the message, it creates a new one.
Fedeproxy finds a local user that is mapped to the identity of a user sending the message, it creates a new one.
When fedeproxy is notifed that a user it knows is merged into another one, it updates its internal representation.

Fedeproxy may create users for two different reasons:

  • To act on their behalf because they are trusted (in which case they have their email)
  • To stage users as a side effect of an action carried on behalf of a trusted user (and they do not have their email)

On a regular basis fedeproxy sends a mail to the user with the list of identities. The mail is sent to all users that are owned. The tokens / passwords are not sent because they can ultimately be retrieved via a password reset via mail. It is a disaster recovery precaution.

The list of identities is stored in a private repository in each forge (except tokens and passwords).

When an Activity is sent on behalf of a user, the fedeproxy instance is also expected to create a “.well-known/ID of the message” in a public repository that belongs to the user to demonstrate they are trusted with this user
The receiving fedeproxy instance checks this “.well-known/ID of the message” before taking action.
If the fedeproxy instance is root on the instance they can also create a “.well-known/???” in place where only root can and it will be trusted for all messages originating from the forge.

For every user it knows on forge A, fedeproxy A creates a maching user for federation purposes. This is required: every ActivityPub message sent must originate from a user. This user is cannonically https://fedeproxy.eu/@hash(public user URL)

Every fedeproxy instance has a reserved user @fedeproxy.

When user A on forge A asks fedeproxy A to federate an issue that is a URL on forge B, it means they trust the forge B to not be malicious and fedeproxy A can therefore trust fedeproxy B with the data of user A. A DM is sent by @fedeproxy on fedeproxy A to @fedeproxy on fedeproxy B with the email of user A.

Forges that trust each other are in a cryptographic web of trust. The emails of the users are encrypted and made available to other fedeproxy instances.

Some users on forge B are created as placeholders to represent users from forge A and allow them to author issues/comments on forge B. They are not the users initiating the federation, they are the users who participated in the conversation and needs to exist. Otherwise the issues/comments on forge B will not belong to anyone. These users are “staged” and do not have an email associated with them.

If user B was staged on forge B to be the author of all actions carried out on forge A by user A, how does the developer controlling user A reclaim ownership of user B ?

  • The developer creates an issue in the “reclaim” project of the fedeproxy user on forge A with the URL of the user B
  • Fedeproxy A sends a DM to fedeproxy B with the email of user A and the URL of user B
  • Fedeproxy B verifies .well-know/ABC proving on user A
  • Fedeproxy B sets the email of user B to the email of user A
  • Fedeproxy B triggers a password reset on user B (or the developer can do the same later on) and the user is no longer staged

@misc suggested yesterday that it would be worth looking at how Matrix handles multiple identities.

I didn’t have time to read through the thread above, but just wanted to pass a link (unfortunately it’s Golang):

1 Like

Glossary

  • Identities: the collection of User that represent the same Developer on multiple Forges
  • Developer: a software developer who has an account on a Forge
  • Forge: a software forge
  • Fedeproxy Service: the publicly online service that runs fedeproxy
  • User: a forge user under the control of a Fedeproxy Service
  • User Pool: the collection of users that are in the scope of a fedeproxy instance
  • Access Token: credentials to use the API of a forge on behalf of a user
  • Local Storage: the file system of the machine where fedeproxy runs
  • Fedeproxy User: the forge user that the Fedeproxy Service uses to store Identities & link to itself
  • Issue: an item in the issue tracker of a Forge
  • Federated Issue Identifier: Fedeproxy Service URL/@hash(forge URL)
  • Federated Issue: an issue that follows (in the ActivityPub sense) another issue. The Fedeproxy Service sends ActivityPub messages when it is modified.

Fedeproxy Service instances

When installed, fedeproxy must be configured with a Forge and will spawn a Fedeproxy Service dedicated to this Forge.
When a Federated Issue is created with Issue A on Forge A and Issue B on Forge B, the Fedeproxy Service A will try to figure out the URL of the Fedeproxy Service B. If it fails to find one, it will spawn a Fedeproxy Service B and use it instead.
Fedeproxy Services running against the same Forge can be merged.

User Pool

Fedeproxy manages a pool of unused users in the forge. These users can be created:

  • By fedeproxy via the REST API, as a cron job (with or without a root token) which adds the users in a repo of the Fedeproxy User
  • Manually, for GitHub or GitLab because bots cannot conveniently create account, possibly via a crowdsource campaign

Installation

When fedeproxy starts the first time:

  • it is given the email of the fedeproxy maintainer and the URL of the forge
  • it gets a user from the User Pool to be the Fedeproxy User and assigns it the email of the maintainer
  • it saves the Access Token to the user in Local Storage
  • it uploads the User Pool in a private repository

Identities

Staged

An Identity is staged when it is not associated with an email. For
instance because they were created to represent the author of a
comment in an Issue.

Owned

An Identity is owned when the Developer does not know about it. If it
is controled by the Developer, it is not owned by the Fedeproxy
Service.

Storage

Fedeproxy Service creates a private repository for each User to store their Identities:

  • Forge URL
  • Fedproxy Service URL
  • username
  • mails
  • staged
  • owned

backups

On a regular basis fedeproxy sends a mail to the user with the list of
identities. The mail is sent to all users that are owned. The tokens /
passwords are not sent because they can ultimately be retrieved via a
password reset via mail. It is a disaster recovery precaution.

Send backup mail every time a new account is created.

Reclaiming a staged user

If User B was staged on Forge B to be the author of all actions carried out on Forge A by User A, how does the Developer controlling User A reclaim ownership of User B ?

  • There exists an issue in the Fedeproxy User project “reclaim” for each staged user on Forge B
  • The comment of the issue is a link to the OAuth2 web page of the Fedeproxy Service for Forge A
  • When the user clicks it confirms that the Fedeproxy Service can get their email, Fedeproxy Service A sends it to Fedeproxy B after verifying that the referer of the request is indeed Forge B

Fedeproxy Service B could trigger a password reset on user B, or the Developer can do the same.

Disaster recovery

Fedeproxy Service maintainer

If the Local Storage is lost, it is the responsibility of the
maintainer to figure out the URL of the Fedeproxy User by searching
the forge, impersonating the user, getting an application token and
running the fedeproxy server with the Fedeproxy User and application
token to regain access.

Developer

Using the URL found in the Identities backups sent to them, the Developer
can regain manual control of a User on any given forge using a password reset (because
all users are associated with emails under the control of Developer).

Trust

Fedeproxy Service

By default a Fedeproxy Service does not impose any restriction on the creation of a User because it is cheap on self-hosted instances. If there is abuse those users can be removed after a period of inaction, just as is done with bots that create accounts on forges at the moment.

However user creation is much more expensive on forges such as GitHub or GitLab and a Fedeproxy Service that runs for such Forges should only allow user creation when it originates from a list of trusted Fedeproxy Services. If Fedeproxy Service A is not trusted by Fedproxy Service B on Forge B. A Fedeproxy Service A can request to follow another Fedeproxy Service B. If the Fedeproxy Service B accepts, it will create/allocate accounts originating from Fedeproxy Service A instead of declining.

Federated Issue

When a Developer A creates a Federated Issue on Forge A that follows an Issue B on Forge B, the Fedeproxy Service A service trusts Fedeproxy Service B. It assumes Developer A did their research and Forge B can be trusted with Issue B.

Share an email

When Developer A on Forge A asks Fedeproxy Service A to federate an Issue that is a URL on Forge B, it means they trust the Forge B to not be malicious and Fedeproxy Service A can therefore trust Fedeproxy Service B with the email of Developer A.

Fedeproxy Service A uses the REST API of Fedeproxy Service B to POST the email of User A and the name of User B that represents User A on Forge B. It also provides in the POST params a .well-known URL on Forge A that proves it is in control of User A. Once Fedeproxy Service B verifies the .well-known URL, it sets the email of User B.

Users in matrix:

@misc the other day you mentioned discussions about user management / migration in Matrix. Do you recall where they can be found?

I do not remember, I said lots of stuff, but maybe

1 Like

The spec is still incomplete and includes the concept of one true identity that could be lost and is ultimately the responsibility of the user (it is stored on their local machine).

User Permanent Key (UPK)

The UPK is an ed25519 public key which represents a user entity. The initial intention is that a user will use this UPK to perform a challenge-response login to a homeserver and that it will become their “one true identity”.

Central to this design is that the UPKs are user-owned and therefore the private key portion to each UPK is held by the user, although they could be protected with a passphrase and backed up to key storage on one or more homeservers if needed.

The UPK private portion must not be decrypted nor used serverside.

The fedeproxy instance for a forge must maintain a table mapping every user for which it knows the email to a cryptographic signature of this email and make it publicly available. Otherwise other forges will have no way to figure out if a given user is known: the email is the unique identifier they rely on for this.