Share the route-certificate view between cultmesh-ts and cultmesh-browser

Both packages mapped an advertised route's wire-shaped certificate
(providerKeyId/providerPublicKeyX/providerPublicKeyY/...) to
CultMeshAuthorityRouteCertificate independently. Move the mapping into
cultnet-ts's cultmesh-authority module, next to verifyAuthorityRoute, and
have both consumers call it instead of duplicating the object literal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-23 15:52:46 +02:00
commit da0935b658
3 changed files with 28 additions and 12 deletions

View file

@ -20,6 +20,7 @@ import {
bytesToBase64,
isLoopbackEndpoint,
isUnsignedCertificate,
routeCertificateView,
verifyAuthorityRoute,
verifyProviderSessionProof,
type CultMeshAuthorityIdentity,
@ -870,17 +871,7 @@ async function selectOdinRoute(
protocolIds: route.protocolIds,
priority: route.priority,
generation: route.generation,
...(route.certificate ? { certificate: {
providerKey: {
keyId: route.certificate.providerKeyId,
x: route.certificate.providerPublicKeyX,
y: route.certificate.providerPublicKeyY,
},
odinKeyId: route.certificate.odinKeyId,
issuedAtUnixMilliseconds: route.certificate.issuedAtUnixMilliseconds,
expiresAtUnixMilliseconds: route.certificate.expiresAtUnixMilliseconds,
signature: route.certificate.signature,
} } : {}),
...(route.certificate ? { certificate: routeCertificateView(route.certificate) } : {}),
};
try {
await verifyAuthorityRoute(candidate, trust);

View file

@ -6,7 +6,7 @@
// through the same functions; the C# reference is
// `src/GameCult.Mesh/CultMeshAuthorityProof.cs`.
import type { CultMeshSessionOpenMessage } from "./contracts";
import type { CultMeshRouteCertificateMessage, CultMeshSessionOpenMessage } from "./contracts";
export interface CultMeshAuthorityIdentity {
verseId: string;
@ -36,6 +36,30 @@ export interface CultMeshAuthorityRouteCertificate {
signature: string;
}
/**
* Maps an advertised route's wire-shaped certificate to the view
* `verifyAuthorityRoute` and the transports consume. Shared by the QUIC
* realtime session manager (`cultmesh-ts`) and the browser WebSocket client
* (`cultmesh-browser`), which advertise the same `CultMeshAuthorityRouteMessage`
* certificate shape and were computing this mapping independently.
*/
export function routeCertificateView(
certificate: CultMeshRouteCertificateMessage | undefined,
): CultMeshAuthorityRouteCertificate | undefined {
if (!certificate) return undefined;
return {
providerKey: {
keyId: certificate.providerKeyId,
x: certificate.providerPublicKeyX,
y: certificate.providerPublicKeyY,
},
odinKeyId: certificate.odinKeyId,
issuedAtUnixMilliseconds: certificate.issuedAtUnixMilliseconds,
expiresAtUnixMilliseconds: certificate.expiresAtUnixMilliseconds,
signature: certificate.signature,
};
}
export type CultMeshAuthorityTrustMode = "authenticated-remote" | "local-development";
export interface CultMeshAuthorityTrustPolicy {

View file

@ -73,6 +73,7 @@ export {
isNullOrWhiteSpaceCSharp,
isProtectedEndpoint,
isUnsignedCertificate,
routeCertificateView,
trimCSharp,
verifyAuthorityRoute,
verifyP256,