package api import ( "net/http" "golang.org/x/crypto/bcrypt" ) func (a *API) reauthenticate(w http.ResponseWriter, uid, password string) bool { a.authLoginMu.Lock() defer a.authLoginMu.Unlock() return a.reauthenticateLocked(w, uid, password, http.StatusForbidden) } // The caller holds authLoginMu; never acquire instance or user locks while holding it. func (a *API) reauthenticateLocked(w http.ResponseWriter, uid, password string, invalidStatus int) bool { u, err := a.s.UserByID(uid) if err != nil { fail(w, 503, "authentication unavailable") return false } locked, err := a.accountLocked(u.Username) if err != nil { fail(w, 503, "authentication unavailable") return false } if locked { fail(w, 429, "account temporarily locked; retry later") return false } hash, err := a.s.Password(u.Username) if err != nil { fail(w, 503, "authentication unavailable") return false } if len(password) > 72 || bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) != nil { if err = a.failedLogin(u.Username); err != nil { fail(w, 503, "authentication unavailable") return false } fail(w, invalidStatus, "invalid current password") return false } return true }