From 1a2bc0ec52a4fd6328404717d579dcedf03d755a Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Fri, 3 Apr 2026 05:27:51 +0200 Subject: [PATCH] fix: use timestamp 0 for never-edited profiles in LWW comparisons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit profileUpdatedAt ?? createdAt treated freshly registered users as having "newer" profiles than users with real edit history, because createdAt is always NOW at registration time. This broke federation profile sync: the client correctly pushed home → remote, but the remote server's LWW guard rejected the write (stored createdAt > incoming profileUpdatedAt). A null profileUpdatedAt means "never edited" — that's timestamp 0, not the user's creation time. --- packages/server/src/routes/users.ts | 2 +- packages/server/src/utils/sanitize.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/routes/users.ts b/packages/server/src/routes/users.ts index b1fd04c5..b51fc6e1 100644 --- a/packages/server/src/routes/users.ts +++ b/packages/server/src/routes/users.ts @@ -361,7 +361,7 @@ export async function userRoutes(app: FastifyInstance): Promise { if (profileUpdatedAt !== undefined && typeof profileUpdatedAt === 'number') { const currentUser = db.select().from(schema.users).where(eq(schema.users.id, request.userId)).get(); if (currentUser) { - const storedTs = currentUser.profileUpdatedAt ?? currentUser.createdAt; + const storedTs = currentUser.profileUpdatedAt ?? 0; if (profileUpdatedAt < storedTs) { // Incoming data is older — return current state without updating return reply.code(200).send(sanitizeUser(currentUser, true)); diff --git a/packages/server/src/utils/sanitize.ts b/packages/server/src/utils/sanitize.ts index 7340fd55..a325479a 100644 --- a/packages/server/src/utils/sanitize.ts +++ b/packages/server/src/utils/sanitize.ts @@ -49,7 +49,7 @@ export function sanitizeUser(row: typeof schema.users.$inferSelect, isSelf = fal customStatus: row.customStatus, isAdmin: row.isAdmin === 1, discoverable: row.discoverable !== 0, - profileUpdatedAt: row.profileUpdatedAt ?? row.createdAt, + profileUpdatedAt: row.profileUpdatedAt ?? 0, createdAt: row.createdAt, homeInstance: row.homeInstance ?? null, homeUserId: row.homeUserId ?? null,