github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/protocol/mediator/service.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package mediator
     8  
     9  import (
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"sync"
    14  	"time"
    15  
    16  	"github.com/cenkalti/backoff/v4"
    17  	"github.com/google/uuid"
    18  
    19  	"github.com/hyperledger/aries-framework-go/pkg/common/log"
    20  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/model"
    21  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
    22  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher"
    23  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
    24  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/messagepickup"
    25  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
    26  	"github.com/hyperledger/aries-framework-go/pkg/doc/util/kmsdidkey"
    27  	"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
    28  	"github.com/hyperledger/aries-framework-go/pkg/internal/logutil"
    29  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    30  	"github.com/hyperledger/aries-framework-go/pkg/store/connection"
    31  	"github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint"
    32  	"github.com/hyperledger/aries-framework-go/spi/storage"
    33  )
    34  
    35  var logger = log.New("aries-framework/route/service")
    36  
    37  // constants for route coordination spec types.
    38  const (
    39  	// Coordination route coordination protocol.
    40  	Coordination = "coordinatemediation"
    41  
    42  	// RouteCoordinationSpec defines the route coordination spec.
    43  	CoordinationSpec = "https://didcomm.org/coordinatemediation/1.0/"
    44  
    45  	// RouteRequestMsgType defines the route coordination request message type.
    46  	RequestMsgType = CoordinationSpec + "mediate-request"
    47  
    48  	// RouteGrantMsgType defines the route coordination request grant message type.
    49  	GrantMsgType = CoordinationSpec + "mediate-grant"
    50  
    51  	// KeyListUpdateMsgType defines the route coordination key list update message type.
    52  	KeylistUpdateMsgType = CoordinationSpec + "keylist_update"
    53  
    54  	// KeyListUpdateResponseMsgType defines the route coordination key list update message response type.
    55  	KeylistUpdateResponseMsgType = CoordinationSpec + "keylist_update_response"
    56  )
    57  
    58  // constants for key list update processing
    59  // https://github.com/hyperledger/aries-rfcs/tree/master/features/0211-route-coordination#keylist-update
    60  const (
    61  	// add key to the store.
    62  	add = "add"
    63  
    64  	// remove key from the store.
    65  	remove = "remove"
    66  
    67  	// server error while storing the key.
    68  	serverError = "server_error"
    69  
    70  	// key save success.
    71  	success = "success"
    72  )
    73  
    74  const (
    75  	// data key to store router connection ID.
    76  	routeConnIDDataKey = "route_connID_%s"
    77  
    78  	// data key to store router config.
    79  	routeConfigDataKey = "route_config_%s"
    80  
    81  	routeGrantKey = "grant_%s"
    82  )
    83  
    84  const (
    85  	updateTimeout = 10 * time.Second
    86  )
    87  
    88  // ErrConnectionNotFound connection not found error.
    89  var ErrConnectionNotFound = errors.New("connection not found")
    90  
    91  // ErrRouterNotRegistered router not registered error.
    92  var ErrRouterNotRegistered = errors.New("router not registered")
    93  
    94  // provider contains dependencies for the Routing protocol and is typically created by using aries.Context().
    95  type provider interface {
    96  	OutboundDispatcher() dispatcher.Outbound
    97  	StorageProvider() storage.Provider
    98  	ProtocolStateStorageProvider() storage.Provider
    99  	RouterEndpoint() string
   100  	KMS() kms.KeyManager
   101  	VDRegistry() vdr.Registry
   102  	Service(id string) (interface{}, error)
   103  	KeyAgreementType() kms.KeyType
   104  	MediaTypeProfiles() []string
   105  }
   106  
   107  // ClientOption configures the route client.
   108  type ClientOption func(opts *ClientOptions)
   109  
   110  // ClientOptions holds options for the router client.
   111  type ClientOptions struct {
   112  	Timeout time.Duration
   113  }
   114  
   115  // Options is a container for route protocol options.
   116  type Options struct {
   117  	ServiceEndpoint string
   118  	RoutingKeys     []string
   119  }
   120  
   121  type callback struct {
   122  	msg      service.DIDCommMsg
   123  	myDID    string
   124  	theirDID string
   125  	options  *Options
   126  	err      error
   127  }
   128  
   129  type routerConnectionEntry struct {
   130  	ConnectionID   string          `json:"connectionID"`
   131  	DIDCommVersion service.Version `json:"didcomm_version,omitempty"`
   132  }
   133  
   134  type connections interface {
   135  	GetConnectionIDByDIDs(string, string) (string, error)
   136  	GetConnectionRecord(string) (*connection.Record, error)
   137  	GetConnectionRecordByDIDs(myDID string, theirDID string) (*connection.Record, error)
   138  }
   139  
   140  // Service for Route Coordination protocol.
   141  // https://github.com/hyperledger/aries-rfcs/tree/master/features/0211-route-coordination
   142  type Service struct {
   143  	service.Action
   144  	service.Message
   145  	routeStore           storage.Store
   146  	connectionLookup     connections
   147  	outbound             dispatcher.Outbound
   148  	endpoint             string
   149  	kms                  kms.KeyManager
   150  	vdRegistry           vdr.Registry
   151  	keylistUpdateMap     map[string]chan *KeylistUpdateResponse
   152  	keylistUpdateMapLock sync.RWMutex
   153  	callbacks            chan *callback
   154  	messagePickupSvc     messagepickup.ProtocolService
   155  	keyAgreementType     kms.KeyType
   156  	mediaTypeProfiles    []string
   157  	initialized          bool
   158  }
   159  
   160  // New return route coordination service.
   161  func New(prov provider) (*Service, error) {
   162  	svc := Service{}
   163  
   164  	err := svc.Initialize(prov)
   165  	if err != nil {
   166  		return nil, err
   167  	}
   168  
   169  	return &svc, nil
   170  }
   171  
   172  // Initialize initializes the Service. If Initialize succeeds, any further call is a no-op.
   173  func (s *Service) Initialize(p interface{}) error {
   174  	if s.initialized {
   175  		return nil
   176  	}
   177  
   178  	prov, ok := p.(provider)
   179  	if !ok {
   180  		return fmt.Errorf("expected provider of type `%T`, got type `%T`", provider(nil), p)
   181  	}
   182  
   183  	store, err := prov.StorageProvider().OpenStore(Coordination)
   184  	if err != nil {
   185  		return fmt.Errorf("open route coordination store : %w", err)
   186  	}
   187  
   188  	err = prov.StorageProvider().SetStoreConfig(Coordination,
   189  		storage.StoreConfiguration{TagNames: []string{routeConnIDDataKey}})
   190  	if err != nil {
   191  		return fmt.Errorf("failed to set store configuration: %w", err)
   192  	}
   193  
   194  	connectionLookup, err := connection.NewLookup(prov)
   195  	if err != nil {
   196  		return err
   197  	}
   198  
   199  	mp, err := prov.Service(messagepickup.MessagePickup)
   200  	if err != nil {
   201  		return err
   202  	}
   203  
   204  	messagePickupSvc, ok := mp.(messagepickup.ProtocolService)
   205  	if !ok {
   206  		return errors.New("cast service to message pickup service failed")
   207  	}
   208  
   209  	s.routeStore = store
   210  	s.outbound = prov.OutboundDispatcher()
   211  	s.endpoint = prov.RouterEndpoint()
   212  	s.kms = prov.KMS()
   213  	s.vdRegistry = prov.VDRegistry()
   214  	s.connectionLookup = connectionLookup
   215  	s.keylistUpdateMap = make(map[string]chan *KeylistUpdateResponse)
   216  	s.callbacks = make(chan *callback)
   217  	s.messagePickupSvc = messagePickupSvc
   218  	s.keyAgreementType = prov.KeyAgreementType()
   219  	s.mediaTypeProfiles = prov.MediaTypeProfiles()
   220  
   221  	logger.Debugf("default endpoint: %s", s.endpoint)
   222  
   223  	go s.listenForCallbacks()
   224  
   225  	s.initialized = true
   226  
   227  	return nil
   228  }
   229  
   230  func (s *Service) listenForCallbacks() {
   231  	for c := range s.callbacks {
   232  		logger.Debugf("handling user callback %+v with options %+v", c, c.options)
   233  
   234  		if c.err != nil {
   235  			go s.handleUserRejection(c)
   236  
   237  			continue
   238  		}
   239  
   240  		switch c.msg.Type() {
   241  		case RequestMsgType:
   242  			err := s.handleInboundRequest(c)
   243  			if err != nil {
   244  				logger.Errorf("failed to handle inbound request: %+v : %w", c.msg, err)
   245  			}
   246  		default:
   247  			logger.Warnf("ignoring unsupported message type %s", c.msg.Type())
   248  		}
   249  	}
   250  }
   251  
   252  func (s *Service) handleUserRejection(c *callback) {
   253  	logger.Infof("user aborted response action for msgID=%s", c.msg.ID())
   254  }
   255  
   256  func triggersActionEvent(msgType string) bool {
   257  	return msgType == RequestMsgType
   258  }
   259  
   260  func (s *Service) sendActionEvent(msg service.DIDCommMsg, myDID, theirDID string) error {
   261  	events := s.ActionEvent()
   262  	if events == nil {
   263  		return fmt.Errorf("no clients registered to handle action events for %s protocol", Coordination)
   264  	}
   265  
   266  	logger.Debugf("dispatching action event for msg=%+v myDID=%s theirDID=%s", msg, myDID, theirDID)
   267  
   268  	go func() {
   269  		c := &callback{
   270  			msg:      msg,
   271  			myDID:    myDID,
   272  			theirDID: theirDID,
   273  		}
   274  
   275  		events <- service.DIDCommAction{
   276  			ProtocolName: Coordination,
   277  			Message:      msg,
   278  			Continue: func(args interface{}) {
   279  				switch o := args.(type) {
   280  				case Options:
   281  					c.options = &o
   282  				case *Options:
   283  					c.options = o
   284  				default:
   285  					c.options = &Options{}
   286  				}
   287  
   288  				s.callbacks <- c
   289  			},
   290  			Stop: func(err error) {
   291  				c.err = err
   292  
   293  				s.callbacks <- c
   294  			},
   295  		}
   296  	}()
   297  
   298  	return nil
   299  }
   300  
   301  // HandleInbound handles inbound route coordination messages.
   302  func (s *Service) HandleInbound(msg service.DIDCommMsg, ctx service.DIDCommContext) (string, error) {
   303  	logger.Debugf("service.HandleInbound() input: msg=%+v myDID=%s theirDID=%s", msg, ctx.MyDID(), ctx.TheirDID())
   304  
   305  	if triggersActionEvent(msg.Type()) {
   306  		return msg.ID(), s.sendActionEvent(msg, ctx.MyDID(), ctx.TheirDID())
   307  	}
   308  
   309  	// perform action on inbound message asynchronously
   310  	go func(msg service.DIDCommMsg) {
   311  		var err error
   312  
   313  		switch msg.Type() {
   314  		case GrantMsgType:
   315  			err = s.saveGrant(msg)
   316  		case KeylistUpdateMsgType:
   317  			err = s.handleKeylistUpdate(msg, ctx.MyDID(), ctx.TheirDID())
   318  		case KeylistUpdateResponseMsgType:
   319  			err = s.handleKeylistUpdateResponse(msg)
   320  		case service.ForwardMsgType, service.ForwardMsgTypeV2:
   321  			err = s.handleForward(msg)
   322  		}
   323  
   324  		connectionIDLog := ""
   325  
   326  		// mediator forward messages don't have connection established with the sender; hence skip the lookup
   327  		if msg.Type() != service.ForwardMsgType && msg.Type() != service.ForwardMsgTypeV2 {
   328  			connectionID, connErr := s.connectionLookup.GetConnectionIDByDIDs(ctx.MyDID(), ctx.TheirDID())
   329  			if connErr != nil {
   330  				logutil.LogError(logger, Coordination, "connectionID lookup using DIDs", connErr.Error())
   331  			}
   332  
   333  			connectionIDLog = logutil.CreateKeyValueString("connectionID", connectionID)
   334  		}
   335  
   336  		if err != nil {
   337  			logutil.LogError(logger, Coordination, "processMessage", err.Error(),
   338  				logutil.CreateKeyValueString("msgType", msg.Type()),
   339  				logutil.CreateKeyValueString("msgID", msg.ID()),
   340  				connectionIDLog)
   341  		} else {
   342  			logutil.LogDebug(logger, Coordination, "processMessage", "success",
   343  				logutil.CreateKeyValueString("msgType", msg.Type()),
   344  				logutil.CreateKeyValueString("msgID", msg.ID()),
   345  				connectionIDLog)
   346  		}
   347  	}(msg.Clone())
   348  
   349  	return msg.ID(), nil
   350  }
   351  
   352  // HandleOutbound handles outbound route coordination messages.
   353  func (s *Service) HandleOutbound(msg service.DIDCommMsg, myDID, theirDID string) (string, error) {
   354  	logger.Debugf("service.HandleOutbound input: msg=%+v myDID=%s theirDID=%s", msg, myDID, theirDID)
   355  
   356  	if !s.Accept(msg.Type()) {
   357  		return "", fmt.Errorf("unsupported message type %s", msg.Type())
   358  	}
   359  
   360  	switch msg.Type() {
   361  	case RequestMsgType:
   362  		return "", s.handleOutboundRequest(msg, myDID, theirDID)
   363  	default:
   364  		return "", fmt.Errorf("invalid or unsupported outbound message type %s", msg.Type())
   365  	}
   366  }
   367  
   368  // Accept checks whether the service can handle the message type.
   369  func (s *Service) Accept(msgType string) bool {
   370  	switch msgType {
   371  	case RequestMsgType, GrantMsgType, KeylistUpdateMsgType, KeylistUpdateResponseMsgType, service.ForwardMsgType,
   372  		service.ForwardMsgTypeV2:
   373  		return true
   374  	}
   375  
   376  	return false
   377  }
   378  
   379  // Name of the service.
   380  func (s *Service) Name() string {
   381  	return Coordination
   382  }
   383  
   384  func (s *Service) handleInboundRequest(c *callback) error {
   385  	logger.Debugf("handling callback: %+v", c)
   386  	logger.Debugf("options: %+v", c.options)
   387  
   388  	// unmarshal the payload
   389  	request := &Request{}
   390  
   391  	err := c.msg.Decode(request)
   392  	if err != nil {
   393  		return fmt.Errorf("handleInboundRequest: route request message unmarshal : %w", err)
   394  	}
   395  
   396  	err = validateRequestVersion(s.mediaTypeProfiles, request.DIDCommV2)
   397  	if err != nil {
   398  		return err
   399  	}
   400  
   401  	grant, err := outboundGrant(
   402  		c.msg.ID(),
   403  		c.options,
   404  		s.endpoint,
   405  		func() (string, error) {
   406  			if request.DIDCommV2 {
   407  				_, pubKeyBytes, e := s.kms.CreateAndExportPubKeyBytes(s.keyAgreementType)
   408  				if e != nil {
   409  					return "", fmt.Errorf("outboundGrant from handleInboundRequest: kms failed to create "+
   410  						"and export %v key: %w", s.keyAgreementType, e)
   411  				}
   412  
   413  				return kmsdidkey.BuildDIDKeyByKeyType(pubKeyBytes, s.keyAgreementType)
   414  			}
   415  
   416  			_, pubKeyBytes, er := s.kms.CreateAndExportPubKeyBytes(kms.ED25519Type)
   417  			if er != nil {
   418  				return "", fmt.Errorf("outboundGrant from handleInboundRequest: kms failed to create and "+
   419  					"export ED25519 key: %w", er)
   420  			}
   421  
   422  			didKey, _ := fingerprint.CreateDIDKey(pubKeyBytes)
   423  
   424  			return didKey, er
   425  		},
   426  	)
   427  	if err != nil {
   428  		return fmt.Errorf("handleInboundRequest: failed to handle inbound request : %w", err)
   429  	}
   430  
   431  	return s.outbound.SendToDID(service.NewDIDCommMsgMap(grant), c.myDID, c.theirDID)
   432  }
   433  
   434  func validateRequestVersion(mtps []string, requestedV2 bool) error {
   435  	if requestedV2 {
   436  		for _, mtp := range mtps {
   437  			if transport.IsDIDCommV2(mtp) {
   438  				return nil
   439  			}
   440  		}
   441  
   442  		return fmt.Errorf("client requested didcomm v2 mediation from mediator " +
   443  			"that does not support didcomm v2")
   444  	}
   445  
   446  	for _, mtp := range mtps {
   447  		if !transport.IsDIDCommV2(mtp) {
   448  			return nil
   449  		}
   450  	}
   451  
   452  	return fmt.Errorf("client requested didcomm v1 mediation from mediator " +
   453  		"that does not support didcomm v1")
   454  }
   455  
   456  func outboundGrant(
   457  	msgID string, opts *Options,
   458  	defaultEndpoint string, defaultKey func() (string, error)) (*Grant, error) {
   459  	grant := &Grant{
   460  		ID:          msgID,
   461  		Type:        GrantMsgType,
   462  		Endpoint:    opts.ServiceEndpoint,
   463  		RoutingKeys: opts.RoutingKeys,
   464  	}
   465  
   466  	if grant.Endpoint == "" {
   467  		grant.Endpoint = defaultEndpoint
   468  	}
   469  
   470  	if len(grant.RoutingKeys) == 0 {
   471  		keys, err := defaultKey()
   472  		if err != nil {
   473  			return nil, fmt.Errorf("outboundGrant: failed to create keys : %w", err)
   474  		}
   475  
   476  		grant.RoutingKeys = []string{keys}
   477  	}
   478  
   479  	logger.Debugf("outbound grant: %+v", grant)
   480  
   481  	return grant, nil
   482  }
   483  
   484  func (s *Service) handleKeylistUpdate(msg service.DIDCommMsg, myDID, theirDID string) error {
   485  	// unmarshal the payload
   486  	keyUpdate := &KeylistUpdate{}
   487  
   488  	err := msg.Decode(keyUpdate)
   489  	if err != nil {
   490  		return fmt.Errorf("route key list update message unmarshal : %w", err)
   491  	}
   492  
   493  	var updates []UpdateResponse
   494  
   495  	// update the db
   496  	for _, v := range keyUpdate.Updates {
   497  		if v.Action == add {
   498  			val := theirDID
   499  			result := success
   500  
   501  			toKey := dataKey(v.RecipientKey)
   502  
   503  			err = s.routeStore.Put(toKey, []byte(val))
   504  			if err != nil {
   505  				logger.Errorf("failed to add the route key to store : %s", err)
   506  
   507  				result = serverError
   508  			}
   509  
   510  			// construct the response doc
   511  			updates = append(updates, UpdateResponse{
   512  				RecipientKey: v.RecipientKey,
   513  				Action:       v.Action,
   514  				Result:       result,
   515  			})
   516  		} else if v.Action == remove {
   517  			// TODO remove from the store
   518  
   519  			// construct the response doc
   520  			updates = append(updates, UpdateResponse{
   521  				RecipientKey: v.RecipientKey,
   522  				Action:       v.Action,
   523  				Result:       serverError,
   524  			})
   525  		}
   526  	}
   527  
   528  	// send the key update response
   529  	updateResponse := &KeylistUpdateResponse{
   530  		Type:    KeylistUpdateResponseMsgType,
   531  		ID:      msg.ID(),
   532  		Updated: updates,
   533  	}
   534  
   535  	return s.outbound.SendToDID(service.NewDIDCommMsgMap(updateResponse), myDID, theirDID)
   536  }
   537  
   538  func (s *Service) handleKeylistUpdateResponse(msg service.DIDCommMsg) error {
   539  	// unmarshal the payload
   540  	respMsg := &KeylistUpdateResponse{}
   541  
   542  	err := msg.Decode(respMsg)
   543  	if err != nil {
   544  		return fmt.Errorf("route keylist update response message unmarshal : %w", err)
   545  	}
   546  
   547  	// check if there are any channels registered for the message ID
   548  	keylistUpdateCh := s.getKeyUpdateResponseCh(respMsg.ID)
   549  
   550  	if keylistUpdateCh != nil {
   551  		// invoke the channel for the incoming message
   552  		keylistUpdateCh <- respMsg
   553  	}
   554  
   555  	return nil
   556  }
   557  
   558  func (s *Service) handleForward(msg service.DIDCommMsg) error {
   559  	// unmarshal the payload
   560  	forward := &model.Forward{}
   561  
   562  	err := msg.Decode(forward)
   563  	if err != nil {
   564  		return fmt.Errorf("forward message unmarshal : %w", err)
   565  	}
   566  
   567  	// TODO Open question - https://github.com/hyperledger/aries-framework-go/issues/965 Mismatch between Route
   568  	//  Coordination and Forward RFC. For now assume, the TO field contains the recipient key (DIDComm V2 uses
   569  	//  keyAgreement.ID, double check if this to do comment is still needed).
   570  	toKey := dataKey(forward.To)
   571  
   572  	theirDID, err := s.routeStore.Get(toKey)
   573  	if err != nil {
   574  		return fmt.Errorf("route key fetch : %w", err)
   575  	}
   576  
   577  	dest, err := service.GetDestination(string(theirDID), s.vdRegistry)
   578  	if err != nil {
   579  		return fmt.Errorf("get destination : %w", err)
   580  	}
   581  
   582  	err = s.outbound.Forward(forward.Msg, dest)
   583  	if err != nil && s.messagePickupSvc != nil {
   584  		return s.messagePickupSvc.AddMessage(forward.Msg, string(theirDID))
   585  	}
   586  
   587  	return err
   588  }
   589  
   590  // Register registers the agent with the router on the other end of the connection identified by
   591  // connectionID. This method blocks until a response is received from the router or it times out.
   592  // The agent is registered with the router and retrieves the router endpoint and routing keys.
   593  // This function throws an error if the agent is already registered against a router.
   594  func (s *Service) Register(connectionID string, options ...ClientOption) error {
   595  	record, err := s.getConnection(connectionID)
   596  	if err != nil {
   597  		return fmt.Errorf("get connection: %w", err)
   598  	}
   599  
   600  	opts := parseClientOpts(options...)
   601  
   602  	return s.doRegistration(
   603  		record,
   604  		&Request{
   605  			Type:   RequestMsgType,
   606  			ID:     uuid.New().String(),
   607  			Timing: decorator.Timing{},
   608  		},
   609  		opts.Timeout,
   610  	)
   611  }
   612  
   613  func (s *Service) doRegistration(record *connection.Record, req *Request, timeout time.Duration) error {
   614  	// check if router is already registered
   615  	err := s.ensureConnectionExists(record.ConnectionID)
   616  	if err == nil {
   617  		return errors.New("router is already registered")
   618  	}
   619  
   620  	if !errors.Is(err, ErrRouterNotRegistered) {
   621  		return fmt.Errorf("ensure connection exists: %w", err)
   622  	}
   623  
   624  	// TODO: would this be better served as time.Now().Add(timeout).Unix() as pkg/doc/verifiable/credential.go
   625  	// demonstrates? additionally `ExpiresTime` would need to be migrated to int64
   626  	req.ExpiresTime = time.Now().UTC().Add(timeout)
   627  
   628  	if record.DIDCommVersion == service.V2 {
   629  		req.DIDCommV2 = true
   630  	}
   631  
   632  	// send message to the router
   633  	if err = s.outbound.SendToDID(service.NewDIDCommMsgMap(req), record.MyDID, record.TheirDID); err != nil {
   634  		return fmt.Errorf("send route request: %w", err)
   635  	}
   636  
   637  	// waits until the mediate-grant message is received or timeout was exceeded
   638  	grant, err := s.getGrant(req.ID, timeout)
   639  	if err != nil {
   640  		return fmt.Errorf("get grant for request ID '%s': %w", req.ID, err)
   641  	}
   642  
   643  	err = s.saveRouterConfig(record.ConnectionID, &config{
   644  		RouterEndpoint: grant.Endpoint,
   645  		RoutingKeys:    grant.RoutingKeys,
   646  	})
   647  	if err != nil {
   648  		return fmt.Errorf("save route config : %w", err)
   649  	}
   650  
   651  	logger.Debugf("saved router config from inbound grant: %+v", grant)
   652  
   653  	// save the connectionID of the router
   654  	return s.saveRouterConnectionID(record.ConnectionID, record.DIDCommVersion)
   655  }
   656  
   657  func (s *Service) getGrant(id string, timeout time.Duration) (*Grant, error) {
   658  	var (
   659  		src []byte
   660  		err error
   661  	)
   662  
   663  	err = backoff.Retry(func() error {
   664  		src, err = s.routeStore.Get(fmt.Sprintf(routeGrantKey, id))
   665  
   666  		return err
   667  	}, backoff.WithMaxRetries(backoff.NewConstantBackOff(time.Second), uint64(timeout/time.Second)))
   668  
   669  	if err != nil {
   670  		return nil, fmt.Errorf("store: %w", err)
   671  	}
   672  
   673  	var grant *Grant
   674  
   675  	err = json.Unmarshal(src, &grant)
   676  	if err != nil {
   677  		return nil, fmt.Errorf("unmarshal grant: %w", err)
   678  	}
   679  
   680  	return grant, nil
   681  }
   682  
   683  func (s *Service) saveGrant(grant service.DIDCommMsg) error {
   684  	src, err := json.Marshal(grant)
   685  	if err != nil {
   686  		return fmt.Errorf("marshal grant: %w", err)
   687  	}
   688  
   689  	return s.routeStore.Put(fmt.Sprintf(routeGrantKey, grant.ID()), src)
   690  }
   691  
   692  // Unregister unregisters the agent with the router.
   693  func (s *Service) Unregister(connID string) error {
   694  	// check if router is already registered
   695  	err := s.ensureConnectionExists(connID)
   696  	if err != nil {
   697  		return fmt.Errorf("ensure connection exists: %w", err)
   698  	}
   699  
   700  	// TODO Remove all the recKeys from the router
   701  	//  https://github.com/hyperledger/aries-rfcs/tree/master/features/0211-route-coordination#keylist-update-response
   702  
   703  	// deletes the connectionID
   704  	return s.deleteRouterConnectionID(connID)
   705  }
   706  
   707  // GetConnections returns the connections of the router.
   708  func (s *Service) GetConnections(options ...ConnectionOption) ([]string, error) {
   709  	opts := &getConnectionOpts{}
   710  
   711  	for _, option := range options {
   712  		option(opts)
   713  	}
   714  
   715  	records, err := s.routeStore.Query(routeConnIDDataKey)
   716  	if err != nil {
   717  		return nil, fmt.Errorf("failed to query route store: %w", err)
   718  	}
   719  
   720  	defer storage.Close(records, logger)
   721  
   722  	var conns []string
   723  
   724  	more, err := records.Next()
   725  	if err != nil {
   726  		return nil, fmt.Errorf("failed to get next record: %w", err)
   727  	}
   728  
   729  	for more {
   730  		value, err := records.Value()
   731  		if err != nil {
   732  			return nil, fmt.Errorf("failed to get value from records: %w", err)
   733  		}
   734  
   735  		data := &routerConnectionEntry{}
   736  
   737  		err = json.Unmarshal(value, data)
   738  		if err != nil {
   739  			return nil, fmt.Errorf("failed to unmarshal router connection entry: %w", err)
   740  		}
   741  
   742  		if opts.version == "" || opts.version == data.DIDCommVersion {
   743  			conns = append(conns, data.ConnectionID)
   744  		}
   745  
   746  		more, err = records.Next()
   747  		if err != nil {
   748  			return nil, fmt.Errorf("failed to get next record: %w", err)
   749  		}
   750  	}
   751  
   752  	return conns, nil
   753  }
   754  
   755  // AddKey adds a recKey of the agent to the registered router. This method blocks until a response is
   756  // received from the router or it times out.
   757  // TODO https://github.com/hyperledger/aries-framework-go/issues/1076 Support for multiple routers
   758  // TODO https://github.com/hyperledger/aries-framework-go/issues/1105 Support to Add multiple
   759  //  recKeys to the Router
   760  func (s *Service) AddKey(connID, recKey string) error {
   761  	// check if router is already registered
   762  	err := s.ensureConnectionExists(connID)
   763  	if err != nil {
   764  		return fmt.Errorf("ensure connection exists: %w", err)
   765  	}
   766  
   767  	// get the connection record for the ID to fetch DID information
   768  	conn, err := s.getConnection(connID)
   769  	if err != nil {
   770  		return fmt.Errorf("get connection: %w", err)
   771  	}
   772  
   773  	// generate message ID
   774  	msgID := uuid.New().String()
   775  
   776  	// register chan for callback processing
   777  	keyUpdateCh := make(chan *KeylistUpdateResponse)
   778  	s.setKeyUpdateResponseCh(msgID, keyUpdateCh)
   779  
   780  	keyUpdate := &KeylistUpdate{
   781  		ID:   msgID,
   782  		Type: KeylistUpdateMsgType,
   783  		Updates: []Update{
   784  			{
   785  				RecipientKey: recKey,
   786  				Action:       add,
   787  			},
   788  		},
   789  	}
   790  
   791  	if err := s.outbound.SendToDID(service.NewDIDCommMsgMap(keyUpdate), conn.MyDID, conn.TheirDID); err != nil {
   792  		return fmt.Errorf("send route request: %w", err)
   793  	}
   794  
   795  	select {
   796  	case keyUpdateResp := <-keyUpdateCh:
   797  		if err := processKeylistUpdateResp(recKey, keyUpdateResp); err != nil {
   798  			return err
   799  		}
   800  	case <-time.After(updateTimeout):
   801  		return errors.New("timeout waiting for keylist update response from the router")
   802  	}
   803  
   804  	// remove the channel once its been processed
   805  	s.setKeyUpdateResponseCh(msgID, nil)
   806  
   807  	return nil
   808  }
   809  
   810  // Config fetches the router config - endpoint and routingKeys.
   811  func (s *Service) Config(connID string) (*Config, error) {
   812  	// check if router is already registered
   813  	if err := s.ensureConnectionExists(connID); err != nil {
   814  		return nil, fmt.Errorf("ensure connection exists: %w", err)
   815  	}
   816  
   817  	return s.getRouterConfig(connID)
   818  }
   819  
   820  func processKeylistUpdateResp(recKey string, keyUpdateResp *KeylistUpdateResponse) error {
   821  	for _, result := range keyUpdateResp.Updated {
   822  		if result.RecipientKey == recKey && result.Action == add && result.Result != success {
   823  			return errors.New("failed to update the recipient key with the router")
   824  		}
   825  	}
   826  
   827  	return nil
   828  }
   829  
   830  func (s *Service) getKeyUpdateResponseCh(msgID string) chan *KeylistUpdateResponse {
   831  	s.keylistUpdateMapLock.RLock()
   832  	defer s.keylistUpdateMapLock.RUnlock()
   833  
   834  	return s.keylistUpdateMap[msgID]
   835  }
   836  
   837  func (s *Service) setKeyUpdateResponseCh(msgID string, keyUpdateCh chan *KeylistUpdateResponse) {
   838  	s.keylistUpdateMapLock.Lock()
   839  	defer s.keylistUpdateMapLock.Unlock()
   840  
   841  	if keyUpdateCh == nil {
   842  		delete(s.keylistUpdateMap, msgID)
   843  	} else {
   844  		s.keylistUpdateMap[msgID] = keyUpdateCh
   845  	}
   846  }
   847  
   848  func (s *Service) ensureConnectionExists(connID string) error {
   849  	_, err := s.routeStore.Get(fmt.Sprintf(routeConnIDDataKey, connID))
   850  	if errors.Is(err, storage.ErrDataNotFound) {
   851  		return ErrRouterNotRegistered
   852  	}
   853  
   854  	return err
   855  }
   856  
   857  func (s *Service) deleteRouterConnectionID(connID string) error {
   858  	return s.routeStore.Delete(fmt.Sprintf(routeConnIDDataKey, connID))
   859  }
   860  
   861  func (s *Service) saveRouterConnectionID(connID string, didcommVersion service.Version) error {
   862  	data := &routerConnectionEntry{
   863  		ConnectionID:   connID,
   864  		DIDCommVersion: didcommVersion,
   865  	}
   866  
   867  	dataBytes, err := json.Marshal(data)
   868  	if err != nil {
   869  		return fmt.Errorf("marshalling router connection ID data: %w", err)
   870  	}
   871  
   872  	return s.routeStore.Put(fmt.Sprintf(routeConnIDDataKey, connID), dataBytes, storage.Tag{Name: routeConnIDDataKey})
   873  }
   874  
   875  type config struct {
   876  	RouterEndpoint string
   877  	RoutingKeys    []string
   878  }
   879  
   880  func (s *Service) getRouterConfig(connID string) (*Config, error) {
   881  	val, err := s.routeStore.Get(fmt.Sprintf(routeConfigDataKey, connID))
   882  	if err != nil {
   883  		return nil, fmt.Errorf("get router config data : %w", err)
   884  	}
   885  
   886  	conf := &config{}
   887  
   888  	err = json.Unmarshal(val, conf)
   889  	if err != nil {
   890  		return nil, fmt.Errorf("unmarshal router config data : %w", err)
   891  	}
   892  
   893  	return NewConfig(conf.RouterEndpoint, conf.RoutingKeys), nil
   894  }
   895  
   896  func (s *Service) saveRouterConfig(connID string, conf *config) error {
   897  	bytes, err := json.Marshal(conf)
   898  	if err != nil {
   899  		return fmt.Errorf("marshal config data: %w", err)
   900  	}
   901  
   902  	return s.routeStore.Put(fmt.Sprintf(routeConfigDataKey, connID), bytes)
   903  }
   904  
   905  func (s *Service) getConnection(routerConnID string) (*connection.Record, error) {
   906  	conn, err := s.connectionLookup.GetConnectionRecord(routerConnID)
   907  	if err != nil {
   908  		if errors.Is(err, storage.ErrDataNotFound) {
   909  			return nil, ErrConnectionNotFound
   910  		}
   911  
   912  		return nil, fmt.Errorf("fetch connection record from store : %w", err)
   913  	}
   914  
   915  	return conn, nil
   916  }
   917  
   918  func (s *Service) handleOutboundRequest(msg service.DIDCommMsg, myDID, theirDID string) error {
   919  	req := &Request{}
   920  
   921  	err := msg.Decode(req)
   922  	if err != nil {
   923  		return fmt.Errorf("failed to decode request : %w", err)
   924  	}
   925  
   926  	record, err := s.connectionLookup.GetConnectionRecordByDIDs(myDID, theirDID)
   927  	if err != nil {
   928  		return fmt.Errorf("failed to lookup connection record with myDID=%s theirDID=%s : %w",
   929  			myDID, theirDID, err)
   930  	}
   931  
   932  	return s.doRegistration(record, req, updateTimeout)
   933  }
   934  
   935  func dataKey(id string) string {
   936  	return "route-" + id
   937  }
   938  
   939  func parseClientOpts(options ...ClientOption) *ClientOptions {
   940  	opts := &ClientOptions{
   941  		Timeout: updateTimeout,
   942  	}
   943  
   944  	// generate router config from options
   945  	for _, option := range options {
   946  		option(opts)
   947  	}
   948  
   949  	return opts
   950  }
   951  
   952  type getConnectionOpts struct {
   953  	version service.Version
   954  }
   955  
   956  // ConnectionOption option for Service.GetConnections.
   957  type ConnectionOption func(opts *getConnectionOpts)
   958  
   959  // ConnectionByVersion filter for mediator connections of the given DIDComm version.
   960  func ConnectionByVersion(v service.Version) ConnectionOption {
   961  	return func(opts *getConnectionOpts) {
   962  		opts.version = v
   963  	}
   964  }