mirror of
https://github.com/temetro/temetro.git
synced 2026-08-19 06:36:21 +00:00
99aa534e88
The relay is now multi-clinic. Each clinic authenticates to the /hub namespace by signing a challenge with its own Ed25519 clinic signing key (a per-clinic identity, not a shared RELAY_TOKEN), and the relay routes every device response back to only the clinic that originated the request (keyed by requestId) — so clinics never see each other's traffic. Backend: - clinic_signing_keys.network_enabled + GET/PUT /api/signing/network (owner/admin) to join/leave the network. - relay-client keeps one authenticated hub connection per network-enabled org (connectOrg/disconnectOrg, hubs map keyed by orgId); emitToWallet/ sendToWallet take orgId; offline flush is org-scoped. - Wallet import/push return 409 until a clinic joins. - RELAY_TOKEN is now optional/legacy (open relay needs no shared secret). Frontend: - "Join Temetro Network" toggle in Settings → Signing, localized in all five languages (en, fr, de, so, ar). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
27 lines
1.4 KiB
TypeScript
27 lines
1.4 KiB
TypeScript
import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
|
|
import { organization } from "./auth.js";
|
|
|
|
// One Ed25519 signing key per clinic (organization). The clinician's edits to a
|
|
// patient record are signed with this key so patients (and other clinics) can
|
|
// verify a change really came from this clinic before approving it. The private
|
|
// key is stored encrypted at rest (lib/crypto.ts `encryptSecret`); the public
|
|
// key + fingerprint are shown in Settings → Signing. Rotating replaces the row.
|
|
export const clinicSigningKeys = pgTable("clinic_signing_keys", {
|
|
organizationId: text("organization_id")
|
|
.primaryKey()
|
|
.references(() => organization.id, { onDelete: "cascade" }),
|
|
algorithm: text("algorithm").notNull().default("ed25519"),
|
|
publicKey: text("public_key").notNull(),
|
|
fingerprint: text("fingerprint").notNull(),
|
|
// Encrypted (lib/crypto.ts) hex of the Ed25519 private key.
|
|
privateKeyEnc: text("private_key_enc").notNull(),
|
|
// Whether this clinic has joined the Temetro Network relay ("Join Temetro
|
|
// Network" in Settings → Signing). Off by default: only when enabled does the
|
|
// backend open this clinic's relay hub connection and expose wallet features.
|
|
// The relay identity *is* this signing key, so the flag lives on the same row.
|
|
networkEnabled: boolean("network_enabled").notNull().default(false),
|
|
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
rotatedAt: timestamp("rotated_at"),
|
|
});
|