Adapt profiles to use new binary metadata system
This commit is contained in:
@@ -76,7 +76,7 @@ func updateGlobalConfigProfile(ctx context.Context, task *modules.Task) error {
|
||||
}
|
||||
|
||||
// build global profile for reference
|
||||
profile := New(SourceSpecial, "global-config")
|
||||
profile := New(SourceSpecial, "global-config", "")
|
||||
profile.Name = "Global Configuration"
|
||||
profile.Internal = true
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ var getProfileSingleInflight singleflight.Group
|
||||
// linkedPath parameters whenever available.
|
||||
func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit
|
||||
profile *Profile,
|
||||
newProfile bool,
|
||||
err error,
|
||||
) {
|
||||
// Select correct key for single in flight.
|
||||
@@ -67,12 +66,10 @@ func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit
|
||||
if errors.Is(err, database.ErrNotFound) {
|
||||
switch id {
|
||||
case UnidentifiedProfileID:
|
||||
profile = New(SourceLocal, UnidentifiedProfileID)
|
||||
newProfile = true
|
||||
profile = New(SourceLocal, UnidentifiedProfileID, linkedPath)
|
||||
err = nil
|
||||
case SystemProfileID:
|
||||
profile = New(SourceLocal, SystemProfileID)
|
||||
newProfile = true
|
||||
profile = New(SourceLocal, SystemProfileID, linkedPath)
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
@@ -90,7 +87,7 @@ func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit
|
||||
}
|
||||
}
|
||||
// Get from database.
|
||||
profile, newProfile, err = findProfile(linkedPath)
|
||||
profile, err = findProfile(linkedPath)
|
||||
|
||||
default:
|
||||
return nil, errors.New("cannot fetch profile without ID or path")
|
||||
@@ -126,13 +123,13 @@ func GetProfile(source profileSource, id, linkedPath string) ( //nolint:gocognit
|
||||
return profile, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
if p == nil {
|
||||
return nil, false, errors.New("profile getter returned nil")
|
||||
return nil, errors.New("profile getter returned nil")
|
||||
}
|
||||
|
||||
return p.(*Profile), newProfile, nil
|
||||
return p.(*Profile), nil
|
||||
}
|
||||
|
||||
// getProfile fetches the profile for the given scoped ID.
|
||||
@@ -149,7 +146,7 @@ func getProfile(scopedID string) (profile *Profile, err error) {
|
||||
|
||||
// findProfile searches for a profile with the given linked path. If it cannot
|
||||
// find one, it will create a new profile for the given linked path.
|
||||
func findProfile(linkedPath string) (profile *Profile, new bool, err error) {
|
||||
func findProfile(linkedPath string) (profile *Profile, err error) {
|
||||
// Search the database for a matching profile.
|
||||
it, err := profileDB.Query(
|
||||
query.New(makeProfileKey(SourceLocal, "")).Where(
|
||||
@@ -157,7 +154,7 @@ func findProfile(linkedPath string) (profile *Profile, new bool, err error) {
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Only wait for the first result, or until the query ends.
|
||||
@@ -168,12 +165,11 @@ func findProfile(linkedPath string) (profile *Profile, new bool, err error) {
|
||||
// Prep and return an existing profile.
|
||||
if r != nil {
|
||||
profile, err = prepProfile(r)
|
||||
return profile, false, err
|
||||
return profile, err
|
||||
}
|
||||
|
||||
// If there was no profile in the database, create a new one, and return it.
|
||||
profile = New(SourceLocal, "")
|
||||
profile.LinkedPath = linkedPath
|
||||
profile = New(SourceLocal, "", linkedPath)
|
||||
|
||||
// Check if the profile should be marked as internal.
|
||||
// This is the case whenever the binary resides within the data root dir.
|
||||
@@ -181,7 +177,7 @@ func findProfile(linkedPath string) (profile *Profile, new bool, err error) {
|
||||
profile.Internal = true
|
||||
}
|
||||
|
||||
return profile, true, nil
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func prepProfile(r record.Record) (*Profile, error) {
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/safing/portmaster/core/pmtesting"
|
||||
)
|
||||
|
||||
/*
|
||||
func TestMain(m *testing.M) {
|
||||
pmtesting.TestMain(m, module)
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -216,7 +216,7 @@ func (lp *LayeredProfile) Update() (revisionCounter uint64) {
|
||||
if layer.outdated.IsSet() {
|
||||
changed = true
|
||||
// update layer
|
||||
newLayer, _, err := GetProfile(layer.Source, layer.ID, layer.LinkedPath)
|
||||
newLayer, err := GetProfile(layer.Source, layer.ID, layer.LinkedPath)
|
||||
if err != nil {
|
||||
log.Errorf("profiles: failed to update profile %s", layer.ScopedID())
|
||||
} else {
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/safing/portbase/utils/osdetail"
|
||||
|
||||
"github.com/tevino/abool"
|
||||
|
||||
"github.com/safing/portbase/config"
|
||||
@@ -58,9 +62,9 @@ type Profile struct { //nolint:maligned // not worth the effort
|
||||
sync.RWMutex
|
||||
|
||||
// ID is a unique identifier for the profile.
|
||||
ID string
|
||||
ID string // constant
|
||||
// Source describes the source of the profile.
|
||||
Source profileSource
|
||||
Source profileSource // constant
|
||||
// Name is a human readable name of the profile. It
|
||||
// defaults to the basename of the application.
|
||||
Name string
|
||||
@@ -78,7 +82,7 @@ type Profile struct { //nolint:maligned // not worth the effort
|
||||
IconType iconType
|
||||
// LinkedPath is a filesystem path to the executable this
|
||||
// profile was created for.
|
||||
LinkedPath string
|
||||
LinkedPath string // constant
|
||||
// LinkedProfiles is a list of other profiles
|
||||
LinkedProfiles []string
|
||||
// SecurityLevel is the mininum security level to apply to
|
||||
@@ -191,10 +195,11 @@ func (profile *Profile) parseConfig() error {
|
||||
}
|
||||
|
||||
// New returns a new Profile.
|
||||
func New(source profileSource, id string) *Profile {
|
||||
func New(source profileSource, id string, linkedPath string) *Profile {
|
||||
profile := &Profile{
|
||||
ID: id,
|
||||
Source: source,
|
||||
LinkedPath: linkedPath,
|
||||
Created: time.Now().Unix(),
|
||||
Config: make(map[string]interface{}),
|
||||
internalSave: true,
|
||||
@@ -377,3 +382,106 @@ func EnsureProfile(r record.Record) (*Profile, error) {
|
||||
}
|
||||
return new, nil
|
||||
}
|
||||
|
||||
// UpdateMetadata updates meta data fields on the profile and returns whether
|
||||
// the profile was changed. If there is data that needs to be fetched from the
|
||||
// operating system, it will start an async worker to fetch that data and save
|
||||
// the profile afterwards.
|
||||
func (p *Profile) UpdateMetadata(processName string) (changed bool) {
|
||||
// Check if this is a local profile, else warn and return.
|
||||
if p.Source != SourceLocal {
|
||||
log.Warningf("tried to update metadata for non-local profile %s", p.ScopedID())
|
||||
return false
|
||||
}
|
||||
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
// Check if this is a special profile.
|
||||
if p.LinkedPath == "" {
|
||||
// This is a special profile, just assign the processName, if needed, and
|
||||
// return.
|
||||
if p.Name != processName {
|
||||
p.Name = processName
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var needsUpdateFromSystem bool
|
||||
|
||||
// Check profile name.
|
||||
_, filename := filepath.Split(p.LinkedPath)
|
||||
|
||||
// Update profile name if it is empty or equals the filename, which is the
|
||||
// case for older profiles.
|
||||
if p.Name == "" || p.Name == filename {
|
||||
// Generate a default profile name if does not exist.
|
||||
p.Name = osdetail.GenerateBinaryNameFromPath(p.LinkedPath)
|
||||
if p.Name == filename {
|
||||
// TODO: Theoretically, the generated name could be identical to the
|
||||
// filename.
|
||||
// As a quick fix, append a space to the name.
|
||||
p.Name += " "
|
||||
}
|
||||
changed = true
|
||||
needsUpdateFromSystem = true
|
||||
}
|
||||
|
||||
// If needed, get more/better data from the operating system.
|
||||
if needsUpdateFromSystem {
|
||||
module.StartWorker("get profile metadata", p.updateMetadataFromSystem)
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
|
||||
// updateMetadataFromSystem updates the profile metadata with data from the
|
||||
// operating system and saves it afterwards.
|
||||
func (p *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
||||
// This function is only valid for local profiles.
|
||||
if p.Source != SourceLocal || p.LinkedPath == "" {
|
||||
return fmt.Errorf("tried to update metadata for non-local / non-linked profile %s", p.ScopedID())
|
||||
}
|
||||
|
||||
// Save the profile when finished, if needed.
|
||||
save := false
|
||||
defer func() {
|
||||
if save {
|
||||
err := p.Save()
|
||||
if err != nil {
|
||||
log.Warningf("profile: failed to save %s after metadata update: %s", p.ScopedID(), err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Get binary name from linked path.
|
||||
newName, err := osdetail.GetBinaryNameFromSystem(p.LinkedPath)
|
||||
if err != nil {
|
||||
log.Warningf("profile: error while getting binary name for %s: %s", p.LinkedPath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get filename of linked path for comparison.
|
||||
_, filename := filepath.Split(p.LinkedPath)
|
||||
|
||||
// TODO: Theoretically, the generated name from the system could be identical
|
||||
// to the filename. This would mean that the worker is triggered every time
|
||||
// the profile is freshly loaded.
|
||||
if newName == filename {
|
||||
// As a quick fix, append a space to the name.
|
||||
newName += " "
|
||||
}
|
||||
|
||||
// Lock profile for applying metadata.
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
// Apply new name if it changed.
|
||||
if p.Name != newName {
|
||||
p.Name = newName
|
||||
save = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user