v4: a deployment chooses which ways federated sign-in goes — every instance took users of the others and let its own sign in to them, with no way to turn either off. GERBEUR_FEDERATION_INCOMING=0 keeps users of other instances out: the login and register pages offer no other instance, /manage no list of instances, their sign-ins are refused, and those already in are signed out until it is on again, their homes' events still applied meanwhile. GERBEUR_FEDERATION_OUTGOING=0 keeps the instance's users from signing in elsewhere: its /authorize page lets no instance sign them in, its metadata says so (gerbeur_outgoing), which other instances check before sending anyone there, the settings page lists no instances, and at startup every grant is withdrawn, which signs them out there. Both are on by default and reach the client through index.html. The dev instance gerbeur (:3000) takes no users of the others, while its own still sign in to them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ import { APIException } from "../lib/api-exception.ts";
|
||||
import { db, transaction } from "../db/connection.ts";
|
||||
import {
|
||||
AVATARS_DIR,
|
||||
FEDERATION,
|
||||
FRONTEND_URL,
|
||||
OG_SITE_NAME,
|
||||
PUBLIC_URL,
|
||||
@@ -102,6 +103,7 @@ export function getInstanceMetadata(): InstanceMetadata {
|
||||
gerbeur_site_name: OG_SITE_NAME,
|
||||
gerbeur_redirect_uri: REDIRECT_URI,
|
||||
gerbeur_events_endpoint: `${PUBLIC_URL}/api/federation/events`,
|
||||
gerbeur_outgoing: FEDERATION.outgoing,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -143,16 +145,24 @@ export function identityClaims(user: User): IdentityClaims {
|
||||
/**
|
||||
* Returns the client `clientId` names, checked: an instance other than this
|
||||
* one, not blocked here, answering as a gerbeur. `user` must have a local
|
||||
* account, which alone may sign in elsewhere.
|
||||
* account, which alone may sign in elsewhere, and this instance must let its
|
||||
* users sign in elsewhere (`FEDERATION.outgoing`).
|
||||
*
|
||||
* @throws {APIException} 400 when `clientId` isn't an instance's address, is
|
||||
* this instance, or `user` comes from another instance; 403 when the client
|
||||
* is blocked here; 502 when it doesn't answer as a gerbeur.
|
||||
* this instance, or `user` comes from another instance; 403 when this
|
||||
* instance's users don't sign in elsewhere, or the client is blocked here;
|
||||
* 502 when it doesn't answer as a gerbeur.
|
||||
*/
|
||||
async function checkClient(
|
||||
user: User,
|
||||
clientId: string,
|
||||
): Promise<{ clientId: string; metadata: InstanceMetadata }> {
|
||||
if (!FEDERATION.outgoing) {
|
||||
throw new APIException(
|
||||
403,
|
||||
"Accounts on this instance don't sign in to other instances",
|
||||
);
|
||||
}
|
||||
if (isRemoteUser(user)) {
|
||||
throw new APIException(
|
||||
400,
|
||||
@@ -362,6 +372,24 @@ export async function revokeGrant(userId: string, host: string): Promise<void> {
|
||||
).run(userId, grant.clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Withdraws every grant, as each user would theirs, and drops the codes not
|
||||
* yet traded, so that no account here stays signed in elsewhere: `main.ts`
|
||||
* calls it at startup when `FEDERATION.outgoing` is off. Returns how many
|
||||
* grants it withdrew.
|
||||
*/
|
||||
export async function withdrawAllGrants(): Promise<number> {
|
||||
db.prepare(`DELETE FROM oauth_codes;`).run();
|
||||
const grants = db.prepare(
|
||||
`SELECT user_id, client_id FROM federation_grants;`,
|
||||
).all() as { user_id: string; client_id: string }[];
|
||||
for (const { user_id, client_id } of grants) {
|
||||
await notifyClients(user_id, { type: "revoke" }, [client_id]);
|
||||
}
|
||||
db.prepare(`DELETE FROM federation_grants;`).run();
|
||||
return grants.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells each instance user `userId` signed in to of `event`, or only those of
|
||||
* `clientIds`: `update` when their name, email or avatar changed, `revoke`
|
||||
|
||||
Reference in New Issue
Block a user