github.com/hyperledger/aries-framework-go@v0.3.2/pkg/client/outofband/example_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package outofband
     8  
     9  import (
    10  	"encoding/base64"
    11  	"encoding/json"
    12  	"fmt"
    13  	"time"
    14  
    15  	"github.com/google/uuid"
    16  
    17  	"github.com/hyperledger/aries-framework-go/component/storageutil/mem"
    18  	"github.com/hyperledger/aries-framework-go/pkg/client/didexchange"
    19  	"github.com/hyperledger/aries-framework-go/pkg/client/mediator"
    20  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
    21  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
    22  	didsvc "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange"
    23  	routesvc "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/mediator"
    24  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/outofband"
    25  	mockdidexchange "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/protocol/didexchange"
    26  	mockroute "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/protocol/mediator"
    27  	mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms"
    28  	mockprovider "github.com/hyperledger/aries-framework-go/pkg/mock/provider"
    29  )
    30  
    31  const (
    32  	// Router is a router that sends an out-of-band invitation to the edge agent.
    33  	Router = "Router"
    34  	// Bob is an edge agent.
    35  	Bob = "Bob"
    36  )
    37  
    38  var agentActions = make(map[string]chan service.DIDCommAction) //nolint:gochecknoglobals
    39  
    40  // Example of an edge agent accepting an out-of-band invitation from a router.
    41  func ExampleClient_AcceptInvitation() { //nolint:gocyclo,gocognit
    42  	// set up the router
    43  	routerCtx := getContext(Router)
    44  
    45  	router, err := New(routerCtx)
    46  	if err != nil {
    47  		panic(err)
    48  	}
    49  
    50  	routerDIDs, err := didexchange.New(routerCtx)
    51  	if err != nil {
    52  		panic(err)
    53  	}
    54  
    55  	routerClient, err := mediator.New(routerCtx)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  
    60  	routerEvents := makeActionsChannel(Router)
    61  
    62  	err = routerDIDs.RegisterActionEvent(routerEvents)
    63  	if err != nil {
    64  		panic(err)
    65  	}
    66  
    67  	err = routerClient.RegisterActionEvent(routerEvents)
    68  	if err != nil {
    69  		panic(err)
    70  	}
    71  
    72  	// set up the edge agent
    73  	bobCtx := getContext(Bob)
    74  
    75  	bob, err := New(bobCtx)
    76  	if err != nil {
    77  		panic(err)
    78  	}
    79  
    80  	// router creates the route-request message
    81  	routeRequest, err := json.Marshal(mediator.NewRequest())
    82  	if err != nil {
    83  		panic(err)
    84  	}
    85  
    86  	// router creates outofband request and embeds the route-request message in it
    87  	inv, err := router.CreateInvitation(
    88  		nil,
    89  		WithLabel(Router),
    90  		WithAttachments(&decorator.Attachment{
    91  			ID: uuid.New().String(),
    92  			Data: decorator.AttachmentData{
    93  				Base64: base64.StdEncoding.EncodeToString(routeRequest),
    94  			},
    95  		}),
    96  	)
    97  	if err != nil {
    98  		panic(err)
    99  	}
   100  
   101  	fmt.Printf("%s creates an out-of-band invitation with an embedded route-request message\n", Router)
   102  
   103  	// the edge agent accepts the outofband invitation
   104  	bobConnID, err := bob.AcceptInvitation(inv, Bob)
   105  	if err != nil {
   106  		panic(err)
   107  	}
   108  
   109  	fmt.Printf(
   110  		"%s accepts the out-of-band invitation received via an out of band channel and created connectionID %s\n",
   111  		Bob, bobConnID)
   112  
   113  	done := make(chan struct{}) // ends this example
   114  
   115  	go func() {
   116  		for event := range routerEvents {
   117  			fmt.Printf("%s received %s from %s\n", Router, event.Message.Type(), Bob)
   118  
   119  			switch event.ProtocolName {
   120  			case didexchange.ProtocolName:
   121  				if event.Message.Type() == didexchange.RequestMsgType {
   122  					didExchangeRequest := &didsvc.Request{}
   123  
   124  					err = event.Message.Decode(didExchangeRequest)
   125  					if err != nil {
   126  						panic(err)
   127  					}
   128  
   129  					if didExchangeRequest.Label != Bob {
   130  						err = fmt.Errorf(
   131  							"%s expected a didexchange request from %s but got %s",
   132  							Router, Bob, didExchangeRequest.Label,
   133  						)
   134  
   135  						event.Stop(err)
   136  						panic(err)
   137  					}
   138  
   139  					props, ok := event.Properties.(didexchange.Event)
   140  					if !ok {
   141  						panic("failed to cast event properties (shouldn't happen)")
   142  					}
   143  
   144  					fmt.Printf("%s created connectionID %s\n", Router, props.ConnectionID())
   145  
   146  					event.Continue(nil)
   147  				}
   148  			case mediator.ProtocolName:
   149  				if event.Message.Type() == mediator.RequestMsgType {
   150  					event.Continue(nil)
   151  					done <- struct{}{}
   152  				}
   153  			}
   154  		}
   155  	}()
   156  
   157  	select {
   158  	case <-done:
   159  	case <-time.After(time.Second): // timeout varies in your environment
   160  		panic("timeout")
   161  	}
   162  
   163  	bobRoutes, err := mediator.New(bobCtx)
   164  	if err != nil {
   165  		panic(err)
   166  	}
   167  
   168  	config, err := bobRoutes.GetConfig("xyz")
   169  	if err != nil {
   170  		panic(err)
   171  	}
   172  
   173  	fmt.Printf(
   174  		"%s has registered a route on %s with routerEndpoint %s and routingKeys %+v\n",
   175  		Bob, Router, config.Endpoint(), config.Keys())
   176  
   177  	// Output:
   178  	// Router creates an out-of-band invitation with an embedded route-request message
   179  	// Bob accepts the out-of-band invitation received via an out of band channel and created connectionID xyz
   180  	// Router received https://didcomm.org/didexchange/1.0/request from Bob
   181  	// Router created connectionID xyz
   182  	// Router received https://didcomm.org/coordinatemediation/1.0/mediate-request from Bob
   183  	// Bob has registered a route on Router with routerEndpoint http://routers-r-us.com and routingKeys [key-1 key-2]
   184  }
   185  
   186  func getContext(agent string) *mockprovider.Provider {
   187  	return &mockprovider.Provider{
   188  		KMSValue:                          &mockkms.KeyManager{},
   189  		StorageProviderValue:              mem.NewProvider(),
   190  		ProtocolStateStorageProviderValue: mem.NewProvider(),
   191  		ServiceMap: map[string]interface{}{
   192  			outofband.Name: &stubOOBService{
   193  				Event: nil,
   194  				acceptInvFunc: func(i *outofband.Invitation, options outofband.Options) (string, error) {
   195  					agentActions[i.Label] <- service.DIDCommAction{
   196  						ProtocolName: didsvc.DIDExchange,
   197  						Message: service.NewDIDCommMsgMap(&didsvc.Request{
   198  							Type:  didsvc.RequestMsgType,
   199  							Label: agent,
   200  						}),
   201  						Continue: func(interface{}) {
   202  							agentActions[i.Label] <- service.DIDCommAction{
   203  								ProtocolName: mediator.ProtocolName,
   204  								Message:      service.NewDIDCommMsgMap(mediator.NewRequest()),
   205  								Continue:     func(interface{}) {},
   206  							}
   207  						},
   208  						Properties: &didexchangeEvent{connID: "xyz"},
   209  					}
   210  
   211  					return "xyz", nil
   212  				},
   213  				saveInvFunc: func(*outofband.Invitation) error { return nil },
   214  			},
   215  			didsvc.DIDExchange: &mockdidexchange.MockDIDExchangeSvc{},
   216  			routesvc.Coordination: &mockroute.MockMediatorSvc{
   217  				RouterEndpoint: "http://routers-r-us.com",
   218  				RoutingKeys:    []string{"key-1", "key-2"},
   219  			},
   220  		},
   221  	}
   222  }
   223  
   224  func makeActionsChannel(agent string) chan service.DIDCommAction {
   225  	c := make(chan service.DIDCommAction, 5)
   226  	agentActions[agent] = c
   227  
   228  	return c
   229  }
   230  
   231  type didexchangeEvent struct {
   232  	connID string
   233  	invID  string
   234  }
   235  
   236  func (d *didexchangeEvent) ConnectionID() string {
   237  	return d.connID
   238  }
   239  
   240  func (d *didexchangeEvent) InvitationID() string {
   241  	return d.invID
   242  }
   243  
   244  func (d *didexchangeEvent) All() map[string]interface{} {
   245  	return map[string]interface{}{
   246  		"connectionID": d.ConnectionID(),
   247  		"invitationID": d.InvitationID(),
   248  	}
   249  }