2023-01-06 12:21:14 +00:00
|
|
|
package pairing
|
2022-06-15 14:49:31 +00:00
|
|
|
|
|
|
|
import (
|
2022-06-15 15:36:17 +00:00
|
|
|
"crypto/ecdsa"
|
2022-08-31 11:44:12 +00:00
|
|
|
"crypto/elliptic"
|
2022-08-19 12:45:50 +00:00
|
|
|
"crypto/rand"
|
2022-06-15 14:49:31 +00:00
|
|
|
"crypto/tls"
|
2022-06-15 15:36:17 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2022-08-31 11:44:12 +00:00
|
|
|
"time"
|
2022-08-19 12:45:50 +00:00
|
|
|
|
|
|
|
"github.com/gorilla/sessions"
|
2022-08-31 12:47:16 +00:00
|
|
|
|
2023-02-17 13:02:42 +00:00
|
|
|
"github.com/status-im/status-go/api"
|
2022-10-21 12:15:39 +00:00
|
|
|
"github.com/status-im/status-go/logutils"
|
2023-02-17 13:02:42 +00:00
|
|
|
"github.com/status-im/status-go/server"
|
2022-06-15 14:49:31 +00:00
|
|
|
)
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
type Server struct {
|
|
|
|
server.Server
|
2022-07-05 05:40:43 +00:00
|
|
|
PayloadManager
|
2023-02-28 12:32:45 +00:00
|
|
|
rawMessagePayloadManager *RawMessagePayloadManager
|
|
|
|
installationPayloadManager *InstallationPayloadManager
|
2022-06-15 15:36:17 +00:00
|
|
|
|
2022-08-07 22:14:33 +00:00
|
|
|
pk *ecdsa.PublicKey
|
|
|
|
ek []byte
|
2022-07-05 05:40:43 +00:00
|
|
|
mode Mode
|
2022-08-19 12:45:50 +00:00
|
|
|
|
|
|
|
cookieStore *sessions.CookieStore
|
2022-06-15 14:49:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Config struct {
|
2022-07-01 15:37:53 +00:00
|
|
|
// Connection fields
|
2022-08-07 22:14:33 +00:00
|
|
|
PK *ecdsa.PublicKey
|
|
|
|
EK []byte
|
2022-06-15 14:49:31 +00:00
|
|
|
Cert *tls.Certificate
|
|
|
|
Hostname string
|
2022-06-15 15:36:17 +00:00
|
|
|
Mode Mode
|
2022-07-01 15:37:53 +00:00
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
// AccountPayload management fields
|
|
|
|
*AccountPayloadManagerConfig
|
2022-06-15 14:49:31 +00:00
|
|
|
}
|
|
|
|
|
2022-08-19 12:45:50 +00:00
|
|
|
func makeCookieStore() (*sessions.CookieStore, error) {
|
|
|
|
auth := make([]byte, 64)
|
|
|
|
_, err := rand.Read(auth)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
enc := make([]byte, 32)
|
|
|
|
_, err = rand.Read(enc)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return sessions.NewCookieStore(auth, enc), nil
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
// NewPairingServer returns a *Server init from the given *Config
|
|
|
|
func NewPairingServer(backend *api.GethStatusBackend, config *Config) (*Server, error) {
|
|
|
|
logger := logutils.ZapLogger().Named("Server")
|
2023-02-17 13:02:42 +00:00
|
|
|
accountPayloadManagerConfig := config.AccountPayloadManagerConfig
|
|
|
|
pm, err := NewAccountPayloadManager(config.EK, accountPayloadManagerConfig, logger)
|
2022-06-10 15:32:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-08-19 12:45:50 +00:00
|
|
|
cs, err := makeCookieStore()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-28 12:32:45 +00:00
|
|
|
rmpm, err := NewRawMessagePayloadManager(logger, pm.accountPayload, config.EK, backend, accountPayloadManagerConfig.GetNodeConfig(), accountPayloadManagerConfig.GetSettingCurrentNetwork(), accountPayloadManagerConfig.GetDeviceType())
|
2023-01-06 12:21:14 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-28 12:32:45 +00:00
|
|
|
ipm, err := NewInstallationPayloadManager(logger, config.EK, backend, accountPayloadManagerConfig.GetDeviceType())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-15 15:50:30 +00:00
|
|
|
s := &Server{Server: server.NewServer(
|
2022-06-15 14:49:31 +00:00
|
|
|
config.Cert,
|
|
|
|
config.Hostname,
|
2022-08-07 07:35:54 +00:00
|
|
|
nil,
|
2022-10-21 12:15:39 +00:00
|
|
|
logger,
|
2022-06-15 15:36:17 +00:00
|
|
|
),
|
2023-02-28 12:32:45 +00:00
|
|
|
pk: config.PK,
|
|
|
|
ek: config.EK,
|
|
|
|
mode: config.Mode,
|
|
|
|
PayloadManager: pm,
|
|
|
|
cookieStore: cs,
|
|
|
|
rawMessagePayloadManager: rmpm,
|
|
|
|
installationPayloadManager: ipm,
|
2023-02-15 15:50:30 +00:00
|
|
|
}
|
2023-02-17 13:02:42 +00:00
|
|
|
s.SetTimeout(config.GetTimeout())
|
2023-02-15 15:50:30 +00:00
|
|
|
|
|
|
|
return s, nil
|
2022-06-15 15:36:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MakeConnectionParams generates a *ConnectionParams based on the Server's current state
|
2023-01-06 12:21:14 +00:00
|
|
|
func (s *Server) MakeConnectionParams() (*ConnectionParams, error) {
|
|
|
|
hostname := s.GetHostname()
|
|
|
|
netIP := net.ParseIP(hostname)
|
2022-06-15 15:36:17 +00:00
|
|
|
if netIP == nil {
|
2023-01-06 12:21:14 +00:00
|
|
|
return nil, fmt.Errorf("invalid ip address given '%s'", hostname)
|
2022-06-15 15:36:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
netIP4 := netIP.To4()
|
|
|
|
if netIP4 != nil {
|
|
|
|
netIP = netIP4
|
|
|
|
}
|
|
|
|
|
2022-10-12 10:00:14 +00:00
|
|
|
return NewConnectionParams(netIP, s.MustGetPort(), s.pk, s.ek, s.mode), nil
|
2022-06-15 14:49:31 +00:00
|
|
|
}
|
2022-06-10 15:32:15 +00:00
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
func (s *Server) StartPairing() error {
|
2022-06-10 15:32:15 +00:00
|
|
|
switch s.mode {
|
|
|
|
case Receiving:
|
2023-01-06 12:21:14 +00:00
|
|
|
return s.startReceivingData()
|
2022-06-10 15:32:15 +00:00
|
|
|
case Sending:
|
2023-01-06 12:21:14 +00:00
|
|
|
return s.startSendingData()
|
2022-06-10 15:32:15 +00:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("invalid server mode '%d'", s.mode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
func (s *Server) startReceivingData() error {
|
|
|
|
s.SetHandlers(server.HandlerPatternMap{
|
2023-02-28 12:32:45 +00:00
|
|
|
pairingReceiveAccount: handleReceiveAccount(s),
|
2023-01-06 12:21:14 +00:00
|
|
|
pairingChallenge: handlePairingChallenge(s),
|
|
|
|
pairingSyncDeviceReceive: handleParingSyncDeviceReceive(s),
|
2023-02-28 12:32:45 +00:00
|
|
|
// send installation data back to sender
|
|
|
|
pairingSendInstallation: handleSendInstallation(s),
|
2022-08-19 12:45:50 +00:00
|
|
|
})
|
2022-06-10 15:32:15 +00:00
|
|
|
return s.Start()
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
func (s *Server) startSendingData() error {
|
2022-08-31 12:47:16 +00:00
|
|
|
err := s.Mount()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
s.SetHandlers(server.HandlerPatternMap{
|
2023-02-28 12:32:45 +00:00
|
|
|
pairingSendAccount: challengeMiddleware(s, handleSendAccount(s)),
|
2023-01-06 12:21:14 +00:00
|
|
|
pairingChallenge: handlePairingChallenge(s),
|
|
|
|
pairingSyncDeviceSend: challengeMiddleware(s, handlePairingSyncDeviceSend(s)),
|
2023-02-28 12:32:45 +00:00
|
|
|
// receive installation data from receiver
|
|
|
|
pairingReceiveInstallation: challengeMiddleware(s, handleReceiveInstallation(s)),
|
2022-08-19 12:45:50 +00:00
|
|
|
})
|
2022-06-10 15:32:15 +00:00
|
|
|
return s.Start()
|
|
|
|
}
|
2022-08-31 11:44:12 +00:00
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
// MakeFullPairingServer generates a fully configured and randomly seeded Server
|
|
|
|
func MakeFullPairingServer(backend *api.GethStatusBackend, mode Mode, storeConfig *PayloadSourceConfig) (*Server, error) {
|
2022-08-31 11:44:12 +00:00
|
|
|
tlsKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
AESKey := make([]byte, 32)
|
|
|
|
_, err = rand.Read(AESKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
outboundIP, err := server.GetOutboundIP()
|
2022-08-31 11:44:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
tlsCert, _, err := GenerateCertFromKey(tlsKey, time.Now(), outboundIP.String())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-02-28 12:32:45 +00:00
|
|
|
|
|
|
|
accountPayloadManagerConfig := &AccountPayloadManagerConfig{
|
|
|
|
// Things that can't be generated, but DO NOT come from app client
|
|
|
|
DB: backend.GetMultiaccountDB(),
|
|
|
|
|
|
|
|
// Things that can't be generated, but DO come from the app client
|
|
|
|
PayloadSourceConfig: storeConfig,
|
|
|
|
}
|
|
|
|
if mode == Receiving {
|
|
|
|
updateLoggedInKeyUID(accountPayloadManagerConfig, backend)
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
return NewPairingServer(backend, &Config{
|
2022-08-31 11:58:59 +00:00
|
|
|
// Things that can be generated, and CANNOT come from the app client (well they could be this is better)
|
2022-08-31 11:44:12 +00:00
|
|
|
PK: &tlsKey.PublicKey,
|
|
|
|
EK: AESKey,
|
|
|
|
Cert: &tlsCert,
|
|
|
|
Hostname: outboundIP.String(),
|
|
|
|
|
2022-08-31 11:58:59 +00:00
|
|
|
// Things that can't be generated, but DO come from the app client
|
2022-08-31 11:44:12 +00:00
|
|
|
Mode: mode,
|
|
|
|
|
2023-02-28 12:32:45 +00:00
|
|
|
AccountPayloadManagerConfig: accountPayloadManagerConfig,
|
2022-08-31 11:44:12 +00:00
|
|
|
})
|
|
|
|
}
|
2022-08-31 12:47:16 +00:00
|
|
|
|
2023-01-06 12:21:14 +00:00
|
|
|
// StartUpPairingServer generates a Server, starts the pairing server in the correct mode
|
|
|
|
// and returns the ConnectionParams string to allow a Client to make a successful connection.
|
|
|
|
func StartUpPairingServer(backend *api.GethStatusBackend, mode Mode, configJSON string) (string, error) {
|
2023-02-17 13:02:42 +00:00
|
|
|
conf, err := NewPayloadSourceForServer(configJSON, mode)
|
2022-08-31 12:47:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2023-02-17 13:02:42 +00:00
|
|
|
ps, err := MakeFullPairingServer(backend, mode, conf)
|
2022-08-31 12:47:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ps.StartPairing()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
cp, err := ps.MakeConnectionParams()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return cp.ToString(), nil
|
|
|
|
}
|