@bifold/verifier 1.0.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.
Files changed (83) hide show
  1. package/README.md +1 -0
  2. package/build/commonjs/README.md +4 -0
  3. package/build/commonjs/constants.js +9 -0
  4. package/build/commonjs/constants.js.map +1 -0
  5. package/build/commonjs/hooks/proofs.js +22 -0
  6. package/build/commonjs/hooks/proofs.js.map +1 -0
  7. package/build/commonjs/index.js +120 -0
  8. package/build/commonjs/index.js.map +1 -0
  9. package/build/commonjs/request-templates.js +59 -0
  10. package/build/commonjs/request-templates.js.map +1 -0
  11. package/build/commonjs/types/agent.js +9 -0
  12. package/build/commonjs/types/agent.js.map +1 -0
  13. package/build/commonjs/types/metadata.js +11 -0
  14. package/build/commonjs/types/metadata.js.map +1 -0
  15. package/build/commonjs/types/proof-reqeust-template.js +12 -0
  16. package/build/commonjs/types/proof-reqeust-template.js.map +1 -0
  17. package/build/commonjs/types/proof.js +26 -0
  18. package/build/commonjs/types/proof.js.map +1 -0
  19. package/build/commonjs/utils/proof-request.js +163 -0
  20. package/build/commonjs/utils/proof-request.js.map +1 -0
  21. package/build/commonjs/utils/proof.js +184 -0
  22. package/build/commonjs/utils/proof.js.map +1 -0
  23. package/build/module/README.md +4 -0
  24. package/build/module/constants.js +3 -0
  25. package/build/module/constants.js.map +1 -0
  26. package/build/module/hooks/proofs.js +15 -0
  27. package/build/module/hooks/proofs.js.map +1 -0
  28. package/build/module/index.js +7 -0
  29. package/build/module/index.js.map +1 -0
  30. package/build/module/request-templates.js +52 -0
  31. package/build/module/request-templates.js.map +1 -0
  32. package/build/module/types/agent.js +5 -0
  33. package/build/module/types/agent.js.map +1 -0
  34. package/build/module/types/metadata.js +5 -0
  35. package/build/module/types/metadata.js.map +1 -0
  36. package/build/module/types/proof-reqeust-template.js +8 -0
  37. package/build/module/types/proof-reqeust-template.js.map +1 -0
  38. package/build/module/types/proof.js +18 -0
  39. package/build/module/types/proof.js.map +1 -0
  40. package/build/module/utils/proof-request.js +151 -0
  41. package/build/module/utils/proof-request.js.map +1 -0
  42. package/build/module/utils/proof.js +171 -0
  43. package/build/module/utils/proof.js.map +1 -0
  44. package/build/typescript/__tests__/verifier/proof-request.test.d.ts +2 -0
  45. package/build/typescript/__tests__/verifier/proof-request.test.d.ts.map +1 -0
  46. package/build/typescript/__tests__/verifier/proof.test.d.ts +2 -0
  47. package/build/typescript/__tests__/verifier/proof.test.d.ts.map +1 -0
  48. package/build/typescript/constants.d.ts +3 -0
  49. package/build/typescript/constants.d.ts.map +1 -0
  50. package/build/typescript/hooks/proofs.d.ts +3 -0
  51. package/build/typescript/hooks/proofs.d.ts.map +1 -0
  52. package/build/typescript/index.d.ts +11 -0
  53. package/build/typescript/index.d.ts.map +1 -0
  54. package/build/typescript/request-templates.d.ts +3 -0
  55. package/build/typescript/request-templates.d.ts.map +1 -0
  56. package/build/typescript/types/agent.d.ts +12 -0
  57. package/build/typescript/types/agent.d.ts.map +1 -0
  58. package/build/typescript/types/metadata.d.ts +9 -0
  59. package/build/typescript/types/metadata.d.ts.map +1 -0
  60. package/build/typescript/types/proof-reqeust-template.d.ts +48 -0
  61. package/build/typescript/types/proof-reqeust-template.d.ts.map +1 -0
  62. package/build/typescript/types/proof.d.ts +51 -0
  63. package/build/typescript/types/proof.d.ts.map +1 -0
  64. package/build/typescript/utils/proof-request.d.ts +30 -0
  65. package/build/typescript/utils/proof-request.d.ts.map +1 -0
  66. package/build/typescript/utils/proof.d.ts +18 -0
  67. package/build/typescript/utils/proof.d.ts.map +1 -0
  68. package/package.json +59 -0
  69. package/src/README.md +4 -0
  70. package/src/__tests__/verifier/__snapshots__/proof-request.test.ts.snap +72 -0
  71. package/src/__tests__/verifier/__snapshots__/proof.test.ts.snap +135 -0
  72. package/src/__tests__/verifier/proof-request.test.ts +34 -0
  73. package/src/__tests__/verifier/proof.test.ts +99 -0
  74. package/src/constants.ts +2 -0
  75. package/src/hooks/proofs.ts +20 -0
  76. package/src/index.ts +45 -0
  77. package/src/request-templates.ts +62 -0
  78. package/src/types/agent.ts +53 -0
  79. package/src/types/metadata.ts +9 -0
  80. package/src/types/proof-reqeust-template.ts +59 -0
  81. package/src/types/proof.ts +68 -0
  82. package/src/utils/proof-request.ts +177 -0
  83. package/src/utils/proof.ts +173 -0
