···
import { check, cidForCbor } from '@atproto/common'
2
-
import { EcdsaKeypair, Keypair, Secp256k1Keypair } from '@atproto/crypto'
2
+
import { EcdsaKeypair, Secp256k1Keypair } from '@atproto/crypto'
···
let rotationKey1: Secp256k1Keypair
let rotationKey2: EcdsaKeypair
20
-
let handle = 'alice.example.com'
20
+
let handle = 'at://alice.example.com'
let atpPds = 'https://example.com'
let oldRotationKey1: Secp256k1Keypair
···
rotationKey2 = await EcdsaKeypair.create()
31
-
const makeNextOp = async (
32
-
changes: Partial<t.Operation>,
34
-
): Promise<t.Operation> => {
31
+
const lastOp = () => {
const lastOp = ops.at(-1)
throw new Error('expected an op on log')
39
-
const prev = await cidForCbor(lastOp)
40
-
return operations.signOperation(
42
-
type: 'plc_operation',
43
-
verificationMethods: lastOp.verificationMethods,
44
-
rotationKeys: lastOp.rotationKeys,
45
-
alsoKnownAs: lastOp.alsoKnownAs,
46
-
services: lastOp.services,
47
-
prev: prev.toString(),
39
+
const verifyDoc = (doc: t.DocumentData | null) => {
41
+
throw new Error('expected doc')
43
+
expect(doc.did).toEqual(did)
44
+
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
45
+
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
46
+
expect(doc.alsoKnownAs).toEqual([handle])
47
+
expect(doc.services).toEqual({
49
+
type: 'AtprotoPersonalDataServer',
it('creates a valid create op', async () => {
55
-
const createOp = await operations.signOperation(
57
-
type: 'plc_operation',
58
-
verificationMethods: {
59
-
atproto: signingKey.did(),
61
-
rotationKeys: [rotationKey1.did(), rotationKey2.did()],
62
-
alsoKnownAs: [handle],
56
+
const createOp = await operations.atprotoOp({
57
+
signingKey: signingKey.did(),
58
+
rotationKeys: [rotationKey1.did(), rotationKey2.did()],
62
+
signer: rotationKey1,
const isValid = check.is(createOp, t.def.operation)
expect(isValid).toBeTruthy()
···
it('parses an operation log with no updates', async () => {
const doc = await data.validateOperationLog(did, ops)
80
-
throw new Error('expected doc')
82
-
expect(doc.did).toEqual(did)
83
-
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
84
-
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
85
-
expect(doc.alsoKnownAs).toEqual([handle])
86
-
expect(doc.services).toEqual({ atpPds })
it('updates handle', async () => {
90
-
handle = 'ali.example2.com'
91
-
const op = await makeNextOp({ alsoKnownAs: [handle] }, rotationKey1)
76
+
handle = 'at://ali.example2.com'
77
+
const op = await operations.updateHandleOp(lastOp(), rotationKey1, handle)
const doc = await data.validateOperationLog(did, ops)
96
-
throw new Error('expected doc')
98
-
expect(doc.did).toEqual(did)
99
-
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
100
-
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
101
-
expect(doc.alsoKnownAs).toEqual([handle])
102
-
expect(doc.services).toEqual({ atpPds })
it('updates atpPds', async () => {
atpPds = 'https://example2.com'
107
-
const op = await makeNextOp(
86
+
const op = await operations.updatePdsOp(lastOp(), rotationKey1, atpPds)
const doc = await data.validateOperationLog(did, ops)
119
-
throw new Error('expected doc')
121
-
expect(doc.did).toEqual(did)
122
-
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
123
-
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
124
-
expect(doc.alsoKnownAs).toEqual([handle])
125
-
expect(doc.services).toEqual({ atpPds })
it('rotates signingKey', async () => {
const newSigningKey = await Secp256k1Keypair.create()
130
-
const op = await makeNextOp(
132
-
verificationMethods: {
133
-
atproto: newSigningKey.did(),
95
+
const op = await operations.updateAtprotoKeyOp(
98
+
newSigningKey.did(),
signingKey = newSigningKey
const doc = await data.validateOperationLog(did, ops)
144
-
throw new Error('expected doc')
146
-
expect(doc.did).toEqual(did)
147
-
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
148
-
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
149
-
expect(doc.alsoKnownAs).toEqual([handle])
150
-
expect(doc.services).toEqual({ atpPds })
it('rotates rotation keys', async () => {
const newRotationKey = await Secp256k1Keypair.create()
155
-
const op = await makeNextOp(
157
-
rotationKeys: [newRotationKey.did(), rotationKey2.did()],
110
+
const op = await operations.updateRotationkeysOp(lastOp(), rotationKey1, [
111
+
newRotationKey.did(),
112
+
rotationKey2.did(),
oldRotationKey1 = rotationKey1
rotationKey1 = newRotationKey
const doc = await data.validateOperationLog(did, ops)
168
-
throw new Error('expected doc')
171
-
expect(doc.did).toEqual(did)
172
-
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
173
-
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
174
-
expect(doc.alsoKnownAs).toEqual([handle])
175
-
expect(doc.services).toEqual({ atpPds })
it('no longer allows operations from old rotation key', async () => {
179
-
const op = await makeNextOp(
181
-
alsoKnownAs: ['bob'],
124
+
const op = await operations.updateHandleOp(
expect(data.validateOperationLog(did, [...ops, op])).rejects.toThrow(
···
it('does not allow operations from the signingKey', async () => {
191
-
const op = await makeNextOp(
193
-
alsoKnownAs: ['bob'],
135
+
const op = await operations.updateHandleOp(lastOp(), signingKey, 'at://bob')
expect(data.validateOperationLog(did, [...ops, op])).rejects.toThrow(
it('allows for operations from either rotation key', async () => {
203
-
const newHandle = 'ali.example.com'
204
-
const op = await makeNextOp(
206
-
alsoKnownAs: [newHandle],
142
+
const newHandle = 'at://ali.example.com'
143
+
const op = await operations.updateHandleOp(
const doc = await data.validateOperationLog(did, ops)
214
-
throw new Error('expected doc')
216
-
expect(doc.did).toEqual(did)
217
-
expect(doc.verificationMethods).toEqual({ atproto: signingKey.did() })
218
-
expect(doc.rotationKeys).toEqual([rotationKey1.did(), rotationKey2.did()])
219
-
expect(doc.alsoKnownAs).toEqual([handle])
220
-
expect(doc.services).toEqual({ atpPds })
it('allows tombstoning a DID', async () => {
···
it('requires operations to be in order', async () => {
231
-
const prev = await cidForCbor(ops[ops.length - 2])
232
-
const op = await makeNextOp(
234
-
alsoKnownAs: ['bob.test'],
235
-
prev: prev.toString(),
162
+
const op = await operations.updateHandleOp(
163
+
ops[ops.length - 2],
expect(data.validateOperationLog(did, [...ops, op])).rejects.toThrow(
MisorderedOperationError,
···
it('does not allow a create operation in the middle of the log', async () => {
245
-
const op = await makeNextOp(
247
-
alsoKnownAs: ['bob.test'],
173
+
const op = await operations.atprotoOp({
174
+
signingKey: signingKey.did(),
175
+
rotationKeys: [rotationKey1.did(), rotationKey2.did()],
179
+
signer: rotationKey1,
expect(data.validateOperationLog(did, [...ops, op])).rejects.toThrow(
MisorderedOperationError,