github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/protocol/didexchange/service_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package didexchange 8 9 import ( 10 "crypto/ed25519" 11 "encoding/base64" 12 "encoding/json" 13 "errors" 14 "fmt" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/btcsuite/btcutil/base58" 20 "github.com/google/uuid" 21 "github.com/stretchr/testify/require" 22 23 commonmodel "github.com/hyperledger/aries-framework-go/pkg/common/model" 24 "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto" 25 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/model" 26 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" 27 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator" 28 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/mediator" 29 "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" 30 "github.com/hyperledger/aries-framework-go/pkg/doc/did" 31 "github.com/hyperledger/aries-framework-go/pkg/doc/util/kmsdidkey" 32 vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr" 33 "github.com/hyperledger/aries-framework-go/pkg/kms" 34 "github.com/hyperledger/aries-framework-go/pkg/kms/localkms" 35 "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/protocol" 36 mockroute "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/protocol/mediator" 37 mockdiddoc "github.com/hyperledger/aries-framework-go/pkg/mock/diddoc" 38 mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms" 39 mockprovider "github.com/hyperledger/aries-framework-go/pkg/mock/provider" 40 mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 41 mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr" 42 "github.com/hyperledger/aries-framework-go/pkg/secretlock" 43 "github.com/hyperledger/aries-framework-go/pkg/secretlock/noop" 44 "github.com/hyperledger/aries-framework-go/pkg/store/connection" 45 didstore "github.com/hyperledger/aries-framework-go/pkg/store/did" 46 "github.com/hyperledger/aries-framework-go/pkg/vdr/peer" 47 "github.com/hyperledger/aries-framework-go/spi/storage" 48 ) 49 50 const ( 51 testMethod = "peer" 52 threadIDValue = "xyz" 53 ) 54 55 type event interface { 56 // connection ID 57 ConnectionID() string 58 59 // invitation ID 60 InvitationID() string 61 } 62 63 func TestService_Name(t *testing.T) { 64 t.Run("test success", func(t *testing.T) { 65 prov, err := New(&protocol.MockProvider{ 66 ServiceMap: map[string]interface{}{ 67 mediator.Coordination: &mockroute.MockMediatorSvc{}, 68 }, 69 }) 70 require.NoError(t, err) 71 require.Equal(t, DIDExchange, prov.Name()) 72 }) 73 } 74 75 func TestServiceNew(t *testing.T) { 76 t.Run("test error from open store", func(t *testing.T) { 77 _, err := New( 78 &protocol.MockProvider{StoreProvider: &mockstorage.MockStoreProvider{ 79 ErrOpenStoreHandle: fmt.Errorf("failed to open store"), 80 }}) 81 require.Error(t, err) 82 require.Contains(t, err.Error(), "failed to open store") 83 }) 84 85 t.Run("test error from open protocol state store", func(t *testing.T) { 86 _, err := New( 87 &protocol.MockProvider{ProtocolStateStoreProvider: &mockstorage.MockStoreProvider{ 88 ErrOpenStoreHandle: fmt.Errorf("failed to open protocol state store"), 89 }}) 90 require.Error(t, err) 91 require.Contains(t, err.Error(), "failed to open protocol state store") 92 }) 93 94 t.Run("test service new error - no route service found", func(t *testing.T) { 95 _, err := New(&protocol.MockProvider{ServiceErr: errors.New("service not found")}) 96 require.Error(t, err) 97 require.Contains(t, err.Error(), "service not found") 98 }) 99 100 t.Run("test service new error - casting to route service failed", func(t *testing.T) { 101 _, err := New(&protocol.MockProvider{}) 102 require.Error(t, err) 103 require.Contains(t, err.Error(), "cast service to Route Service failed") 104 }) 105 } 106 107 func TestService_Initialize(t *testing.T) { 108 t.Run("success: already initialized", func(t *testing.T) { 109 prov := &protocol.MockProvider{ 110 ServiceMap: map[string]interface{}{ 111 mediator.Coordination: &mockroute.MockMediatorSvc{}, 112 }, 113 } 114 115 svc, err := New(prov) 116 require.NoError(t, err) 117 118 require.NoError(t, svc.Initialize(prov)) 119 }) 120 121 t.Run("fail: provider of wrong type", func(t *testing.T) { 122 prov := "this is not a provider" 123 124 svc := Service{} 125 126 err := svc.Initialize(prov) 127 128 require.Error(t, err) 129 require.Contains(t, err.Error(), "expected provider of type") 130 }) 131 } 132 133 // did-exchange flow with role Inviter. 134 func TestService_Handle_Inviter(t *testing.T) { 135 mockStore := &mockstorage.MockStore{Store: make(map[string]mockstorage.DBEntry)} 136 storeProv := mockstorage.NewCustomMockStoreProvider(mockStore) 137 k := newKMS(t, storeProv) 138 prov := &protocol.MockProvider{ 139 StoreProvider: storeProv, 140 ServiceMap: map[string]interface{}{ 141 mediator.Coordination: &mockroute.MockMediatorSvc{}, 142 }, 143 CustomKMS: k, 144 KeyTypeValue: kms.ED25519Type, 145 KeyAgreementTypeValue: kms.X25519ECDHKWType, 146 } 147 148 ctx := &context{ 149 outboundDispatcher: prov.OutboundDispatcher(), 150 crypto: &tinkcrypto.Crypto{}, 151 kms: k, 152 keyType: kms.ED25519Type, 153 keyAgreementType: kms.X25519ECDHKWType, 154 } 155 156 verPubKey, encPubKey := newSigningAndEncryptionDIDKeys(t, ctx) 157 mtp := transport.MediaTypeRFC0019EncryptedEnvelope 158 159 ctx.vdRegistry = &mockvdr.MockVDRegistry{CreateValue: createDIDDocWithKey(verPubKey, encPubKey, mtp)} 160 161 connRec, err := connection.NewRecorder(prov) 162 require.NoError(t, err) 163 require.NotNil(t, connRec) 164 165 ctx.connectionRecorder = connRec 166 167 doc, err := ctx.vdRegistry.Create(testMethod, nil) 168 require.NoError(t, err) 169 170 s, err := New(prov) 171 require.NoError(t, err) 172 173 actionCh := make(chan service.DIDCommAction, 10) 174 err = s.RegisterActionEvent(actionCh) 175 require.NoError(t, err) 176 177 statusCh := make(chan service.StateMsg, 10) 178 err = s.RegisterMsgEvent(statusCh) 179 require.NoError(t, err) 180 181 completedFlag := make(chan struct{}) 182 respondedFlag := make(chan struct{}) 183 184 go msgEventListener(t, statusCh, respondedFlag, completedFlag) 185 186 go func() { service.AutoExecuteActionEvent(actionCh) }() 187 188 invitation := &Invitation{ 189 Type: InvitationMsgType, 190 ID: randomString(), 191 Label: "Bob", 192 RecipientKeys: []string{verPubKey}, 193 ServiceEndpoint: "http://alice.agent.example.com:8081", 194 } 195 196 err = ctx.connectionRecorder.SaveInvitation(invitation.ID, invitation) 197 require.NoError(t, err) 198 199 thid := randomString() 200 201 // Invitation was previously sent by Alice to Bob. 202 // Bob now sends a did-exchange Invitation 203 payloadBytes, err := json.Marshal( 204 &Request{ 205 Type: RequestMsgType, 206 ID: thid, 207 Label: "Bob", 208 Thread: &decorator.Thread{ 209 PID: invitation.ID, 210 }, 211 DID: doc.DIDDocument.ID, 212 DocAttach: unsignedDocAttach(t, doc.DIDDocument), 213 }) 214 require.NoError(t, err) 215 msg, err := service.ParseDIDCommMsgMap(payloadBytes) 216 require.NoError(t, err) 217 _, err = s.HandleInbound(msg, service.NewDIDCommContext(doc.DIDDocument.ID, "", nil)) 218 require.NoError(t, err) 219 220 select { 221 case <-respondedFlag: 222 case <-time.After(2 * time.Second): 223 require.Fail(t, "didn't receive post event responded") 224 } 225 // Alice automatically sends exchange Response to Bob 226 // Bob replies with an ACK 227 payloadBytes, err = json.Marshal( 228 &model.Ack{ 229 Type: AckMsgType, 230 ID: randomString(), 231 Status: "OK", 232 Thread: &decorator.Thread{ID: thid}, 233 }) 234 require.NoError(t, err) 235 236 didMsg, err := service.ParseDIDCommMsgMap(payloadBytes) 237 require.NoError(t, err) 238 239 _, err = s.HandleInbound(didMsg, service.NewDIDCommContext(doc.DIDDocument.ID, "", nil)) 240 require.NoError(t, err) 241 242 select { 243 case <-completedFlag: 244 case <-time.After(2 * time.Second): 245 require.Fail(t, "didn't receive post event complete") 246 } 247 248 validateState(t, s, thid, findNamespace(AckMsgType), (&completed{}).Name()) 249 } 250 251 func msgEventListener(t *testing.T, statusCh chan service.StateMsg, respondedFlag, completedFlag chan struct{}) { 252 for e := range statusCh { 253 require.Equal(t, DIDExchange, e.ProtocolName) 254 255 prop, ok := e.Properties.(event) 256 if !ok { 257 require.Fail(t, "Failed to cast the event properties to service.Event") 258 } 259 // Get the connectionID when it's created 260 if e.Type == service.PreState { 261 if e.StateID == "requested" { 262 require.NotNil(t, prop.ConnectionID()) 263 require.NotNil(t, prop.InvitationID()) 264 } 265 } 266 267 if e.Type == service.PostState { 268 // receive the events 269 if e.StateID == "completed" { 270 // validate connectionID received during state transition with original connectionID 271 require.NotNil(t, prop.ConnectionID()) 272 require.NotNil(t, prop.InvitationID()) 273 close(completedFlag) 274 } 275 276 if e.StateID == "responded" { 277 // validate connectionID received during state transition with original connectionID 278 require.NotNil(t, prop.ConnectionID()) 279 require.NotNil(t, prop.InvitationID()) 280 close(respondedFlag) 281 } 282 } 283 } 284 } 285 286 type kmsProvider struct { 287 store kms.Store 288 secretLockService secretlock.Service 289 } 290 291 func (k *kmsProvider) StorageProvider() kms.Store { 292 return k.store 293 } 294 295 func (k *kmsProvider) SecretLock() secretlock.Service { 296 return k.secretLockService 297 } 298 299 func newKMS(t *testing.T, store storage.Provider) kms.KeyManager { 300 t.Helper() 301 302 kmsStore, err := kms.NewAriesProviderWrapper(store) 303 require.NoError(t, err) 304 305 kmsProv := &kmsProvider{ 306 store: kmsStore, 307 secretLockService: &noop.NoLock{}, 308 } 309 310 customKMS, err := localkms.New("local-lock://primary/test/", kmsProv) 311 require.NoError(t, err) 312 313 return customKMS 314 } 315 316 func newSigningAndEncryptionDIDKeys(t *testing.T, ctx *context) (string, string) { 317 t.Helper() 318 319 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(ctx.keyType) 320 require.NoError(t, err) 321 322 didKey, err := kmsdidkey.BuildDIDKeyByKeyType(pubKey, ctx.keyType) 323 require.NoError(t, err) 324 325 _, encPubKey, err := ctx.kms.CreateAndExportPubKeyBytes(ctx.keyAgreementType) 326 require.NoError(t, err) 327 328 encDIDKey, err := kmsdidkey.BuildDIDKeyByKeyType(encPubKey, ctx.keyAgreementType) 329 require.NoError(t, err) 330 331 return didKey, encDIDKey 332 } 333 334 // did-exchange flow with role Invitee. 335 func TestService_Handle_Invitee(t *testing.T) { 336 protocolStateStore := mockstorage.NewMockStoreProvider() 337 store := mockstorage.NewMockStoreProvider() 338 k := newKMS(t, store) 339 prov := &protocol.MockProvider{ 340 StoreProvider: store, 341 ProtocolStateStoreProvider: protocolStateStore, 342 ServiceMap: map[string]interface{}{ 343 mediator.Coordination: &mockroute.MockMediatorSvc{}, 344 }, 345 CustomKMS: k, 346 KeyTypeValue: kms.ED25519Type, 347 KeyAgreementTypeValue: kms.X25519ECDHKWType, 348 } 349 350 mtp := transport.MediaTypeRFC0019EncryptedEnvelope 351 352 ctx := &context{ 353 outboundDispatcher: prov.OutboundDispatcher(), 354 crypto: &tinkcrypto.Crypto{}, 355 kms: k, 356 keyType: kms.ED25519Type, 357 keyAgreementType: kms.X25519ECDHKWType, 358 mediaTypeProfiles: []string{mtp}, 359 } 360 361 verPubKey, encPubKey := newSigningAndEncryptionDIDKeys(t, ctx) 362 363 ctx.vdRegistry = &mockvdr.MockVDRegistry{CreateValue: createDIDDocWithKey(verPubKey, encPubKey, mtp)} 364 365 connRec, err := connection.NewRecorder(prov) 366 require.NoError(t, err) 367 require.NotNil(t, connRec) 368 369 ctx.connectionRecorder = connRec 370 371 doc, err := ctx.vdRegistry.Create(testMethod, nil) 372 require.NoError(t, err) 373 374 s, err := New(prov) 375 require.NoError(t, err) 376 377 s.ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: doc.DIDDocument} 378 actionCh := make(chan service.DIDCommAction, 10) 379 err = s.RegisterActionEvent(actionCh) 380 require.NoError(t, err) 381 382 statusCh := make(chan service.StateMsg, 10) 383 err = s.RegisterMsgEvent(statusCh) 384 require.NoError(t, err) 385 386 requestedCh := make(chan string) 387 completedCh := make(chan struct{}) 388 389 go handleMessagesInvitee(statusCh, requestedCh, completedCh) 390 391 go func() { service.AutoExecuteActionEvent(actionCh) }() 392 393 invitation := &Invitation{ 394 Type: InvitationMsgType, 395 ID: randomString(), 396 Label: "Bob", 397 RecipientKeys: []string{verPubKey}, 398 ServiceEndpoint: "http://alice.agent.example.com:8081", 399 } 400 401 err = ctx.connectionRecorder.SaveInvitation(invitation.ID, invitation) 402 require.NoError(t, err) 403 // Alice receives an invitation from Bob 404 payloadBytes, err := json.Marshal(invitation) 405 require.NoError(t, err) 406 407 didMsg, err := service.ParseDIDCommMsgMap(payloadBytes) 408 require.NoError(t, err) 409 410 _, err = s.HandleInbound(didMsg, service.EmptyDIDCommContext()) 411 require.NoError(t, err) 412 413 var connID string 414 select { 415 case connID = <-requestedCh: 416 case <-time.After(2 * time.Second): 417 require.Fail(t, "didn't receive post event requested") 418 } 419 420 // Alice automatically sends a Request to Bob and is now in REQUESTED state. 421 connRecord, err := s.connectionRecorder.GetConnectionRecord(connID) 422 require.NoError(t, err) 423 require.Equal(t, (&requested{}).Name(), connRecord.State) 424 require.Equal(t, invitation.ID, connRecord.InvitationID) 425 require.Equal(t, invitation.RecipientKeys, connRecord.RecipientKeys) 426 uri, err := connRecord.ServiceEndPoint.URI() 427 require.NoError(t, err) 428 require.Equal(t, invitation.ServiceEndpoint, uri) 429 430 didKey, err := ctx.getVerKey(invitation.ID) 431 require.NoError(t, err) 432 433 docAttach, err := ctx.didDocAttachment(doc.DIDDocument, didKey) 434 require.NoError(t, err) 435 436 // Bob replies with a Response 437 payloadBytes, err = json.Marshal( 438 &Response{ 439 Type: ResponseMsgType, 440 ID: randomString(), 441 DID: doc.DIDDocument.ID, 442 DocAttach: docAttach, 443 Thread: &decorator.Thread{ 444 ID: connRecord.ThreadID, 445 }, 446 }, 447 ) 448 require.NoError(t, err) 449 450 didMsg, err = service.ParseDIDCommMsgMap(payloadBytes) 451 require.NoError(t, err) 452 453 _, err = s.HandleInbound(didMsg, service.EmptyDIDCommContext()) 454 require.NoError(t, err) 455 456 // Alice automatically sends an ACK to Bob 457 // Alice must now be in COMPLETED state 458 select { 459 case <-completedCh: 460 case <-time.After(2 * time.Second): 461 require.Fail(t, "didn't receive post event complete") 462 } 463 464 validateState(t, s, connRecord.ThreadID, findNamespace(ResponseMsgType), (&completed{}).Name()) 465 } 466 467 func handleMessagesInvitee(statusCh chan service.StateMsg, requestedCh chan string, completedCh chan struct{}) { 468 for e := range statusCh { 469 if e.Type == service.PostState { 470 // receive the events 471 if e.StateID == StateIDCompleted { 472 close(completedCh) 473 } else if e.StateID == StateIDRequested { 474 prop, ok := e.Properties.(event) 475 if !ok { 476 panic("Failed to cast the event properties to service.Event") 477 } 478 479 requestedCh <- prop.ConnectionID() 480 } 481 } 482 } 483 } 484 485 func TestService_Handle_EdgeCases(t *testing.T) { 486 t.Run("handleInbound - must not transition to same state", func(t *testing.T) { 487 s, err := New(&protocol.MockProvider{ 488 ServiceMap: map[string]interface{}{ 489 mediator.Coordination: &mockroute.MockMediatorSvc{}, 490 }, 491 }) 492 require.NoError(t, err) 493 494 err = s.RegisterActionEvent(make(chan service.DIDCommAction)) 495 require.NoError(t, err) 496 497 response, err := json.Marshal( 498 &Response{ 499 Type: ResponseMsgType, 500 ID: randomString(), 501 Thread: &decorator.Thread{ID: randomString()}, 502 }, 503 ) 504 require.NoError(t, err) 505 506 didMsg, err := service.ParseDIDCommMsgMap(response) 507 require.NoError(t, err) 508 509 _, err = s.HandleInbound(didMsg, service.EmptyDIDCommContext()) 510 require.Error(t, err) 511 require.Contains(t, err.Error(), "handle inbound - next state : invalid state transition: "+ 512 "null -> responded") 513 }) 514 515 t.Run("handleInbound - connection record error", func(t *testing.T) { 516 protocolStateStore := &mockstorage.MockStore{ 517 Store: make(map[string]mockstorage.DBEntry), 518 ErrPut: errors.New("db error"), 519 } 520 prov := &protocol.MockProvider{ 521 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider(protocolStateStore), 522 ServiceMap: map[string]interface{}{ 523 mediator.Coordination: &mockroute.MockMediatorSvc{}, 524 }, 525 } 526 svc, err := New(prov) 527 require.NoError(t, err) 528 529 err = svc.RegisterActionEvent(make(chan service.DIDCommAction)) 530 require.NoError(t, err) 531 532 svc.connectionRecorder, err = connection.NewRecorder(prov) 533 require.NotNil(t, svc.connectionRecorder) 534 require.NoError(t, err) 535 536 _, err = svc.HandleInbound( 537 generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), randomString()), 538 service.EmptyDIDCommContext()) 539 require.Error(t, err) 540 require.Contains(t, err.Error(), "save connection record") 541 }) 542 543 t.Run("handleInbound - no error", func(t *testing.T) { 544 svc, err := New(&protocol.MockProvider{ 545 ServiceMap: map[string]interface{}{ 546 mediator.Coordination: &mockroute.MockMediatorSvc{}, 547 }, 548 }) 549 require.NoError(t, err) 550 551 err = svc.RegisterActionEvent(make(chan service.DIDCommAction)) 552 require.NoError(t, err) 553 554 protocolStateStore := &mockStore{ 555 get: func(s string) (bytes []byte, e error) { 556 return nil, storage.ErrDataNotFound 557 }, 558 put: func(s string, bytes []byte, tags ...storage.Tag) error { 559 if strings.Contains(s, "didex-event-") { 560 return errors.New("db error") 561 } 562 563 return nil 564 }, 565 } 566 567 svc.connectionRecorder, err = connection.NewRecorder(&protocol.MockProvider{ 568 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider(protocolStateStore), 569 }) 570 require.NotNil(t, svc.connectionRecorder) 571 require.NoError(t, err) 572 573 requestBytes, err := json.Marshal(&Request{ 574 Type: RequestMsgType, 575 ID: generateRandomID(), 576 Connection: &Connection{ 577 DID: "xyz", 578 }, 579 Thread: &decorator.Thread{ 580 PID: randomString(), 581 }, 582 }) 583 require.NoError(t, err) 584 585 // send invite 586 didMsg, err := service.ParseDIDCommMsgMap(requestBytes) 587 require.NoError(t, err) 588 589 _, err = svc.HandleInbound(didMsg, service.EmptyDIDCommContext()) 590 require.NoError(t, err) 591 }) 592 } 593 594 func TestService_Accept(t *testing.T) { 595 s := &Service{} 596 597 require.Equal(t, true, s.Accept("https://didcomm.org/didexchange/1.0/invitation")) 598 require.Equal(t, true, s.Accept("https://didcomm.org/didexchange/1.0/request")) 599 require.Equal(t, true, s.Accept("https://didcomm.org/didexchange/1.0/response")) 600 require.Equal(t, true, s.Accept("https://didcomm.org/didexchange/1.0/ack")) 601 require.Equal(t, true, s.Accept("https://didcomm.org/didexchange/1.0/complete")) 602 require.Equal(t, false, s.Accept("unsupported msg type")) 603 } 604 605 func TestService_CurrentState(t *testing.T) { 606 t.Run("null state if not found in store", func(t *testing.T) { 607 connRec, err := connection.NewRecorder(&protocol.MockProvider{ 608 StoreProvider: mockstorage.NewCustomMockStoreProvider(&mockStore{ 609 get: func(string) ([]byte, error) { return nil, storage.ErrDataNotFound }, 610 }), 611 }) 612 require.NotNil(t, connRec) 613 require.NoError(t, err) 614 615 svc := &Service{ 616 connectionRecorder: connRec, 617 } 618 thid, err := connection.CreateNamespaceKey(theirNSPrefix, "ignored") 619 require.NoError(t, err) 620 s, err := svc.currentState(thid) 621 require.NoError(t, err) 622 require.Equal(t, (&null{}).Name(), s.Name()) 623 }) 624 625 t.Run("returns state from store", func(t *testing.T) { 626 expected := &requested{} 627 connRecord, err := json.Marshal(&connection.Record{State: expected.Name()}) 628 require.NoError(t, err) 629 630 connRec, err := connection.NewRecorder(&protocol.MockProvider{ 631 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider(&mockStore{ 632 get: func(string) ([]byte, error) { return connRecord, nil }, 633 }), 634 }) 635 require.NotNil(t, connRec) 636 require.NoError(t, err) 637 638 svc := &Service{ 639 connectionRecorder: connRec, 640 } 641 thid, err := connection.CreateNamespaceKey(theirNSPrefix, "ignored") 642 require.NoError(t, err) 643 actual, err := svc.currentState(thid) 644 require.NoError(t, err) 645 require.Equal(t, expected.Name(), actual.Name()) 646 }) 647 648 t.Run("forwards generic error from store", func(t *testing.T) { 649 connRec, err := connection.NewRecorder(&protocol.MockProvider{ 650 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider(&mockStore{ 651 get: func(string) ([]byte, error) { 652 return nil, errors.New("test") 653 }, 654 }), 655 }) 656 require.NotNil(t, connRec) 657 require.NoError(t, err) 658 659 svc := &Service{connectionRecorder: connRec} 660 thid, err := connection.CreateNamespaceKey(theirNSPrefix, "ignored") 661 require.NoError(t, err) 662 _, err = svc.currentState(thid) 663 require.Error(t, err) 664 require.Contains(t, err.Error(), "cannot fetch state from store") 665 }) 666 } 667 668 func TestService_Update(t *testing.T) { 669 s := &requested{} 670 data := make(map[string][]byte) 671 connRecord := &connection.Record{ 672 ThreadID: "123", ConnectionID: "123456", State: s.Name(), 673 Namespace: findNamespace(RequestMsgType), 674 } 675 bytes, err := json.Marshal(connRecord) 676 require.NoError(t, err) 677 678 connRec, err := connection.NewRecorder(&protocol.MockProvider{ 679 StoreProvider: mockstorage.NewCustomMockStoreProvider(&mockStore{ 680 put: func(k string, v []byte, tags ...storage.Tag) error { 681 data[k] = bytes 682 return nil 683 }, 684 get: func(k string) ([]byte, error) { 685 return bytes, nil 686 }, 687 }), 688 }) 689 require.NotNil(t, connRec) 690 require.NoError(t, err) 691 692 svc := &Service{connectionRecorder: connRec} 693 694 require.NoError(t, svc.update(RequestMsgType, connRecord)) 695 696 cr := &connection.Record{} 697 err = json.Unmarshal(bytes, cr) 698 require.NoError(t, err) 699 require.Equal(t, cr, connRecord) 700 } 701 702 func TestCreateConnection(t *testing.T) { 703 store := mockstorage.NewMockStoreProvider() 704 k := newKMS(t, store) 705 706 t.Run("create connection", func(t *testing.T) { 707 theirDID := newPeerDID(t, k) 708 record := &connection.Record{ 709 ConnectionID: uuid.New().String(), 710 State: StateIDCompleted, 711 ThreadID: uuid.New().String(), 712 ParentThreadID: uuid.New().String(), 713 TheirLabel: uuid.New().String(), 714 TheirDID: theirDID.ID, 715 MyDID: newPeerDID(t, k).ID, 716 ServiceEndPoint: commonmodel.NewDIDCommV1Endpoint("http://example.com"), 717 RecipientKeys: []string{"testkeys"}, 718 InvitationID: uuid.New().String(), 719 Namespace: myNSPrefix, 720 } 721 storedInVDR := false 722 storageProvider := &mockprovider.Provider{ 723 StorageProviderValue: mockstorage.NewMockStoreProvider(), 724 ProtocolStateStorageProviderValue: mockstorage.NewMockStoreProvider(), 725 } 726 provider := &mockprovider.Provider{ 727 KMSValue: &mockkms.KeyManager{}, 728 StorageProviderValue: storageProvider.StorageProvider(), 729 ProtocolStateStorageProviderValue: storageProvider.ProtocolStateStorageProvider(), 730 VDRegistryValue: &mockvdr.MockVDRegistry{ 731 CreateFunc: func(method string, result *did.Doc, _ ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 732 storedInVDR = true 733 require.Equal(t, theirDID, result) 734 735 return nil, nil 736 }, 737 }, 738 ServiceMap: map[string]interface{}{ 739 mediator.Coordination: &mockroute.MockMediatorSvc{}, 740 }, 741 DIDConnectionStoreValue: &mockConnectionStore{}, 742 } 743 s, err := New(provider) 744 require.NoError(t, err) 745 746 err = s.CreateConnection(record, theirDID) 747 require.True(t, storedInVDR) 748 require.NoError(t, err) 749 750 connRec, err := connection.NewRecorder(provider) 751 require.NoError(t, err) 752 result, err := connRec.GetConnectionRecord(record.ConnectionID) 753 require.NoError(t, err) 754 require.Equal(t, record, result) 755 }) 756 757 t.Run("wraps vdr registry error", func(t *testing.T) { 758 expected := errors.New("test") 759 s, err := New(&mockprovider.Provider{ 760 KMSValue: &mockkms.KeyManager{}, 761 StorageProviderValue: mockstorage.NewMockStoreProvider(), 762 ProtocolStateStorageProviderValue: mockstorage.NewMockStoreProvider(), 763 VDRegistryValue: &mockvdr.MockVDRegistry{ 764 CreateFunc: func(s string, doc *did.Doc, option ...vdrapi.DIDMethodOption) (*did.DocResolution, error) { 765 return nil, expected 766 }, 767 }, 768 ServiceMap: map[string]interface{}{ 769 mediator.Coordination: &mockroute.MockMediatorSvc{}, 770 }, 771 }) 772 require.NoError(t, err) 773 774 err = s.CreateConnection(&connection.Record{}, newPeerDID(t, k)) 775 require.Error(t, err) 776 require.True(t, errors.Is(err, expected)) 777 }) 778 779 t.Run("wraps connection store error", func(t *testing.T) { 780 expected := errors.New("test") 781 s, err := New(&mockprovider.Provider{ 782 KMSValue: &mockkms.KeyManager{}, 783 StorageProviderValue: &mockstorage.MockStoreProvider{ 784 Store: &mockstorage.MockStore{ErrPut: expected}, 785 }, 786 ProtocolStateStorageProviderValue: mockstorage.NewMockStoreProvider(), 787 VDRegistryValue: &mockvdr.MockVDRegistry{}, 788 ServiceMap: map[string]interface{}{ 789 mediator.Coordination: &mockroute.MockMediatorSvc{}, 790 }, 791 DIDConnectionStoreValue: &mockConnectionStore{}, 792 }) 793 require.NoError(t, err) 794 795 err = s.CreateConnection(&connection.Record{ 796 State: StateIDCompleted, 797 }, newPeerDID(t, k)) 798 require.Error(t, err) 799 require.True(t, errors.Is(err, expected)) 800 }) 801 802 t.Run("wraps did.ConnectionStore.SaveDIDFromDoc error", func(t *testing.T) { 803 expected := errors.New("test") 804 s, err := New(&mockprovider.Provider{ 805 KMSValue: &mockkms.KeyManager{}, 806 KeyTypeValue: kms.ECDSAP384TypeIEEEP1363, 807 KeyAgreementTypeValue: kms.X25519ECDHKWType, 808 StorageProviderValue: mockstorage.NewMockStoreProvider(), 809 ProtocolStateStorageProviderValue: mockstorage.NewMockStoreProvider(), 810 VDRegistryValue: &mockvdr.MockVDRegistry{}, 811 ServiceMap: map[string]interface{}{ 812 mediator.Coordination: &mockroute.MockMediatorSvc{}, 813 }, 814 DIDConnectionStoreValue: &mockConnectionStore{ 815 saveDIDFromDocErr: expected, 816 }, 817 }) 818 require.NoError(t, err) 819 820 err = s.CreateConnection(&connection.Record{ 821 State: StateIDCompleted, 822 }, newPeerDID(t, k)) 823 require.Error(t, err) 824 require.True(t, errors.Is(err, expected)) 825 }) 826 827 t.Run("wraps did.ConnectionStore.SaveDIDByResolving error", func(t *testing.T) { 828 expected := errors.New("test") 829 s, err := New(&mockprovider.Provider{ 830 KMSValue: &mockkms.KeyManager{}, 831 KeyTypeValue: kms.ED25519Type, 832 KeyAgreementTypeValue: kms.X25519ECDHKWType, 833 StorageProviderValue: mockstorage.NewMockStoreProvider(), 834 ProtocolStateStorageProviderValue: mockstorage.NewMockStoreProvider(), 835 VDRegistryValue: &mockvdr.MockVDRegistry{}, 836 ServiceMap: map[string]interface{}{ 837 mediator.Coordination: &mockroute.MockMediatorSvc{}, 838 }, 839 DIDConnectionStoreValue: &mockConnectionStore{ 840 saveDIDByResolvingErr: expected, 841 }, 842 }) 843 require.NoError(t, err) 844 845 err = s.CreateConnection(&connection.Record{ 846 State: StateIDCompleted, 847 }, newPeerDID(t, k)) 848 require.Error(t, err) 849 require.True(t, errors.Is(err, expected)) 850 }) 851 } 852 853 type mockStore struct { 854 put func(string, []byte, ...storage.Tag) error 855 get func(string) ([]byte, error) 856 delete func(string) error 857 } 858 859 // Put stores the key and the record. 860 func (m *mockStore) Put(k string, v []byte, tags ...storage.Tag) error { 861 return m.put(k, v, tags...) 862 } 863 864 // Get fetches the record based on key. 865 func (m *mockStore) Get(k string) ([]byte, error) { 866 return m.get(k) 867 } 868 869 func (m *mockStore) GetTags(key string) ([]storage.Tag, error) { 870 panic("implement me") 871 } 872 873 func (m *mockStore) GetBulk(keys ...string) ([][]byte, error) { 874 panic("implement me") 875 } 876 877 func (m *mockStore) Query(expression string, options ...storage.QueryOption) (storage.Iterator, error) { 878 panic("implement me") 879 } 880 881 // Delete the record based on key. 882 func (m *mockStore) Delete(k string) error { 883 return m.delete(k) 884 } 885 886 func (m *mockStore) Batch(operations []storage.Operation) error { 887 panic("implement me") 888 } 889 890 func (m *mockStore) Flush() error { 891 panic("implement me") 892 } 893 894 func (m *mockStore) Close() error { 895 panic("implement me") 896 } 897 898 func randomString() string { 899 u := uuid.New() 900 return u.String() 901 } 902 903 func TestEventsSuccess(t *testing.T) { 904 sp := mockstorage.NewMockStoreProvider() 905 k := newKMS(t, sp) 906 ctx := &context{ 907 kms: k, 908 keyType: kms.ED25519Type, 909 keyAgreementType: kms.X25519ECDHKWType, 910 } 911 912 svc, err := New(&protocol.MockProvider{ 913 ServiceMap: map[string]interface{}{ 914 mediator.Coordination: &mockroute.MockMediatorSvc{}, 915 }, 916 CustomKMS: k, 917 KeyTypeValue: ctx.keyType, 918 KeyAgreementTypeValue: ctx.keyAgreementType, 919 }) 920 require.NoError(t, err) 921 922 actionCh := make(chan service.DIDCommAction, 10) 923 err = svc.RegisterActionEvent(actionCh) 924 require.NoError(t, err) 925 926 go func() { service.AutoExecuteActionEvent(actionCh) }() 927 928 statusCh := make(chan service.StateMsg, 10) 929 err = svc.RegisterMsgEvent(statusCh) 930 require.NoError(t, err) 931 932 done := make(chan struct{}) 933 934 go func() { 935 for e := range statusCh { 936 if e.Type == service.PostState && e.StateID == StateIDRequested { 937 done <- struct{}{} 938 } 939 } 940 }() 941 942 pubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 943 id := randomString() 944 invite, err := json.Marshal( 945 &Invitation{ 946 Type: InvitationMsgType, 947 ID: id, 948 Label: "test", 949 RecipientKeys: []string{pubKey}, 950 }, 951 ) 952 require.NoError(t, err) 953 954 // send invite 955 didMsg, err := service.ParseDIDCommMsgMap(invite) 956 require.NoError(t, err) 957 958 _, err = svc.HandleInbound(didMsg, service.EmptyDIDCommContext()) 959 require.NoError(t, err) 960 961 select { 962 case <-done: 963 case <-time.After(5 * time.Second): 964 require.Fail(t, "tests are not validated") 965 } 966 } 967 968 func TestContinueWithPublicDID(t *testing.T) { 969 sp := mockstorage.NewMockStoreProvider() 970 k := newKMS(t, sp) 971 ctx := &context{ 972 kms: k, 973 keyType: kms.ED25519Type, 974 keyAgreementType: kms.X25519ECDHKWType, 975 } 976 didDoc := mockdiddoc.GetMockDIDDoc(t, false) 977 svc, err := New(&protocol.MockProvider{ 978 ServiceMap: map[string]interface{}{ 979 mediator.Coordination: &mockroute.MockMediatorSvc{}, 980 }, 981 KeyTypeValue: ctx.keyType, 982 KeyAgreementTypeValue: ctx.keyAgreementType, 983 }) 984 require.NoError(t, err) 985 986 actionCh := make(chan service.DIDCommAction, 10) 987 err = svc.RegisterActionEvent(actionCh) 988 require.NoError(t, err) 989 990 go func() { continueWithPublicDID(actionCh, didDoc.ID) }() 991 992 pubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 993 id := randomString() 994 invite, err := json.Marshal( 995 &Invitation{ 996 Type: InvitationMsgType, 997 ID: id, 998 Label: "test", 999 RecipientKeys: []string{pubKey}, 1000 }, 1001 ) 1002 require.NoError(t, err) 1003 1004 // send invite 1005 didMsg, err := service.ParseDIDCommMsgMap(invite) 1006 require.NoError(t, err) 1007 1008 _, err = svc.HandleInbound(didMsg, service.EmptyDIDCommContext()) 1009 require.NoError(t, err) 1010 } 1011 1012 func continueWithPublicDID(ch chan service.DIDCommAction, pubDID string) { 1013 for msg := range ch { 1014 msg.Continue(&testOptions{publicDID: pubDID}) 1015 } 1016 } 1017 1018 type testOptions struct { 1019 publicDID string 1020 label string 1021 routerConnections []string 1022 } 1023 1024 func (to *testOptions) PublicDID() string { 1025 return to.publicDID 1026 } 1027 1028 func (to *testOptions) Label() string { 1029 return to.label 1030 } 1031 1032 func (to *testOptions) RouterConnections() []string { 1033 return to.routerConnections 1034 } 1035 1036 func TestEventsUserError(t *testing.T) { 1037 svc, err := New(&protocol.MockProvider{ 1038 ServiceMap: map[string]interface{}{ 1039 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1040 }, 1041 }) 1042 require.NoError(t, err) 1043 1044 actionCh := make(chan service.DIDCommAction, 10) 1045 err = svc.RegisterActionEvent(actionCh) 1046 require.NoError(t, err) 1047 1048 statusCh := make(chan service.StateMsg, 10) 1049 err = svc.RegisterMsgEvent(statusCh) 1050 require.NoError(t, err) 1051 1052 done := make(chan struct{}) 1053 1054 go func() { 1055 for { 1056 select { 1057 case e := <-actionCh: 1058 e.Stop(errors.New("invalid id")) 1059 case e := <-statusCh: 1060 if e.Type == service.PostState && e.StateID == StateIDAbandoned { 1061 done <- struct{}{} 1062 } 1063 } 1064 } 1065 }() 1066 1067 id := randomString() 1068 connRec := &connection.Record{ 1069 ConnectionID: randomString(), ThreadID: id, 1070 Namespace: findNamespace(RequestMsgType), State: (&null{}).Name(), 1071 } 1072 1073 err = svc.connectionRecorder.SaveConnectionRecordWithMappings(connRec) 1074 require.NoError(t, err) 1075 1076 _, err = svc.HandleInbound( 1077 generateRequestMsgPayload(t, &protocol.MockProvider{}, id, randomString()), 1078 service.EmptyDIDCommContext()) 1079 require.NoError(t, err) 1080 1081 select { 1082 case <-done: 1083 case <-time.After(5 * time.Second): 1084 require.Fail(t, "tests are not validated") 1085 } 1086 } 1087 1088 func TestEventStoreError(t *testing.T) { 1089 svc, err := New(&protocol.MockProvider{ 1090 ServiceMap: map[string]interface{}{ 1091 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1092 }, 1093 }) 1094 require.NoError(t, err) 1095 1096 actionCh := make(chan service.DIDCommAction, 10) 1097 err = svc.RegisterActionEvent(actionCh) 1098 require.NoError(t, err) 1099 1100 go func() { 1101 for e := range actionCh { 1102 e.Continue = func(args interface{}) { 1103 svc.processCallback(&message{Msg: service.NewDIDCommMsgMap(struct{}{})}) 1104 } 1105 e.Continue(&service.Empty{}) 1106 } 1107 }() 1108 1109 _, err = svc.HandleInbound( 1110 generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), randomString()), 1111 service.EmptyDIDCommContext()) 1112 require.NoError(t, err) 1113 } 1114 1115 func TestEventProcessCallback(t *testing.T) { 1116 svc, err := New(&protocol.MockProvider{ 1117 ServiceMap: map[string]interface{}{ 1118 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1119 }, 1120 }) 1121 require.NoError(t, err) 1122 1123 msg := &message{ 1124 ThreadID: threadIDValue, 1125 Msg: service.NewDIDCommMsgMap(model.Ack{Type: AckMsgType}), 1126 } 1127 1128 err = svc.handleWithoutAction(msg) 1129 require.Error(t, err) 1130 require.Contains(t, err.Error(), "invalid state name: invalid state name ") 1131 1132 err = svc.abandon(msg.ThreadID, msg.Msg, nil) 1133 require.Error(t, err) 1134 require.Contains(t, err.Error(), "unable to update the state to abandoned") 1135 } 1136 1137 func validateState(t *testing.T, svc *Service, id, namespace, expected string) { 1138 nsThid, err := connection.CreateNamespaceKey(namespace, id) 1139 require.NoError(t, err) 1140 s, err := svc.currentState(nsThid) 1141 require.NoError(t, err) 1142 require.Equal(t, expected, s.Name()) 1143 } 1144 1145 func TestServiceErrors(t *testing.T) { 1146 requestBytes, err := json.Marshal( 1147 &Request{ 1148 Type: ResponseMsgType, 1149 ID: randomString(), 1150 Label: "test", 1151 }, 1152 ) 1153 require.NoError(t, err) 1154 1155 msg, err := service.ParseDIDCommMsgMap(requestBytes) 1156 require.NoError(t, err) 1157 1158 svc, err := New(&protocol.MockProvider{ 1159 ServiceMap: map[string]interface{}{ 1160 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1161 }, 1162 }) 1163 require.NoError(t, err) 1164 1165 actionCh := make(chan service.DIDCommAction, 10) 1166 err = svc.RegisterActionEvent(actionCh) 1167 require.NoError(t, err) 1168 1169 // fetch current state error 1170 mockStore := &mockStore{get: func(s string) (bytes []byte, e error) { 1171 return nil, errors.New("error") 1172 }} 1173 1174 prov := &protocol.MockProvider{ 1175 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider( 1176 mockStore, 1177 ), 1178 ServiceMap: map[string]interface{}{ 1179 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1180 }, 1181 } 1182 svc, err = New(prov) 1183 require.NoError(t, err) 1184 1185 payload := generateRequestMsgPayload(t, prov, randomString(), "") 1186 _, err = svc.HandleInbound(payload, service.EmptyDIDCommContext()) 1187 require.Error(t, err) 1188 require.Contains(t, err.Error(), "cannot fetch state from store") 1189 1190 svc, err = New(&protocol.MockProvider{ 1191 ServiceMap: map[string]interface{}{ 1192 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1193 }, 1194 }) 1195 require.NoError(t, err) 1196 1197 // invalid message type 1198 msg["@type"] = "invalid" 1199 svc.connectionRecorder, err = connection.NewRecorder(&protocol.MockProvider{}) 1200 require.NoError(t, err) 1201 1202 _, err = svc.HandleInbound(msg, service.EmptyDIDCommContext()) 1203 require.Error(t, err) 1204 require.Contains(t, err.Error(), "unrecognized msgType: invalid") 1205 1206 // test handle - invalid state name 1207 msg["@type"] = ResponseMsgType 1208 m := &message{Msg: msg, ThreadID: randomString()} 1209 err = svc.handleWithoutAction(m) 1210 require.Error(t, err) 1211 require.Contains(t, err.Error(), "invalid state name:") 1212 1213 // invalid state name 1214 m.NextStateName = StateIDInvited 1215 m.ConnRecord = &connection.Record{ConnectionID: "abc"} 1216 err = svc.handleWithoutAction(m) 1217 require.Error(t, err) 1218 require.Contains(t, err.Error(), "failed to execute state 'invited':") 1219 } 1220 1221 func TestHandleOutbound(t *testing.T) { 1222 svc, err := New(&protocol.MockProvider{ 1223 ServiceMap: map[string]interface{}{ 1224 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1225 }, 1226 }) 1227 require.NoError(t, err) 1228 1229 _, err = svc.HandleOutbound(service.DIDCommMsgMap{}, "", "") 1230 require.Error(t, err) 1231 require.Contains(t, err.Error(), "not implemented") 1232 } 1233 1234 func TestConnectionRecord(t *testing.T) { 1235 svc, err := New(&protocol.MockProvider{ 1236 ServiceMap: map[string]interface{}{ 1237 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1238 }, 1239 }) 1240 require.NoError(t, err) 1241 1242 conn, err := svc.connectionRecord(generateRequestMsgPayload(t, &protocol.MockProvider{}, 1243 randomString(), randomString())) 1244 require.NoError(t, err) 1245 require.NotNil(t, conn) 1246 1247 // invalid type 1248 requestBytes, err := json.Marshal(&Request{ 1249 Type: "invalid-type", 1250 }) 1251 require.NoError(t, err) 1252 msg, err := service.ParseDIDCommMsgMap(requestBytes) 1253 require.NoError(t, err) 1254 1255 _, err = svc.connectionRecord(msg) 1256 require.Error(t, err) 1257 require.Contains(t, err.Error(), "invalid message type") 1258 } 1259 1260 func TestInvitationRecord(t *testing.T) { 1261 sp := mockstorage.NewMockStoreProvider() 1262 k := newKMS(t, sp) 1263 ctx := &context{ 1264 kms: k, 1265 keyType: kms.ED25519Type, 1266 keyAgreementType: kms.X25519ECDHKWType, 1267 } 1268 svc, err := New(&protocol.MockProvider{ 1269 ServiceMap: map[string]interface{}{ 1270 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1271 }, 1272 KeyTypeValue: ctx.keyType, 1273 KeyAgreementTypeValue: ctx.keyAgreementType, 1274 }) 1275 require.NoError(t, err) 1276 1277 verPubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 1278 invitationBytes, err := json.Marshal(&Invitation{ 1279 Type: InvitationMsgType, 1280 ID: "id", 1281 RecipientKeys: []string{verPubKey}, 1282 }) 1283 require.NoError(t, err) 1284 1285 msg, err := service.ParseDIDCommMsgMap(invitationBytes) 1286 require.NoError(t, err) 1287 1288 conn, err := svc.invitationMsgRecord(msg) 1289 require.NoError(t, err) 1290 require.NotNil(t, conn) 1291 1292 // invalid thread id 1293 invitationBytes, err = json.Marshal(&Invitation{ 1294 Type: "invalid-type", 1295 }) 1296 require.NoError(t, err) 1297 msg, err = service.ParseDIDCommMsgMap(invitationBytes) 1298 require.NoError(t, err) 1299 1300 _, err = svc.invitationMsgRecord(msg) 1301 require.Error(t, err) 1302 require.Contains(t, err.Error(), "threadID not found") 1303 1304 // db error 1305 svc, err = New(&protocol.MockProvider{ 1306 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider(&mockstorage.MockStore{ 1307 Store: make(map[string]mockstorage.DBEntry), ErrPut: errors.New("db error"), 1308 }), 1309 ServiceMap: map[string]interface{}{ 1310 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1311 }, 1312 }) 1313 require.NotNil(t, svc.connectionRecorder) 1314 require.NoError(t, err) 1315 1316 invitationBytes, err = json.Marshal(&Invitation{ 1317 Type: InvitationMsgType, 1318 ID: "id", 1319 RecipientKeys: []string{verPubKey}, 1320 }) 1321 require.NoError(t, err) 1322 1323 msg, err = service.ParseDIDCommMsgMap(invitationBytes) 1324 require.NoError(t, err) 1325 1326 _, err = svc.invitationMsgRecord(msg) 1327 require.Error(t, err) 1328 require.Contains(t, err.Error(), "save connection record") 1329 } 1330 1331 func Test_getRequestConnection(t *testing.T) { 1332 store := mockstorage.NewMockStoreProvider() 1333 k := newKMS(t, store) 1334 1335 t.Run("success - did_doc~attach present", func(t *testing.T) { 1336 testDoc := newPeerDID(t, k) 1337 docBytes, err := testDoc.MarshalJSON() 1338 require.NoError(t, err) 1339 1340 attachment := decorator.Attachment{ 1341 Data: decorator.AttachmentData{ 1342 Base64: base64.StdEncoding.EncodeToString(docBytes), 1343 }, 1344 } 1345 1346 r := Request{DID: "test", DocAttach: &attachment} 1347 1348 conn, err := getRequestConnection(&r) 1349 require.NoError(t, err) 1350 require.Equal(t, "test", conn.DID) 1351 }) 1352 1353 t.Run("failure - no connection or did_doc~attach", func(t *testing.T) { 1354 _, err := getRequestConnection(&Request{DID: "test"}) 1355 require.Error(t, err) 1356 require.Contains(t, err.Error(), "missing did_doc~attach") 1357 }) 1358 1359 t.Run("failure - did_doc~attach not valid base64", func(t *testing.T) { 1360 _, err := getRequestConnection(&Request{DID: "test", DocAttach: &decorator.Attachment{ 1361 Data: decorator.AttachmentData{ 1362 Base64: "abc %$#@abc test test bad data ^", 1363 }, 1364 }}) 1365 require.Error(t, err) 1366 require.Contains(t, err.Error(), "failed to parse base64 attachment data") 1367 }) 1368 1369 t.Run("failure - did_doc~attach not valid did doc", func(t *testing.T) { 1370 _, err := getRequestConnection(&Request{DID: "test", DocAttach: &decorator.Attachment{ 1371 Data: decorator.AttachmentData{ 1372 Base64: base64.StdEncoding.EncodeToString([]byte("this is not a valid did doc")), 1373 }, 1374 }}) 1375 require.Error(t, err) 1376 require.Contains(t, err.Error(), "failed to parse did document") 1377 }) 1378 1379 t.Run("test pad", func(t *testing.T) { 1380 in := []string{ 1381 "abcdabcdabcdabcda", 1382 "abcdabcdabcdabcdab", 1383 "abcdabcdabcdabcdabc", 1384 "abcdabcdabcdabcdabcd", 1385 "abcdabcdabcdabcdabcda", 1386 "abcdabcdabcdabcdabcdab", 1387 } 1388 1389 out := []string{ 1390 "abcdabcdabcdabcda", 1391 "abcdabcdabcdabcdab==", 1392 "abcdabcdabcdabcdabc=", 1393 "abcdabcdabcdabcdabcd", 1394 "abcdabcdabcdabcdabcda", 1395 "abcdabcdabcdabcdabcdab==", 1396 } 1397 1398 for i, input := range in { 1399 require.Equal(t, out[i], pad(input)) 1400 } 1401 }) 1402 } 1403 1404 func TestRequestRecord(t *testing.T) { 1405 t.Run("returns connection record", func(t *testing.T) { 1406 svc, err := New(&protocol.MockProvider{ 1407 ServiceMap: map[string]interface{}{ 1408 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1409 }, 1410 }) 1411 require.NoError(t, err) 1412 1413 didcommMsg := generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), uuid.New().String()) 1414 require.NotEmpty(t, didcommMsg.ParentThreadID()) 1415 conn, err := svc.requestMsgRecord(didcommMsg) 1416 require.NoError(t, err) 1417 require.NotNil(t, conn) 1418 require.Equal(t, didcommMsg.ParentThreadID(), conn.InvitationID) 1419 }) 1420 1421 t.Run("returns connection record from request without connection", func(t *testing.T) { 1422 svc, err := New(&protocol.MockProvider{ 1423 ServiceMap: map[string]interface{}{ 1424 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1425 }, 1426 }) 1427 require.NoError(t, err) 1428 1429 didcommMsg := generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), uuid.New().String()) 1430 require.NotEmpty(t, didcommMsg.ParentThreadID()) 1431 delete(didcommMsg, "connection") 1432 didcommMsg["did"] = "did:test:abc" 1433 1434 conn, err := svc.requestMsgRecord(didcommMsg) 1435 require.NoError(t, err) 1436 require.NotNil(t, conn) 1437 require.Equal(t, didcommMsg.ParentThreadID(), conn.InvitationID) 1438 require.Equal(t, "did:test:abc", conn.TheirDID) 1439 }) 1440 1441 t.Run("fails on db error", func(t *testing.T) { 1442 svc, err := New(&protocol.MockProvider{ 1443 ProtocolStateStoreProvider: mockstorage.NewCustomMockStoreProvider( 1444 &mockstorage.MockStore{Store: make(map[string]mockstorage.DBEntry), ErrPut: errors.New("db error")}, 1445 ), 1446 ServiceMap: map[string]interface{}{ 1447 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1448 }, 1449 }) 1450 require.NotNil(t, svc.connectionRecorder) 1451 require.NoError(t, err) 1452 1453 _, err = svc.requestMsgRecord(generateRequestMsgPayload(t, &protocol.MockProvider{}, 1454 randomString(), uuid.New().String())) 1455 require.Error(t, err) 1456 require.Contains(t, err.Error(), "save connection record") 1457 }) 1458 1459 t.Run("fails if parent thread ID is missing", func(t *testing.T) { 1460 svc, err := New(&protocol.MockProvider{ 1461 ServiceMap: map[string]interface{}{ 1462 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1463 }, 1464 }) 1465 require.NoError(t, err) 1466 1467 parentThreadID := "" 1468 didcommMsg := generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), parentThreadID) 1469 require.Empty(t, didcommMsg.ParentThreadID()) 1470 _, err = svc.requestMsgRecord(didcommMsg) 1471 require.Error(t, err) 1472 }) 1473 } 1474 1475 func TestAcceptExchangeRequest(t *testing.T) { 1476 sp := mockstorage.NewMockStoreProvider() 1477 k := newKMS(t, sp) 1478 ctx := &context{ 1479 kms: k, 1480 keyType: kms.ED25519Type, 1481 keyAgreementType: kms.X25519ECDHKWType, 1482 } 1483 1484 svc, err := New(&protocol.MockProvider{ 1485 StoreProvider: sp, 1486 ServiceMap: map[string]interface{}{ 1487 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1488 }, 1489 CustomKMS: k, 1490 KeyTypeValue: ctx.keyType, 1491 KeyAgreementTypeValue: ctx.keyAgreementType, 1492 }) 1493 require.NoError(t, err) 1494 1495 actionCh := make(chan service.DIDCommAction, 10) 1496 err = svc.RegisterActionEvent(actionCh) 1497 require.NoError(t, err) 1498 1499 verPubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 1500 invitation := &Invitation{ 1501 Type: InvitationMsgType, 1502 ID: randomString(), 1503 Label: "Bob", 1504 RecipientKeys: []string{verPubKey}, 1505 ServiceEndpoint: "http://alice.agent.example.com:8081", 1506 } 1507 1508 err = svc.connectionRecorder.SaveInvitation(invitation.ID, invitation) 1509 require.NoError(t, err) 1510 1511 go func() { 1512 for e := range actionCh { 1513 prop, ok := e.Properties.(event) 1514 require.True(t, ok, "Failed to cast the event properties to service.Event") 1515 require.NoError(t, svc.AcceptExchangeRequest(prop.ConnectionID(), "", "", nil)) 1516 } 1517 }() 1518 1519 statusCh := make(chan service.StateMsg, 10) 1520 err = svc.RegisterMsgEvent(statusCh) 1521 require.NoError(t, err) 1522 1523 done := make(chan struct{}) 1524 1525 go func() { 1526 for e := range statusCh { 1527 if e.Type == service.PostState && e.StateID == StateIDResponded { 1528 done <- struct{}{} 1529 } 1530 } 1531 }() 1532 1533 _, err = svc.HandleInbound(generateRequestMsgPayload(t, &protocol.MockProvider{ 1534 StoreProvider: mockstorage.NewMockStoreProvider(), 1535 }, randomString(), invitation.ID), service.EmptyDIDCommContext()) 1536 require.NoError(t, err) 1537 1538 select { 1539 case <-done: 1540 case <-time.After(5 * time.Second): 1541 require.Fail(t, "tests are not validated") 1542 } 1543 } 1544 1545 func TestAcceptExchangeRequestWithPublicDID(t *testing.T) { 1546 sp := mockstorage.NewMockStoreProvider() 1547 k := newKMS(t, sp) 1548 ctx := &context{ 1549 kms: k, 1550 keyType: kms.ED25519Type, 1551 keyAgreementType: kms.X25519ECDHKWType, 1552 } 1553 svc, err := New(&protocol.MockProvider{ 1554 StoreProvider: sp, 1555 ServiceMap: map[string]interface{}{ 1556 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1557 }, 1558 KeyTypeValue: ctx.keyType, 1559 KeyAgreementTypeValue: ctx.keyAgreementType, 1560 }) 1561 require.NoError(t, err) 1562 1563 const publicDIDMethod = "sidetree" 1564 publicDID := fmt.Sprintf("did:%s:123456", publicDIDMethod) 1565 doc, err := svc.ctx.vdRegistry.Create(publicDIDMethod, nil) 1566 require.NoError(t, err) 1567 1568 svc.ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: doc.DIDDocument} 1569 1570 actionCh := make(chan service.DIDCommAction, 10) 1571 err = svc.RegisterActionEvent(actionCh) 1572 require.NoError(t, err) 1573 1574 verPubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 1575 invitation := &Invitation{ 1576 Type: InvitationMsgType, 1577 ID: randomString(), 1578 Label: "Bob", 1579 RecipientKeys: []string{verPubKey}, 1580 ServiceEndpoint: "http://alice.agent.example.com:8081", 1581 } 1582 1583 err = svc.connectionRecorder.SaveInvitation(invitation.ID, invitation) 1584 require.NoError(t, err) 1585 1586 go func() { 1587 for e := range actionCh { 1588 prop, ok := e.Properties.(event) 1589 require.True(t, ok, "Failed to cast the event properties to service.Event") 1590 require.NoError(t, svc.AcceptExchangeRequest(prop.ConnectionID(), publicDID, "sample-label", nil)) 1591 } 1592 }() 1593 1594 statusCh := make(chan service.StateMsg, 10) 1595 err = svc.RegisterMsgEvent(statusCh) 1596 require.NoError(t, err) 1597 1598 done := make(chan struct{}) 1599 1600 go func() { 1601 for e := range statusCh { 1602 if e.Type == service.PostState && e.StateID == StateIDResponded { 1603 done <- struct{}{} 1604 } 1605 } 1606 }() 1607 1608 _, err = svc.HandleInbound(generateRequestMsgPayload(t, &protocol.MockProvider{ 1609 StoreProvider: mockstorage.NewMockStoreProvider(), 1610 }, randomString(), invitation.ID), service.EmptyDIDCommContext()) 1611 require.NoError(t, err) 1612 1613 select { 1614 case <-done: 1615 case <-time.After(5 * time.Second): 1616 require.Fail(t, "tests are not validated") 1617 } 1618 } 1619 1620 func TestAcceptInvitation(t *testing.T) { 1621 t.Run("accept invitation - success", func(t *testing.T) { 1622 sp := mockstorage.NewMockStoreProvider() 1623 k := newKMS(t, sp) 1624 ctx := &context{ 1625 kms: k, 1626 keyType: kms.ED25519Type, 1627 keyAgreementType: kms.X25519ECDHKWType, 1628 } 1629 svc, err := New(&protocol.MockProvider{ 1630 StoreProvider: sp, 1631 ServiceMap: map[string]interface{}{ 1632 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1633 }, 1634 CustomKMS: k, 1635 KeyTypeValue: ctx.keyType, 1636 KeyAgreementTypeValue: ctx.keyAgreementType, 1637 }) 1638 require.NoError(t, err) 1639 1640 actionCh := make(chan service.DIDCommAction, 10) 1641 err = svc.RegisterActionEvent(actionCh) 1642 require.NoError(t, err) 1643 1644 go func() { 1645 for e := range actionCh { 1646 _, ok := e.Properties.(event) 1647 require.True(t, ok, "Failed to cast the event properties to service.Event") 1648 1649 // ignore action event 1650 } 1651 }() 1652 1653 statusCh := make(chan service.StateMsg, 10) 1654 err = svc.RegisterMsgEvent(statusCh) 1655 require.NoError(t, err) 1656 1657 done := make(chan struct{}) 1658 1659 go func() { 1660 for e := range statusCh { 1661 prop, ok := e.Properties.(event) 1662 if !ok { 1663 require.Fail(t, "Failed to cast the event properties to service.Event") 1664 } 1665 1666 if e.Type == service.PostState && e.StateID == StateIDInvited { 1667 require.NoError(t, svc.AcceptInvitation(prop.ConnectionID(), "", "", nil)) 1668 } 1669 1670 if e.Type == service.PostState && e.StateID == StateIDRequested { 1671 done <- struct{}{} 1672 } 1673 } 1674 }() 1675 verPubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 1676 invitationBytes, err := json.Marshal(&Invitation{ 1677 Type: InvitationMsgType, 1678 ID: generateRandomID(), 1679 RecipientKeys: []string{verPubKey}, 1680 }) 1681 require.NoError(t, err) 1682 1683 didMsg, err := service.ParseDIDCommMsgMap(invitationBytes) 1684 require.NoError(t, err) 1685 1686 _, err = svc.HandleInbound(didMsg, service.EmptyDIDCommContext()) 1687 require.NoError(t, err) 1688 1689 select { 1690 case <-done: 1691 case <-time.After(5 * time.Second): 1692 require.Fail(t, "tests are not validated") 1693 } 1694 }) 1695 1696 t.Run("accept invitation - error", func(t *testing.T) { 1697 svc, err := New(&protocol.MockProvider{ 1698 ServiceMap: map[string]interface{}{ 1699 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1700 }, 1701 }) 1702 require.NoError(t, err) 1703 1704 err = svc.AcceptInvitation(generateRandomID(), "", "", nil) 1705 require.Error(t, err) 1706 require.Contains(t, err.Error(), "accept exchange invitation : get protocol state data : data not found") 1707 }) 1708 1709 t.Run("accept invitation - state error", func(t *testing.T) { 1710 svc, err := New(&protocol.MockProvider{ 1711 ServiceMap: map[string]interface{}{ 1712 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1713 }, 1714 }) 1715 require.NoError(t, err) 1716 1717 id := generateRandomID() 1718 connRecord := &connection.Record{ 1719 ConnectionID: id, 1720 State: StateIDRequested, 1721 } 1722 err = svc.connectionRecorder.SaveConnectionRecord(connRecord) 1723 require.NoError(t, err) 1724 1725 err = svc.storeEventProtocolStateData(&message{ConnRecord: connRecord}) 1726 require.NoError(t, err) 1727 1728 err = svc.AcceptInvitation(id, "", "", nil) 1729 require.Error(t, err) 1730 require.Contains(t, err.Error(), "current state (requested) is different from expected state (invited)") 1731 }) 1732 1733 t.Run("accept invitation - no connection record error", func(t *testing.T) { 1734 svc, err := New(&protocol.MockProvider{ 1735 ServiceMap: map[string]interface{}{ 1736 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1737 }, 1738 }) 1739 require.NoError(t, err) 1740 1741 id := generateRandomID() 1742 connRecord := &connection.Record{ 1743 ConnectionID: id, 1744 State: StateIDRequested, 1745 } 1746 1747 err = svc.storeEventProtocolStateData(&message{ConnRecord: connRecord}) 1748 require.NoError(t, err) 1749 1750 err = svc.AcceptInvitation(id, "", "", nil) 1751 require.Error(t, err) 1752 require.Contains(t, err.Error(), "accept exchange invitation : data not found") 1753 }) 1754 } 1755 1756 func TestAcceptInvitationWithPublicDID(t *testing.T) { 1757 t.Run("accept invitation with public DID - success", func(t *testing.T) { 1758 sp := mockstorage.NewMockStoreProvider() 1759 k := newKMS(t, sp) 1760 ctx := &context{ 1761 kms: k, 1762 keyType: kms.ED25519Type, 1763 keyAgreementType: kms.X25519ECDHKWType, 1764 } 1765 svc, err := New(&protocol.MockProvider{ 1766 StoreProvider: sp, 1767 ServiceMap: map[string]interface{}{ 1768 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1769 }, 1770 KeyTypeValue: ctx.keyType, 1771 KeyAgreementTypeValue: ctx.keyAgreementType, 1772 }) 1773 require.NoError(t, err) 1774 1775 const publicDIDMethod = "sidetree" 1776 publicDID := fmt.Sprintf("did:%s:123456", publicDIDMethod) 1777 doc, err := svc.ctx.vdRegistry.Create(publicDIDMethod, nil) 1778 require.NoError(t, err) 1779 svc.ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: doc.DIDDocument} 1780 1781 actionCh := make(chan service.DIDCommAction, 10) 1782 err = svc.RegisterActionEvent(actionCh) 1783 require.NoError(t, err) 1784 1785 go func() { 1786 for e := range actionCh { 1787 _, ok := e.Properties.(event) 1788 require.True(t, ok, "Failed to cast the event properties to service.Event") 1789 1790 // ignore action event 1791 } 1792 }() 1793 1794 statusCh := make(chan service.StateMsg, 10) 1795 err = svc.RegisterMsgEvent(statusCh) 1796 require.NoError(t, err) 1797 1798 done := make(chan struct{}) 1799 1800 go func() { 1801 for e := range statusCh { 1802 prop, ok := e.Properties.(event) 1803 if !ok { 1804 require.Fail(t, "Failed to cast the event properties to service.Event") 1805 } 1806 1807 if e.Type == service.PostState && e.StateID == StateIDInvited { 1808 require.NoError(t, svc.AcceptInvitation(prop.ConnectionID(), publicDID, "sample-label", nil)) 1809 } 1810 1811 if e.Type == service.PostState && e.StateID == StateIDRequested { 1812 done <- struct{}{} 1813 } 1814 } 1815 }() 1816 1817 verPubKey, _ := newSigningAndEncryptionDIDKeys(t, ctx) 1818 invitationBytes, err := json.Marshal(&Invitation{ 1819 Type: InvitationMsgType, 1820 ID: generateRandomID(), 1821 RecipientKeys: []string{verPubKey}, 1822 }) 1823 require.NoError(t, err) 1824 1825 didMsg, err := service.ParseDIDCommMsgMap(invitationBytes) 1826 require.NoError(t, err) 1827 1828 _, err = svc.HandleInbound(didMsg, service.EmptyDIDCommContext()) 1829 require.NoError(t, err) 1830 1831 select { 1832 case <-done: 1833 case <-time.After(5 * time.Second): 1834 require.Fail(t, "tests are not validated") 1835 } 1836 }) 1837 1838 t.Run("accept invitation - error", func(t *testing.T) { 1839 svc, err := New(&protocol.MockProvider{ 1840 ServiceMap: map[string]interface{}{ 1841 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1842 }, 1843 }) 1844 require.NoError(t, err) 1845 1846 err = svc.AcceptInvitation(generateRandomID(), "sample-public-did", "sample-label", nil) 1847 require.Error(t, err) 1848 require.Contains(t, err.Error(), "accept exchange invitation : get protocol state data : data not found") 1849 }) 1850 1851 t.Run("accept invitation - state error", func(t *testing.T) { 1852 svc, err := New(&protocol.MockProvider{ 1853 ServiceMap: map[string]interface{}{ 1854 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1855 }, 1856 }) 1857 require.NoError(t, err) 1858 1859 id := generateRandomID() 1860 connRecord := &connection.Record{ 1861 ConnectionID: id, 1862 State: StateIDRequested, 1863 } 1864 err = svc.connectionRecorder.SaveConnectionRecord(connRecord) 1865 require.NoError(t, err) 1866 1867 err = svc.storeEventProtocolStateData(&message{ConnRecord: connRecord}) 1868 require.NoError(t, err) 1869 1870 err = svc.AcceptInvitation(id, "sample-public-did", "sample-label", nil) 1871 require.Error(t, err) 1872 require.Contains(t, err.Error(), "current state (requested) is different from expected state (invited)") 1873 }) 1874 1875 t.Run("accept invitation - no connection record error", func(t *testing.T) { 1876 svc, err := New(&protocol.MockProvider{ 1877 ServiceMap: map[string]interface{}{ 1878 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1879 }, 1880 }) 1881 require.NoError(t, err) 1882 1883 id := generateRandomID() 1884 connRecord := &connection.Record{ 1885 ConnectionID: id, 1886 State: StateIDRequested, 1887 } 1888 1889 err = svc.storeEventProtocolStateData(&message{ConnRecord: connRecord}) 1890 require.NoError(t, err) 1891 1892 err = svc.AcceptInvitation(id, "sample-public-did", "sample-label", nil) 1893 require.Error(t, err) 1894 require.Contains(t, err.Error(), "accept exchange invitation : data not found") 1895 }) 1896 } 1897 1898 func TestEventProtocolStateData(t *testing.T) { 1899 t.Run("event protocol state data - success", func(t *testing.T) { 1900 svc, err := New(&protocol.MockProvider{ 1901 ServiceMap: map[string]interface{}{ 1902 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1903 }, 1904 }) 1905 require.NoError(t, err) 1906 1907 connID := generateRandomID() 1908 1909 msg := &message{ 1910 ConnRecord: &connection.Record{ConnectionID: connID}, 1911 } 1912 err = svc.storeEventProtocolStateData(msg) 1913 require.NoError(t, err) 1914 1915 retrievedMsg, err := svc.getEventProtocolStateData(connID) 1916 require.NoError(t, err) 1917 require.Equal(t, msg, retrievedMsg) 1918 }) 1919 1920 t.Run("event protocol state data - data not found", func(t *testing.T) { 1921 svc, err := New(&protocol.MockProvider{ 1922 ServiceMap: map[string]interface{}{ 1923 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1924 }, 1925 }) 1926 require.NoError(t, err) 1927 1928 err = svc.AcceptExchangeRequest(generateRandomID(), "", "", nil) 1929 require.Error(t, err) 1930 require.Contains(t, err.Error(), "accept exchange request : get protocol state data : data not found") 1931 1932 err = svc.AcceptExchangeRequest(generateRandomID(), "sample-public-did", "sample-label", nil) 1933 require.Error(t, err) 1934 require.Contains(t, err.Error(), "accept exchange request : get protocol state data : data not found") 1935 }) 1936 1937 t.Run("event protocol state data - invalid data", func(t *testing.T) { 1938 svc, err := New(&protocol.MockProvider{ 1939 ServiceMap: map[string]interface{}{ 1940 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1941 }, 1942 }) 1943 require.NoError(t, err) 1944 1945 connID := generateRandomID() 1946 1947 err = svc.connectionRecorder.SaveEvent(connID, []byte("invalid data")) 1948 require.NoError(t, err) 1949 1950 _, err = svc.getEventProtocolStateData(connID) 1951 require.Error(t, err) 1952 require.Contains(t, err.Error(), "get protocol state data : invalid character") 1953 }) 1954 } 1955 1956 func TestNextState(t *testing.T) { 1957 t.Run("empty thread ID", func(t *testing.T) { 1958 svc, err := New(&protocol.MockProvider{ 1959 ServiceMap: map[string]interface{}{ 1960 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1961 }, 1962 }) 1963 require.NoError(t, err) 1964 1965 _, err = svc.nextState(RequestMsgType, "") 1966 require.EqualError(t, err, "unable to compute hash, empty bytes") 1967 }) 1968 1969 t.Run("valid inputs", func(t *testing.T) { 1970 svc, err := New(&protocol.MockProvider{ 1971 ServiceMap: map[string]interface{}{ 1972 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1973 }, 1974 }) 1975 require.NoError(t, err) 1976 1977 s, errState := svc.nextState(RequestMsgType, generateRandomID()) 1978 require.NoError(t, errState) 1979 require.Equal(t, StateIDRequested, s.Name()) 1980 }) 1981 } 1982 1983 func TestFetchConnectionRecord(t *testing.T) { 1984 t.Run("fetch connection record - invalid payload", func(t *testing.T) { 1985 svc, err := New(&protocol.MockProvider{ 1986 ServiceMap: map[string]interface{}{ 1987 mediator.Coordination: &mockroute.MockMediatorSvc{}, 1988 }, 1989 }) 1990 require.NoError(t, err) 1991 1992 _, err = svc.fetchConnectionRecord("", service.DIDCommMsgMap{"~thread": map[int]int{1: 1}}) 1993 require.Contains(t, fmt.Sprintf("%v", err), `'~thread' needs a map with string keys`) 1994 }) 1995 1996 t.Run("fetch connection record - no thread id", func(t *testing.T) { 1997 svc, err := New(&protocol.MockProvider{ 1998 ServiceMap: map[string]interface{}{ 1999 mediator.Coordination: &mockroute.MockMediatorSvc{}, 2000 }, 2001 }) 2002 require.NoError(t, err) 2003 2004 _, err = svc.fetchConnectionRecord(theirNSPrefix, toDIDCommMsg(t, &Request{ 2005 Type: ResponseMsgType, 2006 ID: generateRandomID(), 2007 })) 2008 require.Error(t, err) 2009 require.Contains(t, err.Error(), "unable to compute hash, empty bytes") 2010 }) 2011 2012 t.Run("fetch connection record - valid input", func(t *testing.T) { 2013 svc, err := New(&protocol.MockProvider{ 2014 ServiceMap: map[string]interface{}{ 2015 mediator.Coordination: &mockroute.MockMediatorSvc{}, 2016 }, 2017 }) 2018 require.NoError(t, err) 2019 2020 _, err = svc.fetchConnectionRecord(theirNSPrefix, toDIDCommMsg(t, &Response{ 2021 Type: ResponseMsgType, 2022 ID: generateRandomID(), 2023 Thread: &decorator.Thread{ID: generateRandomID()}, 2024 })) 2025 require.Error(t, err) 2026 require.Contains(t, err.Error(), "get connectionID by namespaced threadID: data not found") 2027 }) 2028 } 2029 2030 func generateRequestMsgPayload(t *testing.T, prov provider, id, invitationID string) service.DIDCommMsgMap { 2031 connRec, err := connection.NewRecorder(prov) 2032 require.NoError(t, err) 2033 require.NotNil(t, connRec) 2034 2035 ctx := context{ 2036 outboundDispatcher: prov.OutboundDispatcher(), 2037 vdRegistry: &mockvdr.MockVDRegistry{CreateValue: mockdiddoc.GetMockDIDDoc(t, false)}, 2038 connectionRecorder: connRec, 2039 } 2040 doc, err := ctx.vdRegistry.Create(testMethod, nil) 2041 require.NoError(t, err) 2042 2043 requestBytes, err := json.Marshal(&Request{ 2044 Type: RequestMsgType, 2045 ID: id, 2046 Thread: &decorator.Thread{ 2047 PID: invitationID, 2048 }, 2049 DID: doc.DIDDocument.ID, 2050 DocAttach: signedDocAttach(t, doc.DIDDocument), 2051 }) 2052 require.NoError(t, err) 2053 2054 didMsg, err := service.ParseDIDCommMsgMap(requestBytes) 2055 require.NoError(t, err) 2056 2057 return didMsg 2058 } 2059 2060 func TestService_CreateImplicitInvitation(t *testing.T) { 2061 t.Run("success", func(t *testing.T) { 2062 routeSvc := &mockroute.MockMediatorSvc{} 2063 prov := &protocol.MockProvider{ 2064 ServiceMap: map[string]interface{}{ 2065 mediator.Coordination: routeSvc, 2066 }, 2067 } 2068 sp := mockstorage.NewMockStoreProvider() 2069 k := newKMS(t, sp) 2070 ctx := &context{ 2071 kms: k, 2072 outboundDispatcher: prov.OutboundDispatcher(), 2073 routeSvc: routeSvc, 2074 keyType: kms.ED25519Type, 2075 keyAgreementType: kms.X25519ECDHKWType, 2076 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 2077 } 2078 2079 verPubKey, encPubKey := newSigningAndEncryptionDIDKeys(t, ctx) 2080 newDIDDoc := createDIDDocWithKey(verPubKey, encPubKey, ctx.mediaTypeProfiles[0]) 2081 2082 connRec, err := connection.NewRecorder(prov) 2083 require.NoError(t, err) 2084 require.NotNil(t, connRec) 2085 2086 didConnStore, err := didstore.NewConnectionStore(prov) 2087 require.NoError(t, err) 2088 require.NotNil(t, didConnStore) 2089 2090 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: newDIDDoc} 2091 ctx.connectionRecorder = connRec 2092 ctx.connectionStore = didConnStore 2093 2094 s, err := New(prov) 2095 require.NoError(t, err) 2096 2097 s.ctx = ctx 2098 connID, err := s.CreateImplicitInvitation("label", newDIDDoc.ID, "", "", nil) 2099 require.NoError(t, err) 2100 require.NotEmpty(t, connID) 2101 }) 2102 2103 t.Run("error during did resolution", func(t *testing.T) { 2104 routeSvc := &mockroute.MockMediatorSvc{} 2105 prov := &protocol.MockProvider{ 2106 ServiceMap: map[string]interface{}{ 2107 mediator.Coordination: routeSvc, 2108 }, 2109 } 2110 sp := mockstorage.NewMockStoreProvider() 2111 k := newKMS(t, sp) 2112 ctx := &context{ 2113 kms: k, 2114 outboundDispatcher: prov.OutboundDispatcher(), 2115 routeSvc: routeSvc, 2116 keyType: kms.ED25519Type, 2117 keyAgreementType: kms.X25519ECDHKWType, 2118 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 2119 } 2120 verPubKey, encPubKey := newSigningAndEncryptionDIDKeys(t, ctx) 2121 newDIDDoc := createDIDDocWithKey(verPubKey, encPubKey, ctx.mediaTypeProfiles[0]) 2122 2123 connRec, err := connection.NewRecorder(prov) 2124 require.NoError(t, err) 2125 require.NotNil(t, connRec) 2126 2127 didConnStore, err := didstore.NewConnectionStore(prov) 2128 require.NoError(t, err) 2129 require.NotNil(t, didConnStore) 2130 2131 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveErr: errors.New("resolve error")} 2132 ctx.connectionRecorder = connRec 2133 ctx.connectionStore = didConnStore 2134 2135 s, err := New(prov) 2136 require.NoError(t, err) 2137 s.ctx = ctx 2138 2139 connID, err := s.CreateImplicitInvitation("label", newDIDDoc.ID, "", "", nil) 2140 require.Error(t, err) 2141 require.Contains(t, err.Error(), "resolve error") 2142 require.Empty(t, connID) 2143 }) 2144 2145 t.Run("error during saving connection", func(t *testing.T) { 2146 sp := mockstorage.NewMockStoreProvider() 2147 k := newKMS(t, sp) 2148 ctx := &context{ 2149 kms: k, 2150 keyType: kms.ED25519Type, 2151 keyAgreementType: kms.X25519ECDHKWType, 2152 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 2153 } 2154 routeSvc := &mockroute.MockMediatorSvc{} 2155 protocolStateStore := mockstorage.NewMockStoreProvider() 2156 protocolStateStore.Store.ErrPut = errors.New("store put error") 2157 prov := &protocol.MockProvider{ 2158 ProtocolStateStoreProvider: protocolStateStore, 2159 ServiceMap: map[string]interface{}{ 2160 mediator.Coordination: routeSvc, 2161 }, 2162 KeyTypeValue: ctx.keyType, 2163 KeyAgreementTypeValue: ctx.keyAgreementType, 2164 } 2165 2166 ctx.outboundDispatcher = prov.OutboundDispatcher() 2167 ctx.routeSvc = routeSvc 2168 2169 verPubKey, encPubKey := newSigningAndEncryptionDIDKeys(t, ctx) 2170 newDIDDoc := createDIDDocWithKey(verPubKey, encPubKey, ctx.mediaTypeProfiles[0]) 2171 2172 connRec, err := connection.NewRecorder(prov) 2173 require.NoError(t, err) 2174 require.NotNil(t, connRec) 2175 2176 didConnStore, err := didstore.NewConnectionStore(prov) 2177 require.NoError(t, err) 2178 require.NotNil(t, didConnStore) 2179 2180 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: newDIDDoc} 2181 ctx.connectionRecorder = connRec 2182 ctx.connectionStore = didConnStore 2183 2184 s, err := New(prov) 2185 require.NoError(t, err) 2186 s.ctx = ctx 2187 2188 connID, err := s.CreateImplicitInvitation("label", newDIDDoc.ID, "", "", nil) 2189 require.Error(t, err) 2190 require.Contains(t, err.Error(), "store put error") 2191 require.Empty(t, connID) 2192 }) 2193 } 2194 2195 func TestRespondTo(t *testing.T) { 2196 sp := mockstorage.NewMockStoreProvider() 2197 k := newKMS(t, sp) 2198 t.Run("responds to an explicit invitation", func(t *testing.T) { 2199 s, err := New(testProvider()) 2200 require.NoError(t, err) 2201 connID, err := s.RespondTo(newInvitation(&did.Service{ 2202 ID: uuid.New().String(), 2203 Type: "did-communication", 2204 RecipientKeys: []string{"did:key:1234567"}, 2205 ServiceEndpoint: commonmodel.NewDIDCommV1Endpoint("http://example.com"), 2206 }), nil) 2207 require.NoError(t, err) 2208 require.NotEmpty(t, connID) 2209 }) 2210 t.Run("responds to an implicit invitation", func(t *testing.T) { 2211 publicDID := createDIDDoc(t, &context{ 2212 kms: k, 2213 keyType: kms.ED25519Type, 2214 keyAgreementType: kms.X25519ECDHKWType, 2215 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 2216 }) 2217 provider := testProvider() 2218 provider.CustomVDR = &mockvdr.MockVDRegistry{ResolveValue: publicDID} 2219 s, err := New(provider) 2220 require.NoError(t, err) 2221 connID, err := s.RespondTo(newInvitation(publicDID.ID), nil) 2222 require.NoError(t, err) 2223 require.NotEmpty(t, connID) 2224 }) 2225 t.Run("fails if invitation is missing a threadID", func(t *testing.T) { 2226 s, err := New(testProvider()) 2227 require.NoError(t, err) 2228 _, err = s.RespondTo(&OOBInvitation{ 2229 ID: uuid.New().String(), 2230 ThreadID: "", 2231 TheirLabel: "test", 2232 Target: "did:example:123", 2233 }, nil) 2234 require.Error(t, err) 2235 }) 2236 t.Run("fails if invitation is missing a target", func(t *testing.T) { 2237 s, err := New(testProvider()) 2238 require.NoError(t, err) 2239 _, err = s.RespondTo(&OOBInvitation{ 2240 ID: uuid.New().String(), 2241 ThreadID: uuid.New().String(), 2242 TheirLabel: "test", 2243 Target: nil, 2244 }, nil) 2245 require.Error(t, err) 2246 }) 2247 t.Run("fails if invitation has an invalid target type", func(t *testing.T) { 2248 invalid := &struct{}{} 2249 s, err := New(testProvider()) 2250 require.NoError(t, err) 2251 _, err = s.RespondTo(newInvitation(invalid), nil) 2252 require.Error(t, err) 2253 }) 2254 t.Run("wraps error from vdr registry when resolving DID", func(t *testing.T) { 2255 expected := errors.New("test") 2256 provider := testProvider() 2257 provider.CustomVDR = &mockvdr.MockVDRegistry{ 2258 ResolveErr: expected, 2259 } 2260 s, err := New(provider) 2261 require.NoError(t, err) 2262 _, err = s.RespondTo(newInvitation("did:example:123"), nil) 2263 require.Error(t, err) 2264 require.True(t, errors.Is(err, expected)) 2265 }) 2266 } 2267 2268 func TestSave(t *testing.T) { 2269 t.Run("saves invitation", func(t *testing.T) { 2270 expected := newOOBInvite([]string{transport.MediaTypeRFC0019EncryptedEnvelope}, "did:example:public") 2271 provider := testProvider() 2272 provider.StoreProvider = &mockstorage.MockStoreProvider{ 2273 Custom: &mockStore{ 2274 put: func(k string, v []byte, tags ...storage.Tag) error { 2275 result := &OOBInvitation{} 2276 err := json.Unmarshal(v, result) 2277 require.NoError(t, err) 2278 require.Equal(t, expected, result) 2279 return nil 2280 }, 2281 }, 2282 } 2283 s, err := New(provider) 2284 require.NoError(t, err) 2285 err = s.SaveInvitation(expected) 2286 require.NoError(t, err) 2287 }) 2288 t.Run("wraps error returned by store", func(t *testing.T) { 2289 expected := errors.New("test") 2290 provider := testProvider() 2291 provider.StoreProvider = &mockstorage.MockStoreProvider{ 2292 Store: &mockstorage.MockStore{ 2293 ErrPut: expected, 2294 }, 2295 } 2296 s, err := New(provider) 2297 require.NoError(t, err) 2298 err = s.SaveInvitation(newOOBInvite([]string{transport.MediaTypeRFC0019EncryptedEnvelope}, "did:example:public")) 2299 require.Error(t, err) 2300 require.True(t, errors.Is(err, expected)) 2301 }) 2302 } 2303 2304 func newInvitation(target interface{}) *OOBInvitation { 2305 return &OOBInvitation{ 2306 ID: uuid.New().String(), 2307 ThreadID: uuid.New().String(), 2308 TheirLabel: "test", 2309 Target: target, 2310 } 2311 } 2312 2313 func testProvider() *protocol.MockProvider { 2314 return &protocol.MockProvider{ 2315 StoreProvider: mockstorage.NewMockStoreProvider(), 2316 ServiceMap: map[string]interface{}{ 2317 mediator.Coordination: &mockroute.MockMediatorSvc{}, 2318 }, 2319 KeyTypeValue: kms.ED25519Type, 2320 KeyAgreementTypeValue: kms.X25519ECDHKWType, 2321 } 2322 } 2323 2324 func newPeerDID(t *testing.T, k kms.KeyManager) *did.Doc { 2325 kid, pubKey, err := k.CreateAndExportPubKeyBytes(kms.ED25519) 2326 require.NoError(t, err) 2327 2328 key := did.VerificationMethod{ 2329 ID: kid, 2330 Type: "Ed25519VerificationKey2018", 2331 Controller: "", 2332 Value: pubKey, 2333 } 2334 doc, err := peer.NewDoc( 2335 []did.VerificationMethod{key}, 2336 did.WithAuthentication([]did.Verification{{ 2337 VerificationMethod: key, 2338 Relationship: 0, 2339 Embedded: true, 2340 }}), 2341 did.WithService([]did.Service{{ 2342 ID: "didcomm", 2343 Type: "did-communication", 2344 Priority: 0, 2345 RecipientKeys: []string{base58.Encode(pubKey)}, 2346 ServiceEndpoint: commonmodel.NewDIDCommV1Endpoint("http://example.com"), 2347 }}), 2348 ) 2349 require.NoError(t, err) 2350 2351 return doc 2352 } 2353 2354 func unsignedDocAttach(t *testing.T, doc *did.Doc) *decorator.Attachment { 2355 t.Helper() 2356 2357 docBytes, err := doc.JSONBytes() 2358 require.NoError(t, err) 2359 2360 att := &decorator.Attachment{ 2361 Data: decorator.AttachmentData{ 2362 Base64: base64.StdEncoding.EncodeToString(docBytes), 2363 }, 2364 } 2365 2366 return att 2367 } 2368 2369 func signedDocAttach(t *testing.T, doc *did.Doc) *decorator.Attachment { 2370 t.Helper() 2371 2372 docBytes, err := doc.JSONBytes() 2373 require.NoError(t, err) 2374 2375 att := &decorator.Attachment{ 2376 Data: decorator.AttachmentData{ 2377 Base64: base64.StdEncoding.EncodeToString(docBytes), 2378 }, 2379 } 2380 2381 store := mockstorage.NewMockStoreProvider() 2382 2383 kmsInstance := newKMS(t, store) 2384 2385 kid, kh, err := kmsInstance.Create(kms.ED25519Type) 2386 require.NoError(t, err) 2387 2388 pub, kt, err := kmsInstance.ExportPubKeyBytes(kid) 2389 require.NoError(t, err) 2390 require.Equal(t, kms.ED25519Type, kt) 2391 2392 c := &tinkcrypto.Crypto{} 2393 2394 err = att.Data.Sign(c, kh, ed25519.PublicKey(pub), pub) 2395 require.NoError(t, err) 2396 2397 return att 2398 } 2399 2400 type mockConnectionStore struct { 2401 saveDIDByResolvingErr error 2402 saveDIDFromDocErr error 2403 } 2404 2405 // GetDID returns DID associated with key. 2406 func (m *mockConnectionStore) GetDID(string) (string, error) { 2407 return "", nil 2408 } 2409 2410 // SaveDID saves DID to the underlying storage. 2411 func (m *mockConnectionStore) SaveDID(string, ...string) error { 2412 return nil 2413 } 2414 2415 // SaveDIDFromDoc saves DID from did.Doc to the underlying storage. 2416 func (m *mockConnectionStore) SaveDIDFromDoc(*did.Doc) error { 2417 return m.saveDIDFromDocErr 2418 } 2419 2420 // SaveDIDByResolving saves DID resolved by VDR to the underlying storage. 2421 func (m *mockConnectionStore) SaveDIDByResolving(string, ...string) error { 2422 return m.saveDIDByResolvingErr 2423 }