Files
OwnCord/Server/db/lockout_queries.go
T
J3vb 9e48e8d8e8 fix: security hardening — 11 findings across auth, WS, upload, admin, data
Security audit across all 11 sections (AUTH-001 through DATA-001) found
0 critical, 1 high, 7 medium, 15 low issues. This commit addresses:

- Add json:"-" to User.PasswordHash, User.TOTPSecret, Session.TokenHash
  to prevent accidental serialization of sensitive fields (M7)
- Add X-Content-Type-Options: nosniff to file serve responses (M5)
- Apply owner-only guard to backup list endpoint for consistency (M6)
- Persist rate-limit lockouts to SQLite so they survive restarts (M2)
- Normalize DM non-participant responses to 404 to prevent oracle (L3)
- Add explicit per-entry expiry check in partial auth Lookup/Consume (L1)
- Truncate unknown WS message type to 64 chars before echo (L6)
- Rate-limit ping handler to 2/sec per user (L7)
- Replace raw error strings in update handlers with generic messages (L15)
- Update 4 tests to match new 404 behavior for DM non-participant
2026-04-02 14:51:16 +02:00

55 lines
1.5 KiB
Go

package db
import "time"
// UpsertLockout inserts or replaces a rate-limit lockout entry.
func (d *DB) UpsertLockout(key string, expiresAt time.Time) error {
_, err := d.sqlDB.Exec(
`INSERT OR REPLACE INTO rate_lockouts (key, expires_at) VALUES (?, ?)`,
key, expiresAt.UTC().Format(time.RFC3339),
)
return err
}
// LoadActiveLockouts returns all lockouts that have not yet expired as
// parallel slices of keys and expiry times.
func (d *DB) LoadActiveLockouts() (keys []string, expiresAt []time.Time, err error) {
rows, err := d.sqlDB.Query(
`SELECT key, expires_at FROM rate_lockouts WHERE expires_at > ?`,
time.Now().UTC().Format(time.RFC3339),
)
if err != nil {
return nil, nil, err
}
defer rows.Close() //nolint:errcheck
for rows.Next() {
var key, expiresStr string
if err := rows.Scan(&key, &expiresStr); err != nil {
return nil, nil, err
}
t, parseErr := time.Parse(time.RFC3339, expiresStr)
if parseErr != nil {
continue // skip unparseable rows
}
keys = append(keys, key)
expiresAt = append(expiresAt, t)
}
return keys, expiresAt, rows.Err()
}
// CleanupExpiredLockouts removes lockout rows whose expiry has passed.
func (d *DB) CleanupExpiredLockouts() error {
_, err := d.sqlDB.Exec(
`DELETE FROM rate_lockouts WHERE expires_at <= ?`,
time.Now().UTC().Format(time.RFC3339),
)
return err
}
// DeleteLockout removes a single lockout entry.
func (d *DB) DeleteLockout(key string) error {
_, err := d.sqlDB.Exec(`DELETE FROM rate_lockouts WHERE key = ?`, key)
return err
}