Something went wrong. Try again.
An AT Protocol Personal Data Server written in JavaScript pdsjs.dev
pds atproto
Something went wrong. Try again.
4.0 kB · 126 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127// Produces artifacts with the reference implementation for pds.js to verify.// Copied into the atproto worktree by scripts/space-reference/run.sh as a// scratch file; never committed there.
import { mkdirSync, writeFileSync } from 'node:fs';import { P256Keypair } from '@atproto/crypto';import { cidForLex, encode } from '@atproto/lex-cbor';import { calculateJwkThumbprint, exportJWK, generateKeyPair } from 'jose';import { it } from 'vitest';import { createSpaceToken } from '../src/credential.js';import { RepoCommit, serializeRepo } from '../src/index.js';
const OUT = process.env.OUT_DIR ?? '/tmp/ref-conformance';
const SPACE = 'at://did:plc:refauthority/space/com.example.forum/general';const AUTHOR = 'did:plc:refuser';
it('generates reference artifacts', async () => { mkdirSync(OUT, { recursive: true });
const keypair = await P256Keypair.create({ exportable: true }); const authority = await P256Keypair.create({ exportable: true });
// Paths chosen so canonical (length-first) order differs from lexicographic. const inputs = [ { collection: 'com.example.post', rkey: 'aaa', record: { $type: 'com.example.post', text: 'first' }, }, { collection: 'com.example.post', rkey: 'bbb', record: { $type: 'com.example.post', text: 'second' }, }, { collection: 'com.e.p', rkey: 'x', record: { $type: 'com.e.p', n: 42 } }, { collection: 'com.example.reply', rkey: 'zz', record: { $type: 'com.example.reply', deep: { nested: [1, 2, 3] } }, }, ];
const records = await Promise.all( inputs.map(async (i) => ({ collection: i.collection, rkey: i.rkey, cid: await cidForLex(i.record), bytes: encode(i.record), })), );
const repo = RepoCommit.fromRecords(records); const rev = '3mrxrefrevaaa'; const commit = await repo.sign( { space: SPACE, author: AUTHOR, rev }, keypair, );
const chunks: Uint8Array[] = []; for await (const chunk of serializeRepo(commit, records)) chunks.push(chunk); const total = chunks.reduce((n, c) => n + c.length, 0); const car = new Uint8Array(total); let off = 0; for (const c of chunks) { car.set(c, off); off += c.length; } writeFileSync(`${OUT}/repo.car`, car);
const delegationToken = await createSpaceToken( 'delegation', { iss: AUTHOR, sub: SPACE, aud: 'did:plc:refauthority#atproto_space_host' }, keypair, ); // The key a holder would prove possession of. A credential carries its // thumbprint in `cnf.jkt` and the reference refuses to mint one without it. const holder = await generateKeyPair('ES256', { extractable: true }); const dpopJkt = await calculateJwkThumbprint( await exportJWK(holder.publicKey), 'sha256', ); const credential = await createSpaceToken( 'credential', { iss: 'did:plc:refauthority', sub: SPACE, dpopJkt }, authority, );
const b64 = (b: Uint8Array) => Buffer.from(b).toString('base64'); writeFileSync( `${OUT}/manifest.json`, `${JSON.stringify( { producer: '@atproto/space', space: SPACE, author: AUTHOR, authority: 'did:plc:refauthority', userDidKey: keypair.did(), authorityDidKey: authority.did(), rev, recordCount: records.length, commit: { ver: commit.ver, hash: { $bytes: b64(commit.hash) }, ikm: { $bytes: b64(commit.ikm) }, sig: { $bytes: b64(commit.sig) }, mac: { $bytes: b64(commit.mac) }, rev: commit.rev, }, delegationToken, delegationAud: 'did:plc:refauthority#atproto_space_host', credential, credentialJkt: dpopJkt, expectedPaths: [ 'com.e.p/x', 'com.example.post/aaa', 'com.example.post/bbb', 'com.example.reply/zz', ], }, null, 2, )}\n`, ); console.log(`wrote ${OUT}/repo.car (${car.length} bytes) and manifest.json`);});