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  }