github.com/hyperledger/aries-framework-go@v0.3.2/pkg/client/issuecredential/rfc0593/event_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package rfc0593_test 8 9 import ( 10 "encoding/json" 11 "errors" 12 "testing" 13 "time" 14 15 "github.com/google/uuid" 16 "github.com/piprate/json-gold/ld" 17 "github.com/stretchr/testify/require" 18 19 "github.com/hyperledger/aries-framework-go/component/storageutil/mem" 20 "github.com/hyperledger/aries-framework-go/pkg/client/issuecredential/rfc0593" 21 "github.com/hyperledger/aries-framework-go/pkg/crypto" 22 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" 23 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator" 24 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange" 25 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/issuecredential" 26 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" 27 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite" 28 "github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2018" 29 "github.com/hyperledger/aries-framework-go/pkg/doc/util" 30 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 31 "github.com/hyperledger/aries-framework-go/pkg/framework/aries" 32 "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr" 33 "github.com/hyperledger/aries-framework-go/pkg/kms" 34 mockcrypto "github.com/hyperledger/aries-framework-go/pkg/mock/crypto" 35 mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 36 "github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint" 37 "github.com/hyperledger/aries-framework-go/spi/storage" 38 ) 39 40 func TestAutoExecute(t *testing.T) { // nolint:gocyclo 41 t.Run("auto-executes RFC0593", func(t *testing.T) { 42 provider := agent(t) 43 events := make(chan service.DIDCommAction) 44 go rfc0593.AutoExecute(provider, nil)(events) 45 46 testCases := []struct { 47 label string 48 msg interface{} 49 check func(md *issuecredential.MetaData) 50 }{ 51 { 52 label: "handles proposals", 53 check: func(md *issuecredential.MetaData) { require.NotEmpty(t, md.OfferCredentialV2()) }, 54 msg: &issuecredential.ProposeCredentialV2{ 55 Type: issuecredential.ProposeCredentialMsgTypeV2, 56 Formats: []issuecredential.Format{{ 57 AttachID: "123", 58 Format: rfc0593.ProofVCDetailFormat, 59 }}, 60 FiltersAttach: []decorator.Attachment{{ 61 ID: "123", 62 Data: decorator.AttachmentData{ 63 JSON: randomCredSpec(t), 64 }, 65 }}, 66 }, 67 }, 68 { 69 label: "handles offers", 70 check: func(md *issuecredential.MetaData) { require.NotEmpty(t, md.RequestCredentialV2()) }, 71 msg: &issuecredential.OfferCredentialV2{ 72 Type: issuecredential.OfferCredentialMsgTypeV2, 73 Formats: []issuecredential.Format{{ 74 AttachID: "123", 75 Format: rfc0593.ProofVCDetailFormat, 76 }}, 77 OffersAttach: []decorator.Attachment{{ 78 ID: "123", 79 Data: decorator.AttachmentData{ 80 JSON: randomCredSpec(t), 81 }, 82 }}, 83 }, 84 }, 85 { 86 label: "handles requests", 87 check: func(md *issuecredential.MetaData) { require.NotEmpty(t, md.IssueCredentialV2()) }, 88 msg: &issuecredential.RequestCredentialV2{ 89 Type: issuecredential.RequestCredentialMsgTypeV2, 90 Formats: []issuecredential.Format{{ 91 AttachID: "123", 92 Format: rfc0593.ProofVCDetailFormat, 93 }}, 94 RequestsAttach: []decorator.Attachment{{ 95 ID: "123", 96 Data: decorator.AttachmentData{ 97 JSON: randomCredSpec(t), 98 }, 99 }}, 100 }, 101 }, 102 } 103 104 for i := range testCases { 105 tc := testCases[i] 106 107 t.Run(tc.label, func(t *testing.T) { 108 var ( 109 arg interface{} 110 err error 111 ) 112 113 ready := make(chan struct{}) 114 msg := service.NewDIDCommMsgMap(tc.msg) 115 msg.SetID(uuid.New().String()) 116 117 go func() { 118 events <- service.DIDCommAction{ 119 ProtocolName: issuecredential.Name, 120 Message: msg, 121 Continue: func(a interface{}) { 122 arg = a 123 ready <- struct{}{} 124 }, 125 Stop: func(e error) { 126 err = e 127 ready <- struct{}{} 128 }, 129 } 130 }() 131 132 select { 133 case <-ready: 134 case <-time.After(time.Second): 135 require.Fail(t, "timeout") 136 } 137 138 require.NoError(t, err) 139 opt, ok := arg.(issuecredential.Opt) 140 require.True(t, ok) 141 142 md := &issuecredential.MetaData{} 143 opt(md) 144 145 tc.check(md) 146 }) 147 } 148 }) 149 150 t.Run("forwards events from other protocols", func(t *testing.T) { 151 events := make(chan service.DIDCommAction) 152 next := make(chan service.DIDCommAction) 153 154 go rfc0593.AutoExecute(agent(t), next)(events) 155 156 expected := &didexchange.Complete{ 157 ID: uuid.New().String(), 158 Type: didexchange.CompleteMsgType, 159 } 160 161 go func() { 162 events <- service.DIDCommAction{ 163 Message: service.NewDIDCommMsgMap(expected), 164 } 165 }() 166 167 select { 168 case <-time.After(time.Second): 169 require.Fail(t, "timeout") 170 case event := <-next: 171 result := &didexchange.Complete{} 172 173 err := event.Message.Decode(result) 174 require.NoError(t, err) 175 176 require.Equal(t, expected, result) 177 } 178 }) 179 180 t.Run("forwards issue-credential events not related to RFC0593", func(t *testing.T) { 181 events := make(chan service.DIDCommAction) 182 next := make(chan service.DIDCommAction) 183 184 go rfc0593.AutoExecute(agent(t), next)(events) 185 186 expected := &issuecredential.RequestCredentialV2{ 187 Type: issuecredential.RequestCredentialMsgTypeV2, 188 Comment: uuid.New().String(), 189 RequestsAttach: []decorator.Attachment{{ 190 ID: uuid.New().String(), 191 Data: decorator.AttachmentData{ 192 JSON: map[string]interface{}{}, 193 }, 194 }}, 195 } 196 197 go func() { 198 events <- service.DIDCommAction{ 199 Message: service.NewDIDCommMsgMap(expected), 200 } 201 }() 202 203 select { 204 case <-time.After(time.Second): 205 require.Fail(t, "timeout") 206 case event := <-next: 207 result := &issuecredential.RequestCredentialV2{} 208 209 err := event.Message.Decode(result) 210 require.NoError(t, err) 211 require.Equal(t, expected, result) 212 } 213 }) 214 215 t.Run("stops the protocol in the event of an error", func(t *testing.T) { 216 events := make(chan service.DIDCommAction) 217 218 go rfc0593.AutoExecute(agent(t), nil)(events) 219 220 ready := make(chan struct{}) 221 222 go func() { 223 events <- service.DIDCommAction{ 224 Message: service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 225 Type: issuecredential.RequestCredentialMsgTypeV2, 226 Comment: uuid.New().String(), 227 Formats: []issuecredential.Format{{ 228 AttachID: "123", 229 Format: rfc0593.ProofVCDetailFormat, 230 }}, 231 RequestsAttach: []decorator.Attachment{{ 232 ID: "123", 233 Data: decorator.AttachmentData{ 234 JSON: "INVALID", 235 }, 236 }}, 237 }), 238 Continue: func(interface{}) { 239 require.Fail(t, "protocol was continued") 240 }, 241 Stop: func(e error) { 242 require.Error(t, e) 243 require.Contains(t, e.Error(), "failed to unmarshal attachment contents") 244 ready <- struct{}{} 245 }, 246 } 247 }() 248 249 select { 250 case <-ready: 251 case <-time.After(time.Second): 252 require.Fail(t, "timeout") 253 } 254 }) 255 256 t.Run("stops the protocol if the DB cannot be opened", func(t *testing.T) { 257 events := make(chan service.DIDCommAction) 258 259 agent := agent(t, withProtoStateStorageProvider(&mockstorage.MockStoreProvider{ 260 Store: &mockstorage.MockStore{Store: make(map[string]mockstorage.DBEntry)}, 261 FailNamespace: rfc0593.StoreName, 262 })) 263 264 go rfc0593.AutoExecute(agent, nil)(events) 265 266 ready := make(chan struct{}) 267 268 go func() { 269 events <- service.DIDCommAction{ 270 Message: service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 271 Type: issuecredential.RequestCredentialMsgTypeV2, 272 Comment: uuid.New().String(), 273 Formats: []issuecredential.Format{{ 274 AttachID: "123", 275 Format: rfc0593.ProofVCDetailFormat, 276 }}, 277 RequestsAttach: []decorator.Attachment{{ 278 ID: "123", 279 Data: decorator.AttachmentData{ 280 JSON: randomCredSpec(t), 281 }, 282 }}, 283 }), 284 Continue: func(interface{}) { 285 require.Fail(t, "protocol was continued") 286 }, 287 Stop: func(e error) { 288 require.Error(t, e) 289 require.Contains(t, e.Error(), "failed to open store") 290 ready <- struct{}{} 291 }, 292 } 293 }() 294 295 select { 296 case <-ready: 297 case <-time.After(time.Second): 298 require.Fail(t, "timeout") 299 } 300 }) 301 } 302 303 func TestReplayProposal(t *testing.T) { 304 t.Run("replays the proposed spec as an offer", func(t *testing.T) { 305 expected := &rfc0593.CredentialSpec{ 306 Template: marshal(t, newVC(t)), 307 Options: &rfc0593.CredentialSpecOptions{ 308 ProofPurpose: "assertionMethod", 309 Created: time.Now().Format(time.RFC3339), 310 Domain: uuid.New().String(), 311 Challenge: uuid.New().String(), 312 ProofType: "Ed25519Signature2018", 313 Status: &rfc0593.CredentialStatus{Type: "test"}, 314 }, 315 } 316 317 arg, options, err := rfc0593.ReplayProposal(agent(t), service.NewDIDCommMsgMap(&issuecredential.ProposeCredentialV2{ 318 Type: issuecredential.ProposeCredentialMsgTypeV2, 319 Formats: []issuecredential.Format{{ 320 AttachID: "123", 321 Format: rfc0593.ProofVCDetailFormat, 322 }}, 323 FiltersAttach: []decorator.Attachment{{ 324 ID: "123", 325 Data: decorator.AttachmentData{ 326 JSON: expected, 327 }, 328 }}, 329 })) 330 require.NoError(t, err) 331 require.Equal(t, expected.Options, options) 332 333 opt, ok := arg.(issuecredential.Opt) 334 require.True(t, ok) 335 336 md := &issuecredential.MetaData{} 337 opt(md) 338 339 require.NotEmpty(t, md.OfferCredentialV2()) 340 require.Equal(t, 341 expected, 342 extractPayload(t, 343 rfc0593.ProofVCDetailFormat, md.OfferCredentialV2().Formats, md.OfferCredentialV2().OffersAttach), 344 ) 345 }) 346 347 t.Run("error if VC is malformed", func(t *testing.T) { 348 spec := randomCredSpec(t) 349 spec.Template = nil 350 351 _, _, err := rfc0593.ReplayProposal(agent(t), service.NewDIDCommMsgMap(&issuecredential.ProposeCredentialV2{ 352 Type: issuecredential.ProposeCredentialMsgTypeV2, 353 Formats: []issuecredential.Format{{ 354 AttachID: "123", 355 Format: rfc0593.ProofVCDetailFormat, 356 }}, 357 FiltersAttach: []decorator.Attachment{{ 358 ID: "123", 359 Data: decorator.AttachmentData{ 360 JSON: spec, 361 }, 362 }}, 363 })) 364 require.Error(t, err) 365 require.Contains(t, err.Error(), "unable to parse vc") 366 }) 367 } 368 369 func TestReplayOffer(t *testing.T) { 370 t.Run("replays the offered spec as a request", func(t *testing.T) { 371 expected := &rfc0593.CredentialSpec{ 372 Template: marshal(t, newVC(t)), 373 Options: &rfc0593.CredentialSpecOptions{ 374 ProofPurpose: "assertionMethod", 375 Created: time.Now().Format(time.RFC3339), 376 Domain: uuid.New().String(), 377 Challenge: uuid.New().String(), 378 ProofType: "Ed25519Signature2018", 379 Status: &rfc0593.CredentialStatus{Type: "test"}, 380 }, 381 } 382 383 arg, options, err := rfc0593.ReplayOffer(agent(t), service.NewDIDCommMsgMap(&issuecredential.OfferCredentialV2{ 384 Type: issuecredential.OfferCredentialMsgTypeV2, 385 Formats: []issuecredential.Format{{ 386 AttachID: "123", 387 Format: rfc0593.ProofVCDetailFormat, 388 }}, 389 OffersAttach: []decorator.Attachment{{ 390 ID: "123", 391 Data: decorator.AttachmentData{ 392 JSON: expected, 393 }, 394 }}, 395 })) 396 require.NoError(t, err) 397 require.Equal(t, expected.Options, options) 398 399 opt, ok := arg.(issuecredential.Opt) 400 require.True(t, ok) 401 402 md := &issuecredential.MetaData{} 403 opt(md) 404 405 require.NotEmpty(t, md.RequestCredentialV2()) 406 require.Equal(t, 407 expected, 408 extractPayload(t, 409 rfc0593.ProofVCDetailFormat, md.RequestCredentialV2().Formats, md.RequestCredentialV2().RequestsAttach), 410 ) 411 }) 412 413 t.Run("error if VC is malformed", func(t *testing.T) { 414 spec := randomCredSpec(t) 415 spec.Template = nil 416 417 _, _, err := rfc0593.ReplayOffer(agent(t), service.NewDIDCommMsgMap(&issuecredential.OfferCredentialV2{ 418 Type: issuecredential.OfferCredentialMsgTypeV2, 419 Formats: []issuecredential.Format{{ 420 AttachID: "123", 421 Format: rfc0593.ProofVCDetailFormat, 422 }}, 423 OffersAttach: []decorator.Attachment{{ 424 ID: "123", 425 Data: decorator.AttachmentData{ 426 JSON: spec, 427 }, 428 }}, 429 })) 430 require.Error(t, err) 431 require.Contains(t, err.Error(), "unable to parse vc") 432 }) 433 } 434 435 func TestIssueCredential(t *testing.T) { 436 t.Run("attaches LD proof and produces a request-credential message with the VC attached", func(t *testing.T) { 437 t.Run("Ed25519", func(t *testing.T) { 438 agent := agent(t) 439 unverifiedCredential := newVC(t) 440 spec := &rfc0593.CredentialSpec{ 441 Template: marshal(t, unverifiedCredential), 442 Options: &rfc0593.CredentialSpecOptions{ 443 ProofPurpose: "assertionMethod", 444 Created: time.Now().Format(time.RFC3339), 445 Domain: uuid.New().String(), 446 Challenge: uuid.New().String(), 447 ProofType: "Ed25519Signature2018", 448 Status: &rfc0593.CredentialStatus{Type: "test"}, 449 }, 450 } 451 452 arg, options, err := rfc0593.IssueCredential(agent, service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 453 Type: issuecredential.RequestCredentialMsgTypeV2, 454 Formats: []issuecredential.Format{{ 455 AttachID: "123", 456 Format: rfc0593.ProofVCDetailFormat, 457 }}, 458 RequestsAttach: []decorator.Attachment{{ 459 ID: "123", 460 Data: decorator.AttachmentData{ 461 JSON: spec, 462 }, 463 }}, 464 })) 465 require.NoError(t, err) 466 require.Equal(t, spec.Options, options) 467 468 opt, ok := arg.(issuecredential.Opt) 469 require.True(t, ok) 470 471 md := &issuecredential.MetaData{} 472 opt(md) 473 474 require.NotEmpty(t, md.IssueCredentialV2()) 475 require.NotEmpty(t, md.IssueCredentialV2().CredentialsAttach) 476 477 raw, err := md.IssueCredentialV2().CredentialsAttach[0].Data.Fetch() 478 require.NoError(t, err) 479 480 verifiableCredential, err := verifiable.ParseCredential( 481 raw, 482 verifiable.WithPublicKeyFetcher(verifiable.NewVDRKeyResolver(agent.VDRegistry()).PublicKeyFetcher()), 483 verifiable.WithJSONLDDocumentLoader(agent.JSONLDDocumentLoader()), 484 ) 485 require.NoError(t, err) 486 487 require.Equal(t, unverifiedCredential.ID, verifiableCredential.ID) 488 require.NotEmpty(t, verifiableCredential.Proofs) 489 require.Equal(t, spec.Options.Challenge, verifiableCredential.Proofs[0]["challenge"]) 490 require.Equal(t, spec.Options.Domain, verifiableCredential.Proofs[0]["domain"]) 491 }) 492 493 t.Run("BbsBlsSignature2020", func(t *testing.T) { 494 agent := agent(t) 495 unverifiedCredential := newVC(t) 496 497 spec := &rfc0593.CredentialSpec{ 498 Template: marshal(t, unverifiedCredential), 499 Options: &rfc0593.CredentialSpecOptions{ 500 ProofPurpose: "assertionMethod", 501 Created: time.Now().Format(time.RFC3339), 502 Domain: uuid.New().String(), 503 Challenge: uuid.New().String(), 504 ProofType: "BbsBlsSignature2020", 505 Status: &rfc0593.CredentialStatus{Type: "test"}, 506 }, 507 } 508 509 arg, options, err := rfc0593.IssueCredential(agent, service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 510 Type: issuecredential.RequestCredentialMsgTypeV2, 511 Formats: []issuecredential.Format{{ 512 AttachID: "123", 513 Format: rfc0593.ProofVCDetailFormat, 514 }}, 515 RequestsAttach: []decorator.Attachment{{ 516 ID: "123", 517 Data: decorator.AttachmentData{ 518 JSON: spec, 519 }, 520 }}, 521 })) 522 require.NoError(t, err) 523 require.Equal(t, spec.Options, options) 524 525 opt, ok := arg.(issuecredential.Opt) 526 require.True(t, ok) 527 528 md := &issuecredential.MetaData{} 529 opt(md) 530 531 require.NotEmpty(t, md.IssueCredentialV2()) 532 require.NotEmpty(t, md.IssueCredentialV2().CredentialsAttach) 533 534 raw, err := md.IssueCredentialV2().CredentialsAttach[0].Data.Fetch() 535 require.NoError(t, err) 536 537 verifiableCredential, err := verifiable.ParseCredential( 538 raw, 539 verifiable.WithPublicKeyFetcher(verifiable.NewVDRKeyResolver(agent.VDRegistry()).PublicKeyFetcher()), 540 verifiable.WithJSONLDDocumentLoader(agent.JSONLDDocumentLoader()), 541 ) 542 require.NoError(t, err) 543 544 require.Equal(t, unverifiedCredential.ID, verifiableCredential.ID) 545 require.NotEmpty(t, verifiableCredential.Proofs) 546 require.Equal(t, spec.Options.Challenge, verifiableCredential.Proofs[0]["challenge"]) 547 require.Equal(t, spec.Options.Domain, verifiableCredential.Proofs[0]["domain"]) 548 }) 549 }) 550 551 t.Run("error if VC is malformed", func(t *testing.T) { 552 spec := randomCredSpec(t) 553 spec.Template = nil 554 555 _, _, err := rfc0593.IssueCredential(agent(t), service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 556 Type: issuecredential.RequestCredentialMsgTypeV2, 557 Formats: []issuecredential.Format{{ 558 AttachID: "123", 559 Format: rfc0593.ProofVCDetailFormat, 560 }}, 561 RequestsAttach: []decorator.Attachment{{ 562 ID: "123", 563 Data: decorator.AttachmentData{ 564 JSON: spec, 565 }, 566 }}, 567 })) 568 require.Error(t, err) 569 require.Contains(t, err.Error(), "unable to parse vc") 570 }) 571 572 t.Run("error on unsupported proofType", func(t *testing.T) { 573 spec := randomCredSpec(t) 574 spec.Options.ProofType = "UNSUPPORTED" 575 576 _, _, err := rfc0593.IssueCredential(agent(t), service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 577 Type: issuecredential.RequestCredentialMsgTypeV2, 578 Formats: []issuecredential.Format{{ 579 AttachID: "123", 580 Format: rfc0593.ProofVCDetailFormat, 581 }}, 582 RequestsAttach: []decorator.Attachment{{ 583 ID: "123", 584 Data: decorator.AttachmentData{ 585 JSON: spec, 586 }, 587 }}, 588 })) 589 require.Error(t, err) 590 require.Contains(t, err.Error(), "unsupported proof type") 591 }) 592 593 t.Run("error if cannot add LD proof", func(t *testing.T) { 594 expected := errors.New("test") 595 spec := randomCredSpec(t) 596 ctx := agent(t) 597 provider := &mockProvider{ 598 loader: ctx.JSONLDDocumentLoader(), 599 km: ctx.KMS(), 600 cr: &mockcrypto.Crypto{SignErr: expected}, 601 sp: mem.NewProvider(), 602 } 603 604 _, _, err := rfc0593.IssueCredential(provider, service.NewDIDCommMsgMap(&issuecredential.RequestCredentialV2{ 605 Type: issuecredential.RequestCredentialMsgTypeV2, 606 Formats: []issuecredential.Format{{ 607 AttachID: "123", 608 Format: rfc0593.ProofVCDetailFormat, 609 }}, 610 RequestsAttach: []decorator.Attachment{{ 611 ID: "123", 612 Data: decorator.AttachmentData{ 613 JSON: spec, 614 }, 615 }}, 616 })) 617 require.ErrorIs(t, err, expected) 618 }) 619 } 620 621 func TestVerifyCredential(t *testing.T) { 622 t.Run("verifies the credential", func(t *testing.T) { 623 agent := agent(t) 624 spec := randomCredSpec(t) 625 name := uuid.New().String() 626 attachID := uuid.New().String() 627 msg := service.NewDIDCommMsgMap(&issuecredential.IssueCredentialV2{ 628 Type: issuecredential.IssueCredentialMsgTypeV2, 629 Formats: []issuecredential.Format{{ 630 AttachID: attachID, 631 Format: rfc0593.ProofVCFormat, 632 }}, 633 CredentialsAttach: []decorator.Attachment{{ 634 ID: attachID, 635 Data: decorator.AttachmentData{ 636 JSON: newVCWithProof(t, agent, spec), 637 }, 638 }}, 639 }) 640 msg.SetID(uuid.New().String()) 641 642 arg, err := rfc0593.VerifyCredential(agent, spec.Options, name, msg) 643 require.NoError(t, err) 644 645 opt, ok := arg.(issuecredential.Opt) 646 require.True(t, ok) 647 648 md := &issuecredential.MetaData{} 649 opt(md) 650 651 require.Len(t, md.CredentialNames(), 1) 652 require.Equal(t, name, md.CredentialNames()[0]) 653 }) 654 655 t.Run("fails if credential has no proof", func(t *testing.T) { 656 // TODO - enable when ParseCredential is fixed: https://github.com/hyperledger/aries-framework-go/issues/2799 657 t.Skip() 658 agent := agent(t) 659 attachID := uuid.New().String() 660 msg := service.NewDIDCommMsgMap(&issuecredential.IssueCredentialV2{ 661 Type: issuecredential.IssueCredentialMsgTypeV2, 662 Formats: []issuecredential.Format{{ 663 AttachID: attachID, 664 Format: rfc0593.ProofVCFormat, 665 }}, 666 CredentialsAttach: []decorator.Attachment{{ 667 ID: attachID, 668 Data: decorator.AttachmentData{ 669 JSON: newVC(t), 670 }, 671 }}, 672 }) 673 msg.SetID(uuid.New().String()) 674 675 _, err := rfc0593.VerifyCredential(agent, nil, uuid.New().String(), msg) 676 require.NoError(t, err) 677 }) 678 } 679 680 func marshal(t *testing.T, v interface{}) []byte { 681 t.Helper() 682 683 raw, err := json.Marshal(v) 684 require.NoError(t, err) 685 686 return raw 687 } 688 689 type options struct { 690 protoStateStorageProvider storage.Provider 691 } 692 693 type option func(*options) 694 695 func withProtoStateStorageProvider(p storage.Provider) option { 696 return func(o *options) { 697 o.protoStateStorageProvider = p 698 } 699 } 700 701 func agent(t *testing.T, o ...option) rfc0593.Provider { 702 t.Helper() 703 704 opts := &options{ 705 protoStateStorageProvider: mem.NewProvider(), 706 } 707 708 for i := range o { 709 o[i](opts) 710 } 711 712 a, err := aries.New( 713 aries.WithStoreProvider(mem.NewProvider()), 714 aries.WithProtocolStateStoreProvider(opts.protoStateStorageProvider), 715 ) 716 require.NoError(t, err) 717 718 t.Cleanup(func() { 719 err = a.Close() 720 require.NoError(t, err) 721 }) 722 723 ctx, err := a.Context() 724 require.NoError(t, err) 725 726 return ctx 727 } 728 729 func extractPayload(t *testing.T, 730 formatID string, formats []issuecredential.Format, attachments []decorator.Attachment) *rfc0593.CredentialSpec { 731 t.Helper() 732 733 var attachID string 734 735 for i := range formats { 736 if formats[i].Format == formatID { 737 attachID = formats[i].AttachID 738 739 break 740 } 741 } 742 743 require.NotEmpty(t, attachID) 744 745 var a *decorator.Attachment 746 747 for i := range attachments { 748 if attachments[i].ID == attachID { 749 a = &attachments[i] 750 751 break 752 } 753 } 754 755 require.NotNil(t, a) 756 require.NotZero(t, a.Data) 757 758 raw, err := a.Data.Fetch() 759 require.NoError(t, err) 760 761 spec := &rfc0593.CredentialSpec{} 762 763 err = json.Unmarshal(raw, spec) 764 require.NoError(t, err) 765 766 return spec 767 } 768 769 func newVC(t *testing.T) *verifiable.Credential { 770 t.Helper() 771 772 return &verifiable.Credential{ 773 Context: []string{verifiable.ContextURI, "https://w3id.org/security/bbs/v1"}, 774 Types: []string{verifiable.VCType}, 775 ID: uuid.New().URN(), 776 Subject: verifiable.Subject{ 777 ID: uuid.New().URN(), 778 }, 779 Issuer: verifiable.Issuer{ 780 ID: uuid.New().URN(), 781 }, 782 Issued: util.NewTime(time.Now()), 783 } 784 } 785 786 func newVCWithProof(t *testing.T, agent rfc0593.Provider, spec *rfc0593.CredentialSpec) *verifiable.Credential { 787 t.Helper() 788 789 keyID, kh, err := agent.KMS().Create(kms.ED25519Type) 790 require.NoError(t, err) 791 792 keyBytes, kt, err := agent.KMS().ExportPubKeyBytes(keyID) 793 require.NoError(t, err) 794 require.Equal(t, kms.ED25519Type, kt) 795 796 _, verificationMethod := fingerprint.CreateDIDKeyByCode(fingerprint.ED25519PubKeyMultiCodec, keyBytes) 797 798 suiteSigner := suite.NewCryptoSigner(agent.Crypto(), kh) 799 800 vc, err := verifiable.ParseCredential( 801 spec.Template, 802 verifiable.WithDisabledProofCheck(), 803 verifiable.WithJSONLDDocumentLoader(agent.JSONLDDocumentLoader()), 804 ) 805 require.NoError(t, err) 806 807 created, err := time.Parse(time.RFC3339, spec.Options.Created) 808 require.NoError(t, err) 809 810 err = vc.AddLinkedDataProof(&verifiable.LinkedDataProofContext{ 811 SignatureType: spec.Options.ProofType, 812 Suite: ed25519signature2018.New(suite.WithSigner(suiteSigner)), 813 SignatureRepresentation: verifiable.SignatureJWS, 814 Created: &created, 815 VerificationMethod: verificationMethod, 816 Challenge: spec.Options.Challenge, 817 Domain: spec.Options.Domain, 818 Purpose: spec.Options.ProofPurpose, 819 }, jsonld.WithDocumentLoader(agent.JSONLDDocumentLoader())) 820 require.NoError(t, err) 821 822 return vc 823 } 824 825 func randomCredSpec(t *testing.T) *rfc0593.CredentialSpec { 826 t.Helper() 827 828 return &rfc0593.CredentialSpec{ 829 Template: marshal(t, newVC(t)), 830 Options: &rfc0593.CredentialSpecOptions{ 831 ProofPurpose: "assertionMethod", 832 Created: time.Now().Format(time.RFC3339), 833 Domain: uuid.New().String(), 834 Challenge: uuid.New().String(), 835 ProofType: ed25519signature2018.SignatureType, 836 }, 837 } 838 } 839 840 type mockProvider struct { 841 loader ld.DocumentLoader 842 km kms.KeyManager 843 cr crypto.Crypto 844 sp storage.Provider 845 vdr vdr.Registry 846 } 847 848 func (m *mockProvider) JSONLDDocumentLoader() ld.DocumentLoader { 849 return m.loader 850 } 851 852 func (m *mockProvider) KMS() kms.KeyManager { 853 return m.km 854 } 855 856 func (m *mockProvider) Crypto() crypto.Crypto { 857 return m.cr 858 } 859 860 func (m *mockProvider) ProtocolStateStorageProvider() storage.Provider { 861 return m.sp 862 } 863 864 func (m *mockProvider) VDRegistry() vdr.Registry { 865 return m.vdr 866 }