Files
portmaster/profile/config-update.go

133 lines
3.1 KiB
Go

package profile
import (
"context"
"fmt"
"sync"
"time"
"github.com/safing/portbase/config"
"github.com/safing/portbase/modules"
"github.com/safing/portmaster/intel/filterlists"
"github.com/safing/portmaster/profile/endpoints"
)
var (
cfgLock sync.RWMutex
cfgDefaultAction uint8
cfgEndpoints endpoints.Endpoints
cfgServiceEndpoints endpoints.Endpoints
cfgFilterLists []string
)
func registerConfigUpdater() error {
return module.RegisterEventHook(
"config",
"config change",
"update global config profile",
func(ctx context.Context, _ interface{}) error {
return updateGlobalConfigProfile(ctx, nil)
},
)
}
const globalConfigProfileErrorID = "profile:global-profile-error"
func updateGlobalConfigProfile(ctx context.Context, task *modules.Task) error {
cfgLock.Lock()
defer cfgLock.Unlock()
var err error
var lastErr error
action := cfgOptionDefaultAction()
switch action {
case "permit":
cfgDefaultAction = DefaultActionPermit
case "ask":
cfgDefaultAction = DefaultActionAsk
case "block":
cfgDefaultAction = DefaultActionBlock
default:
// TODO: module error?
lastErr = fmt.Errorf(`default action "%s" invalid`, action)
cfgDefaultAction = DefaultActionBlock // default to block in worst case
}
list := cfgOptionEndpoints()
cfgEndpoints, err = endpoints.ParseEndpoints(list)
if err != nil {
// TODO: module error?
lastErr = err
}
list = cfgOptionServiceEndpoints()
cfgServiceEndpoints, err = endpoints.ParseEndpoints(list)
if err != nil {
// TODO: module error?
lastErr = err
}
list = cfgOptionFilterLists()
cfgFilterLists, err = filterlists.ResolveListIDs(list)
if err != nil {
lastErr = err
}
// build global profile for reference
profile := New(SourceSpecial, "global-config", "", nil)
profile.Name = "Global Configuration"
profile.Internal = true
newConfig := make(map[string]interface{})
// fill profile config options
for key, value := range cfgStringOptions {
newConfig[key] = value()
}
for key, value := range cfgStringArrayOptions {
newConfig[key] = value()
}
for key, value := range cfgIntOptions {
newConfig[key] = value()
}
for key, value := range cfgBoolOptions {
newConfig[key] = value()
}
// expand and assign
profile.Config = config.Expand(newConfig)
// save profile
err = profile.Save()
if err != nil && lastErr == nil {
// other errors are more important
lastErr = err
}
// If there was any error, try again later until it succeeds.
if lastErr == nil {
module.Resolve(globalConfigProfileErrorID)
} else {
// Create task after first failure.
if task == nil {
task = module.NewTask(
"retry updating global config profile",
updateGlobalConfigProfile,
)
}
// Schedule task.
task.Schedule(time.Now().Add(15 * time.Second))
// Add module warning to inform user.
module.Warning(
globalConfigProfileErrorID,
"Internal Settings Failure",
fmt.Sprintf("The app settings layering system failed to process the global settings. This means that some global settings might not be applied correctly. You can try restarting the Portmaster to resolve this problem. Refer to the error for more details: %s", err),
)
}
return lastErr
}