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

Commit

Permalink
feat: protocols can send/receive messages to/from DIDs
Browse files Browse the repository at this point in the history
Outbound: SendToDID resolves the target DID, and sends the message
to the destination specified in the DID doc.
Inbound: HandleInbound receives the DID of the sender and the DID
you used to decrypt the message.

Signed-off-by: Filip Burlacu <[email protected]>
  • Loading branch information
Filip Burlacu committed Dec 20, 2019
1 parent c1ad21e commit 5d321d4
Show file tree
Hide file tree
Showing 34 changed files with 586 additions and 441 deletions.
15 changes: 10 additions & 5 deletions pkg/didcomm/common/didconnection/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@ SPDX-License-Identifier: Apache-2.0

package didconnection

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

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

// 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
// SaveDIDByResolving resolves a DID using the VDR then saves the map from keys -> did
SaveDIDByResolving(did, serviceType, keyType string) error
SaveDIDByResolving(did string, keys ...string) error
// SaveDIDFromDoc saves a map from keys -> did for a did doc
SaveDIDFromDoc(doc *diddoc.Doc, serviceType, keyType string) error
SaveDIDFromDoc(doc *diddoc.Doc) error
}

// ErrNotFound signals that the entry for the given DID and key is not present in the store.
var ErrNotFound = errors.New("did not found under given key")
78 changes: 21 additions & 57 deletions pkg/didcomm/common/didconnection/didconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
"github.com/hyperledger/aries-framework-go/pkg/storage"
)

