@arcblock/vc 1.29.17 → 1.29.19
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/esm/index.d.mts +16 -6
- package/esm/index.mjs +49 -16
- package/lib/index.cjs +49 -15
- package/lib/index.d.cts +16 -6
- package/package.json +5 -5
package/esm/index.d.mts
CHANGED
|
@@ -2,12 +2,19 @@ import { WalletObject } from "@ocap/wallet";
|
|
|
2
2
|
import stringify from "json-stable-stringify";
|
|
3
3
|
|
|
4
4
|
//#region src/index.d.ts
|
|
5
|
+
interface VerificationMethod {
|
|
6
|
+
id: string;
|
|
7
|
+
type: string;
|
|
8
|
+
controller: string;
|
|
9
|
+
publicKeyMultibase: string;
|
|
10
|
+
}
|
|
5
11
|
interface Proof {
|
|
6
12
|
type: string;
|
|
7
13
|
created: string;
|
|
8
14
|
proofPurpose: string;
|
|
9
15
|
jws: string;
|
|
10
16
|
pk?: string;
|
|
17
|
+
verificationMethod?: string;
|
|
11
18
|
}
|
|
12
19
|
interface Issuer {
|
|
13
20
|
id: string;
|
|
@@ -24,14 +31,15 @@ interface CredentialStatus {
|
|
|
24
31
|
scope: string;
|
|
25
32
|
}
|
|
26
33
|
interface VerifiableCredential {
|
|
27
|
-
'@context': string;
|
|
34
|
+
'@context': string | string[];
|
|
28
35
|
id: string;
|
|
29
|
-
type: string;
|
|
36
|
+
type: string | string[];
|
|
30
37
|
issuer: Issuer;
|
|
31
38
|
issuanceDate: string;
|
|
32
39
|
expirationDate?: string;
|
|
33
40
|
credentialSubject: CredentialSubject;
|
|
34
|
-
|
|
41
|
+
verificationMethod?: VerificationMethod[];
|
|
42
|
+
proof: Proof | Proof[];
|
|
35
43
|
tag?: string;
|
|
36
44
|
credentialStatus?: CredentialStatus;
|
|
37
45
|
signature?: unknown;
|
|
@@ -50,10 +58,12 @@ interface Credential {
|
|
|
50
58
|
id: string;
|
|
51
59
|
issued: string;
|
|
52
60
|
issuer: Issuer;
|
|
53
|
-
|
|
61
|
+
verificationMethod?: VerificationMethod[];
|
|
62
|
+
proof: Proof | Proof[];
|
|
54
63
|
claim: unknown;
|
|
55
64
|
}
|
|
56
65
|
declare const proofTypes: Record<number, string>;
|
|
66
|
+
declare const verificationKeyTypes: Record<number, string>;
|
|
57
67
|
/**
|
|
58
68
|
* Create a valid verifiable credential
|
|
59
69
|
*
|
|
@@ -77,7 +87,7 @@ declare function create({
|
|
|
77
87
|
endpoint,
|
|
78
88
|
endpointScope
|
|
79
89
|
}: {
|
|
80
|
-
type: string;
|
|
90
|
+
type: string | string[];
|
|
81
91
|
subject: CredentialSubject;
|
|
82
92
|
issuer: IssuerInfo;
|
|
83
93
|
issuanceDate?: string;
|
|
@@ -152,4 +162,4 @@ declare function verifyCredentialList({
|
|
|
152
162
|
}): Promise<unknown[]>;
|
|
153
163
|
declare const stableStringify: typeof stringify;
|
|
154
164
|
//#endregion
|
|
155
|
-
export { create, createCredentialList, proofTypes, stableStringify, verify, verifyCredentialList, verifyPresentation };
|
|
165
|
+
export { create, createCredentialList, proofTypes, stableStringify, verificationKeyTypes, verify, verifyCredentialList, verifyPresentation };
|
package/esm/index.mjs
CHANGED
|
@@ -22,6 +22,18 @@ const proofTypes = {
|
|
|
22
22
|
[types.KeyType.SECP256K1]: "Secp256k1Signature",
|
|
23
23
|
[types.KeyType.ETHEREUM]: "EthereumSignature"
|
|
24
24
|
};
|
|
25
|
+
const verificationKeyTypes = {
|
|
26
|
+
[types.KeyType.ED25519]: "Ed25519VerificationKey2020",
|
|
27
|
+
[types.KeyType.SECP256K1]: "EcdsaSecp256k1VerificationKey2019",
|
|
28
|
+
[types.KeyType.ETHEREUM]: "EcdsaSecp256k1VerificationKey2019"
|
|
29
|
+
};
|
|
30
|
+
function resolvePublicKey(proof, verificationMethods, fallbackPk) {
|
|
31
|
+
if (proof.verificationMethod && verificationMethods?.length) {
|
|
32
|
+
const keyEntry = verificationMethods.find((k) => k.id === proof.verificationMethod);
|
|
33
|
+
if (keyEntry?.publicKeyMultibase) return keyEntry.publicKeyMultibase;
|
|
34
|
+
}
|
|
35
|
+
return fallbackPk;
|
|
36
|
+
}
|
|
25
37
|
/**
|
|
26
38
|
* Create a valid verifiable credential
|
|
27
39
|
*
|
|
@@ -36,7 +48,9 @@ const proofTypes = {
|
|
|
36
48
|
* @returns Promise<object>
|
|
37
49
|
*/
|
|
38
50
|
async function create({ type, subject, issuer, issuanceDate, expirationDate, tag = "", endpoint = "", endpointScope = "public" }) {
|
|
39
|
-
|
|
51
|
+
const typeArray = Array.isArray(type) ? [...type] : type ? [type] : [];
|
|
52
|
+
if (typeArray.length === 0 || typeArray.some((t) => !t)) throw new Error("Can not create verifiable credential without empty type");
|
|
53
|
+
if (!typeArray.includes("VerifiableCredential")) typeArray.unshift("VerifiableCredential");
|
|
40
54
|
if (!subject) throw new Error("Can not create verifiable credential from empty subject");
|
|
41
55
|
if (!subject.id) throw new Error("Can not create verifiable credential without holder");
|
|
42
56
|
if (!isValid(subject.id)) throw new Error("Can not create verifiable credential invalid holder did");
|
|
@@ -50,19 +64,29 @@ async function create({ type, subject, issuer, issuanceDate, expirationDate, tag
|
|
|
50
64
|
role: types.RoleType.ROLE_VC
|
|
51
65
|
};
|
|
52
66
|
const vcDid = fromPublicKeyHash(wallet.hash(stringify(subject)), vcType);
|
|
67
|
+
const pkType = typeInfo.pk;
|
|
68
|
+
if (!proofTypes[pkType]) throw new Error("Unsupported signer type when create verifiable credential");
|
|
53
69
|
const issuanceDateValue = issuanceDate || (/* @__PURE__ */ new Date()).toISOString();
|
|
70
|
+
const issuerPk = toBase58(wallet.publicKey);
|
|
71
|
+
const keyId = `did:abt:${issuerDid}#key-1`;
|
|
54
72
|
const vcObj = {
|
|
55
|
-
"@context": "https://schema.arcblock.io/v0.1/context.jsonld",
|
|
73
|
+
"@context": ["https://www.w3.org/2018/credentials/v1", "https://schema.arcblock.io/v0.1/context.jsonld"],
|
|
56
74
|
id: vcDid,
|
|
57
|
-
type,
|
|
75
|
+
type: typeArray,
|
|
58
76
|
issuer: {
|
|
59
77
|
id: issuerDid,
|
|
60
|
-
pk:
|
|
78
|
+
pk: issuerPk,
|
|
61
79
|
name: issuerName || issuerDid
|
|
62
80
|
},
|
|
63
81
|
issuanceDate: issuanceDateValue,
|
|
64
82
|
expirationDate,
|
|
65
|
-
credentialSubject: subject
|
|
83
|
+
credentialSubject: subject,
|
|
84
|
+
verificationMethod: [{
|
|
85
|
+
id: keyId,
|
|
86
|
+
type: verificationKeyTypes[pkType],
|
|
87
|
+
controller: `did:abt:${issuerDid}`,
|
|
88
|
+
publicKeyMultibase: issuerPk
|
|
89
|
+
}]
|
|
66
90
|
};
|
|
67
91
|
if (tag) vcObj.tag = tag;
|
|
68
92
|
if (endpoint) vcObj.credentialStatus = {
|
|
@@ -70,14 +94,13 @@ async function create({ type, subject, issuer, issuanceDate, expirationDate, tag
|
|
|
70
94
|
type: "NFTStatusList2021",
|
|
71
95
|
scope: endpointScope || "public"
|
|
72
96
|
};
|
|
73
|
-
const pkType = typeInfo.pk;
|
|
74
|
-
if (!proofTypes[pkType]) throw new Error("Unsupported signer type when create verifiable credential");
|
|
75
97
|
const signature = await wallet.sign(stringify(vcObj));
|
|
76
98
|
const result = {
|
|
77
99
|
proof: {
|
|
78
100
|
type: proofTypes[pkType],
|
|
79
101
|
created: issuanceDateValue,
|
|
80
102
|
proofPurpose: "assertionMethod",
|
|
103
|
+
verificationMethod: keyId,
|
|
81
104
|
jws: toBase64(signature)
|
|
82
105
|
},
|
|
83
106
|
...vcObj
|
|
@@ -107,7 +130,8 @@ async function verify({ vc, ownerDid, trustedIssuers, ignoreExpired = false }) {
|
|
|
107
130
|
if (!vc) throw new Error("Empty verifiable credential object");
|
|
108
131
|
if (!vc.issuer || !vc.issuer.id || !vc.issuer.pk || !isValid(vc.issuer.id)) throw new Error("Invalid verifiable credential issuer");
|
|
109
132
|
if (!vc.credentialSubject || !vc.credentialSubject.id || !isValid(vc.credentialSubject.id)) throw new Error("Invalid verifiable credential subject");
|
|
110
|
-
|
|
133
|
+
const proofList = Array.isArray(vc.proof) ? vc.proof : vc.proof ? [vc.proof] : [];
|
|
134
|
+
if (proofList.length === 0 || proofList.some((p) => !p || !p.jws)) throw new Error("Invalid verifiable credential proof");
|
|
111
135
|
if (vc.issuanceDate === void 0) throw Error("Invalid verifiable credential issue date");
|
|
112
136
|
if (new Date(vc.issuanceDate).getTime() > Date.now()) throw Error("Verifiable credential has not take effect");
|
|
113
137
|
if (!ignoreExpired && vc.expirationDate !== void 0 && new Date(vc.expirationDate).getTime() < Date.now()) throw Error("Verifiable credential has expired");
|
|
@@ -115,12 +139,11 @@ async function verify({ vc, ownerDid, trustedIssuers, ignoreExpired = false }) {
|
|
|
115
139
|
if (!issuerDid) throw new Error("Verifiable credential not issued by trusted issuers");
|
|
116
140
|
if (!isFromPublicKey(issuerDid, vc.issuer.pk)) throw new Error("Verifiable credential not issuer pk not match with issuer did");
|
|
117
141
|
if (ownerDid !== vc.credentialSubject.id) throw new Error("Verifiable credential not owned by specified owner did");
|
|
118
|
-
const issuerWallet = fromPublicKey(vc.issuer.pk, toTypeInfo(issuerDid));
|
|
119
142
|
const clone = cloneDeep(vc);
|
|
120
|
-
const signatureStr = clone.proof.jws;
|
|
121
143
|
delete clone.proof;
|
|
122
144
|
delete clone.signature;
|
|
123
|
-
|
|
145
|
+
const signedContent = stringify(clone);
|
|
146
|
+
for (const proof of proofList) if (await fromPublicKey(resolvePublicKey(proof, vc.verificationMethod, vc.issuer.pk), toTypeInfo(issuerDid)).verify(signedContent, fromBase64(proof.jws)) !== true) throw Error("Verifiable credential signature not valid");
|
|
124
147
|
return true;
|
|
125
148
|
}
|
|
126
149
|
/**
|
|
@@ -170,20 +193,29 @@ async function createCredentialList({ claims, issuer, issuanceDate }) {
|
|
|
170
193
|
};
|
|
171
194
|
const issued = issuanceDate || (/* @__PURE__ */ new Date()).toISOString();
|
|
172
195
|
const pkType = typeInfo.pk;
|
|
196
|
+
const issuerPk = toBase58(wallet.publicKey);
|
|
197
|
+
const keyId = `did:abt:${issuerDid}#key-1`;
|
|
173
198
|
return await Promise.all(claims.map(async (x) => {
|
|
174
199
|
const vc = { claim: x };
|
|
175
200
|
vc.id = fromPublicKeyHash(wallet.hash(stringify(vc.claim)), vcType);
|
|
176
201
|
vc.issued = issued;
|
|
177
202
|
vc.issuer = {
|
|
178
203
|
id: issuerDid,
|
|
179
|
-
pk:
|
|
204
|
+
pk: issuerPk,
|
|
180
205
|
name: name$1 || issuerDid
|
|
181
206
|
};
|
|
207
|
+
vc.verificationMethod = [{
|
|
208
|
+
id: keyId,
|
|
209
|
+
type: verificationKeyTypes[pkType],
|
|
210
|
+
controller: `did:abt:${issuerDid}`,
|
|
211
|
+
publicKeyMultibase: issuerPk
|
|
212
|
+
}];
|
|
182
213
|
const signature = await wallet.sign(stringify(vc));
|
|
183
214
|
vc.proof = {
|
|
184
215
|
type: proofTypes[pkType],
|
|
185
216
|
created: issued,
|
|
186
217
|
proofPurpose: "assertionMethod",
|
|
218
|
+
verificationMethod: keyId,
|
|
187
219
|
jws: toBase64(signature)
|
|
188
220
|
};
|
|
189
221
|
return vc;
|
|
@@ -195,15 +227,16 @@ async function verifyCredentialList({ credentials, trustedIssuers }) {
|
|
|
195
227
|
const issuerDid = (Array.isArray(trustedIssuers) ? trustedIssuers : [trustedIssuers]).find((d) => d === x.issuer.id);
|
|
196
228
|
if (!issuerDid) throw new Error("Credential not issued by trusted issuers");
|
|
197
229
|
if (!isFromPublicKey(issuerDid, x.issuer.pk)) throw new Error("Credential not issuer pk not match with issuer did");
|
|
198
|
-
const
|
|
230
|
+
const proofList = Array.isArray(x.proof) ? x.proof : x.proof ? [x.proof] : [];
|
|
231
|
+
if (proofList.length === 0 || proofList.some((p) => !p || !p.jws)) throw new Error("Invalid credential proof");
|
|
199
232
|
const clone = cloneDeep(x);
|
|
200
|
-
const signatureStr = clone.proof.jws;
|
|
201
233
|
delete clone.proof;
|
|
202
|
-
|
|
234
|
+
const signedContent = stringify(clone);
|
|
235
|
+
for (const proof of proofList) if (await fromPublicKey(resolvePublicKey(proof, x.verificationMethod, x.issuer.pk), toTypeInfo(issuerDid)).verify(signedContent, fromBase64(proof.jws)) !== true) throw Error("Status credential signature not valid");
|
|
203
236
|
return x.claim;
|
|
204
237
|
}));
|
|
205
238
|
}
|
|
206
239
|
const stableStringify = stringify;
|
|
207
240
|
|
|
208
241
|
//#endregion
|
|
209
|
-
export { create, createCredentialList, proofTypes, stableStringify, verify, verifyCredentialList, verifyPresentation };
|
|
242
|
+
export { create, createCredentialList, proofTypes, stableStringify, verificationKeyTypes, verify, verifyCredentialList, verifyPresentation };
|
package/lib/index.cjs
CHANGED
|
@@ -27,6 +27,18 @@ const proofTypes = {
|
|
|
27
27
|
[_ocap_mcrypto.types.KeyType.SECP256K1]: "Secp256k1Signature",
|
|
28
28
|
[_ocap_mcrypto.types.KeyType.ETHEREUM]: "EthereumSignature"
|
|
29
29
|
};
|
|
30
|
+
const verificationKeyTypes = {
|
|
31
|
+
[_ocap_mcrypto.types.KeyType.ED25519]: "Ed25519VerificationKey2020",
|
|
32
|
+
[_ocap_mcrypto.types.KeyType.SECP256K1]: "EcdsaSecp256k1VerificationKey2019",
|
|
33
|
+
[_ocap_mcrypto.types.KeyType.ETHEREUM]: "EcdsaSecp256k1VerificationKey2019"
|
|
34
|
+
};
|
|
35
|
+
function resolvePublicKey(proof, verificationMethods, fallbackPk) {
|
|
36
|
+
if (proof.verificationMethod && verificationMethods?.length) {
|
|
37
|
+
const keyEntry = verificationMethods.find((k) => k.id === proof.verificationMethod);
|
|
38
|
+
if (keyEntry?.publicKeyMultibase) return keyEntry.publicKeyMultibase;
|
|
39
|
+
}
|
|
40
|
+
return fallbackPk;
|
|
41
|
+
}
|
|
30
42
|
/**
|
|
31
43
|
* Create a valid verifiable credential
|
|
32
44
|
*
|
|
@@ -41,7 +53,9 @@ const proofTypes = {
|
|
|
41
53
|
* @returns Promise<object>
|
|
42
54
|
*/
|
|
43
55
|
async function create({ type, subject, issuer, issuanceDate, expirationDate, tag = "", endpoint = "", endpointScope = "public" }) {
|
|
44
|
-
|
|
56
|
+
const typeArray = Array.isArray(type) ? [...type] : type ? [type] : [];
|
|
57
|
+
if (typeArray.length === 0 || typeArray.some((t) => !t)) throw new Error("Can not create verifiable credential without empty type");
|
|
58
|
+
if (!typeArray.includes("VerifiableCredential")) typeArray.unshift("VerifiableCredential");
|
|
45
59
|
if (!subject) throw new Error("Can not create verifiable credential from empty subject");
|
|
46
60
|
if (!subject.id) throw new Error("Can not create verifiable credential without holder");
|
|
47
61
|
if (!(0, _arcblock_did.isValid)(subject.id)) throw new Error("Can not create verifiable credential invalid holder did");
|
|
@@ -55,19 +69,29 @@ async function create({ type, subject, issuer, issuanceDate, expirationDate, tag
|
|
|
55
69
|
role: _ocap_mcrypto.types.RoleType.ROLE_VC
|
|
56
70
|
};
|
|
57
71
|
const vcDid = (0, _arcblock_did.fromPublicKeyHash)(wallet.hash((0, json_stable_stringify.default)(subject)), vcType);
|
|
72
|
+
const pkType = typeInfo.pk;
|
|
73
|
+
if (!proofTypes[pkType]) throw new Error("Unsupported signer type when create verifiable credential");
|
|
58
74
|
const issuanceDateValue = issuanceDate || (/* @__PURE__ */ new Date()).toISOString();
|
|
75
|
+
const issuerPk = (0, _ocap_util.toBase58)(wallet.publicKey);
|
|
76
|
+
const keyId = `did:abt:${issuerDid}#key-1`;
|
|
59
77
|
const vcObj = {
|
|
60
|
-
"@context": "https://schema.arcblock.io/v0.1/context.jsonld",
|
|
78
|
+
"@context": ["https://www.w3.org/2018/credentials/v1", "https://schema.arcblock.io/v0.1/context.jsonld"],
|
|
61
79
|
id: vcDid,
|
|
62
|
-
type,
|
|
80
|
+
type: typeArray,
|
|
63
81
|
issuer: {
|
|
64
82
|
id: issuerDid,
|
|
65
|
-
pk:
|
|
83
|
+
pk: issuerPk,
|
|
66
84
|
name: issuerName || issuerDid
|
|
67
85
|
},
|
|
68
86
|
issuanceDate: issuanceDateValue,
|
|
69
87
|
expirationDate,
|
|
70
|
-
credentialSubject: subject
|
|
88
|
+
credentialSubject: subject,
|
|
89
|
+
verificationMethod: [{
|
|
90
|
+
id: keyId,
|
|
91
|
+
type: verificationKeyTypes[pkType],
|
|
92
|
+
controller: `did:abt:${issuerDid}`,
|
|
93
|
+
publicKeyMultibase: issuerPk
|
|
94
|
+
}]
|
|
71
95
|
};
|
|
72
96
|
if (tag) vcObj.tag = tag;
|
|
73
97
|
if (endpoint) vcObj.credentialStatus = {
|
|
@@ -75,14 +99,13 @@ async function create({ type, subject, issuer, issuanceDate, expirationDate, tag
|
|
|
75
99
|
type: "NFTStatusList2021",
|
|
76
100
|
scope: endpointScope || "public"
|
|
77
101
|
};
|
|
78
|
-
const pkType = typeInfo.pk;
|
|
79
|
-
if (!proofTypes[pkType]) throw new Error("Unsupported signer type when create verifiable credential");
|
|
80
102
|
const signature = await wallet.sign((0, json_stable_stringify.default)(vcObj));
|
|
81
103
|
const result = {
|
|
82
104
|
proof: {
|
|
83
105
|
type: proofTypes[pkType],
|
|
84
106
|
created: issuanceDateValue,
|
|
85
107
|
proofPurpose: "assertionMethod",
|
|
108
|
+
verificationMethod: keyId,
|
|
86
109
|
jws: (0, _ocap_util.toBase64)(signature)
|
|
87
110
|
},
|
|
88
111
|
...vcObj
|
|
@@ -112,7 +135,8 @@ async function verify({ vc, ownerDid, trustedIssuers, ignoreExpired = false }) {
|
|
|
112
135
|
if (!vc) throw new Error("Empty verifiable credential object");
|
|
113
136
|
if (!vc.issuer || !vc.issuer.id || !vc.issuer.pk || !(0, _arcblock_did.isValid)(vc.issuer.id)) throw new Error("Invalid verifiable credential issuer");
|
|
114
137
|
if (!vc.credentialSubject || !vc.credentialSubject.id || !(0, _arcblock_did.isValid)(vc.credentialSubject.id)) throw new Error("Invalid verifiable credential subject");
|
|
115
|
-
|
|
138
|
+
const proofList = Array.isArray(vc.proof) ? vc.proof : vc.proof ? [vc.proof] : [];
|
|
139
|
+
if (proofList.length === 0 || proofList.some((p) => !p || !p.jws)) throw new Error("Invalid verifiable credential proof");
|
|
116
140
|
if (vc.issuanceDate === void 0) throw Error("Invalid verifiable credential issue date");
|
|
117
141
|
if (new Date(vc.issuanceDate).getTime() > Date.now()) throw Error("Verifiable credential has not take effect");
|
|
118
142
|
if (!ignoreExpired && vc.expirationDate !== void 0 && new Date(vc.expirationDate).getTime() < Date.now()) throw Error("Verifiable credential has expired");
|
|
@@ -120,12 +144,11 @@ async function verify({ vc, ownerDid, trustedIssuers, ignoreExpired = false }) {
|
|
|
120
144
|
if (!issuerDid) throw new Error("Verifiable credential not issued by trusted issuers");
|
|
121
145
|
if (!(0, _arcblock_did.isFromPublicKey)(issuerDid, vc.issuer.pk)) throw new Error("Verifiable credential not issuer pk not match with issuer did");
|
|
122
146
|
if (ownerDid !== vc.credentialSubject.id) throw new Error("Verifiable credential not owned by specified owner did");
|
|
123
|
-
const issuerWallet = (0, _ocap_wallet.fromPublicKey)(vc.issuer.pk, (0, _arcblock_did.toTypeInfo)(issuerDid));
|
|
124
147
|
const clone = (0, lodash_cloneDeep.default)(vc);
|
|
125
|
-
const signatureStr = clone.proof.jws;
|
|
126
148
|
delete clone.proof;
|
|
127
149
|
delete clone.signature;
|
|
128
|
-
|
|
150
|
+
const signedContent = (0, json_stable_stringify.default)(clone);
|
|
151
|
+
for (const proof of proofList) if (await (0, _ocap_wallet.fromPublicKey)(resolvePublicKey(proof, vc.verificationMethod, vc.issuer.pk), (0, _arcblock_did.toTypeInfo)(issuerDid)).verify(signedContent, (0, _ocap_util.fromBase64)(proof.jws)) !== true) throw Error("Verifiable credential signature not valid");
|
|
129
152
|
return true;
|
|
130
153
|
}
|
|
131
154
|
/**
|
|
@@ -175,20 +198,29 @@ async function createCredentialList({ claims, issuer, issuanceDate }) {
|
|
|
175
198
|
};
|
|
176
199
|
const issued = issuanceDate || (/* @__PURE__ */ new Date()).toISOString();
|
|
177
200
|
const pkType = typeInfo.pk;
|
|
201
|
+
const issuerPk = (0, _ocap_util.toBase58)(wallet.publicKey);
|
|
202
|
+
const keyId = `did:abt:${issuerDid}#key-1`;
|
|
178
203
|
return await Promise.all(claims.map(async (x) => {
|
|
179
204
|
const vc = { claim: x };
|
|
180
205
|
vc.id = (0, _arcblock_did.fromPublicKeyHash)(wallet.hash((0, json_stable_stringify.default)(vc.claim)), vcType);
|
|
181
206
|
vc.issued = issued;
|
|
182
207
|
vc.issuer = {
|
|
183
208
|
id: issuerDid,
|
|
184
|
-
pk:
|
|
209
|
+
pk: issuerPk,
|
|
185
210
|
name: name$1 || issuerDid
|
|
186
211
|
};
|
|
212
|
+
vc.verificationMethod = [{
|
|
213
|
+
id: keyId,
|
|
214
|
+
type: verificationKeyTypes[pkType],
|
|
215
|
+
controller: `did:abt:${issuerDid}`,
|
|
216
|
+
publicKeyMultibase: issuerPk
|
|
217
|
+
}];
|
|
187
218
|
const signature = await wallet.sign((0, json_stable_stringify.default)(vc));
|
|
188
219
|
vc.proof = {
|
|
189
220
|
type: proofTypes[pkType],
|
|
190
221
|
created: issued,
|
|
191
222
|
proofPurpose: "assertionMethod",
|
|
223
|
+
verificationMethod: keyId,
|
|
192
224
|
jws: (0, _ocap_util.toBase64)(signature)
|
|
193
225
|
};
|
|
194
226
|
return vc;
|
|
@@ -200,11 +232,12 @@ async function verifyCredentialList({ credentials, trustedIssuers }) {
|
|
|
200
232
|
const issuerDid = (Array.isArray(trustedIssuers) ? trustedIssuers : [trustedIssuers]).find((d) => d === x.issuer.id);
|
|
201
233
|
if (!issuerDid) throw new Error("Credential not issued by trusted issuers");
|
|
202
234
|
if (!(0, _arcblock_did.isFromPublicKey)(issuerDid, x.issuer.pk)) throw new Error("Credential not issuer pk not match with issuer did");
|
|
203
|
-
const
|
|
235
|
+
const proofList = Array.isArray(x.proof) ? x.proof : x.proof ? [x.proof] : [];
|
|
236
|
+
if (proofList.length === 0 || proofList.some((p) => !p || !p.jws)) throw new Error("Invalid credential proof");
|
|
204
237
|
const clone = (0, lodash_cloneDeep.default)(x);
|
|
205
|
-
const signatureStr = clone.proof.jws;
|
|
206
238
|
delete clone.proof;
|
|
207
|
-
|
|
239
|
+
const signedContent = (0, json_stable_stringify.default)(clone);
|
|
240
|
+
for (const proof of proofList) if (await (0, _ocap_wallet.fromPublicKey)(resolvePublicKey(proof, x.verificationMethod, x.issuer.pk), (0, _arcblock_did.toTypeInfo)(issuerDid)).verify(signedContent, (0, _ocap_util.fromBase64)(proof.jws)) !== true) throw Error("Status credential signature not valid");
|
|
208
241
|
return x.claim;
|
|
209
242
|
}));
|
|
210
243
|
}
|
|
@@ -215,6 +248,7 @@ exports.create = create;
|
|
|
215
248
|
exports.createCredentialList = createCredentialList;
|
|
216
249
|
exports.proofTypes = proofTypes;
|
|
217
250
|
exports.stableStringify = stableStringify;
|
|
251
|
+
exports.verificationKeyTypes = verificationKeyTypes;
|
|
218
252
|
exports.verify = verify;
|
|
219
253
|
exports.verifyCredentialList = verifyCredentialList;
|
|
220
254
|
exports.verifyPresentation = verifyPresentation;
|
package/lib/index.d.cts
CHANGED
|
@@ -2,12 +2,19 @@ import { WalletObject } from "@ocap/wallet";
|
|
|
2
2
|
import stringify from "json-stable-stringify";
|
|
3
3
|
|
|
4
4
|
//#region src/index.d.ts
|
|
5
|
+
interface VerificationMethod {
|
|
6
|
+
id: string;
|
|
7
|
+
type: string;
|
|
8
|
+
controller: string;
|
|
9
|
+
publicKeyMultibase: string;
|
|
10
|
+
}
|
|
5
11
|
interface Proof {
|
|
6
12
|
type: string;
|
|
7
13
|
created: string;
|
|
8
14
|
proofPurpose: string;
|
|
9
15
|
jws: string;
|
|
10
16
|
pk?: string;
|
|
17
|
+
verificationMethod?: string;
|
|
11
18
|
}
|
|
12
19
|
interface Issuer {
|
|
13
20
|
id: string;
|
|
@@ -24,14 +31,15 @@ interface CredentialStatus {
|
|
|
24
31
|
scope: string;
|
|
25
32
|
}
|
|
26
33
|
interface VerifiableCredential {
|
|
27
|
-
'@context': string;
|
|
34
|
+
'@context': string | string[];
|
|
28
35
|
id: string;
|
|
29
|
-
type: string;
|
|
36
|
+
type: string | string[];
|
|
30
37
|
issuer: Issuer;
|
|
31
38
|
issuanceDate: string;
|
|
32
39
|
expirationDate?: string;
|
|
33
40
|
credentialSubject: CredentialSubject;
|
|
34
|
-
|
|
41
|
+
verificationMethod?: VerificationMethod[];
|
|
42
|
+
proof: Proof | Proof[];
|
|
35
43
|
tag?: string;
|
|
36
44
|
credentialStatus?: CredentialStatus;
|
|
37
45
|
signature?: unknown;
|
|
@@ -50,10 +58,12 @@ interface Credential {
|
|
|
50
58
|
id: string;
|
|
51
59
|
issued: string;
|
|
52
60
|
issuer: Issuer;
|
|
53
|
-
|
|
61
|
+
verificationMethod?: VerificationMethod[];
|
|
62
|
+
proof: Proof | Proof[];
|
|
54
63
|
claim: unknown;
|
|
55
64
|
}
|
|
56
65
|
declare const proofTypes: Record<number, string>;
|
|
66
|
+
declare const verificationKeyTypes: Record<number, string>;
|
|
57
67
|
/**
|
|
58
68
|
* Create a valid verifiable credential
|
|
59
69
|
*
|
|
@@ -77,7 +87,7 @@ declare function create({
|
|
|
77
87
|
endpoint,
|
|
78
88
|
endpointScope
|
|
79
89
|
}: {
|
|
80
|
-
type: string;
|
|
90
|
+
type: string | string[];
|
|
81
91
|
subject: CredentialSubject;
|
|
82
92
|
issuer: IssuerInfo;
|
|
83
93
|
issuanceDate?: string;
|
|
@@ -152,4 +162,4 @@ declare function verifyCredentialList({
|
|
|
152
162
|
}): Promise<unknown[]>;
|
|
153
163
|
declare const stableStringify: typeof stringify;
|
|
154
164
|
//#endregion
|
|
155
|
-
export { create, createCredentialList, proofTypes, stableStringify, verify, verifyCredentialList, verifyPresentation };
|
|
165
|
+
export { create, createCredentialList, proofTypes, stableStringify, verificationKeyTypes, verify, verifyCredentialList, verifyPresentation };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcblock/vc",
|
|
3
|
-
"version": "1.29.
|
|
3
|
+
"version": "1.29.19",
|
|
4
4
|
"description": "TypeScript lib to work with ArcBlock Verifiable Credentials",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arcblock",
|
|
@@ -72,10 +72,10 @@
|
|
|
72
72
|
"url": "https://github.com/ArcBlock/blockchain/issues"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@arcblock/did": "1.29.
|
|
76
|
-
"@ocap/mcrypto": "1.29.
|
|
77
|
-
"@ocap/util": "1.29.
|
|
78
|
-
"@ocap/wallet": "1.29.
|
|
75
|
+
"@arcblock/did": "1.29.19",
|
|
76
|
+
"@ocap/mcrypto": "1.29.19",
|
|
77
|
+
"@ocap/util": "1.29.19",
|
|
78
|
+
"@ocap/wallet": "1.29.19",
|
|
79
79
|
"debug": "^4.4.3",
|
|
80
80
|
"is-absolute-url": "^3.0.3",
|
|
81
81
|
"json-stable-stringify": "^1.0.1",
|