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,19 +27,11 @@ 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)
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)
// Get special or regular profile.
localProfile, err := profile.GetLocalProfile(p.getSpecialProfileID(), p.MatchingData(), p.CreateProfileCallback)
if err != nil {
return false, fmt.Errorf("failed to find profile: %w", err)
}
}
// Assign profile to process.
p.PrimaryProfileID = localProfile.ScopedID()
@ -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
}

View file

@ -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)
}

View file

@ -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) {