423 lines
12 KiB
Go
423 lines
12 KiB
Go
package pairing
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"net"
|
|
"runtime"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/status-im/status-go/timesource"
|
|
|
|
"github.com/status-im/status-go/api"
|
|
"github.com/status-im/status-go/logutils"
|
|
"github.com/status-im/status-go/server"
|
|
)
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| type BaseServer struct {
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
type BaseServer struct {
|
|
server.Server
|
|
challengeGiver *ChallengeGiver
|
|
|
|
config ServerConfig
|
|
}
|
|
|
|
// NewBaseServer returns a *BaseServer init from the given *SenderServerConfig
|
|
func NewBaseServer(logger *zap.Logger, e *PayloadEncryptor, config *ServerConfig) (*BaseServer, error) {
|
|
cg, err := NewChallengeGiver(e, logger)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bs := &BaseServer{
|
|
Server: server.NewServer(
|
|
config.Cert,
|
|
config.ListenIP.String(),
|
|
nil,
|
|
logger,
|
|
),
|
|
challengeGiver: cg,
|
|
config: *config,
|
|
}
|
|
bs.SetTimeout(config.Timeout)
|
|
return bs, nil
|
|
}
|
|
|
|
// MakeConnectionParams generates a *ConnectionParams based on the Server's current state
|
|
func (s *BaseServer) MakeConnectionParams() (*ConnectionParams, error) {
|
|
return NewConnectionParams(s.config.IPAddresses, s.MustGetPort(), s.config.PK, s.config.EK, s.config.InstallationID, s.config.KeyUID), nil
|
|
}
|
|
|
|
func MakeServerConfig(config *ServerConfig) error {
|
|
tlsKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
AESKey := make([]byte, 32)
|
|
_, err = rand.Read(AESKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ips, err := server.GetLocalAddressesForPairingServer()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
now := timesource.GetCurrentTime()
|
|
logutils.ZapLogger().Debug("pairing server generate cert",
|
|
logutils.UnixTimeMs("system time", time.Now()),
|
|
logutils.UnixTimeMs("timesource time", now),
|
|
)
|
|
tlsCert, _, err := GenerateCertFromKey(tlsKey, now, ips, []string{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
config.PK = &tlsKey.PublicKey
|
|
config.EK = AESKey
|
|
config.Cert = &tlsCert
|
|
config.IPAddresses = ips
|
|
config.ListenIP = net.IPv4zero
|
|
|
|
return nil
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| type SenderServer struct {
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| With AccountPayloadMounter, RawMessagePayloadMounter and InstallationPayloadMounterReceiver
|
|
|
|
|
*/
|
|
|
|
type SenderServer struct {
|
|
*BaseServer
|
|
accountMounter PayloadMounter
|
|
rawMessageMounter PayloadMounter
|
|
installationMounter PayloadMounterReceiver
|
|
backend *api.GethStatusBackend
|
|
}
|
|
|
|
// NewSenderServer returns a *SenderServer init from the given *SenderServerConfig
|
|
func NewSenderServer(backend *api.GethStatusBackend, config *SenderServerConfig) (*SenderServer, error) {
|
|
logger := logutils.ZapLogger().Named("SenderServer")
|
|
e := NewPayloadEncryptor(config.ServerConfig.EK)
|
|
|
|
bs, err := NewBaseServer(logger, e, config.ServerConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
am, rmm, imr, err := NewPayloadMounters(logger, e, backend, config.SenderConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &SenderServer{
|
|
BaseServer: bs,
|
|
accountMounter: am,
|
|
rawMessageMounter: rmm,
|
|
installationMounter: imr,
|
|
backend: backend,
|
|
}, nil
|
|
}
|
|
|
|
func (s *SenderServer) startSendingData() error {
|
|
logger := s.GetLogger()
|
|
beforeSending := func() {
|
|
if s.backend != nil {
|
|
err := s.backend.LocalPairingStarted()
|
|
if err != nil {
|
|
logger.Error("startSendingData backend.LocalPairingStarted()", zap.Error(err))
|
|
}
|
|
}
|
|
}
|
|
s.SetHandlers(server.HandlerPatternMap{
|
|
pairingChallenge: handlePairingChallenge(s.challengeGiver),
|
|
pairingSendAccount: middlewareChallenge(s.challengeGiver, handleSendAccount(logger, s.accountMounter, beforeSending)),
|
|
pairingSendSyncDevice: middlewareChallenge(s.challengeGiver, handlePairingSyncDeviceSend(logger, s.rawMessageMounter, beforeSending)),
|
|
// TODO implement refactor of installation data exchange to follow the send/receive pattern of
|
|
// the other handlers.
|
|
// https://github.com/status-im/status-go/issues/3304
|
|
// receive installation data from receiver
|
|
pairingReceiveInstallation: middlewareChallenge(s.challengeGiver, handleReceiveInstallation(s.GetLogger(), s.installationMounter)),
|
|
})
|
|
return s.Start()
|
|
}
|
|
|
|
// MakeFullSenderServer generates a fully configured and randomly seeded SenderServer
|
|
func MakeFullSenderServer(backend *api.GethStatusBackend, config *SenderServerConfig) (*SenderServer, error) {
|
|
config.ServerConfig.InstallationID = backend.InstallationID()
|
|
config.ServerConfig.KeyUID = backend.KeyUID()
|
|
err := MakeServerConfig(config.ServerConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
config.SenderConfig.DB = backend.GetMultiaccountDB()
|
|
return NewSenderServer(backend, config)
|
|
}
|
|
|
|
// StartUpSenderServer generates a SenderServer, starts the sending server
|
|
// and returns the ConnectionParams string to allow a ReceiverClient to make a successful connection.
|
|
func StartUpSenderServer(backend *api.GethStatusBackend, configJSON string) (string, error) {
|
|
conf := NewSenderServerConfig()
|
|
err := json.Unmarshal([]byte(configJSON), conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(conf.SenderConfig.ChatKey) == 0 {
|
|
err = validateAndVerifyPassword(conf, conf.SenderConfig)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
ps, err := MakeFullSenderServer(backend, conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = ps.startSendingData()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
cp, err := ps.MakeConnectionParams()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return cp.ToString(), nil
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| ReceiverServer
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| With AccountPayloadReceiver, RawMessagePayloadReceiver, InstallationPayloadMounterReceiver
|
|
|
|
|
*/
|
|
|
|
type ReceiverServer struct {
|
|
*BaseServer
|
|
accountReceiver PayloadReceiver
|
|
rawMessageReceiver PayloadReceiver
|
|
installationReceiver PayloadMounterReceiver
|
|
backend *api.GethStatusBackend
|
|
}
|
|
|
|
// NewReceiverServer returns a *SenderServer init from the given *ReceiverServerConfig
|
|
func NewReceiverServer(backend *api.GethStatusBackend, config *ReceiverServerConfig) (*ReceiverServer, error) {
|
|
logger := logutils.ZapLogger().Named("SenderServer")
|
|
e := NewPayloadEncryptor(config.ServerConfig.EK)
|
|
|
|
bs, err := NewBaseServer(logger, e, config.ServerConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ar, rmr, imr, err := NewPayloadReceivers(logger, e, backend, config.ReceiverConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ReceiverServer{
|
|
BaseServer: bs,
|
|
accountReceiver: ar,
|
|
rawMessageReceiver: rmr,
|
|
installationReceiver: imr,
|
|
backend: backend,
|
|
}, nil
|
|
}
|
|
|
|
func (s *ReceiverServer) startReceivingData() error {
|
|
logger := s.GetLogger()
|
|
beforeSending := func() {
|
|
if s.backend != nil {
|
|
err := s.backend.LocalPairingStarted()
|
|
if err != nil {
|
|
logger.Error("startSendingData backend.LocalPairingStarted()", zap.Error(err))
|
|
}
|
|
}
|
|
}
|
|
s.SetHandlers(server.HandlerPatternMap{
|
|
pairingChallenge: handlePairingChallenge(s.challengeGiver),
|
|
pairingReceiveAccount: handleReceiveAccount(logger, s.accountReceiver),
|
|
pairingReceiveSyncDevice: handleParingSyncDeviceReceive(logger, s.rawMessageReceiver),
|
|
// TODO implement refactor of installation data exchange to follow the send/receive pattern of
|
|
// the other handlers.
|
|
// https://github.com/status-im/status-go/issues/3304
|
|
// send installation data back to sender
|
|
pairingSendInstallation: middlewareChallenge(s.challengeGiver, handleSendInstallation(logger, s.installationReceiver, beforeSending)),
|
|
})
|
|
return s.Start()
|
|
}
|
|
|
|
// MakeFullReceiverServer generates a fully configured and randomly seeded ReceiverServer
|
|
func MakeFullReceiverServer(backend *api.GethStatusBackend, config *ReceiverServerConfig) (*ReceiverServer, error) {
|
|
config.ServerConfig.InstallationID = backend.InstallationID()
|
|
config.ServerConfig.KeyUID = backend.KeyUID()
|
|
|
|
err := MakeServerConfig(config.ServerConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// ignore err because we allow no active account here
|
|
activeAccount, _ := backend.GetActiveAccount()
|
|
if activeAccount != nil {
|
|
config.ReceiverConfig.LoggedInKeyUID = activeAccount.KeyUID
|
|
}
|
|
config.ReceiverConfig.DB = backend.GetMultiaccountDB()
|
|
|
|
return NewReceiverServer(backend, config)
|
|
}
|
|
|
|
// StartUpReceiverServer generates a ReceiverServer, starts the sending server
|
|
// and returns the ConnectionParams string to allow a SenderClient to make a successful connection.
|
|
func StartUpReceiverServer(backend *api.GethStatusBackend, configJSON string) (string, error) {
|
|
conf := NewReceiverServerConfig()
|
|
err := json.Unmarshal([]byte(configJSON), conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// This is a temporal solution to allow clients not to pass DeviceType.
|
|
// Check DeviceType deprecation reason for more info.
|
|
conf.ReceiverConfig.DeviceType = runtime.GOOS
|
|
|
|
err = validateReceiverConfig(conf, conf.ReceiverConfig)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ps, err := MakeFullReceiverServer(backend, conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = ps.startReceivingData()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
cp, err := ps.MakeConnectionParams()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return cp.ToString(), nil
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| type KeystoreFilesSenderServer struct {
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
type KeystoreFilesSenderServer struct {
|
|
*BaseServer
|
|
keystoreFilesMounter PayloadMounter
|
|
backend *api.GethStatusBackend
|
|
}
|
|
|
|
func NewKeystoreFilesSenderServer(backend *api.GethStatusBackend, config *KeystoreFilesSenderServerConfig) (*KeystoreFilesSenderServer, error) {
|
|
logger := logutils.ZapLogger().Named("SenderServer")
|
|
e := NewPayloadEncryptor(config.ServerConfig.EK)
|
|
|
|
bs, err := NewBaseServer(logger, e, config.ServerConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
kfm, err := NewKeystoreFilesPayloadMounter(backend, e, config.SenderConfig, logger)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &KeystoreFilesSenderServer{
|
|
BaseServer: bs,
|
|
keystoreFilesMounter: kfm,
|
|
backend: backend,
|
|
}, nil
|
|
}
|
|
|
|
func (s *KeystoreFilesSenderServer) startSendingData() error {
|
|
logger := s.GetLogger()
|
|
beforeSending := func() {
|
|
if s.backend != nil {
|
|
err := s.backend.LocalPairingStarted()
|
|
if err != nil {
|
|
logger.Error("startSendingData backend.LocalPairingStarted()", zap.Error(err))
|
|
}
|
|
}
|
|
}
|
|
s.SetHandlers(server.HandlerPatternMap{
|
|
pairingChallenge: handlePairingChallenge(s.challengeGiver),
|
|
pairingSendAccount: middlewareChallenge(s.challengeGiver, handleSendAccount(logger, s.keystoreFilesMounter, beforeSending)),
|
|
})
|
|
return s.Start()
|
|
}
|
|
|
|
// MakeFullSenderServer generates a fully configured and randomly seeded KeystoreFilesSenderServer
|
|
func MakeKeystoreFilesSenderServer(backend *api.GethStatusBackend, config *KeystoreFilesSenderServerConfig) (*KeystoreFilesSenderServer, error) {
|
|
config.ServerConfig.InstallationID = backend.InstallationID()
|
|
config.ServerConfig.KeyUID = backend.KeyUID()
|
|
|
|
err := MakeServerConfig(config.ServerConfig)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return NewKeystoreFilesSenderServer(backend, config)
|
|
}
|
|
|
|
// StartUpKeystoreFilesSenderServer generates a KeystoreFilesSenderServer, starts the sending server
|
|
// and returns the ConnectionParams string to allow a ReceiverClient to make a successful connection.
|
|
func StartUpKeystoreFilesSenderServer(backend *api.GethStatusBackend, configJSON string) (string, error) {
|
|
conf := NewKeystoreFilesSenderServerConfig()
|
|
err := json.Unmarshal([]byte(configJSON), conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = validateKeystoreFilesConfig(backend, conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ps, err := MakeKeystoreFilesSenderServer(backend, conf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = ps.startSendingData()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
cp, err := ps.MakeConnectionParams()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return cp.ToString(), nil
|
|
}
|