mirror of
https://github.com/safing/portmaster
synced 2025-09-02 18:49:14 +00:00
Improve status module
This commit is contained in:
parent
e8b5cedc9d
commit
321f3feec5
13 changed files with 342 additions and 107 deletions
|
@ -135,7 +135,7 @@ func EnsureProfile(r record.Record) (*Profile, error) {
|
||||||
// or adjust type
|
// or adjust type
|
||||||
new, ok := r.(*Profile)
|
new, ok := r.(*Profile)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("record not of type *Example, but %T", r)
|
return nil, fmt.Errorf("record not of type *Profile, but %T", r)
|
||||||
}
|
}
|
||||||
return new, nil
|
return new, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ func updateListener(sub *database.Subscription) {
|
||||||
|
|
||||||
profile, err := EnsureProfile(r)
|
profile, err := EnsureProfile(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("profile: received update for special profile, but could not read: %s", err)
|
log.Errorf("profile: received update for profile, but could not read: %s", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
47
status/database.go
Normal file
47
status/database.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package status
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Safing/portbase/database"
|
||||||
|
"github.com/Safing/portbase/database/query"
|
||||||
|
"github.com/Safing/portbase/database/record"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
statusDBKey = "core:status/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
statusDB = database.NewInterface(nil)
|
||||||
|
hook *database.RegisteredHook
|
||||||
|
)
|
||||||
|
|
||||||
|
type statusHook struct {
|
||||||
|
database.HookBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// UsesPrePut implements the Hook interface.
|
||||||
|
func (sh *statusHook) UsesPrePut() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrePut implements the Hook interface.
|
||||||
|
func (sh *statusHook) PrePut(r record.Record) (record.Record, error) {
|
||||||
|
newStatus, err := EnsureSystemStatus(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newStatus.Lock()
|
||||||
|
defer newStatus.Unlock()
|
||||||
|
|
||||||
|
// apply applicable settings
|
||||||
|
setSelectedSecurityLevel(newStatus.SelectedSecurityLevel)
|
||||||
|
// TODO: allow setting of Gate17 status (on/off)
|
||||||
|
|
||||||
|
// return original status
|
||||||
|
return status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initStatusHook() (err error) {
|
||||||
|
hook, err = database.RegisterHook(query.New(statusDBKey), &statusHook{})
|
||||||
|
return err
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ func max(a, b uint8) uint8 {
|
||||||
func ConfigIsActive(name string) SecurityLevelOption {
|
func ConfigIsActive(name string) SecurityLevelOption {
|
||||||
activeAtLevel := config.GetAsInt(name, int64(SecurityLevelDynamic))
|
activeAtLevel := config.GetAsInt(name, int64(SecurityLevelDynamic))
|
||||||
return func(minSecurityLevel uint8) bool {
|
return func(minSecurityLevel uint8) bool {
|
||||||
return uint8(activeAtLevel()) <= max(CurrentSecurityLevel(), minSecurityLevel)
|
return uint8(activeAtLevel()) <= max(ActiveSecurityLevel(), minSecurityLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,6 @@ func ConfigIsActive(name string) SecurityLevelOption {
|
||||||
func ConfigIsActiveConcurrent(name string) SecurityLevelOption {
|
func ConfigIsActiveConcurrent(name string) SecurityLevelOption {
|
||||||
activeAtLevel := config.Concurrent.GetAsInt(name, int64(SecurityLevelDynamic))
|
activeAtLevel := config.Concurrent.GetAsInt(name, int64(SecurityLevelDynamic))
|
||||||
return func(minSecurityLevel uint8) bool {
|
return func(minSecurityLevel uint8) bool {
|
||||||
return uint8(activeAtLevel()) <= max(CurrentSecurityLevel(), minSecurityLevel)
|
return uint8(activeAtLevel()) <= max(ActiveSecurityLevel(), minSecurityLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,32 +5,29 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
currentSecurityLevel *uint32
|
activeSecurityLevel *uint32
|
||||||
selectedSecurityLevel *uint32
|
selectedSecurityLevel *uint32
|
||||||
threatLevel *uint32
|
|
||||||
portmasterStatus *uint32
|
portmasterStatus *uint32
|
||||||
gate17Status *uint32
|
gate17Status *uint32
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var (
|
var (
|
||||||
currentSecurityLevelValue uint32
|
activeSecurityLevelValue uint32
|
||||||
selectedSecurityLevelValue uint32
|
selectedSecurityLevelValue uint32
|
||||||
threatLevelValue uint32
|
|
||||||
portmasterStatusValue uint32
|
portmasterStatusValue uint32
|
||||||
gate17StatusValue uint32
|
gate17StatusValue uint32
|
||||||
)
|
)
|
||||||
|
|
||||||
currentSecurityLevel = ¤tSecurityLevelValue
|
activeSecurityLevel = &activeSecurityLevelValue
|
||||||
selectedSecurityLevel = &selectedSecurityLevelValue
|
selectedSecurityLevel = &selectedSecurityLevelValue
|
||||||
threatLevel = &threatLevelValue
|
|
||||||
portmasterStatus = &portmasterStatusValue
|
portmasterStatus = &portmasterStatusValue
|
||||||
gate17Status = &gate17StatusValue
|
gate17Status = &gate17StatusValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// CurrentSecurityLevel returns the current security level.
|
// ActiveSecurityLevel returns the current security level.
|
||||||
func CurrentSecurityLevel() uint8 {
|
func ActiveSecurityLevel() uint8 {
|
||||||
return uint8(atomic.LoadUint32(currentSecurityLevel))
|
return uint8(atomic.LoadUint32(activeSecurityLevel))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectedSecurityLevel returns the selected security level.
|
// SelectedSecurityLevel returns the selected security level.
|
||||||
|
@ -38,11 +35,6 @@ func SelectedSecurityLevel() uint8 {
|
||||||
return uint8(atomic.LoadUint32(selectedSecurityLevel))
|
return uint8(atomic.LoadUint32(selectedSecurityLevel))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ThreatLevel returns the current threat level.
|
|
||||||
func ThreatLevel() uint8 {
|
|
||||||
return uint8(atomic.LoadUint32(threatLevel))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PortmasterStatus returns the current Portmaster status.
|
// PortmasterStatus returns the current Portmaster status.
|
||||||
func PortmasterStatus() uint8 {
|
func PortmasterStatus() uint8 {
|
||||||
return uint8(atomic.LoadUint32(portmasterStatus))
|
return uint8(atomic.LoadUint32(portmasterStatus))
|
||||||
|
|
|
@ -5,9 +5,9 @@ import "testing"
|
||||||
func TestGet(t *testing.T) {
|
func TestGet(t *testing.T) {
|
||||||
|
|
||||||
// only test for panics
|
// only test for panics
|
||||||
CurrentSecurityLevel()
|
// TODO: write real tests
|
||||||
|
ActiveSecurityLevel()
|
||||||
SelectedSecurityLevel()
|
SelectedSecurityLevel()
|
||||||
ThreatLevel()
|
|
||||||
PortmasterStatus()
|
PortmasterStatus()
|
||||||
Gate17Status()
|
Gate17Status()
|
||||||
option := ConfigIsActive("invalid")
|
option := ConfigIsActive("invalid")
|
||||||
|
|
|
@ -1,25 +1,59 @@
|
||||||
package status
|
package status
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Safing/portbase/database"
|
||||||
"github.com/Safing/portbase/log"
|
"github.com/Safing/portbase/log"
|
||||||
"github.com/Safing/portbase/modules"
|
"github.com/Safing/portbase/modules"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
shutdownSignal = make(chan struct{})
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
modules.Register("status", prep, nil, nil)
|
modules.Register("status", nil, start, stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prep() error {
|
func start() error {
|
||||||
|
var loadedStatus *SystemStatus
|
||||||
|
|
||||||
if CurrentSecurityLevel() == SecurityLevelOff {
|
// load status from database
|
||||||
log.Infof("switching to default active security level: dynamic")
|
r, err := statusDB.Get(statusDBKey)
|
||||||
SetCurrentSecurityLevel(SecurityLevelDynamic)
|
switch err {
|
||||||
|
case nil:
|
||||||
|
loadedStatus, err = EnsureSystemStatus(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Criticalf("status: failed to unwrap system status: %s", err)
|
||||||
|
loadedStatus = nil
|
||||||
|
}
|
||||||
|
case database.ErrNotFound:
|
||||||
|
// create new status
|
||||||
|
default:
|
||||||
|
log.Criticalf("status: failed to load system status: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if SelectedSecurityLevel() == SecurityLevelOff {
|
// activate loaded status, if available
|
||||||
log.Infof("switching to default selected security level: dynamic")
|
if loadedStatus != nil {
|
||||||
SetSelectedSecurityLevel(SecurityLevelDynamic)
|
status = loadedStatus
|
||||||
}
|
}
|
||||||
|
status.Lock()
|
||||||
|
defer status.Unlock()
|
||||||
|
|
||||||
|
// load status into atomic getters
|
||||||
|
atomicUpdateSelectedSecurityLevel(status.SelectedSecurityLevel)
|
||||||
|
atomicUpdatePortmasterStatus(status.PortmasterStatus)
|
||||||
|
atomicUpdateGate17Status(status.Gate17Status)
|
||||||
|
|
||||||
|
// update status
|
||||||
|
status.updateThreatMitigationLevel()
|
||||||
|
status.autopilot()
|
||||||
|
|
||||||
|
go status.Save()
|
||||||
|
|
||||||
|
return initStatusHook()
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop() error {
|
||||||
|
close(shutdownSignal)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
106
status/set.go
106
status/set.go
|
@ -1,61 +1,93 @@
|
||||||
package status
|
package status
|
||||||
|
|
||||||
import "sync/atomic"
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
// SetCurrentSecurityLevel sets the current security level.
|
"github.com/Safing/portbase/log"
|
||||||
func SetCurrentSecurityLevel(level uint8) {
|
)
|
||||||
sysStatusLock.Lock()
|
|
||||||
defer sysStatusLock.Unlock()
|
// autopilot automatically adjusts the security level as needed
|
||||||
sysStatus.CurrentSecurityLevel = level
|
func (s *SystemStatus) autopilot() {
|
||||||
atomicUpdateCurrentSecurityLevel(level)
|
// check if users is overruling
|
||||||
|
if s.SelectedSecurityLevel > SecurityLevelOff {
|
||||||
|
s.ActiveSecurityLevel = s.SelectedSecurityLevel
|
||||||
|
atomicUpdateActiveSecurityLevel(s.SelectedSecurityLevel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// update active security level
|
||||||
|
switch s.ThreatMitigationLevel {
|
||||||
|
case SecurityLevelOff:
|
||||||
|
s.ActiveSecurityLevel = SecurityLevelDynamic
|
||||||
|
atomicUpdateActiveSecurityLevel(SecurityLevelDynamic)
|
||||||
|
case SecurityLevelDynamic, SecurityLevelSecure, SecurityLevelFortress:
|
||||||
|
s.ActiveSecurityLevel = s.ThreatMitigationLevel
|
||||||
|
atomicUpdateActiveSecurityLevel(s.ThreatMitigationLevel)
|
||||||
|
default:
|
||||||
|
log.Errorf("status: threat mitigation level is set to invalid value: %d", s.ThreatMitigationLevel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSelectedSecurityLevel sets the selected security level.
|
// setSelectedSecurityLevel sets the selected security level.
|
||||||
func SetSelectedSecurityLevel(level uint8) {
|
func setSelectedSecurityLevel(level uint8) {
|
||||||
sysStatusLock.Lock()
|
switch level {
|
||||||
defer sysStatusLock.Unlock()
|
case SecurityLevelOff, SecurityLevelDynamic, SecurityLevelSecure, SecurityLevelFortress:
|
||||||
sysStatus.SelectedSecurityLevel = level
|
status.Lock()
|
||||||
atomicUpdateSelectedSecurityLevel(level)
|
defer status.Unlock()
|
||||||
}
|
|
||||||
|
|
||||||
// SetThreatLevel sets the current threat level.
|
status.SelectedSecurityLevel = level
|
||||||
func SetThreatLevel(level uint8) {
|
atomicUpdateSelectedSecurityLevel(level)
|
||||||
sysStatusLock.Lock()
|
status.autopilot()
|
||||||
defer sysStatusLock.Unlock()
|
|
||||||
sysStatus.ThreatLevel = level
|
go status.Save()
|
||||||
atomicUpdateThreatLevel(level)
|
default:
|
||||||
|
log.Errorf("status: tried to set selected security level to invalid value: %d", level)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPortmasterStatus sets the current Portmaster status.
|
// SetPortmasterStatus sets the current Portmaster status.
|
||||||
func SetPortmasterStatus(status uint8) {
|
func SetPortmasterStatus(pmStatus uint8, msg string) {
|
||||||
sysStatusLock.Lock()
|
switch pmStatus {
|
||||||
defer sysStatusLock.Unlock()
|
case StatusOff, StatusError, StatusWarning, StatusOk:
|
||||||
sysStatus.PortmasterStatus = status
|
status.Lock()
|
||||||
atomicUpdatePortmasterStatus(status)
|
defer status.Unlock()
|
||||||
|
|
||||||
|
status.PortmasterStatus = pmStatus
|
||||||
|
status.PortmasterStatusMsg = msg
|
||||||
|
atomicUpdatePortmasterStatus(pmStatus)
|
||||||
|
|
||||||
|
go status.Save()
|
||||||
|
default:
|
||||||
|
log.Errorf("status: tried to set portmaster to invalid status: %d", status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGate17Status sets the current Gate17 status.
|
// SetGate17Status sets the current Gate17 status.
|
||||||
func SetGate17Status(status uint8) {
|
func SetGate17Status(g17Status uint8, msg string) {
|
||||||
sysStatusLock.Lock()
|
switch g17Status {
|
||||||
defer sysStatusLock.Unlock()
|
case StatusOff, StatusError, StatusWarning, StatusOk:
|
||||||
sysStatus.Gate17Status = status
|
status.Lock()
|
||||||
atomicUpdateGate17Status(status)
|
defer status.Unlock()
|
||||||
|
|
||||||
|
status.Gate17Status = g17Status
|
||||||
|
status.Gate17StatusMsg = msg
|
||||||
|
atomicUpdateGate17Status(g17Status)
|
||||||
|
|
||||||
|
go status.Save()
|
||||||
|
default:
|
||||||
|
log.Errorf("status: tried to set gate17 to invalid status: %d", status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update functions for atomic stuff
|
// update functions for atomic stuff
|
||||||
|
func atomicUpdateActiveSecurityLevel(level uint8) {
|
||||||
func atomicUpdateCurrentSecurityLevel(level uint8) {
|
atomic.StoreUint32(activeSecurityLevel, uint32(level))
|
||||||
atomic.StoreUint32(currentSecurityLevel, uint32(level))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func atomicUpdateSelectedSecurityLevel(level uint8) {
|
func atomicUpdateSelectedSecurityLevel(level uint8) {
|
||||||
atomic.StoreUint32(selectedSecurityLevel, uint32(level))
|
atomic.StoreUint32(selectedSecurityLevel, uint32(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
func atomicUpdateThreatLevel(level uint8) {
|
|
||||||
atomic.StoreUint32(threatLevel, uint32(level))
|
|
||||||
}
|
|
||||||
|
|
||||||
func atomicUpdatePortmasterStatus(status uint8) {
|
func atomicUpdatePortmasterStatus(status uint8) {
|
||||||
atomic.StoreUint32(portmasterStatus, uint32(status))
|
atomic.StoreUint32(portmasterStatus, uint32(status))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,9 @@ import "testing"
|
||||||
func TestSet(t *testing.T) {
|
func TestSet(t *testing.T) {
|
||||||
|
|
||||||
// only test for panics
|
// only test for panics
|
||||||
SetCurrentSecurityLevel(0)
|
// TODO: write real tests
|
||||||
SetSelectedSecurityLevel(0)
|
setSelectedSecurityLevel(0)
|
||||||
SetThreatLevel(0)
|
SetPortmasterStatus(0, "")
|
||||||
SetPortmasterStatus(0)
|
SetGate17Status(0, "")
|
||||||
SetGate17Status(0)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,81 @@
|
||||||
package status
|
package status
|
||||||
|
|
||||||
import "sync"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Safing/portbase/database/record"
|
||||||
|
"github.com/Safing/portbase/log"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sysStatus *SystemStatus
|
status *SystemStatus
|
||||||
sysStatusLock sync.RWMutex
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
sysStatus = &SystemStatus{}
|
status = &SystemStatus{
|
||||||
|
Threats: make(map[string]*Threat),
|
||||||
|
}
|
||||||
|
status.SetKey(statusDBKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemStatus saves basic information about the current system status.
|
// SystemStatus saves basic information about the current system status.
|
||||||
type SystemStatus struct {
|
type SystemStatus struct {
|
||||||
// database.Base
|
record.Base
|
||||||
CurrentSecurityLevel uint8
|
sync.Mutex
|
||||||
|
|
||||||
|
ActiveSecurityLevel uint8
|
||||||
SelectedSecurityLevel uint8
|
SelectedSecurityLevel uint8
|
||||||
|
|
||||||
ThreatLevel uint8 `json:",omitempty" bson:",omitempty"`
|
PortmasterStatus uint8
|
||||||
ThreatReason string `json:",omitempty" bson:",omitempty"`
|
PortmasterStatusMsg string
|
||||||
|
|
||||||
PortmasterStatus uint8 `json:",omitempty" bson:",omitempty"`
|
Gate17Status uint8
|
||||||
PortmasterStatusMsg string `json:",omitempty" bson:",omitempty"`
|
Gate17StatusMsg string
|
||||||
|
|
||||||
Gate17Status uint8 `json:",omitempty" bson:",omitempty"`
|
ThreatMitigationLevel uint8
|
||||||
Gate17StatusMsg string `json:",omitempty" bson:",omitempty"`
|
Threats map[string]*Threat
|
||||||
|
|
||||||
|
UpdateStatus string
|
||||||
}
|
}
|
||||||
|
|
||||||
// FmtCurrentSecurityLevel returns the current security level as a string.
|
// Save saves the SystemStatus to the database
|
||||||
func FmtCurrentSecurityLevel() string {
|
func (s *SystemStatus) Save() {
|
||||||
current := CurrentSecurityLevel()
|
err := statusDB.Put(s)
|
||||||
selected := SelectedSecurityLevel()
|
if err != nil {
|
||||||
s := FmtSecurityLevel(current)
|
log.Errorf("status: could not save status to database: %s", err)
|
||||||
if current != selected {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureSystemStatus ensures that the given record is of type SystemStatus and unwraps it, if needed.
|
||||||
|
func EnsureSystemStatus(r record.Record) (*SystemStatus, error) {
|
||||||
|
// unwrap
|
||||||
|
if r.IsWrapped() {
|
||||||
|
// only allocate a new struct, if we need it
|
||||||
|
new := &SystemStatus{}
|
||||||
|
err := record.Unwrap(r, new)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return new, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// or adjust type
|
||||||
|
new, ok := r.(*SystemStatus)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("record not of type *SystemStatus, but %T", r)
|
||||||
|
}
|
||||||
|
return new, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FmtActiveSecurityLevel returns the current security level as a string.
|
||||||
|
func FmtActiveSecurityLevel() string {
|
||||||
|
status.Lock()
|
||||||
|
mitigationLevel := status.ThreatMitigationLevel
|
||||||
|
status.Unlock()
|
||||||
|
active := ActiveSecurityLevel()
|
||||||
|
s := FmtSecurityLevel(active)
|
||||||
|
if mitigationLevel > 0 && active != mitigationLevel {
|
||||||
s += "*"
|
s += "*"
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -4,33 +4,31 @@ import "testing"
|
||||||
|
|
||||||
func TestStatus(t *testing.T) {
|
func TestStatus(t *testing.T) {
|
||||||
|
|
||||||
SetCurrentSecurityLevel(SecurityLevelOff)
|
setSelectedSecurityLevel(SecurityLevelOff)
|
||||||
SetSelectedSecurityLevel(SecurityLevelOff)
|
if FmtActiveSecurityLevel() != "Dynamic" {
|
||||||
if FmtCurrentSecurityLevel() != "Off" {
|
t.Errorf("unexpected string representation: %s", FmtActiveSecurityLevel())
|
||||||
t.Error("unexpected string representation")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurrentSecurityLevel(SecurityLevelDynamic)
|
setSelectedSecurityLevel(SecurityLevelDynamic)
|
||||||
SetSelectedSecurityLevel(SecurityLevelDynamic)
|
AddOrUpdateThreat(&Threat{MitigationLevel: SecurityLevelSecure})
|
||||||
if FmtCurrentSecurityLevel() != "Dynamic" {
|
if FmtActiveSecurityLevel() != "Dynamic*" {
|
||||||
t.Error("unexpected string representation")
|
t.Errorf("unexpected string representation: %s", FmtActiveSecurityLevel())
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurrentSecurityLevel(SecurityLevelSecure)
|
setSelectedSecurityLevel(SecurityLevelSecure)
|
||||||
SetSelectedSecurityLevel(SecurityLevelSecure)
|
if FmtActiveSecurityLevel() != "Secure" {
|
||||||
if FmtCurrentSecurityLevel() != "Secure" {
|
t.Errorf("unexpected string representation: %s", FmtActiveSecurityLevel())
|
||||||
t.Error("unexpected string representation")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurrentSecurityLevel(SecurityLevelFortress)
|
setSelectedSecurityLevel(SecurityLevelSecure)
|
||||||
SetSelectedSecurityLevel(SecurityLevelFortress)
|
AddOrUpdateThreat(&Threat{MitigationLevel: SecurityLevelFortress})
|
||||||
if FmtCurrentSecurityLevel() != "Fortress" {
|
if FmtActiveSecurityLevel() != "Secure*" {
|
||||||
t.Error("unexpected string representation")
|
t.Errorf("unexpected string representation: %s", FmtActiveSecurityLevel())
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSelectedSecurityLevel(SecurityLevelDynamic)
|
setSelectedSecurityLevel(SecurityLevelFortress)
|
||||||
if FmtCurrentSecurityLevel() != "Fortress*" {
|
if FmtActiveSecurityLevel() != "Fortress" {
|
||||||
t.Error("unexpected string representation")
|
t.Errorf("unexpected string representation: %s", FmtActiveSecurityLevel())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
72
status/threat.go
Normal file
72
status/threat.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package status
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Threat describes a detected threat.
|
||||||
|
type Threat struct {
|
||||||
|
ID string // A unique ID chosen by reporting module (eg. modulePrefix-incident) to periodically check threat existence
|
||||||
|
Name string // Descriptive (human readable) name for detected threat
|
||||||
|
Description string // Simple description
|
||||||
|
AdditionalData interface{} // Additional data a module wants to make available for the user
|
||||||
|
MitigationLevel uint8 // Recommended Security Level to switch to for mitigation
|
||||||
|
Started int64
|
||||||
|
Ended int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddOrUpdateThreat adds or updates a new threat in the system status.
|
||||||
|
func AddOrUpdateThreat(new *Threat) {
|
||||||
|
status.Lock()
|
||||||
|
defer status.Unlock()
|
||||||
|
|
||||||
|
status.Threats[new.ID] = new
|
||||||
|
status.updateThreatMitigationLevel()
|
||||||
|
status.autopilot()
|
||||||
|
|
||||||
|
go status.Save()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteThreat deletes a threat from the system status.
|
||||||
|
func DeleteThreat(id string) {
|
||||||
|
status.Lock()
|
||||||
|
defer status.Unlock()
|
||||||
|
|
||||||
|
delete(status.Threats, id)
|
||||||
|
status.updateThreatMitigationLevel()
|
||||||
|
status.autopilot()
|
||||||
|
|
||||||
|
go status.Save()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetThreats returns all threats who's IDs are prefixed by the given string, and also a locker for editing them.
|
||||||
|
func GetThreats(idPrefix string) ([]*Threat, sync.Locker) {
|
||||||
|
status.Lock()
|
||||||
|
defer status.Unlock()
|
||||||
|
|
||||||
|
var exportedThreats []*Threat
|
||||||
|
for id, threat := range status.Threats {
|
||||||
|
if strings.HasPrefix(id, idPrefix) {
|
||||||
|
exportedThreats = append(exportedThreats, threat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exportedThreats, &status.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SystemStatus) updateThreatMitigationLevel() {
|
||||||
|
// get highest mitigationLevel
|
||||||
|
var mitigationLevel uint8
|
||||||
|
for _, threat := range s.Threats {
|
||||||
|
switch threat.MitigationLevel {
|
||||||
|
case SecurityLevelDynamic, SecurityLevelSecure, SecurityLevelFortress:
|
||||||
|
if threat.MitigationLevel > mitigationLevel {
|
||||||
|
mitigationLevel = threat.MitigationLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new ThreatMitigationLevel
|
||||||
|
s.ThreatMitigationLevel = mitigationLevel
|
||||||
|
}
|
18
status/updates.go
Normal file
18
status/updates.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package status
|
||||||
|
|
||||||
|
// Update status options
|
||||||
|
const (
|
||||||
|
UpdateStatusCurrentStable = "stable"
|
||||||
|
UpdateStatusCurrentBeta = "beta"
|
||||||
|
UpdateStatusAvailable = "available" // restart or reboot required
|
||||||
|
UpdateStatusFailed = "failed" // check logs
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetUpdateStatus updates the system status with a new update status.
|
||||||
|
func SetUpdateStatus(newStatus string) {
|
||||||
|
status.Lock()
|
||||||
|
status.UpdateStatus = newStatus
|
||||||
|
status.Unlock()
|
||||||
|
|
||||||
|
go status.Save()
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue