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