Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

Commit

Permalink
refactor: A few refactoring
Browse files Browse the repository at this point in the history
- Add new legacy http header to handle legacy requests. Cover with unit tests
- Encode invitation Recipient key to base58
- Change embedded verification to referenced while creating verification methods
- Add legacy file into doc package to convert DIDdoc to raw doc. Cover with unit test
- Add handling DID id's where did method is not specified
- Add JSONBytes and ParseConnection methods to use them while handling connection data
- Change AckMsgType content to proper one
- Add method to convert array of did-keys to base58 keys
- Enable saving decryption key while handling envelope at connection-request state
- Add new InvitationRecipientKeys into connection.Record model
- Refactor requestMsgRecord, handleInboundRequest and prepareConnectionSignature methods and their unit-tests
- Save Recipient keys while handling connection request
- Use SaveDID instead SaveDIDByResolving

Signed-off-by: Abdulbois <abdulbois.tursunov@avast.com>
  • Loading branch information
Abdulbois committed Aug 18, 2022
1 parent 5e75e60 commit 117ca57
Show file tree
Hide file tree
Showing 16 changed files with 498 additions and 123 deletions.
17 changes: 14 additions & 3 deletions pkg/didcomm/dispatcher/inbound/inbound_message_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,20 @@ func (handler *MessageHandler) HandleInboundEnvelope(envelope *transport.Envelop
}

if foundService != nil {
props := make(map[string]interface{})

switch foundService.Name() {
// perf: DID exchange and legacy-connection doesn't require myDID and theirDID
case didexchange.DIDExchange, legacyconnection.LegacyConnection:
// perf: DID exchange doesn't require myDID and theirDID
case didexchange.DIDExchange:
// perf: legacy-connection requires envelope.ToKey when sending Connection Response (it will sign connection
// data with this key)
case legacyconnection.LegacyConnection:
// When type of envelope.Message is connections/request, the key which was used to decrypt message is the
// same key which was sent during invitation. If ParentThreadID is missed (Interop issues), that key will be
// used to sign connection-data while sending connection response
if msg.Type() == legacyconnection.RequestMsgType && msg.ParentThreadID() == "" {
props[legacyconnection.InvitationRecipientKey] = base58.Encode(envelope.ToKey)
}
default:
if !gotDIDs {
myDID, theirDID, err = handler.getDIDs(envelope, msg)
Expand All @@ -167,7 +178,7 @@ func (handler *MessageHandler) HandleInboundEnvelope(envelope *transport.Envelop
}
}

_, err = foundService.HandleInbound(msg, service.NewDIDCommContext(myDID, theirDID, nil))
_, err = foundService.HandleInbound(msg, service.NewDIDCommContext(myDID, theirDID, props))

return err
}
Expand Down
5 changes: 2 additions & 3 deletions pkg/didcomm/protocol/legacyconnection/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ func (ctx *context) createNewKeyAndVM(didDoc *did.Doc) error {
}

didDoc.VerificationMethod = append(didDoc.VerificationMethod, *vm)
didDoc.Authentication = append(didDoc.Authentication, *did.NewEmbeddedVerification(vm, did.Authentication))
// FIXME is KeyAgreement needed?
didDoc.KeyAgreement = append(didDoc.KeyAgreement, *did.NewEmbeddedVerification(kaVM, did.KeyAgreement))
didDoc.Authentication = append(didDoc.Authentication, *did.NewReferencedVerification(vm, did.Authentication))
didDoc.KeyAgreement = append(didDoc.KeyAgreement, *did.NewReferencedVerification(kaVM, did.KeyAgreement))

return nil
}
Expand Down
80 changes: 80 additions & 0 deletions pkg/didcomm/protocol/legacyconnection/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ SPDX-License-Identifier: Apache-2.0
package legacyconnection

