@atproto/identity 0.0.1 → 0.2.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/dist/did/atproto-data.d.ts +1 -0
- package/dist/handle/index.d.ts +5 -0
- package/dist/index.js +2058 -2449
- package/dist/index.js.map +4 -4
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/did/atproto-data.ts +47 -33
- package/src/handle/index.ts +49 -7
- package/src/id-resolver.ts +4 -1
- package/src/types.ts +2 -0
- package/test.log +15 -0
- package/tests/did-document.test.ts +103 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/types.d.ts
CHANGED
|
@@ -3,9 +3,11 @@ export declare type IdentityResolverOpts = {
|
|
|
3
3
|
timeout?: number;
|
|
4
4
|
plcUrl?: string;
|
|
5
5
|
didCache?: DidCache;
|
|
6
|
+
backupNameservers?: string[];
|
|
6
7
|
};
|
|
7
8
|
export declare type HandleResolverOpts = {
|
|
8
9
|
timeout?: number;
|
|
10
|
+
backupNameservers?: string[];
|
|
9
11
|
};
|
|
10
12
|
export declare type DidResolverOpts = {
|
|
11
13
|
timeout?: number;
|
package/package.json
CHANGED
package/src/did/atproto-data.ts
CHANGED
|
@@ -10,13 +10,16 @@ export const getDid = (doc: DidDocument): string => {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export const getKey = (doc: DidDocument): string | undefined => {
|
|
13
|
+
const did = getDid(doc)
|
|
13
14
|
let keys = doc.verificationMethod
|
|
14
15
|
if (!keys) return undefined
|
|
15
16
|
if (typeof keys !== 'object') return undefined
|
|
16
17
|
if (!Array.isArray(keys)) {
|
|
17
18
|
keys = [keys]
|
|
18
19
|
}
|
|
19
|
-
const found = keys.find(
|
|
20
|
+
const found = keys.find(
|
|
21
|
+
(key) => key.id === '#atproto' || key.id === `${did}#atproto`,
|
|
22
|
+
)
|
|
20
23
|
if (!found) return undefined
|
|
21
24
|
|
|
22
25
|
// @TODO support jwk
|
|
@@ -28,6 +31,9 @@ export const getKey = (doc: DidDocument): string | undefined => {
|
|
|
28
31
|
didKey = crypto.formatDidKey(crypto.P256_JWT_ALG, keyBytes)
|
|
29
32
|
} else if (found.type === 'EcdsaSecp256k1VerificationKey2019') {
|
|
30
33
|
didKey = crypto.formatDidKey(crypto.SECP256K1_JWT_ALG, keyBytes)
|
|
34
|
+
} else if (found.type === 'Multikey') {
|
|
35
|
+
const parsed = crypto.parseMultikey(found.publicKeyMultibase)
|
|
36
|
+
didKey = crypto.formatDidKey(parsed.jwtAlg, parsed.keyBytes)
|
|
31
37
|
}
|
|
32
38
|
return didKey
|
|
33
39
|
}
|
|
@@ -42,41 +48,24 @@ export const getHandle = (doc: DidDocument): string | undefined => {
|
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
export const getPds = (doc: DidDocument): string | undefined => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
services = [services]
|
|
50
|
-
}
|
|
51
|
-
const found = services.find((service) => service.id === '#atproto_pds')
|
|
52
|
-
if (!found) return undefined
|
|
53
|
-
if (found.type !== 'AtprotoPersonalDataServer') {
|
|
54
|
-
return undefined
|
|
55
|
-
}
|
|
56
|
-
if (typeof found.serviceEndpoint !== 'string') {
|
|
57
|
-
return undefined
|
|
58
|
-
}
|
|
59
|
-
validateUrl(found.serviceEndpoint)
|
|
60
|
-
return found.serviceEndpoint
|
|
51
|
+
return getServiceEndpoint(doc, {
|
|
52
|
+
id: '#atproto_pds',
|
|
53
|
+
type: 'AtprotoPersonalDataServer',
|
|
54
|
+
})
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
export const getFeedGen = (doc: DidDocument): string | undefined => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
if (typeof found.serviceEndpoint !== 'string') {
|
|
76
|
-
return undefined
|
|
77
|
-
}
|
|
78
|
-
validateUrl(found.serviceEndpoint)
|
|
79
|
-
return found.serviceEndpoint
|
|
58
|
+
return getServiceEndpoint(doc, {
|
|
59
|
+
id: '#bsky_fg',
|
|
60
|
+
type: 'BskyFeedGenerator',
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const getNotif = (doc: DidDocument): string | undefined => {
|
|
65
|
+
return getServiceEndpoint(doc, {
|
|
66
|
+
id: '#bsky_notif',
|
|
67
|
+
type: 'BskyNotificationService',
|
|
68
|
+
})
|
|
80
69
|
}
|
|
81
70
|
|
|
82
71
|
export const parseToAtprotoDocument = (
|
|
@@ -118,3 +107,28 @@ const validateUrl = (url: string) => {
|
|
|
118
107
|
throw new Error('Invalid pds hostname')
|
|
119
108
|
}
|
|
120
109
|
}
|
|
110
|
+
|
|
111
|
+
const getServiceEndpoint = (
|
|
112
|
+
doc: DidDocument,
|
|
113
|
+
opts: { id: string; type: string },
|
|
114
|
+
) => {
|
|
115
|
+
const did = getDid(doc)
|
|
116
|
+
let services = doc.service
|
|
117
|
+
if (!services) return undefined
|
|
118
|
+
if (typeof services !== 'object') return undefined
|
|
119
|
+
if (!Array.isArray(services)) {
|
|
120
|
+
services = [services]
|
|
121
|
+
}
|
|
122
|
+
const found = services.find(
|
|
123
|
+
(service) => service.id === opts.id || service.id === `${did}${opts.id}`,
|
|
124
|
+
)
|
|
125
|
+
if (!found) return undefined
|
|
126
|
+
if (found.type !== opts.type) {
|
|
127
|
+
return undefined
|
|
128
|
+
}
|
|
129
|
+
if (typeof found.serviceEndpoint !== 'string') {
|
|
130
|
+
return undefined
|
|
131
|
+
}
|
|
132
|
+
validateUrl(found.serviceEndpoint)
|
|
133
|
+
return found.serviceEndpoint
|
|
134
|
+
}
|
package/src/handle/index.ts
CHANGED
|
@@ -6,9 +6,12 @@ const PREFIX = 'did='
|
|
|
6
6
|
|
|
7
7
|
export class HandleResolver {
|
|
8
8
|
public timeout: number
|
|
9
|
+
private backupNameservers: string[] | undefined
|
|
10
|
+
private backupNameserverIps: string[] | undefined
|
|
9
11
|
|
|
10
12
|
constructor(opts: HandleResolverOpts = {}) {
|
|
11
13
|
this.timeout = opts.timeout ?? 3000
|
|
14
|
+
this.backupNameservers = opts.backupNameservers
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
async resolve(handle: string): Promise<string | undefined> {
|
|
@@ -23,7 +26,11 @@ export class HandleResolver {
|
|
|
23
26
|
httpAbort.abort()
|
|
24
27
|
return dnsRes
|
|
25
28
|
}
|
|
26
|
-
|
|
29
|
+
const res = await httpPromise
|
|
30
|
+
if (res) {
|
|
31
|
+
return res
|
|
32
|
+
}
|
|
33
|
+
return this.resolveDnsBackup(handle)
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
async resolveDns(handle: string): Promise<string | undefined> {
|
|
@@ -33,12 +40,7 @@ export class HandleResolver {
|
|
|
33
40
|
} catch (err) {
|
|
34
41
|
return undefined
|
|
35
42
|
}
|
|
36
|
-
|
|
37
|
-
const found = results.filter((i) => i.startsWith(PREFIX))
|
|
38
|
-
if (found.length !== 1) {
|
|
39
|
-
return undefined
|
|
40
|
-
}
|
|
41
|
-
return found[0].slice(PREFIX.length)
|
|
43
|
+
return this.parseDnsResult(chunkedResults)
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
async resolveHttp(
|
|
@@ -57,4 +59,44 @@ export class HandleResolver {
|
|
|
57
59
|
return undefined
|
|
58
60
|
}
|
|
59
61
|
}
|
|
62
|
+
|
|
63
|
+
async resolveDnsBackup(handle: string): Promise<string | undefined> {
|
|
64
|
+
let chunkedResults: string[][]
|
|
65
|
+
try {
|
|
66
|
+
const backupIps = await this.getBackupNameserverIps()
|
|
67
|
+
if (!backupIps || backupIps.length < 1) return undefined
|
|
68
|
+
const resolver = new dns.Resolver()
|
|
69
|
+
resolver.setServers(backupIps)
|
|
70
|
+
chunkedResults = await resolver.resolveTxt(`${SUBDOMAIN}.${handle}`)
|
|
71
|
+
} catch (err) {
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
return this.parseDnsResult(chunkedResults)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
parseDnsResult(chunkedResults: string[][]): string | undefined {
|
|
78
|
+
const results = chunkedResults.map((chunks) => chunks.join(''))
|
|
79
|
+
const found = results.filter((i) => i.startsWith(PREFIX))
|
|
80
|
+
if (found.length !== 1) {
|
|
81
|
+
return undefined
|
|
82
|
+
}
|
|
83
|
+
return found[0].slice(PREFIX.length)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private async getBackupNameserverIps(): Promise<string[] | undefined> {
|
|
87
|
+
if (!this.backupNameservers) {
|
|
88
|
+
return undefined
|
|
89
|
+
} else if (!this.backupNameserverIps) {
|
|
90
|
+
const responses = await Promise.allSettled(
|
|
91
|
+
this.backupNameservers.map((h) => dns.lookup(h)),
|
|
92
|
+
)
|
|
93
|
+
for (const res of responses) {
|
|
94
|
+
if (res.status === 'fulfilled') {
|
|
95
|
+
this.backupNameserverIps ??= []
|
|
96
|
+
this.backupNameserverIps.push(res.value.address)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return this.backupNameserverIps
|
|
101
|
+
}
|
|
60
102
|
}
|
package/src/id-resolver.ts
CHANGED
|
@@ -8,7 +8,10 @@ export class IdResolver {
|
|
|
8
8
|
|
|
9
9
|
constructor(opts: IdentityResolverOpts = {}) {
|
|
10
10
|
const { timeout = 3000, plcUrl, didCache } = opts
|
|
11
|
-
this.handle = new HandleResolver({
|
|
11
|
+
this.handle = new HandleResolver({
|
|
12
|
+
timeout,
|
|
13
|
+
backupNameservers: opts.backupNameservers,
|
|
14
|
+
})
|
|
12
15
|
this.did = new DidResolver({ timeout, plcUrl, didCache })
|
|
13
16
|
}
|
|
14
17
|
}
|
package/src/types.ts
CHANGED
|
@@ -4,10 +4,12 @@ export type IdentityResolverOpts = {
|
|
|
4
4
|
timeout?: number
|
|
5
5
|
plcUrl?: string
|
|
6
6
|
didCache?: DidCache
|
|
7
|
+
backupNameservers?: string[]
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export type HandleResolverOpts = {
|
|
10
11
|
timeout?: number
|
|
12
|
+
backupNameservers?: string[]
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export type DidResolverOpts = {
|
package/test.log
CHANGED
|
@@ -4814,3 +4814,18 @@
|
|
|
4814
4814
|
{"level":30,"time":1684278727274,"pid":65486,"hostname":"Daniels-MBP.attlocal.net","req":{"id":5,"method":"GET","url":"/did%3Aplc%3Aasdf","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:51012","connection":"close"},"remoteAddress":"::1","remotePort":51026},"res":{"statusCode":404,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/json; charset=utf-8","content-length":"46","etag":"W/\"2e-ouyx9dlGpAF6gs2puC1AAUwbx84\""}},"responseTime":321,"msg":"request completed"}
|
|
4815
4815
|
{"level":30,"time":1684278727276,"pid":65486,"hostname":"Daniels-MBP.attlocal.net","req":{"id":6,"method":"GET","url":"/did%3Aplc","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:51012","connection":"close"},"remoteAddress":"::1","remotePort":51027},"err":{"type":"ServerError","message":"DID not registered: did:plc","stack":"Error: DID not registered: did:plc\n at /Users/dholms/Projects/bluesky/did-method-plc/packages/server/dist/index.js:63293:13\n at processTicksAndRejections (node:internal/process/task_queues:95:5)","status":404},"msg":"handled server error"}
|
|
4816
4816
|
{"level":30,"time":1684278727276,"pid":65486,"hostname":"Daniels-MBP.attlocal.net","req":{"id":6,"method":"GET","url":"/did%3Aplc","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:51012","connection":"close"},"remoteAddress":"::1","remotePort":51027},"res":{"statusCode":404,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/json; charset=utf-8","content-length":"41","etag":"W/\"29-pS6VolLLFKlzTQkRVMexS+2oUm8\""}},"responseTime":0,"msg":"request completed"}
|
|
4817
|
+
{"level":30,"time":1692316309954,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":1,"method":"POST","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","content-type":"application/json","user-agent":"axios/1.3.4","content-length":"433","accept-encoding":"gzip, compress, deflate, br","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64198},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"text/plain; charset=utf-8","content-length":"2","etag":"W/\"2-nOO9QiTIwXgNtWtBJezz8kv3SLc\""}},"responseTime":27,"msg":"request completed"}
|
|
4818
|
+
{"level":30,"time":1692316309975,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":2,"method":"GET","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64199},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"526","etag":"W/\"20e-Bz5tHB3Hmhzr3BdJmjjW66tBssI\""}},"responseTime":2,"msg":"request completed"}
|
|
4819
|
+
{"level":30,"time":1692316309982,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":3,"method":"GET","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64200},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"526","etag":"W/\"20e-Bz5tHB3Hmhzr3BdJmjjW66tBssI\""}},"responseTime":1,"msg":"request completed"}
|
|
4820
|
+
{"level":30,"time":1692316309983,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":4,"method":"GET","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64201},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"526","etag":"W/\"20e-Bz5tHB3Hmhzr3BdJmjjW66tBssI\""}},"responseTime":0,"msg":"request completed"}
|
|
4821
|
+
{"level":30,"time":1692316309991,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":5,"method":"GET","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64202},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"526","etag":"W/\"20e-Bz5tHB3Hmhzr3BdJmjjW66tBssI\""}},"responseTime":0,"msg":"request completed"}
|
|
4822
|
+
{"level":30,"time":1692316309994,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":6,"method":"GET","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64203},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"526","etag":"W/\"20e-Bz5tHB3Hmhzr3BdJmjjW66tBssI\""}},"responseTime":1,"msg":"request completed"}
|
|
4823
|
+
{"level":30,"time":1692316310002,"pid":36904,"hostname":"Daniels-MBP.attlocal.net","req":{"id":7,"method":"GET","url":"/did%3Aplc%3A4jfkmzpiy76fnm2sqnr6ou5n","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64197","connection":"close"},"remoteAddress":"::1","remotePort":64204},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"526","etag":"W/\"20e-Bz5tHB3Hmhzr3BdJmjjW66tBssI\""}},"responseTime":1,"msg":"request completed"}
|
|
4824
|
+
{"level":30,"time":1692316310138,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":1,"method":"POST","url":"/did%3Aplc%3Aaqvw54euhbiaqangapth7iiq","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","content-type":"application/json","user-agent":"axios/1.3.4","content-length":"434","accept-encoding":"gzip, compress, deflate, br","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64207},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"text/plain; charset=utf-8","content-length":"2","etag":"W/\"2-nOO9QiTIwXgNtWtBJezz8kv3SLc\""}},"responseTime":23,"msg":"request completed"}
|
|
4825
|
+
{"level":30,"time":1692316310148,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":2,"method":"GET","url":"/did%3Aplc%3Aaqvw54euhbiaqangapth7iiq","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/1.3.4","accept-encoding":"gzip, compress, deflate, br","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64208},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"527","etag":"W/\"20f-nrk1WS+r5hYW1H3OJW80loBMcdw\""}},"responseTime":1,"msg":"request completed"}
|
|
4826
|
+
{"level":30,"time":1692316313207,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":3,"method":"GET","url":"/did%3Aplc%3Aaqvw54euhbiaqangapth7iiq","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64212},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"527","etag":"W/\"20f-nrk1WS+r5hYW1H3OJW80loBMcdw\""}},"responseTime":1,"msg":"request completed"}
|
|
4827
|
+
{"level":30,"time":1692316313212,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":4,"method":"GET","url":"/did%3Aplc%3Aaqvw54euhbiaqangapth7iiq","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64213},"res":{"statusCode":200,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/did+ld+json; charset=utf-8","content-length":"527","etag":"W/\"20f-nrk1WS+r5hYW1H3OJW80loBMcdw\""}},"responseTime":1,"msg":"request completed"}
|
|
4828
|
+
{"level":30,"time":1692316313215,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":5,"method":"GET","url":"/did%3Aplc%3Aasdf","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64214},"err":{"type":"ServerError","message":"DID not registered: did:plc:asdf","stack":"Error: DID not registered: did:plc:asdf\n at /Users/dholms/projects/bluesky/did-method-plc/packages/server/dist/index.js:63293:13\n at processTicksAndRejections (node:internal/process/task_queues:95:5)","status":404},"msg":"handled server error"}
|
|
4829
|
+
{"level":30,"time":1692316313509,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":5,"method":"GET","url":"/did%3Aplc%3Aasdf","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64214},"res":{"statusCode":404,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/json; charset=utf-8","content-length":"46","etag":"W/\"2e-ouyx9dlGpAF6gs2puC1AAUwbx84\""}},"responseTime":294,"msg":"request completed"}
|
|
4830
|
+
{"level":30,"time":1692316313512,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":6,"method":"GET","url":"/did%3Aplc","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64215},"err":{"type":"ServerError","message":"DID not registered: did:plc","stack":"Error: DID not registered: did:plc\n at /Users/dholms/projects/bluesky/did-method-plc/packages/server/dist/index.js:63293:13\n at processTicksAndRejections (node:internal/process/task_queues:95:5)","status":404},"msg":"handled server error"}
|
|
4831
|
+
{"level":30,"time":1692316313512,"pid":36903,"hostname":"Daniels-MBP.attlocal.net","req":{"id":6,"method":"GET","url":"/did%3Aplc","query":{},"params":{},"headers":{"accept":"application/json, text/plain, */*","user-agent":"axios/0.27.2","host":"localhost:64206","connection":"close"},"remoteAddress":"::1","remotePort":64215},"res":{"statusCode":404,"headers":{"x-powered-by":"Express","access-control-allow-origin":"*","content-type":"application/json; charset=utf-8","content-length":"41","etag":"W/\"29-pS6VolLLFKlzTQkRVMexS+2oUm8\""}},"responseTime":0,"msg":"request completed"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { DidResolver, ensureAtpDocument } from '../src'
|
|
2
|
+
|
|
3
|
+
describe('did parsing', () => {
|
|
4
|
+
it('throws on bad DID document', async () => {
|
|
5
|
+
const did = 'did:plc:yk4dd2qkboz2yv6tpubpc6co'
|
|
6
|
+
const docJson = `{
|
|
7
|
+
"ideep": "did:plc:yk4dd2qkboz2yv6tpubpc6co",
|
|
8
|
+
"blah": [
|
|
9
|
+
"https://dholms.xyz"
|
|
10
|
+
],
|
|
11
|
+
"zoot": [
|
|
12
|
+
{
|
|
13
|
+
"id": "#elsewhere",
|
|
14
|
+
"type": "EcdsaSecp256k1VerificationKey2019",
|
|
15
|
+
"controller": "did:plc:yk4dd2qkboz2yv6tpubpc6co",
|
|
16
|
+
"publicKeyMultibase": "zQYEBzXeuTM9UR3rfvNag6L3RNAs5pQZyYPsomTsgQhsxLdEgCrPTLgFna8yqCnxPpNT7DBk6Ym3dgPKNu86vt9GR"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"yarg": [ ]
|
|
20
|
+
}`
|
|
21
|
+
const resolver = new DidResolver({})
|
|
22
|
+
expect(() => {
|
|
23
|
+
resolver.validateDidDoc(did, JSON.parse(docJson))
|
|
24
|
+
}).toThrow()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('parses legacy DID format, extracts atpData', async () => {
|
|
28
|
+
const did = 'did:plc:yk4dd2qkboz2yv6tpubpc6co'
|
|
29
|
+
const docJson = `{
|
|
30
|
+
"@context": [
|
|
31
|
+
"https://www.w3.org/ns/did/v1",
|
|
32
|
+
"https://w3id.org/security/suites/secp256k1-2019/v1"
|
|
33
|
+
],
|
|
34
|
+
"id": "did:plc:yk4dd2qkboz2yv6tpubpc6co",
|
|
35
|
+
"alsoKnownAs": [
|
|
36
|
+
"at://dholms.xyz"
|
|
37
|
+
],
|
|
38
|
+
"verificationMethod": [
|
|
39
|
+
{
|
|
40
|
+
"id": "#atproto",
|
|
41
|
+
"type": "EcdsaSecp256k1VerificationKey2019",
|
|
42
|
+
"controller": "did:plc:yk4dd2qkboz2yv6tpubpc6co",
|
|
43
|
+
"publicKeyMultibase": "zQYEBzXeuTM9UR3rfvNag6L3RNAs5pQZyYPsomTsgQhsxLdEgCrPTLgFna8yqCnxPpNT7DBk6Ym3dgPKNu86vt9GR"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"service": [
|
|
47
|
+
{
|
|
48
|
+
"id": "#atproto_pds",
|
|
49
|
+
"type": "AtprotoPersonalDataServer",
|
|
50
|
+
"serviceEndpoint": "https://bsky.social"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}`
|
|
54
|
+
const resolver = new DidResolver({})
|
|
55
|
+
const doc = resolver.validateDidDoc(did, JSON.parse(docJson))
|
|
56
|
+
const atpData = ensureAtpDocument(doc)
|
|
57
|
+
expect(atpData.did).toEqual(did)
|
|
58
|
+
expect(atpData.handle).toEqual('dholms.xyz')
|
|
59
|
+
expect(atpData.pds).toEqual('https://bsky.social')
|
|
60
|
+
expect(atpData.signingKey).toEqual(
|
|
61
|
+
'did:key:zQ3shXjHeiBuRCKmM36cuYnm7YEMzhGnCmCyW92sRJ9pribSF',
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('parses newer Multikey DID format, extracts atpData', async () => {
|
|
66
|
+
const did = 'did:plc:yk4dd2qkboz2yv6tpubpc6co'
|
|
67
|
+
const docJson = `{
|
|
68
|
+
"@context": [
|
|
69
|
+
"https://www.w3.org/ns/did/v1",
|
|
70
|
+
"https://w3id.org/security/multikey/v1",
|
|
71
|
+
"https://w3id.org/security/suites/secp256k1-2019/v1"
|
|
72
|
+
],
|
|
73
|
+
"id": "did:plc:yk4dd2qkboz2yv6tpubpc6co",
|
|
74
|
+
"alsoKnownAs": [
|
|
75
|
+
"at://dholms.xyz"
|
|
76
|
+
],
|
|
77
|
+
"verificationMethod": [
|
|
78
|
+
{
|
|
79
|
+
"id": "did:plc:yk4dd2qkboz2yv6tpubpc6co#atproto",
|
|
80
|
+
"type": "Multikey",
|
|
81
|
+
"controller": "did:plc:yk4dd2qkboz2yv6tpubpc6co",
|
|
82
|
+
"publicKeyMultibase": "zQ3shXjHeiBuRCKmM36cuYnm7YEMzhGnCmCyW92sRJ9pribSF"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"service": [
|
|
86
|
+
{
|
|
87
|
+
"id": "#atproto_pds",
|
|
88
|
+
"type": "AtprotoPersonalDataServer",
|
|
89
|
+
"serviceEndpoint": "https://bsky.social"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}`
|
|
93
|
+
const resolver = new DidResolver({})
|
|
94
|
+
const doc = resolver.validateDidDoc(did, JSON.parse(docJson))
|
|
95
|
+
const atpData = ensureAtpDocument(doc)
|
|
96
|
+
expect(atpData.did).toEqual(did)
|
|
97
|
+
expect(atpData.handle).toEqual('dholms.xyz')
|
|
98
|
+
expect(atpData.pds).toEqual('https://bsky.social')
|
|
99
|
+
expect(atpData.signingKey).toEqual(
|
|
100
|
+
'did:key:zQ3shXjHeiBuRCKmM36cuYnm7YEMzhGnCmCyW92sRJ9pribSF',
|
|
101
|
+
)
|
|
102
|
+
})
|
|
103
|
+
})
|