outofband

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2020 License: Apache-2.0 Imports: 11 Imported by: 24

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.Request{}
            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

Examples

Constants

View Source
const (
	// RequestMsgType is the request message's '@type'.
	RequestMsgType = outofband.RequestMsgType
	// InvitationMsgType is the '@type' for the invitation message.
	InvitationMsgType = outofband.InvitationMsgType
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Action added in v0.1.4

type Action outofband.Action

Action contains helpful information about action.

type Client

type Client struct {
	service.Event
	// contains filtered or unexported fields
}

Client for the Out-Of-Band protocol: https://github.com/hyperledger/aries-rfcs/blob/master/features/0434-outofband/README.md

func New

func New(p Provider) (*Client, error)

New returns a new Client for the Out-Of-Band protocol.

func (*Client) AcceptInvitation

func (c *Client) AcceptInvitation(i *Invitation, myLabel string) (string, error)

AcceptInvitation from another agent and return the ID of the new connection records.

Example

Example of an edge agent sending an out-of-band request to another edge agent.

{ //nolint:gocyclo,gocognit
	// set up the router
	aliceCtx := getContext(Alice)

	alice, err := New(aliceCtx)
	if err != nil {
		panic(err)
	}

	aliceDIDs, err := didexchange.New(aliceCtx)
	if err != nil {
		panic(err)
	}

	aliceRouting, err := mediator.New(aliceCtx)
	if err != nil {
		panic(err)
	}

	aliceEvents := makeActionsChannel(Alice)

	err = aliceDIDs.RegisterActionEvent(aliceEvents)
	if err != nil {
		panic(err)
	}

	err = aliceRouting.RegisterActionEvent(aliceEvents)
	if err != nil {
		panic(err)
	}

	// set up the edge agent
	bob, err := New(getContext(Bob))
	if err != nil {
		panic(err)
	}

	// alice creates an outofband invitation
	inv, err := alice.CreateInvitation(nil, WithLabel(Alice))
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s creates an out-of-band invitation\n", Alice)

	// 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 aliceEvents {
			fmt.Printf("%s received %s from %s\n", Alice, event.Message.Type(), Bob)

			if event.ProtocolName == didexchange.ProtocolName &&
				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",
						Alice, 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", Alice, props.ConnectionID())

				event.Continue(nil)
				done <- struct{}{}
			}
		}
	}()

	select {
	case <-done:
	case <-time.After(time.Second): // timeout varies in your environment
		panic("timeout")
	}

	
Output:

Alice creates an out-of-band invitation
Bob accepts the out-of-band invitation received via an out of band channel and created connectionID abcdefg
Alice received https://didcomm.org/didexchange/1.0/request from Bob
Alice created connectionID xyz

func (*Client) AcceptRequest

func (c *Client) AcceptRequest(r *Request, myLabel string) (string, error)

AcceptRequest from another agent and return the ID of a new connection record.

Example

Example of an edge agent accepting an out-of-band request from a router.

{ //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
	req, err := router.CreateRequest(
		[]*decorator.Attachment{{
			ID: uuid.New().String(),
			Data: decorator.AttachmentData{
				Base64: base64.StdEncoding.EncodeToString(routeRequest),
			},
		}},
		WithLabel(Router),
	)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%s creates an out-of-band request with an embedded route-request message\n", Router)

	// the edge agent accepts the outofband request
	bobConnID, err := bob.AcceptRequest(req, Bob)
	if err != nil {
		panic(err)
	}

	fmt.Printf(
		"%s accepts the out-of-band request 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()
	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())

	
Output:

Router creates an out-of-band request with an embedded route-request message
Bob accepts the out-of-band request 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 added in v0.1.4

func (c *Client) ActionContinue(piID, label string) error

ActionContinue allows continuing with the protocol after an action event was triggered.

func (*Client) ActionStop added in v0.1.4

func (c *Client) ActionStop(piID string, err error) error

ActionStop stops the protocol after an action event was triggered.

func (*Client) Actions added in v0.1.4

func (c *Client) Actions() ([]Action, error)

Actions returns unfinished actions for the async usage.

func (*Client) CreateInvitation

func (c *Client) CreateInvitation(protocols []string, opts ...MessageOption) (*Invitation, error)

CreateInvitation creates and saves an out-of-band invitation. Protocols is an optional list of protocol identifier URIs that can be used to form connections. A default will be set if none are provided.

func (*Client) CreateRequest

func (c *Client) CreateRequest(attchmnts []*decorator.Attachment, opts ...MessageOption) (*Request, error)

CreateRequest creates and saves an Out-Of-Band request message. At least one attachment must be provided. Service entries can be optionally provided. If none are provided then a new one will be automatically created 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 added in v0.1.4

type EventOptions struct {
	// Label will be shared with the other agent during the subsequent did-exchange.
	Label 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 added in v0.1.4

func (e *EventOptions) MyLabel() string

MyLabel will be shared with the other agent during the subsequent did-exchange.

type Invitation

type Invitation outofband.Invitation

Invitation is this protocol's `invitation` message.

type MessageOption

type MessageOption func(*message) error

MessageOption allow you to customize the way out-of-band messages are built.

func WithGoal

func WithGoal(goal, goalCode string) MessageOption

WithGoal allows you to specify the `goal` and `goalCode` for the message.

func WithLabel

func WithLabel(l string) MessageOption

WithLabel allows you to specify the label on the message.

func WithServices

func WithServices(svcs ...interface{}) MessageOption

WithServices allows you to specify service entries to include in the request message. Each entry must be either a valid DID (string) or a `service` object.

type OobService added in v0.1.4

type OobService interface {
	service.Event
	AcceptRequest(*outofband.Request, string) (string, error)
	AcceptInvitation(*outofband.Invitation, string) (string, error)
	SaveRequest(*outofband.Request) error
	SaveInvitation(*outofband.Invitation) error
	Actions() ([]outofband.Action, error)
	ActionContinue(string, outofband.Options) error
	ActionStop(string, error) error
}

OobService defines the outofband service.

type Provider

type Provider interface {
	ServiceEndpoint() string
	Service(id string) (interface{}, error)
	KMS() kms.KeyManager
}

Provider provides the dependencies for the client.

type Request

type Request outofband.Request

Request is the out-of-band protocol's 'request' message.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL