forked from hyperledger-archives/aries-framework-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
496 lines (436 loc) · 16.7 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package vcwallet
import (
"encoding/json"
"errors"
"fmt"
"github.com/piprate/json-gold/ld"
"github.com/hyperledger/aries-framework-go/pkg/client/outofband"
"github.com/hyperledger/aries-framework-go/pkg/common/log"
"github.com/hyperledger/aries-framework-go/pkg/crypto"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
"github.com/hyperledger/aries-framework-go/pkg/doc/cm"
"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
"github.com/hyperledger/aries-framework-go/pkg/kms"
"github.com/hyperledger/aries-framework-go/pkg/wallet"
"github.com/hyperledger/aries-framework-go/spi/storage"
)
var logger = log.New("aries-framework/client/vcwallet")
// ErrWalletLocked when key manager related operation attempted on locked wallet.
var ErrWalletLocked = errors.New("wallet locked")
// provider contains dependencies for the verifiable credential wallet client
// and is typically created by using aries.Context().
type provider interface {
StorageProvider() storage.Provider
VDRegistry() vdr.Registry
Crypto() crypto.Crypto
JSONLDDocumentLoader() ld.DocumentLoader
MediaTypeProfiles() []string
didCommProvider // to be used only if wallet needs to be participated in DIDComm.
}
// didCommProvider to be used only if wallet needs to be participated in DIDComm operation.
// TODO: using wallet KMS instead of provider KMS.
// TODO: reconcile Protocol storage with wallet store.
type didCommProvider interface {
KMS() kms.KeyManager
ServiceEndpoint() string
ProtocolStateStorageProvider() storage.Provider
Service(id string) (interface{}, error)
KeyType() kms.KeyType
KeyAgreementType() kms.KeyType
}
// walletAuth is auth function which returns wallet unlock token.
type walletAuth func() (string, error)
// noAuth default auth when wallet is still locked.
// nolint:gochecknoglobals
var noAuth walletAuth = func() (string, error) { return "", ErrWalletLocked }
// Client enable access to verifiable credential wallet features.
type Client struct {
wallet *wallet.Wallet
didComm *wallet.DidComm
auth walletAuth
}
// New returns new verifiable credential wallet client for given user.
//
// Args:
// - userID : unique user identifier used for login.
// - provider: dependencies for the verifiable credential wallet client.
// - options : options for unlocking wallet. Any other existing wallet instance of same wallet user will be locked
// once this instance is unlocked.
//
// returns error if wallet profile is not found.
// To create a new wallet profile, use `CreateProfile()`.
// To update an existing profile, use `UpdateProfile()`.
func New(userID string, ctx provider, options ...wallet.UnlockOptions) (*Client, error) {
w, err := wallet.New(userID, ctx)
if err != nil {
return nil, err
}
didComm, err := wallet.NewDidComm(w, ctx)
if err != nil {
return nil, err
}
client := &Client{wallet: w, didComm: didComm, auth: noAuth}
if len(options) > 0 {
if client.Close() {
logger.Debugf("wallet was already open, existing wallet instance key manager is now closed")
}
err = client.Open(options...)
if err != nil {
return nil, err
}
}
return client, nil
}
// CreateProfile creates a new verifiable credential wallet profile for given user.
// returns error if wallet profile is already created.
// Use `UpdateProfile()` for replacing an already created verifiable credential wallet profile.
func CreateProfile(userID string, ctx provider, options ...wallet.ProfileOptions) error {
return wallet.CreateProfile(userID, ctx, options...)
}
// UpdateProfile updates existing verifiable credential wallet profile.
// Will create new profile if no profile exists for given user.
// Caution: you might lose your existing keys if you change kms options.
func UpdateProfile(userID string, ctx provider, options ...wallet.ProfileOptions) error {
return wallet.UpdateProfile(userID, ctx, options...)
}
// ProfileExists checks if profile exists for given wallet user, returns error if not found.
func ProfileExists(userID string, ctx provider) error {
return wallet.ProfileExists(userID, ctx)
}
// Open unlocks wallet client's key manager instance and returns a token for subsequent use of wallet features.
//
// Args:
// - unlock options for opening wallet.
//
// Returns token with expiry that can be used for subsequent use of wallet features.
func (c *Client) Open(options ...wallet.UnlockOptions) error {
authToken, err := c.wallet.Open(options...)
if err != nil {
return err
}
c.auth = func() (s string, e error) {
return authToken, nil
}
return nil
}
// Close expires token issued to this VC wallet client.
// returns false if token is not found or already expired for this wallet user.
func (c *Client) Close() bool {
c.auth = noAuth
return c.wallet.Close()
}
// Export produces a serialized exported wallet representation.
// Only ciphertext wallet contents can be exported.
//
// Args:
// - auth: token to be used to lock the wallet before exporting.
//
// Returns exported locked wallet.
//
// Supported data models:
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Collection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Credential
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#DIDResolutionResponse
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#meta-data
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#connection
//
func (c *Client) Export(auth string) (json.RawMessage, error) {
// TODO to be added #2433
return nil, fmt.Errorf("to be implemented")
}
// Import Takes a serialized exported wallet representation as input
// and imports all contents into wallet.
//
// Args:
// - contents: wallet content to be imported.
// - auth: token used while exporting the wallet.
//
// Supported data models:
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Collection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Credential
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#DIDResolutionResponse
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#meta-data
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#connection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Key
//
func (c *Client) Import(auth string, contents json.RawMessage) error {
// TODO to be added #2433
return fmt.Errorf("to be implemented")
}
// Add adds given data model to wallet contents store.
//
// Supported data models:
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Collection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Credential
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#DIDResolutionResponse
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#meta-data
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#connection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Key
//
// TODO: (#2433) support for correlation between wallet contents (ex: credentials to a profile/collection).
func (c *Client) Add(contentType wallet.ContentType, content json.RawMessage, options ...wallet.AddContentOptions) error { //nolint: lll
auth, err := c.auth()
if err != nil {
return err
}
return c.wallet.Add(auth, contentType, content, options...)
}
// Remove removes wallet content by content ID.
//
// Supported data models:
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Collection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Credential
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#DIDResolutionResponse
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#meta-data
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#connection
//
func (c *Client) Remove(contentType wallet.ContentType, contentID string) error {
auth, err := c.auth()
if err != nil {
return err
}
return c.wallet.Remove(auth, contentType, contentID)
}
// Get fetches a wallet content by content ID.
//
// Supported data models:
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Collection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Credential
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#DIDResolutionResponse
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#meta-data
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#connection
//
func (c *Client) Get(contentType wallet.ContentType, contentID string) (json.RawMessage, error) {
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.Get(auth, contentType, contentID)
}
// GetAll fetches all wallet contents of given type.
//
// Supported data models:
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Collection
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#Credential
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#DIDResolutionResponse
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#meta-data
// - https://w3c-ccg.github.io/universal-wallet-interop-spec/#connection
//
func (c *Client) GetAll(contentType wallet.ContentType, options ...wallet.GetAllContentsOptions) (map[string]json.RawMessage, error) { //nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.GetAll(auth, contentType, options...)
}
// Query runs query against wallet credential contents and returns presentation containing credential results.
//
// https://w3c-ccg.github.io/universal-wallet-interop-spec/#query
//
// Supported Query Types:
// - https://www.w3.org/TR/json-ld11-framing
// - https://identity.foundation/presentation-exchange
// - https://w3c-ccg.github.io/vp-request-spec/#query-by-example
//
func (c *Client) Query(params ...*wallet.QueryParams) ([]*verifiable.Presentation, error) {
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.Query(auth, params...)
}
// Issue adds proof to a Verifiable Credential.
//
// Args:
// - A verifiable credential with or without proof
// - Proof options
//
func (c *Client) Issue(credential json.RawMessage,
options *wallet.ProofOptions) (*verifiable.Credential, error) {
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.Issue(auth, credential, options)
}
// Prove produces a Verifiable Presentation.
//
// Args:
// - list of interfaces (string of credential IDs which can be resolvable to stored credentials in wallet or
// raw credential).
// - proof options
//
func (c *Client) Prove(opts *wallet.ProofOptions, creds ...wallet.ProveOptions) (*verifiable.Presentation, error) { //nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.Prove(auth, opts, creds...)
}
// Verify takes Takes a Verifiable Credential or Verifiable Presentation as input,.
//
// Args:
// - verification option for sending different models (stored credential ID, raw credential, raw presentation).
//
// Returns: a boolean verified, and an error if verified is false.
func (c *Client) Verify(option wallet.VerificationOption) (bool, error) {
auth, err := c.auth()
if err != nil {
return false, err
}
return c.wallet.Verify(auth, option)
}
// Derive derives a credential and returns response credential.
//
// Args:
// - credential to derive (ID of the stored credential, raw credential or credential instance).
// - derive options.
//
func (c *Client) Derive(credential wallet.CredentialToDerive, options *wallet.DeriveOptions) (*verifiable.Credential, error) { //nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.Derive(auth, credential, options)
}
// CreateKeyPair creates key pair inside a wallet.
//
// Args:
// - authToken: authorization for performing create key pair operation.
// - keyType: type of the key to be created.
//
func (c *Client) CreateKeyPair(keyType kms.KeyType) (*wallet.KeyPair, error) {
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.CreateKeyPair(auth, keyType)
}
// Connect accepts out-of-band invitations and performs DID exchange.
//
// Args:
// - invitation: out-of-band invitation.
// - options: connection options.
//
// Returns:
// - connection ID if DID exchange is successful.
// - error if operation false.
//
func (c *Client) Connect(invitation *outofband.Invitation, options ...wallet.ConnectOptions) (string, error) {
auth, err := c.auth()
if err != nil {
return "", err
}
return c.didComm.Connect(auth, invitation, options...)
}
// ProposePresentation accepts out-of-band invitation and sends message proposing presentation
// from wallet to relying party.
//
// https://w3c-ccg.github.io/universal-wallet-interop-spec/#proposepresentation
//
// Currently Supporting
// [0454-present-proof-v2](https://github.com/hyperledger/aries-rfcs/tree/master/features/0454-present-proof-v2)
//
// Args:
// - invitation: out-of-band invitation from relying party.
// - options: options for accepting invitation and send propose presentation message.
//
// Returns:
// - DIDCommMsgMap containing request presentation message if operation is successful.
// - error if operation fails.
//
func (c *Client) ProposePresentation(invitation *wallet.GenericInvitation, options ...wallet.InitiateInteractionOption) (*service.DIDCommMsgMap, error) { //nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.didComm.ProposePresentation(auth, invitation, options...)
}
// PresentProof sends message present proof message from wallet to relying party.
// https://w3c-ccg.github.io/universal-wallet-interop-spec/#presentproof
//
// Currently Supporting
// [0454-present-proof-v2](https://github.com/hyperledger/aries-rfcs/tree/master/features/0454-present-proof-v2)
//
// Args:
// - thID: thread ID (action ID) of request presentation.
// - presentation: presentation to be sent.
//
// Returns:
// - Credential interaction status containing status, redirectURL.
// - error if operation fails.
//
func (c *Client) PresentProof(thID string, presentProofFrom ...wallet.ConcludeInteractionOptions) (*wallet.CredentialInteractionStatus, error) { //nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.didComm.PresentProof(auth, thID, presentProofFrom...)
}
// ProposeCredential sends propose credential message from wallet to issuer.
// https://w3c-ccg.github.io/universal-wallet-interop-spec/#requestcredential
//
// Currently Supporting : 0453-issueCredentialV2
// https://github.com/hyperledger/aries-rfcs/blob/main/features/0453-issue-credential-v2/README.md
//
// Args:
// - invitation: out-of-band invitation from issuer.
// - options: options for accepting invitation and send propose credential message.
//
// Returns:
// - DIDCommMsgMap containing offer credential message if operation is successful.
// - error if operation fails.
//
func (c *Client) ProposeCredential(invitation *wallet.GenericInvitation, options ...wallet.InitiateInteractionOption) (*service.DIDCommMsgMap, error) { // nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.didComm.ProposeCredential(auth, invitation, options...)
}
// RequestCredential sends request credential message from wallet to issuer and
// optionally waits for credential response.
// https://w3c-ccg.github.io/universal-wallet-interop-spec/#proposecredential
//
// Currently Supporting : 0453-issueCredentialV2
// https://github.com/hyperledger/aries-rfcs/blob/main/features/0453-issue-credential-v2/README.md
//
// Args:
// - thID: thread ID (action ID) of offer credential message previously received.
// - concludeInteractionOptions: options to conclude interaction like presentation to be shared etc.
//
// Returns:
// - Credential interaction status containing status, redirectURL.
// - error if operation fails.
//
func (c *Client) RequestCredential(thID string, options ...wallet.ConcludeInteractionOptions) (*wallet.CredentialInteractionStatus, error) { // nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.didComm.RequestCredential(auth, thID, options...)
}
// ResolveCredentialManifest resolves given credential manifest by credential response or credential.
// Supports: https://identity.foundation/credential-manifest/
//
// Args:
// - authToken: authorization for performing operation.
// - manifest: Credential manifest data model in raw format.
// - resolve: options to provide credential response or credential to resolve.
//
// Returns:
// - list of resolved descriptors.
// - error if operation fails.
//
func (c *Client) ResolveCredentialManifest(manifest json.RawMessage, resolve wallet.ResolveManifestOption) ([]*cm.ResolvedDescriptor, error) { // nolint: lll
auth, err := c.auth()
if err != nil {
return nil, err
}
return c.wallet.ResolveCredentialManifest(auth, manifest, resolve)
}