From b9127d3f91eddcb3ad8e85681de4fabb8ed5df9c Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 13 Oct 2022 11:20:04 +0200 Subject: [PATCH] Integrate special profiles into regular profile fetching for correct profile udpates --- process/profile.go | 27 +++---------- profile/get.go | 32 ++++++++++++++-- profile/special.go | 96 ++++++---------------------------------------- 3 files changed, 46 insertions(+), 109 deletions(-) diff --git a/process/profile.go b/process/profile.go index 9c49e832..65680639 100644 --- a/process/profile.go +++ b/process/profile.go @@ -27,18 +27,10 @@ func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) { // If not, continue with loading the profile. log.Tracer(ctx).Trace("process: loading profile") - // Check if there is a special profile for this process. - localProfile, err := p.loadSpecialProfile(ctx) + // Get special or regular profile. + localProfile, err := profile.GetLocalProfile(p.getSpecialProfileID(), p.MatchingData(), p.CreateProfileCallback) if err != nil { - return false, fmt.Errorf("failed to load special profile: %w", err) - } - - // Otherwise, find a regular profile for the process. - if localProfile == nil { - localProfile, err = profile.GetLocalProfile("", p.MatchingData(), p.CreateProfileCallback) - if err != nil { - return false, fmt.Errorf("failed to find profile: %w", err) - } + return false, fmt.Errorf("failed to find profile: %w", err) } // Assign profile to process. @@ -48,10 +40,9 @@ func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) { return true, nil } -// loadSpecialProfile attempts to load a special profile. -func (p *Process) loadSpecialProfile(_ context.Context) (*profile.Profile, error) { +// getSpecialProfileID returns the special profile ID for the process, if any. +func (p *Process) getSpecialProfileID() (specialProfileID string) { // Check if we need a special profile. - var specialProfileID string switch p.Pid { case UnidentifiedProcessID: specialProfileID = profile.UnidentifiedProfileID @@ -103,11 +94,5 @@ func (p *Process) loadSpecialProfile(_ context.Context) (*profile.Profile, error } } - // Check if a special profile should be applied. - if specialProfileID == "" { - return nil, nil - } - - // Return special profile. - return profile.GetSpecialProfile(specialProfileID, p.Path) + return specialProfileID } diff --git a/profile/get.go b/profile/get.go index 9d6d1b61..b9cc360f 100644 --- a/profile/get.go +++ b/profile/get.go @@ -7,6 +7,7 @@ import ( "strings" "sync" + "github.com/safing/portbase/database" "github.com/safing/portbase/database/query" "github.com/safing/portbase/database/record" "github.com/safing/portbase/log" @@ -50,6 +51,7 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P // In some cases, we might need to get a profile directly, without matching data. // This could lead to inconsistent data - use with caution. + // Example: Saving prompt results to profile should always be to the same ID! if md == nil { if id == "" { return nil, errors.New("cannot get local profiles without ID and matching data") @@ -61,6 +63,26 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P } } + // Check if we are requesting a special profile. + var created, special bool + if id != "" && isSpecialProfileID(id) { + special = true + + // Get special profile from DB. + if profile == nil { + profile, err = getProfile(makeScopedID(SourceLocal, id)) + if err != nil && !errors.Is(err, database.ErrNotFound) { + log.Warningf("profile: failed to get special profile %s: %s", id, err) + } + } + + // Create profile if not found or if it needs a reset. + if profile == nil || specialProfileNeedsReset(profile) { + profile = createSpecialProfile(id, md.Path()) + created = true + } + } + // If we don't have a profile yet, find profile based on matching data. if profile == nil { profile, err = findProfile(SourceLocal, md) @@ -70,7 +92,6 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P } // If we still don't have a profile, create a new one. - var created bool if profile == nil { created = true @@ -105,7 +126,12 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P // Initialize and update profile. // Update metadata. - changed := profile.updateMetadata(md.Path()) + var changed bool + if special { + changed = updateSpecialProfileMetadata(profile, md.Path()) + } else { + changed = profile.updateMetadata(md.Path()) + } // Save if created or changed. if created || changed { @@ -117,7 +143,7 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P } // Trigger further metadata fetching from system if profile was created. - if created && profile.UsePresentationPath { + if created && profile.UsePresentationPath && !special { module.StartWorker("get profile metadata", profile.updateMetadataFromSystem) } diff --git a/profile/special.go b/profile/special.go index 79c2a7b5..7080659c 100644 --- a/profile/special.go +++ b/profile/special.go @@ -1,10 +1,8 @@ package profile import ( - "errors" "time" - "github.com/safing/portbase/database" "github.com/safing/portbase/log" "github.com/safing/portmaster/status" ) @@ -77,91 +75,19 @@ If you think you might have messed up the settings of the System DNS Client, jus PortmasterNotifierProfileDescription = `This is the Portmaster UI Tray Notifier.` ) -// GetSpecialProfile fetches a special profile. This function ensures that the loaded profile -// is shared among all callers. Always provide all available data points. -func GetSpecialProfile(id string, path string) ( //nolint:gocognit - profile *Profile, - err error, -) { - // Check if we have an ID. - if id == "" { - return nil, errors.New("cannot get special profile without ID") - } - scopedID := makeScopedID(SourceLocal, id) - - // Globally lock getting a profile. - // This does not happen too often, and it ensures we really have integrity - // and no race conditions. - getProfileLock.Lock() - defer getProfileLock.Unlock() - - // Check if there already is an active profile. - var previousVersion *Profile - profile = getActiveProfile(scopedID) - if profile != nil { - // Mark active and return if not outdated. - if profile.outdated.IsNotSet() { - profile.MarkStillActive() - return profile, nil - } - - // If outdated, get from database. - previousVersion = profile - } - - // Get special profile from DB and check if it needs a reset. - var created bool - profile, err = getProfile(scopedID) - switch { - case err == nil: - // Reset profile if needed. - if specialProfileNeedsReset(profile) { - profile = createSpecialProfile(id, path) - created = true - } - case !errors.Is(err, database.ErrNotFound): - // Warn when fetching from DB fails, and create new profile as fallback. - log.Warningf("profile: failed to get special profile %s: %s", id, err) - fallthrough +func isSpecialProfileID(id string) bool { + switch id { + case UnidentifiedProfileID, + UnsolicitedProfileID, + SystemProfileID, + SystemResolverProfileID, + PortmasterProfileID, + PortmasterAppProfileID, + PortmasterNotifierProfileID: + return true default: - // Create new profile if it does not exist (or failed to load). - profile = createSpecialProfile(id, path) - created = true + return false } - // Check if creating the special profile was successful. - if profile == nil { - return nil, errors.New("given ID is not a special profile ID") - } - - // Update metadata - changed := updateSpecialProfileMetadata(profile, path) - - // Save if created or changed. - if created || changed { - err := profile.Save() - if err != nil { - log.Warningf("profile: failed to save special profile %s: %s", scopedID, err) - } - } - - // Prepare profile for first use. - - // If we are refetching, assign the layered profile from the previous version. - // The internal references will be updated when the layered profile checks for updates. - if previousVersion != nil && previousVersion.layeredProfile != nil { - profile.layeredProfile = previousVersion.layeredProfile - } - - // Profiles must have a layered profile, create a new one if it - // does not yet exist. - if profile.layeredProfile == nil { - profile.layeredProfile = NewLayeredProfile(profile) - } - - // Add the profile to the currently active profiles. - addActiveProfile(profile) - - return profile, nil } func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (changed bool) {