@@ -0,0 +1,177 @@
1
+ import {
2
+ AnonCredsRequestedAttribute,
3
+ AnonCredsRequestedPredicate,
4
+ LegacyIndyProofRequest,
5
+ V1RequestPresentationMessage,
6
+ } from '@credo-ts/anoncreds'
7
+ import { Agent, AgentMessage, AutoAcceptProof, ProofExchangeRecord } from '@credo-ts/core'
8
+
9
+ import { BifoldAgent } from '../types/agent'
10
+ import { ProofRequestTemplate, ProofRequestType } from '../types/proof-reqeust-template'
11
+
12
+ const protocolVersion = 'v2'
13
+ const domain = 'http://aries-mobile-agent.com'
14
+
15
+ /*
16
+ * Find Proof Request message in the storage by the given id
17
+ * */
18
+ export const findProofRequestMessage = async (
19
+ agent: Agent,
20
+ id: string
21
+ ): Promise<LegacyIndyProofRequest | undefined> => {
22
+ const message = await agent.proofs.findRequestMessage(id)
23
+ if (message && message instanceof V1RequestPresentationMessage && message.indyProofRequest) {
24
+ return message.indyProofRequest
25
+ } else {
26
+ return undefined
27
+ }
28
+ }
29
+
30
+ /*
31
+ * Build Proof Request data from for provided template
32
+ * */
33
+ /*
34
+ * Build Proof Request data for provided template
35
+ * */
36
+ export const buildProofRequestDataForTemplate = (
37
+ template: ProofRequestTemplate,
38
+ customValues?: Record<string, Record<string, number>>
39
+ ) => {
40
+ if (template.payload.type === ProofRequestType.AnonCreds) {
41
+ const requestedAttributes: Record<string, AnonCredsRequestedAttribute> = {}
42
+ const requestedPredicates: Record<string, AnonCredsRequestedPredicate> = {}
43
+ let index = 0
44
+
45
+ template.payload.data.forEach((data) => {
46
+ if (data.requestedAttributes?.length) {
47
+ data.requestedAttributes.forEach((requestedAttribute) => {
48
+ requestedAttributes[`referent_${index}`] = {
49
+ name: requestedAttribute.name,
50
+ names: requestedAttribute.names,
51
+ non_revoked: requestedAttribute.nonRevoked,
52
+ restrictions: requestedAttribute.restrictions,
53
+ }
54
+ index++
55
+ })
56
+ }
57
+ if (data.requestedPredicates?.length) {
58
+ data.requestedPredicates.forEach((requestedPredicate) => {
59
+ const customValue =
60
+ customValues && customValues[data.schema] ? customValues[data.schema][requestedPredicate.name] : undefined
61
+
62
+ requestedPredicates[`referent_${index}`] = {
63
+ name: requestedPredicate.name,
64
+ p_value:
65
+ requestedPredicate.parameterizable && customValue ? customValue : requestedPredicate.predicateValue,
66
+ p_type: requestedPredicate.predicateType,
67
+ non_revoked: requestedPredicate.nonRevoked,
68
+ restrictions: requestedPredicate.restrictions,
69
+ }
70
+ index++
71
+ })
72
+ }
73
+ })
74
+ return {
75
+ anoncreds: {
76
+ name: template.name,
77
+ version: template.version,
78
+ nonce: Date.now().toString(),
79
+ requested_attributes: requestedAttributes,
80
+ requested_predicates: requestedPredicates,
81
+ },
82
+ }
83
+ }
84
+ if (template.payload.type === ProofRequestType.DIF) {
85
+ return {}
86
+ }
87
+ }
88
+
89
+ export interface CreateProofRequestInvitationResult {
90
+ request: AgentMessage
91
+ proofRecord: ProofExchangeRecord
92
+ invitation: AgentMessage
93
+ invitationUrl: string
94
+ }
95
+
96
+ /*
97
+ * Create connectionless proof request invitation for provided template
98
+ * */
99
+ export const createConnectionlessProofRequestInvitation = async (
100
+ agent: BifoldAgent,
101
+ template: ProofRequestTemplate,
102
+ customPredicateValues?: Record<string, Record<string, number>>
103
+ ): Promise<CreateProofRequestInvitationResult | undefined> => {
104
+ const proofFormats = buildProofRequestDataForTemplate(template, customPredicateValues)
105
+ if (!proofFormats) {
106
+ return undefined
107
+ }
108
+ const { message: request, proofRecord } = await agent.proofs.createRequest({
109
+ protocolVersion,
110
+ autoAcceptProof: AutoAcceptProof.Always,
111
+ proofFormats,
112
+ })
113
+ const { message: invitation, invitationUrl } = await agent.oob.createLegacyConnectionlessInvitation({
114
+ recordId: proofRecord.id,
115
+ message: request,
116
+ domain,
117
+ })
118
+ return {
119
+ request,
120
+ proofRecord,
121
+ invitation,
122
+ invitationUrl,
123
+ }
124
+ }
125
+
126
+ export interface SendProofRequestResult {
127
+ proofRecord: ProofExchangeRecord
128
+ }
129
+
130
+ /*
131
+ * Build Proof Request for provided template and send it to provided connection
132
+ * */
133
+ export const sendProofRequest = async (
134
+ agent: BifoldAgent,
135
+ template: ProofRequestTemplate,
136
+ connectionId: string,
137
+ customPredicateValues?: Record<string, Record<string, number>>
138
+ ): Promise<SendProofRequestResult | undefined> => {
139
+ const proofFormats = buildProofRequestDataForTemplate(template, customPredicateValues)
140
+ if (!proofFormats) {
141
+ return undefined
142
+ }
143
+ const proofRecord = await agent.proofs.requestProof({
144
+ protocolVersion,
145
+ connectionId,
146
+ proofFormats,
147
+ })
148
+ return {
149
+ proofRecord,
150
+ }
151
+ }
152
+
153
+ /*
154
+ * Check if the Proof Request template contains at least one predicate
155
+ * */
156
+ export const hasPredicates = (record: ProofRequestTemplate): boolean => {
157
+ if (record.payload.type === ProofRequestType.AnonCreds) {
158
+ return record.payload.data.some((d) => d.requestedPredicates && d.requestedPredicates?.length > 0)
159
+ }
160
+ if (record.payload.type === ProofRequestType.DIF) {
161
+ return false
162
+ }
163
+ return false
164
+ }
165
+
166
+ /*
167
+ * Check if the Proof Request template contains parameterizable predicates
168
+ * */
169
+ export const isParameterizable = (record: ProofRequestTemplate): boolean => {
170
+ if (record.payload.type === ProofRequestType.AnonCreds) {
171
+ return record.payload.data.some((d) => d.requestedPredicates?.some((predicate) => predicate.parameterizable))
172
+ }
173
+ if (record.payload.type === ProofRequestType.DIF) {
174
+ return false
175
+ }
176
+ return false
177
+ }
@@ -0,0 +1,173 @@
1
+ import { AnonCredsProof, AnonCredsProofRequest } from '@credo-ts/anoncreds'
2
+ import { Agent, ProofExchangeRecord, ProofState } from '@credo-ts/core'
3
+
4
+ import { BifoldAgent } from '../types/agent'
5
+ import { ProofMetadata } from '../types/metadata'
6
+ import {
7
+ CredentialSharedProofData,
8
+ GroupedSharedProofData,
9
+ GroupedSharedProofDataItem,
10
+ ParsedAnonCredsProof,
11
+ } from '../types/proof'
12
+
13
+ /*
14
+ * Extract identifiers from indy proof
15
+ * */
16
+ export const getProofIdentifiers = (proof: AnonCredsProof, proofIndex: number) => {
17
+ const identifiers = proof.identifiers[proofIndex]
18
+ if (!identifiers) {
19
+ throw new Error('Invalid indy proof data')
20
+ }
21
+ return identifiers
22
+ }
23
+
24
+ /*
25
+ * Process anoncreds proof and return
26
+ * - shared attributes
27
+ * - shared attribute groups
28
+ * - resolved predicates
29
+ * - missing attributes
30
+ * - missing attribute groups
31
+ * - unresolved predicates
32
+ * */
33
+ export const parseAnonCredsProof = (request: AnonCredsProofRequest, proof: AnonCredsProof): ParsedAnonCredsProof => {
34
+ const result = new ParsedAnonCredsProof()
35
+
36
+ for (const [referent, requested_attribute] of Object.entries(request.requested_attributes)) {
37
+ if (requested_attribute.name) {
38
+ const shared = proof.requested_proof.revealed_attrs[referent]
39
+ if (shared) {
40
+ const identifiers = getProofIdentifiers(proof, shared.sub_proof_index)
41
+ result.sharedAttributes.push({
42
+ name: requested_attribute.name,
43
+ value: shared.raw,
44
+ identifiers,
45
+ })
46
+ } else {
47
+ result.unresolvedAttributes.push({
48
+ name: requested_attribute.name,
49
+ })
50
+ }
51
+ }
52
+
53
+ if (requested_attribute.names) {
54
+ const shared = proof.requested_proof.revealed_attr_groups?.[referent]
55
+ if (shared) {
56
+ const attributes = Object.entries(shared.values).map(([name, value]) => ({
57
+ name,
58
+ value: value.raw,
59
+ }))
60
+ const identifiers = getProofIdentifiers(proof, shared.sub_proof_index)
61
+ result.sharedAttributeGroups.push({
62
+ attributes,
63
+ identifiers,
64
+ })
65
+ } else {
66
+ result.unresolvedAttributeGroups.push(requested_attribute.names.map((name) => ({ name })))
67
+ }
68
+ }
69
+ }
70
+
71
+ for (const [referent, requestedPredicate] of Object.entries(request.requested_predicates)) {
72
+ const shared = proof.requested_proof.predicates[referent]
73
+ if (shared) {
74
+ const identifiers = getProofIdentifiers(proof, shared.sub_proof_index)
75
+ result.resolvedPredicates.push({
76
+ name: requestedPredicate.name,
77
+ predicateType: requestedPredicate.p_type,
78
+ predicateValue: requestedPredicate.p_value,
79
+ identifiers,
80
+ })
81
+ } else {
82
+ result.unresolvedPredicates.push({
83
+ name: requestedPredicate.name,
84
+ predicateType: requestedPredicate.p_type,
85
+ predicateValue: requestedPredicate.p_value,
86
+ })
87
+ }
88
+ }
89
+
90
+ return result
91
+ }
92
+
93
+ /*
94
+ * Group parsed indy proof data ( returned from `parseIndyProof`) by credential definition id
95
+ * */
96
+ export const groupSharedProofDataByCredential = (data: ParsedAnonCredsProof): GroupedSharedProofData => {
97
+ const result: GroupedSharedProofData = new Map<string, GroupedSharedProofDataItem>()
98
+ for (const item of data.sharedAttributes) {
99
+ if (!result.has(item.identifiers.cred_def_id)) {
100
+ result.set(item.identifiers.cred_def_id, {
101
+ data: new CredentialSharedProofData(),
102
+ identifiers: item.identifiers,
103
+ })
104
+ }
105
+ result.get(item.identifiers.cred_def_id)?.data.sharedAttributes.push(item)
106
+ }
107
+ for (const item of data.sharedAttributeGroups) {
108
+ if (!result.has(item.identifiers.cred_def_id)) {
109
+ result.set(item.identifiers.cred_def_id, {
110
+ data: new CredentialSharedProofData(),
111
+ identifiers: item.identifiers,
112
+ })
113
+ }
114
+ result.get(item.identifiers.cred_def_id)?.data.sharedAttributeGroups.push(item)
115
+ }
116
+ for (const item of data.resolvedPredicates) {
117
+ if (!result.has(item.identifiers.cred_def_id)) {
118
+ result.set(item.identifiers.cred_def_id, {
119
+ data: new CredentialSharedProofData(),
120
+ identifiers: item.identifiers,
121
+ })
122
+ }
123
+ result.get(item.identifiers.cred_def_id)?.data.resolvedPredicates.push(item)
124
+ }
125
+ return result
126
+ }
127
+
128
+ /*
129
+ * Retrieve proof details from Credo record
130
+ * */
131
+ export const getProofData = async (agent: BifoldAgent, recordId: string): Promise<ParsedAnonCredsProof | undefined> => {
132
+ const data = await agent.proofs.getFormatData(recordId)
133
+ if (data.request?.anoncreds && data.presentation?.anoncreds) {
134
+ return parseAnonCredsProof(data.request.anoncreds, data.presentation.anoncreds)
135
+ } else if (data.request?.indy && data.presentation?.indy) {
136
+ return parseAnonCredsProof(data.request.indy, data.presentation.indy)
137
+ }
138
+
139
+ return undefined
140
+ }
141
+
142
+ /*
143
+ * Check if a presentation received
144
+ * */
145
+ export const isPresentationReceived = (record: ProofExchangeRecord) => {
146
+ return record.state === ProofState.PresentationReceived || record.state === ProofState.Done
147
+ }
148
+
149
+ /*
150
+ * Check if a presentation failed
151
+ * */
152
+ export const isPresentationFailed = (record: ProofExchangeRecord) => {
153
+ return record.state === ProofState.Abandoned
154
+ }
155
+
156
+ /*
157
+ * Mark Proof record as viewed
158
+ * */
159
+ export const markProofAsViewed = async (agent: Agent, record: ProofExchangeRecord) => {
160
+ record.metadata.set(ProofMetadata.customMetadata, { ...record.metadata.data.customMetadata, details_seen: true })
161
+ return agent.proofs.update(record)
162
+ }
163
+
164
+ /*
165
+ * Add template reference to Proof Exchange record
166
+ * */
167
+ export const linkProofWithTemplate = async (agent: Agent, record: ProofExchangeRecord, templateId: string) => {
168
+ record.metadata.set(ProofMetadata.customMetadata, {
169
+ ...record.metadata.data.customMetadata,
170
+ proof_request_template_id: templateId,
171
+ })
172
+ return agent.proofs.update(record)
173
+ }