github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/presexch/example_v1_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package presexch_test 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "time" 13 14 "github.com/google/uuid" 15 16 "github.com/hyperledger/aries-framework-go/pkg/doc/ldcontext" 17 . "github.com/hyperledger/aries-framework-go/pkg/doc/presexch" 18 "github.com/hyperledger/aries-framework-go/pkg/doc/util" 19 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 20 "github.com/hyperledger/aries-framework-go/pkg/internal/ldtestutil" 21 ) 22 23 const dummy = "DUMMY" 24 25 func ExamplePresentationDefinition_CreateVP_v1() { 26 required := Required 27 28 pd := &PresentationDefinition{ 29 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 30 Purpose: "To sell you a drink we need to know that you are an adult.", 31 InputDescriptors: []*InputDescriptor{{ 32 ID: "age_descriptor", 33 Purpose: "Your age should be greater or equal to 18.", 34 Schema: []*Schema{{ 35 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 36 }}, 37 Constraints: &Constraints{ 38 LimitDisclosure: &required, 39 Fields: []*Field{{ 40 Path: []string{"$.age"}, 41 Predicate: &required, 42 Filter: &Filter{ 43 Type: &intFilterType, 44 Minimum: 18, 45 }, 46 }}, 47 }, 48 }}, 49 } 50 51 loader, err := ldtestutil.DocumentLoader() 52 if err != nil { 53 panic(err) 54 } 55 56 vp, err := pd.CreateVP([]*verifiable.Credential{ 57 { 58 ID: "http://example.edu/credentials/777", 59 Context: []string{verifiable.ContextURI}, 60 Types: []string{verifiable.VCType}, 61 Issuer: verifiable.Issuer{ 62 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 63 }, 64 Issued: &util.TimeWrapper{ 65 Time: time.Time{}, 66 }, 67 Subject: "did:example:76e12ec712ebc6f1c221ebfeb1f", 68 CustomFields: map[string]interface{}{ 69 "first_name": "Jesse", 70 "last_name": "Pinkman", 71 "age": 21, 72 }, 73 }, 74 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 75 if err != nil { 76 panic(err) 77 } 78 79 vp.ID = dummy 80 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 81 82 vpBytes, err := json.MarshalIndent(vp, "", "\t") 83 if err != nil { 84 panic(err) 85 } 86 87 fmt.Println(string(vpBytes)) 88 // Output: 89 // { 90 // "@context": [ 91 // "https://www.w3.org/2018/credentials/v1", 92 // "https://identity.foundation/presentation-exchange/submission/v1" 93 // ], 94 // "id": "DUMMY", 95 // "presentation_submission": { 96 // "id": "DUMMY", 97 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 98 // "descriptor_map": [ 99 // { 100 // "id": "age_descriptor", 101 // "format": "ldp_vp", 102 // "path": "$", 103 // "path_nested": { 104 // "id": "age_descriptor", 105 // "format": "ldp_vc", 106 // "path": "$.verifiableCredential[0]" 107 // } 108 // } 109 // ] 110 // }, 111 // "type": [ 112 // "VerifiablePresentation", 113 // "PresentationSubmission" 114 // ], 115 // "verifiableCredential": [ 116 // { 117 // "@context": [ 118 // "https://www.w3.org/2018/credentials/v1" 119 // ], 120 // "age": true, 121 // "credentialSubject": "did:example:76e12ec712ebc6f1c221ebfeb1f", 122 // "id": "http://example.edu/credentials/777", 123 // "issuanceDate": "0001-01-01T00:00:00Z", 124 // "issuer": "did:example:76e12ec712ebc6f1c221ebfeb1f", 125 // "type": "VerifiableCredential" 126 // } 127 // ] 128 // } 129 } 130 131 func ExamplePresentationDefinition_CreateVP_v1_With_LDP_FormatAndProof() { 132 required := Required 133 134 pd := &PresentationDefinition{ 135 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 136 Purpose: "To sell you a drink we need to know that you are an adult.", 137 InputDescriptors: []*InputDescriptor{{ 138 ID: "age_descriptor", 139 Purpose: "Your age should be greater or equal to 18.", 140 Schema: []*Schema{{ 141 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 142 }}, 143 Constraints: &Constraints{ 144 LimitDisclosure: &required, 145 Fields: []*Field{{ 146 Path: []string{"$.age"}, 147 Predicate: &required, 148 Filter: &Filter{ 149 Type: &intFilterType, 150 Minimum: 18, 151 }, 152 }}, 153 }, 154 }}, 155 Format: &Format{ 156 Ldp: &LdpType{ProofType: []string{"JsonWebSignature2020"}}, 157 }, 158 } 159 160 loader, err := ldtestutil.DocumentLoader() 161 if err != nil { 162 panic(err) 163 } 164 165 vp, err := pd.CreateVP([]*verifiable.Credential{ 166 { 167 ID: "http://example.edu/credentials/777", 168 Context: []string{verifiable.ContextURI}, 169 Types: []string{verifiable.VCType}, 170 Issuer: verifiable.Issuer{ 171 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 172 }, 173 Issued: &util.TimeWrapper{ 174 Time: time.Time{}, 175 }, 176 Subject: "did:example:76e12ec712ebc6f1c221ebfeb1f", 177 CustomFields: map[string]interface{}{ 178 "first_name": "Jesse", 179 "last_name": "Pinkman", 180 "age": 21, 181 }, 182 Proofs: []verifiable.Proof{{"type": "JsonWebSignature2020"}}, 183 }, 184 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 185 if err != nil { 186 panic(err) 187 } 188 189 vp.ID = dummy 190 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 191 192 vpBytes, err := json.MarshalIndent(vp, "", "\t") 193 if err != nil { 194 panic(err) 195 } 196 197 fmt.Println(string(vpBytes)) 198 // Output: 199 // { 200 // "@context": [ 201 // "https://www.w3.org/2018/credentials/v1", 202 // "https://identity.foundation/presentation-exchange/submission/v1" 203 // ], 204 // "id": "DUMMY", 205 // "presentation_submission": { 206 // "id": "DUMMY", 207 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 208 // "descriptor_map": [ 209 // { 210 // "id": "age_descriptor", 211 // "format": "ldp", 212 // "path": "$", 213 // "path_nested": { 214 // "id": "age_descriptor", 215 // "format": "ldp_vc", 216 // "path": "$.verifiableCredential[0]" 217 // } 218 // } 219 // ] 220 // }, 221 // "type": [ 222 // "VerifiablePresentation", 223 // "PresentationSubmission" 224 // ], 225 // "verifiableCredential": [ 226 // { 227 // "@context": [ 228 // "https://www.w3.org/2018/credentials/v1" 229 // ], 230 // "age": true, 231 // "credentialSubject": "did:example:76e12ec712ebc6f1c221ebfeb1f", 232 // "id": "http://example.edu/credentials/777", 233 // "issuanceDate": "0001-01-01T00:00:00Z", 234 // "issuer": "did:example:76e12ec712ebc6f1c221ebfeb1f", 235 // "type": "VerifiableCredential" 236 // } 237 // ] 238 // } 239 } 240 241 func ExamplePresentationDefinition_CreateVP_v1_With_LDPVC_FormatAndProof() { 242 required := Required 243 244 pd := &PresentationDefinition{ 245 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 246 Purpose: "To sell you a drink we need to know that you are an adult.", 247 InputDescriptors: []*InputDescriptor{{ 248 ID: "age_descriptor", 249 Purpose: "Your age should be greater or equal to 18.", 250 Schema: []*Schema{{ 251 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 252 }}, 253 Constraints: &Constraints{ 254 LimitDisclosure: &required, 255 Fields: []*Field{{ 256 Path: []string{"$.age"}, 257 Predicate: &required, 258 Filter: &Filter{ 259 Type: &intFilterType, 260 Minimum: 18, 261 }, 262 }}, 263 }, 264 }}, 265 Format: &Format{ 266 LdpVC: &LdpType{ProofType: []string{"JsonWebSignature2020"}}, 267 }, 268 } 269 270 loader, err := ldtestutil.DocumentLoader() 271 if err != nil { 272 panic(err) 273 } 274 275 vp, err := pd.CreateVP([]*verifiable.Credential{ 276 { 277 ID: "http://example.edu/credentials/777", 278 Context: []string{verifiable.ContextURI}, 279 Types: []string{verifiable.VCType}, 280 Issuer: verifiable.Issuer{ 281 ID: "did:example:76e12ec712ebc6f1c221ebfeb1f", 282 }, 283 Issued: &util.TimeWrapper{ 284 Time: time.Time{}, 285 }, 286 Subject: "did:example:76e12ec712ebc6f1c221ebfeb1f", 287 CustomFields: map[string]interface{}{ 288 "first_name": "Jesse", 289 "last_name": "Pinkman", 290 "age": 21, 291 }, 292 Proofs: []verifiable.Proof{{"type": "JsonWebSignature2020"}}, 293 }, 294 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 295 if err != nil { 296 panic(err) 297 } 298 299 vp.ID = dummy 300 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 301 302 vpBytes, err := json.MarshalIndent(vp, "", "\t") 303 if err != nil { 304 panic(err) 305 } 306 307 fmt.Println(string(vpBytes)) 308 // Output: 309 // { 310 // "@context": [ 311 // "https://www.w3.org/2018/credentials/v1", 312 // "https://identity.foundation/presentation-exchange/submission/v1" 313 // ], 314 // "id": "DUMMY", 315 // "presentation_submission": { 316 // "id": "DUMMY", 317 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 318 // "descriptor_map": [ 319 // { 320 // "id": "age_descriptor", 321 // "format": "ldp_vc", 322 // "path": "$", 323 // "path_nested": { 324 // "id": "age_descriptor", 325 // "format": "ldp_vc", 326 // "path": "$.verifiableCredential[0]" 327 // } 328 // } 329 // ] 330 // }, 331 // "type": [ 332 // "VerifiablePresentation", 333 // "PresentationSubmission" 334 // ], 335 // "verifiableCredential": [ 336 // { 337 // "@context": [ 338 // "https://www.w3.org/2018/credentials/v1" 339 // ], 340 // "age": true, 341 // "credentialSubject": "did:example:76e12ec712ebc6f1c221ebfeb1f", 342 // "id": "http://example.edu/credentials/777", 343 // "issuanceDate": "0001-01-01T00:00:00Z", 344 // "issuer": "did:example:76e12ec712ebc6f1c221ebfeb1f", 345 // "type": "VerifiableCredential" 346 // } 347 // ] 348 // } 349 } 350 351 func ExamplePresentationDefinition_CreateVP_multipleMatches() { 352 pd := &PresentationDefinition{ 353 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 354 Purpose: "To sell you a drink we need to know that you are an adult.", 355 InputDescriptors: []*InputDescriptor{{ 356 ID: "age_descriptor", 357 Purpose: "Your age should be greater or equal to 18.", 358 Schema: []*Schema{{ 359 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 360 }}, 361 Constraints: &Constraints{ 362 Fields: []*Field{{ 363 Path: []string{"$.age"}, 364 Filter: &Filter{ 365 Type: &intFilterType, 366 Minimum: 18, 367 }, 368 }}, 369 }, 370 }, { 371 ID: "first_name_descriptor", 372 Purpose: "First name must be either Andrew or Jesse", 373 Schema: []*Schema{{ 374 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 375 }}, 376 Constraints: &Constraints{ 377 Fields: []*Field{{ 378 Path: []string{"$.first_name"}, 379 Filter: &Filter{ 380 Type: &strFilterType, 381 Pattern: "Andrew|Jesse", 382 }, 383 }}, 384 }, 385 }}, 386 } 387 388 loader, err := ldtestutil.DocumentLoader() 389 if err != nil { 390 panic(err) 391 } 392 393 vp, err := pd.CreateVP([]*verifiable.Credential{ 394 { 395 ID: "http://example.edu/credentials/777", 396 Context: []string{verifiable.ContextURI}, 397 Types: []string{verifiable.VCType}, 398 Issuer: verifiable.Issuer{ 399 ID: "did:example:777", 400 }, 401 Issued: &util.TimeWrapper{ 402 Time: time.Time{}, 403 }, 404 Subject: "did:example:777", 405 CustomFields: map[string]interface{}{ 406 "first_name": "Andrew", 407 "last_name": "Hanks", 408 "age": 25, 409 }, 410 }, 411 { 412 ID: "http://example.edu/credentials/888", 413 Context: []string{verifiable.ContextURI}, 414 Types: []string{verifiable.VCType}, 415 Issuer: verifiable.Issuer{ 416 ID: "did:example:888", 417 }, 418 Issued: &util.TimeWrapper{ 419 Time: time.Time{}, 420 }, 421 Subject: "did:example:888", 422 CustomFields: map[string]interface{}{ 423 "first_name": "Jesse", 424 "last_name": "Pinkman", 425 "age": 21, 426 }, 427 }, 428 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 429 if err != nil { 430 panic(err) 431 } 432 433 vp.ID = dummy 434 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 435 436 vpBytes, err := json.MarshalIndent(vp, "", "\t") 437 if err != nil { 438 panic(err) 439 } 440 441 fmt.Println(string(vpBytes)) 442 // Output: 443 // { 444 // "@context": [ 445 // "https://www.w3.org/2018/credentials/v1", 446 // "https://identity.foundation/presentation-exchange/submission/v1" 447 // ], 448 // "id": "DUMMY", 449 // "presentation_submission": { 450 // "id": "DUMMY", 451 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 452 // "descriptor_map": [ 453 // { 454 // "id": "age_descriptor", 455 // "format": "ldp_vp", 456 // "path": "$", 457 // "path_nested": { 458 // "id": "age_descriptor", 459 // "format": "ldp_vc", 460 // "path": "$.verifiableCredential[0]" 461 // } 462 // }, 463 // { 464 // "id": "age_descriptor", 465 // "format": "ldp_vp", 466 // "path": "$", 467 // "path_nested": { 468 // "id": "age_descriptor", 469 // "format": "ldp_vc", 470 // "path": "$.verifiableCredential[1]" 471 // } 472 // }, 473 // { 474 // "id": "first_name_descriptor", 475 // "format": "ldp_vp", 476 // "path": "$", 477 // "path_nested": { 478 // "id": "first_name_descriptor", 479 // "format": "ldp_vc", 480 // "path": "$.verifiableCredential[0]" 481 // } 482 // }, 483 // { 484 // "id": "first_name_descriptor", 485 // "format": "ldp_vp", 486 // "path": "$", 487 // "path_nested": { 488 // "id": "first_name_descriptor", 489 // "format": "ldp_vc", 490 // "path": "$.verifiableCredential[1]" 491 // } 492 // } 493 // ] 494 // }, 495 // "type": [ 496 // "VerifiablePresentation", 497 // "PresentationSubmission" 498 // ], 499 // "verifiableCredential": [ 500 // { 501 // "@context": [ 502 // "https://www.w3.org/2018/credentials/v1" 503 // ], 504 // "age": 25, 505 // "credentialSubject": "did:example:777", 506 // "first_name": "Andrew", 507 // "id": "http://example.edu/credentials/777", 508 // "issuanceDate": "0001-01-01T00:00:00Z", 509 // "issuer": "did:example:777", 510 // "last_name": "Hanks", 511 // "type": "VerifiableCredential" 512 // }, 513 // { 514 // "@context": [ 515 // "https://www.w3.org/2018/credentials/v1" 516 // ], 517 // "age": 21, 518 // "credentialSubject": "did:example:888", 519 // "first_name": "Jesse", 520 // "id": "http://example.edu/credentials/888", 521 // "issuanceDate": "0001-01-01T00:00:00Z", 522 // "issuer": "did:example:888", 523 // "last_name": "Pinkman", 524 // "type": "VerifiableCredential" 525 // } 526 // ] 527 // } 528 } 529 530 func ExamplePresentationDefinition_CreateVP_multipleMatchesDisclosure() { 531 required := Required 532 533 pd := &PresentationDefinition{ 534 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 535 Purpose: "To sell you a drink we need to know that you are an adult.", 536 InputDescriptors: []*InputDescriptor{{ 537 ID: "age_descriptor", 538 Purpose: "Your age should be greater or equal to 18.", 539 Schema: []*Schema{{ 540 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 541 }}, 542 Constraints: &Constraints{ 543 Fields: []*Field{{ 544 Path: []string{"$.age"}, 545 Filter: &Filter{ 546 Type: &intFilterType, 547 Minimum: 18, 548 }, 549 }}, 550 }, 551 }, { 552 ID: "first_name_descriptor", 553 Purpose: "First name must be either Andrew or Jesse", 554 Schema: []*Schema{{ 555 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 556 }}, 557 Constraints: &Constraints{ 558 LimitDisclosure: &required, 559 Fields: []*Field{{ 560 Path: []string{"$.first_name"}, 561 Filter: &Filter{ 562 Type: &strFilterType, 563 Pattern: "Andrew|Jesse", 564 }, 565 }}, 566 }, 567 }}, 568 } 569 570 loader, err := ldtestutil.DocumentLoader() 571 if err != nil { 572 panic(err) 573 } 574 575 vp, err := pd.CreateVP([]*verifiable.Credential{ 576 { 577 ID: "http://example.edu/credentials/777", 578 Context: []string{verifiable.ContextURI}, 579 Types: []string{verifiable.VCType}, 580 Issuer: verifiable.Issuer{ 581 ID: "did:example:777", 582 }, 583 Issued: &util.TimeWrapper{ 584 Time: time.Time{}, 585 }, 586 Subject: "did:example:777", 587 CustomFields: map[string]interface{}{ 588 "first_name": "Andrew", 589 "last_name": "Hanks", 590 "age": 25, 591 }, 592 }, 593 { 594 ID: "http://example.edu/credentials/888", 595 Context: []string{verifiable.ContextURI}, 596 Types: []string{verifiable.VCType}, 597 Issuer: verifiable.Issuer{ 598 ID: "did:example:888", 599 }, 600 Issued: &util.TimeWrapper{ 601 Time: time.Time{}, 602 }, 603 Subject: "did:example:888", 604 CustomFields: map[string]interface{}{ 605 "first_name": "Jesse", 606 "last_name": "Pinkman", 607 "age": 21, 608 }, 609 }, 610 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 611 if err != nil { 612 panic(err) 613 } 614 615 vp.ID = dummy 616 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 617 618 vpBytes, err := json.MarshalIndent(vp, "", "\t") 619 if err != nil { 620 panic(err) 621 } 622 623 fmt.Println(string(vpBytes)) 624 // Output: 625 // { 626 // "@context": [ 627 // "https://www.w3.org/2018/credentials/v1", 628 // "https://identity.foundation/presentation-exchange/submission/v1" 629 // ], 630 // "id": "DUMMY", 631 // "presentation_submission": { 632 // "id": "DUMMY", 633 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 634 // "descriptor_map": [ 635 // { 636 // "id": "age_descriptor", 637 // "format": "ldp_vp", 638 // "path": "$", 639 // "path_nested": { 640 // "id": "age_descriptor", 641 // "format": "ldp_vc", 642 // "path": "$.verifiableCredential[0]" 643 // } 644 // }, 645 // { 646 // "id": "age_descriptor", 647 // "format": "ldp_vp", 648 // "path": "$", 649 // "path_nested": { 650 // "id": "age_descriptor", 651 // "format": "ldp_vc", 652 // "path": "$.verifiableCredential[1]" 653 // } 654 // }, 655 // { 656 // "id": "first_name_descriptor", 657 // "format": "ldp_vp", 658 // "path": "$", 659 // "path_nested": { 660 // "id": "first_name_descriptor", 661 // "format": "ldp_vc", 662 // "path": "$.verifiableCredential[2]" 663 // } 664 // }, 665 // { 666 // "id": "first_name_descriptor", 667 // "format": "ldp_vp", 668 // "path": "$", 669 // "path_nested": { 670 // "id": "first_name_descriptor", 671 // "format": "ldp_vc", 672 // "path": "$.verifiableCredential[3]" 673 // } 674 // } 675 // ] 676 // }, 677 // "type": [ 678 // "VerifiablePresentation", 679 // "PresentationSubmission" 680 // ], 681 // "verifiableCredential": [ 682 // { 683 // "@context": [ 684 // "https://www.w3.org/2018/credentials/v1" 685 // ], 686 // "age": 25, 687 // "credentialSubject": "did:example:777", 688 // "first_name": "Andrew", 689 // "id": "http://example.edu/credentials/777", 690 // "issuanceDate": "0001-01-01T00:00:00Z", 691 // "issuer": "did:example:777", 692 // "last_name": "Hanks", 693 // "type": "VerifiableCredential" 694 // }, 695 // { 696 // "@context": [ 697 // "https://www.w3.org/2018/credentials/v1" 698 // ], 699 // "age": 21, 700 // "credentialSubject": "did:example:888", 701 // "first_name": "Jesse", 702 // "id": "http://example.edu/credentials/888", 703 // "issuanceDate": "0001-01-01T00:00:00Z", 704 // "issuer": "did:example:888", 705 // "last_name": "Pinkman", 706 // "type": "VerifiableCredential" 707 // }, 708 // { 709 // "@context": [ 710 // "https://www.w3.org/2018/credentials/v1" 711 // ], 712 // "credentialSubject": "did:example:777", 713 // "first_name": "Andrew", 714 // "id": "http://example.edu/credentials/777", 715 // "issuanceDate": "0001-01-01T00:00:00Z", 716 // "issuer": "did:example:777", 717 // "type": "VerifiableCredential" 718 // }, 719 // { 720 // "@context": [ 721 // "https://www.w3.org/2018/credentials/v1" 722 // ], 723 // "credentialSubject": "did:example:888", 724 // "first_name": "Jesse", 725 // "id": "http://example.edu/credentials/888", 726 // "issuanceDate": "0001-01-01T00:00:00Z", 727 // "issuer": "did:example:888", 728 // "type": "VerifiableCredential" 729 // } 730 // ] 731 // } 732 } 733 734 func ExamplePresentationDefinition_CreateVP_submissionRequirementsLimitDisclosure() { 735 required := Required 736 737 pd := &PresentationDefinition{ 738 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 739 Purpose: "To sell you a drink we need to know that you are an adult.", 740 SubmissionRequirements: []*SubmissionRequirement{ 741 { 742 Rule: "all", 743 From: "A", 744 }, 745 { 746 Rule: "pick", 747 Purpose: "We need your photo to identify you", 748 Count: 1, 749 FromNested: []*SubmissionRequirement{ 750 { 751 Rule: "all", 752 From: "drivers_license_image", 753 }, 754 { 755 Rule: "all", 756 From: "passport_image", 757 }, 758 }, 759 }, 760 }, 761 InputDescriptors: []*InputDescriptor{{ 762 ID: "age_descriptor", 763 Group: []string{"A"}, 764 Purpose: "Your age should be greater or equal to 18.", 765 Schema: []*Schema{{ 766 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 767 }}, 768 Constraints: &Constraints{ 769 Fields: []*Field{{ 770 Path: []string{"$.age"}, 771 Filter: &Filter{ 772 Type: &intFilterType, 773 Minimum: 18, 774 }, 775 }}, 776 }, 777 }, { 778 ID: "drivers_license_image_descriptor", 779 Group: []string{"drivers_license_image"}, 780 Purpose: "We need your photo to identify you", 781 Schema: []*Schema{{ 782 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 783 }}, 784 Constraints: &Constraints{ 785 LimitDisclosure: &required, 786 Fields: []*Field{{ 787 Path: []string{"$.photo"}, 788 Filter: &Filter{ 789 Type: &strFilterType, 790 Format: "uri", 791 }, 792 }}, 793 }, 794 }, { 795 ID: "passport_image_descriptor", 796 Group: []string{"passport_image"}, 797 Purpose: "We need your image to identify you", 798 Schema: []*Schema{{ 799 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 800 }}, 801 Constraints: &Constraints{ 802 LimitDisclosure: &required, 803 Fields: []*Field{{ 804 Path: []string{"$.image"}, 805 Filter: &Filter{ 806 Type: &strFilterType, 807 Format: "uri", 808 }, 809 }}, 810 }, 811 }}, 812 } 813 814 loader, err := ldtestutil.DocumentLoader() 815 if err != nil { 816 panic(err) 817 } 818 819 vp, err := pd.CreateVP([]*verifiable.Credential{ 820 { 821 ID: "http://example.edu/credentials/777", 822 Context: []string{verifiable.ContextURI}, 823 Types: []string{verifiable.VCType}, 824 Issuer: verifiable.Issuer{ 825 ID: "did:example:777", 826 }, 827 Issued: &util.TimeWrapper{ 828 Time: time.Time{}, 829 }, 830 Subject: "did:example:777", 831 CustomFields: map[string]interface{}{ 832 "first_name": "Andrew", 833 "last_name": "Hanks", 834 "image": "http://image.com/user777", 835 "age": 25, 836 }, 837 }, 838 { 839 ID: "http://example.edu/credentials/888", 840 Context: []string{verifiable.ContextURI}, 841 Types: []string{verifiable.VCType}, 842 Issuer: verifiable.Issuer{ 843 ID: "did:example:888", 844 }, 845 Issued: &util.TimeWrapper{ 846 Time: time.Time{}, 847 }, 848 Subject: "did:example:888", 849 CustomFields: map[string]interface{}{ 850 "first_name": "Jesse", 851 "last_name": "Pinkman", 852 "photo": "http://image.com/user777", 853 "age": 21, 854 }, 855 }, 856 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 857 if err != nil { 858 panic(err) 859 } 860 861 vp.ID = dummy 862 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 863 864 vpBytes, err := json.MarshalIndent(vp, "", "\t") 865 if err != nil { 866 panic(err) 867 } 868 869 fmt.Println(string(vpBytes)) 870 // Output: 871 // { 872 // "@context": [ 873 // "https://www.w3.org/2018/credentials/v1", 874 // "https://identity.foundation/presentation-exchange/submission/v1" 875 // ], 876 // "id": "DUMMY", 877 // "presentation_submission": { 878 // "id": "DUMMY", 879 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 880 // "descriptor_map": [ 881 // { 882 // "id": "age_descriptor", 883 // "format": "ldp_vp", 884 // "path": "$", 885 // "path_nested": { 886 // "id": "age_descriptor", 887 // "format": "ldp_vc", 888 // "path": "$.verifiableCredential[0]" 889 // } 890 // }, 891 // { 892 // "id": "age_descriptor", 893 // "format": "ldp_vp", 894 // "path": "$", 895 // "path_nested": { 896 // "id": "age_descriptor", 897 // "format": "ldp_vc", 898 // "path": "$.verifiableCredential[1]" 899 // } 900 // }, 901 // { 902 // "id": "drivers_license_image_descriptor", 903 // "format": "ldp_vp", 904 // "path": "$", 905 // "path_nested": { 906 // "id": "drivers_license_image_descriptor", 907 // "format": "ldp_vc", 908 // "path": "$.verifiableCredential[2]" 909 // } 910 // }, 911 // { 912 // "id": "passport_image_descriptor", 913 // "format": "ldp_vp", 914 // "path": "$", 915 // "path_nested": { 916 // "id": "passport_image_descriptor", 917 // "format": "ldp_vc", 918 // "path": "$.verifiableCredential[3]" 919 // } 920 // } 921 // ] 922 // }, 923 // "type": [ 924 // "VerifiablePresentation", 925 // "PresentationSubmission" 926 // ], 927 // "verifiableCredential": [ 928 // { 929 // "@context": [ 930 // "https://www.w3.org/2018/credentials/v1" 931 // ], 932 // "age": 25, 933 // "credentialSubject": "did:example:777", 934 // "first_name": "Andrew", 935 // "id": "http://example.edu/credentials/777", 936 // "image": "http://image.com/user777", 937 // "issuanceDate": "0001-01-01T00:00:00Z", 938 // "issuer": "did:example:777", 939 // "last_name": "Hanks", 940 // "type": "VerifiableCredential" 941 // }, 942 // { 943 // "@context": [ 944 // "https://www.w3.org/2018/credentials/v1" 945 // ], 946 // "age": 21, 947 // "credentialSubject": "did:example:888", 948 // "first_name": "Jesse", 949 // "id": "http://example.edu/credentials/888", 950 // "issuanceDate": "0001-01-01T00:00:00Z", 951 // "issuer": "did:example:888", 952 // "last_name": "Pinkman", 953 // "photo": "http://image.com/user777", 954 // "type": "VerifiableCredential" 955 // }, 956 // { 957 // "@context": [ 958 // "https://www.w3.org/2018/credentials/v1" 959 // ], 960 // "credentialSubject": "did:example:888", 961 // "id": "http://example.edu/credentials/888", 962 // "issuanceDate": "0001-01-01T00:00:00Z", 963 // "issuer": "did:example:888", 964 // "photo": "http://image.com/user777", 965 // "type": "VerifiableCredential" 966 // }, 967 // { 968 // "@context": [ 969 // "https://www.w3.org/2018/credentials/v1" 970 // ], 971 // "credentialSubject": "did:example:777", 972 // "id": "http://example.edu/credentials/777", 973 // "image": "http://image.com/user777", 974 // "issuanceDate": "0001-01-01T00:00:00Z", 975 // "issuer": "did:example:777", 976 // "type": "VerifiableCredential" 977 // } 978 // ] 979 // } 980 } 981 982 func ExamplePresentationDefinition_CreateVP_submissionRequirements() { 983 pd := &PresentationDefinition{ 984 ID: "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 985 Purpose: "To sell you a drink we need to know that you are an adult.", 986 SubmissionRequirements: []*SubmissionRequirement{ 987 { 988 Rule: "all", 989 From: "A", 990 }, 991 { 992 Rule: "pick", 993 Purpose: "We need your photo to identify you.", 994 Count: 1, 995 FromNested: []*SubmissionRequirement{ 996 { 997 Rule: "all", 998 From: "drivers_license_image", 999 }, 1000 { 1001 Rule: "all", 1002 From: "passport_image", 1003 }, 1004 }, 1005 }, 1006 }, 1007 InputDescriptors: []*InputDescriptor{{ 1008 ID: "age_descriptor", 1009 Group: []string{"A"}, 1010 Purpose: "Your age should be greater or equal to 18.", 1011 Schema: []*Schema{{ 1012 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1013 }}, 1014 Constraints: &Constraints{ 1015 Fields: []*Field{{ 1016 Path: []string{"$.age"}, 1017 Filter: &Filter{ 1018 Type: &intFilterType, 1019 Minimum: 18, 1020 }, 1021 }}, 1022 }, 1023 }, { 1024 ID: "drivers_license_image_descriptor", 1025 Group: []string{"drivers_license_image"}, 1026 Purpose: "We need your photo to identify you", 1027 Schema: []*Schema{{ 1028 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1029 }}, 1030 Constraints: &Constraints{ 1031 Fields: []*Field{{ 1032 Path: []string{"$.photo"}, 1033 Filter: &Filter{ 1034 Type: &strFilterType, 1035 Format: "uri", 1036 }, 1037 }}, 1038 }, 1039 }, { 1040 ID: "passport_image_descriptor", 1041 Group: []string{"passport_image"}, 1042 Purpose: "We need your image to identify you", 1043 Schema: []*Schema{{ 1044 URI: fmt.Sprintf("%s#%s", verifiable.ContextID, verifiable.VCType), 1045 }}, 1046 Constraints: &Constraints{ 1047 Fields: []*Field{{ 1048 Path: []string{"$.image"}, 1049 Filter: &Filter{ 1050 Type: &strFilterType, 1051 Format: "uri", 1052 }, 1053 }}, 1054 }, 1055 }}, 1056 } 1057 1058 loader, err := ldtestutil.DocumentLoader() 1059 if err != nil { 1060 panic(err) 1061 } 1062 1063 vp, err := pd.CreateVP([]*verifiable.Credential{ 1064 { 1065 ID: "http://example.edu/credentials/777", 1066 Context: []string{verifiable.ContextURI}, 1067 Types: []string{verifiable.VCType}, 1068 Issuer: verifiable.Issuer{ 1069 ID: "did:example:777", 1070 }, 1071 Issued: &util.TimeWrapper{ 1072 Time: time.Time{}, 1073 }, 1074 Subject: "did:example:777", 1075 CustomFields: map[string]interface{}{ 1076 "first_name": "Andrew", 1077 "last_name": "Hanks", 1078 "image": "http://image.com/user777", 1079 "age": 25, 1080 }, 1081 }, 1082 { 1083 ID: "http://example.edu/credentials/888", 1084 Context: []string{"https://www.w3.org/2018/credentials/v1"}, 1085 Types: []string{"VerifiableCredential"}, 1086 Issuer: verifiable.Issuer{ 1087 ID: "did:example:888", 1088 }, 1089 Issued: &util.TimeWrapper{ 1090 Time: time.Time{}, 1091 }, 1092 Subject: "did:example:888", 1093 CustomFields: map[string]interface{}{ 1094 "first_name": "Jesse", 1095 "last_name": "Pinkman", 1096 "photo": "http://image.com/user777", 1097 "age": 21, 1098 }, 1099 }, 1100 }, loader, verifiable.WithJSONLDDocumentLoader(loader)) 1101 if err != nil { 1102 panic(err) 1103 } 1104 1105 vp.ID = dummy 1106 vp.CustomFields["presentation_submission"].(*PresentationSubmission).ID = dummy 1107 1108 vpBytes, err := json.MarshalIndent(vp, "", "\t") 1109 if err != nil { 1110 panic(err) 1111 } 1112 1113 fmt.Println(string(vpBytes)) 1114 // Output: 1115 // { 1116 // "@context": [ 1117 // "https://www.w3.org/2018/credentials/v1", 1118 // "https://identity.foundation/presentation-exchange/submission/v1" 1119 // ], 1120 // "id": "DUMMY", 1121 // "presentation_submission": { 1122 // "id": "DUMMY", 1123 // "definition_id": "c1b88ce1-8460-4baf-8f16-4759a2f055fd", 1124 // "descriptor_map": [ 1125 // { 1126 // "id": "age_descriptor", 1127 // "format": "ldp_vp", 1128 // "path": "$", 1129 // "path_nested": { 1130 // "id": "age_descriptor", 1131 // "format": "ldp_vc", 1132 // "path": "$.verifiableCredential[0]" 1133 // } 1134 // }, 1135 // { 1136 // "id": "age_descriptor", 1137 // "format": "ldp_vp", 1138 // "path": "$", 1139 // "path_nested": { 1140 // "id": "age_descriptor", 1141 // "format": "ldp_vc", 1142 // "path": "$.verifiableCredential[1]" 1143 // } 1144 // }, 1145 // { 1146 // "id": "drivers_license_image_descriptor", 1147 // "format": "ldp_vp", 1148 // "path": "$", 1149 // "path_nested": { 1150 // "id": "drivers_license_image_descriptor", 1151 // "format": "ldp_vc", 1152 // "path": "$.verifiableCredential[1]" 1153 // } 1154 // }, 1155 // { 1156 // "id": "passport_image_descriptor", 1157 // "format": "ldp_vp", 1158 // "path": "$", 1159 // "path_nested": { 1160 // "id": "passport_image_descriptor", 1161 // "format": "ldp_vc", 1162 // "path": "$.verifiableCredential[0]" 1163 // } 1164 // } 1165 // ] 1166 // }, 1167 // "type": [ 1168 // "VerifiablePresentation", 1169 // "PresentationSubmission" 1170 // ], 1171 // "verifiableCredential": [ 1172 // { 1173 // "@context": [ 1174 // "https://www.w3.org/2018/credentials/v1" 1175 // ], 1176 // "age": 25, 1177 // "credentialSubject": "did:example:777", 1178 // "first_name": "Andrew", 1179 // "id": "http://example.edu/credentials/777", 1180 // "image": "http://image.com/user777", 1181 // "issuanceDate": "0001-01-01T00:00:00Z", 1182 // "issuer": "did:example:777", 1183 // "last_name": "Hanks", 1184 // "type": "VerifiableCredential" 1185 // }, 1186 // { 1187 // "@context": [ 1188 // "https://www.w3.org/2018/credentials/v1" 1189 // ], 1190 // "age": 21, 1191 // "credentialSubject": "did:example:888", 1192 // "first_name": "Jesse", 1193 // "id": "http://example.edu/credentials/888", 1194 // "issuanceDate": "0001-01-01T00:00:00Z", 1195 // "issuer": "did:example:888", 1196 // "last_name": "Pinkman", 1197 // "photo": "http://image.com/user777", 1198 // "type": "VerifiableCredential" 1199 // } 1200 // ] 1201 // } 1202 } 1203 1204 // Example of a Verifier verifying the presentation submission of a Holder. 1205 func ExamplePresentationDefinition_Match() { 1206 // verifier sends their presentation definitions to the holder 1207 verifierDefinitions := &PresentationDefinition{ 1208 InputDescriptors: []*InputDescriptor{ 1209 { 1210 ID: "banking", 1211 Schema: []*Schema{{ 1212 URI: "https://example.org/examples#Customer", 1213 }}, 1214 }, 1215 { 1216 ID: "residence", 1217 Schema: []*Schema{{ 1218 URI: "https://example.org/examples#Street", 1219 }}, 1220 }, 1221 }, 1222 } 1223 1224 // holder fetches their credentials 1225 accountCredential := fetchVC([]string{"https://example.context.jsonld/account"}, []string{"Customer"}) 1226 addressCredential := fetchVC([]string{"https://example.context.jsonld/address"}, []string{"Street"}) 1227 1228 // holder builds their presentation submission against the verifier's definitions 1229 vp, err := newPresentationSubmission( 1230 &PresentationSubmission{DescriptorMap: []*InputDescriptorMapping{ 1231 { 1232 ID: "banking", 1233 Path: "$.verifiableCredential[0]", 1234 }, 1235 { 1236 ID: "residence", 1237 Path: "$.verifiableCredential[1]", 1238 }, 1239 }}, 1240 accountCredential, addressCredential, 1241 ) 1242 if err != nil { 1243 panic(err) 1244 } 1245 1246 // holder sends VP over the wire to the verifier 1247 vpBytes, err := json.Marshal(vp) 1248 if err != nil { 1249 panic(err) 1250 } 1251 1252 // load json-ld context 1253 loader, err := ldtestutil.DocumentLoader( 1254 ldcontext.Document{ 1255 URL: "https://example.context.jsonld/account", 1256 Content: []byte(exampleJSONLDContext), 1257 }, 1258 ldcontext.Document{ 1259 URL: "https://example.context.jsonld/address", 1260 Content: []byte(exampleJSONLDContext), 1261 }, 1262 ) 1263 if err != nil { 1264 panic(err) 1265 } 1266 1267 // verifier parses the vp 1268 // note: parsing this VP without verifying the proof just for example purposes. 1269 // Always verify proofs in production! 1270 receivedVP, err := verifiable.ParsePresentation(vpBytes, 1271 verifiable.WithPresDisabledProofCheck(), 1272 verifiable.WithPresJSONLDDocumentLoader(loader)) 1273 if err != nil { 1274 panic(err) 1275 } 1276 1277 // verifier matches the received VP against their definitions 1278 matched, err := verifierDefinitions.Match( 1279 []*verifiable.Presentation{receivedVP}, loader, 1280 WithCredentialOptions(verifiable.WithJSONLDDocumentLoader(loader)), 1281 ) 1282 if err != nil { 1283 panic(fmt.Errorf("presentation submission did not match definitions: %w", err)) 1284 } 1285 1286 for _, descriptor := range verifierDefinitions.InputDescriptors { 1287 receivedCred := matched[descriptor.ID] 1288 fmt.Printf( 1289 "verifier received the '%s' credential for the input descriptor id '%s'\n", 1290 receivedCred.Credential.Context[1], descriptor.ID) 1291 } 1292 1293 // Output: 1294 // verifier received the 'https://example.context.jsonld/account' credential for the input descriptor id 'banking' 1295 // verifier received the 'https://example.context.jsonld/address' credential for the input descriptor id 'residence' 1296 } 1297 1298 func newPresentationSubmission( 1299 submission *PresentationSubmission, vcs ...*verifiable.Credential) (*verifiable.Presentation, error) { 1300 vp, err := verifiable.NewPresentation(verifiable.WithCredentials(vcs...)) 1301 if err != nil { 1302 return nil, err 1303 } 1304 1305 vp.Context = append(vp.Context, "https://identity.foundation/presentation-exchange/submission/v1") 1306 vp.Type = append(vp.Type, "PresentationSubmission") 1307 1308 if submission != nil { 1309 vp.CustomFields = make(map[string]interface{}) 1310 vp.CustomFields["presentation_submission"] = toExampleMap(submission) 1311 } 1312 1313 return vp, nil 1314 } 1315 1316 func toExampleMap(v interface{}) map[string]interface{} { 1317 bits, err := json.Marshal(v) 1318 if err != nil { 1319 panic(err) 1320 } 1321 1322 m := make(map[string]interface{}) 1323 1324 err = json.Unmarshal(bits, &m) 1325 if err != nil { 1326 panic(err) 1327 } 1328 1329 return m 1330 } 1331 1332 const exampleJSONLDContext = `{ 1333 "@context":{ 1334 "@version":1.1, 1335 "@protected":true, 1336 "name":"http://schema.org/name", 1337 "ex":"https://example.org/examples#", 1338 "Customer":"ex:Customer", 1339 "Street":"ex:Street", 1340 "xsd":"http://www.w3.org/2001/XMLSchema#" 1341 } 1342 }` 1343 1344 func fetchVC(ctx, types []string) *verifiable.Credential { 1345 vc := &verifiable.Credential{ 1346 Context: append([]string{verifiable.ContextURI}, ctx...), 1347 Types: append([]string{verifiable.VCType}, types...), 1348 ID: "http://test.credential.com/123", 1349 Issuer: verifiable.Issuer{ID: "http://test.issuer.com"}, 1350 Issued: &util.TimeWrapper{ 1351 Time: time.Now(), 1352 }, 1353 Subject: map[string]interface{}{ 1354 "id": uuid.New().String(), 1355 }, 1356 } 1357 1358 return vc 1359 }