Documentation ¶
Overview ¶
Package outofband provides support for the Out-of-Band protocols: https://github.com/hyperledger/aries-rfcs/blob/master/features/0434-outofband/README.md.
Create your client:
ctx := getFrameworkContext() client, err := outofband.New(ctx)
if err != nil { panic(err) }
You can create requests and invitations with client.CreateRequest() and client.CreateInvitation() respectively.
You can accept out-of-band requests and invitations received via out of band channels. If you have a request or an invitation on hand you can use the client.AcceptRequest() and client.AcceptInvitation() respectively. These return the ID of the newly-created connection record.
If you're expecting to receive out-of-band invitations or requests via a DIDComm channel then you should register to the action event stream and the state event stream:
events := make(chan service.DIDCommAction) err = client.RegisterActionEvent(events)
if err != nil { panic(err) }
states := make(chan service.StateMsg) err = client.RegisterMsgEvent(states)
if err != nil { panic(err) }
for { select { case event := <-events: switch event.Message.Type() { case outofband.RequestMsgType: // inspect the request req := &outofband.Invitation{} err = event.Message.Decode(req) if err != nil { panic(err) } // accept the request: event.Continue(&outofband.EventOptions{Label: "Bob"}) // OR you may reject this request: // event.Stop(errors.New("rejected")) case outofband.InvitationMsgType: // inspect and handle the out-of-band invitation just like with the // request message above } case state := <-states: // the connection ID is delivered in a PostState if state.Type == service.PostState { props := state.Properties.(outofband.Event) if props.Error() != nil { panic(props.Error()) } // the connection ID connID := props.ConnectionID() } } }
Note: the ouf-of-band protocol results in the execution of other protocols. You need to subscribe to the event and state streams of those protocols as well.
Index ¶
- Constants
- type Action
- type Client
- func (c *Client) AcceptInvitation(i *Invitation, myLabel string, opts ...MessageOption) (string, error)
- func (c *Client) ActionContinue(piID, label string, opts ...MessageOption) error
- func (c *Client) ActionStop(piID string, err error) error
- func (c *Client) Actions() ([]Action, error)
- func (c *Client) CreateInvitation(services []interface{}, opts ...MessageOption) (*Invitation, error)
- type Event
- type EventOptions
- type Invitation
- type MessageOption
- func ReuseAnyConnection() MessageOption
- func ReuseConnection(theirDID string) MessageOption
- func WithAccept(a ...string) MessageOption
- func WithAttachments(a ...*decorator.Attachment) MessageOption
- func WithGoal(goal, goalCode string) MessageOption
- func WithHandshakeProtocols(proto ...string) MessageOption
- func WithLabel(l string) MessageOption
- func WithRouterConnections(conn ...string) MessageOption
- type OobService
- type Provider
Examples ¶
Constants ¶
const ( // InvitationMsgType is the '@type' for the invitation message. InvitationMsgType = outofband.InvitationMsgType // HandshakeReuseMsgType is the '@type' for the handshake reuse message. HandshakeReuseMsgType = outofband.HandshakeReuseMsgType // HandshakeReuseAcceptedMsgType is the '@type' for the handshake reuse accepted message. HandshakeReuseAcceptedMsgType = outofband.HandshakeReuseAcceptedMsgType )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
Client for the Out-Of-Band protocol: https://github.com/hyperledger/aries-rfcs/blob/master/features/0434-outofband/README.md
func (*Client) AcceptInvitation ¶
func (c *Client) AcceptInvitation(i *Invitation, myLabel string, opts ...MessageOption) (string, error)
AcceptInvitation from another agent and return the ID of the new connection records.
Example ¶
Example of an edge agent accepting an out-of-band invitation from a router.
package main import ( "encoding/base64" "encoding/json" "fmt" "time" "github.com/google/uuid" "github.com/hyperledger/aries-framework-go/component/storageutil/mem" "github.com/hyperledger/aries-framework-go/pkg/client/didexchange" "github.com/hyperledger/aries-framework-go/pkg/client/mediator" "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator" didsvc "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange" routesvc "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/mediator" "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/outofband" mockdidexchange "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/protocol/didexchange" mockroute "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/protocol/mediator" mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms" mockprovider "github.com/hyperledger/aries-framework-go/pkg/mock/provider" ) const ( // Router is a router that sends an out-of-band invitation to the edge agent. Router = "Router" // Bob is an edge agent. Bob = "Bob" ) var agentActions = make(map[string]chan service.DIDCommAction) //nolint:gochecknoglobals // Example of an edge agent accepting an out-of-band invitation from a router. func main() { //nolint:gocyclo,gocognit // set up the router routerCtx := getContext(Router) router, err := New(routerCtx) if err != nil { panic(err) } routerDIDs, err := didexchange.New(routerCtx) if err != nil { panic(err) } routerClient, err := mediator.New(routerCtx) if err != nil { panic(err) } routerEvents := makeActionsChannel(Router) err = routerDIDs.RegisterActionEvent(routerEvents) if err != nil { panic(err) } err = routerClient.RegisterActionEvent(routerEvents) if err != nil { panic(err) } // set up the edge agent bobCtx := getContext(Bob) bob, err := New(bobCtx) if err != nil { panic(err) } // router creates the route-request message routeRequest, err := json.Marshal(mediator.NewRequest()) if err != nil { panic(err) } // router creates outofband request and embeds the route-request message in it inv, err := router.CreateInvitation( nil, WithLabel(Router), WithAttachments(&decorator.Attachment{ ID: uuid.New().String(), Data: decorator.AttachmentData{ Base64: base64.StdEncoding.EncodeToString(routeRequest), }, }), ) if err != nil { panic(err) } fmt.Printf("%s creates an out-of-band invitation with an embedded route-request message\n", Router) // the edge agent accepts the outofband invitation bobConnID, err := bob.AcceptInvitation(inv, Bob) if err != nil { panic(err) } fmt.Printf( "%s accepts the out-of-band invitation received via an out of band channel and created connectionID %s\n", Bob, bobConnID) done := make(chan struct{}) // ends this example go func() { for event := range routerEvents { fmt.Printf("%s received %s from %s\n", Router, event.Message.Type(), Bob) switch event.ProtocolName { case didexchange.ProtocolName: if event.Message.Type() == didexchange.RequestMsgType { didExchangeRequest := &didsvc.Request{} err = event.Message.Decode(didExchangeRequest) if err != nil { panic(err) } if didExchangeRequest.Label != Bob { err = fmt.Errorf( "%s expected a didexchange request from %s but got %s", Router, Bob, didExchangeRequest.Label, ) event.Stop(err) panic(err) } props, ok := event.Properties.(didexchange.Event) if !ok { panic("failed to cast event properties (shouldn't happen)") } fmt.Printf("%s created connectionID %s\n", Router, props.ConnectionID()) event.Continue(nil) } case mediator.ProtocolName: if event.Message.Type() == mediator.RequestMsgType { event.Continue(nil) done <- struct{}{} } } } }() select { case <-done: case <-time.After(time.Second): // timeout varies in your environment panic("timeout") } bobRoutes, err := mediator.New(bobCtx) if err != nil { panic(err) } config, err := bobRoutes.GetConfig("xyz") if err != nil { panic(err) } fmt.Printf( "%s has registered a route on %s with routerEndpoint %s and routingKeys %+v\n", Bob, Router, config.Endpoint(), config.Keys()) } func getContext(agent string) *mockprovider.Provider { return &mockprovider.Provider{ KMSValue: &mockkms.KeyManager{}, StorageProviderValue: mem.NewProvider(), ProtocolStateStorageProviderValue: mem.NewProvider(), ServiceMap: map[string]interface{}{ outofband.Name: &stubOOBService{ Event: nil, acceptInvFunc: func(i *outofband.Invitation, options outofband.Options) (string, error) { agentActions[i.Label] <- service.DIDCommAction{ ProtocolName: didsvc.DIDExchange, Message: service.NewDIDCommMsgMap(&didsvc.Request{ Type: didsvc.RequestMsgType, Label: agent, }), Continue: func(interface{}) { agentActions[i.Label] <- service.DIDCommAction{ ProtocolName: mediator.ProtocolName, Message: service.NewDIDCommMsgMap(mediator.NewRequest()), Continue: func(interface{}) {}, } }, Properties: &didexchangeEvent{connID: "xyz"}, } return "xyz", nil }, saveInvFunc: func(*outofband.Invitation) error { return nil }, }, didsvc.DIDExchange: &mockdidexchange.MockDIDExchangeSvc{}, routesvc.Coordination: &mockroute.MockMediatorSvc{ RouterEndpoint: "http://routers-r-us.com", RoutingKeys: []string{"key-1", "key-2"}, }, }, } } func makeActionsChannel(agent string) chan service.DIDCommAction { c := make(chan service.DIDCommAction, 5) agentActions[agent] = c return c } type didexchangeEvent struct { connID string invID string } func (d *didexchangeEvent) ConnectionID() string { return d.connID } func (d *didexchangeEvent) InvitationID() string { return d.invID } func (d *didexchangeEvent) All() map[string]interface{} { return map[string]interface{}{ "connectionID": d.ConnectionID(), "invitationID": d.InvitationID(), } }
Output: Router creates an out-of-band invitation with an embedded route-request message Bob accepts the out-of-band invitation received via an out of band channel and created connectionID xyz Router received https://didcomm.org/didexchange/1.0/request from Bob Router created connectionID xyz Router received https://didcomm.org/coordinatemediation/1.0/mediate-request from Bob Bob has registered a route on Router with routerEndpoint http://routers-r-us.com and routingKeys [key-1 key-2]
func (*Client) ActionContinue ¶
func (c *Client) ActionContinue(piID, label string, opts ...MessageOption) error
ActionContinue allows continuing with the protocol after an action event was triggered.
func (*Client) ActionStop ¶
ActionStop stops the protocol after an action event was triggered.
func (*Client) CreateInvitation ¶
func (c *Client) CreateInvitation(services []interface{}, opts ...MessageOption) (*Invitation, error)
CreateInvitation creates and saves an out-of-band invitation. Services are required in the RFC, but optional in this implementation. If not provided, a default will be assigned. TODO HandShakeProtocols are optional in the RFC and as arguments to this function.
However, if not provided, a default will be assigned for you.
type Event ¶
type Event interface { // ConnectionID of the connection record, once it's created. // This becomes available in a post-state event unless an error condition is encountered. ConnectionID() string // Error is non-nil if an error is encountered. Error() error }
Event is a container of out-of-band protocol-specific properties for DIDCommActions and StateMsgs.
type EventOptions ¶
type EventOptions struct { // Label will be shared with the other agent during the subsequent did-exchange. Label string // Connections allows specifying router connections. Connections []string ReuseAny bool ReuseDID string }
EventOptions are is a container of options that you can pass to an event's Continue function to customize the reaction to incoming out-of-band messages.
func (*EventOptions) MyLabel ¶
func (e *EventOptions) MyLabel() string
MyLabel will be shared with the other agent during the subsequent did-exchange.
func (*EventOptions) ReuseAnyConnection ¶
func (e *EventOptions) ReuseAnyConnection() bool
ReuseAnyConnection signals whether to use any recognized DID in the services array for a reusable connection.
func (*EventOptions) ReuseConnection ¶
func (e *EventOptions) ReuseConnection() string
ReuseConnection returns the DID to be used when reusing a connection.
func (*EventOptions) RouterConnections ¶
func (e *EventOptions) RouterConnections() []string
RouterConnections return router connections.
type Invitation ¶
type Invitation outofband.Invitation
Invitation is this protocol's `invitation` message.
type MessageOption ¶
type MessageOption func(*message)
MessageOption allow you to customize the way out-of-band messages are built.
func ReuseAnyConnection ¶
func ReuseAnyConnection() MessageOption
ReuseAnyConnection is used when accepting an invitation with either AcceptInvitation or ActionContinue. The `services` array will be scanned until it finds a recognized DID entry and send a `handshake-reuse` message to its did-communication service endpoint. Cannot be used together with ReuseConnection.
func ReuseConnection ¶
func ReuseConnection(theirDID string) MessageOption
ReuseConnection is used when accepting an invitation with either AcceptInvitation or ActionContinue. 'did' must be an entry in the Invitation's 'services' array. A `handshake-reuse` message is sent to its did-communication service endpoint. Cannot be used together with ReuseAnyConnection.
func WithAccept ¶
func WithAccept(a ...string) MessageOption
WithAccept will set the given media type profiles in the Invitation's `accept` property. Only valid values from RFC 0044 are supported.
func WithAttachments ¶
func WithAttachments(a ...*decorator.Attachment) MessageOption
WithAttachments allows you to include attachments in the Invitation.
func WithGoal ¶
func WithGoal(goal, goalCode string) MessageOption
WithGoal allows you to specify the `goal` and `goalCode` for the message.
func WithHandshakeProtocols ¶
func WithHandshakeProtocols(proto ...string) MessageOption
WithHandshakeProtocols allows you to customize the handshake_protocols to include in the Invitation.
func WithLabel ¶
func WithLabel(l string) MessageOption
WithLabel allows you to specify the label on the message.
func WithRouterConnections ¶
func WithRouterConnections(conn ...string) MessageOption
WithRouterConnections allows you to specify the router connections.
type OobService ¶
type OobService interface { service.Event AcceptInvitation(*outofband.Invitation, outofband.Options) (string, error) SaveInvitation(*outofband.Invitation) error Actions() ([]outofband.Action, error) ActionContinue(string, outofband.Options) error ActionStop(string, error) error }
OobService defines the outofband service.