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

     1  package pairing
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"encoding/json"
     8  	"encoding/pem"
     9  	"fmt"
    10  	"io"
    11  	"net"
    12  	"net/http"
    13  	"net/http/cookiejar"
    14  	"net/url"
    15  	"runtime"
    16  
    17  	"go.uber.org/zap"
    18  
    19  	"github.com/status-im/status-go/api"
    20  	"github.com/status-im/status-go/logutils"
    21  	"github.com/status-im/status-go/server"
    22  	"github.com/status-im/status-go/signal"
    23  	"github.com/status-im/status-go/timesource"
    24  )
    25  
    26  /*
    27  |--------------------------------------------------------------------------
    28  | BaseClient
    29  |--------------------------------------------------------------------------
    30  |
    31  |
    32  |
    33  */
    34  
    35  // BaseClient is responsible for lower level pairing.Client functionality common to dependent Client types
    36  type BaseClient struct {
    37  	*http.Client
    38  	serverCert     *x509.Certificate
    39  	baseAddress    *url.URL
    40  	challengeTaker *ChallengeTaker
    41  }
    42  
    43  func findServerCert(c *ConnectionParams, reachableIPs []net.IP) (*url.URL, *x509.Certificate, error) {
    44  	var baseAddress *url.URL
    45  	var serverCert *x509.Certificate
    46  
    47  	type connectionError struct {
    48  		ip  net.IP
    49  		err error
    50  	}
    51  	errCh := make(chan connectionError, len(reachableIPs))
    52  
    53  	type result struct {
    54  		u    *url.URL
    55  		cert *x509.Certificate
    56  	}
    57  	successCh := make(chan result, 1) // as we close on the first success
    58  
    59  	for _, ip := range reachableIPs {
    60  		go func(ip net.IP) {
    61  			u := c.BuildURL(ip)
    62  			cert, err := getServerCert(u)
    63  			if err != nil {
    64  				errCh <- connectionError{ip: ip, err: fmt.Errorf("connecting to '%s' failed: %s", u, err.Error())}
    65  				return
    66  			}
    67  			// If no error, send the results to the success channel
    68  			successCh <- result{u: u, cert: cert}
    69  		}(ip)
    70  	}
    71  
    72  	// Keep track of error counts
    73  	errorCount := 0
    74  	var combinedErrors string
    75  	for {
    76  		select {
    77  		case success := <-successCh:
    78  			baseAddress = success.u
    79  			serverCert = success.cert
    80  			return baseAddress, serverCert, nil
    81  		case ipErr := <-errCh:
    82  			errorCount++
    83  			combinedErrors += fmt.Sprintf("IP %s: %s; ", ipErr.ip, ipErr.err)
    84  			if errorCount == len(reachableIPs) {
    85  				return nil, nil, fmt.Errorf(combinedErrors)
    86  			}
    87  		}
    88  	}
    89  }
    90  
    91  // NewBaseClient returns a fully qualified BaseClient from the given ConnectionParams
    92  func NewBaseClient(c *ConnectionParams, logger *zap.Logger) (*BaseClient, error) {
    93  	var baseAddress *url.URL
    94  	var serverCert *x509.Certificate
    95  	var certErrs error
    96  
    97  	netIPs, err := server.FindReachableAddressesForPairingClient(c.netIPs)
    98  	if err != nil {
    99  		logger.Error("[local pair client] failed to find reachable addresses", zap.Error(err), zap.Any("netIPs", netIPs))
   100  		signal.SendLocalPairingEvent(Event{Type: EventConnectionError, Error: err.Error(), Action: ActionConnect})
   101  		return nil, err
   102  	}
   103  	// if client and server aren't on the same network, netIPs maybe empty, we should check it before invoking findServerCert
   104  	if len(netIPs) == 0 {
   105  		logger.Error("[local pair client] no reachable addresses found")
   106  		signal.SendLocalPairingEvent(Event{Type: EventConnectionError, Error: "no reachable addresses found", Action: ActionConnect})
   107  		return nil, fmt.Errorf("no reachable addresses found")
   108  	}
   109  
   110  	maxRetries := 3
   111  	for i := 0; i < maxRetries; i++ {
   112  		baseAddress, serverCert, certErrs = findServerCert(c, netIPs)
   113  		if serverCert == nil {
   114  			certErrs = fmt.Errorf("failed to connect to any of given addresses. %w", certErrs)
   115  			logger.Warn("failed to connect to any of given addresses. Retrying...", zap.Error(certErrs), zap.Any("netIPs", netIPs), zap.Int("retry", i+1))
   116  		} else {
   117  			break
   118  		}
   119  	}
   120  
   121  	if serverCert == nil {
   122  		certErrs = fmt.Errorf("failed to connect to any of given addresses. %w", certErrs)
   123  		signal.SendLocalPairingEvent(Event{Type: EventConnectionError, Error: certErrs.Error(), Action: ActionConnect})
   124  		return nil, certErrs
   125  	}
   126  
   127  	// No error on the dial out then the URL.Host is accessible
   128  	signal.SendLocalPairingEvent(Event{Type: EventConnectionSuccess, Action: ActionConnect})
   129  
   130  	err = verifyCert(serverCert, c.publicKey)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	certPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: serverCert.Raw})
   136  
   137  	rootCAs, err := x509.SystemCertPool()
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	if ok := rootCAs.AppendCertsFromPEM(certPem); !ok {
   142  		return nil, fmt.Errorf("failed to append certPem to rootCAs")
   143  	}
   144  
   145  	tr := &http.Transport{
   146  		TLSClientConfig: &tls.Config{
   147  			MinVersion:         tls.VersionTLS12,
   148  			InsecureSkipVerify: false, // MUST BE FALSE
   149  			RootCAs:            rootCAs,
   150  			Time:               timesource.GetCurrentTime,
   151  		},
   152  	}
   153  
   154  	cj, err := cookiejar.New(nil)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	return &BaseClient{
   160  		Client:         &http.Client{Transport: tr, Jar: cj},
   161  		serverCert:     serverCert,
   162  		challengeTaker: NewChallengeTaker(NewPayloadEncryptor(c.aesKey)),
   163  		baseAddress:    baseAddress,
   164  	}, nil
   165  }
   166  
   167  // getChallenge makes a call to the identified Server and receives a [32]byte challenge
   168  func (c *BaseClient) getChallenge() error {
   169  	c.baseAddress.Path = pairingChallenge
   170  	resp, err := c.Get(c.baseAddress.String())
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	if resp.StatusCode != http.StatusOK {
   176  		return fmt.Errorf("[client] status not ok when getting challenge, received '%s'", resp.Status)
   177  	}
   178  
   179  	return c.challengeTaker.SetChallenge(resp)
   180  }
   181  
   182  /*
   183  |--------------------------------------------------------------------------
   184  | SenderClient
   185  |--------------------------------------------------------------------------
   186  |
   187  | With AccountPayloadMounter, RawMessagePayloadMounter and InstallationPayloadMounterReceiver
   188  |
   189  */
   190  
   191  // SenderClient is responsible for sending pairing data to a ReceiverServer
   192  type SenderClient struct {
   193  	*BaseClient
   194  	accountMounter      PayloadMounter
   195  	rawMessageMounter   PayloadMounter
   196  	installationMounter PayloadMounterReceiver
   197  }
   198  
   199  // NewSenderClient returns a fully qualified SenderClient created with the incoming parameters
   200  func NewSenderClient(backend *api.GethStatusBackend, c *ConnectionParams, config *SenderClientConfig) (*SenderClient, error) {
   201  	logger := logutils.ZapLogger().Named("SenderClient")
   202  	pe := NewPayloadEncryptor(c.aesKey)
   203  
   204  	bc, err := NewBaseClient(c, logger)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	am, rmm, imr, err := NewPayloadMounters(logger, pe, backend, config.SenderConfig)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	return &SenderClient{
   215  		BaseClient:          bc,
   216  		accountMounter:      am,
   217  		rawMessageMounter:   rmm,
   218  		installationMounter: imr,
   219  	}, nil
   220  }
   221  
   222  func (c *SenderClient) sendAccountData() error {
   223  	err := c.accountMounter.Mount()
   224  	if err != nil {
   225  		return err
   226  	}
   227  
   228  	c.baseAddress.Path = pairingReceiveAccount
   229  	resp, err := c.Post(c.baseAddress.String(), "application/octet-stream", bytes.NewBuffer(c.accountMounter.ToSend()))
   230  	if err != nil {
   231  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
   232  		return err
   233  	}
   234  
   235  	if resp.StatusCode != http.StatusOK {
   236  		err = fmt.Errorf("[client] status not ok when sending account data, received '%s'", resp.Status)
   237  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
   238  		return err
   239  	}
   240  
   241  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingAccount})
   242  
   243  	c.accountMounter.LockPayload()
   244  	return nil
   245  }
   246  
   247  func (c *SenderClient) sendSyncDeviceData() error {
   248  	err := c.rawMessageMounter.Mount()
   249  	if err != nil {
   250  		return err
   251  	}
   252  
   253  	c.baseAddress.Path = pairingReceiveSyncDevice
   254  	resp, err := c.Post(c.baseAddress.String(), "application/octet-stream", bytes.NewBuffer(c.rawMessageMounter.ToSend()))
   255  	if err != nil {
   256  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   257  		return err
   258  	}
   259  
   260  	if resp.StatusCode != http.StatusOK {
   261  		err = fmt.Errorf("[client] status not okay when sending sync device data, status: %s", resp.Status)
   262  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   263  		return err
   264  	}
   265  
   266  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionSyncDevice})
   267  	return nil
   268  }
   269  
   270  func (c *SenderClient) receiveInstallationData() error {
   271  	c.baseAddress.Path = pairingSendInstallation
   272  	req, err := http.NewRequest(http.MethodGet, c.baseAddress.String(), nil)
   273  	if err != nil {
   274  		return err
   275  	}
   276  
   277  	err = c.challengeTaker.DoChallenge(req)
   278  	if err != nil {
   279  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   280  		return err
   281  	}
   282  
   283  	resp, err := c.Do(req)
   284  	if err != nil {
   285  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   286  		return err
   287  	}
   288  
   289  	if resp.StatusCode != http.StatusOK {
   290  		err = fmt.Errorf("[client] status not ok when receiving installation data, received '%s'", resp.Status)
   291  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   292  		return err
   293  	}
   294  
   295  	payload, err := io.ReadAll(resp.Body)
   296  	if err != nil {
   297  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   298  		return err
   299  	}
   300  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingInstallation})
   301  
   302  	err = c.installationMounter.Receive(payload)
   303  	if err != nil {
   304  		signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionPairingInstallation})
   305  		return err
   306  	}
   307  	signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionPairingInstallation})
   308  	return nil
   309  }
   310  
   311  // setupSendingClient creates a new SenderClient after parsing string inputs
   312  func setupSendingClient(backend *api.GethStatusBackend, cs, configJSON string) (*SenderClient, error) {
   313  	ccp := new(ConnectionParams)
   314  	err := ccp.FromString(cs)
   315  	if err != nil {
   316  		return nil, err
   317  	}
   318  
   319  	conf := NewSenderClientConfig()
   320  	err = json.Unmarshal([]byte(configJSON), conf)
   321  	if err != nil {
   322  		return nil, err
   323  	}
   324  	err = validateAndVerifyPassword(conf, conf.SenderConfig)
   325  	if err != nil {
   326  		return nil, err
   327  	}
   328  
   329  	conf.SenderConfig.DB = backend.GetMultiaccountDB()
   330  
   331  	return NewSenderClient(backend, ccp, conf)
   332  }
   333  
   334  // StartUpSendingClient creates a SenderClient and triggers all `send` calls in sequence to the ReceiverServer
   335  func StartUpSendingClient(backend *api.GethStatusBackend, cs, configJSON string) error {
   336  	c, err := setupSendingClient(backend, cs, configJSON)
   337  	if err != nil {
   338  		return err
   339  	}
   340  	err = c.sendAccountData()
   341  	if err != nil {
   342  		return err
   343  	}
   344  	err = c.sendSyncDeviceData()
   345  	if err != nil {
   346  		return err
   347  	}
   348  	err = c.getChallenge()
   349  	if err != nil {
   350  		return err
   351  	}
   352  	return c.receiveInstallationData()
   353  }
   354  
   355  /*
   356  |--------------------------------------------------------------------------
   357  | ReceiverClient
   358  |--------------------------------------------------------------------------
   359  |
   360  | With AccountPayloadReceiver, RawMessagePayloadReceiver, InstallationPayloadMounterReceiver
   361  |
   362  */
   363  
   364  // ReceiverClient is responsible for accepting pairing data to a SenderServer
   365  type ReceiverClient struct {
   366  	*BaseClient
   367  
   368  	accountReceiver      PayloadReceiver
   369  	rawMessageReceiver   PayloadReceiver
   370  	installationReceiver PayloadMounterReceiver
   371  }
   372  
   373  // NewReceiverClient returns a fully qualified ReceiverClient created with the incoming parameters
   374  func NewReceiverClient(backend *api.GethStatusBackend, c *ConnectionParams, config *ReceiverClientConfig) (*ReceiverClient, error) {
   375  	logger := logutils.ZapLogger().Named("ReceiverClient")
   376  
   377  	bc, err := NewBaseClient(c, logger)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  
   382  	pe := NewPayloadEncryptor(c.aesKey)
   383  
   384  	ar, rmr, imr, err := NewPayloadReceivers(logger, pe, backend, config.ReceiverConfig)
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  
   389  	return &ReceiverClient{
   390  		BaseClient:           bc,
   391  		accountReceiver:      ar,
   392  		rawMessageReceiver:   rmr,
   393  		installationReceiver: imr,
   394  	}, nil
   395  }
   396  
   397  func (c *ReceiverClient) receiveAccountData() error {
   398  	c.baseAddress.Path = pairingSendAccount
   399  	req, err := http.NewRequest(http.MethodGet, c.baseAddress.String(), nil)
   400  	if err != nil {
   401  		return err
   402  	}
   403  
   404  	err = c.challengeTaker.DoChallenge(req)
   405  	if err != nil {
   406  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
   407  		return err
   408  	}
   409  
   410  	resp, err := c.Do(req)
   411  	if err != nil {
   412  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
   413  		return err
   414  	}
   415  
   416  	if resp.StatusCode != http.StatusOK {
   417  		err = fmt.Errorf("[client] status not ok when receiving account data, received '%s'", resp.Status)
   418  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
   419  		return err
   420  	}
   421  
   422  	payload, err := io.ReadAll(resp.Body)
   423  	if err != nil {
   424  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingAccount})
   425  		return err
   426  	}
   427  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingAccount})
   428  
   429  	err = c.accountReceiver.Receive(payload)
   430  	if err != nil {
   431  		signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionPairingAccount})
   432  		return err
   433  	}
   434  	signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionPairingAccount})
   435  	return nil
   436  }
   437  
   438  func (c *ReceiverClient) receiveSyncDeviceData() error {
   439  	c.baseAddress.Path = pairingSendSyncDevice
   440  	req, err := http.NewRequest(http.MethodGet, c.baseAddress.String(), nil)
   441  	if err != nil {
   442  		return err
   443  	}
   444  
   445  	err = c.challengeTaker.DoChallenge(req)
   446  	if err != nil {
   447  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   448  		return err
   449  	}
   450  
   451  	resp, err := c.Do(req)
   452  	if err != nil {
   453  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   454  		return err
   455  	}
   456  
   457  	if resp.StatusCode != http.StatusOK {
   458  		err = fmt.Errorf("[client] status not ok when receiving sync device data, received '%s'", resp.Status)
   459  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   460  		return err
   461  	}
   462  
   463  	payload, err := io.ReadAll(resp.Body)
   464  	if err != nil {
   465  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionSyncDevice})
   466  		return err
   467  	}
   468  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionSyncDevice})
   469  
   470  	err = c.rawMessageReceiver.Receive(payload)
   471  	if err != nil {
   472  		signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionSyncDevice})
   473  		return err
   474  	}
   475  	signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionSyncDevice})
   476  	return nil
   477  }
   478  
   479  func (c *ReceiverClient) sendInstallationData() error {
   480  	err := c.installationReceiver.Mount()
   481  	if err != nil {
   482  		return err
   483  	}
   484  
   485  	c.baseAddress.Path = pairingReceiveInstallation
   486  	req, err := http.NewRequest(http.MethodPost, c.baseAddress.String(), bytes.NewBuffer(c.installationReceiver.ToSend()))
   487  	if err != nil {
   488  		return err
   489  	}
   490  	req.Header.Set("Content-Type", "application/octet-stream")
   491  
   492  	err = c.challengeTaker.DoChallenge(req)
   493  	if err != nil {
   494  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   495  		return err
   496  	}
   497  
   498  	resp, err := c.Do(req)
   499  	if err != nil {
   500  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   501  		return err
   502  	}
   503  
   504  	if resp.StatusCode != http.StatusOK {
   505  		err = fmt.Errorf("[client] status not okay when sending installation data, status: %s", resp.Status)
   506  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionPairingInstallation})
   507  		return err
   508  	}
   509  
   510  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionPairingInstallation})
   511  	return nil
   512  }
   513  
   514  // setupReceivingClient creates a new ReceiverClient after parsing string inputs
   515  func setupReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) (*ReceiverClient, error) {
   516  	ccp := new(ConnectionParams)
   517  	err := ccp.FromString(cs)
   518  	if err != nil {
   519  		return nil, err
   520  	}
   521  
   522  	conf := NewReceiverClientConfig()
   523  	err = json.Unmarshal([]byte(configJSON), conf)
   524  	if err != nil {
   525  		return nil, err
   526  	}
   527  
   528  	// This is a temporal solution to allow clients not to pass DeviceType.
   529  	// Check DeviceType deprecation reason for more info.
   530  	conf.ReceiverConfig.DeviceType = runtime.GOOS
   531  
   532  	err = validateReceiverConfig(conf, conf.ReceiverConfig)
   533  	if err != nil {
   534  		return nil, err
   535  	}
   536  
   537  	// ignore err because we allow no active account here
   538  	activeAccount, _ := backend.GetActiveAccount()
   539  	if activeAccount != nil {
   540  		conf.ReceiverConfig.LoggedInKeyUID = activeAccount.KeyUID
   541  	}
   542  
   543  	conf.ReceiverConfig.DB = backend.GetMultiaccountDB()
   544  
   545  	return NewReceiverClient(backend, ccp, conf)
   546  }
   547  
   548  // StartUpReceivingClient creates a ReceiverClient and triggers all `receive` calls in sequence to the SenderServer
   549  func StartUpReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) error {
   550  	c, err := setupReceivingClient(backend, cs, configJSON)
   551  	if err != nil {
   552  		return err
   553  	}
   554  
   555  	err = c.getChallenge()
   556  	if err != nil {
   557  		return err
   558  	}
   559  	err = c.receiveAccountData()
   560  	if err != nil {
   561  		return err
   562  	}
   563  
   564  	err = c.getChallenge()
   565  	if err != nil {
   566  		return err
   567  	}
   568  	err = c.receiveSyncDeviceData()
   569  	if err != nil {
   570  		return err
   571  	}
   572  
   573  	err = c.getChallenge()
   574  	if err != nil {
   575  		return err
   576  	}
   577  	return c.sendInstallationData()
   578  }
   579  
   580  /*
   581  |--------------------------------------------------------------------------
   582  | ReceiverClient
   583  |--------------------------------------------------------------------------
   584  */
   585  
   586  type KeystoreFilesReceiverClient struct {
   587  	*BaseClient
   588  
   589  	keystoreFilesReceiver PayloadReceiver
   590  }
   591  
   592  func NewKeystoreFilesReceiverClient(backend *api.GethStatusBackend, c *ConnectionParams, config *KeystoreFilesReceiverClientConfig) (*KeystoreFilesReceiverClient, error) {
   593  	logger := logutils.ZapLogger().Named("ReceiverClient")
   594  	bc, err := NewBaseClient(c, logger)
   595  	if err != nil {
   596  		return nil, err
   597  	}
   598  	pe := NewPayloadEncryptor(c.aesKey)
   599  
   600  	kfrc, err := NewKeystoreFilesPayloadReceiver(backend, pe, config.ReceiverConfig, logger)
   601  	if err != nil {
   602  		return nil, err
   603  	}
   604  
   605  	return &KeystoreFilesReceiverClient{
   606  		BaseClient:            bc,
   607  		keystoreFilesReceiver: kfrc,
   608  	}, nil
   609  }
   610  
   611  func (c *KeystoreFilesReceiverClient) receiveKeystoreFilesData() error {
   612  	c.baseAddress.Path = pairingSendAccount
   613  	req, err := http.NewRequest(http.MethodGet, c.baseAddress.String(), nil)
   614  	if err != nil {
   615  		return err
   616  	}
   617  
   618  	err = c.challengeTaker.DoChallenge(req)
   619  	if err != nil {
   620  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionKeystoreFilesTransfer})
   621  		return err
   622  	}
   623  
   624  	resp, err := c.Do(req)
   625  	if err != nil {
   626  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionKeystoreFilesTransfer})
   627  		return err
   628  	}
   629  
   630  	if resp.StatusCode != http.StatusOK {
   631  		err = fmt.Errorf("[client] status not ok when receiving account data, received '%s'", resp.Status)
   632  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionKeystoreFilesTransfer})
   633  		return err
   634  	}
   635  
   636  	payload, err := io.ReadAll(resp.Body)
   637  	if err != nil {
   638  		signal.SendLocalPairingEvent(Event{Type: EventTransferError, Error: err.Error(), Action: ActionKeystoreFilesTransfer})
   639  		return err
   640  	}
   641  	signal.SendLocalPairingEvent(Event{Type: EventTransferSuccess, Action: ActionKeystoreFilesTransfer})
   642  
   643  	err = c.keystoreFilesReceiver.Receive(payload)
   644  	if err != nil {
   645  		signal.SendLocalPairingEvent(Event{Type: EventProcessError, Error: err.Error(), Action: ActionKeystoreFilesTransfer})
   646  		return err
   647  	}
   648  	signal.SendLocalPairingEvent(Event{Type: EventProcessSuccess, Action: ActionKeystoreFilesTransfer})
   649  	return nil
   650  }
   651  
   652  // setupKeystoreFilesReceivingClient creates a new ReceiverClient after parsing string inputs
   653  func setupKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) (*KeystoreFilesReceiverClient, error) {
   654  	ccp := new(ConnectionParams)
   655  	err := ccp.FromString(cs)
   656  	if err != nil {
   657  		return nil, err
   658  	}
   659  
   660  	conf := NewKeystoreFilesReceiverClientConfig()
   661  	err = json.Unmarshal([]byte(configJSON), conf)
   662  	if err != nil {
   663  		return nil, err
   664  	}
   665  	err = validateKeystoreFilesConfig(backend, conf)
   666  	if err != nil {
   667  		return nil, err
   668  	}
   669  
   670  	return NewKeystoreFilesReceiverClient(backend, ccp, conf)
   671  }
   672  
   673  // StartUpKeystoreFilesReceivingClient creates a KeystoreFilesReceiverClient and triggers all `receive` calls in sequence to the KeystoreFilesSenderServer
   674  func StartUpKeystoreFilesReceivingClient(backend *api.GethStatusBackend, cs, configJSON string) error {
   675  	c, err := setupKeystoreFilesReceivingClient(backend, cs, configJSON)
   676  	if err != nil {
   677  		return err
   678  	}
   679  
   680  	err = c.getChallenge()
   681  	if err != nil {
   682  		return err
   683  	}
   684  
   685  	return c.receiveKeystoreFilesData()
   686  }