github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/identity/manager.go (about) 1 /* 2 * Copyright (C) 2017 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 // Maps Ethereum account to dto.Identity. 19 // Currently creates a new eth account with passphrase on CreateNewIdentity(). 20 21 package identity 22 23 import ( 24 "sync" 25 26 "github.com/ethereum/go-ethereum/accounts" 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/pkg/errors" 29 "github.com/rs/zerolog/log" 30 31 "github.com/mysteriumnetwork/node/eventbus" 32 ) 33 34 // Identity events 35 const ( 36 AppTopicIdentityUnlock = "identity-unlocked" 37 AppTopicIdentityCreated = "identity-created" 38 ) 39 40 // AppEventIdentityUnlock represents the payload that is sent on identity unlock. 41 type AppEventIdentityUnlock struct { 42 ChainID int64 43 ID Identity 44 } 45 46 // ResidentCountryEvent represent actual resident country changed event 47 type ResidentCountryEvent struct { 48 ID string 49 Country string 50 } 51 52 type identityManager struct { 53 keystoreManager keystore 54 residentCountry *ResidentCountry 55 unlocked map[string]bool // Currently unlocked addresses 56 unlockedMu sync.RWMutex 57 eventBus eventbus.EventBus 58 } 59 60 // keystore allows actions with accounts (listing, creating, unlocking, signing) 61 type keystore interface { 62 Accounts() []accounts.Account 63 NewAccount(passphrase string) (accounts.Account, error) 64 Find(a accounts.Account) (accounts.Account, error) 65 Unlock(a accounts.Account, passphrase string) error 66 SignHash(a accounts.Account, hash []byte) ([]byte, error) 67 } 68 69 // NewIdentityManager creates and returns new identityManager 70 func NewIdentityManager(keystore keystore, eventBus eventbus.EventBus, residentCountry *ResidentCountry) *identityManager { 71 return &identityManager{ 72 keystoreManager: keystore, 73 residentCountry: residentCountry, 74 unlocked: map[string]bool{}, 75 eventBus: eventBus, 76 } 77 } 78 79 // GetUnlockedIdentity retrieves unlocked identity 80 func (idm *identityManager) GetUnlockedIdentity() (Identity, bool) { 81 for _, identity := range idm.GetIdentities() { 82 if idm.IsUnlocked(identity.Address) { 83 return identity, true 84 } 85 } 86 return Identity{}, false 87 } 88 89 // IsUnlocked checks if the given identity is unlocked or not 90 func (idm *identityManager) IsUnlocked(identity string) bool { 91 idm.unlockedMu.Lock() 92 defer idm.unlockedMu.Unlock() 93 _, ok := idm.unlocked[identity] 94 return ok 95 } 96 97 func accountToIdentity(account accounts.Account) Identity { 98 identity := FromAddress(account.Address.Hex()) 99 return identity 100 } 101 102 func identityToAccount(identity Identity) accounts.Account { 103 return addressToAccount(identity.Address) 104 } 105 106 func addressToAccount(address string) accounts.Account { 107 return accounts.Account{ 108 Address: common.HexToAddress(address), 109 } 110 } 111 112 func (idm *identityManager) CreateNewIdentity(passphrase string) (identity Identity, err error) { 113 account, err := idm.keystoreManager.NewAccount(passphrase) 114 if err != nil { 115 return identity, err 116 } 117 118 identity = accountToIdentity(account) 119 idm.eventBus.Publish(AppTopicIdentityCreated, identity.Address) 120 return identity, nil 121 } 122 123 func (idm *identityManager) GetIdentities() []Identity { 124 accountList := idm.keystoreManager.Accounts() 125 126 var ids = make([]Identity, len(accountList)) 127 for i, account := range accountList { 128 ids[i] = accountToIdentity(account) 129 } 130 131 return ids 132 } 133 134 func (idm *identityManager) GetIdentity(address string) (identity Identity, err error) { 135 account, err := idm.findAccount(address) 136 if err != nil { 137 return identity, errors.New("identity not found") 138 } 139 140 return accountToIdentity(account), nil 141 } 142 143 func (idm *identityManager) HasIdentity(address string) bool { 144 _, err := idm.findAccount(address) 145 return err == nil 146 } 147 148 func (idm *identityManager) Unlock(chainID int64, address string, passphrase string) error { 149 idm.unlockedMu.Lock() 150 defer idm.unlockedMu.Unlock() 151 152 if idm.unlocked[address] { 153 log.Debug().Msg("Unlocked identity found in cache, skipping keystore: " + address) 154 return nil 155 } 156 157 account, err := idm.findAccount(address) 158 if err != nil { 159 return err 160 } 161 162 err = idm.keystoreManager.Unlock(account, passphrase) 163 if err != nil { 164 return errors.Wrapf(err, "keystore failed to unlock identity: %s", address) 165 } 166 log.Debug().Msgf("Caching unlocked address: %s", address) 167 idm.unlocked[address] = true 168 169 go func() { 170 idm.eventBus.Publish(AppTopicIdentityUnlock, AppEventIdentityUnlock{ 171 ChainID: chainID, 172 ID: FromAddress(address), 173 }) 174 idm.residentCountry.publishResidentCountry(address) 175 }() 176 177 return nil 178 } 179 180 func (idm *identityManager) findAccount(address string) (accounts.Account, error) { 181 account, err := idm.keystoreManager.Find(addressToAccount(address)) 182 if err != nil { 183 return accounts.Account{}, errors.New("identity not found: " + address) 184 } 185 186 return account, err 187 }