github.com/hyperledger/aries-framework-go@v0.3.2/pkg/client/presentproof/client.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package presentproof 8 9 import ( 10 "errors" 11 12 "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service" 13 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator" 14 "github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/presentproof" 15 "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" 16 "github.com/hyperledger/aries-framework-go/pkg/store/connection" 17 ) 18 19 type ( 20 // ProposePresentation is an optional message sent by the Prover to the verifier to initiate a proof 21 // presentation process, or in response to a request-presentation message when the Prover wants to 22 // propose using a different presentation format. 23 ProposePresentation = presentproof.ProposePresentationParams 24 // RequestPresentation describes values that need to be revealed and predicates that need to be fulfilled. 25 RequestPresentation = presentproof.RequestPresentationParams 26 // Presentation is a response to a RequestPresentation message and contains signed presentations. 27 Presentation = presentproof.PresentationParams 28 // ProposePresentationV2 is an optional message sent by the Prover to the verifier to initiate a proof 29 // presentation process, or in response to a request-presentation message when the Prover wants to 30 // propose using a different presentation format. 31 ProposePresentationV2 presentproof.ProposePresentationV2 32 // RequestPresentationV2 describes values that need to be revealed and predicates that need to be fulfilled. 33 RequestPresentationV2 presentproof.RequestPresentationV2 34 // PresentationV2 is a response to a RequestPresentationV2 message and contains signed presentations. 35 PresentationV2 presentproof.PresentationV2 36 // ProposePresentationV3 is an optional message sent by the Prover to the verifier to initiate a proof 37 // presentation process, or in response to a request-presentation message when the Prover wants to 38 // propose using a different presentation format. 39 ProposePresentationV3 presentproof.ProposePresentationV3 40 // RequestPresentationV3 describes values that need to be revealed and predicates that need to be fulfilled. 41 RequestPresentationV3 presentproof.RequestPresentationV3 42 // PresentationV3 is a response to a RequestPresentationV3 message and contains signed presentations. 43 PresentationV3 presentproof.PresentationV3 44 // Action contains helpful information about action. 45 Action presentproof.Action 46 ) 47 48 const ( 49 // web redirect decorator. 50 webRedirectDecorator = "~web-redirect" 51 webRedirectStatusOK = "OK" 52 webRedirectStatusFAIL = "FAIL" 53 ) 54 55 var ( 56 errEmptyRequestPresentation = errors.New("request presentation message is empty") 57 errEmptyProposePresentation = errors.New("propose presentation message is empty") 58 ) 59 60 // Provider contains dependencies for the protocol and is typically created by using aries.Context(). 61 type Provider interface { 62 Service(id string) (interface{}, error) 63 } 64 65 // ProtocolService defines the presentproof service. 66 type ProtocolService interface { 67 service.DIDComm 68 Actions() ([]presentproof.Action, error) 69 ActionContinue(piID string, opt ...presentproof.Opt) error 70 ActionStop(piID string, err error, opt ...presentproof.Opt) error 71 } 72 73 // Client enable access to presentproof API 74 // https://github.com/hyperledger/aries-rfcs/tree/master/features/0037-present-proof 75 type Client struct { 76 service.Event 77 service ProtocolService 78 } 79 80 // New returns new instance of the presentproof client. 81 func New(ctx Provider) (*Client, error) { 82 raw, err := ctx.Service(presentproof.Name) 83 if err != nil { 84 return nil, err 85 } 86 87 svc, ok := raw.(ProtocolService) 88 if !ok { 89 return nil, errors.New("cast service to presentproof service failed") 90 } 91 92 return &Client{ 93 Event: svc, 94 service: svc, 95 }, nil 96 } 97 98 // Actions returns pending actions that have yet to be executed or cancelled. 99 func (c *Client) Actions() ([]Action, error) { 100 actions, err := c.service.Actions() 101 if err != nil { 102 return nil, err 103 } 104 105 result := make([]Action, len(actions)) 106 for i, action := range actions { 107 result[i] = Action(action) 108 } 109 110 return result, nil 111 } 112 113 // SendRequestPresentation is used by the Verifier to send a request presentation. 114 // It returns the threadID of the new instance of the protocol. 115 func (c *Client) SendRequestPresentation( 116 params *RequestPresentation, connRec *connection.Record) (string, error) { 117 if params == nil { 118 return "", errEmptyRequestPresentation 119 } 120 121 switch connRec.DIDCommVersion { 122 default: 123 fallthrough // use didcomm v1 + present-proof v2 by default, if the connection record doesn't indicate version. 124 case service.V1: 125 return c.service.HandleOutbound(service.NewDIDCommMsgMap(&RequestPresentationV2{ 126 Type: presentproof.RequestPresentationMsgTypeV2, 127 Comment: params.Comment, 128 WillConfirm: params.WillConfirm, 129 Formats: params.Formats, 130 RequestPresentationsAttach: decorator.GenericAttachmentsToV1(params.Attachments), 131 }), connRec.MyDID, connRec.TheirDID) 132 case service.V2: 133 return c.service.HandleOutbound(service.NewDIDCommMsgMap(&RequestPresentationV3{ 134 Type: presentproof.RequestPresentationMsgTypeV3, 135 Body: presentproof.RequestPresentationV3Body{ 136 GoalCode: params.GoalCode, 137 Comment: params.Comment, 138 WillConfirm: params.WillConfirm, 139 }, 140 Attachments: decorator.GenericAttachmentsToV2(params.Attachments), 141 }), connRec.MyDID, connRec.TheirDID) 142 } 143 } 144 145 type addProof func(presentation *verifiable.Presentation) error 146 147 // AcceptRequestPresentation is used by the Prover is to accept a presentation request. 148 func (c *Client) AcceptRequestPresentation(piID string, msg *Presentation, sign addProof) error { 149 return c.service.ActionContinue(piID, WithMultiOptions(WithPresentation(msg), WithAddProofFn(sign))) 150 } 151 152 // NegotiateRequestPresentation is used by the Prover to counter a presentation request they received with a proposal. 153 func (c *Client) NegotiateRequestPresentation(piID string, msg *ProposePresentation) error { 154 return c.service.ActionContinue(piID, WithProposePresentation(msg)) 155 } 156 157 // DeclineRequestPresentation is used when the Prover does not want to accept the request presentation. 158 func (c *Client) DeclineRequestPresentation(piID, reason string) error { 159 return c.service.ActionStop(piID, errors.New(reason)) 160 } 161 162 // SendProposePresentation is used by the Prover to send a propose presentation. 163 // It returns the threadID of the new instance of the protocol. 164 func (c *Client) SendProposePresentation( 165 params *ProposePresentation, connRec *connection.Record) (string, error) { 166 if params == nil { 167 return "", errEmptyProposePresentation 168 } 169 170 switch connRec.DIDCommVersion { 171 default: 172 fallthrough // use didcomm v1 + present-proof v2 by default, if the connection record doesn't indicate version. 173 case service.V1: 174 return c.service.HandleOutbound(service.NewDIDCommMsgMap(&ProposePresentationV2{ 175 Type: presentproof.ProposePresentationMsgTypeV2, 176 Comment: params.Comment, 177 Formats: params.Formats, 178 ProposalsAttach: decorator.GenericAttachmentsToV1(params.Attachments), 179 }), connRec.MyDID, connRec.TheirDID) 180 case service.V2: 181 return c.service.HandleOutbound(service.NewDIDCommMsgMap(&ProposePresentationV3{ 182 Type: presentproof.ProposePresentationMsgTypeV3, 183 Body: presentproof.ProposePresentationV3Body{ 184 GoalCode: params.GoalCode, 185 Comment: params.Comment, 186 }, 187 Attachments: decorator.GenericAttachmentsToV2(params.Attachments), 188 }), connRec.MyDID, connRec.TheirDID) 189 } 190 } 191 192 // AcceptProposePresentation is used when the Verifier is willing to accept the propose presentation. 193 func (c *Client) AcceptProposePresentation(piID string, msg *RequestPresentation) error { 194 return c.service.ActionContinue(piID, WithRequestPresentation(msg)) 195 } 196 197 // DeclineProposePresentation is used when the Verifier does not want to accept the propose presentation. 198 func (c *Client) DeclineProposePresentation(piID string, options ...DeclinePresentationOptions) error { 199 opts := &declinePresentationOpts{} 200 201 for _, option := range options { 202 option(opts) 203 } 204 205 return c.service.ActionStop(piID, opts.reason, prepareRedirectProperties(opts.redirect, webRedirectStatusFAIL)) 206 } 207 208 // AcceptPresentation is used by the Verifier to accept a presentation. 209 func (c *Client) AcceptPresentation(piID string, options ...AcceptPresentationOptions) error { 210 opts := &acceptPresentationOpts{} 211 212 for _, option := range options { 213 option(opts) 214 } 215 216 return c.service.ActionContinue(piID, presentproof.WithFriendlyNames(opts.names...), 217 prepareRedirectProperties(opts.redirect, webRedirectStatusOK)) 218 } 219 220 // DeclinePresentation is used by the Verifier to decline a presentation. 221 func (c *Client) DeclinePresentation(piID string, options ...DeclinePresentationOptions) error { 222 opts := &declinePresentationOpts{} 223 224 for _, option := range options { 225 option(opts) 226 } 227 228 return c.service.ActionStop(piID, opts.reason, prepareRedirectProperties(opts.redirect, webRedirectStatusFAIL)) 229 } 230 231 // AcceptProblemReport accepts problem report action. 232 func (c *Client) AcceptProblemReport(piID string) error { 233 return c.service.ActionContinue(piID) 234 } 235 236 // WithPresentation allows providing Presentation message. 237 // Use this option to respond to RequestPresentation. 238 func WithPresentation(msg *Presentation) presentproof.Opt { 239 return presentproof.WithPresentation(msg) 240 } 241 242 // WithMultiOptions allows combining several options into one. 243 func WithMultiOptions(opts ...presentproof.Opt) presentproof.Opt { 244 return presentproof.WithMultiOptions(opts...) 245 } 246 247 // WithAddProofFn allows providing function that will sign the Presentation. 248 // Use this option to respond to RequestPresentation. 249 func WithAddProofFn(sign addProof) presentproof.Opt { 250 return presentproof.WithAddProofFn(sign) 251 } 252 253 // WithProposePresentation allows providing ProposePresentation message. 254 // Use this option to respond to RequestPresentation. 255 func WithProposePresentation(msg *ProposePresentation) presentproof.Opt { 256 return presentproof.WithProposePresentation(msg) 257 } 258 259 // WithRequestPresentation allows providing RequestPresentation message. 260 // Use this option to respond to ProposePresentation. 261 func WithRequestPresentation(msg *RequestPresentation) presentproof.Opt { 262 return presentproof.WithRequestPresentation(msg) 263 } 264 265 // create web redirect properties to add ~web-redirect decorator. 266 func prepareRedirectProperties(redirect, status string) presentproof.Opt { 267 properties := map[string]interface{}{} 268 269 if redirect != "" { 270 properties[webRedirectDecorator] = &decorator.WebRedirect{ 271 Status: status, 272 URL: redirect, 273 } 274 } 275 276 return presentproof.WithProperties(properties) 277 } 278 279 // declinePresentationOpts options for declining propose presentation and presentation. 280 type declinePresentationOpts struct { 281 reason error 282 redirect string 283 } 284 285 // DeclinePresentationOptions is custom option for declining propose presentation and presentation messages from prover. 286 type DeclinePresentationOptions func(opts *declinePresentationOpts) 287 288 // DeclineReason option to provide optional reason for declining given message. 289 func DeclineReason(reason string) DeclinePresentationOptions { 290 return func(opts *declinePresentationOpts) { 291 if reason != "" { 292 opts.reason = errors.New(reason) 293 } 294 } 295 } 296 297 // DeclineRedirect option to provide optional redirect URL requesting prover to redirect. 298 func DeclineRedirect(url string) DeclinePresentationOptions { 299 return func(opts *declinePresentationOpts) { 300 opts.redirect = url 301 } 302 } 303 304 // acceptPresentationOpts options for accepting presentation message. 305 type acceptPresentationOpts struct { 306 names []string 307 redirect string 308 } 309 310 // AcceptPresentationOptions is custom option for accepting presentation message from prover. 311 type AcceptPresentationOptions func(opts *acceptPresentationOpts) 312 313 // AcceptByFriendlyNames option to provide optional friendly names for accepting presentation message. 314 func AcceptByFriendlyNames(names ...string) AcceptPresentationOptions { 315 return func(opts *acceptPresentationOpts) { 316 opts.names = names 317 } 318 } 319 320 // AcceptByRequestingRedirect option to provide optional redirect URL requesting prover to redirect. 321 func AcceptByRequestingRedirect(url string) AcceptPresentationOptions { 322 return func(opts *acceptPresentationOpts) { 323 opts.redirect = url 324 } 325 }