github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/protocol/legacyconnection/states_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 "crypto/ed25519" 11 "crypto/rand" 12 "encoding/base64" 13 "encoding/binary" 14 "encoding/json" 15 "errors" 16 "fmt" 17 "testing" 18 "time" 19 20 "github.com/btcsuite/btcutil/base58" 21 "github.com/google/uuid" 22 "github.com/stretchr/testify/require" 23 24 "github.com/hyperledger/aries-framework-go/component/storageutil/mem" 25 commonmodel "github.com/hyperledger/aries-framework-go/pkg/common/model" 26 "github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto" 27 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/model" 28 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" 29 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator" 30 "github.com/hyperledger/aries-framework-go/pkg/didcomm/transport" 31 diddoc "github.com/hyperledger/aries-framework-go/pkg/doc/did" 32 vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr" 33 "github.com/hyperledger/aries-framework-go/pkg/kms" 34 mockcrypto "github.com/hyperledger/aries-framework-go/pkg/mock/crypto" 35 "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 mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage" 39 mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr" 40 "github.com/hyperledger/aries-framework-go/pkg/store/connection" 41 didstore "github.com/hyperledger/aries-framework-go/pkg/store/did" 42 ) 43 44 func TestNoopState(t *testing.T) { 45 noop := &noOp{} 46 require.Equal(t, "noop", noop.Name()) 47 48 t.Run("must not transition to any state", func(t *testing.T) { 49 all := []state{&null{}, &invited{}, &requested{}, &responded{}, &completed{}} 50 for _, s := range all { 51 require.False(t, noop.CanTransitionTo(s)) 52 } 53 }) 54 } 55 56 // null state can transition to invited state or requested state. 57 func TestNullState(t *testing.T) { 58 nul := &null{} 59 require.Equal(t, "null", nul.Name()) 60 require.False(t, nul.CanTransitionTo(nul)) 61 require.True(t, nul.CanTransitionTo(&invited{})) 62 require.True(t, nul.CanTransitionTo(&requested{})) 63 require.False(t, nul.CanTransitionTo(&responded{})) 64 require.False(t, nul.CanTransitionTo(&completed{})) 65 } 66 67 // invited can only transition to requested state. 68 func TestInvitedState(t *testing.T) { 69 inv := &invited{} 70 require.Equal(t, "invited", inv.Name()) 71 require.False(t, inv.CanTransitionTo(&null{})) 72 require.False(t, inv.CanTransitionTo(inv)) 73 require.True(t, inv.CanTransitionTo(&requested{})) 74 require.False(t, inv.CanTransitionTo(&responded{})) 75 require.False(t, inv.CanTransitionTo(&completed{})) 76 } 77 78 // requested can only transition to responded state. 79 func TestRequestedState(t *testing.T) { 80 req := &requested{} 81 require.Equal(t, "requested", req.Name()) 82 require.False(t, req.CanTransitionTo(&null{})) 83 require.False(t, req.CanTransitionTo(&invited{})) 84 require.False(t, req.CanTransitionTo(req)) 85 require.True(t, req.CanTransitionTo(&responded{})) 86 require.False(t, req.CanTransitionTo(&completed{})) 87 } 88 89 // responded can only transition to completed state. 90 func TestRespondedState(t *testing.T) { 91 res := &responded{} 92 require.Equal(t, "responded", res.Name()) 93 require.False(t, res.CanTransitionTo(&null{})) 94 require.False(t, res.CanTransitionTo(&invited{})) 95 require.False(t, res.CanTransitionTo(&requested{})) 96 require.False(t, res.CanTransitionTo(res)) 97 require.True(t, res.CanTransitionTo(&completed{})) 98 } 99 100 // completed is an end state. 101 func TestCompletedState(t *testing.T) { 102 comp := &completed{} 103 require.Equal(t, "completed", comp.Name()) 104 require.False(t, comp.CanTransitionTo(&null{})) 105 require.False(t, comp.CanTransitionTo(&invited{})) 106 require.False(t, comp.CanTransitionTo(&requested{})) 107 require.False(t, comp.CanTransitionTo(&responded{})) 108 require.False(t, comp.CanTransitionTo(comp)) 109 } 110 111 func TestStateFromMsgType(t *testing.T) { 112 t.Run("invited", func(t *testing.T) { 113 expected := &invited{} 114 actual, err := stateFromMsgType(InvitationMsgType) 115 require.NoError(t, err) 116 require.Equal(t, expected.Name(), actual.Name()) 117 }) 118 t.Run("requested", func(t *testing.T) { 119 expected := &requested{} 120 actual, err := stateFromMsgType(RequestMsgType) 121 require.NoError(t, err) 122 require.Equal(t, expected.Name(), actual.Name()) 123 }) 124 t.Run("responded", func(t *testing.T) { 125 expected := &responded{} 126 actual, err := stateFromMsgType(ResponseMsgType) 127 require.NoError(t, err) 128 require.Equal(t, expected.Name(), actual.Name()) 129 }) 130 t.Run("completed", func(t *testing.T) { 131 expected := &completed{} 132 actual, err := stateFromMsgType(AckMsgType) 133 require.NoError(t, err) 134 require.Equal(t, expected.Name(), actual.Name()) 135 }) 136 t.Run("invalid", func(t *testing.T) { 137 actual, err := stateFromMsgType("invalid") 138 require.Nil(t, actual) 139 require.Error(t, err) 140 require.Contains(t, err.Error(), "unrecognized msgType: invalid") 141 }) 142 } 143 144 func TestStateFromName(t *testing.T) { 145 t.Run("noop", func(t *testing.T) { 146 expected := &noOp{} 147 actual, err := stateFromName(expected.Name()) 148 require.NoError(t, err) 149 require.Equal(t, expected.Name(), actual.Name()) 150 }) 151 t.Run("null", func(t *testing.T) { 152 expected := &null{} 153 actual, err := stateFromName(expected.Name()) 154 require.NoError(t, err) 155 require.Equal(t, expected.Name(), actual.Name()) 156 }) 157 t.Run("invited", func(t *testing.T) { 158 expected := &invited{} 159 actual, err := stateFromName(expected.Name()) 160 require.NoError(t, err) 161 require.Equal(t, expected.Name(), actual.Name()) 162 }) 163 t.Run("requested", func(t *testing.T) { 164 expected := &requested{} 165 actual, err := stateFromName(expected.Name()) 166 require.NoError(t, err) 167 require.Equal(t, expected.Name(), actual.Name()) 168 }) 169 t.Run("responded", func(t *testing.T) { 170 expected := &responded{} 171 actual, err := stateFromName(expected.Name()) 172 require.NoError(t, err) 173 require.Equal(t, expected.Name(), actual.Name()) 174 }) 175 t.Run("completed", func(t *testing.T) { 176 expected := &completed{} 177 actual, err := stateFromName(expected.Name()) 178 require.NoError(t, err) 179 require.Equal(t, expected.Name(), actual.Name()) 180 }) 181 t.Run("undefined", func(t *testing.T) { 182 actual, err := stateFromName("undefined") 183 require.Nil(t, actual) 184 require.Error(t, err) 185 require.Contains(t, err.Error(), "invalid state name") 186 }) 187 } 188 189 // noOp.ExecuteInbound() returns nil, error. 190 func TestNoOpState_Execute(t *testing.T) { 191 _, followup, _, err := (&noOp{}).ExecuteInbound(&stateMachineMsg{}, "", &context{}) 192 require.Error(t, err) 193 require.Contains(t, err.Error(), "cannot execute no-op") 194 require.Nil(t, followup) 195 } 196 197 // null.ExecuteInbound() is a no-op. 198 func TestNullState_Execute(t *testing.T) { 199 _, followup, _, err := (&null{}).ExecuteInbound(&stateMachineMsg{}, "", &context{}) 200 require.NoError(t, err) 201 require.IsType(t, &noOp{}, followup) 202 } 203 204 func TestInvitedState_Execute(t *testing.T) { 205 t.Run("rejects msgs other than invitations", func(t *testing.T) { 206 others := []service.DIDCommMsg{ 207 service.NewDIDCommMsgMap(Request{Type: RequestMsgType}), 208 service.NewDIDCommMsgMap(Response{Type: ResponseMsgType}), 209 service.NewDIDCommMsgMap(model.Ack{Type: AckMsgType}), 210 } 211 for _, msg := range others { 212 _, _, _, err := (&invited{}).ExecuteInbound(&stateMachineMsg{ 213 DIDCommMsg: msg, 214 }, "", &context{}) 215 require.Error(t, err) 216 require.Contains(t, err.Error(), "illegal msg type") 217 } 218 }) 219 t.Run("followup to 'requested' on inbound invitations", func(t *testing.T) { 220 invitationPayloadBytes, err := json.Marshal(&Invitation{ 221 Type: InvitationMsgType, 222 ID: randomString(), 223 Label: "Bob", 224 RecipientKeys: []string{"8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K"}, 225 ServiceEndpoint: "https://localhost:8090", 226 RoutingKeys: []string{"8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K"}, 227 }) 228 require.NoError(t, err) 229 connRec, followup, _, err := (&invited{}).ExecuteInbound( 230 &stateMachineMsg{ 231 DIDCommMsg: bytesToDIDCommMsg(t, invitationPayloadBytes), 232 connRecord: &connection.Record{}, 233 }, 234 "", 235 &context{}) 236 require.NoError(t, err) 237 require.Equal(t, &requested{}, followup) 238 require.NotNil(t, connRec) 239 }) 240 } 241 242 func TestRequestedState_Execute(t *testing.T) { 243 prov := getProvider(t) 244 // Alice receives an invitation from Bob 245 invitationPayloadBytes, err := json.Marshal(&Invitation{ 246 Type: InvitationMsgType, 247 ID: randomString(), 248 Label: "Bob", 249 RecipientKeys: []string{"8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K"}, 250 ServiceEndpoint: "https://localhost:8090", 251 RoutingKeys: []string{"8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K"}, 252 }) 253 require.NoError(t, err) 254 255 mtps := []string{ 256 transport.MediaTypeRFC0019EncryptedEnvelope, 257 transport.MediaTypeProfileDIDCommAIP1, 258 } 259 260 for _, mtp := range mtps { 261 t.Run("rejects messages other than invitations or requests", func(t *testing.T) { 262 others := []service.DIDCommMsg{ 263 service.NewDIDCommMsgMap(Response{Type: ResponseMsgType}), 264 service.NewDIDCommMsgMap(model.Ack{Type: AckMsgType}), 265 } 266 for _, msg := range others { 267 _, _, _, e := (&requested{}).ExecuteInbound(&stateMachineMsg{ 268 DIDCommMsg: msg, 269 }, "", &context{}) 270 require.Error(t, e) 271 require.Contains(t, e.Error(), "illegal msg type") 272 } 273 }) 274 t.Run("handle inbound invitations", func(t *testing.T) { 275 ctx := getContext(t, &prov, mtp) 276 msg, e := service.ParseDIDCommMsgMap(invitationPayloadBytes) 277 require.NoError(t, e) 278 thid, e := msg.ThreadID() 279 require.NoError(t, e) 280 connRec, _, _, e := (&requested{}).ExecuteInbound(&stateMachineMsg{ 281 DIDCommMsg: msg, 282 connRecord: &connection.Record{}, 283 }, thid, ctx) 284 require.NoError(t, e) 285 require.NotNil(t, connRec.MyDID) 286 }) 287 t.Run("handling invitations fails if my diddoc does not have a valid didcomm service", func(t *testing.T) { 288 msg, e := service.ParseDIDCommMsgMap(invitationPayloadBytes) 289 require.NoError(t, e) 290 291 ctx := getContext(t, &prov, mtp) 292 293 myDoc := createDIDDoc(t, ctx) 294 myDoc.Service = []diddoc.Service{{ 295 ID: uuid.New().String(), 296 Type: "invalid", 297 Priority: 0, 298 RecipientKeys: nil, 299 ServiceEndpoint: commonmodel.NewDIDCommV1Endpoint("https://localhost:8090"), 300 }} 301 ctx.vdRegistry = &mockvdr.MockVDRegistry{CreateValue: myDoc} 302 _, _, _, err = (&requested{}).ExecuteInbound(&stateMachineMsg{ 303 DIDCommMsg: msg, 304 connRecord: &connection.Record{}, 305 }, "", ctx) 306 require.Error(t, err) 307 }) 308 t.Run("inbound request unmarshalling error", func(t *testing.T) { 309 _, followup, _, err := (&requested{}).ExecuteInbound(&stateMachineMsg{ 310 DIDCommMsg: service.DIDCommMsgMap{ 311 "@type": InvitationMsgType, 312 "@id": map[int]int{}, 313 }, 314 }, "", &context{}) 315 require.Error(t, err) 316 require.Contains(t, err.Error(), "JSON unmarshalling of invitation") 317 require.Nil(t, followup) 318 }) 319 t.Run("create DID error", func(t *testing.T) { 320 ctx2 := &context{ 321 outboundDispatcher: prov.OutboundDispatcher(), 322 vdRegistry: &mockvdr.MockVDRegistry{CreateErr: fmt.Errorf("create DID error")}, 323 } 324 didDoc, err := ctx2.vdRegistry.Create(testMethod, nil) 325 require.Error(t, err) 326 require.Contains(t, err.Error(), "create DID error") 327 require.Nil(t, didDoc) 328 }) 329 } 330 } 331 332 func TestRespondedState_Execute(t *testing.T) { 333 mtps := []string{transport.MediaTypeProfileDIDCommAIP1, transport.MediaTypeRFC0019EncryptedEnvelope} 334 335 for _, mtp := range mtps { 336 prov := getProvider(t) 337 ctx := getContext(t, &prov, mtp) 338 339 request, err := createRequest(t, ctx) 340 require.NoError(t, err) 341 342 requestPayloadBytes, err := json.Marshal(request) 343 require.NoError(t, err) 344 345 response, err := createResponse(request, ctx) 346 require.NoError(t, err) 347 348 responsePayloadBytes, err := json.Marshal(response) 349 require.NoError(t, err) 350 351 t.Run("rejects messages other than requests and responses", func(t *testing.T) { 352 others := []service.DIDCommMsg{ 353 service.NewDIDCommMsgMap(Invitation{Type: InvitationMsgType}), 354 service.NewDIDCommMsgMap(model.Ack{Type: AckMsgType}), 355 } 356 for _, msg := range others { 357 _, _, _, e := (&responded{}).ExecuteInbound(&stateMachineMsg{ 358 DIDCommMsg: msg, 359 }, "", &context{}) 360 require.Error(t, e) 361 require.Contains(t, e.Error(), "illegal msg type") 362 } 363 }) 364 t.Run("no followup for inbound requests", func(t *testing.T) { 365 connRec, followup, _, e := (&responded{}).ExecuteInbound(&stateMachineMsg{ 366 DIDCommMsg: bytesToDIDCommMsg(t, requestPayloadBytes), 367 connRecord: &connection.Record{}, 368 }, "", ctx) 369 require.NoError(t, e) 370 require.NotNil(t, connRec) 371 require.IsType(t, &noOp{}, followup) 372 }) 373 t.Run("followup to 'completed' on inbound responses", func(t *testing.T) { 374 connRec := &connection.Record{ 375 State: (&responded{}).Name(), 376 ThreadID: request.ID, 377 ConnectionID: "123", 378 Namespace: findNamespace(ResponseMsgType), 379 } 380 err = ctx.connectionRecorder.SaveConnectionRecordWithMappings(connRec) 381 require.NoError(t, err) 382 connRec, followup, _, e := (&responded{}).ExecuteInbound( 383 &stateMachineMsg{ 384 DIDCommMsg: bytesToDIDCommMsg(t, responsePayloadBytes), 385 connRecord: connRec, 386 }, "", ctx) 387 require.NoError(t, e) 388 require.NotNil(t, connRec) 389 require.Equal(t, (&completed{}).Name(), followup.Name()) 390 }) 391 392 t.Run("handle inbound request unmarshalling error", func(t *testing.T) { 393 _, followup, _, err := (&responded{}).ExecuteInbound(&stateMachineMsg{ 394 DIDCommMsg: service.DIDCommMsgMap{"@id": map[int]int{}, "@type": RequestMsgType}, 395 }, "", &context{}) 396 require.Error(t, err) 397 require.Contains(t, err.Error(), "JSON unmarshalling of request") 398 require.Nil(t, followup) 399 }) 400 401 t.Run("fails if my did has an invalid didcomm service entry", func(t *testing.T) { 402 myDoc := createDIDDoc(t, ctx) 403 myDoc.Service = []diddoc.Service{{ 404 ID: uuid.New().String(), 405 Type: "invalid", 406 Priority: 0, 407 RecipientKeys: nil, 408 ServiceEndpoint: commonmodel.NewDIDCommV1Endpoint("http://localhost:58416"), 409 }} 410 ctx.vdRegistry = &mockvdr.MockVDRegistry{CreateValue: myDoc} 411 _, _, _, err := (&responded{}).ExecuteInbound(&stateMachineMsg{ 412 DIDCommMsg: bytesToDIDCommMsg(t, requestPayloadBytes), 413 connRecord: &connection.Record{}, 414 }, "", ctx) 415 require.Error(t, err) 416 }) 417 } 418 } 419 420 // completed is an end state. 421 func TestCompletedState_Execute(t *testing.T) { 422 prov := getProvider(t) 423 customKMS := newKMS(t, prov.StoreProvider) 424 ctx := &context{ 425 crypto: &tinkcrypto.Crypto{}, 426 kms: customKMS, 427 keyType: kms.ED25519Type, 428 keyAgreementType: kms.X25519ECDHKWType, 429 } 430 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 431 require.NoError(t, err) 432 433 connRec, err := connection.NewRecorder(&prov) 434 435 require.NoError(t, err) 436 require.NotNil(t, connRec) 437 438 ctx.connectionRecorder = connRec 439 440 newDIDDoc := createDIDDocWithKey(pubKey) 441 442 invitation, err := createMockInvitation(pubKey, ctx) 443 require.NoError(t, err) 444 445 connectionSignature, err := ctx.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 446 require.NoError(t, err) 447 448 response := &Response{ 449 Type: ResponseMsgType, 450 ID: randomString(), 451 ConnectionSignature: connectionSignature, 452 Thread: &decorator.Thread{ 453 ID: "test", 454 }, 455 PleaseAck: &PleaseAck{On: []string{PlsAckOnReceipt}}, 456 } 457 458 t.Run("no followup for inbound responses", func(t *testing.T) { 459 var responsePayloadBytes []byte 460 461 responsePayloadBytes, err = json.Marshal(response) 462 require.NoError(t, err) 463 464 newConnRec := &connection.Record{ 465 State: (&responded{}).Name(), 466 ThreadID: response.Thread.ID, 467 ConnectionID: "123", 468 MyDID: "did:peer:123456789abcdefghi#inbox", 469 Namespace: myNSPrefix, 470 InvitationID: invitation.ID, 471 RecipientKeys: []string{base58.Encode(pubKey)}, 472 } 473 err = ctx.connectionRecorder.SaveConnectionRecordWithMappings(newConnRec) 474 require.NoError(t, err) 475 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: mockdiddoc.GetMockDIDDoc(t, false)} 476 require.NoError(t, err) 477 _, followup, _, e := (&completed{}).ExecuteInbound(&stateMachineMsg{ 478 DIDCommMsg: bytesToDIDCommMsg(t, responsePayloadBytes), 479 connRecord: newConnRec, 480 }, "", ctx) 481 require.NoError(t, e) 482 require.IsType(t, &noOp{}, followup) 483 }) 484 t.Run("no followup for inbound acks", func(t *testing.T) { 485 newConnRec := &connection.Record{ 486 State: (&responded{}).Name(), 487 ThreadID: response.Thread.ID, 488 ConnectionID: "123", 489 Namespace: findNamespace(AckMsgType), 490 RecipientKeys: []string{base58.Encode(pubKey)}, 491 } 492 err = ctx.connectionRecorder.SaveConnectionRecordWithMappings(newConnRec) 493 require.NoError(t, err) 494 ack := &model.Ack{ 495 Type: AckMsgType, 496 ID: randomString(), 497 Status: ackStatusOK, 498 Thread: &decorator.Thread{ 499 ID: response.Thread.ID, 500 }, 501 } 502 ackPayloadBytes, e := json.Marshal(ack) 503 require.NoError(t, e) 504 _, followup, _, e := (&completed{}).ExecuteInbound(&stateMachineMsg{ 505 DIDCommMsg: bytesToDIDCommMsg(t, ackPayloadBytes), 506 }, "", ctx) 507 require.NoError(t, e) 508 require.IsType(t, &noOp{}, followup) 509 }) 510 t.Run("rejects messages other than responses, acks, and completes", func(t *testing.T) { 511 others := []service.DIDCommMsg{ 512 service.NewDIDCommMsgMap(Invitation{Type: InvitationMsgType}), 513 service.NewDIDCommMsgMap(Request{Type: RequestMsgType}), 514 } 515 516 for _, msg := range others { 517 _, _, _, err = (&completed{}).ExecuteInbound(&stateMachineMsg{ 518 DIDCommMsg: msg, 519 }, "", &context{}) 520 require.Error(t, err) 521 require.Contains(t, err.Error(), "illegal msg type") 522 } 523 }) 524 t.Run("no followup for inbound responses unmarshalling error", func(t *testing.T) { 525 _, followup, _, err := (&completed{}).ExecuteInbound(&stateMachineMsg{ 526 DIDCommMsg: service.DIDCommMsgMap{"@id": map[int]int{}, "@type": ResponseMsgType}, 527 }, "", &context{}) 528 require.Error(t, err) 529 require.Contains(t, err.Error(), "JSON unmarshalling of response") 530 require.Nil(t, followup) 531 }) 532 533 t.Run("execute inbound handle inbound response error", func(t *testing.T) { 534 response.ConnectionSignature = &ConnectionSignature{} 535 responsePayloadBytes, err := json.Marshal(response) 536 require.NoError(t, err) 537 538 _, followup, _, err := (&completed{}).ExecuteInbound(&stateMachineMsg{ 539 DIDCommMsg: bytesToDIDCommMsg(t, responsePayloadBytes), 540 }, "", ctx) 541 require.Error(t, err) 542 require.Contains(t, err.Error(), "handle inbound response") 543 require.Nil(t, followup) 544 }) 545 } 546 547 func TestNewRequestFromInvitation(t *testing.T) { 548 invitation := &Invitation{ 549 Type: InvitationMsgType, 550 ID: randomString(), 551 Label: "Bob", 552 RecipientKeys: []string{"8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K"}, 553 ServiceEndpoint: "https://localhost:8090", 554 RoutingKeys: []string{"8HH5gYEeNc3z7PYXmd54d4x6qAfCNrqQqEB3nS7Zfu7K"}, 555 } 556 557 t.Run("successful new request from invitation", func(t *testing.T) { 558 prov := getProvider(t) 559 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 560 _, connRec, err := ctx.handleInboundInvitation(invitation, invitation.ID, &options{}, &connection.Record{}) 561 require.NoError(t, err) 562 require.NotNil(t, connRec.MyDID) 563 }) 564 t.Run("successful response to invitation with public did", func(t *testing.T) { 565 prov := getProvider(t) 566 ctx := &context{ 567 kms: prov.CustomKMS, 568 keyType: kms.ED25519Type, 569 keyAgreementType: kms.X25519ECDHKWType, 570 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 571 } 572 doc := createDIDDoc(t, ctx) 573 connRec, err := connection.NewRecorder(&protocol.MockProvider{}) 574 require.NoError(t, err) 575 didConnStore, err := didstore.NewConnectionStore(&protocol.MockProvider{}) 576 require.NoError(t, err) 577 578 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: doc} 579 ctx.connectionRecorder = connRec 580 ctx.connectionStore = didConnStore 581 582 _, connRecord, err := ctx.handleInboundInvitation(invitation, invitation.ID, &options{publicDID: doc.ID}, 583 &connection.Record{}) 584 require.NoError(t, err) 585 require.NotNil(t, connRecord.MyDID) 586 require.Equal(t, connRecord.MyDID, doc.ID) 587 }) 588 t.Run("unsuccessful new request from invitation ", func(t *testing.T) { 589 prov := protocol.MockProvider{} 590 customKMS := newKMS(t, mem.NewProvider()) 591 592 ctx := &context{ 593 kms: customKMS, 594 outboundDispatcher: prov.OutboundDispatcher(), 595 routeSvc: &mockroute.MockMediatorSvc{}, 596 vdRegistry: &mockvdr.MockVDRegistry{CreateErr: fmt.Errorf("create DID error")}, 597 keyType: kms.ED25519Type, 598 keyAgreementType: kms.X25519ECDHKWType, 599 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 600 } 601 _, connRec, err := ctx.handleInboundInvitation(invitation, invitation.ID, &options{}, &connection.Record{}) 602 require.Error(t, err) 603 require.Contains(t, err.Error(), "create DID error") 604 require.Nil(t, connRec) 605 }) 606 } 607 608 func TestNewResponseFromRequest(t *testing.T) { 609 prov := getProvider(t) 610 store := mockstorage.NewMockStoreProvider() 611 k := newKMS(t, store) 612 613 t.Run("successful new response from request", func(t *testing.T) { 614 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 615 request, err := createRequest(t, ctx) 616 require.NoError(t, err) 617 _, connRec, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 618 require.NoError(t, err) 619 require.NotNil(t, connRec.MyDID) 620 require.NotNil(t, connRec.TheirDID) 621 }) 622 623 t.Run("unsuccessful new response from request due to resolve DID error", func(t *testing.T) { 624 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 625 request, err := createRequest(t, ctx) 626 require.NoError(t, err) 627 628 request.Connection.DID = "did:invalid" 629 _, connRec, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 630 require.Error(t, err) 631 require.Contains(t, err.Error(), "resolve did doc from connection request") 632 require.Nil(t, connRec) 633 }) 634 635 t.Run("unsuccessful new response from request due to create did error", func(t *testing.T) { 636 didDoc := mockdiddoc.GetMockDIDDoc(t, false) 637 ctx := &context{ 638 vdRegistry: &mockvdr.MockVDRegistry{ 639 CreateErr: fmt.Errorf("create DID error"), 640 ResolveValue: mockdiddoc.GetMockDIDDoc(t, false), 641 }, 642 routeSvc: &mockroute.MockMediatorSvc{}, 643 } 644 request := &Request{ 645 Connection: &Connection{ 646 DID: didDoc.ID, 647 DIDDoc: didDoc, 648 }, 649 } 650 _, connRec, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 651 require.Error(t, err) 652 require.Contains(t, err.Error(), "create DID error") 653 require.Nil(t, connRec) 654 }) 655 656 t.Run("unsuccessful new response from request due to get did doc error", func(t *testing.T) { 657 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 658 ctx.connectionStore = &mockConnectionStore{saveDIDFromDocErr: fmt.Errorf("save did error")} 659 660 request, err := createRequest(t, ctx) 661 require.NoError(t, err) 662 _, connRec, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 663 require.Error(t, err) 664 require.Contains(t, err.Error(), "get response did doc and connection") 665 require.Nil(t, connRec) 666 }) 667 668 t.Run("prepare connection signature get invitation", func(t *testing.T) { 669 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 670 671 request, err := createRequest(t, ctx) 672 request.Thread.PID = "test" 673 674 require.NoError(t, err) 675 _, connRec, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 676 require.Error(t, err) 677 678 require.Contains(t, err.Error(), "get invitation for [invitationID=test]: data not found") 679 require.Nil(t, connRec) 680 }) 681 682 t.Run("prepare connection signature get invitation", func(t *testing.T) { 683 invID := randomString() 684 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 685 686 request, err := createRequest(t, ctx) 687 request.Thread.PID = invID 688 689 require.NoError(t, err) 690 _, connRec, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 691 require.Error(t, err) 692 693 require.Contains(t, err.Error(), fmt.Sprintf("get invitation for [invitationID=%s]: data not found", invID)) 694 require.Nil(t, connRec) 695 }) 696 697 t.Run("unsuccessful new response from request due to sign error", func(t *testing.T) { 698 connRec, err := connection.NewRecorder(&prov) 699 require.NoError(t, err) 700 require.NotNil(t, connRec) 701 702 didConnStore, err := didstore.NewConnectionStore(&prov) 703 require.NoError(t, err) 704 require.NotNil(t, didConnStore) 705 706 ctx := &context{ 707 vdRegistry: &mockvdr.MockVDRegistry{CreateValue: mockdiddoc.GetMockDIDDoc(t, false)}, 708 crypto: &mockcrypto.Crypto{SignErr: errors.New("sign error")}, 709 connectionRecorder: connRec, 710 connectionStore: didConnStore, 711 routeSvc: &mockroute.MockMediatorSvc{}, 712 kms: prov.CustomKMS, 713 keyType: kms.ED25519Type, 714 keyAgreementType: kms.X25519ECDHKWType, 715 doACAPyInterop: true, 716 } 717 718 request, err := createRequest(t, ctx) 719 require.NoError(t, err) 720 721 _, connRecord, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 722 723 require.Error(t, err) 724 require.Contains(t, err.Error(), "sign error") 725 require.Nil(t, connRecord) 726 }) 727 728 t.Run("unsuccessful new response from request due to resolve public did from request error", func(t *testing.T) { 729 ctx := &context{vdRegistry: &mockvdr.MockVDRegistry{ResolveErr: errors.New("resolver error")}} 730 request := &Request{Connection: &Connection{DID: "did:sidetree:abc", DIDDoc: &diddoc.Doc{}}} 731 _, _, err := ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 732 require.Error(t, err) 733 require.Contains(t, err.Error(), "resolver error") 734 }) 735 736 t.Run("unsuccessful new response from request due to invalid did for creating destination", func(t *testing.T) { 737 mockDoc := newPeerDID(t, k) 738 mockDoc.Service = nil 739 740 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 741 742 request, err := createRequest(t, ctx) 743 require.NoError(t, err) 744 745 request.Connection.DID = mockDoc.ID 746 request.Connection.DIDDoc = mockDoc 747 748 _, _, err = ctx.handleInboundRequest(request, &options{}, &connection.Record{}) 749 require.Error(t, err) 750 require.Contains(t, err.Error(), "missing DID doc service") 751 }) 752 } 753 754 func TestPrepareConnectionSignature(t *testing.T) { 755 prov := getProvider(t) 756 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 757 758 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 759 require.NoError(t, err) 760 761 invitation, err := createMockInvitation(pubKey, ctx) 762 require.NoError(t, err) 763 764 doc, err := ctx.vdRegistry.Create(testMethod, nil) 765 require.NoError(t, err) 766 767 t.Run("prepare connection signature", func(t *testing.T) { 768 connectionSignature, err := ctx.prepareConnectionSignature(doc.DIDDocument, invitation.RecipientKeys[0]) 769 require.NoError(t, err) 770 require.NotNil(t, connectionSignature) 771 sigData, err := base64.URLEncoding.DecodeString(connectionSignature.SignedData) 772 require.NoError(t, err) 773 connBytes := sigData[timestampLength:] 774 sigDataConnection := &Connection{} 775 err = json.Unmarshal(connBytes, sigDataConnection) 776 require.NoError(t, err) 777 require.Equal(t, doc.DIDDocument.ID, sigDataConnection.DID) 778 }) 779 t.Run("implicit invitation with DID - success", func(t *testing.T) { 780 connRec, err := connection.NewRecorder(&prov) 781 require.NoError(t, err) 782 require.NotNil(t, connRec) 783 784 didConnStore, err := didstore.NewConnectionStore(&prov) 785 require.NoError(t, err) 786 require.NotNil(t, didConnStore) 787 788 connectionSignature, err := ctx.prepareConnectionSignature(doc.DIDDocument, invitation.RecipientKeys[0]) 789 require.NoError(t, err) 790 require.NotNil(t, connectionSignature) 791 sigData, err := base64.URLEncoding.DecodeString(connectionSignature.SignedData) 792 require.NoError(t, err) 793 connBytes := sigData[timestampLength:] 794 sigDataConnection := &Connection{} 795 err = json.Unmarshal(connBytes, sigDataConnection) 796 require.NoError(t, err) 797 require.Equal(t, doc.DIDDocument.ID, sigDataConnection.DID) 798 }) 799 t.Run("prepare connection signature error", func(t *testing.T) { 800 ctx2 := ctx 801 ctx2.crypto = &mockcrypto.Crypto{SignErr: errors.New("sign error")} 802 newDIDDoc := mockdiddoc.GetMockDIDDoc(t, false) 803 804 connectionSignature, err := ctx2.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 805 require.Error(t, err) 806 require.Contains(t, err.Error(), "sign error") 807 require.Nil(t, connectionSignature) 808 }) 809 } 810 811 func TestVerifySignature(t *testing.T) { 812 prov := getProvider(t) 813 814 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 815 816 keyID, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 817 require.NoError(t, err) 818 819 newDIDDoc := createDIDDocWithKey(pubKey) 820 821 invitation, err := createMockInvitation(pubKey, ctx) 822 require.NoError(t, err) 823 824 t.Run("signature verified", func(t *testing.T) { 825 connectionSignature, err := ctx.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 826 require.NoError(t, err) 827 con, err := ctx.verifySignature(connectionSignature, invitation.RecipientKeys[0]) 828 require.NoError(t, err) 829 require.NotNil(t, con) 830 require.Equal(t, newDIDDoc.ID, con.DID) 831 }) 832 t.Run("missing/invalid signature data", func(t *testing.T) { 833 con, err := ctx.verifySignature(&ConnectionSignature{}, invitation.RecipientKeys[0]) 834 require.Error(t, err) 835 require.Contains(t, err.Error(), "missing or invalid signature data") 836 require.Nil(t, con) 837 }) 838 t.Run("decode signature data error", func(t *testing.T) { 839 connectionSignature, err := ctx.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 840 require.NoError(t, err) 841 842 connectionSignature.SignedData = "invalid-signed-data" 843 con, err := ctx.verifySignature(connectionSignature, "") 844 require.Error(t, err) 845 require.Contains(t, err.Error(), "decode signature data: illegal base64 data") 846 require.Nil(t, con) 847 }) 848 t.Run("decode signature error", func(t *testing.T) { 849 connectionSignature, err := ctx.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 850 require.NoError(t, err) 851 852 connectionSignature.Signature = "invalid-signature" 853 con, err := ctx.verifySignature(connectionSignature, "") 854 require.Error(t, err) 855 require.Contains(t, err.Error(), "decode signature: illegal base64 data") 856 require.Nil(t, con) 857 }) 858 t.Run("decode verification key error", func(t *testing.T) { 859 connectionSignature, err := ctx.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 860 require.NoError(t, err) 861 862 con, err := ctx.verifySignature(connectionSignature, "invalid-key") 863 require.Error(t, err) 864 require.Contains(t, err.Error(), "failed to get key handle: pubKey is empty") 865 require.Nil(t, con) 866 }) 867 t.Run("verify signature error", func(t *testing.T) { 868 connectionSignature, err := ctx.prepareConnectionSignature(newDIDDoc, invitation.RecipientKeys[0]) 869 require.NoError(t, err) 870 871 // generate different key and assign it to signature verification key 872 pubKey2, _ := generateKeyPair() 873 con, err := ctx.verifySignature(connectionSignature, pubKey2) 874 require.Error(t, err) 875 require.Contains(t, err.Error(), "invalid signature") 876 require.Nil(t, con) 877 }) 878 t.Run("connection unmarshal error", func(t *testing.T) { 879 connAttributeBytes := []byte("{hello world}") 880 881 now := getEpochTime() 882 timestampBuf := make([]byte, timestampLength) 883 binary.BigEndian.PutUint64(timestampBuf, uint64(now)) 884 concatenateSignData := append(timestampBuf, connAttributeBytes...) 885 886 kh, err := ctx.kms.Get(keyID) 887 require.NoError(t, err) 888 889 signature, err := ctx.crypto.Sign(concatenateSignData, kh) 890 require.NoError(t, err) 891 892 cs := &ConnectionSignature{ 893 Type: "https://didcomm.org/signature/1.0/ed25519Sha512_single", 894 SignedData: base64.URLEncoding.EncodeToString(concatenateSignData), 895 SignVerKey: base64.URLEncoding.EncodeToString(pubKey), 896 Signature: base64.URLEncoding.EncodeToString(signature), 897 } 898 899 con, err := ctx.verifySignature(cs, invitation.RecipientKeys[0]) 900 require.Error(t, err) 901 require.Contains(t, err.Error(), "JSON unmarshalling of connection") 902 require.Nil(t, con) 903 }) 904 t.Run("missing connection attribute bytes", func(t *testing.T) { 905 now := getEpochTime() 906 timestampBuf := make([]byte, timestampLength) 907 binary.BigEndian.PutUint64(timestampBuf, uint64(now)) 908 909 kh, err := ctx.kms.Get(keyID) 910 require.NoError(t, err) 911 912 signature, err := ctx.crypto.Sign(timestampBuf, kh) 913 require.NoError(t, err) 914 915 cs := &ConnectionSignature{ 916 Type: "https://didcomm.org/signature/1.0/ed25519Sha512_single", 917 SignedData: base64.URLEncoding.EncodeToString(timestampBuf), 918 SignVerKey: base64.URLEncoding.EncodeToString(pubKey), 919 Signature: base64.URLEncoding.EncodeToString(signature), 920 } 921 922 con, err := ctx.verifySignature(cs, invitation.RecipientKeys[0]) 923 require.Error(t, err) 924 require.Contains(t, err.Error(), "missing connection attribute bytes") 925 require.Nil(t, con) 926 }) 927 } 928 929 func TestResolveDIDDocFromConnection(t *testing.T) { 930 prov := getProvider(t) 931 mtps := []string{transport.MediaTypeProfileDIDCommAIP1, transport.MediaTypeRFC0019EncryptedEnvelope} 932 933 for _, mtp := range mtps { 934 t.Run(fmt.Sprintf("success with media type profile: %s", mtp), func(t *testing.T) { 935 ctx := getContext(t, &prov, mtp) 936 docIn := mockdiddoc.GetMockDIDDoc(t, false) 937 con := &Connection{ 938 DID: docIn.ID, 939 DIDDoc: docIn, 940 } 941 doc, err := ctx.resolveDidDocFromConnection(con) 942 require.NoError(t, err) 943 944 require.Equal(t, docIn.ID, doc.ID) 945 }) 946 947 t.Run(fmt.Sprintf("success - public resolution with media type profile: %s", mtp), func(t *testing.T) { 948 ctx := getContext(t, &prov, mtp) 949 docIn := mockdiddoc.GetMockDIDDoc(t, false) 950 docIn.ID = "did:remote:abc" 951 952 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveValue: docIn} 953 954 con := &Connection{ 955 DID: docIn.ID, 956 DIDDoc: docIn, 957 } 958 doc, err := ctx.resolveDidDocFromConnection(con) 959 require.NoError(t, err) 960 961 require.Equal(t, docIn.ID, doc.ID) 962 }) 963 964 t.Run(fmt.Sprintf("failure - can't do public resolution with media type profile: %s", mtp), 965 func(t *testing.T) { 966 ctx := getContext(t, &prov, mtp) 967 docIn := mockdiddoc.GetMockDIDDoc(t, false) 968 docIn.ID = "did:remote:abc" 969 970 ctx.vdRegistry = &mockvdr.MockVDRegistry{ResolveErr: fmt.Errorf("resolve error")} 971 972 con := &Connection{ 973 DID: docIn.ID, 974 DIDDoc: docIn, 975 } 976 _, err := ctx.resolveDidDocFromConnection(con) 977 require.Error(t, err) 978 require.Contains(t, err.Error(), "failed to resolve public did") 979 }) 980 981 t.Run(fmt.Sprintf("failure - missing attachment for private did with media type profile: %s", mtp), 982 func(t *testing.T) { 983 ctx := getContext(t, &prov, mtp) 984 _, err := ctx.resolveDidDocFromConnection(&Connection{DID: "did:peer:abcdefg"}) 985 require.Error(t, err) 986 require.Contains(t, err.Error(), "missing DIDDoc") 987 }) 988 989 t.Run(fmt.Sprintf("failure - can't store document locally with media type profile: %s", mtp), 990 func(t *testing.T) { 991 ctx := getContext(t, &prov, mtp) 992 993 ctx.vdRegistry = &mockvdr.MockVDRegistry{CreateErr: fmt.Errorf("create error")} 994 995 docIn := mockdiddoc.GetMockDIDDoc(t, false) 996 997 con := &Connection{ 998 DID: docIn.ID, 999 DIDDoc: docIn, 1000 } 1001 _, err := ctx.resolveDidDocFromConnection(con) 1002 require.Error(t, err) 1003 require.Contains(t, err.Error(), "failed to store provided did document") 1004 }) 1005 } 1006 } 1007 1008 func TestHandleInboundResponse(t *testing.T) { 1009 prov := getProvider(t) 1010 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 1011 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 1012 require.NoError(t, err) 1013 1014 _, err = createMockInvitation(pubKey, ctx) 1015 require.NoError(t, err) 1016 1017 t.Run("handle inbound responses get connection record error", func(t *testing.T) { 1018 response := &Response{Thread: &decorator.Thread{ID: "test"}} 1019 _, connRec, e := ctx.handleInboundResponse(response) 1020 require.Error(t, e) 1021 require.Contains(t, e.Error(), "get connection record") 1022 require.Nil(t, connRec) 1023 }) 1024 t.Run("handle inbound responses get connection record error", func(t *testing.T) { 1025 response := &Response{Thread: &decorator.Thread{ID: ""}} 1026 _, connRec, e := ctx.handleInboundResponse(response) 1027 require.Error(t, e) 1028 require.Contains(t, e.Error(), "empty bytes") 1029 require.Nil(t, connRec) 1030 }) 1031 } 1032 1033 func TestGetInvitationRecipientKey(t *testing.T) { 1034 prov := getProvider(t) 1035 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 1036 1037 t.Run("successfully getting invitation recipient key", func(t *testing.T) { 1038 invitation := &Invitation{ 1039 Type: InvitationMsgType, 1040 ID: randomString(), 1041 Label: "Bob", 1042 RecipientKeys: []string{"test"}, 1043 ServiceEndpoint: "http://alice.agent.example.com:8081", 1044 } 1045 recKey, err := ctx.getInvitationRecipientKey(invitation) 1046 require.NoError(t, err) 1047 require.Equal(t, invitation.RecipientKeys[0], recKey) 1048 }) 1049 t.Run("failed to get invitation recipient key", func(t *testing.T) { 1050 doc := mockdiddoc.GetMockDIDDoc(t, false) 1051 _, ok := diddoc.LookupService(doc, "did-communication") 1052 require.True(t, ok) 1053 1054 ctx := context{vdRegistry: &mockvdr.MockVDRegistry{ResolveValue: doc}} 1055 invitation := &Invitation{ 1056 Type: InvitationMsgType, 1057 ID: randomString(), 1058 DID: doc.ID, 1059 } 1060 1061 recKey, err := ctx.getInvitationRecipientKey(invitation) 1062 require.NoError(t, err) 1063 require.Equal(t, doc.Service[0].RecipientKeys[0], recKey) 1064 }) 1065 t.Run("failed to get invitation recipient key", func(t *testing.T) { 1066 invitation := &Invitation{ 1067 Type: InvitationMsgType, 1068 ID: randomString(), 1069 DID: "test", 1070 } 1071 _, err := ctx.getInvitationRecipientKey(invitation) 1072 require.Error(t, err) 1073 require.Contains(t, err.Error(), "get invitation recipient key: DID does not exist") 1074 }) 1075 } 1076 1077 func TestGetPublicKey(t *testing.T) { 1078 k := newKMS(t, mockstorage.NewMockStoreProvider()) 1079 t.Run("successfully getting public key by id", func(t *testing.T) { 1080 prov := protocol.MockProvider{CustomKMS: k} 1081 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 1082 doc, err := ctx.vdRegistry.Create(testMethod, nil) 1083 require.NoError(t, err) 1084 pubkey, ok := diddoc.LookupPublicKey(doc.DIDDocument.VerificationMethod[0].ID, doc.DIDDocument) 1085 require.True(t, ok) 1086 require.NotNil(t, pubkey) 1087 }) 1088 t.Run("failed to get public key", func(t *testing.T) { 1089 prov := protocol.MockProvider{CustomKMS: k} 1090 ctx := getContext(t, &prov, transport.MediaTypeRFC0019EncryptedEnvelope) 1091 doc, err := ctx.vdRegistry.Create(testMethod, nil) 1092 require.NoError(t, err) 1093 pubkey, ok := diddoc.LookupPublicKey("invalid-key", doc.DIDDocument) 1094 require.False(t, ok) 1095 require.Nil(t, pubkey) 1096 }) 1097 } 1098 1099 func TestGetDIDDocAndConnection(t *testing.T) { 1100 k := newKMS(t, mockstorage.NewMockStoreProvider()) 1101 ctx := &context{ 1102 kms: k, 1103 keyType: kms.ED25519Type, 1104 keyAgreementType: kms.X25519ECDHKWType, 1105 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 1106 } 1107 1108 t.Run("successfully getting did doc and connection for public did", func(t *testing.T) { 1109 doc := createDIDDoc(t, ctx) 1110 connRec, err := connection.NewRecorder(&protocol.MockProvider{}) 1111 require.NoError(t, err) 1112 didConnStore, err := didstore.NewConnectionStore(&protocol.MockProvider{}) 1113 require.NoError(t, err) 1114 ctx := context{ 1115 vdRegistry: &mockvdr.MockVDRegistry{ResolveValue: doc}, 1116 connectionRecorder: connRec, 1117 connectionStore: didConnStore, 1118 } 1119 didDoc, err := ctx.getMyDIDDoc(doc.ID, nil, "") 1120 require.NoError(t, err) 1121 require.NotNil(t, didDoc) 1122 }) 1123 t.Run("error getting public did doc from resolver", func(t *testing.T) { 1124 ctx := context{ 1125 vdRegistry: &mockvdr.MockVDRegistry{ResolveErr: errors.New("resolver error")}, 1126 } 1127 didDoc, err := ctx.getMyDIDDoc("did-id", nil, "") 1128 require.Error(t, err) 1129 require.Contains(t, err.Error(), "resolver error") 1130 require.Nil(t, didDoc) 1131 }) 1132 t.Run("error creating peer did", func(t *testing.T) { 1133 customKMS := newKMS(t, mockstorage.NewMockStoreProvider()) 1134 ctx := context{ 1135 kms: customKMS, 1136 vdRegistry: &mockvdr.MockVDRegistry{CreateErr: errors.New("creator error")}, 1137 routeSvc: &mockroute.MockMediatorSvc{}, 1138 keyType: kms.ED25519Type, 1139 keyAgreementType: kms.X25519ECDHKWType, 1140 } 1141 didDoc, err := ctx.getMyDIDDoc("", nil, didCommServiceType) 1142 require.Error(t, err) 1143 require.Contains(t, err.Error(), "creator error") 1144 require.Nil(t, didDoc) 1145 }) 1146 t.Run("error creating peer did with DIDCommV2 service type", func(t *testing.T) { 1147 customKMS := newKMS(t, mockstorage.NewMockStoreProvider()) 1148 ctx := context{ 1149 kms: customKMS, 1150 vdRegistry: &mockvdr.MockVDRegistry{CreateErr: errors.New("DIDCommMessaging is not supported")}, 1151 routeSvc: &mockroute.MockMediatorSvc{}, 1152 keyType: kms.ED25519Type, 1153 keyAgreementType: kms.X25519ECDHKWType, 1154 } 1155 didDoc, err := ctx.getMyDIDDoc("", nil, vdrapi.DIDCommV2ServiceType) 1156 require.Error(t, err) 1157 require.Contains(t, err.Error(), "DIDCommMessaging is not supported") 1158 require.Nil(t, didDoc) 1159 }) 1160 t.Run("error creating peer did with empty service type", func(t *testing.T) { 1161 customKMS := newKMS(t, mockstorage.NewMockStoreProvider()) 1162 ctx := context{ 1163 kms: customKMS, 1164 vdRegistry: &mockvdr.MockVDRegistry{CreateErr: errors.New("is not supported")}, 1165 routeSvc: &mockroute.MockMediatorSvc{}, 1166 keyType: kms.ED25519Type, 1167 keyAgreementType: kms.X25519ECDHKWType, 1168 } 1169 didDoc, err := ctx.getMyDIDDoc("", nil, "") 1170 require.Error(t, err) 1171 require.Contains(t, err.Error(), "is not supported") 1172 require.Nil(t, didDoc) 1173 }) 1174 1175 t.Run("successfully created peer did", func(t *testing.T) { 1176 connRec, err := connection.NewRecorder(&protocol.MockProvider{}) 1177 require.NoError(t, err) 1178 didConnStore, err := didstore.NewConnectionStore(&protocol.MockProvider{}) 1179 require.NoError(t, err) 1180 customKMS := newKMS(t, mockstorage.NewMockStoreProvider()) 1181 ctx := context{ 1182 kms: customKMS, 1183 vdRegistry: &mockvdr.MockVDRegistry{CreateValue: mockdiddoc.GetMockDIDDoc(t, false)}, 1184 connectionRecorder: connRec, 1185 connectionStore: didConnStore, 1186 routeSvc: &mockroute.MockMediatorSvc{}, 1187 keyType: kms.ED25519Type, 1188 keyAgreementType: kms.X25519ECDHKWType, 1189 } 1190 didDoc, err := ctx.getMyDIDDoc("", nil, didCommServiceType) 1191 require.NoError(t, err) 1192 require.NotNil(t, didDoc) 1193 }) 1194 t.Run("test create did doc - router service config error", func(t *testing.T) { 1195 connRec, err := connection.NewRecorder(&protocol.MockProvider{}) 1196 require.NoError(t, err) 1197 customKMS := newKMS(t, mockstorage.NewMockStoreProvider()) 1198 ctx := context{ 1199 kms: customKMS, 1200 vdRegistry: &mockvdr.MockVDRegistry{CreateValue: mockdiddoc.GetMockDIDDoc(t, false)}, 1201 connectionRecorder: connRec, 1202 routeSvc: &mockroute.MockMediatorSvc{ 1203 Connections: []string{"xyz"}, 1204 ConfigErr: errors.New("router config error"), 1205 }, 1206 } 1207 didDoc, err := ctx.getMyDIDDoc("", []string{"xyz"}, "") 1208 require.Error(t, err) 1209 require.Contains(t, err.Error(), "did doc - fetch router config") 1210 require.Nil(t, didDoc) 1211 }) 1212 1213 t.Run("test create did doc - router service config error", func(t *testing.T) { 1214 connRec, err := connection.NewRecorder(&protocol.MockProvider{}) 1215 require.NoError(t, err) 1216 customKMS := newKMS(t, mockstorage.NewMockStoreProvider()) 1217 ctx := context{ 1218 kms: customKMS, 1219 vdRegistry: &mockvdr.MockVDRegistry{ 1220 CreateValue: mockdiddoc.GetLegacyInteropMockDIDDoc(t, "1234567abcdefg", []byte("key")), 1221 }, 1222 connectionRecorder: connRec, 1223 routeSvc: &mockroute.MockMediatorSvc{ 1224 Connections: []string{"xyz"}, 1225 AddKeyErr: errors.New("router add key error"), 1226 }, 1227 keyType: kms.ED25519Type, 1228 keyAgreementType: kms.X25519ECDHKWType, 1229 } 1230 didDoc, err := ctx.getMyDIDDoc("", []string{"xyz"}, legacyDIDCommServiceType) 1231 require.Error(t, err) 1232 require.Contains(t, err.Error(), "did doc - add key to the router") 1233 require.Nil(t, didDoc) 1234 }) 1235 } 1236 1237 func TestGetVerKey(t *testing.T) { 1238 k := newKMS(t, mockstorage.NewMockStoreProvider()) 1239 ctx := &context{ 1240 kms: k, 1241 keyType: kms.ED25519Type, 1242 keyAgreementType: kms.X25519ECDHKWType, 1243 mediaTypeProfiles: []string{transport.MediaTypeRFC0019EncryptedEnvelope}, 1244 } 1245 1246 t.Run("returns verkey from explicit connection invitation", func(t *testing.T) { 1247 expected := newServiceBlock() 1248 invitation := newConnectionInvite(t, "", expected) 1249 ctx.connectionRecorder = connRecorder(t, testProvider()) 1250 1251 err := ctx.connectionRecorder.SaveInvitation(invitation.ID, invitation) 1252 require.NoError(t, err) 1253 1254 result, err := ctx.getVerKey(invitation.ID) 1255 require.NoError(t, err) 1256 require.Equal(t, expected.RecipientKeys[0], result) 1257 1258 expected = newServiceBlock() 1259 invitation = newConnectionInvite(t, "", expected) 1260 ctx.connectionRecorder = connRecorder(t, testProvider()) 1261 1262 err = ctx.connectionRecorder.SaveInvitation(invitation.ID, invitation) 1263 require.NoError(t, err) 1264 1265 result, err = ctx.getVerKey(invitation.ID) 1266 require.NoError(t, err) 1267 require.Equal(t, expected.RecipientKeys[0], result) 1268 }) 1269 1270 t.Run("returns verkey from implicit connection invitation", func(t *testing.T) { 1271 publicDID := createDIDDoc(t, ctx) 1272 ctx.connectionRecorder = connRecorder(t, testProvider()) 1273 ctx.vdRegistry = &mockvdr.MockVDRegistry{ 1274 ResolveValue: publicDID, 1275 } 1276 1277 svc, found := diddoc.LookupService(publicDID, "did-communication") 1278 require.True(t, found) 1279 1280 result, err := ctx.getVerKey(publicDID.ID) 1281 require.NoError(t, err) 1282 require.Equal(t, svc.RecipientKeys[0], result) 1283 }) 1284 1285 t.Run("wraps error from store", func(t *testing.T) { 1286 expected := errors.New("test") 1287 pr := testProvider() 1288 pr.StoreProvider = &mockstorage.MockStoreProvider{ 1289 Store: &mockstorage.MockStore{ 1290 Store: make(map[string]mockstorage.DBEntry), 1291 ErrGet: expected, 1292 }, 1293 } 1294 ctx.connectionRecorder = connRecorder(t, pr) 1295 1296 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 1297 require.NoError(t, err) 1298 1299 invitation, err := createMockInvitation(pubKey, ctx) 1300 require.NoError(t, err) 1301 1302 err = ctx.connectionRecorder.SaveInvitation(invitation.ID, invitation) 1303 require.NoError(t, err) 1304 1305 _, err = ctx.getVerKey(invitation.ID) 1306 require.Error(t, err) 1307 }) 1308 1309 t.Run("wraps error from vdr resolution", func(t *testing.T) { 1310 expected := errors.New("test") 1311 ctx.connectionRecorder = connRecorder(t, testProvider()) 1312 ctx.vdRegistry = &mockvdr.MockVDRegistry{ 1313 ResolveErr: expected, 1314 } 1315 1316 _, err := ctx.getVerKey("did:example:123") 1317 require.Error(t, err) 1318 require.True(t, errors.Is(err, expected)) 1319 }) 1320 } 1321 1322 func createDIDDoc(t *testing.T, ctx *context) *diddoc.Doc { 1323 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 1324 require.NoError(t, err) 1325 1326 return createDIDDocWithKey(pubKey) 1327 } 1328 1329 func createDIDDocWithKey(pubKey []byte) *diddoc.Doc { 1330 const ( 1331 didFormat = "did:%s:%s" 1332 didPKID = "%s#keys-%d" 1333 didServiceID = "%s#endpoint-%d" 1334 method = "test" 1335 ) 1336 1337 pub := base58.Encode(pubKey) 1338 id := fmt.Sprintf(didFormat, method, pub[:16]) 1339 pubKeyID := fmt.Sprintf(didPKID, id, 1) 1340 verPubKeyVM := diddoc.VerificationMethod{ 1341 ID: pubKeyID, 1342 Type: "Ed25519VerificationKey2018", 1343 Controller: id, 1344 Value: pubKey, 1345 } 1346 services := []diddoc.Service{ 1347 { 1348 ID: fmt.Sprintf(didServiceID, id, 1), 1349 Type: vdrapi.DIDCommServiceType, 1350 ServiceEndpoint: commonmodel.NewDIDCommV1Endpoint("http://localhost:58416"), 1351 Priority: 0, 1352 RecipientKeys: []string{pubKeyID}, 1353 }, 1354 } 1355 1356 services[0].Accept = []string{transport.MediaTypeRFC0019EncryptedEnvelope} 1357 1358 createdTime := time.Now() 1359 didDoc := &diddoc.Doc{ 1360 Context: []string{diddoc.ContextV1}, 1361 ID: id, 1362 VerificationMethod: []diddoc.VerificationMethod{verPubKeyVM}, 1363 Service: services, 1364 Created: &createdTime, 1365 Updated: &createdTime, 1366 } 1367 1368 return didDoc 1369 } 1370 1371 func getProvider(t *testing.T) protocol.MockProvider { 1372 t.Helper() 1373 1374 store := &mockstorage.MockStore{Store: make(map[string]mockstorage.DBEntry)} 1375 sProvider := mockstorage.NewCustomMockStoreProvider(store) 1376 customKMS := newKMS(t, sProvider) 1377 1378 return protocol.MockProvider{ 1379 StoreProvider: sProvider, 1380 CustomKMS: customKMS, 1381 } 1382 } 1383 1384 func getContext(t *testing.T, prov *protocol.MockProvider, mediaTypeProfile string) *context { 1385 t.Helper() 1386 1387 ctx := &context{ 1388 outboundDispatcher: prov.OutboundDispatcher(), 1389 crypto: &tinkcrypto.Crypto{}, 1390 routeSvc: &mockroute.MockMediatorSvc{}, 1391 kms: prov.KMS(), 1392 keyType: kms.ED25519Type, 1393 keyAgreementType: kms.X25519ECDHKWType, 1394 mediaTypeProfiles: []string{mediaTypeProfile}, 1395 } 1396 1397 connRec, err := connection.NewRecorder(prov) 1398 require.NoError(t, err) 1399 1400 didConnStore, err := didstore.NewConnectionStore(prov) 1401 require.NoError(t, err) 1402 1403 ctx.vdRegistry = &mockvdr.MockVDRegistry{CreateValue: createDIDDoc(t, ctx)} 1404 ctx.connectionRecorder = connRec 1405 ctx.connectionStore = didConnStore 1406 1407 return ctx 1408 } 1409 1410 func createRequest(t *testing.T, ctx *context) (*Request, error) { 1411 t.Helper() 1412 1413 _, pubKey, err := ctx.kms.CreateAndExportPubKeyBytes(kms.ED25519Type) 1414 require.NoError(t, err) 1415 1416 invitation, err := createMockInvitation(pubKey, ctx) 1417 if err != nil { 1418 return nil, err 1419 } 1420 1421 newDidDoc := createDIDDocWithKey(pubKey) 1422 1423 // Prepare connection inbound request 1424 request := &Request{ 1425 Type: RequestMsgType, 1426 ID: randomString(), 1427 Label: "Bob", 1428 Thread: &decorator.Thread{ 1429 PID: invitation.ID, 1430 }, 1431 Connection: &Connection{ 1432 DID: newDidDoc.ID, 1433 DIDDoc: newDidDoc, 1434 }, 1435 } 1436 1437 return request, nil 1438 } 1439 1440 func generateKeyPair() (string, []byte) { 1441 pubKey, privKey, err := ed25519.GenerateKey(rand.Reader) 1442 if err != nil { 1443 panic(err) 1444 } 1445 1446 return base58.Encode(pubKey[:]), privKey 1447 } 1448 1449 func createResponse(request *Request, ctx *context) (*Response, error) { 1450 doc, err := ctx.vdRegistry.Create(testMethod, nil) 1451 if err != nil { 1452 return nil, err 1453 } 1454 1455 verKey, err := ctx.getVerKey(request.Thread.PID) 1456 if err != nil { 1457 return nil, err 1458 } 1459 1460 connectionSignature, err := ctx.prepareConnectionSignature(doc.DIDDocument, verKey) 1461 if err != nil { 1462 return nil, err 1463 } 1464 1465 response := &Response{ 1466 Type: ResponseMsgType, 1467 ID: randomString(), 1468 Thread: &decorator.Thread{ 1469 ID: request.ID, 1470 }, 1471 ConnectionSignature: connectionSignature, 1472 PleaseAck: &PleaseAck{ 1473 On: []string{PlsAckOnReceipt}, 1474 }, 1475 } 1476 1477 return response, nil 1478 } 1479 1480 func createMockInvitation(pubKey []byte, ctx *context) (*Invitation, error) { 1481 invitation := &Invitation{ 1482 Type: InvitationMsgType, 1483 ID: randomString(), 1484 Label: "Bob", 1485 RecipientKeys: []string{base58.Encode(pubKey)}, 1486 ServiceEndpoint: "http://alice.agent.example.com:8081", 1487 } 1488 1489 err := ctx.connectionRecorder.SaveInvitation(invitation.ID, invitation) 1490 if err != nil { 1491 return nil, err 1492 } 1493 1494 return invitation, nil 1495 } 1496 1497 func toDIDCommMsg(t *testing.T, v interface{}) service.DIDCommMsgMap { 1498 msg, err := service.ParseDIDCommMsgMap(toBytes(t, v)) 1499 require.NoError(t, err) 1500 1501 return msg 1502 } 1503 1504 func bytesToDIDCommMsg(t *testing.T, v []byte) service.DIDCommMsg { 1505 msg, err := service.ParseDIDCommMsgMap(v) 1506 require.NoError(t, err) 1507 1508 return msg 1509 } 1510 1511 func toBytes(t *testing.T, data interface{}) []byte { 1512 t.Helper() 1513 1514 src, err := json.Marshal(data) 1515 require.NoError(t, err) 1516 1517 return src 1518 } 1519 1520 func newConnectionInvite(t *testing.T, publicDID string, svc *diddoc.Service) *Invitation { 1521 t.Helper() 1522 1523 i := &Invitation{ 1524 ID: uuid.New().String(), 1525 Type: InvitationMsgType, 1526 DID: publicDID, 1527 } 1528 1529 if svc != nil { 1530 var err error 1531 1532 i.RecipientKeys = svc.RecipientKeys 1533 i.RoutingKeys = svc.RoutingKeys 1534 1535 i.ServiceEndpoint, err = svc.ServiceEndpoint.URI() 1536 require.NoError(t, err) 1537 } 1538 1539 return i 1540 } 1541 1542 func newServiceBlock() *diddoc.Service { 1543 var ( 1544 sp commonmodel.Endpoint 1545 didCommV1RoutingKeys []string 1546 ) 1547 1548 sp = commonmodel.NewDIDCommV1Endpoint("http://test.com") 1549 didCommV1RoutingKeys = []string{uuid.New().String()} 1550 1551 svc := &diddoc.Service{ 1552 ID: uuid.New().String(), 1553 Type: didCommServiceType, 1554 RecipientKeys: []string{uuid.New().String()}, 1555 ServiceEndpoint: sp, 1556 } 1557 1558 svc.Accept = []string{transport.MediaTypeRFC0019EncryptedEnvelope} 1559 svc.RoutingKeys = didCommV1RoutingKeys 1560 1561 return svc 1562 } 1563 1564 func connRecorder(t *testing.T, p provider) *connection.Recorder { 1565 s, err := connection.NewRecorder(p) 1566 require.NoError(t, err) 1567 1568 return s 1569 } 1570 1571 func getEpochTime() int64 { 1572 return time.Now().Unix() 1573 }