Improve installer extraction, login failures, and upload handling

This commit is contained in:
2026-07-27 00:17:30 +08:00
parent 97ea6fb7aa
commit 73555cd04c
14 changed files with 199 additions and 31 deletions
@@ -59,6 +59,15 @@ type Captcha struct {
Image string `json:"image"`
}
type LoginFailure string
const (
LoginFailureNone LoginFailure = ""
LoginFailureLocked LoginFailure = "locked"
LoginFailureCaptcha LoginFailure = "captcha"
LoginFailureCredentials LoginFailure = "credentials"
)
func NewService(store *db.Store) *Service {
return &Service{
store: store,
@@ -103,21 +112,26 @@ func (s *Service) NewCaptcha() (Captcha, error) {
}
func (s *Service) Login(ctx context.Context, username, password, captchaID, captcha string, clientKeys ...string) (string, string, bool, error) {
sessionID, csrf, failure, err := s.LoginDetailed(ctx, username, password, captchaID, captcha, clientKeys...)
return sessionID, csrf, err == nil && failure == LoginFailureNone, err
}
func (s *Service) LoginDetailed(ctx context.Context, username, password, captchaID, captcha string, clientKeys ...string) (string, string, LoginFailure, error) {
attemptKey := loginAttemptKey(username, clientKeys...)
if s.loginLocked(attemptKey) {
return "", "", false, nil
return "", "", LoginFailureLocked, nil
}
if !s.consumeCaptcha(captchaID, captcha) {
s.recordLoginFailure(attemptKey)
return "", "", false, nil
return "", "", LoginFailureCaptcha, nil
}
user, ok, err := s.store.VerifyAdminPassword(ctx, username, password)
if err != nil {
return "", "", false, err
return "", "", LoginFailureNone, err
}
if !ok {
s.recordLoginFailure(attemptKey)
return "", "", false, nil
return "", "", LoginFailureCredentials, nil
}
sessionID := randomToken(32)
csrf := randomToken(32)
@@ -126,7 +140,7 @@ func (s *Service) Login(ctx context.Context, username, password, captchaID, capt
s.sessions[sessionID] = sessionEntry{username: user.Username, csrf: csrf, expiresAt: time.Now().Add(sessionTTL)}
delete(s.loginAttempts, attemptKey)
s.mu.Unlock()
return sessionID, csrf, true, nil
return sessionID, csrf, LoginFailureNone, nil
}
func (s *Service) Logout(w http.ResponseWriter, r *http.Request) {