Documentation ¶
Overview ¶
Package issuecredential provides support for the Issue Credential Protocol 2.0: https://github.com/hyperledger/aries-rfcs/blob/master/features/0453-issue-credential-v2/README.md.
Formalizes messages used to issue a credential. The protocol is responsible for orchestrating the message flow according to the RFC.
1. Create your client:
client, err := issuecredential.New(ctx) if err != nil { panic(err) }
2. Register an action event channel.
actions := make(chan service.DIDCommAction) client.RegisterActionEvent(actions)
3. Handle incoming actions.
for { select { case event := <-actions: piid := e.Properties.All()["piid"].(string) if event.Message.Type() == presentproof.ProposeCredentialMsgType { // If Issuer is willing to accept the proposal. client.AcceptProposal(piid, &OfferCredential{}) // If Issuer is not willing to accept the proposal. client.DeclineProposal(piid, reason) } if event.Message.Type() == presentproof.OfferCredentialMsgType { // If Holder is willing to accept the offer. client.AcceptOffer(piid) // If Holder wants to counter an offer they received with a proposal. client.NegotiateProposal(piid, &ProposeCredential{}) // If Holder is not willing to accept the offer. client.DeclineOffer(piid, reason) } if event.Message.Type() == presentproof.RequestCredentialMsgType { // If Issuer is willing to accept the request. client.AcceptRequest(piid, &IssueCredential{}) // If Issuer is not willing to accept the request. client.DeclineRequest(piid, reason) } if event.Message.Type() == presentproof.IssueCredentialMsgType { // If Holder is willing to accept the credentials. client.AcceptCredential(piid, names) // If Holder is not willing to accept the credentials. client.DeclineCredential(piid, reason) } if event.Message.Type() == presentproof.ProblemReportMsgType { // Problem report message is triggered to notify client about the error. // In that case, there is only one option - accept it. client.AcceptProblemReport(piid) } } }
How to initiate the protocol? The protocol can be initiated by the Issuer or by the Holder. Issuer initiates the protocol.
client.SendOffer(&OfferCredential{}, myDID, theirDID)
Holder initiates the protocol. There are two options of how to initiate the protocol.
- The Holder can begin with a proposal. client.SendProposal(&ProposeCredential{}, myDID, theirDID)
- Holder can begin with a request. client.SendRequest(&RequestCredential{}, myDID, theirDID)
Index ¶
- func WithFriendlyNames(names ...string) issuecredential.Opt
- func WithIssueCredential(msg *IssueCredential) issuecredential.Opt
- func WithOfferCredential(msg *OfferCredential) issuecredential.Opt
- func WithProposeCredential(msg *ProposeCredential) issuecredential.Opt
- func WithRequestCredential(msg *RequestCredential) issuecredential.Opt
- type Action
- type Client
- func (c *Client) AcceptCredential(piID string, names ...string) error
- func (c *Client) AcceptOffer(piID string) error
- func (c *Client) AcceptProblemReport(piID string) error
- func (c *Client) AcceptProposal(piID string, msg *OfferCredential) error
- func (c *Client) AcceptRequest(piID string, msg *IssueCredential) error
- func (c *Client) Actions() ([]Action, error)
- func (c *Client) DeclineCredential(piID, reason string) error
- func (c *Client) DeclineOffer(piID, reason string) error
- func (c *Client) DeclineProposal(piID, reason string) error
- func (c *Client) DeclineRequest(piID, reason string) error
- func (c *Client) NegotiateProposal(piID string, msg *ProposeCredential) error
- func (c *Client) SendOffer(offer *OfferCredential, myDID, theirDID string) (string, error)
- func (c *Client) SendProposal(proposal *ProposeCredential, myDID, theirDID string) (string, error)
- func (c *Client) SendRequest(request *RequestCredential, myDID, theirDID string) (string, error)
- type IssueCredential
- type OfferCredential
- type ProposeCredential
- type ProtocolService
- type Provider
- type RequestCredential
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func WithFriendlyNames ¶
func WithFriendlyNames(names ...string) issuecredential.Opt
WithFriendlyNames allows providing names for the credentials. USAGE: This function should be used when the Holder receives IssueCredential message.
func WithIssueCredential ¶
func WithIssueCredential(msg *IssueCredential) issuecredential.Opt
WithIssueCredential allows providing IssueCredential message USAGE: This message should be provided after receiving a RequestCredential message.
func WithOfferCredential ¶
func WithOfferCredential(msg *OfferCredential) issuecredential.Opt
WithOfferCredential allows providing OfferCredential message USAGE: This message should be provided after receiving a ProposeCredential message.
func WithProposeCredential ¶
func WithProposeCredential(msg *ProposeCredential) issuecredential.Opt
WithProposeCredential allows providing ProposeCredential message USAGE: This message should be provided after receiving an OfferCredential message.
func WithRequestCredential ¶
func WithRequestCredential(msg *RequestCredential) issuecredential.Opt
WithRequestCredential allows providing RequestCredential message USAGE: This message should be provided after receiving an OfferCredential message.
Types ¶
type Client ¶
Client enable access to issuecredential API.
func (*Client) AcceptCredential ¶
AcceptCredential is used when the Holder is willing to accept the IssueCredential. NOTE: For async usage.
func (*Client) AcceptOffer ¶
AcceptOffer is used when the Holder is willing to accept the offer.
func (*Client) AcceptProblemReport ¶
AcceptProblemReport accepts problem report action.
func (*Client) AcceptProposal ¶
func (c *Client) AcceptProposal(piID string, msg *OfferCredential) error
AcceptProposal is used when the Issuer is willing to accept the proposal. NOTE: For async usage.
func (*Client) AcceptRequest ¶
func (c *Client) AcceptRequest(piID string, msg *IssueCredential) error
AcceptRequest is used when the Issuer is willing to accept the request. NOTE: For async usage.
func (*Client) DeclineCredential ¶
DeclineCredential is used when the Holder does not want to accept the IssueCredential. NOTE: For async usage.
func (*Client) DeclineOffer ¶
DeclineOffer is used when the Holder does not want to accept the offer. NOTE: For async usage.
func (*Client) DeclineProposal ¶
DeclineProposal is used when the Issuer does not want to accept the proposal. NOTE: For async usage.
func (*Client) DeclineRequest ¶
DeclineRequest is used when the Issuer does not want to accept the request. NOTE: For async usage.
func (*Client) NegotiateProposal ¶
func (c *Client) NegotiateProposal(piID string, msg *ProposeCredential) error
NegotiateProposal is used when the Holder wants to negotiate about an offer he received. NOTE: For async usage. This function can be used only after receiving OfferCredential.
func (*Client) SendOffer ¶
func (c *Client) SendOffer(offer *OfferCredential, myDID, theirDID string) (string, error)
SendOffer is used by the Issuer to send an offer.
Example ¶
transport := map[string]chan payload{ Alice: make(chan payload), Bob: make(chan payload), } // Alice creates client clientAlice, err := New(mockContext(Alice, transport)) if err != nil { panic(err) } // Alice registers channel for actions. actionsAlice := make(chan service.DIDCommAction) err = clientAlice.RegisterActionEvent(actionsAlice) if err != nil { panic(err) } // Bob creates client. clientBob, err := New(mockContext(Bob, transport)) if err != nil { panic(err) } // Bob registers channel for actions. actionsBob := make(chan service.DIDCommAction) err = clientBob.RegisterActionEvent(actionsBob) if err != nil { panic(err) } go func() { for { var acceptErr error select { case e := <-actionsAlice: acceptErr = clientAlice.AcceptRequest(e.Properties.All()["piid"].(string), &IssueCredential{}) case e := <-actionsBob: acceptErr = clientBob.AcceptOffer(e.Properties.All()["piid"].(string)) } if acceptErr != nil { fmt.Println(acceptErr) } } }() // Alice. waitForAlice := waitForFn(clientAlice) // Bob. waitForBob := waitForFn(clientBob) _, err = clientAlice.SendOffer(&OfferCredential{}, Alice, Bob) if err != nil { fmt.Println(err) } waitForAlice() waitForBob()
Output: Bob received https://didcomm.org/issue-credential/2.0/offer-credential from Alice Alice received https://didcomm.org/issue-credential/2.0/request-credential from Bob Bob received https://didcomm.org/issue-credential/2.0/issue-credential from Alice Alice received https://didcomm.org/issue-credential/2.0/ack from Bob
func (*Client) SendProposal ¶
func (c *Client) SendProposal(proposal *ProposeCredential, myDID, theirDID string) (string, error)
SendProposal is used by the Holder to send a proposal.
Example ¶
nolint: gocyclo
transport := map[string]chan payload{ Alice: make(chan payload), Bob: make(chan payload), } // Alice creates client. clientAlice, err := New(mockContext(Alice, transport)) if err != nil { panic(err) } // Alice registers channel for actions. actionsAlice := make(chan service.DIDCommAction) err = clientAlice.RegisterActionEvent(actionsAlice) if err != nil { panic(err) } // Bob creates client. clientBob, err := New(mockContext(Bob, transport)) if err != nil { panic(err) } // Bob registers channel for actions. actionsBob := make(chan service.DIDCommAction) err = clientBob.RegisterActionEvent(actionsBob) if err != nil { panic(err) } go func() { for { var acceptErr error var e service.DIDCommAction select { case e = <-actionsAlice: case e = <-actionsBob: } piid, ok := e.Properties.All()["piid"].(string) if !ok { fmt.Println("empty piid") } if e.Message.Type() == issuecredential.ProposeCredentialMsgType { acceptErr = clientAlice.AcceptProposal(piid, &OfferCredential{}) } if e.Message.Type() == issuecredential.RequestCredentialMsgType { acceptErr = clientAlice.AcceptRequest(piid, &IssueCredential{}) } if e.Message.Type() == issuecredential.OfferCredentialMsgType { acceptErr = clientBob.AcceptOffer(piid) } if e.Message.Type() == issuecredential.IssueCredentialMsgType { acceptErr = clientBob.AcceptCredential(piid) } if acceptErr != nil { fmt.Println(acceptErr) } } }() // Alice. waitForAlice := waitForFn(clientAlice) // Bob. waitForBob := waitForFn(clientBob) _, err = clientBob.SendProposal(&ProposeCredential{}, Bob, Alice) if err != nil { fmt.Println(err) } waitForAlice() waitForBob()
Output: Alice received https://didcomm.org/issue-credential/2.0/propose-credential from Bob Bob received https://didcomm.org/issue-credential/2.0/offer-credential from Alice Alice received https://didcomm.org/issue-credential/2.0/request-credential from Bob Bob received https://didcomm.org/issue-credential/2.0/issue-credential from Alice Alice received https://didcomm.org/issue-credential/2.0/ack from Bob
func (*Client) SendRequest ¶
func (c *Client) SendRequest(request *RequestCredential, myDID, theirDID string) (string, error)
SendRequest is used by the Holder to send a request.
Example ¶
transport := map[string]chan payload{ Alice: make(chan payload), Bob: make(chan payload), } // Alice creates client. clientAlice, err := New(mockContext(Alice, transport)) if err != nil { panic(err) } // Alice registers channel for actions. actionsAlice := make(chan service.DIDCommAction) err = clientAlice.RegisterActionEvent(actionsAlice) if err != nil { panic(err) } // Bob creates client. clientBob, err := New(mockContext(Bob, transport)) if err != nil { panic(err) } // Bob registers channel for actions. actionsBob := make(chan service.DIDCommAction) err = clientBob.RegisterActionEvent(actionsBob) if err != nil { panic(err) } go func() { for { var acceptErr error select { case e := <-actionsAlice: acceptErr = clientAlice.AcceptRequest(e.Properties.All()["piid"].(string), &IssueCredential{}) case e := <-actionsBob: acceptErr = clientBob.AcceptCredential(e.Properties.All()["piid"].(string)) } if acceptErr != nil { fmt.Println(acceptErr) } } }() // Alice. waitForAlice := waitForFn(clientAlice) // Bob. waitForBob := waitForFn(clientBob) _, err = clientBob.SendRequest(&RequestCredential{}, Bob, Alice) if err != nil { fmt.Println(err) } waitForAlice() waitForBob()
Output: Alice received https://didcomm.org/issue-credential/2.0/request-credential from Bob Bob received https://didcomm.org/issue-credential/2.0/issue-credential from Alice Alice received https://didcomm.org/issue-credential/2.0/ack from Bob
type IssueCredential ¶
type IssueCredential issuecredential.IssueCredential
IssueCredential contains as attached payload the credentials being issued and is sent in response to a valid Request Credential message.
type OfferCredential ¶
type OfferCredential issuecredential.OfferCredential
OfferCredential is a message sent by the Issuer to the potential Holder, describing the credential they intend to offer and possibly the price they expect to be paid.
type ProposeCredential ¶
type ProposeCredential issuecredential.ProposeCredential
ProposeCredential is an optional message sent by the potential Holder to the Issuer to initiate the protocol or in response to a offer-credential message when the Holder wants some adjustments made to the credential data offered by Issuer.
type ProtocolService ¶
type ProtocolService interface { service.DIDComm Actions() ([]issuecredential.Action, error) ActionContinue(piID string, opt issuecredential.Opt) error ActionStop(piID string, err error) error }
ProtocolService defines the issuecredential service.
type Provider ¶
Provider contains dependencies for the issuecredential protocol and is typically created by using aries.Context().
type RequestCredential ¶
type RequestCredential issuecredential.RequestCredential
RequestCredential is a message sent by the potential Holder to the Issuer, to request the issuance of a credential. Where circumstances do not require a preceding Offer Credential message (e.g., there is no cost to issuance that the Issuer needs to explain in advance, and there is no need for cryptographic negotiation), this message initiates the protocol.