From e4dbf706838b05299c03f5fd133b281ec311aadd Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Fri, 28 Jan 2022 02:05:46 +0530 Subject: [PATCH 1/4] fix: otp attempt issue #23 --- cmd/otpgateway/handlers.go | 41 ++++++++++++++++++++++++++++---------- internal/store/store.go | 12 ++++++++--- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/cmd/otpgateway/handlers.go b/cmd/otpgateway/handlers.go index 20706d4..1238c1c 100644 --- a/cmd/otpgateway/handlers.go +++ b/cmd/otpgateway/handlers.go @@ -307,6 +307,15 @@ func handleVerifyOTP(w http.ResponseWriter, r *http.Request) { return } + if err == store.ErrTooManyAttempts { + code = http.StatusTooManyRequests + errMsg := fmt.Sprintf("Too many attempts. Please retry after %0.f seconds.", + out.TTL.Seconds()) + err := errors.New(errMsg) + sendErrorResponse(w, err.Error(), code, nil) + return + } + if out.Closed { code = http.StatusTooManyRequests } @@ -349,8 +358,17 @@ func handleOTPView(w http.ResponseWriter, r *http.Request) { return } + isOtpLocked := false // Attempts are maxed out and locked. - if isLocked(out) { + if action == actCheck { + if otpErr == store.ErrTooManyAttempts { + isOtpLocked = true + } + } else if isLocked(out) { + isOtpLocked = true + } + + if isOtpLocked { app.tpl.ExecuteTemplate(w, "message", webviewTpl{App: app.constants, Title: "Too many attempts", Description: fmt.Sprintf("Please retry after %d seconds.", int64(out.TTLSeconds)), @@ -522,20 +540,21 @@ func verifyOTP(namespace, id, otp string, deleteOnVerify bool, app *App) (models app.lo.Printf("error checking OTP: %v", err) return out, err } - return out, errors.New("error checking OTP.") + return out, errors.New("error checking OTP") } - errMsg := "" - if isLocked(out) { - errMsg = fmt.Sprintf("Too many attempts. Please retry after %0.f seconds.", - out.TTL.Seconds()) - } else if out.OTP != otp { - errMsg = "Incorrect OTP" + // Attempts exceeded for OTP + if out.Attempts > out.MaxAttempts { + return out, store.ErrTooManyAttempts + } + + // Final attempt with incorrect OTP + if out.Attempts == out.MaxAttempts && out.OTP != otp { + return out, store.ErrTooManyAttempts } - // There was an error. - if errMsg != "" { - return out, errors.New(errMsg) + if out.OTP != otp { + return out, errors.New("incorrect OTP") } // Delete the OTP? diff --git a/internal/store/store.go b/internal/store/store.go index b3953fa..4b9153d 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -6,9 +6,15 @@ import ( "github.com/knadh/otpgateway/v3/internal/models" ) -// ErrNotExist is thrown when an OTP (requested by namespace / ID) -// does not exist. -var ErrNotExist = errors.New("the OTP does not exist") + +var ( + // ErrNotExist is thrown when an OTP (requested by namespace / ID) + // does not exist. + ErrNotExist = errors.New("the OTP does not exist") + // ErrNotExist is thrown when an OTP (requested by namespace / ID) + // strictly exceeds the maximum number of attempts. + ErrTooManyAttempts = errors.New("too many attempts") +) // Store represents a storage backend where OTP data is stored. type Store interface { From 0ff85578f200c9920fe3cc83acb68743ef3f90dd Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Fri, 28 Jan 2022 02:33:13 +0530 Subject: [PATCH 2/4] fix typo --- internal/store/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/store/store.go b/internal/store/store.go index 4b9153d..c694580 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -11,7 +11,7 @@ var ( // ErrNotExist is thrown when an OTP (requested by namespace / ID) // does not exist. ErrNotExist = errors.New("the OTP does not exist") - // ErrNotExist is thrown when an OTP (requested by namespace / ID) + // ErrTooManyAttempts is thrown when an OTP (requested by namespace / ID) // strictly exceeds the maximum number of attempts. ErrTooManyAttempts = errors.New("too many attempts") ) From 585c6e9855bcf6db8c7b3973dcfb56a8259a9437 Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Fri, 28 Jan 2022 02:38:15 +0530 Subject: [PATCH 3/4] docs: edit comment --- internal/store/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/store/store.go b/internal/store/store.go index c694580..d9df478 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -12,7 +12,7 @@ var ( // does not exist. ErrNotExist = errors.New("the OTP does not exist") // ErrTooManyAttempts is thrown when an OTP (requested by namespace / ID) - // strictly exceeds the maximum number of attempts. + // attempts are maxed out. ErrTooManyAttempts = errors.New("too many attempts") ) From d09e2267496357932d0beab399a0105b69f85b4e Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Mon, 31 Jan 2022 11:11:34 +0530 Subject: [PATCH 4/4] format code --- cmd/otpgateway/handlers.go | 6 +++--- internal/store/store.go | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/otpgateway/handlers.go b/cmd/otpgateway/handlers.go index 1238c1c..91f4b48 100644 --- a/cmd/otpgateway/handlers.go +++ b/cmd/otpgateway/handlers.go @@ -310,7 +310,7 @@ func handleVerifyOTP(w http.ResponseWriter, r *http.Request) { if err == store.ErrTooManyAttempts { code = http.StatusTooManyRequests errMsg := fmt.Sprintf("Too many attempts. Please retry after %0.f seconds.", - out.TTL.Seconds()) + out.TTL.Seconds()) err := errors.New(errMsg) sendErrorResponse(w, err.Error(), code, nil) return @@ -360,7 +360,7 @@ func handleOTPView(w http.ResponseWriter, r *http.Request) { isOtpLocked := false // Attempts are maxed out and locked. - if action == actCheck { + if action == actCheck { if otpErr == store.ErrTooManyAttempts { isOtpLocked = true } @@ -547,7 +547,7 @@ func verifyOTP(namespace, id, otp string, deleteOnVerify bool, app *App) (models if out.Attempts > out.MaxAttempts { return out, store.ErrTooManyAttempts } - + // Final attempt with incorrect OTP if out.Attempts == out.MaxAttempts && out.OTP != otp { return out, store.ErrTooManyAttempts diff --git a/internal/store/store.go b/internal/store/store.go index d9df478..4c55af2 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -6,7 +6,6 @@ import ( "github.com/knadh/otpgateway/v3/internal/models" ) - var ( // ErrNotExist is thrown when an OTP (requested by namespace / ID) // does not exist.