Refactor status package to use portbase/runtime.
Refactor the status package to use portbase/runtime and make system status readonly. Also adapts the code base to the new portbase/notifications package.
This commit is contained in:
162
status/threat.go
162
status/threat.go
@@ -1,73 +1,131 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/safing/portbase/log"
|
||||
"github.com/safing/portbase/notifications"
|
||||
)
|
||||
|
||||
// Threat describes a detected threat.
|
||||
// Threat represents a threat to the system.
|
||||
// A threat is basically a notification with strong
|
||||
// typed EventData. Use the methods expored on Threat
|
||||
// to manipulate the EventData field and push updates
|
||||
// of the notification.
|
||||
// Do not use EventData directly!
|
||||
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
|
||||
// TODO: add locking
|
||||
*notifications.Notification
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
status.SaveAsync()
|
||||
// ThreatPayload holds threat related information.
|
||||
type ThreatPayload struct {
|
||||
// MitigationLevel holds the recommended security
|
||||
// level to mitigate the threat.
|
||||
MitigationLevel uint8
|
||||
// Started holds the UNIX epoch timestamp in seconds
|
||||
// at which the threat has been detected the first time.
|
||||
Started int64
|
||||
// Ended holds the UNIX epoch timestamp in seconds
|
||||
// at which the threat has been detected the last time.
|
||||
Ended int64
|
||||
// Data may holds threat-specific data.
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
// DeleteThreat deletes a threat from the system status.
|
||||
func DeleteThreat(id string) {
|
||||
status.Lock()
|
||||
defer status.Unlock()
|
||||
// NewThreat returns a new threat. Note that the
|
||||
// threat only gets published once Publish is called.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// threat := NewThreat("portscan", "Someone is scanning you").
|
||||
// SetData(portscanResult).
|
||||
// SetMitigationLevel(SecurityLevelExtreme).
|
||||
// Publish()
|
||||
//
|
||||
// // Once you're done, delete the threat
|
||||
// threat.Delete().Publish()
|
||||
//
|
||||
func NewThreat(id, msg string) *Threat {
|
||||
t := &Threat{
|
||||
Notification: ¬ifications.Notification{
|
||||
EventID: id,
|
||||
Message: msg,
|
||||
Type: notifications.Warning,
|
||||
State: notifications.Active,
|
||||
},
|
||||
}
|
||||
t.threatData().Started = time.Now().Unix()
|
||||
|
||||
delete(status.Threats, id)
|
||||
status.updateThreatMitigationLevel()
|
||||
status.autopilot()
|
||||
|
||||
status.SaveAsync()
|
||||
return t
|
||||
}
|
||||
|
||||
// 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()
|
||||
// SetData sets the data member of the threat payload.
|
||||
func (t *Threat) SetData(data interface{}) *Threat {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
var exportedThreats []*Threat
|
||||
for id, threat := range status.Threats {
|
||||
if strings.HasPrefix(id, idPrefix) {
|
||||
exportedThreats = append(exportedThreats, threat)
|
||||
}
|
||||
t.threatData().Data = data
|
||||
return t
|
||||
}
|
||||
|
||||
// SetMitigationLevel sets the mitigation level of the
|
||||
// threat data.
|
||||
func (t *Threat) SetMitigationLevel(lvl uint8) *Threat {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
t.threatData().MitigationLevel = lvl
|
||||
return t
|
||||
}
|
||||
|
||||
// Delete sets the ended timestamp of the threat.
|
||||
func (t *Threat) Delete() *Threat {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
t.threatData().Ended = time.Now().Unix()
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// Payload returns a copy of the threat payload.
|
||||
func (t *Threat) Payload() ThreatPayload {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
return *t.threatData() // creates a copy
|
||||
}
|
||||
|
||||
// Publish publishes the current threat.
|
||||
// Publish should always be called when changes to
|
||||
// the threat are recorded.
|
||||
func (t *Threat) Publish() *Threat {
|
||||
data := t.Payload()
|
||||
if data.Ended > 0 {
|
||||
DeleteMitigationLevel(t.EventID)
|
||||
} else {
|
||||
SetMitigationLevel(t.EventID, data.MitigationLevel)
|
||||
}
|
||||
|
||||
return exportedThreats, &status.Mutex
|
||||
t.Save()
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func (s *SystemStatus) updateThreatMitigationLevel() {
|
||||
// get highest mitigationLevel
|
||||
var mitigationLevel uint8
|
||||
for _, threat := range s.Threats {
|
||||
switch threat.MitigationLevel {
|
||||
case SecurityLevelNormal, SecurityLevelHigh, SecurityLevelExtreme:
|
||||
if threat.MitigationLevel > mitigationLevel {
|
||||
mitigationLevel = threat.MitigationLevel
|
||||
}
|
||||
}
|
||||
// threatData returns the threat payload associated with this
|
||||
// threat. If not data has been created yet a new ThreatPayload
|
||||
// is attached to t and returned. The caller must make sure to
|
||||
// hold appropriate locks when working with the returned payload.
|
||||
func (t *Threat) threatData() *ThreatPayload {
|
||||
if t.EventData == nil {
|
||||
t.EventData = new(ThreatPayload)
|
||||
}
|
||||
|
||||
// set new ThreatMitigationLevel
|
||||
s.ThreatMitigationLevel = mitigationLevel
|
||||
payload, ok := t.EventData.(*ThreatPayload)
|
||||
if !ok {
|
||||
log.Warningf("unexpected type %T in thread notification payload", t.EventData)
|
||||
return new(ThreatPayload)
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user