@arcblock/did-connect-js 1.21.2
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/LICENSE +13 -0
- package/README.md +211 -0
- package/lib/authenticator/base.js +98 -0
- package/lib/authenticator/wallet.js +768 -0
- package/lib/handlers/base.js +49 -0
- package/lib/handlers/util.js +943 -0
- package/lib/handlers/wallet.js +168 -0
- package/lib/index.d.ts +384 -0
- package/lib/index.js +7 -0
- package/lib/protocol.js +46 -0
- package/lib/schema/claims.js +256 -0
- package/lib/schema/index.js +56 -0
- package/package.json +86 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
const { Joi } = require('@arcblock/validator');
|
|
2
|
+
const { types } = require('@ocap/mcrypto');
|
|
3
|
+
|
|
4
|
+
const trustedIssuerSchema = Joi.alternatives().try(
|
|
5
|
+
Joi.object({
|
|
6
|
+
did: Joi.DID().required(),
|
|
7
|
+
endpoint: Joi.string()
|
|
8
|
+
.uri({ scheme: ['http', 'https'] })
|
|
9
|
+
.required(),
|
|
10
|
+
}),
|
|
11
|
+
Joi.DID().required()
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const optionalUrlSchema = Joi.string()
|
|
15
|
+
.uri({ scheme: ['http', 'https'], allowRelative: true })
|
|
16
|
+
.optional()
|
|
17
|
+
.default('')
|
|
18
|
+
.allow('');
|
|
19
|
+
|
|
20
|
+
const requirementSchema = Joi.object({
|
|
21
|
+
tokens: Joi.array()
|
|
22
|
+
.items(
|
|
23
|
+
Joi.object({
|
|
24
|
+
address: Joi.DID().required(),
|
|
25
|
+
value: Joi.BN().positive().required(),
|
|
26
|
+
})
|
|
27
|
+
)
|
|
28
|
+
.required(),
|
|
29
|
+
assets: Joi.object({
|
|
30
|
+
address: Joi.array().items(Joi.DID()).optional(),
|
|
31
|
+
parent: Joi.array().items(Joi.DID()).optional(),
|
|
32
|
+
issuer: Joi.array().items(Joi.DID()).optional(),
|
|
33
|
+
amount: Joi.number().positive().min(1),
|
|
34
|
+
}).optional(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const targetTypeSchema = Joi.object({
|
|
38
|
+
key: Joi.string()
|
|
39
|
+
.valid(...Object.keys(types.KeyType).map((x) => x.toLowerCase()))
|
|
40
|
+
.default('ed25519'),
|
|
41
|
+
hash: Joi.string()
|
|
42
|
+
.valid(...Object.keys(types.HashType).map((x) => x.toLowerCase()))
|
|
43
|
+
.default('sha3'),
|
|
44
|
+
role: Joi.string()
|
|
45
|
+
.valid(...Object.keys(types.RoleType).map((x) => x.toLowerCase().split('_').pop()))
|
|
46
|
+
.default('account'),
|
|
47
|
+
encoding: Joi.string()
|
|
48
|
+
.valid(...Object.keys(types.EncodingType).map((x) => x.toLowerCase()))
|
|
49
|
+
.default('base58'),
|
|
50
|
+
}).optional();
|
|
51
|
+
// .default({
|
|
52
|
+
// key: 'ed25519',
|
|
53
|
+
// hash: 'sha3',
|
|
54
|
+
// role: 'account',
|
|
55
|
+
// encoding: 'base58',
|
|
56
|
+
// });
|
|
57
|
+
|
|
58
|
+
module.exports = (chainInfo) => {
|
|
59
|
+
const options = { stripUnknown: true, noDefaults: false };
|
|
60
|
+
const createStandardFields = (type, description) => ({
|
|
61
|
+
type: Joi.string().valid(type).default(type),
|
|
62
|
+
description: Joi.string().min(1).default(description),
|
|
63
|
+
chainInfo,
|
|
64
|
+
mfaCode: Joi.array().items(Joi.number().min(10).max(99).optional()).default([]),
|
|
65
|
+
meta: Joi.any().optional().default({}),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Ask wallet to select a did for later interaction
|
|
69
|
+
const authPrincipal = Joi.object({
|
|
70
|
+
...createStandardFields('authPrincipal', 'Please continue with your account'),
|
|
71
|
+
target: Joi.DID().optional().allow('').default(''),
|
|
72
|
+
supervised: Joi.boolean().default(false),
|
|
73
|
+
targetType: targetTypeSchema,
|
|
74
|
+
}).options(options);
|
|
75
|
+
|
|
76
|
+
// Ask wallet to create new did and provide sk
|
|
77
|
+
const keyPair = Joi.object({
|
|
78
|
+
...createStandardFields('keyPair', 'Please create account to continue.'),
|
|
79
|
+
moniker: Joi.string()
|
|
80
|
+
.regex(/^[a-zA-Z0-9][-a-zA-Z0-9_]{2,128}$/)
|
|
81
|
+
.required(),
|
|
82
|
+
declare: Joi.boolean().optional().default(true),
|
|
83
|
+
migrateFrom: Joi.DID().optional().allow('').default(''),
|
|
84
|
+
targetType: targetTypeSchema,
|
|
85
|
+
}).options(options);
|
|
86
|
+
|
|
87
|
+
// Ask wallet to derive encryption key = SHA3(Buffer.concat(keyPair.sk, salt), 3)
|
|
88
|
+
const encryptionKey = Joi.object({
|
|
89
|
+
...createStandardFields('encryptionKey', 'Please provide encryptionKey to continue.'),
|
|
90
|
+
salt: Joi.string().required(),
|
|
91
|
+
delegation: Joi.string().optional().allow('').default(''),
|
|
92
|
+
}).options(options);
|
|
93
|
+
|
|
94
|
+
const profile = Joi.object({
|
|
95
|
+
...createStandardFields('profile', 'Please provide your profile to continue.'),
|
|
96
|
+
items: Joi.array()
|
|
97
|
+
.items(Joi.string().valid('did', 'fullName', 'email', 'phone', 'signature', 'avatar', 'birthday', 'url'))
|
|
98
|
+
.min(1)
|
|
99
|
+
.default(['fullName']),
|
|
100
|
+
})
|
|
101
|
+
.rename('fields', 'items', { ignoreUndefined: true, override: true })
|
|
102
|
+
.options(options);
|
|
103
|
+
|
|
104
|
+
const signature = Joi.object({
|
|
105
|
+
...createStandardFields('signature', 'Sign this transaction or message to continue.'),
|
|
106
|
+
typeUrl: Joi.string()
|
|
107
|
+
.valid(
|
|
108
|
+
'fg:x:delegation',
|
|
109
|
+
'fg:t:transaction',
|
|
110
|
+
'mime:text/plain',
|
|
111
|
+
'mime:text/html',
|
|
112
|
+
'eth:transaction',
|
|
113
|
+
'eth:standard-data',
|
|
114
|
+
'eth:personal-data',
|
|
115
|
+
'eth:typed-data',
|
|
116
|
+
'eth:legacy-data'
|
|
117
|
+
)
|
|
118
|
+
.required(),
|
|
119
|
+
display: Joi.string().allow('').default(''),
|
|
120
|
+
method: Joi.string()
|
|
121
|
+
.allow('none', ...Object.keys(types.HashType).map((x) => x.toLowerCase()))
|
|
122
|
+
.optional()
|
|
123
|
+
.default('sha3'),
|
|
124
|
+
digest: Joi.string().allow('').default(''),
|
|
125
|
+
origin: Joi.string().allow('').default(''),
|
|
126
|
+
nonce: Joi.string().allow('').default(''),
|
|
127
|
+
requirement: requirementSchema.optional(),
|
|
128
|
+
}).options(options);
|
|
129
|
+
|
|
130
|
+
const prepareTx = Joi.object({
|
|
131
|
+
...createStandardFields('prepareTx', 'Prepare and sign this transaction to continue.'),
|
|
132
|
+
display: Joi.string().allow('').default(''),
|
|
133
|
+
partialTx: Joi.string().required(),
|
|
134
|
+
nonce: Joi.string().allow('').default(''),
|
|
135
|
+
requirement: requirementSchema.required(),
|
|
136
|
+
}).options(options);
|
|
137
|
+
|
|
138
|
+
const agreement = Joi.object({
|
|
139
|
+
...createStandardFields('agreement', 'Confirm your agreement to continue.'),
|
|
140
|
+
uri: Joi.string()
|
|
141
|
+
.uri({ scheme: ['http', 'https'] })
|
|
142
|
+
.required()
|
|
143
|
+
.allow(''),
|
|
144
|
+
method: Joi.string()
|
|
145
|
+
.allow(...Object.keys(types.HashType).map((x) => x.toLowerCase()))
|
|
146
|
+
.optional()
|
|
147
|
+
.default('sha2'),
|
|
148
|
+
digest: Joi.string().required(),
|
|
149
|
+
}).options(options);
|
|
150
|
+
|
|
151
|
+
const verifiableCredential = Joi.object({
|
|
152
|
+
...createStandardFields('verifiableCredential', 'Please present a verifiable credential to continue.'),
|
|
153
|
+
|
|
154
|
+
optional: Joi.boolean().default(false),
|
|
155
|
+
|
|
156
|
+
claimUrl: optionalUrlSchema,
|
|
157
|
+
acquireUrl: optionalUrlSchema,
|
|
158
|
+
|
|
159
|
+
// v1
|
|
160
|
+
item: Joi.array().items(Joi.string().min(1).required()).min(1).optional(), // alias to type
|
|
161
|
+
target: Joi.DID().optional(),
|
|
162
|
+
trustedIssuers: Joi.array().items(trustedIssuerSchema).min(1).optional(),
|
|
163
|
+
tag: Joi.string().min(1).allow('').default(''),
|
|
164
|
+
ownerDid: Joi.array().items(Joi.DID()).optional().default([]),
|
|
165
|
+
|
|
166
|
+
// v2
|
|
167
|
+
// - multiple filter should be interpreted as OR
|
|
168
|
+
// - fields inside a filter should be interpreted as AND
|
|
169
|
+
// - values inside a filter field should be interpreted as OR
|
|
170
|
+
filters: Joi.array()
|
|
171
|
+
.items(
|
|
172
|
+
Joi.object({
|
|
173
|
+
type: Joi.array().items(Joi.string().min(1).required()).min(1).optional(),
|
|
174
|
+
target: Joi.DID().optional(),
|
|
175
|
+
trustedIssuers: Joi.array().items(trustedIssuerSchema).min(1).optional(),
|
|
176
|
+
tag: Joi.string().min(1).allow('').default(''),
|
|
177
|
+
ownerDid: Joi.array().items(Joi.DID()).optional().default([]),
|
|
178
|
+
claimUrl: optionalUrlSchema,
|
|
179
|
+
acquireUrl: optionalUrlSchema,
|
|
180
|
+
})
|
|
181
|
+
)
|
|
182
|
+
.optional(),
|
|
183
|
+
}).options(options);
|
|
184
|
+
|
|
185
|
+
const asset = Joi.object({
|
|
186
|
+
...createStandardFields('asset', 'Please present an on chain asset to continue.'),
|
|
187
|
+
|
|
188
|
+
optional: Joi.boolean().default(false),
|
|
189
|
+
|
|
190
|
+
// v1
|
|
191
|
+
address: Joi.DID().optional(),
|
|
192
|
+
trustedIssuers: Joi.array().items(trustedIssuerSchema).min(1).optional(),
|
|
193
|
+
trustedParents: Joi.array().items(Joi.DID().required()).min(1).optional(),
|
|
194
|
+
tag: Joi.string().min(1).allow('').default(''),
|
|
195
|
+
ownerDid: Joi.array().items(Joi.DID()).optional().default([]),
|
|
196
|
+
consumed: Joi.boolean().optional(),
|
|
197
|
+
acquireUrl: optionalUrlSchema,
|
|
198
|
+
|
|
199
|
+
// v2
|
|
200
|
+
// - multiple filter should be interpreted as OR
|
|
201
|
+
// - fields inside a filter should be interpreted as AND
|
|
202
|
+
// - values inside a filter field should be interpreted as OR
|
|
203
|
+
filters: Joi.array()
|
|
204
|
+
.items(
|
|
205
|
+
Joi.object({
|
|
206
|
+
address: Joi.DID().optional(),
|
|
207
|
+
trustedIssuers: Joi.array().items(trustedIssuerSchema).min(1).optional(),
|
|
208
|
+
trustedParents: Joi.array().items(Joi.DID().required()).min(1).optional(),
|
|
209
|
+
tag: Joi.string().min(1).allow('').default(''),
|
|
210
|
+
ownerDid: Joi.array().items(Joi.DID()).optional().default([]),
|
|
211
|
+
consumed: Joi.boolean().optional(),
|
|
212
|
+
acquireUrl: optionalUrlSchema,
|
|
213
|
+
})
|
|
214
|
+
)
|
|
215
|
+
.optional(),
|
|
216
|
+
}).options(options);
|
|
217
|
+
|
|
218
|
+
const assetOrVC = Joi.object({
|
|
219
|
+
...createStandardFields('assetOrVC', 'Please present NFT to continue.'),
|
|
220
|
+
|
|
221
|
+
// - multiple filter should be interpreted as OR
|
|
222
|
+
// - fields inside a filter should be interpreted as AND
|
|
223
|
+
// - values inside a filter field should be interpreted as OR
|
|
224
|
+
filters: Joi.array()
|
|
225
|
+
.items(
|
|
226
|
+
Joi.object({
|
|
227
|
+
type: Joi.array().items(Joi.string().min(1).required()).min(1).optional(), // by vc type
|
|
228
|
+
address: Joi.DID().optional(), // by nft or vc did
|
|
229
|
+
trustedIssuers: Joi.array().items(trustedIssuerSchema).min(1).optional(),
|
|
230
|
+
trustedParents: Joi.array().items(Joi.DID().required()).min(1).optional(),
|
|
231
|
+
tag: Joi.string().min(1).allow('').default(''), // by vc or nft tag
|
|
232
|
+
ownerDid: Joi.array().items(Joi.DID()).optional().default([]),
|
|
233
|
+
consumed: Joi.boolean().optional(), // only valid for nft
|
|
234
|
+
claimUrl: optionalUrlSchema, // only valid for vc
|
|
235
|
+
acquireUrl: optionalUrlSchema, // only valid for nft
|
|
236
|
+
})
|
|
237
|
+
)
|
|
238
|
+
.required()
|
|
239
|
+
.min(1),
|
|
240
|
+
|
|
241
|
+
optional: Joi.boolean().default(false),
|
|
242
|
+
}).options(options);
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
authPrincipal,
|
|
246
|
+
profile,
|
|
247
|
+
signature,
|
|
248
|
+
prepareTx,
|
|
249
|
+
agreement,
|
|
250
|
+
verifiableCredential,
|
|
251
|
+
asset,
|
|
252
|
+
assetOrVC,
|
|
253
|
+
keyPair,
|
|
254
|
+
encryptionKey,
|
|
255
|
+
};
|
|
256
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const { Joi } = require('@arcblock/validator');
|
|
2
|
+
|
|
3
|
+
const createClaimsSchema = require('./claims');
|
|
4
|
+
|
|
5
|
+
const chainInfo = Joi.object({
|
|
6
|
+
type: Joi.string().optional().valid('arcblock', 'ethereum', 'solona').default('arcblock'),
|
|
7
|
+
id: Joi.any()
|
|
8
|
+
.when('type', { is: 'arcblock', then: Joi.string().optional().default('none') })
|
|
9
|
+
.when('type', {
|
|
10
|
+
is: 'ethereum',
|
|
11
|
+
then: Joi.string()
|
|
12
|
+
.required()
|
|
13
|
+
.pattern(/^[0-9]+$/, 'numbers'),
|
|
14
|
+
})
|
|
15
|
+
.when('type', {
|
|
16
|
+
is: 'solona',
|
|
17
|
+
then: Joi.string()
|
|
18
|
+
.required()
|
|
19
|
+
.pattern(/^[0-9]+$/, 'numbers'),
|
|
20
|
+
}),
|
|
21
|
+
host: Joi.string()
|
|
22
|
+
.when('type', { is: 'ethereum', then: Joi.string().optional().allow('') })
|
|
23
|
+
.when('type', { is: 'solona', then: Joi.string().optional().allow('') })
|
|
24
|
+
.when('type', {
|
|
25
|
+
is: 'arcblock',
|
|
26
|
+
then: Joi.string()
|
|
27
|
+
.uri({ scheme: ['http', 'https'] })
|
|
28
|
+
.allow('none')
|
|
29
|
+
.default('none'),
|
|
30
|
+
}),
|
|
31
|
+
}).options({ stripUnknown: true, noDefaults: false });
|
|
32
|
+
|
|
33
|
+
const appInfo = Joi.object({
|
|
34
|
+
name: Joi.string().required(),
|
|
35
|
+
description: Joi.string().required(),
|
|
36
|
+
icon: Joi.string()
|
|
37
|
+
.uri({ scheme: ['http', 'https'] })
|
|
38
|
+
.required(),
|
|
39
|
+
link: Joi.string()
|
|
40
|
+
.uri({ scheme: ['http', 'https'] })
|
|
41
|
+
.optional(),
|
|
42
|
+
path: Joi.string()
|
|
43
|
+
.uri({ scheme: ['http', 'https'] })
|
|
44
|
+
.default('https://abtwallet.io/i/'),
|
|
45
|
+
publisher: Joi.DID().optional(),
|
|
46
|
+
updateSubEndpoint: Joi.boolean().optional(),
|
|
47
|
+
subscriptionEndpoint: Joi.string().optional(),
|
|
48
|
+
nodeDid: Joi.DID().optional(),
|
|
49
|
+
agentDid: Joi.DID().optional(),
|
|
50
|
+
}).options({ stripUnknown: false, noDefaults: false });
|
|
51
|
+
|
|
52
|
+
module.exports = Object.freeze({
|
|
53
|
+
chainInfo,
|
|
54
|
+
appInfo,
|
|
55
|
+
claims: createClaimsSchema(chainInfo),
|
|
56
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arcblock/did-connect-js",
|
|
3
|
+
"description": "Helper function to setup DID Connect support on a node.js web server",
|
|
4
|
+
"version": "1.21.2",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "wangshijun",
|
|
7
|
+
"email": "shijun@arcblock.io",
|
|
8
|
+
"url": "https://github.com/wangshijun"
|
|
9
|
+
},
|
|
10
|
+
"contributors": [
|
|
11
|
+
"wangshijun <shijun@arcblock.io> (https://github.com/wangshijun)"
|
|
12
|
+
],
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ArcBlock/blockchain/issues",
|
|
15
|
+
"email": "shijun@arcblock.io"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"cors": "^2.8.5",
|
|
22
|
+
"debug": "^4.3.6",
|
|
23
|
+
"json-stable-stringify": "^1.0.1",
|
|
24
|
+
"lodash": "^4.17.21",
|
|
25
|
+
"semver": "^7.6.3",
|
|
26
|
+
"tweetnacl-sealedbox-js": "^1.2.0",
|
|
27
|
+
"@arcblock/did": "1.21.2",
|
|
28
|
+
"@arcblock/jwt": "1.21.2",
|
|
29
|
+
"@arcblock/validator": "1.21.2",
|
|
30
|
+
"@ocap/client": "1.21.2",
|
|
31
|
+
"@ocap/mcrypto": "1.21.2",
|
|
32
|
+
"@ocap/util": "1.21.2",
|
|
33
|
+
"@ocap/wallet": "1.21.2"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@arcblock/did-agent-storage-memory": "^1.8.0",
|
|
37
|
+
"@arcblock/did-connect-storage-memory": "^1.8.0",
|
|
38
|
+
"axios": "^1.7.5",
|
|
39
|
+
"jest": "^29.7.0",
|
|
40
|
+
"remark-cli": "^10.0.1",
|
|
41
|
+
"remark-preset-github": "^4.0.4",
|
|
42
|
+
"tweetnacl": "^1.0.3",
|
|
43
|
+
"@ocap/e2e-test": "1.21.2"
|
|
44
|
+
},
|
|
45
|
+
"remarkConfig": {
|
|
46
|
+
"plugins": [
|
|
47
|
+
"preset-github",
|
|
48
|
+
[
|
|
49
|
+
{
|
|
50
|
+
"repository": "ArcBlock/blockchain"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/ArcBlock/blockchain/tree/master/did/did-connect",
|
|
56
|
+
"keywords": [
|
|
57
|
+
"blockchain",
|
|
58
|
+
"arcblock",
|
|
59
|
+
"sdk",
|
|
60
|
+
"nodejs"
|
|
61
|
+
],
|
|
62
|
+
"license": "Apache-2.0",
|
|
63
|
+
"main": "./lib/index.js",
|
|
64
|
+
"files": [
|
|
65
|
+
"lib"
|
|
66
|
+
],
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "https://github.com/ArcBlock/blockchain/tree/master/did/did-connect"
|
|
70
|
+
},
|
|
71
|
+
"resolutions": {
|
|
72
|
+
"tweetnacl": "1.0.3"
|
|
73
|
+
},
|
|
74
|
+
"gitHead": "87990c8b5e215107fc587c1ced0d6b3e2cd2483e",
|
|
75
|
+
"scripts": {
|
|
76
|
+
"lint": "eslint lib tests",
|
|
77
|
+
"lint:fix": "eslint --fix lib tests",
|
|
78
|
+
"docs": "pnpm run gen-dts && pnpm run gen-docs && pnpm run cleanup-docs && pnpm run format-docs",
|
|
79
|
+
"cleanup-docs": "node ../../scripts/cleanup-docs.js docs/README.md $npm_package_name",
|
|
80
|
+
"gen-docs": "jsdoc2md lib/**/*.js lib/**/**/*.js > docs/README.md",
|
|
81
|
+
"gen-dts": "j2d lib/index.js",
|
|
82
|
+
"format-docs": "remark . -o",
|
|
83
|
+
"test": "jest --forceExit --detectOpenHandles",
|
|
84
|
+
"coverage": "npm run test -- --coverage"
|
|
85
|
+
}
|
|
86
|
+
}
|