Fix federation flows and add versioned updater

This commit is contained in:
cyph3rasi
2026-03-07 21:55:55 -08:00
parent 5d524a0354
commit 1b0b3d8d52
24 changed files with 1486 additions and 142 deletions
+39 -9
View File
@@ -7,26 +7,56 @@ import { verifySwarmRequest } from '@/lib/swarm/signature';
import { fetchAndCacheRemoteKey, logKeyChange } from '@/lib/swarm/identity-cache';
import { z } from 'zod';
// Schema for direct signed action (legacy)
const chatReceiveSchema = z.object({
const signedChatActionSchema = z.object({
action: z.string().min(1),
did: z.string().regex(/^did:/, 'Must be a valid DID'),
handle: z.string().min(3).max(30),
ts: z.number(),
nonce: z.string().min(1),
sig: z.string().min(1),
data: z.object({
recipientDid: z.string().regex(/^did:/, 'Must be a valid DID'),
content: z.string().min(1).max(5000),
}),
});
// Backward compatibility for older nodes that sent legacy field names.
const legacyChatActionSchema = z.object({
did: z.string().regex(/^did:/, 'Must be a valid DID'),
handle: z.string().min(3).max(30),
data: z.object({
recipientDid: z.string().regex(/^did:/, 'Must be a valid DID'),
content: z.string().min(1).max(5000),
}),
signature: z.string(),
timestamp: z.number().optional(),
signature: z.string().min(1),
timestamp: z.number(),
});
// Schema for federated envelope
const incomingChatActionSchema = z.union([signedChatActionSchema, legacyChatActionSchema]);
const federatedEnvelopeSchema = z.object({
userAction: chatReceiveSchema,
userAction: incomingChatActionSchema,
fullSenderHandle: z.string().min(3).max(60),
sourceDomain: z.string().min(1),
ts: z.number(),
});
function normalizeSignedAction(action: z.infer<typeof incomingChatActionSchema>): SignedAction {
if ('sig' in action) {
return action;
}
return {
action: 'chat',
data: action.data,
did: action.did,
handle: action.handle,
ts: action.timestamp,
nonce: `legacy:${action.did}:${action.timestamp}`,
sig: action.signature,
};
}
/**
* POST /api/chat/receive
* Endpoint for receiving federated chat messages from other nodes.
@@ -67,19 +97,19 @@ export async function POST(request: NextRequest) {
}
// Extract user's signed action and full handle from envelope
signedAction = body.userAction;
signedAction = normalizeSignedAction(body.userAction);
fullSenderHandle = body.fullSenderHandle;
console.log(`[Chat Receive] Federated envelope from node: ${sourceDomain}, full handle: ${fullSenderHandle}`);
} else {
// Legacy format - direct user signed action
const actionValidation = chatReceiveSchema.safeParse(body);
const actionValidation = incomingChatActionSchema.safeParse(body);
if (!actionValidation.success) {
return NextResponse.json(
{ error: 'Invalid action payload', details: actionValidation.error.issues },
{ status: 400 }
);
}
signedAction = body;
signedAction = normalizeSignedAction(actionValidation.data);
}
const { did, handle, data } = signedAction;