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

Commit

Permalink
Protocols can use DIDs to identify the agents they communicate with.
Browse files Browse the repository at this point in the history
Outbound: create a Destination struct from a DID using helper functions,
so an agent can provide the DID of the target.
- One function resolves a DID using your VDRI
- The other uses a DID doc if it's already available

Inbound: receive the DID of the sender as a parameter to the message
handler, if the sender has a DID doc in your VDRI.

Signed-off-by: Filip Burlacu <[email protected]>
  • Loading branch information
Filip Burlacu committed Dec 10, 2019
1 parent 55e25af commit 2374d91
Show file tree
Hide file tree
Showing 51 changed files with 1,132 additions and 553 deletions.
6 changes: 4 additions & 2 deletions pkg/client/didexchange/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/google/uuid"

"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/didconnection"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange"
"github.com/hyperledger/aries-framework-go/pkg/kms"
Expand Down Expand Up @@ -40,6 +41,7 @@ type provider interface {
InboundTransportEndpoint() string
StorageProvider() storage.Provider
TransientStorageProvider() storage.Provider
DIDConnectionStore() didconnection.Store
}

// Client enable access to didexchange api
Expand Down Expand Up @@ -94,7 +96,7 @@ func New(ctx provider) (*Client, error) {
didexchangeSvc: didexchangeSvc,
kms: ctx.KMS(),
inboundTransportEndpoint: ctx.InboundTransportEndpoint(),
connectionStore: didexchange.NewConnectionRecorder(transientStore, store),
connectionStore: didexchange.NewConnectionRecorder(transientStore, store, ctx.DIDConnectionStore()),
}, nil
}

Expand Down Expand Up @@ -157,7 +159,7 @@ func (c *Client) HandleInvitation(invitation *Invitation) (string, error) {
return "", fmt.Errorf("failed to create DIDCommMsg: %w", err)
}

connectionID, err := c.didexchangeSvc.HandleInbound(msg)
connectionID, err := c.didexchangeSvc.HandleInbound(msg, "", "")
if err != nil {
return "", fmt.Errorf("failed from didexchange service handle: %w", err)
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/client/didexchange/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func TestClient_QueryConnectionByID(t *testing.T) {
require.NoError(t, err)
require.NoError(t, err)
require.NoError(t, transientStore.Put("conn_id1", connBytes))
c := didexchange.NewConnectionRecorder(transientStore, store)
c := didexchange.NewConnectionRecorder(transientStore, store, nil)
result, err := c.GetConnectionRecord(connID)
require.NoError(t, err)
require.Equal(t, "complete", result.State)
Expand All @@ -219,7 +219,7 @@ func TestClient_QueryConnectionByID(t *testing.T) {
connRec := &didexchange.ConnectionRecord{ConnectionID: connID, ThreadID: threadID, State: "complete"}
connBytes, err := json.Marshal(connRec)
require.NoError(t, err)
c := didexchange.NewConnectionRecorder(transientStore, store)
c := didexchange.NewConnectionRecorder(transientStore, store, nil)
require.NoError(t, transientStore.Put("conn_id1", connBytes))
_, err = c.GetConnectionRecord(connID)
require.Error(t, err)
Expand All @@ -234,7 +234,7 @@ func TestClient_QueryConnectionByID(t *testing.T) {
transientStore := mockstore.MockStore{ErrGet: storage.ErrDataNotFound}
store := mockstore.MockStore{}
require.NoError(t, err)
c := didexchange.NewConnectionRecorder(&transientStore, &store)
c := didexchange.NewConnectionRecorder(&transientStore, &store, nil)
_, err = c.GetConnectionRecord(connID)
require.Error(t, err)
require.True(t, errors.Is(err, storage.ErrDataNotFound))
Expand Down Expand Up @@ -589,7 +589,7 @@ func TestServiceEvents(t *testing.T) {

msg, err := service.NewDIDCommMsg(request)
require.NoError(t, err)
_, err = didExSvc.HandleInbound(msg)
_, err = didExSvc.HandleInbound(msg, "", "")
require.NoError(t, err)

select {
Expand Down Expand Up @@ -679,7 +679,7 @@ func TestAcceptExchangeRequest(t *testing.T) {

msg, err := service.NewDIDCommMsg(request)
require.NoError(t, err)
_, err = didExSvc.HandleInbound(msg)
_, err = didExSvc.HandleInbound(msg, "", "")
require.NoError(t, err)

select {
Expand Down Expand Up @@ -760,7 +760,7 @@ func TestAcceptInvitation(t *testing.T) {

msg, svcErr := service.NewDIDCommMsg(invitation)
require.NoError(t, svcErr)
_, err = didExSvc.HandleInbound(msg)
_, err = didExSvc.HandleInbound(msg, "", "")
require.NoError(t, err)

select {
Expand Down
18 changes: 18 additions & 0 deletions pkg/didcomm/common/didconnection/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package didconnection

// Store stores DIDs indexed by public key, so agents can find the DID associated with a given key.
type Store interface {
// SaveDID saves a DID indexed by the given public keys to the Store
SaveDID(did string, keys ...string) error
// GetDID gets the DID stored under the given key
GetDID(key string) (string, error)
// SaveDIDConnection saves a connection between this agent's DID and another agent's DID
SaveDIDConnection(myDID, theirDID string, theirKeys []string) error
// SaveDIDFromDoc resolves a DID using the VDR then saves the map from keys -> did
SaveDIDFromDoc(did, serviceType, keyType string) error
}
121 changes: 121 additions & 0 deletions pkg/didcomm/common/didconnection/didconnection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package didconnection

import (
"encoding/json"
"fmt"

diddoc "github.com/hyperledger/aries-framework-go/pkg/doc/did"
"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdri"
"github.com/hyperledger/aries-framework-go/pkg/storage"
)

// BaseDIDConnectionStore stores DIDs indexed by key
type BaseDIDConnectionStore struct {
store storage.Store
vdr vdri.Registry
}

type didRecord struct {
DID string `json:"did,omitempty"`
}

type provider interface {
StorageProvider() storage.Provider
VDRIRegistry() vdri.Registry
}

// New returns a new did lookup Store
func New(ctx provider) (*BaseDIDConnectionStore, error) {
store, err := ctx.StorageProvider().OpenStore("con-store")
if err != nil {
return nil, err
}

return &BaseDIDConnectionStore{store: store, vdr: ctx.VDRIRegistry()}, nil
}

// saveDID saves a DID, indexed using the given public key
func (c *BaseDIDConnectionStore) saveDID(did, key string) error {
data := didRecord{
DID: did,
}

bytes, err := json.Marshal(data)
if err != nil {
return err
}

return c.store.Put(key, bytes)
}

// SaveDID saves a DID, indexed using the given public keys
func (c *BaseDIDConnectionStore) SaveDID(did string, keys ...string) error {
for _, key := range keys {
err := c.saveDID(did, key)
if err != nil {
return fmt.Errorf("saving DID in did map: %w", err)
}
}

return nil
}

// SaveDIDFromDoc resolves a DID using the VDR then saves the map from keys -> did
func (c *BaseDIDConnectionStore) SaveDIDFromDoc(did, serviceType, keyType string) error {
doc, err := c.vdr.Resolve(did)
if err != nil {
return err
}

keys, err := diddoc.GetRecipientKeys(doc, serviceType, keyType)
if err != nil {
return err
}

err = c.SaveDID(did, keys...)
if err != nil {
return err
}

return nil
}

// GetDID gets the DID stored under the given key
func (c *BaseDIDConnectionStore) GetDID(key string) (string, error) {
bytes, err := c.store.Get(key)
if err != nil {
return "", err
}

var record didRecord

err = json.Unmarshal(bytes, &record)
if err != nil {
return "", err
}

return record.DID, nil
}

// SaveDIDConnection saves a connection between this agent's did and another agent
func (c *BaseDIDConnectionStore) SaveDIDConnection(myDID, theirDID string, theirKeys []string) error {
// map their pub keys -> their DID
err := c.SaveDID(theirDID, theirKeys...)
if err != nil {
return err
}

// map their DID -> my DID
err = c.SaveDID(myDID, theirDID)
if err != nil {
return fmt.Errorf("save DID in did map: %w", err)
}

return nil
}
67 changes: 67 additions & 0 deletions pkg/didcomm/common/didconnection/didconnection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package didconnection

import (
"testing"

"github.com/stretchr/testify/require"

vdriapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdri"
mockdiddoc "github.com/hyperledger/aries-framework-go/pkg/internal/mock/diddoc"
mockstorage "github.com/hyperledger/aries-framework-go/pkg/internal/mock/storage"
mockvdri "github.com/hyperledger/aries-framework-go/pkg/internal/mock/vdri"
"github.com/hyperledger/aries-framework-go/pkg/storage"
)

type ctx struct {
store storage.Provider
vdr vdriapi.Registry
}

func (c *ctx) StorageProvider() storage.Provider {
return c.store
}

func (c *ctx) VDRIRegistry() vdriapi.Registry {
return c.vdr
}

func TestBaseConnectionStore(t *testing.T) {
prov := ctx{
store: mockstorage.NewMockStoreProvider(),
vdr: &mockvdri.MockVDRIRegistry{
CreateErr: nil,
CreateValue: mockdiddoc.GetMockDIDDoc(),
MemStore: nil,
PutErr: nil,
ResolveErr: nil,
ResolveValue: mockdiddoc.GetMockDIDDoc(),
},
}

connStore, err := New(&prov)
require.NoError(t, err)

err = connStore.SaveDID("did:abcde", "abcde")
require.NoError(t, err)

did, err := connStore.GetDID("abcde")
require.NoError(t, err)
require.Equal(t, "did:abcde", did)

wrong, err := connStore.GetDID("fhtagn")
require.EqualError(t, err, storage.ErrDataNotFound.Error())
require.Equal(t, "", wrong)

err = connStore.store.Put("bad-data", []byte("aaooga"))
require.NoError(t, err)

_, err = connStore.GetDID("bad-data")
require.Error(t, err)
require.Contains(t, err.Error(), "invalid character")
}
50 changes: 50 additions & 0 deletions pkg/didcomm/common/service/destination.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package service

import (
diddoc "github.com/hyperledger/aries-framework-go/pkg/doc/did"
"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdri"
)

// Destination provides the recipientKeys, routingKeys, and serviceEndpoint for an outbound message.
// Can be populated from an Invitation or DIDDoc.
type Destination struct {
RecipientKeys []string
ServiceEndpoint string
RoutingKeys []string
TransportReturnRoute string
}

// GetDestination constructs a Destination struct based on the given DID and parameters
// It resolves the DID using the given VDR, and collects relevant data from the resolved DIDDoc.
func GetDestination(did, serviceType, keyType string, vdr vdri.Registry) (*Destination, error) {
didDoc, err := vdr.Resolve(did)
if err != nil {
return nil, err
}

return MakeDestination(didDoc, serviceType, keyType)
}

// MakeDestination makes a Destination object from a DID Doc, following the given parameters.
func MakeDestination(didDoc *diddoc.Doc, serviceType, keyType string) (*Destination, error) {
didCommService, err := diddoc.GetDIDCommService(didDoc, serviceType)
if err != nil {
return nil, err
}

recipientKeys, err := diddoc.GetRecipientKeys(didDoc, serviceType, keyType)
if err != nil {
return nil, err
}

return &Destination{
RecipientKeys: recipientKeys,
ServiceEndpoint: didCommService.ServiceEndpoint,
}, nil
}
Loading

0 comments on commit 2374d91

Please sign in to comment.