Ignore:
Timestamp:
10/24/2026 11:48:41 AM (24 hours ago)
Author:
Bart <bart@…>
Branches:
main
Children:
5d0d3f35
Parents:
61d52ed
Message:

Identiteitsbewijzen (FEP-c390): een sleutel van elders zegt dat dit account van hem is

Een Ed25519-sleutel die niet op deze server staat -- in Shaer op papier, alleen
ingetypt als hij nodig is -- ondertekent een VerifiableIdentityStatement:
"did:key:... is ook deze actor". Klonkt ondertekent niets. Hij controleert de
verklaring en zet hem onder attachment op de actor, waar iedereen hem zelf
kan nalopen.

Wat dat bewijst: dat dezelfde entiteit achter sleutel en account zit. Verhuist
het account, dan draagt het nieuwe dezelfde did:key, en dat bewijst de
continuiteit ook als de oude server weg of vijandig is -- een Move kan dat niet,
want die moet door de OUDE server getekend worden.

eddsa-jcs-2022, omdat Mitra en streams dat controleren. IdentityProof.js is
puur: JCS (RFC 8785, in JavaScript precies een gesorteerde JSON.stringify),
base58btc, did:key en de proof zelf. De controle volgt c390 regel voor regel,
met een eigen reden per weigering; verificationMethod moet PRECIES de subject
zijn, zonder het #-fragment dat de W3C-voorbeelden gebruiken.

Getoetst tegen de W3C-testvectoren (vc-di-eddsa B.3): dezelfde did:key, dezelfde
canonieke vorm, dezelfde hashes en byte voor byte dezelfde handtekening. Een
implementatie die het alleen met zichzelf eens is, bewijst niets.

POST /ap/users/:slug/identityProofs (alleen de eigenaar) controleert en
publiceert, één per did:key, hoogstens drie; DELETE ?subject= haalt hem weg.
Beide sturen een Update van de actor naar de volgers. De actor noemt het
eindpunt als endpoints.shaer:identityProofs. Elke verklaring draagt haar eigen
@context, zodat de actor er geen bij hoeft -- did/v1 en data-integrity/v1 hebben
beschermde termen die op actorniveau met onze inline context konden botsen.

shaer-jpxj
Co-Authored-By: Claude Opus 5.5 <claude@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r61d52ed rb1d5f3f  
    393393      oauthTokenEndpoint: `${base}/oauth/token`,
    394394      uploadMedia: `${id}/uploadMedia`,
     395      // FEP-c390 (shaer-jpxj): waar de eigenaar een identiteitsbewijs aanbiedt.
     396      // Alleen met zijn token; Shaer vindt het hier in plaats van het te raden.
     397      'shaer:identityProofs': `${id}/identityProofs`,
    395398    },
    396399    publicKey: {
    … …  
    449452    }
    450453  } catch { /* skip malformed profile_links */ }
     454  // FEP-c390: de identiteitsbewijzen, ACHTER de profiellinks. Ongewijzigd uit de
     455  // database: ze werden bij binnenkomst gecontroleerd, en een handtekening hangt
     456  // aan elke byte. Elke verklaring draagt haar eigen @context, dus de actor zelf
     457  // hoeft er geen bij.
     458  try {
     459    const bewijzen = JSON.parse(site.identity_proofs || '[]');
     460    if (Array.isArray(bewijzen) && bewijzen.length) {
     461      actor.attachment = [...(actor.attachment || []), ...bewijzen.filter((b) => b && b.type === 'VerifiableIdentityStatement')];
     462    }
     463  } catch { /* skip malformed identity_proofs */ }
    451464  return actor;
    452465}
Note: See TracChangeset for help on using the changeset viewer.