chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { compressPublicKey, sign } from '@pdsjs/core/crypto';
import { publicKeyToDidKey } from '@pdsjs/core/plc';
import { describe, expect, it } from 'vitest';
import { createVerifier, parseDidKey } from '../src/verifier.js';
import { vectors } from './helpers/vectors.js';
async function p256() {
const keys = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' },
true,
['sign', 'verify'],
);
const raw = new Uint8Array(
await crypto.subtle.exportKey('raw', keys.publicKey),
);
return {
didKey: publicKeyToDidKey(compressPublicKey(raw), 'p256'),
/** @param {Uint8Array} data */
sign: (data) => sign(keys.privateKey, data),
};
}
describe('parseDidKey', () => {
it('recognises the P-256 multicodec', () => {
const parsed = parseDidKey(vectors.kem.authorDidKey);
expect(parsed.curve).toBe('p256');
expect(parsed.publicKey.length).toBe(33);
});
it('rejects a non-did:key string', () => {
expect(() => parseDidKey('did:plc:aaaa')).toThrow(/did:key/);
});
});
describe('createVerifier', () => {
it('verifies a P-256 signature', async () => {
const key = await p256();
const data = new Uint8Array([1, 2, 3]);
expect(
await createVerifier().verify(key.didKey, data, await key.sign(data)),
).toBe(true);
});
it('rejects a tampered signature or data', async () => {
const key = await p256();
const data = new Uint8Array([1, 2, 3]);
const sig = await key.sign(data);
const badSig = sig.slice();
badSig[0] ^= 0xff;
expect(await createVerifier().verify(key.didKey, data, badSig)).toBe(false);
expect(
await createVerifier().verify(key.didKey, new Uint8Array([1, 2, 4]), sig),
).toBe(false);
});
it('rejects secp256k1 when no verifier is injected', async () => {
const verifier = createVerifier();
// did:key with the secp256k1 multicodec, the well-known example from the
// did:key spec (https://w3c-ccg.github.io/did-method-key/#secp256k1).
await expect(
verifier.verify(
'zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme',
new Uint8Array(1),
new Uint8Array(64),
),
).rejects.toThrow(/secp256k1/);
});
it('delegates secp256k1 to an injected verifier', async () => {
/** @type {any} */
let called = null;
const verifier = createVerifier({
secp256k1: async (publicKey, data, sig) => {
called = { publicKey, data, sig };
return true;
},
});
const didKey = 'did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme';
const data = new Uint8Array([1, 2, 3]);
const sig = new Uint8Array(64);
expect(await verifier.verify(didKey, data, sig)).toBe(true);
expect(called.data).toEqual(data);
expect(called.publicKey.length).toBe(33);
});
});