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 ¶
- Constants
- type Action
- type Client
- func (c *Client) AcceptInvitation(i *Invitation, myLabel string) (string, error)
- func (c *Client) AcceptRequest(r *Request, myLabel string) (string, error)
- func (c *Client) ActionContinue(piID, label string) error
- func (c *Client) ActionStop(piID string, err error) error
- func (c *Client) Actions() ([]Action, error)
- func (c *Client) CreateInvitation(protocols []string, opts ...MessageOption) (*Invitation, error)
- func (c *Client) CreateRequest(attchmnts []*decorator.Attachment, opts ...MessageOption) (*Request, error)
- type Event
- type EventOptions
- type Invitation
- type MessageOption
- type OobService
- type Provider
- type Request
Examples ¶
Constants ¶
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 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) (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 ¶
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
ActionContinue allows continuing with the protocol after an action event was triggered.
func (*Client) ActionStop ¶ added in v0.1.4
ActionStop stops the protocol after an action event was triggered.
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.