// BaseDIDConnectionStore stores DIDs indexed by key
type BaseDIDConnectionStore struct {
// ConnectionStore stores DIDs indexed by key
type ConnectionStore struct {
store storage.Store
vdr vdri.Registry
}
Expand All @@ -32,17 +32,17 @@ type provider interface {
}

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

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

// saveDID saves a DID, indexed using the given public key
func (c *BaseDIDConnectionStore) saveDID(did, key string) error {
func (c *ConnectionStore) saveDID(did, key string) error {
data := didRecord{
DID: did,
}
Expand All @@ -56,7 +56,7 @@ func (c *BaseDIDConnectionStore) saveDID(did, key string) error {
}

// SaveDID saves a DID, indexed using the given public keys
func (c *BaseDIDConnectionStore) SaveDID(did string, keys ...string) error {
func (c *ConnectionStore) SaveDID(did string, keys ...string) error {
for _, key := range keys {
err := c.saveDID(did, key)
if err != nil {
Expand All @@ -68,29 +68,34 @@ func (c *BaseDIDConnectionStore) SaveDID(did string, keys ...string) error {
}

// SaveDIDFromDoc saves a map from a did doc's keys to the did
func (c *BaseDIDConnectionStore) SaveDIDFromDoc(doc *diddoc.Doc, serviceType, keyType string) error {
keys, ok := diddoc.LookupRecipientKeys(doc, serviceType, keyType)
if !ok {
return fmt.Errorf("getting DID doc keys")
func (c *ConnectionStore) SaveDIDFromDoc(doc *diddoc.Doc) error {
var keys []string
for i := range doc.PublicKey {
keys = append(keys, string(doc.PublicKey[i].Value))
}

return c.SaveDID(doc.ID, keys...)
}

// SaveDIDByResolving resolves a DID using the VDR then saves the map from keys -> did
func (c *BaseDIDConnectionStore) SaveDIDByResolving(did, serviceType, keyType string) error {
// keys: fallback keys in case the DID can't be resolved
func (c *ConnectionStore) SaveDIDByResolving(did string, keys ...string) error {
doc, err := c.vdr.Resolve(did)
if err != nil {
if errors.Is(err, vdri.ErrNotFound) {
return c.SaveDID(did, keys...)
} else if err != nil {
return err
}

return c.SaveDIDFromDoc(doc, serviceType, keyType)
return c.SaveDIDFromDoc(doc)
}

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

Expand All @@ -103,44 +108,3 @@ func (c *BaseDIDConnectionStore) GetDID(key string) (string, error) {

return record.DID, nil
}

func (c *BaseDIDConnectionStore) resolvePublicKeys(id string) ([]string, error) {
doc, err := c.vdr.Resolve(id)
if err != nil {
return nil, err
}

var keys []string

for i := range doc.PublicKey {
keys = append(keys, string(doc.PublicKey[i].Value))
}

return keys, nil
}

// SaveDIDConnection saves a connection between this agent's did and another agent
func (c *BaseDIDConnectionStore) SaveDIDConnection(myDID, theirDID string, theirKeys []string) error {
var keys []string

keys, err := c.resolvePublicKeys(theirDID)
if errors.Is(err, vdri.ErrNotFound) {
keys = theirKeys
} else if err != nil {
return err
}

// map their pub keys -> their DID
err = c.SaveDID(theirDID, keys...)
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
}
69 changes: 4 additions & 65 deletions pkg/didcomm/common/didconnection/didconnection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestBaseConnectionStore(t *testing.T) {
require.Equal(t, "did:abcde", didVal)

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

err = connStore.store.Put("bad-data", []byte("aaooga"))
Expand All @@ -97,42 +97,19 @@ func TestBaseConnectionStore(t *testing.T) {
require.Contains(t, err.Error(), "invalid character")
})

ed25519KeyType := "Ed25519VerificationKey2018"
didCommServiceType := "did-communication"

t.Run("SaveDIDFromDoc", func(t *testing.T) {
connStore, err := New(&prov)
require.NoError(t, err)

err = connStore.SaveDIDFromDoc(
mockdiddoc.GetMockDIDDoc(),
didCommServiceType,
"bad")
require.Error(t, err)
require.Contains(t, err.Error(), "getting DID doc keys")

err = connStore.SaveDIDFromDoc(
mockdiddoc.GetMockDIDDoc(),
"bad",
ed25519KeyType)
require.Error(t, err)
require.Contains(t, err.Error(), "getting DID doc keys")

err = connStore.SaveDIDFromDoc(
mockdiddoc.GetMockDIDDoc(),
didCommServiceType,
ed25519KeyType)
err = connStore.SaveDIDFromDoc(mockdiddoc.GetMockDIDDoc())
require.NoError(t, err)
})

t.Run("SaveDIDByResolving success", func(t *testing.T) {
cs, err := New(&prov)
require.NoError(t, err)

err = cs.SaveDIDByResolving(
mockdiddoc.GetMockDIDDoc().ID,
didCommServiceType,
ed25519KeyType)
err = cs.SaveDIDByResolving(mockdiddoc.GetMockDIDDoc().ID)
require.NoError(t, err)
})

Expand All @@ -145,46 +122,8 @@ func TestBaseConnectionStore(t *testing.T) {
cs, err := New(&prov)
require.NoError(t, err)

err = cs.SaveDIDByResolving("did", "abc", "def")
err = cs.SaveDIDByResolving("did")
require.Error(t, err)
require.Contains(t, err.Error(), "resolve error")
})

t.Run("SaveDIDConnection success", func(t *testing.T) {
prov := ctx{
vdr: &mockvdri.MockVDRIRegistry{
ResolveValue: mockdiddoc.GetMockDIDDoc(),
},
store: mockstorage.NewMockStoreProvider(),
}

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

err = cs.SaveDIDConnection("mine", mockdiddoc.GetMockDIDDoc().ID, []string{"abc", "def"})
require.NoError(t, err)
})

t.Run("SaveDIDConnection error", func(t *testing.T) {
prov := ctx{
vdr: &mockvdri.MockVDRIRegistry{
ResolveValue: mockdiddoc.GetMockDIDDoc(),
},
store: &mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{
Store: map[string][]byte{},
ErrPut: fmt.Errorf("store error"),
}},
}

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

err = cs.SaveDIDConnection("mine", "theirs", []string{"abc", "def"})
require.Error(t, err)
require.Contains(t, err.Error(), "store error")

err = cs.SaveDIDConnection("mine", "theirs", nil)
require.Error(t, err)
require.Contains(t, err.Error(), "saving DID in did map")
})
}
3 changes: 2 additions & 1 deletion pkg/didcomm/common/service/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ type Destination struct {

const (
didCommServiceType = "did-communication"
ed25519KeyType = "Ed25519VerificationKey2018"
// TODO: hardcoded key type https://github.com/hyperledger/aries-framework-go/issues/1008
ed25519KeyType = "Ed25519VerificationKey2018"
)

// GetDestination constructs a Destination struct based on the given DID and parameters
Expand Down
11 changes: 8 additions & 3 deletions pkg/didcomm/common/transport/envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ SPDX-License-Identifier: Apache-2.0

package transport

// Envelope contain msg, FromVerKey and ToVerKeys
// Envelope holds message data and metadata for inbound and outbound messaging
type Envelope struct {
Message []byte
FromVerKey string
ToVerKeys []string
FromVerKey []byte
// ToVerKeys stores string (base58) verification keys for an outbound message
ToVerKeys []string
// ToVerKey holds the key that was used to decrypt an inbound message
ToVerKey []byte
FromDID string
ToDID string
}
27 changes: 24 additions & 3 deletions pkg/didcomm/dispatcher/outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,29 @@ import (
"fmt"
"strings"

"github.com/btcsuite/btcutil/base58"

"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
commontransport "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/transport"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdri"
)

// provider interface for outbound ctx
type provider interface {
Packager() commontransport.Packager
OutboundTransports() []transport.OutboundTransport
TransportReturnRoute() string
VDRIRegistry() vdri.Registry
}

// OutboundDispatcher dispatch msgs to destination
type OutboundDispatcher struct {
outboundTransports []transport.OutboundTransport
packager commontransport.Packager
transportReturnRoute string
vdRegistry vdri.Registry
}

// NewOutbound return new dispatcher outbound instance
Expand All @@ -37,12 +42,28 @@ func NewOutbound(prov provider) *OutboundDispatcher {
outboundTransports: prov.OutboundTransports(),
packager: prov.Packager(),
transportReturnRoute: prov.TransportReturnRoute(),
vdRegistry: prov.VDRIRegistry(),
}
}

// SendToDID msg
// SendToDID sends a message from myDID to the agent who owns theirDID
func (o *OutboundDispatcher) SendToDID(msg interface{}, myDID, theirDID string) error {
return nil
dest, err := service.GetDestination(theirDID, o.vdRegistry)
if err != nil {
return err
}

src, err := service.GetDestination(myDID, o.vdRegistry)
if err != nil {
return err
}

// We get at least one recipient key, so we can use the first one
// (right now, with only one key type used for sending)
// TODO: relies on hardcoded key type
key := src.RecipientKeys[0]

return o.Send(msg, key, dest)
}

// Send sends the message after packing with the sender key and recipient keys.
Expand Down Expand Up @@ -79,7 +100,7 @@ func (o *OutboundDispatcher) Send(msg interface{}, senderVerKey string, des *ser
}

packedMsg, err := o.packager.PackMessage(
&commontransport.Envelope{Message: req, FromVerKey: senderVerKey, ToVerKeys: des.RecipientKeys})
&commontransport.Envelope{Message: req, FromVerKey: base58.Decode(senderVerKey), ToVerKeys: des.RecipientKeys})
if err != nil {
return fmt.Errorf("failed to pack msg: %w", err)
}
Expand Down
Loading

0 comments on commit 5d321d4

Please sign in to comment.