From 642e2eb11259dffa1f6620f3c962992ef6fb4a65 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 3 Jun 2021 23:28:41 +0200 Subject: [PATCH] Establish beta and staging release channels, move indexes to helper --- updates/config.go | 28 ++++++---- updates/export.go | 12 +++-- updates/helper/electron.go | 9 ---- updates/helper/indexes.go | 50 ++++++++++++++++++ updates/helper/updates.go | 68 ++++++++++++++++++++++++ updates/main.go | 105 +++++-------------------------------- updates/upgrader.go | 9 ++-- 7 files changed, 161 insertions(+), 120 deletions(-) create mode 100644 updates/helper/indexes.go create mode 100644 updates/helper/updates.go diff --git a/updates/config.go b/updates/config.go index 2889029c..8043038b 100644 --- a/updates/config.go +++ b/updates/config.go @@ -4,6 +4,7 @@ import ( "context" "github.com/safing/portbase/notifications" + "github.com/safing/portmaster/updates/helper" "github.com/tevino/abool" "github.com/safing/portbase/config" @@ -20,6 +21,7 @@ var ( devMode config.BoolOption enableUpdates config.BoolOption + initialReleaseChannel string previousReleaseChannel string updatesCurrentlyEnabled bool previousDevMode bool @@ -29,21 +31,28 @@ var ( func registerConfig() error { err := config.Register(&config.Option{ Name: "Release Channel", - Key: releaseChannelKey, + Key: helper.ReleaseChannelKey, Description: "Switch release channel.", OptType: config.OptTypeString, ExpertiseLevel: config.ExpertiseLevelDeveloper, ReleaseLevel: config.ReleaseLevelExperimental, - RequiresRestart: false, - DefaultValue: releaseChannelStable, + RequiresRestart: true, + DefaultValue: helper.ReleaseChannelStable, PossibleValues: []config.PossibleValue{ { - Name: "Stable", - Value: releaseChannelStable, + Name: "Stable", + Description: "Production releases.", + Value: helper.ReleaseChannelStable, }, { - Name: "Beta", - Value: releaseChannelBeta, + Name: "Beta", + Description: "Production releases for testing new features that may break and cause interruption.", + Value: helper.ReleaseChannelBeta, + }, + { + Name: "Staging", + Description: "Development releases for testing random things and experimenting. Dangerous - only use when told so.", + Value: helper.ReleaseChannelStaging, }, }, Annotations: config.Annotations{ @@ -78,7 +87,8 @@ func registerConfig() error { } func initConfig() { - releaseChannel = config.GetAsString(releaseChannelKey, releaseChannelStable) + releaseChannel = config.GetAsString(helper.ReleaseChannelKey, helper.ReleaseChannelStable) + initialReleaseChannel = releaseChannel() previousReleaseChannel = releaseChannel() enableUpdates = config.GetAsBool(enableUpdatesKey, true) @@ -107,7 +117,7 @@ func updateRegistryConfig(_ context.Context, _ interface{}) error { changed := false if releaseChannel() != previousReleaseChannel { - registry.SetBeta(releaseChannel() == releaseChannelBeta) + registry.SetUsePreReleases(releaseChannel() != helper.ReleaseChannelStable) previousReleaseChannel = releaseChannel() changed = true } diff --git a/updates/export.go b/updates/export.go index 112413b3..e00dee33 100644 --- a/updates/export.go +++ b/updates/export.go @@ -11,14 +11,14 @@ import ( "github.com/safing/portbase/info" "github.com/safing/portbase/log" "github.com/safing/portbase/updater" + "github.com/safing/portmaster/updates/helper" ) -// database key for update information +// Database key for update information. const ( versionsDBKey = "core:status/versions" ) -// working vars var ( versionExport *versions versionExportDB = database.NewInterface(&database.Options{ @@ -35,6 +35,7 @@ type versions struct { Core *info.Info Resources map[string]*updater.Resource + Channel string Beta bool Staging bool @@ -45,8 +46,9 @@ func initVersionExport() (err error) { // init export struct versionExport = &versions{ internalSave: true, - Beta: registry.Beta, - Staging: staging, + Channel: initialReleaseChannel, + Beta: initialReleaseChannel == helper.ReleaseChannelBeta, + Staging: initialReleaseChannel == helper.ReleaseChannelStaging, } versionExport.SetKey(versionsDBKey) @@ -68,7 +70,7 @@ func stopVersionExport() error { return versionExportHook.Cancel() } -// export is an event hook +// export is an event hook. func export(_ context.Context, _ interface{}) error { // populate versionExport.lock.Lock() diff --git a/updates/helper/electron.go b/updates/helper/electron.go index a01dabba..cb997667 100644 --- a/updates/helper/electron.go +++ b/updates/helper/electron.go @@ -1,7 +1,6 @@ package helper import ( - "fmt" "io/ioutil" "os" "path/filepath" @@ -54,14 +53,6 @@ func EnsureChromeSandboxPermissions(reg *updater.ResourceRegistry) error { return nil } -// PlatformIdentifier converts identifier for the current platform. -func PlatformIdentifier(identifier string) string { - // From https://golang.org/pkg/runtime/#GOARCH - // GOOS is the running program's operating system target: one of darwin, freebsd, linux, and so on. - // GOARCH is the running program's architecture target: one of 386, amd64, arm, s390x, and so on. - return fmt.Sprintf("%s_%s/%s", runtime.GOOS, runtime.GOARCH, identifier) -} - func checkSysctl(setting string, value byte) bool { c, err := sysctl(setting) if err != nil { diff --git a/updates/helper/indexes.go b/updates/helper/indexes.go new file mode 100644 index 00000000..97689db4 --- /dev/null +++ b/updates/helper/indexes.go @@ -0,0 +1,50 @@ +package helper + +import ( + "github.com/safing/portbase/updater" +) + +const ( + ReleaseChannelKey = "core/releaseChannel" + ReleaseChannelJSONKey = "core.releaseChannel" + ReleaseChannelStable = "stable" + ReleaseChannelBeta = "beta" + ReleaseChannelStaging = "staging" +) + +func SetIndexes(registry *updater.ResourceRegistry, releaseChannel string) { + // Be reminded that the order is important, as indexes added later will + // override the current release from earlier indexes. + + // Reset indexes before adding them (again). + registry.ResetIndexes() + + // Always add the stable index as a base. + registry.AddIndex(updater.Index{ + Path: "stable.json", + }) + + // Add beta index if in beta or staging channel. + if releaseChannel == ReleaseChannelBeta || + releaseChannel == ReleaseChannelStaging { + registry.AddIndex(updater.Index{ + Path: "beta.json", + PreRelease: true, + }) + } + + // Add staging index if in staging channel. + if releaseChannel == ReleaseChannelStaging { + registry.AddIndex(updater.Index{ + Path: "staging.json", + PreRelease: true, + }) + } + + // Add the intel index last, as it updates the fastest and should not be + // crippled by other faulty indexes. It can only specify versions for its + // scope anyway. + registry.AddIndex(updater.Index{ + Path: "all/intel/intel.json", + }) +} diff --git a/updates/helper/updates.go b/updates/helper/updates.go new file mode 100644 index 00000000..6ad4ffe5 --- /dev/null +++ b/updates/helper/updates.go @@ -0,0 +1,68 @@ +package helper + +import ( + "fmt" + "runtime" +) + +const ( + onWindows = runtime.GOOS == "windows" +) + +// PlatformIdentifier converts identifier for the current platform. +func PlatformIdentifier(identifier string) string { + // From https://golang.org/pkg/runtime/#GOARCH + // GOOS is the running program's operating system target: one of darwin, freebsd, linux, and so on. + // GOARCH is the running program's architecture target: one of 386, amd64, arm, s390x, and so on. + return fmt.Sprintf("%s_%s/%s", runtime.GOOS, runtime.GOARCH, identifier) +} + +// MandatoryUpdates returns mandatory updates that should be loaded on install +// or reset. +func MandatoryUpdates() (identifiers []string) { + // Binaries + if onWindows { + identifiers = []string{ + PlatformIdentifier("core/portmaster-core.exe"), + PlatformIdentifier("kext/portmaster-kext.dll"), + PlatformIdentifier("kext/portmaster-kext.sys"), + PlatformIdentifier("start/portmaster-start.exe"), + PlatformIdentifier("notifier/portmaster-notifier.exe"), + PlatformIdentifier("notifier/portmaster-snoretoast.exe"), + } + } else { + identifiers = []string{ + PlatformIdentifier("core/portmaster-core"), + PlatformIdentifier("start/portmaster-start"), + PlatformIdentifier("notifier/portmaster-notifier"), + } + } + + // Components, Assets and Data + identifiers = append( + identifiers, + + // User interface components + PlatformIdentifier("app/portmaster-app.zip"), + "all/ui/modules/portmaster.zip", + "all/ui/modules/assets.zip", + + // Filter lists data + "all/intel/lists/base.dsdl", + "all/intel/lists/intermediate.dsdl", + "all/intel/lists/urgent.dsdl", + + // Geo IP data + "all/intel/geoip/geoipv4.mmdb.gz", + "all/intel/geoip/geoipv6.mmdb.gz", + ) + + return identifiers +} + +// AutoUnpackUpdates returns assets that need unpacking. +func AutoUnpackUpdates() []string { + return []string{ + PlatformIdentifier("app/portmaster-app.zip"), + } +} diff --git a/updates/main.go b/updates/main.go index b3057588..c1d88814 100644 --- a/updates/main.go +++ b/updates/main.go @@ -4,11 +4,11 @@ import ( "context" "flag" "fmt" - "os" - "path/filepath" "runtime" "time" + "github.com/safing/portmaster/updates/helper" + "github.com/safing/portbase/dataroot" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" @@ -19,10 +19,6 @@ import ( const ( onWindows = runtime.GOOS == "windows" - releaseChannelKey = "core/releaseChannel" - releaseChannelStable = "stable" - releaseChannelBeta = "beta" - enableUpdatesKey = "core/automaticUpdates" // ModuleName is the name of the update module @@ -48,16 +44,11 @@ var ( module *modules.Module registry *updater.ResourceRegistry userAgentFromFlag string - staging bool updateTask *modules.Task updateASAP bool disableTaskSchedule bool - // MandatoryUpdates is a list of full identifiers that - // should always be kept up to date. - MandatoryUpdates []string - // UserAgent is an HTTP User-Agent that is used to add // more context to requests made by the registry when // fetching resources from the update server. @@ -65,9 +56,8 @@ var ( ) const ( - updateInProgress = "updates:in-progress" - updateFailed = "updates:failed" - updateSuccess = "updates:success" + updateFailed = "updates:failed" + updateSuccess = "updates:success" ) func init() { @@ -76,29 +66,9 @@ func init() { module.RegisterEvent(ResourceUpdateEvent, true) flag.StringVar(&userAgentFromFlag, "update-agent", "", "set the user agent for requests to the update server") - flag.BoolVar(&staging, "staging", false, "use staging update channel; for testing only") - // initialize mandatory updates - if onWindows { - MandatoryUpdates = []string{ - platform("core/portmaster-core.exe"), - platform("start/portmaster-start.exe"), - platform("notifier/portmaster-notifier.exe"), - platform("notifier/portmaster-snoretoast.exe"), - } - } else { - MandatoryUpdates = []string{ - platform("core/portmaster-core"), - platform("start/portmaster-start"), - platform("notifier/portmaster-notifier"), - } - } - - MandatoryUpdates = append( - MandatoryUpdates, - platform("app/portmaster-app.zip"), - "all/ui/modules/portmaster.zip", - ) + var dummy bool + flag.BoolVar(&dummy, "staging", false, "deprecated, configure in settings instead") } func prep() error { @@ -107,8 +77,6 @@ func prep() error { } return registerAPIEndpoints() - - return nil } func start() error { @@ -131,13 +99,11 @@ func start() error { "https://updates.safing.io", }, UserAgent: UserAgent, - MandatoryUpdates: MandatoryUpdates, - AutoUnpack: []string{ - platform("app/portmaster-app.zip"), - }, - Beta: releaseChannel() == releaseChannelBeta, - DevMode: devMode(), - Online: true, + MandatoryUpdates: helper.MandatoryUpdates(), + AutoUnpack: helper.AutoUnpackUpdates(), + UsePreReleases: initialReleaseChannel != helper.ReleaseChannelStable, + DevMode: devMode(), + Online: true, } if userAgentFromFlag != "" { // override with flag value @@ -149,38 +115,8 @@ func start() error { return err } - registry.AddIndex(updater.Index{ - Path: "stable.json", - Stable: true, - Beta: false, - }) - - if registry.Beta { - registry.AddIndex(updater.Index{ - Path: "beta.json", - Stable: false, - Beta: true, - }) - } - - registry.AddIndex(updater.Index{ - Path: "all/intel/intel.json", - Stable: true, - Beta: true, - }) - - if stagingActive() { - // Set flag no matter how staging was activated. - staging = true - - log.Warning("updates: staging environment is active") - - registry.AddIndex(updater.Index{ - Path: "staging.json", - Stable: true, - Beta: true, - }) - } + // Set indexes based on the release channel. + helper.SetIndexes(registry, initialReleaseChannel) err = registry.LoadIndexes(module.Ctx) if err != nil { @@ -342,21 +278,6 @@ func stop() error { return stopVersionExport() } -func platform(identifier string) string { - return fmt.Sprintf("%s_%s/%s", runtime.GOOS, runtime.GOARCH, identifier) -} - -func stagingActive() bool { - // Check flag and env variable. - if staging || os.Getenv("PORTMASTER_STAGING") == "enabled" { - return true - } - - // Check if staging index is present and acessible. - _, err := os.Stat(filepath.Join(registry.StorageDir().Path, "staging.json")) - return err == nil -} - // RootPath returns the root path used for storing updates. func RootPath() string { if !module.Online() { diff --git a/updates/upgrader.go b/updates/upgrader.go index 83c5aaa2..753bddde 100644 --- a/updates/upgrader.go +++ b/updates/upgrader.go @@ -351,10 +351,9 @@ func upgradeFile(fileToUpgrade string, file *updater.File) error { } // CopyFile atomically copies a file using the update registry's tmp dir. -func CopyFile(srcPath, dstPath string) (err error) { - +func CopyFile(srcPath, dstPath string) error { // check tmp dir - err = registry.TmpDir().Ensure() + err := registry.TmpDir().Ensure() if err != nil { return fmt.Errorf("could not prepare tmp directory for copying file: %w", err) } @@ -369,14 +368,14 @@ func CopyFile(srcPath, dstPath string) (err error) { // open source srcFile, err := os.Open(srcPath) if err != nil { - return + return err } defer srcFile.Close() // copy data _, err = io.Copy(atomicDstFile, srcFile) if err != nil { - return + return err } // finalize file