···
import { didForCreateOp, PlcClientError } from '@did-plc/lib'
describe('PLC server', () => {
+
let handle1 = 'at://alice.example.com'
+
let handle2 = 'at://bob.example.com'
let atpPds = 'https://example.com'
···
let signingKey: P256Keypair
let rotationKey1: P256Keypair
let rotationKey2: P256Keypair
+
let rotationKey3: P256Keypair
const server = await runTestServer({
···
signingKey = await P256Keypair.create()
rotationKey1 = await P256Keypair.create()
rotationKey2 = await P256Keypair.create()
+
rotationKey3 = await P256Keypair.create()
···
throw new Error('expected doc')
+
expect(doc.did).toEqual(did1)
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
+
expect(doc.alsoKnownAs).toEqual([handle1])
expect(doc.services).toEqual({
type: 'AtprotoPersonalDataServer',
···
it('registers a did', async () => {
+
did1 = await client.createDid({
signingKey: signingKey.did(),
rotationKeys: [rotationKey1.did(), rotationKey2.did()],
+
did2 = await client.createDid({
+
signingKey: signingKey.did(),
+
rotationKeys: [rotationKey3.did()],
it('retrieves did doc data', async () => {
+
const doc = await client.getDocumentData(did1)
it('can perform some updates', async () => {
const newRotationKey = await P256Keypair.create()
signingKey = await P256Keypair.create()
+
handle1 = 'at://ali.example2.com'
atpPds = 'https://example2.com'
+
await client.updateAtprotoKey(did1, rotationKey1, signingKey.did())
+
await client.updateRotationKeys(did1, rotationKey1, [
rotationKey1 = newRotationKey
+
await client.updateHandle(did1, rotationKey1, handle1)
+
await client.updatePds(did1, rotationKey1, atpPds)
+
const doc = await client.getDocumentData(did1)
+
it('does not allow *rotation* key types that we do not yet support', async () => {
+
// an ed25519 key, which we don't yet support
+
'did:key:z6MkjwbBXZnFqL8su24wGL2Fdjti6GSLv9SWdYGswfazUPm9'
+
const promise = client.updateRotationKeys(did2, rotationKey3, [
+
await expect(promise).rejects.toThrow(PlcClientError)
+
it('allows *verificationMethod* key types that we do not explicitly support', async () => {
+
// an ed25519 key, which we don't explicitly support
'did:key:z6MkjwbBXZnFqL8su24wGL2Fdjti6GSLv9SWdYGswfazUPm9'
+
// Note: atproto itself does not currently support ed25519 keys, but PLC
+
// does not have opinions about atproto (or other services!)
+
await client.updateAtprotoKey(did2, rotationKey3, newSigningKey)
+
const exoticSigningKeyFromTheFuture =
+
'did:key:zUC7K4ndUaGZgV7Cp2yJy6JtMoUHY6u7tkcSYUvPrEidqBmLCTLmi6d5WvwnUqejscAkERJ3bfjEiSYtdPkRSE8kSa11hFBr4sTgnbZ95SJj19PN2jdvJjyzpSZgxkyyxNnBNnY'
+
await client.updateAtprotoKey(
+
exoticSigningKeyFromTheFuture,
+
// check that we can still read back the rendered did document
+
const doc = await client.getDocument(did2)
+
expect(doc.verificationMethod).toEqual([
+
publicKeyMultibase: exoticSigningKeyFromTheFuture.slice(8),
+
it('does not allow syntactically invalid verificationMethod keys', async () => {
+
const promise1 = client.updateAtprotoKey(
+
'did:key:BJV2WY5DJMJQXGZJANFZSAYLXMVZW63LFEEQFY3ZP', // not b58 (b32!)
+
await expect(promise1).rejects.toThrow(PlcClientError)
+
const promise2 = client.updateAtprotoKey(
+
'did:banana', // a malformed did:key
await expect(promise2).rejects.toThrow(PlcClientError)
+
const promise3 = client.updateAtprotoKey(
+
'blah', // an even more malformed did:key
+
await expect(promise3).rejects.toThrow(PlcClientError)
+
it('does not allow unreasonably long verificationMethod keys', async () => {
+
const promise = client.updateAtprotoKey(
+
'did:key:z41vu8qtWtp8XRJ9Te5QhkyzU9ByBbiw7bZHKXDjZ8iYorixqZQmEZpxgVSteYirYWMBjqQuEbMYTDsCzXXCAanCSH2xG2cwpbCWGZ2coY2PnhbrDVo7QghsAHpm2X5zsRRwDLyUcm9MTNQAZuRs2B22ygQw3UwkKLA7PZ9ZQ9wMHppmkoaBapmUGaxRNjp1Mt4zxrm9RbEx8FiK3ANBL1fsjggNqvkKpbj6MjntRScPQnJCes9Vt1cFe3iwNP7Ya9RfbaKsVi1eothvSBcbWoouHActGeakHgqFLj1JpbkP7PL3hGGSWLQbXxzmdrfzBCYAtiUxGRvpf3JiaNA2WYbJTh58bzx',
+
await expect(promise).rejects.toThrow(PlcClientError)
it('retrieves the operation log', async () => {
+
const doc = await client.getDocumentData(did1)
+
const ops = await client.getOperationLog(did1)
+
const computedDoc = await plc.validateOperationLog(did1, ops)
expect(computedDoc).toEqual(doc)
it('rejects on bad updates', async () => {
const newKey = await P256Keypair.create()
+
const operation = client.updateAtprotoKey(did1, newKey, newKey.did())
await expect(operation).rejects.toThrow()
it('allows for recovery through a forked history', async () => {
const attackerKey = await P256Keypair.create()
+
await client.updateRotationKeys(did1, rotationKey2, [attackerKey.did()])
const newKey = await P256Keypair.create()
+
const ops = await client.getOperationLog(did1)
const forkPoint = ops.at(-2)
if (!check.is(forkPoint, plc.def.operation)) {
throw new Error('Could not find fork point')
···
+
await client.sendOperation(did1, op)
+
const doc = await client.getDocumentData(did1)
it('retrieves the auditable operation log', async () => {
+
const log = await client.getOperationLog(did1)
+
const auditable = await client.getAuditableLog(did1)
expect(auditable.length).toBe(log.length + 1)
expect(auditable.filter((op) => op.nullified).length).toBe(1)
···
it('retrieves the did doc', async () => {
+
const data = await client.getDocumentData(did1)
+
const doc = await client.getDocument(did1)
expect(doc).toEqual(plc.formatDidDoc(data))
···
keys.map(async (key) => {
+
await client.updateAtprotoKey(did1, rotationKey1, key.did())
···
expect(successes).toBe(1)
expect(failures).toBe(19)
+
const ops = await client.getOperationLog(did1)
+
await plc.validateOperationLog(did1, ops)
it('tombstones the did', async () => {
+
await client.tombstone(did1, rotationKey1)
+
const promise = client.getDocument(did1)
await expect(promise).rejects.toThrow(PlcClientError)
+
const promise2 = client.getDocumentData(did1)
await expect(promise2).rejects.toThrow(PlcClientError)
it('exports the data set', async () => {
const data = await client.export()
expect(data.every((row) => check.is(row, plc.def.exportedOp))).toBeTruthy()
+
expect(data.length).toBe(32)
for (let i = 1; i < data.length; i++) {
expect(data[i].createdAt >= data[i - 1].createdAt).toBeTruthy()
···
signingKey: signingKey.did(),
recoveryKey: rotationKey1.did(),