Files
Prism/internal/store/login_attempts.go
T
renjue 2780eaf30c
CI / test (push) Successful in 1m55s
CI / docker (push) Failing after 24s
feat: Prism HTTP/SOCKS5 代理网关及管理台
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 15:11:50 +08:00

66 lines
1.6 KiB
Go

package store
import (
"context"
"database/sql"
"time"
)
type LoginAttempt struct {
FailCount int
WindowStart time.Time
LockedUntil *time.Time
}
func (s *Store) GetLoginAttempt(ctx context.Context, ip string) (*LoginAttempt, error) {
var failCount int
var windowStart string
var lockedUntil sql.NullString
err := s.db.QueryRowContext(ctx,
`SELECT fail_count, window_start, locked_until FROM login_attempts WHERE ip = ?`, ip,
).Scan(&failCount, &windowStart, &lockedUntil)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
out := &LoginAttempt{
FailCount: failCount,
WindowStart: parseTime(windowStart),
}
if lockedUntil.Valid && lockedUntil.String != "" {
t := parseTime(lockedUntil.String)
out.LockedUntil = &t
}
return out, nil
}
func (s *Store) SetLoginAttempt(ctx context.Context, ip string, attempt LoginAttempt) error {
var locked string
if attempt.LockedUntil != nil {
locked = attempt.LockedUntil.Format("2006-01-02 15:04:05")
}
_, err := s.db.ExecContext(ctx, `
INSERT INTO login_attempts(ip, fail_count, window_start, locked_until)
VALUES(?,?,?,?)
ON CONFLICT(ip) DO UPDATE SET
fail_count = excluded.fail_count,
window_start = excluded.window_start,
locked_until = excluded.locked_until
`, ip, attempt.FailCount, attempt.WindowStart.Format("2006-01-02 15:04:05"), nullIfEmpty(locked))
return err
}
func (s *Store) ClearLoginAttempt(ctx context.Context, ip string) error {
_, err := s.db.ExecContext(ctx, `DELETE FROM login_attempts WHERE ip = ?`, ip)
return err
}
func nullIfEmpty(s string) any {
if s == "" {
return nil
}
return s
}