From c1059072a6a323dc71e2b5213fadfac2a6ce3922 Mon Sep 17 00:00:00 2001 From: Bagas Aulia Rezki Date: Wed, 19 Jun 2024 21:34:50 +0700 Subject: [PATCH] Adding response to 2FA --- cache/cache.go | 2 ++ handler/auth/totp/totp.go | 47 ++++++++++++++++++++++++++++++++++ handler/signin/signin.go | 18 +++++++++++++ routes/routes.go | 11 ++++++++ session/session.go | 8 ++++++ types/types.go | 1 + view/totp/totp.templ | 54 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+) create mode 100644 handler/auth/totp/totp.go create mode 100644 view/totp/totp.templ diff --git a/cache/cache.go b/cache/cache.go index 81ab8e8..d859b71 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -15,6 +15,7 @@ type UserWithExpired struct { Username string Email string Password string + Totp string AccessAt time.Time mu sync.Mutex } @@ -103,6 +104,7 @@ func GetUser(email string) (*UserWithExpired, error) { Username: userData.Username, Email: userData.Email, Password: userData.Password, + Totp: userData.Totp, AccessAt: time.Now(), } diff --git a/handler/auth/totp/totp.go b/handler/auth/totp/totp.go new file mode 100644 index 0000000..171597f --- /dev/null +++ b/handler/auth/totp/totp.go @@ -0,0 +1,47 @@ +package totpHandler + +import ( + "fmt" + "github.com/fossyy/filekeeper/session" + "github.com/fossyy/filekeeper/types" + totpView "github.com/fossyy/filekeeper/view/totp" + "github.com/xlzd/gotp" + "net/http" + "time" +) + +func GET(w http.ResponseWriter, r *http.Request) { + component := totpView.Main("Filekeeper - 2FA Page") + err := component.Render(r.Context(), w) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + return +} + +func POST(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + code := r.Form.Get("code") + _, user, key := session.GetSession(r) + + totp := gotp.NewDefaultTOTP(user.Totp) + if totp.Verify(code, time.Now().Unix()) { + storeSession, err := session.Get(key) + if err != nil { + return + } + fmt.Println(storeSession) + storeSession.Values["user"] = types.User{ + UserID: user.UserID, + Email: user.Email, + Username: user.Username, + Totp: "", + Authenticated: true, + } + http.Redirect(w, r, "/user", http.StatusFound) + return + } else { + fmt.Fprint(w, "wrong") + } +} diff --git a/handler/signin/signin.go b/handler/signin/signin.go index d779153..532a5fa 100644 --- a/handler/signin/signin.go +++ b/handler/signin/signin.go @@ -17,6 +17,10 @@ import ( var log *logger.AggregatedLogger var errorMessages = make(map[string]string) +func init() { + +} + func init() { errorMessages = map[string]string{ "redirect_uri_mismatch": "The redirect URI provided does not match the one registered with our service. Please contact the administrator for assistance.", @@ -92,6 +96,20 @@ func POST(w http.ResponseWriter, r *http.Request) { } if email == userData.Email && utils.CheckPasswordHash(password, userData.Password) { + if userData.Totp != "" { + storeSession := session.Create() + storeSession.Values["user"] = types.User{ + UserID: userData.UserID, + Email: email, + Username: userData.Username, + Totp: userData.Totp, + Authenticated: false, + } + storeSession.Save(w) + http.Redirect(w, r, "/auth/totp", http.StatusSeeOther) + return + } + storeSession := session.Create() storeSession.Values["user"] = types.User{ UserID: userData.UserID, diff --git a/routes/routes.go b/routes/routes.go index a06ce9f..8948521 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -4,6 +4,7 @@ import ( googleOauthHandler "github.com/fossyy/filekeeper/handler/auth/google" googleOauthCallbackHandler "github.com/fossyy/filekeeper/handler/auth/google/callback" googleOauthSetupHandler "github.com/fossyy/filekeeper/handler/auth/google/setup" + totpHandler "github.com/fossyy/filekeeper/handler/auth/totp" downloadHandler "github.com/fossyy/filekeeper/handler/download" downloadFileHandler "github.com/fossyy/filekeeper/handler/download/file" forgotPasswordHandler "github.com/fossyy/filekeeper/handler/forgotPassword" @@ -47,7 +48,17 @@ func SetupRoutes() *http.ServeMux { default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } + }) + authRouter.HandleFunc("/totp", func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + middleware.Guest(totpHandler.GET, w, r) + case http.MethodPost: + middleware.Guest(totpHandler.POST, w, r) + default: + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + } }) authRouter.HandleFunc("/google/callback", func(w http.ResponseWriter, r *http.Request) { diff --git a/session/session.go b/session/session.go index 0a1ed1e..6f18872 100644 --- a/session/session.go +++ b/session/session.go @@ -176,6 +176,14 @@ func GetSession(r *http.Request) (UserStatus, types.User, string) { return Unauthorized, types.User{}, "" } + if !userSession.Authenticated && userSession.Totp != "" { + return Unauthorized, userSession, cookie.Value + } + + if !userSession.Authenticated { + return Unauthorized, types.User{}, "" + } + return Authorized, userSession, cookie.Value } diff --git a/types/types.go b/types/types.go index 8c5c410..7eda14f 100644 --- a/types/types.go +++ b/types/types.go @@ -13,6 +13,7 @@ type User struct { UserID uuid.UUID Email string Username string + Totp string Authenticated bool } diff --git a/view/totp/totp.templ b/view/totp/totp.templ new file mode 100644 index 0000000..24f42f0 --- /dev/null +++ b/view/totp/totp.templ @@ -0,0 +1,54 @@ +package totpView + +import ( + "github.com/fossyy/filekeeper/view/layout" +) + +templ content(title string) { + @layout.Base(title){ +
+
+
+
+

Verify Your Identity

+

+ Enter the 6-digit code sent to your registered device to complete the login process. +

+
+
+
+ +
+ +
+
+
+ +
+
+
+
+
+ } +} + +templ Main(title string) { + @content(title) +} \ No newline at end of file