github.com/status-im/status-go@v1.1.0/server/pairing/payload_receiver.go (about) 1 package pairing 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "go.uber.org/multierr" 11 "go.uber.org/zap" 12 13 "github.com/status-im/status-go/api" 14 "github.com/status-im/status-go/multiaccounts" 15 "github.com/status-im/status-go/multiaccounts/accounts" 16 "github.com/status-im/status-go/protocol/requests" 17 "github.com/status-im/status-go/signal" 18 ) 19 20 type PayloadReceiver interface { 21 PayloadLocker 22 23 // Receive accepts data from an inbound source into the PayloadReceiver's state 24 Receive(data []byte) error 25 26 // Received returns a decrypted and parsed payload from an inbound source 27 Received() []byte 28 } 29 30 type PayloadStorer interface { 31 Store() error 32 } 33 34 type BasePayloadReceiver struct { 35 *PayloadLockPayload 36 *PayloadReceived 37 38 encryptor *PayloadEncryptor 39 unmarshaller ProtobufUnmarshaller 40 storer PayloadStorer 41 42 receiveCallback func() 43 } 44 45 func NewBasePayloadReceiver(e *PayloadEncryptor, um ProtobufUnmarshaller, s PayloadStorer, callback func()) *BasePayloadReceiver { 46 return &BasePayloadReceiver{ 47 PayloadLockPayload: &PayloadLockPayload{e}, 48 PayloadReceived: &PayloadReceived{e}, 49 encryptor: e, 50 unmarshaller: um, 51 storer: s, 52 receiveCallback: callback, 53 } 54 } 55 56 // Receive takes a []byte representing raw data, parses and stores the data 57 func (bpr *BasePayloadReceiver) Receive(data []byte) error { 58 err := bpr.encryptor.decrypt(data) 59 if err != nil { 60 return err 61 } 62 63 err = bpr.unmarshaller.UnmarshalProtobuf(bpr.Received()) 64 if err != nil { 65 return err 66 } 67 68 err = bpr.storer.Store() 69 if err != nil { 70 return err 71 } 72 73 if bpr.receiveCallback != nil { 74 bpr.receiveCallback() 75 } 76 77 return nil 78 } 79 80 /* 81 |-------------------------------------------------------------------------- 82 | AccountPayload 83 |-------------------------------------------------------------------------- 84 | 85 | AccountPayloadReceiver, AccountPayloadStorer and AccountPayloadMarshaller 86 | 87 */ 88 89 // NewAccountPayloadReceiver generates a new and initialised AccountPayload flavoured BasePayloadReceiver 90 // AccountPayloadReceiver is responsible for the whole receive and store cycle of an AccountPayload 91 func NewAccountPayloadReceiver(e *PayloadEncryptor, p *AccountPayload, config *ReceiverConfig, logger *zap.Logger) (*BasePayloadReceiver, error) { 92 l := logger.Named("AccountPayloadManager") 93 l.Debug("fired", zap.Any("config", config)) 94 95 e = e.Renew() 96 97 aps, err := NewAccountPayloadStorer(p, config) 98 if err != nil { 99 return nil, err 100 } 101 102 return NewBasePayloadReceiver(e, NewPairingPayloadMarshaller(p, l), aps, 103 func() { 104 data := AccountData{Account: p.multiaccount, Password: p.password, ChatKey: p.chatKey} 105 signal.SendLocalPairingEvent(Event{Type: EventReceivedAccount, Action: ActionPairingAccount, Data: data}) 106 }, 107 ), nil 108 } 109 110 // AccountPayloadStorer is responsible for parsing, validating and storing AccountPayload data 111 type AccountPayloadStorer struct { 112 *AccountPayload 113 multiaccountsDB *multiaccounts.Database 114 115 keystorePath string 116 kdfIterations int 117 loggedInKeyUID string 118 } 119 120 func NewAccountPayloadStorer(p *AccountPayload, config *ReceiverConfig) (*AccountPayloadStorer, error) { 121 ppr := &AccountPayloadStorer{ 122 AccountPayload: p, 123 } 124 125 if config == nil { 126 return ppr, nil 127 } 128 129 if config.CreateAccount != nil { 130 ppr.kdfIterations = config.CreateAccount.KdfIterations 131 ppr.keystorePath = config.AbsoluteKeystorePath() 132 } 133 134 ppr.multiaccountsDB = config.DB 135 ppr.loggedInKeyUID = config.LoggedInKeyUID 136 return ppr, nil 137 } 138 139 func (aps *AccountPayloadStorer) Store() error { 140 keyUID := aps.multiaccount.KeyUID 141 if aps.loggedInKeyUID != "" && aps.loggedInKeyUID != keyUID { 142 return ErrLoggedInKeyUIDConflict 143 } 144 if aps.loggedInKeyUID == keyUID { 145 // skip storing keys if user is logged in with the same key 146 return nil 147 } 148 149 err := validateKeys(aps.keys, aps.password) 150 if err != nil { 151 return err 152 } 153 154 if err = aps.storeKeys(aps.keystorePath); err != nil && err != ErrKeyFileAlreadyExists { 155 return err 156 } 157 158 // skip storing multiaccount if key already exists 159 if err == ErrKeyFileAlreadyExists { 160 aps.exist = true 161 aps.multiaccount, err = aps.multiaccountsDB.GetAccount(keyUID) 162 if err != nil { 163 return err 164 } 165 return nil 166 } 167 return aps.storeMultiAccount() 168 } 169 170 func (aps *AccountPayloadStorer) storeKeys(keyStorePath string) error { 171 if keyStorePath == "" { 172 return fmt.Errorf("keyStorePath can not be empty") 173 } 174 175 _, lastDir := filepath.Split(keyStorePath) 176 177 // If lastDir == keystoreDir we presume we need to create the rest of the keystore path 178 // else we presume the provided keystore is valid 179 if lastDir == api.DefaultKeystoreRelativePath { 180 if aps.multiaccount == nil || aps.multiaccount.KeyUID == "" { 181 return fmt.Errorf("no known Key UID") 182 } 183 keyStorePath = filepath.Join(keyStorePath, aps.multiaccount.KeyUID) 184 _, err := os.Stat(keyStorePath) 185 if os.IsNotExist(err) { 186 err := os.MkdirAll(keyStorePath, 0700) 187 if err != nil { 188 return err 189 } 190 } else if err != nil { 191 return err 192 } else { 193 return ErrKeyFileAlreadyExists 194 } 195 } 196 197 for name, data := range aps.keys { 198 err := ioutil.WriteFile(filepath.Join(keyStorePath, name), data, 0600) 199 if err != nil { 200 writeErr := fmt.Errorf("failed to write key to path '%s' : %w", filepath.Join(keyStorePath, name), err) 201 // If we get an error on any of the key files attempt to revert 202 err := emptyDir(keyStorePath) 203 if err != nil { 204 // If we get an error when trying to empty the dir combine the write error and empty error 205 emptyDirErr := fmt.Errorf("failed to revert and cleanup storeKeys : %w", err) 206 return multierr.Combine(writeErr, emptyDirErr) 207 } 208 return writeErr 209 } 210 } 211 return nil 212 } 213 214 func (aps *AccountPayloadStorer) storeMultiAccount() error { 215 aps.multiaccount.KDFIterations = aps.kdfIterations 216 return aps.multiaccountsDB.SaveAccount(*aps.multiaccount) 217 } 218 219 /* 220 |-------------------------------------------------------------------------- 221 | RawMessagePayload 222 |-------------------------------------------------------------------------- 223 | 224 | RawMessagePayloadReceiver and RawMessageStorer 225 | 226 */ 227 228 // NewRawMessagePayloadReceiver generates a new and initialised RawMessagesPayload flavoured BasePayloadReceiver 229 // RawMessagePayloadReceiver is responsible for the whole receive and store cycle of a RawMessagesPayload 230 func NewRawMessagePayloadReceiver(accountPayload *AccountPayload, e *PayloadEncryptor, backend *api.GethStatusBackend, config *ReceiverConfig) *BasePayloadReceiver { 231 e = e.Renew() 232 payload := NewRawMessagesPayload() 233 234 return NewBasePayloadReceiver(e, 235 NewRawMessagePayloadMarshaller(payload), 236 NewRawMessageStorer(backend, payload, accountPayload, config), nil) 237 } 238 239 type RawMessageStorer struct { 240 payload *RawMessagesPayload 241 syncRawMessageHandler *SyncRawMessageHandler 242 accountPayload *AccountPayload 243 createAccount *requests.CreateAccount 244 deviceType string 245 } 246 247 func NewRawMessageStorer(backend *api.GethStatusBackend, payload *RawMessagesPayload, accountPayload *AccountPayload, config *ReceiverConfig) *RawMessageStorer { 248 return &RawMessageStorer{ 249 syncRawMessageHandler: NewSyncRawMessageHandler(backend), 250 payload: payload, 251 accountPayload: accountPayload, 252 deviceType: config.DeviceType, 253 createAccount: config.CreateAccount, 254 } 255 } 256 257 func (r *RawMessageStorer) Store() error { 258 if r.accountPayload == nil || r.accountPayload.multiaccount == nil { 259 return fmt.Errorf("no known multiaccount when storing raw messages") 260 } 261 return r.syncRawMessageHandler.HandleRawMessage(r.accountPayload, r.createAccount, r.deviceType, r.payload) 262 } 263 264 /* 265 |-------------------------------------------------------------------------- 266 | InstallationPayload 267 |-------------------------------------------------------------------------- 268 | 269 | InstallationPayloadReceiver and InstallationPayloadStorer 270 | 271 */ 272 273 // NewInstallationPayloadReceiver generates a new and initialised InstallationPayload flavoured BasePayloadReceiver 274 // InstallationPayloadReceiver is responsible for the whole receive and store cycle of a RawMessagesPayload specifically 275 // for sending / requesting installation data from the Receiver device. 276 func NewInstallationPayloadReceiver(e *PayloadEncryptor, backend *api.GethStatusBackend, deviceType string) *BasePayloadReceiver { 277 e = e.Renew() 278 payload := NewRawMessagesPayload() 279 280 return NewBasePayloadReceiver(e, 281 NewRawMessagePayloadMarshaller(payload), 282 NewInstallationPayloadStorer(backend, payload, deviceType), nil) 283 } 284 285 type InstallationPayloadStorer struct { 286 payload *RawMessagesPayload 287 syncRawMessageHandler *SyncRawMessageHandler 288 deviceType string 289 backend *api.GethStatusBackend 290 } 291 292 func NewInstallationPayloadStorer(backend *api.GethStatusBackend, payload *RawMessagesPayload, deviceType string) *InstallationPayloadStorer { 293 return &InstallationPayloadStorer{ 294 payload: payload, 295 syncRawMessageHandler: NewSyncRawMessageHandler(backend), 296 deviceType: deviceType, 297 backend: backend, 298 } 299 } 300 301 func (r *InstallationPayloadStorer) Store() error { 302 messenger := r.backend.Messenger() 303 if messenger == nil { 304 return fmt.Errorf("messenger is nil when invoke InstallationPayloadRepository#Store()") 305 } 306 err := messenger.SetInstallationDeviceType(r.deviceType) 307 if err != nil { 308 return err 309 } 310 311 installations := GetMessengerInstallationsMap(messenger) 312 313 err = messenger.HandleSyncRawMessages(r.payload.rawMessages) 314 315 if err != nil { 316 return err 317 } 318 319 if newInstallation := FindNewInstallations(messenger, installations); newInstallation != nil { 320 signal.SendLocalPairingEvent(Event{ 321 Type: EventReceivedInstallation, 322 Action: ActionPairingInstallation, 323 Data: newInstallation}) 324 } 325 326 return nil 327 } 328 329 /* 330 |-------------------------------------------------------------------------- 331 | PayloadReceivers 332 |-------------------------------------------------------------------------- 333 | 334 | Funcs for all PayloadReceivers AccountPayloadReceiver, RawMessagePayloadReceiver and InstallationPayloadMounter 335 | 336 */ 337 338 func NewPayloadReceivers(logger *zap.Logger, pe *PayloadEncryptor, backend *api.GethStatusBackend, config *ReceiverConfig) (PayloadReceiver, PayloadReceiver, PayloadMounterReceiver, error) { 339 // A new SHARED AccountPayload 340 p := new(AccountPayload) 341 342 ar, err := NewAccountPayloadReceiver(pe, p, config, logger) 343 if err != nil { 344 return nil, nil, nil, err 345 } 346 rmr := NewRawMessagePayloadReceiver(p, pe, backend, config) 347 imr := NewInstallationPayloadMounterReceiver(pe, backend, config.DeviceType) 348 return ar, rmr, imr, nil 349 } 350 351 /* 352 |-------------------------------------------------------------------------- 353 | KeystoreFilesPayload 354 |-------------------------------------------------------------------------- 355 */ 356 357 func NewKeystoreFilesPayloadReceiver(backend *api.GethStatusBackend, e *PayloadEncryptor, config *KeystoreFilesReceiverConfig, logger *zap.Logger) (*BasePayloadReceiver, error) { 358 l := logger.Named("KeystoreFilesPayloadManager") 359 l.Debug("fired", zap.Any("config", config)) 360 361 e = e.Renew() 362 363 // A new SHARED AccountPayload 364 p := new(AccountPayload) 365 366 kfps, err := NewKeystoreFilesPayloadStorer(backend, p, config) 367 if err != nil { 368 return nil, err 369 } 370 371 return NewBasePayloadReceiver(e, NewPairingPayloadMarshaller(p, l), kfps, 372 func() { 373 data := config.KeypairsToImport 374 signal.SendLocalPairingEvent(Event{Type: EventReceivedKeystoreFiles, Action: ActionKeystoreFilesTransfer, Data: data}) 375 }, 376 ), nil 377 } 378 379 type KeystoreFilesPayloadStorer struct { 380 *AccountPayload 381 382 keystorePath string 383 loggedInKeyUID string 384 expectedKeypairsToImport []string 385 expectedKeystoreFilesToReceive []string 386 backend *api.GethStatusBackend 387 } 388 389 func NewKeystoreFilesPayloadStorer(backend *api.GethStatusBackend, p *AccountPayload, config *KeystoreFilesReceiverConfig) (*KeystoreFilesPayloadStorer, error) { 390 if config == nil { 391 return nil, fmt.Errorf("empty keystore files receiver config") 392 } 393 394 kfps := &KeystoreFilesPayloadStorer{ 395 AccountPayload: p, 396 keystorePath: config.KeystorePath, 397 loggedInKeyUID: config.LoggedInKeyUID, 398 expectedKeypairsToImport: config.KeypairsToImport, 399 backend: backend, 400 } 401 402 accountService := backend.StatusNode().AccountService() 403 404 for _, keyUID := range kfps.expectedKeypairsToImport { 405 kp, err := accountService.GetKeypairByKeyUID(keyUID) 406 if err != nil { 407 return nil, err 408 } 409 410 if kp.Type == accounts.KeypairTypeSeed { 411 kfps.expectedKeystoreFilesToReceive = append(kfps.expectedKeystoreFilesToReceive, kp.DerivedFrom[2:]) 412 } 413 414 for _, acc := range kp.Accounts { 415 kfps.expectedKeystoreFilesToReceive = append(kfps.expectedKeystoreFilesToReceive, acc.Address.Hex()[2:]) 416 } 417 } 418 419 return kfps, nil 420 } 421 422 func (kfps *KeystoreFilesPayloadStorer) Store() error { 423 err := validateReceivedKeystoreFiles(kfps.expectedKeystoreFilesToReceive, kfps.keys, kfps.password) 424 if err != nil { 425 return err 426 } 427 428 return kfps.storeKeys(kfps.keystorePath) 429 } 430 431 func (kfps *KeystoreFilesPayloadStorer) storeKeys(keyStorePath string) error { 432 messenger := kfps.backend.Messenger() 433 if messenger == nil { 434 return fmt.Errorf("messenger is nil") 435 } 436 437 if keyStorePath == "" { 438 return fmt.Errorf("keyStorePath can not be empty") 439 } 440 441 _, lastDir := filepath.Split(keyStorePath) 442 443 // If lastDir == keystoreDir we presume we need to create the rest of the keystore path 444 // else we presume the provided keystore is valid 445 if lastDir == api.DefaultKeystoreRelativePath { 446 keyStorePath = filepath.Join(keyStorePath, kfps.loggedInKeyUID) 447 _, err := os.Stat(keyStorePath) 448 if os.IsNotExist(err) { 449 err := os.MkdirAll(keyStorePath, 0700) 450 if err != nil { 451 return err 452 } 453 } else if err != nil { 454 return err 455 } 456 } 457 458 for name, data := range kfps.keys { 459 found := false 460 for _, key := range kfps.expectedKeystoreFilesToReceive { 461 if strings.Contains(name, strings.ToLower(key)) { 462 found = true 463 } 464 } 465 if !found { 466 continue 467 } 468 469 err := ioutil.WriteFile(filepath.Join(keyStorePath, name), data, 0600) 470 if err != nil { 471 writeErr := fmt.Errorf("failed to write key to path '%s' : %w", filepath.Join(keyStorePath, name), err) 472 // If we get an error on any of the key files attempt to revert 473 err := emptyDir(keyStorePath) 474 if err != nil { 475 // If we get an error when trying to empty the dir combine the write error and empty error 476 emptyDirErr := fmt.Errorf("failed to revert and cleanup storeKeys : %w", err) 477 return multierr.Combine(writeErr, emptyDirErr) 478 } 479 return writeErr 480 } 481 } 482 483 for _, keyUID := range kfps.expectedKeypairsToImport { 484 err := messenger.MarkKeypairFullyOperable(keyUID) 485 if err != nil { 486 return err 487 } 488 } 489 490 return nil 491 }