import (
"encoding/json"
"errors"
"fmt"
"time"

"github.com/mitchellh/mapstructure"

"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
"github.com/hyperledger/aries-framework-go/pkg/doc/did"
)
Expand Down Expand Up @@ -76,3 +83,76 @@ type Connection struct {
DID string `json:"DID,omitempty"`
DIDDoc *did.Doc `json:"DIDDoc,omitempty"`
}

type connectionRaw struct {
DID string `json:"DID,omitempty"`
DIDDoc *rawDoc `json:"DIDDoc,omitempty"`
}

type rawDoc struct {
Context interface{} `json:"@context,omitempty"`
ID string `json:"id,omitempty"`
AlsoKnownAs []interface{} `json:"alsoKnownAs,omitempty"`
VerificationMethod []map[string]interface{} `json:"verificationMethod,omitempty"`
PublicKey []map[string]interface{} `json:"publicKey,omitempty"`
Service []map[string]interface{} `json:"service,omitempty"`
Authentication []interface{} `json:"authentication,omitempty"`
AssertionMethod []interface{} `json:"assertionMethod,omitempty"`
CapabilityDelegation []interface{} `json:"capabilityDelegation,omitempty"`
CapabilityInvocation []interface{} `json:"capabilityInvocation,omitempty"`
KeyAgreement []interface{} `json:"keyAgreement,omitempty"`
Created *time.Time `json:"created,omitempty"`
Updated *time.Time `json:"updated,omitempty"`
Proof []interface{} `json:"proof,omitempty"`
}

// JSONBytes converts Connection to json bytes.
func (con *Connection) JSONBytes() ([]byte, error) {
legacyDoc, err := con.DIDDoc.ToLegacyRawDoc()
if err != nil {
return nil, fmt.Errorf("converting to Legacy Raw Doc failed: %w", err)
}

connDoc := &rawDoc{}

_ = mapstructure.Decode(legacyDoc, connDoc) //nolint: errcheck

conRaw := connectionRaw{
DID: con.DID,
DIDDoc: connDoc,
}

byteConn, err := json.Marshal(conRaw)
if err != nil {
return nil, fmt.Errorf("JSON marshalling of connection raw failed: %w", err)
}

return byteConn, nil
}

// ParseConnection creates an instance of Connection by reading a JSON connection from bytes.
func ParseConnection(data []byte) (*Connection, error) {
raw := &connectionRaw{}

err := json.Unmarshal(data, &raw)
if err != nil {
return nil, fmt.Errorf("JSON umarshalling of connection data bytes failed: %w", err)
} else if raw == nil {
return nil, errors.New("document payload is not provided")
}

docRaw, err := json.Marshal(raw.DIDDoc)
if err != nil {
return nil, fmt.Errorf("JSON marshaling failed: %w", err)
}

doc, err := did.ParseDocument(docRaw)
if err != nil {
return nil, fmt.Errorf("parcing did document failed: %w", err)
}

return &Connection{
DID: raw.DID,
DIDDoc: doc,
}, nil
}
45 changes: 28 additions & 17 deletions pkg/didcomm/protocol/legacyconnection/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const (
// ResponseMsgType defines the legacy-connection response message type.
ResponseMsgType = PIURI + "/response"
// AckMsgType defines the legacy-connection ack message type.
AckMsgType = PIURI + "/ack"
AckMsgType = "https://didcomm.org/notification/1.0/ack"
routerConnsMetadataKey = "routerConnections"
)

Expand All @@ -55,6 +55,8 @@ const (
// TODO: https://github.com/hyperledger/aries-framework-go/issues/556 It will not be constant, this namespace
// will need to be figured with verification key
theirNSPrefix = "their"
// InvitationRecipientKey is map key constant.
InvitationRecipientKey = "invRecipientKey"
)

// message type to store data for eventing. This is retrieved during callback.
Expand Down Expand Up @@ -222,7 +224,7 @@ func retrievingRouterConnections(msg service.DIDCommMsg) []string {
}

