diff --git a/Makefile b/Makefile index a83de954a..4ba30e620 100644 --- a/Makefile +++ b/Makefile @@ -152,10 +152,9 @@ status-backend: ##@build Build status-backend to run status-go as HTTP server status-backend: build/bin/status-backend run-status-backend: PORT ?= 0 -MEDIA_HTTPS ?= true run-status-backend: generate run-status-backend: ##@run Start status-backend server listening to localhost:PORT - go run ./cmd/status-backend --address localhost:${PORT} --media-https=${MEDIA_HTTPS} + go run ./cmd/status-backend --address localhost:${PORT} statusgo-cross: statusgo-android statusgo-ios @echo "Full cross compilation done." diff --git a/cmd/status-backend/main.go b/cmd/status-backend/main.go index e6ad00d6e..763b15c8f 100644 --- a/cmd/status-backend/main.go +++ b/cmd/status-backend/main.go @@ -9,16 +9,14 @@ import ( "github.com/ethereum/go-ethereum/log" - backendServer "github.com/status-im/status-go/cmd/status-backend/server" + "github.com/status-im/status-go/cmd/status-backend/server" "github.com/status-im/status-go/internal/version" "github.com/status-im/status-go/logutils" - mediaServer "github.com/status-im/status-go/server" ) var ( - address = flag.String("address", "", "host:port to listen") - useMediaHTTPS = flag.Bool("media-https", true, "use HTTPS for media server (default: true)") - logger = log.New("package", "status-go/cmd/status-backend") + address = flag.String("address", "", "host:port to listen") + logger = log.New("package", "status-go/cmd/status-backend") ) func init() { @@ -36,9 +34,7 @@ func init() { func main() { flag.Parse() - mediaServer.UseHTTP = !*useMediaHTTPS - - srv := backendServer.NewServer() + srv := server.NewServer() srv.Setup() err := srv.Listen(*address) diff --git a/mobile/status.go b/mobile/status.go index 3b431d8dc..07f34d398 100644 --- a/mobile/status.go +++ b/mobile/status.go @@ -84,9 +84,9 @@ func initializeApplication(requestJSON string) string { providers.MixpanelAppID = request.MixpanelAppID providers.MixpanelToken = request.MixpanelToken - datadir := request.DataDir + statusBackend.StatusNode().SetMediaServerEnableTLS(request.MediaServerEnableTLS) - statusBackend.UpdateRootDataDir(datadir) + statusBackend.UpdateRootDataDir(request.DataDir) err = statusBackend.OpenAccounts() if err != nil { return makeJSONResponse(err) diff --git a/node/get_status_node.go b/node/get_status_node.go index 0ec00dd85..bc5b6ec25 100644 --- a/node/get_status_node.go +++ b/node/get_status_node.go @@ -88,7 +88,9 @@ type StatusNode struct { rpcClient *rpc.Client // reference to an RPC client downloader *ipfs.Downloader - httpServer *server.MediaServer + + mediaServerEnableTLS *bool + httpServer *server.MediaServer discovery discovery.Discovery register *peers.Register @@ -215,7 +217,11 @@ func (n *StatusNode) StartMediaServerWithoutDB() error { } } - httpServer, err := server.NewMediaServer(nil, nil, n.multiaccountsDB, nil) + var opts []server.MediaServerOption + if n.mediaServerEnableTLS != nil { + opts = append(opts, server.WithMediaServerDisableTLS(!*n.mediaServerEnableTLS)) + } + httpServer, err := server.NewMediaServer(nil, nil, n.multiaccountsDB, nil, opts...) if err != nil { return err } @@ -269,6 +275,10 @@ func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOp return nil } +func (n *StatusNode) SetMediaServerEnableTLS(enableTLS *bool) { + n.mediaServerEnableTLS = enableTLS +} + func (n *StatusNode) startWithDB(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) error { if err := n.createNode(config, accs, db); err != nil { return err @@ -287,7 +297,12 @@ func (n *StatusNode) startWithDB(config *params.NodeConfig, accs *accounts.Manag } } - httpServer, err := server.NewMediaServer(n.appDB, n.downloader, n.multiaccountsDB, n.walletDB) + var opts []server.MediaServerOption + if n.mediaServerEnableTLS != nil { + opts = append(opts, server.WithMediaServerDisableTLS(!*n.mediaServerEnableTLS)) + } + + httpServer, err := server.NewMediaServer(n.appDB, n.downloader, n.multiaccountsDB, n.walletDB, opts...) if err != nil { return err } diff --git a/protocol/requests/initialize_application.go b/protocol/requests/initialize_application.go index f97fc4929..39fa3aa14 100644 --- a/protocol/requests/initialize_application.go +++ b/protocol/requests/initialize_application.go @@ -12,6 +12,8 @@ type InitializeApplication struct { DataDir string `json:"dataDir"` MixpanelAppID string `json:"mixpanelAppId"` MixpanelToken string `json:"mixpanelToken"` + // MediaServerEnableTLS is optional, if not provided, media server will use TLS by default + MediaServerEnableTLS *bool `json:"mediaServerEnableTLS"` } func (i *InitializeApplication) Validate() error { diff --git a/server/certs.go b/server/certs.go index eb8dd475b..2f7525119 100644 --- a/server/certs.go +++ b/server/certs.go @@ -75,9 +75,9 @@ func GenerateTLSCert(notBefore, notAfter time.Time, IPAddresses []net.IP, DNSNam return &finalCert, certPem, err } -func generateMediaTLSCert() error { +func generateMediaTLSCert() (*tls.Certificate, string, error) { if globalMediaCertificate != nil { - return nil + return globalMediaCertificate, globalMediaPem, nil } now := time.Now() @@ -90,21 +90,21 @@ func generateMediaTLSCert() error { ) finalCert, certPem, err := GenerateTLSCert(notBefore, notAfter, []net.IP{}, []string{Localhost}) if err != nil { - return err + return nil, "", err } globalMediaCertificate = finalCert globalMediaPem = string(certPem) - return nil + return finalCert, globalMediaPem, nil } func PublicMediaTLSCert() (string, error) { - err := generateMediaTLSCert() + _, pem, err := generateMediaTLSCert() if err != nil { return "", err } - return globalMediaPem, nil + return pem, nil } // ToECDSA takes a []byte of D and uses it to create an ecdsa.PublicKey on the elliptic.P256 curve diff --git a/server/server.go b/server/server.go index 03a0c4d54..fe60ffc28 100644 --- a/server/server.go +++ b/server/server.go @@ -55,25 +55,26 @@ func (s *Server) mustGetHost() string { return fmt.Sprintf("%s:%d", s.hostname, s.MustGetPort()) } +func (s *Server) createListener() (net.Listener, error) { + host := s.getHost() + if s.cert == nil { + // HTTP mode + return net.Listen("tcp", host) + } + + // HTTPS mode + cfg := &tls.Config{ + Certificates: []tls.Certificate{*s.cert}, + ServerName: s.hostname, + MinVersion: tls.VersionTLS12, + } + return tls.Listen("tcp", host, cfg) +} + func (s *Server) listenAndServe() { defer common.LogOnPanic() - var listener net.Listener - var err error - - if s.cert != nil { - // HTTPS mode - cfg := &tls.Config{ - Certificates: []tls.Certificate{*s.cert}, - ServerName: s.hostname, - MinVersion: tls.VersionTLS12, - } - listener, err = tls.Listen("tcp", s.getHost(), cfg) - } else { - // HTTP mode - listener, err = net.Listen("tcp", s.getHost()) - } - + listener, err := s.createListener() if err != nil { s.logger.Error("failed to start server, retrying", zap.Error(err)) s.ResetPort() diff --git a/server/server_media.go b/server/server_media.go index 8f5100f27..793318acf 100644 --- a/server/server_media.go +++ b/server/server_media.go @@ -14,13 +14,13 @@ import ( "github.com/status-im/status-go/signal" ) -var ( - // UseHTTP controls whether the media server uses HTTP instead of HTTPS. - // Set to true to avoid TLS certificate issues with react-native-fast-image - // on Android, which has limitations with dynamic certificate updates. - // Pls check doc/use-status-backend-server.md in status-mobile for more details - UseHTTP = false -) +type MediaServerOption func(*MediaServer) + +func WithMediaServerDisableTLS(disableTLS bool) MediaServerOption { + return func(s *MediaServer) { + s.disableTLS = disableTLS + } +} type MediaServer struct { Server @@ -29,31 +29,52 @@ type MediaServer struct { downloader *ipfs.Downloader multiaccountsDB *multiaccounts.Database walletDB *sql.DB + + // disableTLS controls whether the media server uses HTTP instead of HTTPS. + // Set to true to avoid TLS certificate issues with react-native-fast-image + // on Android, which has limitations with dynamic certificate updates. + // Pls check doc/use-status-backend-server.md in status-mobile for more details + disableTLS bool +} + +func initMediaCertificate(disableTLS bool) (*tls.Certificate, error) { + if disableTLS { + return nil, nil + } + + cert, _, err := generateMediaTLSCert() + if err != nil { + return nil, err + } + return cert, nil } // NewMediaServer returns a *MediaServer -func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *multiaccounts.Database, walletDB *sql.DB) (*MediaServer, error) { - var cert *tls.Certificate - if !UseHTTP { - err := generateMediaTLSCert() - if err != nil { - return nil, err - } - cert = globalMediaCertificate - } +func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *multiaccounts.Database, walletDB *sql.DB, opts ...MediaServerOption) (*MediaServer, error) { s := &MediaServer{ - Server: NewServer( - cert, - Localhost, - signal.SendMediaServerStarted, - logutils.ZapLogger().Named("MediaServer"), - ), + disableTLS: false, db: db, downloader: downloader, multiaccountsDB: multiaccountsDB, walletDB: walletDB, } + + for _, opt := range opts { + opt(s) + } + + cert, err := initMediaCertificate(s.disableTLS) + if err != nil { + return nil, err + } + s.Server = NewServer( + cert, + Localhost, + signal.SendMediaServerStarted, + logutils.ZapLogger().Named("MediaServer"), + ) + s.SetHandlers(HandlerPatternMap{ accountImagesPath: handleAccountImages(s.multiaccountsDB, s.logger), accountInitialsPath: handleAccountInitials(s.multiaccountsDB, s.logger), @@ -80,7 +101,7 @@ func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *mu func (s *MediaServer) MakeBaseURL() *url.URL { return &url.URL{ - Scheme: map[bool]string{true: "http", false: "https"}[UseHTTP], + Scheme: map[bool]string{true: "http", false: "https"}[s.disableTLS], Host: s.mustGetHost(), } }