diff --git a/cmd/otpgateway/handlers.go b/cmd/otpgateway/handlers.go index 20706d4..2309bac 100644 --- a/cmd/otpgateway/handlers.go +++ b/cmd/otpgateway/handlers.go @@ -349,8 +349,8 @@ func handleOTPView(w http.ResponseWriter, r *http.Request) { return } - // Attempts are maxed out and locked. - if isLocked(out) { + // Attempts are maxed out and locked + if action != actCheck && isLocked(out) { app.tpl.ExecuteTemplate(w, "message", webviewTpl{App: app.constants, Title: "Too many attempts", Description: fmt.Sprintf("Please retry after %d seconds.", int64(out.TTLSeconds)), @@ -526,7 +526,7 @@ func verifyOTP(namespace, id, otp string, deleteOnVerify bool, app *App) (models } errMsg := "" - if isLocked(out) { + if isLocked(out) && !isFinalAttempt(out) { errMsg = fmt.Sprintf("Too many attempts. Please retry after %0.f seconds.", out.TTL.Seconds()) } else if out.OTP != otp { @@ -595,10 +595,12 @@ func generateRandomString(totalLen int, chars string) (string, error) { // isLocked tells if an OTP is locked after exceeding attempts. func isLocked(otp models.OTP) bool { - if otp.Attempts >= otp.MaxAttempts { - return true - } - return false + return otp.Attempts >= otp.MaxAttempts +} + +// isFinalAttempt checks if it's the final attempt +func isFinalAttempt(otp models.OTP) bool { + return otp.Attempts == otp.MaxAttempts } // push compiles a message template and pushes it to the provider.