Improve profile metadata handling
This commit is contained in:
@@ -64,14 +64,14 @@ func GetProcessByConnection(ctx context.Context, pktInfo *packet.Info) (process
|
|||||||
func GetNetworkHost(ctx context.Context, remoteIP net.IP) (process *Process, err error) { //nolint:interfacer
|
func GetNetworkHost(ctx context.Context, remoteIP net.IP) (process *Process, err error) { //nolint:interfacer
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
networkHost := &Process{
|
networkHost := &Process{
|
||||||
Name: fmt.Sprintf("Network Host %s", remoteIP),
|
Name: fmt.Sprintf("Device at %s", remoteIP),
|
||||||
UserName: "Unknown",
|
UserName: "N/A",
|
||||||
UserID: NetworkHostProcessID,
|
UserID: NetworkHostProcessID,
|
||||||
Pid: NetworkHostProcessID,
|
Pid: NetworkHostProcessID,
|
||||||
ParentPid: NetworkHostProcessID,
|
ParentPid: NetworkHostProcessID,
|
||||||
Tags: []profile.Tag{
|
Tags: []profile.Tag{
|
||||||
{
|
{
|
||||||
Key: "net",
|
Key: "ip",
|
||||||
Value: remoteIP.String(),
|
Value: remoteIP.String(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -89,16 +89,6 @@ func GetNetworkHost(ctx context.Context, remoteIP net.IP) (process *Process, err
|
|||||||
networkHost.PrimaryProfileID = networkHostProfile.ScopedID()
|
networkHost.PrimaryProfileID = networkHostProfile.ScopedID()
|
||||||
networkHost.profile = networkHostProfile.LayeredProfile()
|
networkHost.profile = networkHostProfile.LayeredProfile()
|
||||||
|
|
||||||
if networkHostProfile.Name == "" {
|
|
||||||
// Assign name and save.
|
|
||||||
networkHostProfile.Name = networkHost.Name
|
|
||||||
|
|
||||||
err := networkHostProfile.Save()
|
|
||||||
if err != nil {
|
|
||||||
log.Warningf("process: failed to save profile %s: %s", networkHostProfile.ScopedID(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return networkHost, nil
|
return networkHost, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ var ownPID = os.Getpid()
|
|||||||
|
|
||||||
// GetProfile finds and assigns a profile set to the process.
|
// GetProfile finds and assigns a profile set to the process.
|
||||||
func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {
|
func (p *Process) GetProfile(ctx context.Context) (changed bool, err error) {
|
||||||
// Update profile metadata outside of *Process lock.
|
|
||||||
defer p.UpdateProfileMetadata()
|
|
||||||
|
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
|
|
||||||
@@ -114,24 +111,3 @@ func (p *Process) loadSpecialProfile(_ context.Context) (*profile.Profile, error
|
|||||||
// Return special profile.
|
// Return special profile.
|
||||||
return profile.GetSpecialProfile(specialProfileID, p.Path)
|
return profile.GetSpecialProfile(specialProfileID, p.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProfileMetadata updates the metadata of the local profile
|
|
||||||
// as required.
|
|
||||||
func (p *Process) UpdateProfileMetadata() {
|
|
||||||
// Check if there is a profile to work with.
|
|
||||||
localProfile := p.Profile().LocalProfile()
|
|
||||||
if localProfile == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update metadata of profile.
|
|
||||||
metadataUpdated := localProfile.UpdateMetadata(p.Path)
|
|
||||||
|
|
||||||
// Save the profile if we changed something.
|
|
||||||
if metadataUpdated {
|
|
||||||
err := localProfile.Save()
|
|
||||||
if err != nil {
|
|
||||||
log.Warningf("process: failed to save profile %s: %s", localProfile.ScopedID(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package tags
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/utils/osdetail"
|
||||||
"github.com/safing/portmaster/process"
|
"github.com/safing/portmaster/process"
|
||||||
"github.com/safing/portmaster/profile"
|
"github.com/safing/portmaster/profile"
|
||||||
)
|
)
|
||||||
@@ -71,8 +72,10 @@ func (h *AppImageHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||||||
for _, tag := range p.Tags {
|
for _, tag := range p.Tags {
|
||||||
if tag.Key == appImagePathTagKey {
|
if tag.Key == appImagePathTagKey {
|
||||||
return profile.New(&profile.Profile{
|
return profile.New(&profile.Profile{
|
||||||
Source: profile.SourceLocal,
|
Source: profile.SourceLocal,
|
||||||
PresentationPath: p.Path,
|
Name: osdetail.GenerateBinaryNameFromPath(tag.Value),
|
||||||
|
PresentationPath: p.Path,
|
||||||
|
UsePresentationPath: true,
|
||||||
Fingerprints: []profile.Fingerprint{
|
Fingerprints: []profile.Fingerprint{
|
||||||
{
|
{
|
||||||
Type: profile.FingerprintTypePathID,
|
Type: profile.FingerprintTypePathID,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
|
"github.com/safing/portbase/utils/osdetail"
|
||||||
"github.com/safing/portmaster/process"
|
"github.com/safing/portmaster/process"
|
||||||
"github.com/safing/portmaster/profile"
|
"github.com/safing/portmaster/profile"
|
||||||
)
|
)
|
||||||
@@ -17,7 +18,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
svchostName = "SvcHost"
|
svchostName = "Service Host"
|
||||||
svchostTagKey = "svchost"
|
svchostTagKey = "svchost"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ type SVCHostTagHandler struct{}
|
|||||||
|
|
||||||
// Name returns the tag handler name.
|
// Name returns the tag handler name.
|
||||||
func (h *SVCHostTagHandler) Name() string {
|
func (h *SVCHostTagHandler) Name() string {
|
||||||
return svcHostName
|
return svchostName
|
||||||
}
|
}
|
||||||
|
|
||||||
// TagDescriptions returns a list of all possible tags and their description
|
// TagDescriptions returns a list of all possible tags and their description
|
||||||
@@ -34,7 +35,7 @@ func (h *SVCHostTagHandler) Name() string {
|
|||||||
func (h *SVCHostTagHandler) TagDescriptions() []process.TagDescription {
|
func (h *SVCHostTagHandler) TagDescriptions() []process.TagDescription {
|
||||||
return []process.TagDescription{
|
return []process.TagDescription{
|
||||||
process.TagDescription{
|
process.TagDescription{
|
||||||
ID: svcHostTagKey,
|
ID: svchostTagKey,
|
||||||
Name: "SvcHost Service Name",
|
Name: "SvcHost Service Name",
|
||||||
Description: "Name of a service running in svchost.exe as reported by Windows.",
|
Description: "Name of a service running in svchost.exe as reported by Windows.",
|
||||||
},
|
},
|
||||||
@@ -43,7 +44,7 @@ func (h *SVCHostTagHandler) TagDescriptions() []process.TagDescription {
|
|||||||
|
|
||||||
// TagKeys returns a list of all possible tag keys of this handler.
|
// TagKeys returns a list of all possible tag keys of this handler.
|
||||||
func (h *SVCHostTagHandler) TagKeys() []string {
|
func (h *SVCHostTagHandler) TagKeys() []string {
|
||||||
return []string{svcHostTagKey}
|
return []string{svchostTagKey}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTags adds tags to the given process.
|
// AddTags adds tags to the given process.
|
||||||
@@ -61,7 +62,7 @@ func (h *SVCHostTagHandler) AddTags(p *process.Process) {
|
|||||||
p.Name += fmt.Sprintf(" (%s)", strings.Join(svcNames, ", "))
|
p.Name += fmt.Sprintf(" (%s)", strings.Join(svcNames, ", "))
|
||||||
// Add services as tags.
|
// Add services as tags.
|
||||||
for _, svcName := range svcNames {
|
for _, svcName := range svcNames {
|
||||||
p.Tag = append(p.Tag, profile.Tag{
|
p.Tags = append(p.Tags, profile.Tag{
|
||||||
Key: svchostTagKey,
|
Key: svchostTagKey,
|
||||||
Value: svcName,
|
Value: svcName,
|
||||||
})
|
})
|
||||||
@@ -78,19 +79,19 @@ func (h *SVCHostTagHandler) AddTags(p *process.Process) {
|
|||||||
func (h *SVCHostTagHandler) CreateProfile(p *process.Process) *profile.Profile {
|
func (h *SVCHostTagHandler) CreateProfile(p *process.Process) *profile.Profile {
|
||||||
for _, tag := range p.Tags {
|
for _, tag := range p.Tags {
|
||||||
if tag.Key == svchostTagKey {
|
if tag.Key == svchostTagKey {
|
||||||
return profile.New(
|
return profile.New(&profile.Profile{
|
||||||
profile.SourceLocal,
|
Source: profile.SourceLocal,
|
||||||
"",
|
Name: "Windows Service: " + osdetail.GenerateBinaryNameFromPath(tag.Value),
|
||||||
"Windows Service: "+tag.Value,
|
UsePresentationPath: false,
|
||||||
p.Path,
|
Fingerprints: []profile.Fingerprint{
|
||||||
[]profile.Fingerprint{profile.Fingerprint{
|
profile.Fingerprint{
|
||||||
Type: profile.FingerprintTypeTagID,
|
Type: profile.FingerprintTypeTagID,
|
||||||
Key: tag.Key,
|
Key: tag.Key,
|
||||||
Operation: profile.FingerprintOperationEqualsID,
|
Operation: profile.FingerprintOperationEqualsID,
|
||||||
Value: tag.Value,
|
Value: tag.Value,
|
||||||
}},
|
},
|
||||||
nil,
|
},
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/safing/portbase/utils/osdetail"
|
||||||
|
|
||||||
"github.com/safing/portbase/log"
|
"github.com/safing/portbase/log"
|
||||||
|
|
||||||
"github.com/safing/portbase/utils"
|
"github.com/safing/portbase/utils"
|
||||||
@@ -20,7 +22,7 @@ func init() {
|
|||||||
|
|
||||||
// Add custom WindowsApps path.
|
// Add custom WindowsApps path.
|
||||||
customWinStorePath := os.ExpandEnv(`%ProgramFiles%\WindowsApps\`)
|
customWinStorePath := os.ExpandEnv(`%ProgramFiles%\WindowsApps\`)
|
||||||
if !utils.StringSliceEqual(winStorePaths, customWinStorePath) {
|
if !utils.StringInSlice(winStorePaths, customWinStorePath) {
|
||||||
winStorePaths = append(winStorePaths, customWinStorePath)
|
winStorePaths = append(winStorePaths, customWinStorePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +66,7 @@ func (h *WinStoreHandler) AddTags(p *process.Process) {
|
|||||||
var appDir string
|
var appDir string
|
||||||
for _, winStorePath := range winStorePaths {
|
for _, winStorePath := range winStorePaths {
|
||||||
if strings.HasPrefix(p.Path, winStorePath) {
|
if strings.HasPrefix(p.Path, winStorePath) {
|
||||||
appDir := strings.SplitN(strings.TrimPrefix(p.Path, winStorePath), `\`, 2)[0]
|
appDir = strings.SplitN(strings.TrimPrefix(p.Path, winStorePath), `\`, 2)[0]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +77,7 @@ func (h *WinStoreHandler) AddTags(p *process.Process) {
|
|||||||
// Extract information from path.
|
// Extract information from path.
|
||||||
// Example: Microsoft.Office.OneNote_17.6769.57631.0_x64__8wekyb3d8bbwe
|
// Example: Microsoft.Office.OneNote_17.6769.57631.0_x64__8wekyb3d8bbwe
|
||||||
splitted := strings.Split(appDir, "_")
|
splitted := strings.Split(appDir, "_")
|
||||||
if splitted != 5 { // Four fields, one "__".
|
if len(splitted) != 5 { // Four fields, one "__".
|
||||||
log.Debugf("profile/tags: windows store app has incompatible app dir format: %q", appDir)
|
log.Debugf("profile/tags: windows store app has incompatible app dir format: %q", appDir)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -102,9 +104,10 @@ func (h *WinStoreHandler) CreateProfile(p *process.Process) *profile.Profile {
|
|||||||
for _, tag := range p.Tags {
|
for _, tag := range p.Tags {
|
||||||
if tag.Key == winStoreAppNameTagKey {
|
if tag.Key == winStoreAppNameTagKey {
|
||||||
return profile.New(&profile.Profile{
|
return profile.New(&profile.Profile{
|
||||||
Source: profile.SourceLocal,
|
Source: profile.SourceLocal,
|
||||||
Name: tag.Value,
|
Name: osdetail.GenerateBinaryNameFromPath(tag.Value),
|
||||||
PresentationPath: p.Path,
|
PresentationPath: p.Path,
|
||||||
|
UsePresentationPath: true,
|
||||||
Fingerprints: []profile.Fingerprint{
|
Fingerprints: []profile.Fingerprint{
|
||||||
{
|
{
|
||||||
Type: profile.FingerprintTypeTagID,
|
Type: profile.FingerprintTypeTagID,
|
||||||
|
|||||||
@@ -163,8 +163,9 @@ type parsedFingerprints struct {
|
|||||||
func parseFingerprints(raw []Fingerprint, deprecatedLinkedPath string) (parsed *parsedFingerprints, firstErr error) {
|
func parseFingerprints(raw []Fingerprint, deprecatedLinkedPath string) (parsed *parsedFingerprints, firstErr error) {
|
||||||
parsed = &parsedFingerprints{}
|
parsed = &parsedFingerprints{}
|
||||||
|
|
||||||
// Add deprecated linked path to fingerprints.
|
// Add deprecated LinkedPath to fingerprints, if they are empty.
|
||||||
if deprecatedLinkedPath != "" {
|
// TODO: Remove in v1.5
|
||||||
|
if len(raw) == 0 && deprecatedLinkedPath != "" {
|
||||||
parsed.pathPrints = append(parsed.pathPrints, &fingerprintEquals{
|
parsed.pathPrints = append(parsed.pathPrints, &fingerprintEquals{
|
||||||
Fingerprint: Fingerprint{
|
Fingerprint: Fingerprint{
|
||||||
Type: FingerprintTypePathID,
|
Type: FingerprintTypePathID,
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ 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
|
||||||
|
|
||||||
// Try the profile creation callback, if we have one.
|
// Try the profile creation callback, if we have one.
|
||||||
if createProfileCallback != nil {
|
if createProfileCallback != nil {
|
||||||
profile = createProfileCallback()
|
profile = createProfileCallback()
|
||||||
@@ -84,9 +87,10 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P
|
|||||||
}
|
}
|
||||||
|
|
||||||
profile = New(&Profile{
|
profile = New(&Profile{
|
||||||
ID: id,
|
ID: id,
|
||||||
Source: SourceLocal,
|
Source: SourceLocal,
|
||||||
PresentationPath: md.Path(),
|
PresentationPath: md.Path(),
|
||||||
|
UsePresentationPath: true,
|
||||||
Fingerprints: []Fingerprint{
|
Fingerprints: []Fingerprint{
|
||||||
{
|
{
|
||||||
Type: FingerprintTypePathID,
|
Type: FingerprintTypePathID,
|
||||||
@@ -98,6 +102,25 @@ func GetLocalProfile(id string, md MatchingData, createProfileCallback func() *P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize and update profile.
|
||||||
|
|
||||||
|
// Update metadata.
|
||||||
|
changed := profile.updateMetadata(md.Path())
|
||||||
|
|
||||||
|
// Save if created or changed.
|
||||||
|
if created || changed {
|
||||||
|
// Save profile.
|
||||||
|
err := profile.Save()
|
||||||
|
if err != nil {
|
||||||
|
log.Warningf("profile: failed to save profile %s after creation: %s", profile.ScopedID(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger further metadata fetching from system if profile was created.
|
||||||
|
if created && profile.UsePresentationPath {
|
||||||
|
module.StartWorker("get profile metadata", profile.updateMetadataFromSystem)
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare profile for first use.
|
// Prepare profile for first use.
|
||||||
|
|
||||||
// Process profiles are coming directly from the database or are new.
|
// Process profiles are coming directly from the database or are new.
|
||||||
@@ -158,7 +181,10 @@ profileFeed:
|
|||||||
prints, err := loadProfileFingerprints(r)
|
prints, err := loadProfileFingerprints(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("profile: failed to load fingerprints of %s: %s", r.Key(), err)
|
log.Debugf("profile: failed to load fingerprints of %s: %s", r.Key(), err)
|
||||||
continue
|
}
|
||||||
|
// Continue with any returned fingerprints.
|
||||||
|
if prints == nil {
|
||||||
|
continue profileFeed
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get matching score and compare.
|
// Get matching score and compare.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -89,6 +88,10 @@ type Profile struct { //nolint:maligned // not worth the effort
|
|||||||
// Is automatically removed when the path does not exist.
|
// Is automatically removed when the path does not exist.
|
||||||
// Is automatically populated with the next match when empty.
|
// Is automatically populated with the next match when empty.
|
||||||
PresentationPath string
|
PresentationPath string
|
||||||
|
// UsePresentationPath can be used to enable/disable fetching information
|
||||||
|
// from the executable at PresentationPath. In some cases, this is not
|
||||||
|
// desirable.
|
||||||
|
UsePresentationPath bool
|
||||||
// Fingerprints holds process matching information.
|
// Fingerprints holds process matching information.
|
||||||
Fingerprints []Fingerprint
|
Fingerprints []Fingerprint
|
||||||
// SecurityLevel is the mininum security level to apply to
|
// SecurityLevel is the mininum security level to apply to
|
||||||
@@ -419,48 +422,54 @@ func EnsureProfile(r record.Record) (*Profile, error) {
|
|||||||
return newProfile, nil
|
return newProfile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateMetadata updates meta data fields on the profile and returns whether
|
// 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
|
// the profile was changed.
|
||||||
// operating system, it will start an async worker to fetch that data and save
|
func (profile *Profile) updateMetadata(binaryPath string) (changed bool) {
|
||||||
// the profile afterwards.
|
|
||||||
func (profile *Profile) UpdateMetadata(binaryPath string) (changed bool) {
|
|
||||||
// Check if this is a local profile, else warn and return.
|
// Check if this is a local profile, else warn and return.
|
||||||
if profile.Source != SourceLocal {
|
if profile.Source != SourceLocal {
|
||||||
log.Warningf("tried to update metadata for non-local profile %s", profile.ScopedID())
|
log.Warningf("tried to update metadata for non-local profile %s", profile.ScopedID())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
profile.Lock()
|
// Set PresentationPath if unset.
|
||||||
defer profile.Unlock()
|
if profile.PresentationPath == "" && binaryPath != "" {
|
||||||
|
profile.PresentationPath = binaryPath
|
||||||
// Update special profile and return if it was one.
|
changed = true
|
||||||
if ok, changed := updateSpecialProfileMetadata(profile, binaryPath); ok {
|
|
||||||
return changed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var needsUpdateFromSystem bool
|
// Migrate LinkedPath to PresentationPath.
|
||||||
|
// TODO: Remove in v1.5
|
||||||
|
if profile.PresentationPath == "" && profile.LinkedPath != "" {
|
||||||
|
profile.PresentationPath = profile.LinkedPath
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
// Check profile name.
|
// Set Name if unset.
|
||||||
filename := filepath.Base(profile.PresentationPath)
|
if profile.Name == "" && profile.PresentationPath != "" {
|
||||||
|
// Generate a default profile name from path.
|
||||||
// Update profile name if it is empty or equals the filename, which is the
|
|
||||||
// case for older profiles.
|
|
||||||
if strings.TrimSpace(profile.Name) == "" || profile.Name == filename {
|
|
||||||
// Generate a default profile name if does not exist.
|
|
||||||
profile.Name = osdetail.GenerateBinaryNameFromPath(profile.PresentationPath)
|
profile.Name = osdetail.GenerateBinaryNameFromPath(profile.PresentationPath)
|
||||||
if profile.Name == filename {
|
changed = true
|
||||||
// TODO: Theoretically, the generated name could be identical to the
|
}
|
||||||
// filename.
|
|
||||||
// As a quick fix, append a space to the name.
|
// Migrato to Fingerprints.
|
||||||
profile.Name += " "
|
// TODO: Remove in v1.5
|
||||||
|
if len(profile.Fingerprints) == 0 && profile.LinkedPath != "" {
|
||||||
|
profile.Fingerprints = []Fingerprint{
|
||||||
|
{
|
||||||
|
Type: FingerprintTypePathID,
|
||||||
|
Operation: FingerprintOperationEqualsID,
|
||||||
|
Value: profile.LinkedPath,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
changed = true
|
changed = true
|
||||||
needsUpdateFromSystem = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If needed, get more/better data from the operating system.
|
// UI Backward Compatibility:
|
||||||
if needsUpdateFromSystem {
|
// Fill LinkedPath with PresentationPath
|
||||||
module.StartWorker("get profile metadata", profile.updateMetadataFromSystem)
|
// TODO: Remove in v1.1
|
||||||
|
if profile.LinkedPath == "" && profile.PresentationPath != "" {
|
||||||
|
profile.LinkedPath = profile.PresentationPath
|
||||||
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
@@ -469,23 +478,14 @@ func (profile *Profile) UpdateMetadata(binaryPath string) (changed bool) {
|
|||||||
// updateMetadataFromSystem updates the profile metadata with data from the
|
// updateMetadataFromSystem updates the profile metadata with data from the
|
||||||
// operating system and saves it afterwards.
|
// operating system and saves it afterwards.
|
||||||
func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
||||||
|
var changed bool
|
||||||
|
|
||||||
// This function is only valid for local profiles.
|
// This function is only valid for local profiles.
|
||||||
if profile.Source != SourceLocal || profile.PresentationPath == "" {
|
if profile.Source != SourceLocal || profile.PresentationPath == "" {
|
||||||
return fmt.Errorf("tried to update metadata for non-local or non-path profile %s", profile.ScopedID())
|
return fmt.Errorf("tried to update metadata for non-local or non-path profile %s", profile.ScopedID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the profile when finished, if needed.
|
// Get binary name from PresentationPath.
|
||||||
save := false
|
|
||||||
defer func() {
|
|
||||||
if save {
|
|
||||||
err := profile.Save()
|
|
||||||
if err != nil {
|
|
||||||
log.Warningf("profile: failed to save %s after metadata update: %s", profile.ScopedID(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Get binary name from linked path.
|
|
||||||
newName, err := osdetail.GetBinaryNameFromSystem(profile.PresentationPath)
|
newName, err := osdetail.GetBinaryNameFromSystem(profile.PresentationPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
@@ -503,25 +503,26 @@ func (profile *Profile) updateMetadataFromSystem(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get filename of linked path for comparison.
|
// Apply new data to profile.
|
||||||
filename := filepath.Base(profile.PresentationPath)
|
func() {
|
||||||
|
// Lock profile for applying metadata.
|
||||||
|
profile.Lock()
|
||||||
|
defer profile.Unlock()
|
||||||
|
|
||||||
// TODO: Theoretically, the generated name from the system could be identical
|
// Apply new name if it changed.
|
||||||
// to the filename. This would mean that the worker is triggered every time
|
if profile.Name != newName {
|
||||||
// the profile is freshly loaded.
|
profile.Name = newName
|
||||||
if newName == filename {
|
changed = true
|
||||||
// As a quick fix, append a space to the name.
|
}
|
||||||
newName += " "
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
// Lock profile for applying metadata.
|
// If anything changed, save the profile.
|
||||||
profile.Lock()
|
// profile.Lock must not be held!
|
||||||
defer profile.Unlock()
|
if changed {
|
||||||
|
err := profile.Save()
|
||||||
// Apply new name if it changed.
|
if err != nil {
|
||||||
if profile.Name != newName {
|
log.Warningf("profile: failed to save %s after metadata update: %s", profile.ScopedID(), err)
|
||||||
profile.Name = newName
|
}
|
||||||
save = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -110,20 +110,40 @@ func GetSpecialProfile(id string, path string) ( //nolint:gocognit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get special profile from DB and check if it needs a reset.
|
// Get special profile from DB and check if it needs a reset.
|
||||||
|
var created bool
|
||||||
profile, err = getProfile(scopedID)
|
profile, err = getProfile(scopedID)
|
||||||
if err != nil {
|
switch {
|
||||||
if !errors.Is(err, database.ErrNotFound) {
|
case err == nil:
|
||||||
log.Warningf("profile: failed to get special profile %s: %s", id, err)
|
// 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:
|
||||||
|
// Create new profile if it does not exist (or failed to load).
|
||||||
profile = createSpecialProfile(id, path)
|
profile = createSpecialProfile(id, path)
|
||||||
} else if specialProfileNeedsReset(profile) {
|
created = true
|
||||||
log.Debugf("profile: resetting special profile %s", id)
|
|
||||||
profile = createSpecialProfile(id, path)
|
|
||||||
}
|
}
|
||||||
|
// Check if creating the special profile was successful.
|
||||||
if profile == nil {
|
if profile == nil {
|
||||||
return nil, errors.New("given ID is not a special profile ID")
|
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.
|
// Prepare profile for first use.
|
||||||
|
|
||||||
// If we are refetching, assign the layered profile from the previous version.
|
// If we are refetching, assign the layered profile from the previous version.
|
||||||
@@ -144,7 +164,7 @@ func GetSpecialProfile(id string, path string) ( //nolint:gocognit
|
|||||||
return profile, nil
|
return profile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (ok, changed bool) {
|
func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (changed bool) {
|
||||||
// Get new profile name and check if profile is applicable to special handling.
|
// Get new profile name and check if profile is applicable to special handling.
|
||||||
var newProfileName, newDescription string
|
var newProfileName, newDescription string
|
||||||
switch profile.ID {
|
switch profile.ID {
|
||||||
@@ -170,7 +190,7 @@ func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (ok, chan
|
|||||||
newProfileName = PortmasterNotifierProfileName
|
newProfileName = PortmasterNotifierProfileName
|
||||||
newDescription = PortmasterNotifierProfileDescription
|
newDescription = PortmasterNotifierProfileDescription
|
||||||
default:
|
default:
|
||||||
return false, false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update profile name if needed.
|
// Update profile name if needed.
|
||||||
@@ -191,7 +211,7 @@ func updateSpecialProfileMetadata(profile *Profile, binaryPath string) (ok, chan
|
|||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, changed
|
return changed
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSpecialProfile(profileID string, path string) *Profile {
|
func createSpecialProfile(profileID string, path string) *Profile {
|
||||||
@@ -203,6 +223,13 @@ func createSpecialProfile(profileID string, path string) *Profile {
|
|||||||
PresentationPath: path,
|
PresentationPath: path,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
case UnsolicitedProfileID:
|
||||||
|
return New(&Profile{
|
||||||
|
ID: UnsolicitedProfileID,
|
||||||
|
Source: SourceLocal,
|
||||||
|
PresentationPath: path,
|
||||||
|
})
|
||||||
|
|
||||||
case SystemProfileID:
|
case SystemProfileID:
|
||||||
return New(&Profile{
|
return New(&Profile{
|
||||||
ID: SystemProfileID,
|
ID: SystemProfileID,
|
||||||
@@ -306,7 +333,7 @@ func specialProfileNeedsReset(profile *Profile) bool {
|
|||||||
|
|
||||||
switch profile.ID {
|
switch profile.ID {
|
||||||
case SystemResolverProfileID:
|
case SystemResolverProfileID:
|
||||||
return canBeUpgraded(profile, "20.11.2021")
|
return canBeUpgraded(profile, "21.10.2022")
|
||||||
case PortmasterAppProfileID:
|
case PortmasterAppProfileID:
|
||||||
return canBeUpgraded(profile, "8.9.2021")
|
return canBeUpgraded(profile, "8.9.2021")
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user