A program bans an address (every port, or a protocol's ports) for a time; the ban list says what it is kept from: the firewall, some hosts behind it, or everything. Bans drop ahead of every rule, close the address's connections, group IPv6 by /64, are kept in the database across restarts and audited. Never banned: the inside, the firewall's own addresses, the caller, the list's never. bans grant (bans:write:LIST), hc banlist/bans/ban/unban, Traffic -> Bans, a fail2ban action in contrib/, and failed logins and refused tokens logged for Guard and fail2ban. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
135 lines
4.4 KiB
Go
135 lines
4.4 KiB
Go
package model
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
// Grant gives access to one resource (see internal/auth).
|
|
type Grant struct {
|
|
Resource string `json:"resource"` // config, sets, bans, log, audit, *
|
|
Access string `json:"access"` // read or write (write implies read)
|
|
// Sets limits a "sets" grant to these dynamic sets, and a "bans"
|
|
// grant to these ban lists (none: all).
|
|
Sets []string `json:"sets,omitempty"`
|
|
}
|
|
|
|
// User is a person or a service account.
|
|
type User struct {
|
|
ID int64 `json:"id"`
|
|
Username string `json:"username"`
|
|
PasswordHash string `json:"-"`
|
|
HasPassword bool `json:"has_password"`
|
|
Admin bool `json:"admin"`
|
|
Grants []Grant `json:"grants"`
|
|
Disabled bool `json:"disabled"`
|
|
Comment string `json:"comment"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
LastLoginAt *time.Time `json:"last_login_at,omitempty"`
|
|
}
|
|
|
|
// Token is an API token. The secret is shown once, when it is made; only
|
|
// its hash is stored.
|
|
type Token struct {
|
|
ID int64 `json:"id"`
|
|
UserID int64 `json:"user_id"`
|
|
Username string `json:"username,omitempty"`
|
|
Name string `json:"name"`
|
|
PublicID string `json:"public_id"`
|
|
SecretHash string `json:"-"`
|
|
// Grants restrict the token to part of its user's permissions; nil
|
|
// means all of them.
|
|
Grants []Grant `json:"grants"`
|
|
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
|
|
LastUsedIP string `json:"last_used_ip,omitempty"`
|
|
RevokedAt *time.Time `json:"revoked_at,omitempty"`
|
|
// RotatedAt is when the token last got a new secret (nil: never).
|
|
RotatedAt *time.Time `json:"rotated_at,omitempty"`
|
|
// After a rotation with a grace period, the previous secret keeps
|
|
// working until PrevExpiresAt.
|
|
PrevSecretHash string `json:"-"`
|
|
PrevExpiresAt *time.Time `json:"previous_secret_valid_until,omitempty"`
|
|
}
|
|
|
|
// IssuedAt is when the token's current secret was made: its last
|
|
// rotation, or its creation.
|
|
func (t *Token) IssuedAt() time.Time {
|
|
if t.RotatedAt != nil {
|
|
return *t.RotatedAt
|
|
}
|
|
return t.CreatedAt
|
|
}
|
|
|
|
// Session is a web UI login.
|
|
type Session struct {
|
|
IDHash string `json:"-"`
|
|
UserID int64 `json:"user_id"`
|
|
CSRFToken string `json:"-"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
ExpiresAt time.Time `json:"expires_at"`
|
|
LastSeenAt time.Time `json:"last_seen_at"`
|
|
IP string `json:"ip"`
|
|
UserAgent string `json:"user_agent"`
|
|
}
|
|
|
|
// AuditEvent records an action: logins, users and tokens, changes,
|
|
// dynamic set entries.
|
|
type AuditEvent struct {
|
|
ID int64 `json:"id"`
|
|
Time time.Time `json:"time"`
|
|
UserID int64 `json:"user_id,omitempty"`
|
|
Username string `json:"username,omitempty"`
|
|
Auth string `json:"auth,omitempty"` // session, token, socket
|
|
TokenID int64 `json:"token_id,omitempty"`
|
|
IP string `json:"ip,omitempty"`
|
|
Action string `json:"action"`
|
|
Object string `json:"object,omitempty"`
|
|
Result string `json:"result"` // success, failure, denied
|
|
Detail string `json:"detail,omitempty"`
|
|
}
|
|
|
|
// Change is one object's change: Before is nil for a create, After is nil
|
|
// for a delete. Settings have ID 0.
|
|
type Change struct {
|
|
Kind string `json:"kind"`
|
|
ID int64 `json:"id"`
|
|
Label string `json:"label"`
|
|
Before json.RawMessage `json:"before,omitempty"`
|
|
After json.RawMessage `json:"after,omitempty"`
|
|
}
|
|
|
|
// Action describes a change in a word.
|
|
func (c Change) Action() string {
|
|
switch {
|
|
case c.Before == nil:
|
|
return "create"
|
|
case c.After == nil:
|
|
return "delete"
|
|
}
|
|
return "update"
|
|
}
|
|
|
|
// Inverse is the change that undoes c.
|
|
func (c Change) Inverse() Change {
|
|
c.Before, c.After = c.After, c.Before
|
|
return c
|
|
}
|
|
|
|
// HistoryEntry is a saved configuration change.
|
|
type HistoryEntry struct {
|
|
ID int64 `json:"id"`
|
|
Time time.Time `json:"time"`
|
|
UserID int64 `json:"user_id,omitempty"`
|
|
Username string `json:"username"`
|
|
Via string `json:"via"` // web, cli, api
|
|
Description string `json:"description"`
|
|
Changes []Change `json:"changes"`
|
|
// RevertOf is the entry this one undid; RevertedBy the entry that
|
|
// undid this one.
|
|
RevertOf int64 `json:"revert_of,omitempty"`
|
|
RevertedBy int64 `json:"reverted_by,omitempty"`
|
|
}
|