Working on portmaster restructure
This commit is contained in:
@@ -35,29 +35,17 @@ func updateActiveUserProfile(profile *Profile) {
|
||||
}
|
||||
}
|
||||
|
||||
func updateActiveGlobalProfile(profile *Profile) {
|
||||
updateActiveProfile(1, profile)
|
||||
}
|
||||
|
||||
func updateActiveStampProfile(profile *Profile) {
|
||||
updateActiveProfile(2, profile)
|
||||
}
|
||||
|
||||
func updateActiveFallbackProfile(profile *Profile) {
|
||||
updateActiveProfile(3, profile)
|
||||
}
|
||||
|
||||
func updateActiveProfile(setID int, profile *Profile) {
|
||||
activeProfileSetsLock.RLock()
|
||||
defer activeProfileSetsLock.RUnlock()
|
||||
|
||||
for _, activeSet := range activeProfileSets {
|
||||
activeSet.Lock()
|
||||
activeProfile := activeSet.profiles[setID]
|
||||
activeProfile := activeSet.profiles[2]
|
||||
if activeProfile != nil {
|
||||
activeProfile.Lock()
|
||||
if activeProfile.ID == profile.ID {
|
||||
activeSet.profiles[setID] = profile
|
||||
activeSet.profiles[2] = profile
|
||||
}
|
||||
activeProfile.Unlock()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package profile
|
||||
|
||||
import "time"
|
||||
|
||||
var (
|
||||
fingerprintWeights = map[string]int{
|
||||
"full_path": 2,
|
||||
@@ -10,41 +12,21 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// Fingerprint links processes to profiles.
|
||||
type Fingerprint struct {
|
||||
OS string
|
||||
Type string
|
||||
Value string
|
||||
Comment string
|
||||
OS string
|
||||
Type string
|
||||
Value string
|
||||
Comment string
|
||||
LastUsed int64
|
||||
}
|
||||
|
||||
// MatchesOS returns whether the Fingerprint is applicable for the current OS.
|
||||
func (fp *Fingerprint) MatchesOS() bool {
|
||||
return fp.OS == osIdentifier
|
||||
}
|
||||
|
||||
//
|
||||
// func (fp *Fingerprint) Equals(other *Fingerprint) bool {
|
||||
// return fp.OS == other.OS &&
|
||||
// fp.Type == other.Type &&
|
||||
// fp.Value == other.Value
|
||||
// }
|
||||
//
|
||||
// func (fp *Fingerprint) Check(type, value string) (weight int) {
|
||||
// if fp.Match(fpType, value) {
|
||||
// return GetFingerprintWeight(fpType)
|
||||
// }
|
||||
// return 0
|
||||
// }
|
||||
//
|
||||
// func (fp *Fingerprint) Match(fpType, value string) (matches bool) {
|
||||
// switch fp.Type {
|
||||
// case "partial_path":
|
||||
// return
|
||||
// default:
|
||||
// return fp.OS == osIdentifier &&
|
||||
// fp.Type == fpType &&
|
||||
// fp.Value == value
|
||||
// }
|
||||
//
|
||||
// GetFingerprintWeight returns the weight of the given fingerprint type.
|
||||
func GetFingerprintWeight(fpType string) (weight int) {
|
||||
weight, ok := fingerprintWeights[fpType]
|
||||
if ok {
|
||||
@@ -53,47 +35,14 @@ func GetFingerprintWeight(fpType string) (weight int) {
|
||||
return 0
|
||||
}
|
||||
|
||||
//
|
||||
// func (p *Profile) GetApplicableFingerprints() (fingerprints []*Fingerprint) {
|
||||
// for _, fp := range p.Fingerprints {
|
||||
// if fp.OS == osIdentifier {
|
||||
// fingerprints = append(fingerprints, fp)
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// AddFingerprint adds the given fingerprint to the profile.
|
||||
func (p *Profile) AddFingerprint(fp *Fingerprint) {
|
||||
if fp.OS == "" {
|
||||
fp.OS = osIdentifier
|
||||
}
|
||||
if fp.LastUsed == 0 {
|
||||
fp.LastUsed = time.Now().Unix()
|
||||
}
|
||||
|
||||
p.Fingerprints = append(p.Fingerprints, fp)
|
||||
}
|
||||
|
||||
//
|
||||
// func (p *Profile) GetApplicableFingerprintTypes() (types []string) {
|
||||
// for _, fp := range p.Fingerprints {
|
||||
// if fp.OS == osIdentifier && !utils.StringInSlice(types, fp.Type) {
|
||||
// types = append(types, fp.Type)
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// func (p *Profile) MatchFingerprints(fingerprints map[string]string) (score int) {
|
||||
// for _, fp := range p.Fingerprints {
|
||||
// if fp.OS == osIdentifier {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// func FindUserProfiles() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// func FindProfiles(path string) (*ProfileSet, error) {
|
||||
//
|
||||
// }
|
||||
|
||||
@@ -77,19 +77,6 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// FlagsFromNames creates Flags from a comma seperated list of flagnames (e.g. "System,Strict,Secure")
|
||||
// func FlagsFromNames(words []string) (*Flags, error) {
|
||||
// var flags Flags
|
||||
// for _, entry := range words {
|
||||
// flag, ok := flagIDs[entry]
|
||||
// if !ok {
|
||||
// return nil, ErrFlagsParseFailed
|
||||
// }
|
||||
// flags = append(flags, flag)
|
||||
// }
|
||||
// return &flags, nil
|
||||
// }
|
||||
|
||||
// Check checks if a flag is set at all and if it's active in the given security level.
|
||||
func (flags Flags) Check(flag, level uint8) (active bool, ok bool) {
|
||||
if flags == nil {
|
||||
|
||||
@@ -15,12 +15,14 @@ type ProfileIndex struct {
|
||||
record.Base
|
||||
sync.Mutex
|
||||
|
||||
ID string
|
||||
|
||||
UserProfiles []string
|
||||
StampProfiles []string
|
||||
}
|
||||
|
||||
func makeIndexRecordKey(id string) string {
|
||||
return fmt.Sprintf("index:profiles/%s", base64.RawURLEncoding.EncodeToString([]byte(id)))
|
||||
func makeIndexRecordKey(fpType, id string) string {
|
||||
return fmt.Sprintf("index:profiles/%s:%s", fpType, base64.RawURLEncoding.EncodeToString([]byte(id)))
|
||||
}
|
||||
|
||||
// NewIndex returns a new ProfileIndex.
|
||||
@@ -32,8 +34,8 @@ func NewIndex(id string) *ProfileIndex {
|
||||
|
||||
// AddUserProfile adds a User Profile to the index.
|
||||
func (pi *ProfileIndex) AddUserProfile(identifier string) (changed bool) {
|
||||
if !utils.StringInSlice(pi.UserProfiles, id) {
|
||||
pi.UserProfiles = append(pi.UserProfiles, id)
|
||||
if !utils.StringInSlice(pi.UserProfiles, identifier) {
|
||||
pi.UserProfiles = append(pi.UserProfiles, identifier)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -41,8 +43,8 @@ func (pi *ProfileIndex) AddUserProfile(identifier string) (changed bool) {
|
||||
|
||||
// AddStampProfile adds a Stamp Profile to the index.
|
||||
func (pi *ProfileIndex) AddStampProfile(identifier string) (changed bool) {
|
||||
if !utils.StringInSlice(pi.StampProfiles, id) {
|
||||
pi.StampProfiles = append(pi.StampProfiles, id)
|
||||
if !utils.StringInSlice(pi.StampProfiles, identifier) {
|
||||
pi.StampProfiles = append(pi.StampProfiles, identifier)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -59,8 +61,8 @@ func (pi *ProfileIndex) RemoveStampProfile(id string) {
|
||||
}
|
||||
|
||||
// Get gets a ProfileIndex from the database.
|
||||
func Get(id string) (*ProfileIndex, error) {
|
||||
key := makeIndexRecordKey(id)
|
||||
func Get(fpType, id string) (*ProfileIndex, error) {
|
||||
key := makeIndexRecordKey(fpType, id)
|
||||
|
||||
r, err := indexDB.Get(key)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/Safing/portbase/database"
|
||||
"github.com/Safing/portbase/database/query"
|
||||
"github.com/Safing/portbase/database/record"
|
||||
@@ -25,7 +23,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
modules.Register("profile:index", nil, start, stop, "database")
|
||||
modules.Register("profile:index", nil, start, stop, "profile", "database")
|
||||
}
|
||||
|
||||
func start() (err error) {
|
||||
@@ -49,13 +47,17 @@ func indexer() {
|
||||
case <-shutdownIndexer:
|
||||
return
|
||||
case r := <-indexSub.Feed:
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
prof := ensureProfile(r)
|
||||
if prof != nil {
|
||||
for _, id := range prof.Identifiers {
|
||||
if strings.HasPrefix(id, profile.IdentifierPrefix) {
|
||||
for _, fp := range prof.Fingerprints {
|
||||
if fp.MatchesOS() && fp.Type == "full_path" {
|
||||
|
||||
// get Profile and ensure identifier is set
|
||||
pi, err := GetIndex(id)
|
||||
pi, err := Get("full_path", fp.Value)
|
||||
if err != nil {
|
||||
if err == database.ErrNotFound {
|
||||
pi = NewIndex(id)
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
package profile
|
||||
|
||||
.
|
||||
import "github.com/Safing/portbase/modules"
|
||||
|
||||
var (
|
||||
shutdownSignal = make(chan struct{})
|
||||
)
|
||||
|
||||
func init() {
|
||||
modules.Register("profile", nil, start, stop, "database")
|
||||
}
|
||||
|
||||
func start() error {
|
||||
err := initSpecialProfiles()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return initUpdateListener()
|
||||
}
|
||||
|
||||
func stop() error {
|
||||
close(shutdownSignal)
|
||||
return nil
|
||||
}
|
||||
|
||||
46
profile/ports_test.go
Normal file
46
profile/ports_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPorts(t *testing.T) {
|
||||
var ports Ports
|
||||
ports = map[int16][]*Port{
|
||||
6: []*Port{
|
||||
&Port{ // SSH
|
||||
Permit: true,
|
||||
Created: time.Now().Unix(),
|
||||
Start: 22,
|
||||
End: 22,
|
||||
},
|
||||
},
|
||||
-17: []*Port{
|
||||
&Port{ // HTTP
|
||||
Permit: false,
|
||||
Created: time.Now().Unix(),
|
||||
Start: 80,
|
||||
End: 81,
|
||||
},
|
||||
},
|
||||
93: []*Port{
|
||||
&Port{ // HTTP
|
||||
Permit: true,
|
||||
Created: time.Now().Unix(),
|
||||
Start: 93,
|
||||
End: 93,
|
||||
},
|
||||
},
|
||||
}
|
||||
if ports.String() != "TCP:[permit:22], <UDP:[deny:80-81], 93:[permit:93]" {
|
||||
t.Errorf("unexpected result: %s", ports.String())
|
||||
}
|
||||
|
||||
var noPorts Ports
|
||||
noPorts = map[int16][]*Port{}
|
||||
if noPorts.String() != "None" {
|
||||
t.Errorf("unexpected result: %s", ports.String())
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,8 +37,10 @@ type Profile struct {
|
||||
Domains Domains
|
||||
Ports Ports
|
||||
|
||||
StampProfileKey string
|
||||
StampProfileAssigned int64
|
||||
// User Profile Only
|
||||
CoupledPath string `json:",omitempty"`
|
||||
StampProfileKey string `json:",omitempty"`
|
||||
StampProfileAssigned int64 `json:",omitempty"`
|
||||
|
||||
// If a Profile is declared as a Framework (i.e. an Interpreter and the likes), then the real process must be found
|
||||
// Framework *Framework `json:",omitempty bson:",omitempty"`
|
||||
|
||||
@@ -42,6 +42,8 @@ func NewSet(user, stamp *Profile) *Set {
|
||||
|
||||
// Update gets the new global and default profile and updates the independence status. It must be called when reusing a profile set for a series of calls.
|
||||
func (set *Set) Update(securityLevel uint8) {
|
||||
set.Lock()
|
||||
|
||||
specialProfileLock.RLock()
|
||||
defer specialProfileLock.RUnlock()
|
||||
|
||||
@@ -58,15 +60,36 @@ func (set *Set) Update(securityLevel uint8) {
|
||||
}
|
||||
|
||||
// update independence
|
||||
set.Unlock()
|
||||
if set.CheckFlag(Independent) {
|
||||
set.Lock()
|
||||
set.independent = true
|
||||
set.Unlock()
|
||||
} else {
|
||||
set.Lock()
|
||||
set.independent = false
|
||||
set.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// GetProfileMode returns the active profile mode.
|
||||
func (set *Set) GetProfileMode() uint8 {
|
||||
switch {
|
||||
case set.CheckFlag(Whitelist):
|
||||
return Whitelist
|
||||
case set.CheckFlag(Prompt):
|
||||
return Prompt
|
||||
case set.CheckFlag(Blacklist):
|
||||
return Blacklist
|
||||
default:
|
||||
return Whitelist
|
||||
}
|
||||
}
|
||||
|
||||
// CheckFlag returns whether a given flag is set.
|
||||
func (set *Set) CheckFlag(flag uint8) (active bool) {
|
||||
set.Lock()
|
||||
defer set.Unlock()
|
||||
|
||||
for i, profile := range set.profiles {
|
||||
if i == 2 && set.independent {
|
||||
@@ -86,6 +109,8 @@ func (set *Set) CheckFlag(flag uint8) (active bool) {
|
||||
|
||||
// CheckDomain checks if the given domain is governed in any the lists of domains and returns whether it is permitted.
|
||||
func (set *Set) CheckDomain(domain string) (permit, ok bool) {
|
||||
set.Lock()
|
||||
defer set.Unlock()
|
||||
|
||||
for i, profile := range set.profiles {
|
||||
if i == 2 && set.independent {
|
||||
@@ -105,6 +130,8 @@ func (set *Set) CheckDomain(domain string) (permit, ok bool) {
|
||||
|
||||
// CheckPort checks if the given protocol and port are governed in any the lists of ports and returns whether it is permitted.
|
||||
func (set *Set) CheckPort(listen bool, protocol uint8, port uint16) (permit, ok bool) {
|
||||
set.Lock()
|
||||
defer set.Unlock()
|
||||
|
||||
signedProtocol := int16(protocol)
|
||||
if listen {
|
||||
|
||||
@@ -1,17 +1,167 @@
|
||||
package profile
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Safing/portmaster/status"
|
||||
)
|
||||
|
||||
var (
|
||||
testUserProfile *Profile
|
||||
testStampProfile *Profile
|
||||
)
|
||||
|
||||
func init() {
|
||||
specialProfileLock.Lock()
|
||||
defer specialProfileLock.Unlock()
|
||||
|
||||
globalProfile = makeDefaultGlobalProfile()
|
||||
fallbackProfile = makeDefaultFallbackProfile()
|
||||
|
||||
testUserProfile = &Profile{
|
||||
ID: "unit-test-user",
|
||||
Name: "Unit Test User Profile",
|
||||
SecurityLevel: status.SecurityLevelDynamic,
|
||||
Flags: map[uint8]uint8{
|
||||
Independent: status.SecurityLevelFortress,
|
||||
},
|
||||
Domains: map[string]*DomainDecision{
|
||||
"example.com": &DomainDecision{
|
||||
Permit: true,
|
||||
Created: time.Now().Unix(),
|
||||
IncludeSubdomains: false,
|
||||
},
|
||||
"bad.example.com": &DomainDecision{
|
||||
Permit: false,
|
||||
Created: time.Now().Unix(),
|
||||
IncludeSubdomains: true,
|
||||
},
|
||||
},
|
||||
Ports: map[int16][]*Port{
|
||||
6: []*Port{
|
||||
&Port{
|
||||
Permit: true,
|
||||
Created: time.Now().Unix(),
|
||||
Start: 22000,
|
||||
End: 22000,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testStampProfile = &Profile{
|
||||
ID: "unit-test-stamp",
|
||||
Name: "Unit Test Stamp Profile",
|
||||
SecurityLevel: status.SecurityLevelFortress,
|
||||
Flags: map[uint8]uint8{
|
||||
Internet: status.SecurityLevelsAll,
|
||||
},
|
||||
Domains: map[string]*DomainDecision{
|
||||
"bad2.example.com": &DomainDecision{
|
||||
Permit: false,
|
||||
Created: time.Now().Unix(),
|
||||
IncludeSubdomains: true,
|
||||
},
|
||||
"good.bad.example.com": &DomainDecision{
|
||||
Permit: true,
|
||||
Created: time.Now().Unix(),
|
||||
IncludeSubdomains: false,
|
||||
},
|
||||
},
|
||||
Ports: map[int16][]*Port{
|
||||
6: []*Port{
|
||||
&Port{
|
||||
Permit: false,
|
||||
Created: time.Now().Unix(),
|
||||
Start: 80,
|
||||
End: 80,
|
||||
},
|
||||
},
|
||||
-17: []*Port{
|
||||
&Port{
|
||||
Permit: true,
|
||||
Created: time.Now().Unix(),
|
||||
Start: 12345,
|
||||
End: 12347,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testFlag(t *testing.T, set *Set, flag uint8, shouldBeActive bool) {
|
||||
active := set.CheckFlag(flag)
|
||||
if active != shouldBeActive {
|
||||
t.Errorf("unexpected result: flag %s: permitted=%v, expected=%v", flagNames[flag], active, shouldBeActive)
|
||||
}
|
||||
}
|
||||
|
||||
func testDomain(t *testing.T, set *Set, domain string, shouldBePermitted bool) {
|
||||
permitted, ok := set.CheckDomain(domain)
|
||||
if !ok {
|
||||
t.Errorf("domain %s should be in test profile set", domain)
|
||||
}
|
||||
if permitted != shouldBePermitted {
|
||||
t.Errorf("unexpected result: domain %s: permitted=%v, expected=%v", domain, permitted, shouldBePermitted)
|
||||
}
|
||||
}
|
||||
|
||||
func testUnregulatedDomain(t *testing.T, set *Set, domain string) {
|
||||
_, ok := set.CheckDomain(domain)
|
||||
if ok {
|
||||
t.Errorf("domain %s should not be in test profile set", domain)
|
||||
}
|
||||
}
|
||||
|
||||
func testPort(t *testing.T, set *Set, listen bool, protocol uint8, port uint16, shouldBePermitted bool) {
|
||||
permitted, ok := set.CheckPort(listen, protocol, port)
|
||||
if !ok {
|
||||
t.Errorf("port [%v %d %d] should be in test profile set", listen, protocol, port)
|
||||
}
|
||||
if permitted != shouldBePermitted {
|
||||
t.Errorf("unexpected result: port [%v %d %d]: permitted=%v, expected=%v", listen, protocol, port, permitted, shouldBePermitted)
|
||||
}
|
||||
}
|
||||
|
||||
func testUnregulatedPort(t *testing.T, set *Set, listen bool, protocol uint8, port uint16) {
|
||||
_, ok := set.CheckPort(listen, protocol, port)
|
||||
if ok {
|
||||
t.Errorf("port [%v %d %d] should not be in test profile set", listen, protocol, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProfileSet(t *testing.T) {
|
||||
|
||||
// new := &Set{
|
||||
// profiles: [4]*Profile{
|
||||
// user, // Application
|
||||
// nil, // Global
|
||||
// stamp, // Stamp
|
||||
// nil, // Default
|
||||
// },
|
||||
// }
|
||||
// new.Update(status.SecurityLevelFortress)
|
||||
set := NewSet(testUserProfile, testStampProfile)
|
||||
|
||||
set.Update(status.SecurityLevelDynamic)
|
||||
testFlag(t, set, Whitelist, false)
|
||||
testFlag(t, set, Internet, true)
|
||||
testDomain(t, set, "example.com", true)
|
||||
testDomain(t, set, "bad.example.com", false)
|
||||
testDomain(t, set, "other.bad.example.com", false)
|
||||
testDomain(t, set, "good.bad.example.com", false)
|
||||
testDomain(t, set, "bad2.example.com", false)
|
||||
testPort(t, set, false, 6, 443, true)
|
||||
testPort(t, set, false, 6, 143, true)
|
||||
testPort(t, set, false, 6, 22, true)
|
||||
testPort(t, set, false, 6, 80, false)
|
||||
testPort(t, set, false, 6, 80, false)
|
||||
testPort(t, set, true, 17, 12345, true)
|
||||
testPort(t, set, true, 17, 12346, true)
|
||||
testPort(t, set, true, 17, 12347, true)
|
||||
testUnregulatedDomain(t, set, "other.example.com")
|
||||
testUnregulatedPort(t, set, false, 17, 53)
|
||||
testUnregulatedPort(t, set, false, 17, 443)
|
||||
testUnregulatedPort(t, set, true, 6, 443)
|
||||
|
||||
set.Update(status.SecurityLevelSecure)
|
||||
testFlag(t, set, Internet, true)
|
||||
|
||||
set.Update(status.SecurityLevelFortress) // Independent!
|
||||
testFlag(t, set, Internet, false)
|
||||
testPort(t, set, false, 6, 80, true)
|
||||
testUnregulatedDomain(t, set, "bad2.example.com")
|
||||
testUnregulatedPort(t, set, true, 17, 12346)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Safing/portbase/database"
|
||||
@@ -19,35 +18,41 @@ func initUpdateListener() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
slashedUserNamespace = fmt.Sprintf("/%s/", userNamespace)
|
||||
slashedStampNamespace = fmt.Sprintf("/%s/", stampNamespace)
|
||||
)
|
||||
|
||||
func updateListener(sub *database.Subscription) {
|
||||
for r := range sub.Feed {
|
||||
profile, err := ensureProfile(r)
|
||||
if err != nil {
|
||||
log.Errorf("profile: received update for special profile, but could not read: %s", err)
|
||||
continue
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-shutdownSignal:
|
||||
return
|
||||
case r := <-sub.Feed:
|
||||
|
||||
specialProfileLock.Lock()
|
||||
switch profile.ID {
|
||||
case "global":
|
||||
globalProfile = profile
|
||||
updateActiveGlobalProfile(profile)
|
||||
case "fallback":
|
||||
fallbackProfile = profile
|
||||
updateActiveFallbackProfile(profile)
|
||||
default:
|
||||
switch {
|
||||
case strings.HasPrefix(profile.Key(), makeProfileKey(userNamespace, "")):
|
||||
updateActiveUserProfile(profile)
|
||||
case strings.HasPrefix(profile.Key(), makeProfileKey(stampNamespace, "")):
|
||||
updateActiveStampProfile(profile)
|
||||
if r.Meta().IsDeleted() {
|
||||
continue
|
||||
}
|
||||
|
||||
profile, err := ensureProfile(r)
|
||||
if err != nil {
|
||||
log.Errorf("profile: received update for special profile, but could not read: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
switch profile.ID {
|
||||
case "global":
|
||||
specialProfileLock.Lock()
|
||||
globalProfile = profile
|
||||
specialProfileLock.Unlock()
|
||||
case "fallback":
|
||||
specialProfileLock.Lock()
|
||||
fallbackProfile = profile
|
||||
specialProfileLock.Unlock()
|
||||
default:
|
||||
switch {
|
||||
case strings.HasPrefix(profile.Key(), makeProfileKey(userNamespace, "")):
|
||||
updateActiveUserProfile(profile)
|
||||
case strings.HasPrefix(profile.Key(), makeProfileKey(stampNamespace, "")):
|
||||
updateActiveStampProfile(profile)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
specialProfileLock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user