Changeset f63cbc2 in Klonkt for src/services/CircleFederation.js


Ignore:
Timestamp:
06/16/2026 06:33:38 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
4fee228
Parents:
1b4d5dd
Message:

Circles: protocol version enforced via signature binding (update enforcement)

KLONKT_PROTO is now part of the signed basis (signingInput:
"klonkt/proto/N\n"+body). An instance on a different proto cannot verify
the signed outbox and vice versa → staying up to date is cryptographically
enforced, not a patchable check. Both sides verify the proto
(actor.klonkt.proto + Klonkt-Proto header → 426); too-old/too-new sources
are excluded with status 'outdated' + a clear message. Couple security to
every proto bump. Proto starts at 2; roll out in lockstep.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/CircleFederation.js

    r1b4d5dd rf63cbc2  
    1515import db from '../config/database.js';
    1616import { getSetting, setSetting } from './SettingsService.js';
     17
     18// ── Protocol-versie (federatie) ───────────────────────────────
     19// KLONKT_PROTO zit IN de ondertekende grondslag (zie signingInput): een instance
     20// die niet op deze proto draait kan onze getekende outbox NIET verifiëren, en wij
     21// de hare niet. Bijblijven is dus geen beleefde check die je wegpatcht, maar
     22// cryptografisch afgedwongen — de enige manier om mee te doen is dezelfde proto
     23// draaien (= de update). Bump KLONKT_PROTO bij elke release die federatie/security
     24// raakt, en koppel een securityfix aan elke bump → outdated = buiten + onveilig.
     25// MIN_PROTO = de laagste proto waarmee we nog federeren.
     26export const KLONKT_PROTO = 2;
     27export const MIN_PROTO = 2;
     28
     29function signingInput(proto, body) {
     30  return `klonkt/proto/${proto}\n${body}`;
     31}
    1732
    1833// ── Sleutelbeheer ─────────────────────────────────────────────
     
    3752}
    3853
    39 /** Tekent een exacte body-string met de instance-privésleutel (Ed25519). */
    40 export function signBody(rawString) {
     54/** Tekent een body-string, gebonden aan de protocol-versie (Ed25519). */
     55export function signBody(rawString, proto = KLONKT_PROTO) {
    4156  const key = crypto.createPrivateKey(getKeys().priv);
    42   return crypto.sign(null, Buffer.from(rawString, 'utf8'), key).toString('base64');
     57  return crypto.sign(null, Buffer.from(signingInput(proto, rawString), 'utf8'), key).toString('base64');
    4358}
    4459
    45 /** Verifieert een body tegen een SPKI-DER-base64 publieke sleutel (voor sync/tests). */
    46 export function verifyBody(rawString, sigB64, pubDerB64) {
     60/** Verifieert een body tegen een SPKI-DER-base64 publieke sleutel, voor de gegeven
     61 *  proto. Een mismatch in proto = mismatch in grondslag = ongeldige handtekening. */
     62export function verifyBody(rawString, sigB64, pubDerB64, proto = KLONKT_PROTO) {
    4763  try {
    4864    const key = crypto.createPublicKey({
    4965      key: Buffer.from(pubDerB64, 'base64'), format: 'der', type: 'spki',
    5066    });
    51     return crypto.verify(null, Buffer.from(rawString, 'utf8'), key, Buffer.from(sigB64, 'base64'));
     67    return crypto.verify(null, Buffer.from(signingInput(proto, rawString), 'utf8'), key, Buffer.from(sigB64, 'base64'));
    5268  } catch {
    5369    return false;
     
    101117      publicKeyBase64: getPublicKeyB64(),
    102118    },
    103     klonkt: { version: 1, allowCircle: allowsCircle(site) },
     119    klonkt: { version: 1, proto: KLONKT_PROTO, allowCircle: allowsCircle(site) },
    104120  };
    105121}
     
    111127  const empty = {
    112128    '@context': 'https://www.w3.org/ns/activitystreams',
    113     type: 'OrderedCollection', id, totalItems: 0, orderedItems: [],
     129    type: 'OrderedCollection', id, totalItems: 0, orderedItems: [], klonkt: { proto: KLONKT_PROTO },
    114130  };
    115131  if (!allowsCircle(site)) return empty;
     
    148164    '@context': 'https://www.w3.org/ns/activitystreams',
    149165    type: 'OrderedCollection', id, totalItems: orderedItems.length, orderedItems,
     166    klonkt: { proto: KLONKT_PROTO },
    150167  };
    151168}
Note: See TracChangeset for help on using the changeset viewer.