github.com/status-im/status-go@v1.1.0/server/pairing/common.go (about)

     1  package pairing
     2  
     3  import (
     4  	"fmt"
     5  	"io/fs"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"regexp"
    11  	"strings"
    12  
    13  	"github.com/status-im/status-go/protocol/requests"
    14  
    15  	"gopkg.in/go-playground/validator.v9"
    16  
    17  	"github.com/status-im/status-go/account/generator"
    18  	"github.com/status-im/status-go/api"
    19  	"github.com/status-im/status-go/eth-node/keystore"
    20  )
    21  
    22  func newValidate() (*validator.Validate, error) {
    23  	var validate = validator.New()
    24  	var keyUIDPattern = regexp.MustCompile(`^0x[0-9a-fA-F]{64}$`)
    25  	if err := validate.RegisterValidation("keyuid", func(fl validator.FieldLevel) bool {
    26  		return keyUIDPattern.MatchString(fl.Field().String())
    27  	}); err != nil {
    28  		return nil, err
    29  	}
    30  
    31  	if err := validate.RegisterValidation("keystorepath", func(fl validator.FieldLevel) bool {
    32  		keyUIDField := fl.Parent()
    33  		if keyUIDField.Kind() == reflect.Ptr {
    34  			keyUIDField = keyUIDField.Elem()
    35  		}
    36  
    37  		keyUID := keyUIDField.FieldByName("KeyUID").String()
    38  		return strings.HasSuffix(fl.Field().String(), keyUID)
    39  	}); err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	return validate, nil
    44  }
    45  
    46  func validateKeys(keys map[string][]byte, password string) error {
    47  	for _, key := range keys {
    48  		k, err := keystore.DecryptKey(key, password)
    49  		if err != nil {
    50  			return err
    51  		}
    52  
    53  		err = generator.ValidateKeystoreExtendedKey(k)
    54  		if err != nil {
    55  			return err
    56  		}
    57  	}
    58  
    59  	return nil
    60  }
    61  
    62  func loadKeys(keys map[string][]byte, keyStorePath string) error {
    63  	fileWalker := func(path string, dirEntry fs.DirEntry, err error) error {
    64  		if err != nil {
    65  			return err
    66  		}
    67  
    68  		if dirEntry.IsDir() || filepath.Dir(path) != keyStorePath {
    69  			return nil
    70  		}
    71  
    72  		rawKeyFile, err := ioutil.ReadFile(path)
    73  		if err != nil {
    74  			return fmt.Errorf("invalid account key file: %v", err)
    75  		}
    76  
    77  		keys[dirEntry.Name()] = rawKeyFile
    78  
    79  		return nil
    80  	}
    81  
    82  	err := filepath.WalkDir(keyStorePath, fileWalker)
    83  	if err != nil {
    84  		return fmt.Errorf("cannot traverse key store folder: %v", err)
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  func validate(s interface{}) error {
    91  	v, err := newValidate()
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	return v.Struct(s)
    97  }
    98  
    99  func validateAndVerifyPassword(s interface{}, senderConfig *SenderConfig) error {
   100  	err := validate(s)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	keys := make(map[string][]byte)
   106  	err = loadKeys(keys, senderConfig.KeystorePath)
   107  	if err != nil {
   108  		return err
   109  	}
   110  
   111  	return validateKeys(keys, senderConfig.Password)
   112  }
   113  
   114  func validateReceiverConfig(s interface{}, receiverConfig *ReceiverConfig) error {
   115  	err := validate(s)
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	return receiverConfig.CreateAccount.Validate(&requests.CreateAccountValidation{
   121  		AllowEmptyDisplayName:        true,
   122  		AllowEmptyCustomizationColor: true,
   123  		AllowEmptyPassword:           true,
   124  	})
   125  }
   126  
   127  func emptyDir(dir string) error {
   128  	// Open the directory
   129  	d, err := os.Open(dir)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	defer d.Close()
   134  
   135  	// Get all the directory entries
   136  	entries, err := d.Readdir(-1)
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	// Remove all the files and directories
   142  	for _, entry := range entries {
   143  		name := entry.Name()
   144  		if name == "." || name == ".." {
   145  			continue
   146  		}
   147  		path := filepath.Join(dir, name)
   148  		if entry.IsDir() {
   149  			err = os.RemoveAll(path)
   150  			if err != nil {
   151  				return err
   152  			}
   153  		} else {
   154  			err = os.Remove(path)
   155  			if err != nil {
   156  				return err
   157  			}
   158  		}
   159  	}
   160  	return nil
   161  }
   162  
   163  func validateReceivedKeystoreFiles(expectedKeys []string, keys map[string][]byte, password string) error {
   164  	for _, searchKey := range expectedKeys {
   165  		found := false
   166  		for key := range keys {
   167  			if strings.Contains(key, strings.ToLower(searchKey)) {
   168  				found = true
   169  				break
   170  			}
   171  		}
   172  		if !found {
   173  			return fmt.Errorf("one or more expected keystore files are not found among the sent files")
   174  		}
   175  	}
   176  
   177  	return validateKeys(keys, password)
   178  }
   179  
   180  func validateKeystoreFilesConfig(backend *api.GethStatusBackend, conf interface{}) error {
   181  	var (
   182  		loggedInKeyUID string
   183  		password       string
   184  		numOfKeypairs  int
   185  		keystorePath   string
   186  	)
   187  
   188  	switch c := conf.(type) {
   189  	case *KeystoreFilesSenderServerConfig:
   190  		loggedInKeyUID = c.SenderConfig.LoggedInKeyUID
   191  		password = c.SenderConfig.Password
   192  		numOfKeypairs = len(c.SenderConfig.KeypairsToExport)
   193  		keystorePath = c.SenderConfig.KeystorePath
   194  	case *KeystoreFilesReceiverClientConfig:
   195  		loggedInKeyUID = c.ReceiverConfig.LoggedInKeyUID
   196  		password = c.ReceiverConfig.Password
   197  		numOfKeypairs = len(c.ReceiverConfig.KeypairsToImport)
   198  		keystorePath = c.ReceiverConfig.KeystorePath
   199  	default:
   200  		return fmt.Errorf("unknown config type: %v", reflect.TypeOf(conf))
   201  	}
   202  
   203  	accountService := backend.StatusNode().AccountService()
   204  	if accountService == nil {
   205  		return fmt.Errorf("cannot resolve accounts service instance")
   206  	}
   207  
   208  	if !accountService.GetMessenger().HasPairedDevices() {
   209  		return fmt.Errorf("there are no known paired devices")
   210  	}
   211  
   212  	selectedAccount, err := backend.GetActiveAccount()
   213  	if err != nil {
   214  		return err
   215  	}
   216  
   217  	if selectedAccount.KeyUID != loggedInKeyUID {
   218  		return fmt.Errorf("configuration is not meant for the logged in account")
   219  	}
   220  
   221  	if selectedAccount.KeycardPairing == "" {
   222  		if !accountService.VerifyPassword(password) {
   223  			return fmt.Errorf("provided password is not correct")
   224  		}
   225  	}
   226  
   227  	if numOfKeypairs == 0 {
   228  		return fmt.Errorf("it should be at least a single keypair set a keystore files are transferred for")
   229  	}
   230  
   231  	if keystorePath == "" {
   232  		return fmt.Errorf("keyStorePath can not be empty")
   233  	}
   234  
   235  	return nil
   236  }