github.com/hyperledger/aries-framework-go@v0.3.2/pkg/wallet/profile.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package wallet 8 9 import ( 10 "encoding/json" 11 "errors" 12 "fmt" 13 14 "github.com/google/uuid" 15 16 "github.com/hyperledger/aries-framework-go/pkg/kms" 17 "github.com/hyperledger/aries-framework-go/pkg/secretlock" 18 "github.com/hyperledger/aries-framework-go/spi/storage" 19 ) 20 21 const ( 22 profileStoreName = "vcwallet_profiles" 23 profileStoreUserKeyPrefix = "vcwallet_usr_%s" 24 ) 25 26 // ErrProfileNotFound error for wallet profile not found scenario. 27 var ErrProfileNotFound = errors.New("profile does not exist") 28 29 // profile of VC wallet contains wallet specific settings of wallet user to be remembered. 30 type profile struct { 31 // ID unique identifier assigned to this wallet profile. 32 ID string 33 34 // User ID of the wallet profile user. 35 User string 36 37 // Encrypted MasterLock is for localkms. 38 MasterLockCipher string 39 40 // KeyServerURL for remotekms. 41 KeyServerURL string 42 43 // EDV configuration 44 EDVConf *edvConf 45 } 46 47 type edvConf struct { 48 // ServerURL for encrypted data vault storage of wallet contents. 49 ServerURL string 50 51 // VaultID for encrypted data vault storage of wallet contents. 52 VaultID string 53 54 // Key ID for encryption key for EDV. 55 EncryptionKeyID string 56 57 // Key ID for MAC key for EDV. 58 MACKeyID string 59 } 60 61 // createProfile creates new verifiable credential wallet profile for given user and saves it in store. 62 // This profile is required for creating verifiable credential wallet client. 63 func createProfile(user string, opts *profileOpts) (*profile, error) { 64 profile := &profile{User: user, ID: uuid.New().String()} 65 66 err := profile.setKMSOptions(opts.passphrase, opts.secretLockSvc, opts.keyServerURL) 67 if err != nil { 68 return nil, err 69 } 70 71 err = profile.setEDVOptions(opts.edvConf) 72 if err != nil { 73 return nil, err 74 } 75 76 return profile, nil 77 } 78 79 func (pr *profile) setKMSOptions(passphrase string, secretLockSvc secretlock.Service, keyServerURL string) error { 80 pr.resetKMSOptions() 81 82 var err error 83 84 switch { 85 case passphrase != "": 86 // localkms with passphrase 87 secretLockSvc, err = getDefaultSecretLock(passphrase) 88 if err != nil { 89 return err 90 } 91 92 pr.MasterLockCipher, err = createMasterLock(secretLockSvc) 93 if err != nil { 94 return err 95 } 96 case secretLockSvc != nil: 97 // localkms with secret lock service 98 pr.MasterLockCipher, err = createMasterLock(secretLockSvc) 99 if err != nil { 100 return err 101 } 102 case keyServerURL != "": 103 // remotekms 104 pr.KeyServerURL = keyServerURL 105 default: 106 return fmt.Errorf("invalid create profile options") 107 } 108 109 return nil 110 } 111 112 func (pr *profile) setEDVOptions(opts *edvConf) error { 113 if opts == nil { 114 return nil 115 } 116 117 if opts.ServerURL == "" || opts.VaultID == "" { 118 return errors.New("invalid EDV settings in profile") 119 } 120 121 pr.EDVConf = opts 122 123 return nil 124 } 125 126 func (pr *profile) setupEDVEncryptionKey(keyManager kms.KeyManager) error { 127 kid, _, err := keyManager.Create(kms.NISTP256ECDHKWType) 128 if err != nil { 129 return err 130 } 131 132 pr.EDVConf.EncryptionKeyID = kid 133 134 return nil 135 } 136 137 func (pr *profile) setupEDVMacKey(keyManager kms.KeyManager) error { 138 kid, _, err := keyManager.Create(kms.HMACSHA256Tag256Type) 139 if err != nil { 140 return err 141 } 142 143 pr.EDVConf.MACKeyID = kid 144 145 return nil 146 } 147 148 func (pr *profile) resetKMSOptions() { 149 pr.KeyServerURL = "" 150 pr.MasterLockCipher = "" 151 } 152 153 // getUserKeyPrefix is key prefix for vc wallet profile store user key. 154 func getUserKeyPrefix(user string) string { 155 return fmt.Sprintf(profileStoreUserKeyPrefix, user) 156 } 157 158 // newProfileStore creates new profile store. 159 func newProfileStore(provider storage.Provider) (*profileStore, error) { 160 store, err := provider.OpenStore(profileStoreName) 161 if err != nil { 162 return nil, err 163 } 164 165 return &profileStore{store: store}, nil 166 } 167 168 // profileStore is store for vc wallet profiles contains unique collection of user profile info. 169 // key --> userID, val --> profile. 170 type profileStore struct { 171 store storage.Store 172 } 173 174 // getProfile gets profile from store. 175 func (p *profileStore) get(user string) (*profile, error) { 176 profileBytes, err := p.store.Get(getUserKeyPrefix(user)) 177 if err != nil { 178 if errors.Is(err, storage.ErrDataNotFound) { 179 return nil, ErrProfileNotFound 180 } 181 182 return nil, err 183 } 184 185 var result profile 186 187 err = json.Unmarshal(profileBytes, &result) 188 if err != nil { 189 return nil, err 190 } 191 192 return &result, nil 193 } 194 195 // save saves profile into store, 196 // if argument 'override=true' then replaces existing profile else returns error. 197 func (p *profileStore) save(val *profile, override bool) error { 198 if !override { 199 profileBytes, _ := p.get(val.User) //nolint: errcheck 200 if profileBytes != nil { 201 return fmt.Errorf("profile already exists for given user") 202 } 203 } 204 205 profileBytes, err := json.Marshal(val) 206 if err != nil { 207 return err 208 } 209 210 return p.store.Put(getUserKeyPrefix(val.User), profileBytes) 211 }