@atcute/lexicon-resolver 0.1.2 → 0.1.4
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/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/schemas/xrpc.d.ts.map +1 -1
- package/dist/schemas/xrpc.js +22 -4
- package/dist/schemas/xrpc.js.map +1 -1
- package/lib/constants.ts +1 -1
- package/lib/errors.ts +0 -1
- package/lib/index.ts +1 -1
- package/lib/schemas/xrpc.ts +30 -4
- package/package.json +8 -11
- package/dist/schemas/verify.d.ts +0 -19
- package/dist/schemas/verify.d.ts.map +0 -1
- package/dist/schemas/verify.js +0 -169
- package/dist/schemas/verify.js.map +0 -1
- package/lib/schemas/verify.ts +0 -245
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD,qBAAa,+BAAgC,SAAQ,KAAK;IAChD,IAAI,SAAqC;CAClD;AAED,qBAAa,sBAAuB,SAAQ,+BAA+B;IAGvD,IAAI,EAAE,IAAI;IAFpB,IAAI,SAA4B;gBAEtB,IAAI,EAAE,IAAI;CAG7B;AAED,qBAAa,8BAA+B,SAAQ,+BAA+B;IAI1E,IAAI,EAAE,IAAI;IAHT,IAAI,SAAoC;gBAGzC,IAAI,EAAE,IAAI,EACjB,OAAO,CAAC,EAAE,YAAY;CAIvB;AAED,qBAAa,6BAA8B,SAAQ,+BAA+B;IAIzE,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,MAAM;IAJV,IAAI,SAAmC;gBAGxC,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM;CAInB;AAED,qBAAa,uBAAwB,SAAQ,+BAA+B;IAGxD,IAAI,EAAE,IAAI;IAFpB,IAAI,SAA6B;gBAEvB,IAAI,EAAE,IAAI;CAG7B;AAID,qBAAa,sBAAuB,SAAQ,KAAK;IACvC,IAAI,SAA4B;CACzC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD,qBAAa,+BAAgC,SAAQ,KAAK;IAChD,IAAI,SAAqC;CAClD;AAED,qBAAa,sBAAuB,SAAQ,+BAA+B;IAGvD,IAAI,EAAE,IAAI;IAFpB,IAAI,SAA4B;gBAEtB,IAAI,EAAE,IAAI;CAG7B;AAED,qBAAa,8BAA+B,SAAQ,+BAA+B;IAI1E,IAAI,EAAE,IAAI;IAHT,IAAI,SAAoC;gBAGzC,IAAI,EAAE,IAAI,EACjB,OAAO,CAAC,EAAE,YAAY;CAIvB;AAED,qBAAa,6BAA8B,SAAQ,+BAA+B;IAIzE,IAAI,EAAE,IAAI;IACV,GAAG,EAAE,MAAM;IAJV,IAAI,SAAmC;gBAGxC,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,MAAM;CAInB;AAED,qBAAa,uBAAwB,SAAQ,+BAA+B;IAGxD,IAAI,EAAE,IAAI;IAFpB,IAAI,SAA6B;gBAEvB,IAAI,EAAE,IAAI;CAG7B;AAID,qBAAa,sBAAuB,SAAQ,KAAK;IACvC,IAAI,SAA4B;CACzC;AAED,qBAAa,4BAA6B,SAAQ,sBAAsB;IAI/D,IAAI,EAAE,IAAI;IAHT,IAAI,SAAkC;gBAGvC,IAAI,EAAE,IAAI,EACjB,OAAO,CAAC,EAAE,YAAY;CAIvB;AAED,qBAAa,yBAA0B,SAAQ,sBAAsB;IAI5D,IAAI,EAAE,IAAI;IAHT,IAAI,SAA+B;gBAGpC,IAAI,EAAE,IAAI,EACjB,OAAO,CAAC,EAAE,YAAY;CAIvB;AAED,qBAAa,wBAAyB,SAAQ,sBAAsB;IAI3D,IAAI,EAAE,IAAI;IAHT,IAAI,SAA8B;gBAGnC,IAAI,EAAE,IAAI,EACjB,OAAO,CAAC,EAAE,YAAY;CAIvB"}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../lib/errors.ts"],"names":[],"mappings":"AAEA,8CAA8C;AAC9C,MAAM,OAAO,+BAAgC,SAAQ,KAAK;IAChD,IAAI,GAAG,iCAAiC,CAAC;CAClD;AAED,MAAM,OAAO,sBAAuB,SAAQ,+BAA+B;IAGvD;IAFV,IAAI,GAAG,wBAAwB,CAAC;IAEzC,YAAmB,IAAU;QAC5B,KAAK,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;QADjC,SAAI,GAAJ,IAAI,CAAM;IAE7B,CAAC;CACD;AAED,MAAM,OAAO,8BAA+B,SAAQ,+BAA+B;IAI1E;IAHC,IAAI,GAAG,gCAAgC,CAAC;IAEjD,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,6CAA6C,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAH7D,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,6BAA8B,SAAQ,+BAA+B;IAIzE;IACA;IAJC,IAAI,GAAG,+BAA+B,CAAC;IAEhD,YACQ,IAAU,EACV,GAAW;QAElB,KAAK,CAAC,gDAAgD,IAAI,SAAS,GAAG,EAAE,CAAC,CAAC;QAHnE,SAAI,GAAJ,IAAI,CAAM;QACV,QAAG,GAAH,GAAG,CAAQ;IAGnB,CAAC;CACD;AAED,MAAM,OAAO,uBAAwB,SAAQ,+BAA+B;IAGxD;IAFV,IAAI,GAAG,yBAAyB,CAAC;IAE1C,YAAmB,IAAU;QAC5B,KAAK,CAAC,wDAAwD,IAAI,EAAE,CAAC,CAAC;QADpD,SAAI,GAAJ,IAAI,CAAM;IAE7B,CAAC;CACD;AACD,aAAa;AAEb,oCAAoC;AACpC,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACvC,IAAI,GAAG,wBAAwB,CAAC;CACzC;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../lib/errors.ts"],"names":[],"mappings":"AAEA,8CAA8C;AAC9C,MAAM,OAAO,+BAAgC,SAAQ,KAAK;IAChD,IAAI,GAAG,iCAAiC,CAAC;CAClD;AAED,MAAM,OAAO,sBAAuB,SAAQ,+BAA+B;IAGvD;IAFV,IAAI,GAAG,wBAAwB,CAAC;IAEzC,YAAmB,IAAU;QAC5B,KAAK,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;QADjC,SAAI,GAAJ,IAAI,CAAM;IAE7B,CAAC;CACD;AAED,MAAM,OAAO,8BAA+B,SAAQ,+BAA+B;IAI1E;IAHC,IAAI,GAAG,gCAAgC,CAAC;IAEjD,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,6CAA6C,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAH7D,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,6BAA8B,SAAQ,+BAA+B;IAIzE;IACA;IAJC,IAAI,GAAG,+BAA+B,CAAC;IAEhD,YACQ,IAAU,EACV,GAAW;QAElB,KAAK,CAAC,gDAAgD,IAAI,SAAS,GAAG,EAAE,CAAC,CAAC;QAHnE,SAAI,GAAJ,IAAI,CAAM;QACV,QAAG,GAAH,GAAG,CAAQ;IAGnB,CAAC;CACD;AAED,MAAM,OAAO,uBAAwB,SAAQ,+BAA+B;IAGxD;IAFV,IAAI,GAAG,yBAAyB,CAAC;IAE1C,YAAmB,IAAU;QAC5B,KAAK,CAAC,wDAAwD,IAAI,EAAE,CAAC,CAAC;QADpD,SAAI,GAAJ,IAAI,CAAM;IAE7B,CAAC;CACD;AACD,aAAa;AAEb,oCAAoC;AACpC,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACvC,IAAI,GAAG,wBAAwB,CAAC;CACzC;AAED,MAAM,OAAO,4BAA6B,SAAQ,sBAAsB;IAI/D;IAHC,IAAI,GAAG,8BAA8B,CAAC;IAE/C,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,mCAAmC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAHnD,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,yBAA0B,SAAQ,sBAAsB;IAI5D;IAHC,IAAI,GAAG,2BAA2B,CAAC;IAE5C,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,gCAAgC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAHhD,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AAED,MAAM,OAAO,wBAAyB,SAAQ,sBAAsB;IAI3D;IAHC,IAAI,GAAG,0BAA0B,CAAC;IAE3C,YACQ,IAAU,EACjB,OAAsB;QAEtB,KAAK,CAAC,sCAAsC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAHtD,SAAI,GAAJ,IAAI,CAAM;IAIlB,CAAC;CACD;AACD,aAAa"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../../lib/schemas/xrpc.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../../lib/schemas/xrpc.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAOhE,OAAO,KAAK,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAE/E,MAAM,WAAW,4BAA4B;IAC5C,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,qBAAa,qBAAqB;;IACjC,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;gBAGtC,EAAE,mBAAmB,EAAE,KAAK,EAAE,SAAiB,EAAE,EAAE,4BAA4B;IAKrF,OAAO,CACZ,SAAS,EAAE,UAAU,EACrB,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,2BAA2B,GACnC,OAAO,CAAC,cAAc,CAAC;CAiG1B"}
|
package/dist/schemas/xrpc.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getPublicKeyFromDidController, P256PublicKey, Secp256k1PublicKey, } from '@atcute/crypto';
|
|
2
|
+
import { getAtprotoVerificationMaterial, getPdsEndpoint } from '@atcute/identity';
|
|
2
3
|
import { lexiconDoc } from '@atcute/lexicon-doc';
|
|
4
|
+
import { verifyRecord } from '@atcute/repo';
|
|
3
5
|
import { FailedResponseError } from '@atcute/util-fetch';
|
|
4
6
|
import { LEXICON_SCHEMA_COLLECTION } from '../constants.js';
|
|
5
7
|
import * as err from '../errors.js';
|
|
6
|
-
import { verifyRecord } from './verify.js';
|
|
7
8
|
export class LexiconSchemaResolver {
|
|
8
9
|
didDocumentResolver;
|
|
9
10
|
#fetch;
|
|
@@ -46,11 +47,28 @@ export class LexiconSchemaResolver {
|
|
|
46
47
|
// Step 3: Verify record and extract data
|
|
47
48
|
let verifiedRecord;
|
|
48
49
|
try {
|
|
50
|
+
// Extract public key from DID document for signature verification
|
|
51
|
+
const controller = getAtprotoVerificationMaterial(didDocument);
|
|
52
|
+
if (!controller) {
|
|
53
|
+
throw new Error(`did document does not contain verification material`);
|
|
54
|
+
}
|
|
55
|
+
const found = getPublicKeyFromDidController(controller);
|
|
56
|
+
let publicKey;
|
|
57
|
+
switch (found.type) {
|
|
58
|
+
case 'p256': {
|
|
59
|
+
publicKey = await P256PublicKey.importRaw(found.publicKeyBytes);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'secp256k1': {
|
|
63
|
+
publicKey = await Secp256k1PublicKey.importRaw(found.publicKeyBytes);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
49
67
|
verifiedRecord = await verifyRecord({
|
|
50
68
|
did: authority,
|
|
51
69
|
collection: LEXICON_SCHEMA_COLLECTION,
|
|
52
70
|
rkey: nsid,
|
|
53
|
-
|
|
71
|
+
publicKey,
|
|
54
72
|
carBytes,
|
|
55
73
|
});
|
|
56
74
|
}
|
|
@@ -73,7 +91,7 @@ export class LexiconSchemaResolver {
|
|
|
73
91
|
throw new err.InvalidLexiconSchemaError(nsid, { cause });
|
|
74
92
|
}
|
|
75
93
|
return {
|
|
76
|
-
uri:
|
|
94
|
+
uri: `at://${authority}/${LEXICON_SCHEMA_COLLECTION}/${nsid}`,
|
|
77
95
|
cid: verifiedRecord.cid,
|
|
78
96
|
rawSchema: verifiedRecord.record,
|
|
79
97
|
schema: schema,
|
package/dist/schemas/xrpc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xrpc.js","sourceRoot":"","sources":["../../lib/schemas/xrpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"xrpc.js","sourceRoot":"","sources":["../../lib/schemas/xrpc.ts"],"names":[],"mappings":"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"}
|
package/lib/constants.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LEXICON_SCHEMA_COLLECTION = 'com.atproto.lexicon.schema';
|
|
1
|
+
export const LEXICON_SCHEMA_COLLECTION = 'com.atproto.lexicon.schema';
|
package/lib/errors.ts
CHANGED
package/lib/index.ts
CHANGED
package/lib/schemas/xrpc.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getPublicKeyFromDidController,
|
|
3
|
+
P256PublicKey,
|
|
4
|
+
Secp256k1PublicKey,
|
|
5
|
+
type PublicKey,
|
|
6
|
+
} from '@atcute/crypto';
|
|
7
|
+
import { getAtprotoVerificationMaterial, getPdsEndpoint } from '@atcute/identity';
|
|
2
8
|
import type { DidDocumentResolver } from '@atcute/identity-resolver';
|
|
3
9
|
import { lexiconDoc, type LexiconDoc } from '@atcute/lexicon-doc';
|
|
4
10
|
import type { AtprotoDid, Nsid } from '@atcute/lexicons/syntax';
|
|
11
|
+
import { verifyRecord, type VerifiedRecord } from '@atcute/repo';
|
|
5
12
|
|
|
6
13
|
import { FailedResponseError } from '@atcute/util-fetch';
|
|
7
14
|
|
|
8
15
|
import { LEXICON_SCHEMA_COLLECTION } from '../constants.js';
|
|
9
16
|
import * as err from '../errors.js';
|
|
10
17
|
import type { ResolvedSchema, ResolveLexiconRecordOptions } from '../types.js';
|
|
11
|
-
import { verifyRecord, type VerifiedRecord } from './verify.js';
|
|
12
18
|
|
|
13
19
|
export interface LexiconSchemaResolverOptions {
|
|
14
20
|
didDocumentResolver: DidDocumentResolver;
|
|
@@ -69,11 +75,31 @@ export class LexiconSchemaResolver {
|
|
|
69
75
|
// Step 3: Verify record and extract data
|
|
70
76
|
let verifiedRecord: VerifiedRecord;
|
|
71
77
|
try {
|
|
78
|
+
// Extract public key from DID document for signature verification
|
|
79
|
+
const controller = getAtprotoVerificationMaterial(didDocument);
|
|
80
|
+
if (!controller) {
|
|
81
|
+
throw new Error(`did document does not contain verification material`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const found = getPublicKeyFromDidController(controller);
|
|
85
|
+
|
|
86
|
+
let publicKey: PublicKey;
|
|
87
|
+
switch (found.type) {
|
|
88
|
+
case 'p256': {
|
|
89
|
+
publicKey = await P256PublicKey.importRaw(found.publicKeyBytes);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case 'secp256k1': {
|
|
93
|
+
publicKey = await Secp256k1PublicKey.importRaw(found.publicKeyBytes);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
72
98
|
verifiedRecord = await verifyRecord({
|
|
73
99
|
did: authority,
|
|
74
100
|
collection: LEXICON_SCHEMA_COLLECTION,
|
|
75
101
|
rkey: nsid,
|
|
76
|
-
|
|
102
|
+
publicKey,
|
|
77
103
|
carBytes,
|
|
78
104
|
});
|
|
79
105
|
} catch (cause) {
|
|
@@ -99,7 +125,7 @@ export class LexiconSchemaResolver {
|
|
|
99
125
|
}
|
|
100
126
|
|
|
101
127
|
return {
|
|
102
|
-
uri:
|
|
128
|
+
uri: `at://${authority}/${LEXICON_SCHEMA_COLLECTION}/${nsid}`,
|
|
103
129
|
cid: verifiedRecord.cid,
|
|
104
130
|
rawSchema: verifiedRecord.record,
|
|
105
131
|
schema: schema,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@atcute/lexicon-resolver",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"description": "atproto lexicon authority resolution",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"atproto",
|
|
@@ -29,18 +29,15 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@badrap/valita": "^0.4.6",
|
|
32
|
-
"@atcute/
|
|
33
|
-
"@atcute/
|
|
34
|
-
"@atcute/
|
|
35
|
-
"@atcute/
|
|
36
|
-
"@atcute/
|
|
37
|
-
"@atcute/lexicons": "^1.2.2",
|
|
38
|
-
"@atcute/uint8array": "^1.0.5",
|
|
39
|
-
"@atcute/util-fetch": "^1.0.3"
|
|
32
|
+
"@atcute/lexicon-doc": "^2.0.0",
|
|
33
|
+
"@atcute/crypto": "^2.2.6",
|
|
34
|
+
"@atcute/lexicons": "^1.2.4",
|
|
35
|
+
"@atcute/util-fetch": "^1.0.3",
|
|
36
|
+
"@atcute/repo": "^0.1.0"
|
|
40
37
|
},
|
|
41
38
|
"devDependencies": {
|
|
42
|
-
"@types/bun": "^1.
|
|
43
|
-
"@atcute/identity": "^1.1.
|
|
39
|
+
"@types/bun": "^1.3.1",
|
|
40
|
+
"@atcute/identity": "^1.1.2",
|
|
44
41
|
"@atcute/identity-resolver": "^1.1.4"
|
|
45
42
|
},
|
|
46
43
|
"scripts": {
|
package/dist/schemas/verify.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type DidDocument } from '@atcute/identity';
|
|
2
|
-
import { type AtprotoDid } from '@atcute/lexicons/syntax';
|
|
3
|
-
export interface VerifiedRecord {
|
|
4
|
-
/** AT-URI of the record */
|
|
5
|
-
uri: string;
|
|
6
|
-
/** CID of the record */
|
|
7
|
-
cid: string;
|
|
8
|
-
/** Record data */
|
|
9
|
-
record: unknown;
|
|
10
|
-
}
|
|
11
|
-
export interface VerifyRecordOptions {
|
|
12
|
-
did: AtprotoDid;
|
|
13
|
-
collection: string;
|
|
14
|
-
rkey: string;
|
|
15
|
-
didDocument: DidDocument;
|
|
16
|
-
carBytes: Uint8Array;
|
|
17
|
-
}
|
|
18
|
-
export declare const verifyRecord: ({ did, collection, rkey, didDocument, carBytes, }: VerifyRecordOptions) => Promise<VerifiedRecord>;
|
|
19
|
-
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../lib/schemas/verify.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,WAAW,EAAkC,MAAM,kBAAkB,CAAC;AACpF,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAG1D,MAAM,WAAW,cAAc;IAC9B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB;IAClB,MAAM,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IACnC,GAAG,EAAE,UAAU,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,UAAU,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,GAAU,mDAMhC,mBAAmB,KAAG,OAAO,CAAC,cAAc,CA0E9C,CAAC"}
|
package/dist/schemas/verify.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import * as CAR from '@atcute/car';
|
|
2
|
-
import { CarReader } from '@atcute/car/v4';
|
|
3
|
-
import * as CBOR from '@atcute/cbor';
|
|
4
|
-
import * as CID from '@atcute/cid';
|
|
5
|
-
import { getPublicKeyFromDidController, verifySig } from '@atcute/crypto';
|
|
6
|
-
import { getAtprotoVerificationMaterial } from '@atcute/identity';
|
|
7
|
-
import {} from '@atcute/lexicons/syntax';
|
|
8
|
-
import { toSha256 } from '@atcute/uint8array';
|
|
9
|
-
export const verifyRecord = async ({ did, collection, rkey, didDocument, carBytes, }) => {
|
|
10
|
-
// grab public key from did document
|
|
11
|
-
let publicKey;
|
|
12
|
-
{
|
|
13
|
-
const controller = getAtprotoVerificationMaterial(didDocument);
|
|
14
|
-
if (!controller) {
|
|
15
|
-
throw new Error(`did document does not contain verification material`);
|
|
16
|
-
}
|
|
17
|
-
publicKey = getPublicKeyFromDidController(controller);
|
|
18
|
-
}
|
|
19
|
-
// read the car
|
|
20
|
-
let blockmap;
|
|
21
|
-
let commit;
|
|
22
|
-
{
|
|
23
|
-
const reader = CarReader.fromUint8Array(carBytes);
|
|
24
|
-
if (reader.header.data.roots.length !== 1) {
|
|
25
|
-
throw new Error(`car must have exactly one root`);
|
|
26
|
-
}
|
|
27
|
-
blockmap = new Map();
|
|
28
|
-
for (const entry of reader) {
|
|
29
|
-
const cidString = CID.toString(entry.cid);
|
|
30
|
-
// Verify that `bytes` matches its associated CID
|
|
31
|
-
const expectedCid = CID.toString(await CID.create(entry.cid.codec, entry.bytes));
|
|
32
|
-
if (cidString !== expectedCid) {
|
|
33
|
-
throw new Error(`cid does not match bytes`);
|
|
34
|
-
}
|
|
35
|
-
blockmap.set(cidString, entry);
|
|
36
|
-
}
|
|
37
|
-
if (blockmap.size === 0) {
|
|
38
|
-
throw new Error(`car must have at least one block`);
|
|
39
|
-
}
|
|
40
|
-
commit = CAR.readBlock(blockmap, reader.header.data.roots[0], CAR.isCommit);
|
|
41
|
-
}
|
|
42
|
-
// verify did in commit matches the did
|
|
43
|
-
if (commit.did !== did) {
|
|
44
|
-
throw new Error(`did in commit does not match expected did`);
|
|
45
|
-
}
|
|
46
|
-
// verify signature contained in commit is valid
|
|
47
|
-
{
|
|
48
|
-
const { sig, ...unsigned } = commit;
|
|
49
|
-
const data = CBOR.encode(unsigned);
|
|
50
|
-
const valid = await verifySig(publicKey, CBOR.fromBytes(sig), data);
|
|
51
|
-
if (!valid) {
|
|
52
|
-
throw new Error(`signature verification failed`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
// find and verify the record in the commit
|
|
56
|
-
const targetKey = `${collection}/${rkey}`;
|
|
57
|
-
const { found } = await dfs(blockmap, commit.data.$link, targetKey);
|
|
58
|
-
if (!found) {
|
|
59
|
-
throw new Error(`could not find record in car`);
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
uri: `at://${did}/${collection}/${rkey}`,
|
|
63
|
-
cid: found.cid,
|
|
64
|
-
record: found.record,
|
|
65
|
-
};
|
|
66
|
-
};
|
|
67
|
-
const encoder = new TextEncoder();
|
|
68
|
-
const decoder = new TextDecoder();
|
|
69
|
-
const dfs = async (blockmap, from, targetKey, visited = new Set()) => {
|
|
70
|
-
// If there's no starting point, return empty state
|
|
71
|
-
if (from == null) {
|
|
72
|
-
return { found: false };
|
|
73
|
-
}
|
|
74
|
-
// Check for cycles
|
|
75
|
-
{
|
|
76
|
-
if (visited.has(from)) {
|
|
77
|
-
throw new Error(`cycle detected; cid=${from}`);
|
|
78
|
-
}
|
|
79
|
-
visited.add(from);
|
|
80
|
-
}
|
|
81
|
-
// Get the block data
|
|
82
|
-
let node;
|
|
83
|
-
{
|
|
84
|
-
const entry = blockmap.get(from);
|
|
85
|
-
if (!entry) {
|
|
86
|
-
return { found: false };
|
|
87
|
-
}
|
|
88
|
-
const decoded = CBOR.decode(entry.bytes);
|
|
89
|
-
if (!CAR.isMstNode(decoded)) {
|
|
90
|
-
throw new Error(`invalid mst node; cid=${from}`);
|
|
91
|
-
}
|
|
92
|
-
node = decoded;
|
|
93
|
-
}
|
|
94
|
-
// Recursively process the left child
|
|
95
|
-
const left = await dfs(blockmap, node.l?.$link, targetKey, visited);
|
|
96
|
-
let key = '';
|
|
97
|
-
let found = left.found;
|
|
98
|
-
let depth;
|
|
99
|
-
let firstKey;
|
|
100
|
-
let lastKey;
|
|
101
|
-
// Process all entries in this node
|
|
102
|
-
for (const entry of node.e) {
|
|
103
|
-
// Construct the key by truncating and appending
|
|
104
|
-
key = key.substring(0, entry.p) + decoder.decode(CBOR.fromBytes(entry.k));
|
|
105
|
-
// Check if this is our target key
|
|
106
|
-
if (key === targetKey) {
|
|
107
|
-
const recordBlock = blockmap.get(entry.v.$link);
|
|
108
|
-
if (recordBlock) {
|
|
109
|
-
const record = CBOR.decode(recordBlock.bytes);
|
|
110
|
-
found = { cid: entry.v.$link, record };
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// Calculate depth based on leading zeros in the hash
|
|
114
|
-
const keyDigest = await toSha256(encoder.encode(key));
|
|
115
|
-
let zeroCount = 0;
|
|
116
|
-
outerLoop: for (const byte of keyDigest) {
|
|
117
|
-
for (let bit = 7; bit >= 0; bit--) {
|
|
118
|
-
if (((byte >> bit) & 1) !== 0) {
|
|
119
|
-
break outerLoop;
|
|
120
|
-
}
|
|
121
|
-
zeroCount++;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const thisDepth = Math.floor(zeroCount / 2);
|
|
125
|
-
// Ensure consistent depth
|
|
126
|
-
if (depth === undefined) {
|
|
127
|
-
depth = thisDepth;
|
|
128
|
-
}
|
|
129
|
-
else if (depth !== thisDepth) {
|
|
130
|
-
throw new Error(`node has entries with different depths; cid=${from}`);
|
|
131
|
-
}
|
|
132
|
-
// Track first and last keys
|
|
133
|
-
if (lastKey === undefined) {
|
|
134
|
-
firstKey = key;
|
|
135
|
-
lastKey = key;
|
|
136
|
-
}
|
|
137
|
-
// Check key ordering
|
|
138
|
-
if (lastKey > key) {
|
|
139
|
-
throw new Error(`entries are out of order; cid=${from}`);
|
|
140
|
-
}
|
|
141
|
-
// Process right child
|
|
142
|
-
const right = await dfs(blockmap, entry.t?.$link, targetKey, visited);
|
|
143
|
-
// Check ordering with right subtree
|
|
144
|
-
if (right.min && right.min < lastKey) {
|
|
145
|
-
throw new Error(`entries are out of order; cid=${from}`);
|
|
146
|
-
}
|
|
147
|
-
found = found || right.found;
|
|
148
|
-
// Check depth ordering
|
|
149
|
-
if (left.depth !== undefined && left.depth >= thisDepth) {
|
|
150
|
-
throw new Error(`depths are out of order; cid=${from}`);
|
|
151
|
-
}
|
|
152
|
-
if (right.depth !== undefined && right.depth >= thisDepth) {
|
|
153
|
-
throw new Error(`depths are out of order; cid=${from}`);
|
|
154
|
-
}
|
|
155
|
-
// Update last key based on right subtree
|
|
156
|
-
lastKey = right.max ?? key;
|
|
157
|
-
}
|
|
158
|
-
// Check ordering with left subtree
|
|
159
|
-
if (left.max && firstKey && left.max > firstKey) {
|
|
160
|
-
throw new Error(`entries are out of order; cid=${from}`);
|
|
161
|
-
}
|
|
162
|
-
return {
|
|
163
|
-
found,
|
|
164
|
-
min: firstKey,
|
|
165
|
-
max: lastKey,
|
|
166
|
-
depth,
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
//# sourceMappingURL=verify.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../lib/schemas/verify.ts"],"names":[],"mappings":"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"}
|
package/lib/schemas/verify.ts
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import * as CAR from '@atcute/car';
|
|
2
|
-
import { CarReader } from '@atcute/car/v4';
|
|
3
|
-
import * as CBOR from '@atcute/cbor';
|
|
4
|
-
import * as CID from '@atcute/cid';
|
|
5
|
-
import { type FoundPublicKey, getPublicKeyFromDidController, verifySig } from '@atcute/crypto';
|
|
6
|
-
import { type DidDocument, getAtprotoVerificationMaterial } from '@atcute/identity';
|
|
7
|
-
import { type AtprotoDid } from '@atcute/lexicons/syntax';
|
|
8
|
-
import { toSha256 } from '@atcute/uint8array';
|
|
9
|
-
|
|
10
|
-
export interface VerifiedRecord {
|
|
11
|
-
/** AT-URI of the record */
|
|
12
|
-
uri: string;
|
|
13
|
-
/** CID of the record */
|
|
14
|
-
cid: string;
|
|
15
|
-
/** Record data */
|
|
16
|
-
record: unknown;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface VerifyRecordOptions {
|
|
20
|
-
did: AtprotoDid;
|
|
21
|
-
collection: string;
|
|
22
|
-
rkey: string;
|
|
23
|
-
didDocument: DidDocument;
|
|
24
|
-
carBytes: Uint8Array;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const verifyRecord = async ({
|
|
28
|
-
did,
|
|
29
|
-
collection,
|
|
30
|
-
rkey,
|
|
31
|
-
didDocument,
|
|
32
|
-
carBytes,
|
|
33
|
-
}: VerifyRecordOptions): Promise<VerifiedRecord> => {
|
|
34
|
-
// grab public key from did document
|
|
35
|
-
let publicKey: FoundPublicKey;
|
|
36
|
-
{
|
|
37
|
-
const controller = getAtprotoVerificationMaterial(didDocument);
|
|
38
|
-
if (!controller) {
|
|
39
|
-
throw new Error(`did document does not contain verification material`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
publicKey = getPublicKeyFromDidController(controller);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// read the car
|
|
46
|
-
let blockmap: CAR.BlockMap;
|
|
47
|
-
let commit: CAR.Commit;
|
|
48
|
-
{
|
|
49
|
-
const reader = CarReader.fromUint8Array(carBytes);
|
|
50
|
-
if (reader.header.data.roots.length !== 1) {
|
|
51
|
-
throw new Error(`car must have exactly one root`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
blockmap = new Map();
|
|
55
|
-
for (const entry of reader) {
|
|
56
|
-
const cidString = CID.toString(entry.cid);
|
|
57
|
-
|
|
58
|
-
// Verify that `bytes` matches its associated CID
|
|
59
|
-
const expectedCid = CID.toString(await CID.create(entry.cid.codec as 85 | 113, entry.bytes));
|
|
60
|
-
if (cidString !== expectedCid) {
|
|
61
|
-
throw new Error(`cid does not match bytes`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
blockmap.set(cidString, entry);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (blockmap.size === 0) {
|
|
68
|
-
throw new Error(`car must have at least one block`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
commit = CAR.readBlock(blockmap, reader.header.data.roots[0], CAR.isCommit);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// verify did in commit matches the did
|
|
75
|
-
if (commit.did !== did) {
|
|
76
|
-
throw new Error(`did in commit does not match expected did`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// verify signature contained in commit is valid
|
|
80
|
-
{
|
|
81
|
-
const { sig, ...unsigned } = commit;
|
|
82
|
-
|
|
83
|
-
const data = CBOR.encode(unsigned);
|
|
84
|
-
const valid = await verifySig(
|
|
85
|
-
publicKey,
|
|
86
|
-
CBOR.fromBytes(sig) as Uint8Array<ArrayBuffer>,
|
|
87
|
-
data as Uint8Array<ArrayBuffer>,
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
if (!valid) {
|
|
91
|
-
throw new Error(`signature verification failed`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// find and verify the record in the commit
|
|
96
|
-
const targetKey = `${collection}/${rkey}`;
|
|
97
|
-
const { found } = await dfs(blockmap, commit.data.$link, targetKey);
|
|
98
|
-
if (!found) {
|
|
99
|
-
throw new Error(`could not find record in car`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
uri: `at://${did}/${collection}/${rkey}`,
|
|
104
|
-
cid: found.cid,
|
|
105
|
-
record: found.record,
|
|
106
|
-
};
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
interface DfsResult {
|
|
110
|
-
found: false | { cid: string; record: unknown };
|
|
111
|
-
min?: string;
|
|
112
|
-
max?: string;
|
|
113
|
-
depth?: number;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const encoder = new TextEncoder();
|
|
117
|
-
const decoder = new TextDecoder();
|
|
118
|
-
|
|
119
|
-
const dfs = async (
|
|
120
|
-
blockmap: CAR.BlockMap,
|
|
121
|
-
from: string | undefined,
|
|
122
|
-
targetKey: string,
|
|
123
|
-
visited = new Set<string>(),
|
|
124
|
-
): Promise<DfsResult> => {
|
|
125
|
-
// If there's no starting point, return empty state
|
|
126
|
-
if (from == null) {
|
|
127
|
-
return { found: false };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Check for cycles
|
|
131
|
-
{
|
|
132
|
-
if (visited.has(from)) {
|
|
133
|
-
throw new Error(`cycle detected; cid=${from}`);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
visited.add(from);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Get the block data
|
|
140
|
-
let node: CAR.MstNode;
|
|
141
|
-
{
|
|
142
|
-
const entry = blockmap.get(from);
|
|
143
|
-
if (!entry) {
|
|
144
|
-
return { found: false };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const decoded = CBOR.decode(entry.bytes);
|
|
148
|
-
if (!CAR.isMstNode(decoded)) {
|
|
149
|
-
throw new Error(`invalid mst node; cid=${from}`);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
node = decoded;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Recursively process the left child
|
|
156
|
-
const left = await dfs(blockmap, node.l?.$link, targetKey, visited);
|
|
157
|
-
|
|
158
|
-
let key = '';
|
|
159
|
-
let found = left.found;
|
|
160
|
-
let depth: number | undefined;
|
|
161
|
-
let firstKey: string | undefined;
|
|
162
|
-
let lastKey: string | undefined;
|
|
163
|
-
|
|
164
|
-
// Process all entries in this node
|
|
165
|
-
for (const entry of node.e) {
|
|
166
|
-
// Construct the key by truncating and appending
|
|
167
|
-
key = key.substring(0, entry.p) + decoder.decode(CBOR.fromBytes(entry.k));
|
|
168
|
-
|
|
169
|
-
// Check if this is our target key
|
|
170
|
-
if (key === targetKey) {
|
|
171
|
-
const recordBlock = blockmap.get(entry.v.$link);
|
|
172
|
-
if (recordBlock) {
|
|
173
|
-
const record = CBOR.decode(recordBlock.bytes);
|
|
174
|
-
found = { cid: entry.v.$link, record };
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Calculate depth based on leading zeros in the hash
|
|
179
|
-
const keyDigest = await toSha256(encoder.encode(key));
|
|
180
|
-
let zeroCount = 0;
|
|
181
|
-
|
|
182
|
-
outerLoop: for (const byte of keyDigest) {
|
|
183
|
-
for (let bit = 7; bit >= 0; bit--) {
|
|
184
|
-
if (((byte >> bit) & 1) !== 0) {
|
|
185
|
-
break outerLoop;
|
|
186
|
-
}
|
|
187
|
-
zeroCount++;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const thisDepth = Math.floor(zeroCount / 2);
|
|
192
|
-
|
|
193
|
-
// Ensure consistent depth
|
|
194
|
-
if (depth === undefined) {
|
|
195
|
-
depth = thisDepth;
|
|
196
|
-
} else if (depth !== thisDepth) {
|
|
197
|
-
throw new Error(`node has entries with different depths; cid=${from}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Track first and last keys
|
|
201
|
-
if (lastKey === undefined) {
|
|
202
|
-
firstKey = key;
|
|
203
|
-
lastKey = key;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Check key ordering
|
|
207
|
-
if (lastKey > key) {
|
|
208
|
-
throw new Error(`entries are out of order; cid=${from}`);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Process right child
|
|
212
|
-
const right = await dfs(blockmap, entry.t?.$link, targetKey, visited);
|
|
213
|
-
|
|
214
|
-
// Check ordering with right subtree
|
|
215
|
-
if (right.min && right.min < lastKey) {
|
|
216
|
-
throw new Error(`entries are out of order; cid=${from}`);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
found = found || right.found;
|
|
220
|
-
|
|
221
|
-
// Check depth ordering
|
|
222
|
-
if (left.depth !== undefined && left.depth >= thisDepth) {
|
|
223
|
-
throw new Error(`depths are out of order; cid=${from}`);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (right.depth !== undefined && right.depth >= thisDepth) {
|
|
227
|
-
throw new Error(`depths are out of order; cid=${from}`);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Update last key based on right subtree
|
|
231
|
-
lastKey = right.max ?? key;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Check ordering with left subtree
|
|
235
|
-
if (left.max && firstKey && left.max > firstKey) {
|
|
236
|
-
throw new Error(`entries are out of order; cid=${from}`);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return {
|
|
240
|
-
found,
|
|
241
|
-
min: firstKey,
|
|
242
|
-
max: lastKey,
|
|
243
|
-
depth,
|
|
244
|
-
};
|
|
245
|
-
};
|