GODT-1425: Factory reset enables launch on startup

This commit is contained in:
Jakub
2021-12-01 13:23:01 +01:00
committed by Jakub Cuth
parent a0dc764bb9
commit f2d568d92f
11 changed files with 105 additions and 34 deletions

View File

@ -73,7 +73,8 @@ const (
FlagCLI = "cli" FlagCLI = "cli"
flagCLIShort = "c" flagCLIShort = "c"
flagRestart = "restart" flagRestart = "restart"
flagLauncher = "launcher" FlagLauncher = "launcher"
FlagNoWindow = "no-window"
) )
type Base struct { type Base struct {
@ -235,7 +236,7 @@ func New( // nolint[funlen]
autostart := &autostart.App{ autostart := &autostart.App{
Name: appName, Name: appName,
DisplayName: appName, DisplayName: appName,
Exec: []string{exe}, Exec: []string{exe, "--" + FlagNoWindow},
} }
return &Base{ return &Base{
@ -264,13 +265,13 @@ func New( // nolint[funlen]
}, nil }, nil
} }
func (b *Base) NewApp(action func(*Base, *cli.Context) error) *cli.App { func (b *Base) NewApp(mainLoop func(*Base, *cli.Context) error) *cli.App {
app := cli.NewApp() app := cli.NewApp()
app.Name = b.Name app.Name = b.Name
app.Usage = b.usage app.Usage = b.usage
app.Version = constants.Version app.Version = constants.Version
app.Action = b.run(action) app.Action = b.wrapMainLoop(mainLoop)
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
Name: flagCPUProfile, Name: flagCPUProfile,
@ -292,13 +293,17 @@ func (b *Base) NewApp(action func(*Base, *cli.Context) error) *cli.App {
Aliases: []string{flagCLIShort}, Aliases: []string{flagCLIShort},
Usage: "Use command line interface", Usage: "Use command line interface",
}, },
&cli.BoolFlag{
Name: FlagNoWindow,
Usage: "Don't show window after start",
},
&cli.StringFlag{ &cli.StringFlag{
Name: flagRestart, Name: flagRestart,
Usage: "The number of times the application has already restarted", Usage: "The number of times the application has already restarted",
Hidden: true, Hidden: true,
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: flagLauncher, Name: FlagLauncher,
Usage: "The launcher to use to restart the application", Usage: "The launcher to use to restart the application",
Hidden: true, Hidden: true,
}, },
@ -317,15 +322,18 @@ func (b *Base) AddTeardownAction(fn func() error) {
b.teardown = append(b.teardown, fn) b.teardown = append(b.teardown, fn)
} }
func (b *Base) run(appMainLoop func(*Base, *cli.Context) error) cli.ActionFunc { // nolint[funlen] func (b *Base) wrapMainLoop(appMainLoop func(*Base, *cli.Context) error) cli.ActionFunc { // nolint[funlen]
return func(c *cli.Context) error { return func(c *cli.Context) error {
defer b.CrashHandler.HandlePanic() defer b.CrashHandler.HandlePanic()
defer func() { _ = b.Lock.Close() }() defer func() { _ = b.Lock.Close() }()
// If launcher was used to start the app, use that for restart/autostart. // If launcher was used to start the app, use that for restart
if launcher := c.String(flagLauncher); launcher != "" { // and autostart.
b.Autostart.Exec = []string{launcher} if launcher := c.String(FlagLauncher); launcher != "" {
b.command = launcher b.command = launcher
// Bridge supports no-window option which we should use
// for autostart.
b.Autostart.Exec = []string{launcher, "--" + FlagNoWindow}
} }
if c.Bool(flagCPUProfile) { if c.Bool(flagCPUProfile) {

View File

@ -44,7 +44,6 @@ import (
const ( const (
flagLogIMAP = "log-imap" flagLogIMAP = "log-imap"
flagLogSMTP = "log-smtp" flagLogSMTP = "log-smtp"
flagNoWindow = "no-window"
flagNonInteractive = "noninteractive" flagNonInteractive = "noninteractive"
// Memory cache was estimated by empirical usage in past and it was set to 100MB. // Memory cache was estimated by empirical usage in past and it was set to 100MB.
@ -53,7 +52,7 @@ const (
) )
func New(base *base.Base) *cli.App { func New(base *base.Base) *cli.App {
app := base.NewApp(run) app := base.NewApp(mailLoop)
app.Flags = append(app.Flags, []cli.Flag{ app.Flags = append(app.Flags, []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
@ -62,9 +61,6 @@ func New(base *base.Base) *cli.App {
&cli.BoolFlag{ &cli.BoolFlag{
Name: flagLogSMTP, Name: flagLogSMTP,
Usage: "Enable logging of SMTP communications (may contain decrypted data!)"}, Usage: "Enable logging of SMTP communications (may contain decrypted data!)"},
&cli.BoolFlag{
Name: flagNoWindow,
Usage: "Don't show window after start"},
&cli.BoolFlag{ &cli.BoolFlag{
Name: flagNonInteractive, Name: flagNonInteractive,
Usage: "Start Bridge entirely noninteractively"}, Usage: "Start Bridge entirely noninteractively"},
@ -73,7 +69,7 @@ func New(base *base.Base) *cli.App {
return app return app
} }
func run(b *base.Base, c *cli.Context) error { // nolint[funlen] func mailLoop(b *base.Base, c *cli.Context) error { // nolint[funlen]
tlsConfig, err := loadTLSConfig(b) tlsConfig, err := loadTLSConfig(b)
if err != nil { if err != nil {
return err return err
@ -89,7 +85,21 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
b.Settings.GetInt(settings.AttachmentWorkers), b.Settings.GetInt(settings.AttachmentWorkers),
) )
bridge := pkgBridge.New(b.Locations, b.Cache, b.Settings, b.SentryReporter, b.CrashHandler, b.Listener, cache, builder, b.CM, b.Creds, b.Updater, b.Versioner) bridge := pkgBridge.New(
b.Locations,
b.Cache,
b.Settings,
b.SentryReporter,
b.CrashHandler,
b.Listener,
cache,
builder,
b.CM,
b.Creds,
b.Updater,
b.Versioner,
b.Autostart,
)
imapBackend := imap.NewIMAPBackend(b.CrashHandler, b.Listener, b.Cache, b.Settings, bridge) imapBackend := imap.NewIMAPBackend(b.CrashHandler, b.Listener, b.Cache, b.Settings, bridge)
smtpBackend := smtp.NewSMTPBackend(b.CrashHandler, b.Listener, b.Settings, bridge) smtpBackend := smtp.NewSMTPBackend(b.CrashHandler, b.Listener, b.Settings, bridge)
@ -122,9 +132,6 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
smtpPort, useSSL, tlsConfig, smtpBackend, b.Listener).ListenAndServe() smtpPort, useSSL, tlsConfig, smtpBackend, b.Listener).ListenAndServe()
}() }()
// Bridge supports no-window option which we should use for autostart.
b.Autostart.Exec = append(b.Autostart.Exec, "--"+flagNoWindow)
// We want to remove old versions if the app exits successfully. // We want to remove old versions if the app exits successfully.
b.AddTeardownAction(b.Versioner.RemoveOldVersions) b.AddTeardownAction(b.Versioner.RemoveOldVersions)
@ -147,7 +154,7 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
constants.BuildVersion, constants.BuildVersion,
b.Name, b.Name,
frontendMode, frontendMode,
!c.Bool(flagNoWindow), !c.Bool(base.FlagNoWindow),
b.CrashHandler, b.CrashHandler,
b.Locations, b.Locations,
b.Settings, b.Settings,
@ -156,7 +163,6 @@ func run(b *base.Base, c *cli.Context) error { // nolint[funlen]
b.UserAgent, b.UserAgent,
bridge, bridge,
smtpBackend, smtpBackend,
b.Autostart,
b, b,
) )

View File

@ -0,0 +1,31 @@
// Copyright (c) 2021 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Package bridge provides core functionality of Bridge app.
package bridge
func (b *Bridge) IsAutostartEnabled() bool {
return b.autostart.IsEnabled()
}
func (b *Bridge) EnableAutostart() error {
return b.autostart.Enable()
}
func (b *Bridge) DisableAutostart() error {
return b.autostart.Disable()
}

View File

@ -25,6 +25,7 @@ import (
"time" "time"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/ProtonMail/go-autostart"
"github.com/ProtonMail/proton-bridge/internal/config/settings" "github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/constants" "github.com/ProtonMail/proton-bridge/internal/constants"
"github.com/ProtonMail/proton-bridge/internal/metrics" "github.com/ProtonMail/proton-bridge/internal/metrics"
@ -52,8 +53,11 @@ type Bridge struct {
updater Updater updater Updater
versioner Versioner versioner Versioner
cacheProvider CacheProvider cacheProvider CacheProvider
autostart *autostart.App
// Bridge's global errors list. // Bridge's global errors list.
errors []error errors []error
lastVersion string
} }
func New( func New(
@ -69,6 +73,7 @@ func New(
credStorer users.CredentialsStorer, credStorer users.CredentialsStorer,
updater Updater, updater Updater,
versioner Versioner, versioner Versioner,
autostart *autostart.App,
) *Bridge { ) *Bridge {
// Allow DoH before starting the app if the user has previously set this setting. // Allow DoH before starting the app if the user has previously set this setting.
// This allows us to start even if protonmail is blocked. // This allows us to start even if protonmail is blocked.
@ -94,6 +99,7 @@ func New(
updater: updater, updater: updater,
versioner: versioner, versioner: versioner,
cacheProvider: cacheProvider, cacheProvider: cacheProvider,
autostart: autostart,
} }
if setting.GetBool(settings.FirstStartKey) { if setting.GetBool(settings.FirstStartKey) {
@ -101,9 +107,17 @@ func New(
logrus.WithError(err).Error("Failed to send metric") logrus.WithError(err).Error("Failed to send metric")
} }
if err := b.EnableAutostart(); err != nil {
log.WithError(err).Error("Failed to enable autostart")
}
setting.SetBool(settings.FirstStartKey, false) setting.SetBool(settings.FirstStartKey, false)
} }
// Keep in bridge and update in settings the last used version.
b.lastVersion = b.settings.Get(settings.LastVersionKey)
b.settings.Set(settings.LastVersionKey, constants.Version)
go b.heartbeat() go b.heartbeat()
return b return b
@ -279,3 +293,8 @@ func (b *Bridge) HasError(err error) bool {
return false return false
} }
// GetLastVersion returns the version which was used in previous execution of Bridge.
func (b *Bridge) GetLastVersion() string {
return b.lastVersion
}

View File

@ -19,7 +19,6 @@
package frontend package frontend
import ( import (
"github.com/ProtonMail/go-autostart"
"github.com/ProtonMail/proton-bridge/internal/bridge" "github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/config/settings" "github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/config/useragent" "github.com/ProtonMail/proton-bridge/internal/config/useragent"
@ -55,7 +54,6 @@ func New(
userAgent *useragent.UserAgent, userAgent *useragent.UserAgent,
bridge *bridge.Bridge, bridge *bridge.Bridge,
noEncConfirmator types.NoEncConfirmator, noEncConfirmator types.NoEncConfirmator,
autostart *autostart.App,
restarter types.Restarter, restarter types.Restarter,
) Frontend { ) Frontend {
bridgeWrap := types.NewBridgeWrap(bridge) bridgeWrap := types.NewBridgeWrap(bridge)
@ -74,7 +72,6 @@ func New(
userAgent, userAgent,
bridgeWrap, bridgeWrap,
noEncConfirmator, noEncConfirmator,
autostart,
restarter, restarter,
) )
case "cli": case "cli":

View File

@ -25,7 +25,6 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/ProtonMail/go-autostart"
"github.com/ProtonMail/proton-bridge/internal/config/settings" "github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/config/useragent" "github.com/ProtonMail/proton-bridge/internal/config/useragent"
"github.com/ProtonMail/proton-bridge/internal/frontend/types" "github.com/ProtonMail/proton-bridge/internal/frontend/types"
@ -50,7 +49,6 @@ type FrontendQt struct {
userAgent *useragent.UserAgent userAgent *useragent.UserAgent
bridge types.Bridger bridge types.Bridger
noEncConfirmator types.NoEncConfirmator noEncConfirmator types.NoEncConfirmator
autostart *autostart.App
restarter types.Restarter restarter types.Restarter
showOnStartup bool showOnStartup bool
@ -82,7 +80,6 @@ func New(
userAgent *useragent.UserAgent, userAgent *useragent.UserAgent,
bridge types.Bridger, bridge types.Bridger,
_ types.NoEncConfirmator, _ types.NoEncConfirmator,
autostart *autostart.App,
restarter types.Restarter, restarter types.Restarter,
) *FrontendQt { ) *FrontendQt {
userAgent.SetPlatform(core.QSysInfo_PrettyProductName()) userAgent.SetPlatform(core.QSysInfo_PrettyProductName())
@ -99,7 +96,6 @@ func New(
updater: updater, updater: updater,
userAgent: userAgent, userAgent: userAgent,
bridge: bridge, bridge: bridge,
autostart: autostart,
restarter: restarter, restarter: restarter,
showOnStartup: showWindowOnStart, showOnStartup: showWindowOnStart,
} }
@ -122,6 +118,12 @@ func (f *FrontendQt) Loop() error {
f.watchEvents() f.watchEvents()
}() }()
// Set whether this is the first time GUI starts.
f.qml.SetIsFirstGUIStart(f.settings.GetBool(settings.FirstStartGUIKey))
defer func() {
f.settings.SetBool(settings.FirstStartGUIKey, false)
}()
if ret := f.app.Exec(); ret != 0 { if ret := f.app.Exec(); ret != 0 {
err := fmt.Errorf("Event loop ended with return value: %v", ret) err := fmt.Errorf("Event loop ended with return value: %v", ret)
f.log.Warn("App exec", err) f.log.Warn("App exec", err)

View File

@ -23,7 +23,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/ProtonMail/go-autostart"
"github.com/ProtonMail/proton-bridge/internal/config/settings" "github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/config/useragent" "github.com/ProtonMail/proton-bridge/internal/config/useragent"
"github.com/ProtonMail/proton-bridge/internal/frontend/types" "github.com/ProtonMail/proton-bridge/internal/frontend/types"
@ -50,7 +49,6 @@ func New(
userAgent *useragent.UserAgent, userAgent *useragent.UserAgent,
bridge types.Bridger, bridge types.Bridger,
noEncConfirmator types.NoEncConfirmator, noEncConfirmator types.NoEncConfirmator,
autostart *autostart.App,
restarter types.Restarter, restarter types.Restarter,
) *FrontendHeadless { ) *FrontendHeadless {
return &FrontendHeadless{} return &FrontendHeadless{}

View File

@ -75,21 +75,21 @@ func (f *FrontendQt) changeLocalCache(enableDiskCache bool, diskCachePath *core.
} }
func (f *FrontendQt) setIsAutostartOn() { func (f *FrontendQt) setIsAutostartOn() {
f.qml.SetIsAutostartOn(f.autostart.IsEnabled()) f.qml.SetIsAutostartOn(f.bridge.IsAutostartEnabled())
} }
func (f *FrontendQt) toggleAutostart(makeItEnabled bool) { func (f *FrontendQt) toggleAutostart(makeItEnabled bool) {
defer f.qml.ToggleAutostartFinished() defer f.qml.ToggleAutostartFinished()
if makeItEnabled == f.autostart.IsEnabled() { if makeItEnabled == f.bridge.IsAutostartEnabled() {
f.setIsAutostartOn() f.setIsAutostartOn()
return return
} }
var err error var err error
if makeItEnabled { if makeItEnabled {
err = f.autostart.Enable() err = f.bridge.EnableAutostart()
} else { } else {
err = f.autostart.Disable() err = f.bridge.DisableAutostart()
} }
f.setIsAutostartOn() f.setIsAutostartOn()

View File

@ -90,6 +90,8 @@ type QMLBackend struct {
_ func(enableDiskCache bool, diskCachePath core.QUrl) `slot:"changeLocalCache"` _ func(enableDiskCache bool, diskCachePath core.QUrl) `slot:"changeLocalCache"`
_ func() `signal:"changeLocalCacheFinished"` _ func() `signal:"changeLocalCacheFinished"`
_ bool `property:"isFirstGUIStart"`
_ bool `property:"isAutomaticUpdateOn"` _ bool `property:"isAutomaticUpdateOn"`
_ func(makeItActive bool) `slot:"toggleAutomaticUpdate"` _ func(makeItActive bool) `slot:"toggleAutomaticUpdate"`

View File

@ -87,6 +87,9 @@ type Bridger interface {
GetKeychainApp() string GetKeychainApp() string
SetKeychainApp(keychain string) SetKeychainApp(keychain string)
HasError(err error) bool HasError(err error) bool
IsAutostartEnabled() bool
EnableAutostart() error
DisableAutostart() error
} }
type bridgeWrap struct { type bridgeWrap struct {

View File

@ -20,6 +20,7 @@ package context
import ( import (
"time" "time"
"github.com/ProtonMail/go-autostart"
"github.com/ProtonMail/proton-bridge/internal/bridge" "github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/config/settings" "github.com/ProtonMail/proton-bridge/internal/config/settings"
"github.com/ProtonMail/proton-bridge/internal/config/useragent" "github.com/ProtonMail/proton-bridge/internal/config/useragent"
@ -87,5 +88,9 @@ func newBridgeInstance(
credStore, credStore,
newFakeUpdater(), newFakeUpdater(),
newFakeVersioner(), newFakeVersioner(),
&autostart.App{
Name: "bridge",
Exec: []string{"bridge"},
},
) )
} }