Integrate special profiles into regular profile fetching for correct profile udpates

This commit is contained in:
Daniel 2022-10-13 11:20:04 +02:00
parent afa696bb48
commit b9127d3f91
3 changed files with 46 additions and 109 deletions

View file

@ -27,18 +27,10 @@ func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {
// If not, continue with loading the profile. // If not, continue with loading the profile.
log.Tracer(ctx).Trace("process: loading profile") log.Tracer(ctx).Trace("process: loading profile")
// Check if there is a special profile for this process. // Get special or regular profile.
localProfile, err := p.loadSpecialProfile(ctx) localProfile, err := profile.GetLocalProfile(p.getSpecialProfileID(), p.MatchingData(), p.CreateProfileCallback)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to load special profile: %w", err) return false, fmt.Errorf("failed to find 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)
}
} }
// Assign profile to process. // Assign profile to process.
@ -48,10 +40,9 @@ func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {
return true, nil return true, nil
} }
// loadSpecialProfile attempts to load a special profile. // getSpecialProfileID returns the special profile ID for the process, if any.
func (p *Process) loadSpecialProfile(_ context.Context) (*profile.Profile, error) { func (p *Process) getSpecialProfileID() (specialProfileID string) {
// Check if we need a special profile. // Check if we need a special profile.
var specialProfileID string
switch p.Pid { switch p.Pid {
case UnidentifiedProcessID: case UnidentifiedProcessID:
specialProfileID = profile.UnidentifiedProfileID specialProfileID = profile.UnidentifiedProfileID
@ -103,11 +94,5 @@ func (p *Process) loadSpecialProfile(_ context.Context) (*profile.Profile, error
} }
} }
// Check if a special profile should be applied. return specialProfileID
if specialProfileID == "" {
return nil, nil
}
// Return special profile.
return profile.GetSpecialProfile(specialProfileID, p.Path)
} }

View file

@ -7,6 +7,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/safing/portbase/database"
"github.com/safing/portbase/database/query" "github.com/safing/portbase/database/query"
"github.com/safing/portbase/database/record" "github.com/safing/portbase/database/record"
"github.com/safing/portbase/log" "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. // In some cases, we might need to get a profile directly, without matching data.
// This could lead to inconsistent data - use with caution. // 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 md == nil {
if id == "" { if id == "" {
return nil, errors.New("cannot get local profiles without ID and matching data") 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 we don't have a profile yet, find profile based on matching data.
if profile == nil { if profile == nil {
profile, err = findProfile(SourceLocal, md) 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. // If we still don't have a profile, create a new one.
var created bool
if profile == nil { if profile == nil {
created = true created = true
@ -105,7 +126,12 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P
// Initialize and update profile. // Initialize and update profile.
// Update metadata. // 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. // Save if created or changed.
if created || 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. // 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) module.StartWorker("get profile metadata", profile.updateMetadataFromSystem)
} }

View file

@ -1,10 +1,8 @@
package profile package profile
import ( import (
"errors"
"time" "time"
"github.com/safing/portbase/database"
"github.com/safing/portbase/log" "github.com/safing/portbase/log"
"github.com/safing/portmaster/status" "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.` PortmasterNotifierProfileDescription = `This is the Portmaster UI Tray Notifier.`
) )
// GetSpecialProfile fetches a special profile. This function ensures that the loaded profile func isSpecialProfileID(id string) bool {
// is shared among all callers. Always provide all available data points. switch id {
func GetSpecialProfile(id string, path string) ( //nolint:gocognit case UnidentifiedProfileID,
profile *Profile, UnsolicitedProfileID,
err error, SystemProfileID,
) { SystemResolverProfileID,
// Check if we have an ID. PortmasterProfileID,
if id == "" { PortmasterAppProfileID,
return nil, errors.New("cannot get special profile without ID") PortmasterNotifierProfileID:
} return true
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
default: default:
// Create new profile if it does not exist (or failed to load). return false
profile = createSpecialProfile(id, path)
created = true
} }
// 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) { func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (changed bool) {