WIP: Save current state - security subsystems, migrations, logging

This commit is contained in:
Fimeg
2025-12-16 14:19:59 -05:00
parent f792ab23c7
commit f7c8d23c5d
89 changed files with 8884 additions and 1394 deletions

View File

@@ -22,9 +22,9 @@ func NewCommandQueries(db *sqlx.DB) *CommandQueries {
func (q *CommandQueries) CreateCommand(cmd *models.AgentCommand) error {
query := `
INSERT INTO agent_commands (
id, agent_id, command_type, params, status, source, retried_from_id
id, agent_id, command_type, params, status, source, signature, retried_from_id
) VALUES (
:id, :agent_id, :command_type, :params, :status, :source, :retried_from_id
:id, :agent_id, :command_type, :params, :status, :source, :signature, :retried_from_id
)
`
_, err := q.db.NamedExec(query, cmd)
@@ -200,6 +200,7 @@ func (q *CommandQueries) GetActiveCommands() ([]models.ActiveCommandInfo, error)
c.params,
c.status,
c.source,
c.signature,
c.created_at,
c.sent_at,
c.result,
@@ -262,6 +263,7 @@ func (q *CommandQueries) GetRecentCommands(limit int) ([]models.ActiveCommandInf
c.command_type,
c.status,
c.source,
c.signature,
c.created_at,
c.sent_at,
c.completed_at,

View File

@@ -116,7 +116,7 @@ func (q *RegistrationTokenQueries) MarkTokenUsed(token string, agentID uuid.UUID
return nil
}
// GetActiveRegistrationTokens returns all active tokens
// GetActiveRegistrationTokens returns all active tokens that haven't expired
func (q *RegistrationTokenQueries) GetActiveRegistrationTokens() ([]RegistrationToken, error) {
var tokens []RegistrationToken
query := `
@@ -124,7 +124,7 @@ func (q *RegistrationTokenQueries) GetActiveRegistrationTokens() ([]Registration
revoked, revoked_at, revoked_reason, status, created_by, metadata,
max_seats, seats_used
FROM registration_tokens
WHERE status = 'active'
WHERE status = 'active' AND expires_at > NOW()
ORDER BY created_at DESC
`

View File

@@ -1,123 +0,0 @@
package queries
import (
"time"
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
"github.com/google/uuid"
"github.com/jmoiron/sqlx"
"golang.org/x/crypto/bcrypt"
)
type UserQueries struct {
db *sqlx.DB
}
func NewUserQueries(db *sqlx.DB) *UserQueries {
return &UserQueries{db: db}
}
// CreateUser inserts a new user into the database with password hashing
func (q *UserQueries) CreateUser(username, email, password, role string) (*models.User, error) {
// Hash the password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
user := &models.User{
ID: uuid.New(),
Username: username,
Email: email,
PasswordHash: string(hashedPassword),
Role: role,
CreatedAt: time.Now().UTC(),
}
query := `
INSERT INTO users (
id, username, email, password_hash, role, created_at
) VALUES (
:id, :username, :email, :password_hash, :role, :created_at
)
RETURNING *
`
rows, err := q.db.NamedQuery(query, user)
if err != nil {
return nil, err
}
defer rows.Close()
if rows.Next() {
if err := rows.StructScan(user); err != nil {
return nil, err
}
return user, nil
}
return nil, nil
}
// GetUserByUsername retrieves a user by username
func (q *UserQueries) GetUserByUsername(username string) (*models.User, error) {
var user models.User
query := `SELECT * FROM users WHERE username = $1`
err := q.db.Get(&user, query, username)
if err != nil {
return nil, err
}
return &user, nil
}
// VerifyCredentials checks if the provided username and password are valid
func (q *UserQueries) VerifyCredentials(username, password string) (*models.User, error) {
user, err := q.GetUserByUsername(username)
if err != nil {
return nil, err
}
// Compare the provided password with the stored hash
err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password))
if err != nil {
return nil, err // Invalid password
}
// Update last login time
q.UpdateLastLogin(user.ID)
// Don't return password hash
user.PasswordHash = ""
return user, nil
}
// UpdateLastLogin updates the user's last login timestamp
func (q *UserQueries) UpdateLastLogin(id uuid.UUID) error {
query := `UPDATE users SET last_login = $1 WHERE id = $2`
_, err := q.db.Exec(query, time.Now().UTC(), id)
return err
}
// GetUserByID retrieves a user by ID
func (q *UserQueries) GetUserByID(id uuid.UUID) (*models.User, error) {
var user models.User
query := `SELECT id, username, email, role, created_at, last_login FROM users WHERE id = $1`
err := q.db.Get(&user, query, id)
if err != nil {
return nil, err
}
return &user, nil
}
// EnsureAdminUser creates an admin user if one doesn't exist
func (q *UserQueries) EnsureAdminUser(username, email, password string) error {
// Check if admin user already exists
existingUser, err := q.GetUserByUsername(username)
if err == nil && existingUser != nil {
return nil // Admin user already exists
}
// Create admin user
_, err = q.CreateUser(username, email, password, "admin")
return err
}