// HandleInbound handles inbound connection messages.
func (s *Service) HandleInbound(msg service.DIDCommMsg, _ service.DIDCommContext) (string, error) {
func (s *Service) HandleInbound(msg service.DIDCommMsg, ctx service.DIDCommContext) (string, error) {
logger.Debugf("receive inbound message : %s", msg)

// fetch the thread id
Expand All @@ -238,7 +240,7 @@ func (s *Service) HandleInbound(msg service.DIDCommMsg, _ service.DIDCommContext
}

// connection record
connRecord, err := s.connectionRecord(msg)
connRecord, err := s.connectionRecord(msg, ctx)
if err != nil {
return "", fmt.Errorf("failed to fetch connection record : %w", err)
}
Expand Down Expand Up @@ -376,7 +378,7 @@ func (s *Service) handle(msg *message, aEvent chan<- service.DIDCommAction) erro
}

if connectionRecord.State == StateIDCompleted {
err = s.connectionStore.SaveDIDByResolving(connectionRecord.TheirDID, connectionRecord.RecipientKeys...)
err = s.connectionStore.SaveDID(connectionRecord.TheirDID, connectionRecord.RecipientKeys...)
if err != nil {
return fmt.Errorf("save theirDID: %w", err)
}
Expand Down Expand Up @@ -627,12 +629,12 @@ func (s *Service) CreateConnection(record *connection.Record, theirDID *did.Doc)
return s.connectionRecorder.SaveConnectionRecord(record)
}

func (s *Service) connectionRecord(msg service.DIDCommMsg) (*connection.Record, error) {
func (s *Service) connectionRecord(msg service.DIDCommMsg, ctx service.DIDCommContext) (*connection.Record, error) {
switch msg.Type() {
case InvitationMsgType:
return s.invitationMsgRecord(msg)
case RequestMsgType:
return s.requestMsgRecord(msg)
return s.requestMsgRecord(msg, ctx)
case ResponseMsgType:
return s.responseMsgRecord(msg)
case AckMsgType:
Expand Down Expand Up @@ -680,8 +682,11 @@ func (s *Service) invitationMsgRecord(msg service.DIDCommMsg) (*connection.Recor
return connRecord, nil
}

func (s *Service) requestMsgRecord(msg service.DIDCommMsg) (*connection.Record, error) {
request := Request{}
func (s *Service) requestMsgRecord(msg service.DIDCommMsg, ctx service.DIDCommContext) (*connection.Record, error) {
var (
request Request
invitationRecKey []string
)

err := msg.Decode(&request)
if err != nil {
Expand All @@ -690,22 +695,28 @@ func (s *Service) requestMsgRecord(msg service.DIDCommMsg) (*connection.Record,

invitationID := msg.ParentThreadID()
if invitationID == "" {
return nil, fmt.Errorf("missing parent thread ID on connection request with @id=%s", request.ID)
// try to retrieve key which was assigned at HandleInboundEnvelope method of inbound handler
if verKey, ok := ctx.All()[InvitationRecipientKey].(string); ok && verKey != "" {
invitationRecKey = append(invitationRecKey, verKey)
} else {
return nil, fmt.Errorf("missing parent thread ID on connection request with @id=%s", request.ID)
}
}

if request.Connection == nil {
return nil, fmt.Errorf("missing connection field on connection request with @id=%s", request.ID)
}

connRecord := &connection.Record{
TheirLabel: request.Label,
ConnectionID: generateRandomID(),
ThreadID: request.ID,
State: stateNameNull,
TheirDID: request.Connection.DID,
InvitationID: invitationID,
Namespace: theirNSPrefix,
DIDCommVersion: service.V1,
TheirLabel: request.Label,
ConnectionID: generateRandomID(),
ThreadID: request.ID,
State: stateNameNull,
TheirDID: request.Connection.DID,
InvitationID: invitationID,
InvitationRecipientKeys: invitationRecKey,
Namespace: theirNSPrefix,
DIDCommVersion: service.V1,
}

if !strings.HasPrefix(connRecord.TheirDID, "did") {
Expand Down
16 changes: 8 additions & 8 deletions pkg/didcomm/protocol/legacyconnection/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ func TestService_Handle_Invitee(t *testing.T) {
require.NoError(t, err)
require.Equal(t, invitation.ServiceEndpoint, uri)

connectionSignature, err := ctx.prepareConnectionSignature(doc.DIDDocument, invitation.ID)
connectionSignature, err := ctx.prepareConnectionSignature(doc.DIDDocument, invitation.RecipientKeys[0])
require.NoError(t, err)

// Bob replies with a Response
Expand Down Expand Up @@ -578,7 +578,7 @@ func TestService_Accept(t *testing.T) {
require.Equal(t, true, s.Accept("https://didcomm.org/connections/1.0/invitation"))
require.Equal(t, true, s.Accept("https://didcomm.org/connections/1.0/request"))
require.Equal(t, true, s.Accept("https://didcomm.org/connections/1.0/response"))
require.Equal(t, true, s.Accept("https://didcomm.org/connections/1.0/ack"))
require.Equal(t, true, s.Accept("https://didcomm.org/notification/1.0/ack"))
require.Equal(t, false, s.Accept("unsupported msg type"))
}

Expand Down Expand Up @@ -1215,7 +1215,7 @@ func TestConnectionRecord(t *testing.T) {
require.NoError(t, err)

conn, err := svc.connectionRecord(generateRequestMsgPayload(t, &protocol.MockProvider{},
randomString(), randomString()))
randomString(), randomString()), service.EmptyDIDCommContext())
require.NoError(t, err)
require.NotNil(t, conn)

Expand All @@ -1227,7 +1227,7 @@ func TestConnectionRecord(t *testing.T) {
msg, err := service.ParseDIDCommMsgMap(requestBytes)
require.NoError(t, err)

_, err = svc.connectionRecord(msg)
_, err = svc.connectionRecord(msg, service.EmptyDIDCommContext())
require.Error(t, err)
require.Contains(t, err.Error(), "invalid message type")
}
Expand Down Expand Up @@ -1315,7 +1315,7 @@ func TestRequestRecord(t *testing.T) {

didcommMsg := generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), uuid.New().String())
require.NotEmpty(t, didcommMsg.ParentThreadID())
conn, err := svc.requestMsgRecord(didcommMsg)
conn, err := svc.requestMsgRecord(didcommMsg, service.EmptyDIDCommContext())
require.NoError(t, err)
require.NotNil(t, conn)
require.Equal(t, didcommMsg.ParentThreadID(), conn.InvitationID)
Expand All @@ -1333,7 +1333,7 @@ func TestRequestRecord(t *testing.T) {
require.NotEmpty(t, didcommMsg.ParentThreadID())
delete(didcommMsg, "connection")

_, err = svc.requestMsgRecord(didcommMsg)
_, err = svc.requestMsgRecord(didcommMsg, service.EmptyDIDCommContext())
require.Error(t, err)
require.Contains(t, err.Error(), "missing connection field")
})
Expand All @@ -1351,7 +1351,7 @@ func TestRequestRecord(t *testing.T) {
require.NoError(t, err)

_, err = svc.requestMsgRecord(generateRequestMsgPayload(t, &protocol.MockProvider{},
randomString(), uuid.New().String()))
randomString(), uuid.New().String()), service.EmptyDIDCommContext())
require.Error(t, err)
require.Contains(t, err.Error(), "save connection record")
})
Expand All @@ -1367,7 +1367,7 @@ func TestRequestRecord(t *testing.T) {
parentThreadID := ""
didcommMsg := generateRequestMsgPayload(t, &protocol.MockProvider{}, randomString(), parentThreadID)
require.Empty(t, didcommMsg.ParentThreadID())
_, err = svc.requestMsgRecord(didcommMsg)
_, err = svc.requestMsgRecord(didcommMsg, service.EmptyDIDCommContext())
require.Error(t, err)
})
}
Expand Down

0 comments on commit 117ca57

Please sign in to comment.