init bootstrap
This commit is contained in:
367
local/model/security_event.go
Normal file
367
local/model/security_event.go
Normal file
@@ -0,0 +1,367 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// SecurityEvent represents a security event in the system
|
||||
type SecurityEvent struct {
|
||||
BaseModel
|
||||
EventType string `json:"eventType" gorm:"not null;type:varchar(100);index"`
|
||||
Severity string `json:"severity" gorm:"not null;type:varchar(20);index"`
|
||||
UserID string `json:"userId" gorm:"type:varchar(36);index"`
|
||||
IPAddress string `json:"ipAddress" gorm:"type:varchar(45);index"`
|
||||
UserAgent string `json:"userAgent" gorm:"type:text"`
|
||||
Resource string `json:"resource" gorm:"type:varchar(100)"`
|
||||
Action string `json:"action" gorm:"type:varchar(100)"`
|
||||
Success bool `json:"success" gorm:"index"`
|
||||
Blocked bool `json:"blocked" gorm:"default:false;index"`
|
||||
Message string `json:"message" gorm:"type:text"`
|
||||
Details map[string]interface{} `json:"details" gorm:"type:text"`
|
||||
SessionID string `json:"sessionId,omitempty" gorm:"type:varchar(255)"`
|
||||
RequestID string `json:"requestId,omitempty" gorm:"type:varchar(255)"`
|
||||
CountryCode string `json:"countryCode,omitempty" gorm:"type:varchar(2)"`
|
||||
City string `json:"city,omitempty" gorm:"type:varchar(100)"`
|
||||
Resolved bool `json:"resolved" gorm:"default:false;index"`
|
||||
ResolvedBy string `json:"resolvedBy,omitempty" gorm:"type:varchar(36)"`
|
||||
ResolvedAt *time.Time `json:"resolvedAt,omitempty"`
|
||||
Notes string `json:"notes,omitempty" gorm:"type:text"`
|
||||
User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
|
||||
Resolver *User `json:"resolver,omitempty" gorm:"foreignKey:ResolvedBy"`
|
||||
}
|
||||
|
||||
// SecurityEventCreateRequest represents the request to create a new security event
|
||||
type SecurityEventCreateRequest struct {
|
||||
EventType string `json:"eventType" validate:"required,max=100"`
|
||||
Severity string `json:"severity" validate:"required,oneof=low medium high critical"`
|
||||
UserID string `json:"userId"`
|
||||
IPAddress string `json:"ipAddress" validate:"max=45"`
|
||||
UserAgent string `json:"userAgent"`
|
||||
Resource string `json:"resource" validate:"max=100"`
|
||||
Action string `json:"action" validate:"max=100"`
|
||||
Success bool `json:"success"`
|
||||
Blocked bool `json:"blocked"`
|
||||
Message string `json:"message" validate:"required"`
|
||||
Details map[string]interface{} `json:"details"`
|
||||
SessionID string `json:"sessionId"`
|
||||
RequestID string `json:"requestId"`
|
||||
CountryCode string `json:"countryCode" validate:"max=2"`
|
||||
City string `json:"city" validate:"max=100"`
|
||||
}
|
||||
|
||||
// SecurityEventUpdateRequest represents the request to update a security event
|
||||
type SecurityEventUpdateRequest struct {
|
||||
Resolved *bool `json:"resolved,omitempty"`
|
||||
ResolvedBy *string `json:"resolvedBy,omitempty"`
|
||||
Notes *string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
// SecurityEventInfo represents public security event information
|
||||
type SecurityEventInfo struct {
|
||||
ID string `json:"id"`
|
||||
EventType string `json:"eventType"`
|
||||
Severity string `json:"severity"`
|
||||
UserID string `json:"userId"`
|
||||
UserEmail string `json:"userEmail,omitempty"`
|
||||
UserName string `json:"userName,omitempty"`
|
||||
IPAddress string `json:"ipAddress"`
|
||||
UserAgent string `json:"userAgent"`
|
||||
Resource string `json:"resource"`
|
||||
Action string `json:"action"`
|
||||
Success bool `json:"success"`
|
||||
Blocked bool `json:"blocked"`
|
||||
Message string `json:"message"`
|
||||
Details map[string]interface{} `json:"details"`
|
||||
SessionID string `json:"sessionId,omitempty"`
|
||||
RequestID string `json:"requestId,omitempty"`
|
||||
CountryCode string `json:"countryCode,omitempty"`
|
||||
City string `json:"city,omitempty"`
|
||||
Resolved bool `json:"resolved"`
|
||||
ResolvedBy string `json:"resolvedBy,omitempty"`
|
||||
ResolverEmail string `json:"resolverEmail,omitempty"`
|
||||
ResolverName string `json:"resolverName,omitempty"`
|
||||
ResolvedAt *time.Time `json:"resolvedAt,omitempty"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
DateCreated string `json:"dateCreated"`
|
||||
}
|
||||
|
||||
// BeforeCreate is called before creating a security event
|
||||
func (se *SecurityEvent) BeforeCreate(tx *gorm.DB) error {
|
||||
se.BaseModel.BeforeCreate()
|
||||
|
||||
// Normalize fields
|
||||
se.EventType = strings.ToLower(strings.TrimSpace(se.EventType))
|
||||
se.Severity = strings.ToLower(strings.TrimSpace(se.Severity))
|
||||
se.IPAddress = strings.TrimSpace(se.IPAddress)
|
||||
se.UserAgent = strings.TrimSpace(se.UserAgent)
|
||||
se.Resource = strings.ToLower(strings.TrimSpace(se.Resource))
|
||||
se.Action = strings.ToLower(strings.TrimSpace(se.Action))
|
||||
se.Message = strings.TrimSpace(se.Message)
|
||||
|
||||
return se.Validate()
|
||||
}
|
||||
|
||||
// BeforeUpdate is called before updating a security event
|
||||
func (se *SecurityEvent) BeforeUpdate(tx *gorm.DB) error {
|
||||
se.BaseModel.BeforeUpdate()
|
||||
|
||||
// If resolving the event, set resolved timestamp
|
||||
if se.Resolved && se.ResolvedAt == nil {
|
||||
now := time.Now()
|
||||
se.ResolvedAt = &now
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate validates security event data
|
||||
func (se *SecurityEvent) Validate() error {
|
||||
validSeverities := []string{"low", "medium", "high", "critical"}
|
||||
isValidSeverity := false
|
||||
for _, severity := range validSeverities {
|
||||
if se.Severity == severity {
|
||||
isValidSeverity = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isValidSeverity {
|
||||
return gorm.ErrInvalidValue
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDetails sets the details field from a map
|
||||
func (se *SecurityEvent) SetDetails(details map[string]interface{}) error {
|
||||
se.Details = details
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDetails returns the details as a map
|
||||
func (se *SecurityEvent) GetDetails() map[string]interface{} {
|
||||
if se.Details == nil {
|
||||
return make(map[string]interface{})
|
||||
}
|
||||
return se.Details
|
||||
}
|
||||
|
||||
// SetDetailsFromJSON sets the details field from a JSON string
|
||||
func (se *SecurityEvent) SetDetailsFromJSON(jsonStr string) error {
|
||||
if jsonStr == "" {
|
||||
se.Details = make(map[string]interface{})
|
||||
return nil
|
||||
}
|
||||
|
||||
var details map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(jsonStr), &details); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
se.Details = details
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDetailsAsJSON returns the details as a JSON string
|
||||
func (se *SecurityEvent) GetDetailsAsJSON() (string, error) {
|
||||
if se.Details == nil || len(se.Details) == 0 {
|
||||
return "{}", nil
|
||||
}
|
||||
|
||||
bytes, err := json.Marshal(se.Details)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// ToSecurityEventInfo converts SecurityEvent to SecurityEventInfo (public information)
|
||||
func (se *SecurityEvent) ToSecurityEventInfo() SecurityEventInfo {
|
||||
info := SecurityEventInfo{
|
||||
ID: se.ID,
|
||||
EventType: se.EventType,
|
||||
Severity: se.Severity,
|
||||
UserID: se.UserID,
|
||||
IPAddress: se.IPAddress,
|
||||
UserAgent: se.UserAgent,
|
||||
Resource: se.Resource,
|
||||
Action: se.Action,
|
||||
Success: se.Success,
|
||||
Blocked: se.Blocked,
|
||||
Message: se.Message,
|
||||
Details: se.GetDetails(),
|
||||
SessionID: se.SessionID,
|
||||
RequestID: se.RequestID,
|
||||
CountryCode: se.CountryCode,
|
||||
City: se.City,
|
||||
Resolved: se.Resolved,
|
||||
ResolvedBy: se.ResolvedBy,
|
||||
ResolvedAt: se.ResolvedAt,
|
||||
Notes: se.Notes,
|
||||
DateCreated: se.DateCreated.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
|
||||
// Include user information if available
|
||||
if se.User != nil {
|
||||
info.UserEmail = se.User.Email
|
||||
info.UserName = se.User.Name
|
||||
}
|
||||
|
||||
// Include resolver information if available
|
||||
if se.Resolver != nil {
|
||||
info.ResolverEmail = se.Resolver.Email
|
||||
info.ResolverName = se.Resolver.Name
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// AddDetail adds a single detail to the details map
|
||||
func (se *SecurityEvent) AddDetail(key string, value interface{}) {
|
||||
if se.Details == nil {
|
||||
se.Details = make(map[string]interface{})
|
||||
}
|
||||
se.Details[key] = value
|
||||
}
|
||||
|
||||
// GetDetail gets a single detail from the details map
|
||||
func (se *SecurityEvent) GetDetail(key string) (interface{}, bool) {
|
||||
if se.Details == nil {
|
||||
return nil, false
|
||||
}
|
||||
value, exists := se.Details[key]
|
||||
return value, exists
|
||||
}
|
||||
|
||||
// Resolve resolves the security event
|
||||
func (se *SecurityEvent) Resolve(resolverID, notes string) {
|
||||
se.Resolved = true
|
||||
se.ResolvedBy = resolverID
|
||||
se.Notes = notes
|
||||
now := time.Now()
|
||||
se.ResolvedAt = &now
|
||||
}
|
||||
|
||||
// Unresolve unresolves the security event
|
||||
func (se *SecurityEvent) Unresolve() {
|
||||
se.Resolved = false
|
||||
se.ResolvedBy = ""
|
||||
se.ResolvedAt = nil
|
||||
}
|
||||
|
||||
// IsResolved returns whether the security event is resolved
|
||||
func (se *SecurityEvent) IsResolved() bool {
|
||||
return se.Resolved
|
||||
}
|
||||
|
||||
// IsCritical returns whether the security event is critical
|
||||
func (se *SecurityEvent) IsCritical() bool {
|
||||
return se.Severity == SecuritySeverityCritical
|
||||
}
|
||||
|
||||
// IsHigh returns whether the security event is high severity
|
||||
func (se *SecurityEvent) IsHigh() bool {
|
||||
return se.Severity == SecuritySeverityHigh
|
||||
}
|
||||
|
||||
// IsBlocked returns whether the security event was blocked
|
||||
func (se *SecurityEvent) IsBlocked() bool {
|
||||
return se.Blocked
|
||||
}
|
||||
|
||||
// Security event types
|
||||
const (
|
||||
SecurityEventLoginAttempt = "login_attempt"
|
||||
SecurityEventLoginFailure = "login_failure"
|
||||
SecurityEventLoginSuccess = "login_success"
|
||||
SecurityEventBruteForce = "brute_force"
|
||||
SecurityEventAccountLockout = "account_lockout"
|
||||
SecurityEventUnauthorizedAccess = "unauthorized_access"
|
||||
SecurityEventPrivilegeEscalation = "privilege_escalation"
|
||||
SecurityEventSuspiciousActivity = "suspicious_activity"
|
||||
SecurityEventRateLimitExceeded = "rate_limit_exceeded"
|
||||
SecurityEventInvalidToken = "invalid_token"
|
||||
SecurityEventTokenExpired = "token_expired"
|
||||
SecurityEventPasswordChange = "password_change"
|
||||
SecurityEventEmailVerification = "email_verification"
|
||||
SecurityEventTwoFactorAuth = "two_factor_auth"
|
||||
SecurityEventDataExfiltration = "data_exfiltration"
|
||||
SecurityEventMaliciousRequest = "malicious_request"
|
||||
SecurityEventSystemAccess = "system_access"
|
||||
SecurityEventConfigChange = "config_change"
|
||||
SecurityEventFileAccess = "file_access"
|
||||
SecurityEventDatabaseAccess = "database_access"
|
||||
)
|
||||
|
||||
// Security severity levels
|
||||
const (
|
||||
SecuritySeverityLow = "low"
|
||||
SecuritySeverityMedium = "medium"
|
||||
SecuritySeverityHigh = "high"
|
||||
SecuritySeverityCritical = "critical"
|
||||
)
|
||||
|
||||
// CreateSecurityEvent creates a new security event
|
||||
func CreateSecurityEvent(eventType, severity, message string) *SecurityEvent {
|
||||
event := &SecurityEvent{
|
||||
EventType: eventType,
|
||||
Severity: severity,
|
||||
Message: message,
|
||||
Details: make(map[string]interface{}),
|
||||
}
|
||||
event.Init()
|
||||
return event
|
||||
}
|
||||
|
||||
// CreateSecurityEventWithUser creates a new security event with user information
|
||||
func CreateSecurityEventWithUser(eventType, severity, message, userID string) *SecurityEvent {
|
||||
event := CreateSecurityEvent(eventType, severity, message)
|
||||
event.UserID = userID
|
||||
return event
|
||||
}
|
||||
|
||||
// CreateSecurityEventWithDetails creates a new security event with details
|
||||
func CreateSecurityEventWithDetails(eventType, severity, message string, details map[string]interface{}) *SecurityEvent {
|
||||
event := CreateSecurityEvent(eventType, severity, message)
|
||||
event.Details = details
|
||||
return event
|
||||
}
|
||||
|
||||
// SetRequestInfo sets request-related information
|
||||
func (se *SecurityEvent) SetRequestInfo(ipAddress, userAgent, sessionID, requestID string) {
|
||||
se.IPAddress = ipAddress
|
||||
se.UserAgent = userAgent
|
||||
se.SessionID = sessionID
|
||||
se.RequestID = requestID
|
||||
}
|
||||
|
||||
// SetLocationInfo sets location-related information
|
||||
func (se *SecurityEvent) SetLocationInfo(countryCode, city string) {
|
||||
se.CountryCode = countryCode
|
||||
se.City = city
|
||||
}
|
||||
|
||||
// SetResourceAction sets resource and action information
|
||||
func (se *SecurityEvent) SetResourceAction(resource, action string) {
|
||||
se.Resource = resource
|
||||
se.Action = action
|
||||
}
|
||||
|
||||
// MarkAsBlocked marks the security event as blocked
|
||||
func (se *SecurityEvent) MarkAsBlocked() {
|
||||
se.Blocked = true
|
||||
}
|
||||
|
||||
// MarkAsSuccess marks the security event as successful
|
||||
func (se *SecurityEvent) MarkAsSuccess() {
|
||||
se.Success = true
|
||||
}
|
||||
|
||||
// MarkAsFailure marks the security event as failed
|
||||
func (se *SecurityEvent) MarkAsFailure() {
|
||||
se.Success = false
|
||||
}
|
||||
Reference in New Issue
Block a user