@atcute/did-plc 0.1.7 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -5
- package/dist/client.d.ts +68 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +127 -0
- package/dist/client.js.map +1 -0
- package/dist/data.d.ts +15 -9
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +97 -5
- package/dist/data.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/typedefs.d.ts +2 -0
- package/dist/typedefs.d.ts.map +1 -1
- package/dist/typedefs.js +21 -86
- package/dist/typedefs.js.map +1 -1
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +22 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +36 -1
- package/dist/utils.js.map +1 -1
- package/lib/client.ts +195 -0
- package/lib/data.ts +120 -6
- package/lib/index.ts +1 -0
- package/lib/typedefs.ts +23 -101
- package/lib/types.ts +23 -0
- package/lib/utils.ts +44 -1
- package/package.json +15 -10
package/dist/typedefs.js
CHANGED
|
@@ -34,10 +34,8 @@ const _unsignedLegacyCreateOperation = v.object({
|
|
|
34
34
|
prev: v.null(),
|
|
35
35
|
signingKey: didKeyString,
|
|
36
36
|
recoveryKey: didKeyString,
|
|
37
|
-
handle: v.string()
|
|
38
|
-
service: v
|
|
39
|
-
.string()
|
|
40
|
-
.assert((input) => input.length <= 512, `service endpoint too long (max 512 characters)`),
|
|
37
|
+
handle: v.string(),
|
|
38
|
+
service: v.string(),
|
|
41
39
|
});
|
|
42
40
|
export const unsignedLegacyCreateOperation = _unsignedLegacyCreateOperation;
|
|
43
41
|
export const legacyCreateOperation = _unsignedLegacyCreateOperation.extend({
|
|
@@ -46,92 +44,16 @@ export const legacyCreateOperation = _unsignedLegacyCreateOperation.extend({
|
|
|
46
44
|
// #endregion
|
|
47
45
|
// #region plc_operation
|
|
48
46
|
export const service = v.object({
|
|
49
|
-
type: v.string()
|
|
50
|
-
endpoint: v
|
|
51
|
-
.string()
|
|
52
|
-
.assert((input) => input.length <= 512, `service endpoint too long (max 512 characters)`),
|
|
47
|
+
type: v.string(),
|
|
48
|
+
endpoint: v.string(),
|
|
53
49
|
});
|
|
54
50
|
const _unsignedOperation = v.object({
|
|
55
51
|
type: v.literal('plc_operation'),
|
|
56
52
|
prev: v.string().nullable(),
|
|
57
|
-
rotationKeys: v.array(didKeyString)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
else if (length > 10) {
|
|
63
|
-
return v.err(`too many rotation keys (max 10 keys)`);
|
|
64
|
-
}
|
|
65
|
-
for (let i = 0; i < length; i++) {
|
|
66
|
-
const key = input[i];
|
|
67
|
-
for (let j = 0; j < i; j++) {
|
|
68
|
-
if (input[j] === key) {
|
|
69
|
-
return v.err({
|
|
70
|
-
message: `duplicate "${key}" rotation key`,
|
|
71
|
-
path: [i],
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return v.ok(input);
|
|
77
|
-
}),
|
|
78
|
-
verificationMethods: v.record(permissiveDidKeyString).chain((input) => {
|
|
79
|
-
const length = Object.keys(input).length;
|
|
80
|
-
if (length > 10) {
|
|
81
|
-
return v.err(`too many verification method entries (max 10)`);
|
|
82
|
-
}
|
|
83
|
-
for (const id in input) {
|
|
84
|
-
const key = input[id];
|
|
85
|
-
if (id.length > 32) {
|
|
86
|
-
return v.err({
|
|
87
|
-
message: `verification method id too long (max 32 characters)`,
|
|
88
|
-
path: [id],
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (key.length > 256) {
|
|
92
|
-
return v.err({
|
|
93
|
-
message: `verification method key too long (max 256 characters)`,
|
|
94
|
-
path: [id],
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return v.ok(input);
|
|
99
|
-
}),
|
|
100
|
-
alsoKnownAs: v
|
|
101
|
-
.array(v.string().assert((input) => input.length <= 256, `aka entry too long (max 256 characters)`))
|
|
102
|
-
.chain((input) => {
|
|
103
|
-
const length = input.length;
|
|
104
|
-
if (length > 10) {
|
|
105
|
-
return v.err(`too many aka entries (max 10)`);
|
|
106
|
-
}
|
|
107
|
-
for (let i = 0; i < length; i++) {
|
|
108
|
-
const aka = input[i];
|
|
109
|
-
for (let j = 0; j < i; j++) {
|
|
110
|
-
if (input[j] === aka) {
|
|
111
|
-
return v.err({
|
|
112
|
-
message: `duplicate "${aka}" aka entry`,
|
|
113
|
-
path: [i],
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return v.ok(input);
|
|
119
|
-
}),
|
|
120
|
-
services: v.record(service).chain((input) => {
|
|
121
|
-
const length = Object.keys(input).length;
|
|
122
|
-
if (length > 10) {
|
|
123
|
-
return v.err(`too many service entries (max 10)`);
|
|
124
|
-
}
|
|
125
|
-
for (const id in input) {
|
|
126
|
-
if (id.length > 32) {
|
|
127
|
-
return v.err({
|
|
128
|
-
message: `service id too long (max 32 characters)`,
|
|
129
|
-
path: [id],
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return v.ok(input);
|
|
134
|
-
}),
|
|
53
|
+
rotationKeys: v.array(didKeyString),
|
|
54
|
+
verificationMethods: v.record(permissiveDidKeyString),
|
|
55
|
+
alsoKnownAs: v.array(v.string()),
|
|
56
|
+
services: v.record(service),
|
|
135
57
|
});
|
|
136
58
|
export const unsignedOperation = _unsignedOperation;
|
|
137
59
|
export const operation = _unsignedOperation.extend({
|
|
@@ -169,4 +91,17 @@ export const indexedEntryLog = v
|
|
|
169
91
|
.tuple([_indexedEntry.extend({ operation: compatibleOperation })])
|
|
170
92
|
.concat(v.array(_indexedEntry.extend({ operation: operationOrTombstone })));
|
|
171
93
|
// #endregion
|
|
94
|
+
// #region Client response schemas
|
|
95
|
+
export const plcState = v.object({
|
|
96
|
+
did: didPlcString,
|
|
97
|
+
rotationKeys: v.array(didKeyString),
|
|
98
|
+
verificationMethods: v.record(permissiveDidKeyString),
|
|
99
|
+
alsoKnownAs: v.array(v.string()),
|
|
100
|
+
services: v.record(service),
|
|
101
|
+
});
|
|
102
|
+
export const sequencedEntry = _indexedEntry.extend({
|
|
103
|
+
type: v.literal('sequenced_op'),
|
|
104
|
+
seq: v.number(),
|
|
105
|
+
});
|
|
106
|
+
// #endregion
|
|
172
107
|
//# sourceMappingURL=typedefs.js.map
|
package/dist/typedefs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typedefs.js","sourceRoot":"","sources":["../lib/typedefs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAEpC,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,KAAK,CAAC,MAAM,YAAY,CAAC;AAEhC,kBAAkB;AAClB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;AAEvF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"typedefs.js","sourceRoot":"","sources":["../lib/typedefs.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -53,4 +53,21 @@ export type IndexedEntryLog = [
|
|
|
53
53
|
genesis: IndexedEntry<CompatibleOperation>,
|
|
54
54
|
...IndexedEntry<OperationOrTombstone>[]
|
|
55
55
|
];
|
|
56
|
+
/**
|
|
57
|
+
* current identity state derived from the did:plc operation log
|
|
58
|
+
*/
|
|
59
|
+
export interface PlcState {
|
|
60
|
+
did: DidPlcString;
|
|
61
|
+
rotationKeys: DidKeyString[];
|
|
62
|
+
verificationMethods: Record<string, DidKeyString>;
|
|
63
|
+
alsoKnownAs: string[];
|
|
64
|
+
services: Record<string, Service>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* operation entry with sequence number from /export endpoint
|
|
68
|
+
*/
|
|
69
|
+
export interface SequencedEntry extends IndexedEntry {
|
|
70
|
+
type: 'sequenced_op';
|
|
71
|
+
seq: number;
|
|
72
|
+
}
|
|
56
73
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;AAEtC,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;AAEtC,MAAM,WAAW,6BAA6B;IAC7C,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,YAAY,CAAC;IACzB,WAAW,EAAE,YAAY,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAsB,SAAQ,6BAA6B;IAC3E,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,SAAU,SAAQ,iBAAiB;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAU,SAAQ,iBAAiB;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,qBAAqB,CAAC;AAEpE,MAAM,MAAM,8BAA8B,GAAG,mBAAmB,GAAG,SAAS,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,oBAAoB,EAAE,CAAC,CAAC;AAErF,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,8BAA8B,GAAG,8BAA8B;IACtG,GAAG,EAAE,YAAY,CAAC;IAClB,SAAS,EAAE,CAAC,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB,CACtC,CAAC,SAAS,8BAA8B,GAAG,8BAA8B,CACxE,SAAQ,YAAY,CAAC,CAAC,CAAC;IACxB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,QAAQ,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,YAAY,CAAC,mBAAmB,CAAC;IAC1C,GAAG,YAAY,CAAC,oBAAoB,CAAC,EAAE;CACvC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnD,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;AAEtC,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;AAEtC,MAAM,WAAW,6BAA6B;IAC7C,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,YAAY,CAAC;IACzB,WAAW,EAAE,YAAY,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAsB,SAAQ,6BAA6B;IAC3E,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,SAAU,SAAQ,iBAAiB;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAU,SAAQ,iBAAiB;IACnD,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,qBAAqB,CAAC;AAEpE,MAAM,MAAM,8BAA8B,GAAG,mBAAmB,GAAG,SAAS,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,oBAAoB,EAAE,CAAC,CAAC;AAErF,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,8BAA8B,GAAG,8BAA8B;IACtG,GAAG,EAAE,YAAY,CAAC;IAClB,SAAS,EAAE,CAAC,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB,CACtC,CAAC,SAAS,8BAA8B,GAAG,8BAA8B,CACxE,SAAQ,YAAY,CAAC,CAAC,CAAC;IACxB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,QAAQ,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,MAAM,eAAe,GAAG;IAC7B,OAAO,EAAE,YAAY,CAAC,mBAAmB,CAAC;IAC1C,GAAG,YAAY,CAAC,oBAAoB,CAAC,EAAE;CACvC,CAAC;AAIF;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,GAAG,EAAE,YAAY,CAAC;IAClB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAClD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,YAAY;IACnD,IAAI,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACZ"}
|
package/dist/types.js
CHANGED
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":";AA+FA,aAAa"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
|
+
import type { PrivateKey } from '@atcute/crypto';
|
|
1
2
|
import * as t from './types.js';
|
|
2
3
|
export declare const wrapHttpPrefix: (str: string) => string;
|
|
3
4
|
export declare const wrapAtprotoPrefix: (str: string) => string;
|
|
5
|
+
/**
|
|
6
|
+
* derives the did:plc identifier from a genesis operation
|
|
7
|
+
* @param op signed genesis operation
|
|
8
|
+
* @returns the did:plc string
|
|
9
|
+
*/
|
|
10
|
+
export declare const deriveDidFromGenesisOp: (op: t.CompatibleOperation) => Promise<`did:plc:${string}`>;
|
|
4
11
|
export declare const normalizeOp: (op: t.CompatibleOperation) => t.Operation;
|
|
5
|
-
export declare const isSignedOperationValid: (allowedKeys:
|
|
12
|
+
export declare const isSignedOperationValid: (allowedKeys: `did:key:${string}`[], op: t.CompatibleOperationOrTombstone) => Promise<`did:key:${string}` | null>;
|
|
13
|
+
/**
|
|
14
|
+
* signs an unsigned plc operation
|
|
15
|
+
* @param op unsigned operation to sign
|
|
16
|
+
* @param key private key to sign with (must be one of the rotation keys)
|
|
17
|
+
* @returns signed operation
|
|
18
|
+
*/
|
|
19
|
+
export declare const signOperation: (op: t.UnsignedOperation, key: PrivateKey) => Promise<t.Operation>;
|
|
20
|
+
/**
|
|
21
|
+
* signs an unsigned plc tombstone
|
|
22
|
+
* @param op unsigned tombstone to sign
|
|
23
|
+
* @param key private key to sign with (must be one of the rotation keys)
|
|
24
|
+
* @returns signed tombstone
|
|
25
|
+
*/
|
|
26
|
+
export declare const signTombstone: (op: t.UnsignedTombstone, key: PrivateKey) => Promise<t.Tombstone>;
|
|
6
27
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAKjD,OAAO,KAAK,CAAC,MAAM,YAAY,CAAC;AAEhC,eAAO,MAAM,cAAc,yBAM1B,CAAC;AAEF,eAAO,MAAM,iBAAiB,yBAQ7B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,6DAIlC,CAAC;AAEF,eAAO,MAAM,WAAW,4CAqBvB,CAAC;AAEF,eAAO,MAAM,sBAAsB,mHAkBlC,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,oEAKzB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,oEAKzB,CAAC"}
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as CBOR from '@atcute/cbor';
|
|
2
2
|
import { verifySigWithDidKey } from '@atcute/crypto';
|
|
3
|
-
import { fromBase64Url } from '@atcute/multibase';
|
|
3
|
+
import { fromBase64Url, toBase32, toBase64Url } from '@atcute/multibase';
|
|
4
|
+
import { toSha256 } from '@atcute/uint8array';
|
|
4
5
|
import * as t from './types.js';
|
|
5
6
|
export const wrapHttpPrefix = (str) => {
|
|
6
7
|
if (str.startsWith('http://') || str.startsWith('https://')) {
|
|
@@ -15,6 +16,16 @@ export const wrapAtprotoPrefix = (str) => {
|
|
|
15
16
|
const stripped = str.replace('http://', '').replace('https://', '');
|
|
16
17
|
return `at://${stripped}`;
|
|
17
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* derives the did:plc identifier from a genesis operation
|
|
21
|
+
* @param op signed genesis operation
|
|
22
|
+
* @returns the did:plc string
|
|
23
|
+
*/
|
|
24
|
+
export const deriveDidFromGenesisOp = async (op) => {
|
|
25
|
+
const opBytes = CBOR.encode(op);
|
|
26
|
+
const hash = await toSha256(opBytes);
|
|
27
|
+
return `did:plc:${toBase32(hash).slice(0, 24)}`;
|
|
28
|
+
};
|
|
18
29
|
export const normalizeOp = (op) => {
|
|
19
30
|
if (op.type === 'create') {
|
|
20
31
|
return {
|
|
@@ -48,4 +59,28 @@ export const isSignedOperationValid = async (allowedKeys, op) => {
|
|
|
48
59
|
}
|
|
49
60
|
return null;
|
|
50
61
|
};
|
|
62
|
+
// #region signing operations
|
|
63
|
+
/**
|
|
64
|
+
* signs an unsigned plc operation
|
|
65
|
+
* @param op unsigned operation to sign
|
|
66
|
+
* @param key private key to sign with (must be one of the rotation keys)
|
|
67
|
+
* @returns signed operation
|
|
68
|
+
*/
|
|
69
|
+
export const signOperation = async (op, key) => {
|
|
70
|
+
const data = CBOR.encode(op);
|
|
71
|
+
const sig = await key.sign(data);
|
|
72
|
+
return { ...op, sig: toBase64Url(sig) };
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* signs an unsigned plc tombstone
|
|
76
|
+
* @param op unsigned tombstone to sign
|
|
77
|
+
* @param key private key to sign with (must be one of the rotation keys)
|
|
78
|
+
* @returns signed tombstone
|
|
79
|
+
*/
|
|
80
|
+
export const signTombstone = async (op, key) => {
|
|
81
|
+
const data = CBOR.encode(op);
|
|
82
|
+
const sig = await key.sign(data);
|
|
83
|
+
return { ...op, sig: toBase64Url(sig) };
|
|
84
|
+
};
|
|
85
|
+
// #endregion
|
|
51
86
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../lib/utils.ts"],"names":[],"mappings":"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"}
|
package/lib/client.ts
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { DidDocument } from '@atcute/identity';
|
|
2
|
+
import { defs as identityDefs } from '@atcute/identity';
|
|
3
|
+
import { FailedResponseError, isResponseOk, parseResponseAsJson, pipe, validateJsonWith } from '@atcute/util-fetch';
|
|
4
|
+
|
|
5
|
+
import * as defs from './typedefs.js';
|
|
6
|
+
import * as t from './types.js';
|
|
7
|
+
|
|
8
|
+
const MAX_RESPONSE_SIZE = 64 * 1024;
|
|
9
|
+
|
|
10
|
+
const handleDocument = pipe(
|
|
11
|
+
isResponseOk,
|
|
12
|
+
parseResponseAsJson(/^application\/(did\+ld\+)?json$/, MAX_RESPONSE_SIZE),
|
|
13
|
+
validateJsonWith(identityDefs.didDocument, { mode: 'passthrough' }),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const handlePlcState = pipe(
|
|
17
|
+
isResponseOk,
|
|
18
|
+
parseResponseAsJson(/^application\/json$/, MAX_RESPONSE_SIZE),
|
|
19
|
+
validateJsonWith(defs.plcState, { mode: 'passthrough' }),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const handleOperationLog = pipe(
|
|
23
|
+
isResponseOk,
|
|
24
|
+
parseResponseAsJson(/^application\/json$/, MAX_RESPONSE_SIZE),
|
|
25
|
+
validateJsonWith(defs.operationLog, { mode: 'passthrough' }),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const handleIndexedEntryLog = pipe(
|
|
29
|
+
isResponseOk,
|
|
30
|
+
parseResponseAsJson(/^application\/json$/, MAX_RESPONSE_SIZE),
|
|
31
|
+
validateJsonWith(defs.indexedEntryLog, { mode: 'passthrough' }),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const handleLastOperation = pipe(
|
|
35
|
+
isResponseOk,
|
|
36
|
+
parseResponseAsJson(/^application\/json$/, MAX_RESPONSE_SIZE),
|
|
37
|
+
validateJsonWith(defs.compatibleOperationOrTombstone, { mode: 'passthrough' }),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export interface PlcClientOptions {
|
|
41
|
+
/** plc directory URL, defaults to https://plc.directory */
|
|
42
|
+
serviceUrl?: string;
|
|
43
|
+
/** custom fetch function */
|
|
44
|
+
fetch?: typeof globalThis.fetch;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface PlcRequestOptions {
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* client for interacting with plc.directory
|
|
53
|
+
*/
|
|
54
|
+
export class PlcClient {
|
|
55
|
+
readonly serviceUrl: string;
|
|
56
|
+
#fetch: typeof globalThis.fetch;
|
|
57
|
+
|
|
58
|
+
constructor({ serviceUrl = 'https://plc.directory', fetch: fetchFn = fetch }: PlcClientOptions = {}) {
|
|
59
|
+
this.serviceUrl = serviceUrl;
|
|
60
|
+
this.#fetch = fetchFn;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* fetches the DID document for a did:plc
|
|
65
|
+
* @param did the did:plc identifier
|
|
66
|
+
* @param options request options
|
|
67
|
+
* @returns the DID document
|
|
68
|
+
*/
|
|
69
|
+
async getDocument(did: t.DidPlcString, options?: PlcRequestOptions): Promise<DidDocument> {
|
|
70
|
+
const url = new URL(`/${encodeURIComponent(did)}`, this.serviceUrl);
|
|
71
|
+
|
|
72
|
+
const response = await this.#fetch(url, {
|
|
73
|
+
signal: options?.signal,
|
|
74
|
+
headers: { accept: 'application/did+ld+json,application/json' },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const { json } = await handleDocument(response);
|
|
78
|
+
return json;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* fetches the current identity state for a did:plc
|
|
83
|
+
* @param did the did:plc identifier
|
|
84
|
+
* @param options request options
|
|
85
|
+
* @returns the current plc state
|
|
86
|
+
*/
|
|
87
|
+
async getState(did: t.DidPlcString, options?: PlcRequestOptions): Promise<t.PlcState> {
|
|
88
|
+
const url = new URL(`/${encodeURIComponent(did)}/data`, this.serviceUrl);
|
|
89
|
+
|
|
90
|
+
const response = await this.#fetch(url, {
|
|
91
|
+
signal: options?.signal,
|
|
92
|
+
headers: { accept: 'application/json' },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const { json } = await handlePlcState(response);
|
|
96
|
+
return json;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* fetches the operation log for a did:plc
|
|
101
|
+
* @param did the did:plc identifier
|
|
102
|
+
* @param options request options
|
|
103
|
+
* @returns the operation log
|
|
104
|
+
*/
|
|
105
|
+
async getOperationLog(did: t.DidPlcString, options?: PlcRequestOptions): Promise<t.OperationLog> {
|
|
106
|
+
const url = new URL(`/${encodeURIComponent(did)}/log`, this.serviceUrl);
|
|
107
|
+
|
|
108
|
+
const response = await this.#fetch(url, {
|
|
109
|
+
signal: options?.signal,
|
|
110
|
+
headers: { accept: 'application/json' },
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const { json } = await handleOperationLog(response);
|
|
114
|
+
return json;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* fetches the auditable log for a did:plc (includes CIDs and timestamps)
|
|
119
|
+
* @param did the did:plc identifier
|
|
120
|
+
* @param options request options
|
|
121
|
+
* @returns the indexed entry log
|
|
122
|
+
*/
|
|
123
|
+
async getAuditLog(did: t.DidPlcString, options?: PlcRequestOptions): Promise<t.IndexedEntryLog> {
|
|
124
|
+
const url = new URL(`/${encodeURIComponent(did)}/log/audit`, this.serviceUrl);
|
|
125
|
+
|
|
126
|
+
const response = await this.#fetch(url, {
|
|
127
|
+
signal: options?.signal,
|
|
128
|
+
headers: { accept: 'application/json' },
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const { json } = await handleIndexedEntryLog(response);
|
|
132
|
+
return json;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* fetches the last operation for a did:plc
|
|
137
|
+
* @param did the did:plc identifier
|
|
138
|
+
* @param options request options
|
|
139
|
+
* @returns the last operation or tombstone
|
|
140
|
+
*/
|
|
141
|
+
async getLastOperation(
|
|
142
|
+
did: t.DidPlcString,
|
|
143
|
+
options?: PlcRequestOptions,
|
|
144
|
+
): Promise<t.CompatibleOperationOrTombstone> {
|
|
145
|
+
const url = new URL(`/${encodeURIComponent(did)}/log/last`, this.serviceUrl);
|
|
146
|
+
|
|
147
|
+
const response = await this.#fetch(url, {
|
|
148
|
+
signal: options?.signal,
|
|
149
|
+
headers: { accept: 'application/json' },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const { json } = await handleLastOperation(response);
|
|
153
|
+
return json;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* submits a signed operation to plc.directory
|
|
158
|
+
* @param did the did:plc identifier
|
|
159
|
+
* @param operation the signed operation to submit
|
|
160
|
+
* @param options request options
|
|
161
|
+
*/
|
|
162
|
+
async submitOperation(
|
|
163
|
+
did: t.DidPlcString,
|
|
164
|
+
operation: t.OperationOrTombstone,
|
|
165
|
+
options?: PlcRequestOptions,
|
|
166
|
+
): Promise<void> {
|
|
167
|
+
const url = new URL(`/${encodeURIComponent(did)}`, this.serviceUrl);
|
|
168
|
+
|
|
169
|
+
const response = await this.#fetch(url, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
signal: options?.signal,
|
|
172
|
+
headers: { 'content-type': 'application/json' },
|
|
173
|
+
body: JSON.stringify(operation),
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
throw new FailedResponseError(response);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* checks if the plc directory is reachable
|
|
183
|
+
* @param options request options
|
|
184
|
+
* @returns true if reachable
|
|
185
|
+
*/
|
|
186
|
+
async ping(options?: PlcRequestOptions): Promise<boolean> {
|
|
187
|
+
const url = new URL('/_health', this.serviceUrl);
|
|
188
|
+
|
|
189
|
+
const response = await this.#fetch(url, {
|
|
190
|
+
signal: options?.signal,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return response.ok;
|
|
194
|
+
}
|
|
195
|
+
}
|
package/lib/data.ts
CHANGED
|
@@ -1,12 +1,127 @@
|
|
|
1
1
|
import * as CBOR from '@atcute/cbor';
|
|
2
2
|
import * as CID from '@atcute/cid';
|
|
3
|
-
import {
|
|
4
|
-
import { toSha256 } from '@atcute/uint8array';
|
|
3
|
+
import { isKeyDid } from '@atcute/identity';
|
|
5
4
|
|
|
6
5
|
import { DISPUTE_WINDOW } from './constants.js';
|
|
7
6
|
import * as err from './errors.js';
|
|
8
7
|
import * as t from './types.js';
|
|
9
|
-
import { isSignedOperationValid, normalizeOp } from './utils.js';
|
|
8
|
+
import { deriveDidFromGenesisOp, isSignedOperationValid, normalizeOp } from './utils.js';
|
|
9
|
+
|
|
10
|
+
// soft constraint limits for incoming operations
|
|
11
|
+
const MAX_OP_BYTES = 4000;
|
|
12
|
+
const MAX_AKA_ENTRIES = 10;
|
|
13
|
+
const MAX_AKA_LENGTH = 258; // max handle length (253) plus at:// prefix (5)
|
|
14
|
+
const MAX_ROTATION_ENTRIES = 10;
|
|
15
|
+
const MAX_SERVICE_ENTRIES = 10;
|
|
16
|
+
const MAX_SERVICE_TYPE_LENGTH = 256;
|
|
17
|
+
const MAX_SERVICE_ENDPOINT_LENGTH = 512;
|
|
18
|
+
const MAX_VERIFICATION_METHOD_ENTRIES = 10;
|
|
19
|
+
const MAX_ID_LENGTH = 32;
|
|
20
|
+
const MAX_DID_KEY_LENGTH = 256; // k256 = 57, BLS12-381 = 143
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validate an incoming operation against soft constraints (length limits, counts, duplicates).
|
|
24
|
+
* This should be used when preparing to submit a new operation to plc.directory.
|
|
25
|
+
* Historical operations should only be validated against hard constraints (structure, signatures, hashes).
|
|
26
|
+
*/
|
|
27
|
+
export const validateIncomingOp = (op: t.CompatibleOperationOrTombstone): void => {
|
|
28
|
+
// Check CBOR size limit
|
|
29
|
+
const byteLength = CBOR.encode(op).byteLength;
|
|
30
|
+
if (byteLength > MAX_OP_BYTES) {
|
|
31
|
+
throw new Error(`operation too large (${MAX_OP_BYTES} bytes maximum in cbor encoding)`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (op.type === 'plc_tombstone') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
op = normalizeOp(op);
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
const alsoKnownAs = op.alsoKnownAs;
|
|
42
|
+
|
|
43
|
+
if (alsoKnownAs.length > MAX_AKA_ENTRIES) {
|
|
44
|
+
throw new Error(`too many alsoKnownAs entries (max ${MAX_AKA_ENTRIES})`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const alsoKnownAsDupe = new Set<string>();
|
|
48
|
+
for (const aka of alsoKnownAs) {
|
|
49
|
+
if (aka.length > MAX_AKA_LENGTH) {
|
|
50
|
+
throw new Error(`alsoKnownAs entry too long (max ${MAX_AKA_LENGTH}): ${aka}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (alsoKnownAsDupe.has(aka)) {
|
|
54
|
+
throw new Error(`duplicate alsoKnownAs entry: ${aka}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
alsoKnownAsDupe.add(aka);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
{
|
|
62
|
+
const rotationKeys = op.rotationKeys;
|
|
63
|
+
|
|
64
|
+
if (rotationKeys.length === 0) {
|
|
65
|
+
throw new Error(`missing rotation keys`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (rotationKeys.length > MAX_ROTATION_ENTRIES) {
|
|
69
|
+
throw new Error(`too many rotationKey entries (max ${MAX_ROTATION_ENTRIES})`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const rotationKeyDupe = new Set<string>();
|
|
73
|
+
for (const key of rotationKeys) {
|
|
74
|
+
if (rotationKeyDupe.has(key)) {
|
|
75
|
+
throw new Error(`duplicate rotation key: ${key}`);
|
|
76
|
+
}
|
|
77
|
+
rotationKeyDupe.add(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
{
|
|
82
|
+
const services = Object.entries(op.services);
|
|
83
|
+
|
|
84
|
+
if (services.length > MAX_SERVICE_ENTRIES) {
|
|
85
|
+
throw new Error(`too many service entries (max ${MAX_SERVICE_ENTRIES})`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const [id, service] of services) {
|
|
89
|
+
if (id.length > MAX_ID_LENGTH) {
|
|
90
|
+
throw new Error(`service id too long (max ${MAX_ID_LENGTH}): ${id}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (service.type.length > MAX_SERVICE_TYPE_LENGTH) {
|
|
94
|
+
throw new Error(`service type too long (max ${MAX_SERVICE_TYPE_LENGTH})`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (service.endpoint.length > MAX_SERVICE_ENDPOINT_LENGTH) {
|
|
98
|
+
throw new Error(`service endpoint too long (max ${MAX_SERVICE_ENDPOINT_LENGTH})`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
{
|
|
104
|
+
const verificationMethods = Object.entries(op.verificationMethods);
|
|
105
|
+
|
|
106
|
+
if (verificationMethods.length > MAX_VERIFICATION_METHOD_ENTRIES) {
|
|
107
|
+
throw new Error(`too many verification method entries (max ${MAX_VERIFICATION_METHOD_ENTRIES})`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const [id, key] of verificationMethods) {
|
|
111
|
+
if (id.length > MAX_ID_LENGTH) {
|
|
112
|
+
throw new Error(`verification method id too long (max ${MAX_ID_LENGTH}): ${id}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (key.length > MAX_DID_KEY_LENGTH) {
|
|
116
|
+
throw new Error(`verification method key too long (max ${MAX_DID_KEY_LENGTH}): ${key}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!isKeyDid(key)) {
|
|
120
|
+
throw new Error(`invalid verification method key: ${key}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
10
125
|
|
|
11
126
|
/**
|
|
12
127
|
* Process an indexed entry by validating it and integrating it into the canonical log.
|
|
@@ -31,13 +146,12 @@ export const processIndexedEntry = async (
|
|
|
31
146
|
|
|
32
147
|
// Check if CID and DID matches
|
|
33
148
|
{
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const expectedDid = `did:plc:${toBase32(await toSha256(opBytes)).slice(0, 24)}`;
|
|
149
|
+
const expectedDid = await deriveDidFromGenesisOp(proposed.operation);
|
|
37
150
|
if (expectedDid !== did) {
|
|
38
151
|
throw new err.GenesisHashError(proposed, did);
|
|
39
152
|
}
|
|
40
153
|
|
|
154
|
+
const opBytes = CBOR.encode(proposed.operation);
|
|
41
155
|
const expectedCid = CID.toString(await CID.create(CID.CODEC_DCBOR, opBytes));
|
|
42
156
|
if (expectedCid !== proposed.cid) {
|
|
43
157
|
throw new err.InvalidHashError(proposed, expectedCid);
|