diff --git a/admin/accounthttp.go b/admin/accounthttp.go index b5deca2..9402410 100644 --- a/admin/accounthttp.go +++ b/admin/accounthttp.go @@ -30,15 +30,30 @@ func accountIndexHandler(app *model.AppState) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*model.Session) - totps, err := controller.GetTOTPsForAccount(app.DB, session.Account.ID) + dbTOTPs, err := controller.GetTOTPsForAccount(app.DB, session.Account.ID) if err != nil { fmt.Printf("WARN: Failed to fetch TOTPs: %v\n", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } - type accountResponse struct { - Session *model.Session - TOTPs []model.TOTP + type ( + TOTP struct { + model.TOTP + CreatedAtString string + } + + accountResponse struct { + Session *model.Session + TOTPs []TOTP + } + ) + + totps := []TOTP{} + for _, totp := range dbTOTPs { + totps = append(totps, TOTP{ + TOTP: totp, + CreatedAtString: totp.CreatedAt.Format("02 Jan 2006, 15:04:05"), + }) } sessionMessage := session.Message diff --git a/admin/http.go b/admin/http.go index 7dd5207..4d32aa9 100644 --- a/admin/http.go +++ b/admin/http.go @@ -284,26 +284,65 @@ func loginHandler(app *model.AppState) http.Handler { return } - totpMethod, err := controller.CheckTOTPForAccount(app.DB, account.ID, credentials.TOTP) - if err != nil { - fmt.Fprintf(os.Stderr, "WARN: Failed to fetch TOTPs: %v\n", err) - controller.SetSessionError(app.DB, session, "Something went wrong. Please try again.") - render() - return + var totpMethod *model.TOTP + if len(credentials.TOTP) == 0 { + // check if user has TOTP + totps, err := controller.GetTOTPsForAccount(app.DB, account.ID) + if err != nil { + fmt.Fprintf(os.Stderr, "WARN: Failed to fetch TOTPs: %v\n", err) + controller.SetSessionError(app.DB, session, "Something went wrong. Please try again.") + render() + return + } + + if len(totps) > 0 { + type loginTOTPData struct { + Session *model.Session + Username string + Password string + } + err = pages["login-totp"].Execute(w, loginTOTPData{ + Session: session, + Username: credentials.Username, + Password: credentials.Password, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "WARN: Failed to render login TOTP page: %v\n", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + } + } else { + totpMethod, err = controller.CheckTOTPForAccount(app.DB, account.ID, credentials.TOTP) + if err != nil { + fmt.Fprintf(os.Stderr, "WARN: Failed to fetch TOTPs: %v\n", err) + controller.SetSessionError(app.DB, session, "Something went wrong. Please try again.") + render() + return + } + if totpMethod == nil { + controller.SetSessionError(app.DB, session, "Invalid TOTP.") + render() + return + } } - if totpMethod == nil { - controller.SetSessionError(app.DB, session, "Invalid TOTP.") - render() - return + + if totpMethod != nil { + fmt.Printf( + "[%s] INFO: Account \"%s\" logged in with method \"%s\"\n", + time.Now().Format(time.UnixDate), + account.Username, + totpMethod.Name, + ) + } else { + fmt.Printf( + "[%s] INFO: Account \"%s\" logged in\n", + time.Now().Format(time.UnixDate), + account.Username, + ) } // TODO: log login activity to user - fmt.Printf( - "[%s] INFO: Account \"%s\" logged in with method \"%s\"\n", - time.Now().Format(time.UnixDate), - account.Username, - totpMethod.Name, - ) // login success! controller.SetSessionAccount(app.DB, session, account) diff --git a/admin/static/admin.css b/admin/static/admin.css index cbb827e..a6e0bc2 100644 --- a/admin/static/admin.css +++ b/admin/static/admin.css @@ -85,6 +85,15 @@ a img.icon { height: .8em; } +code { + background: #303030; + color: #f0f0f0; + padding: .23em .3em; + border-radius: 4px; +} + + + .card { margin-bottom: 1em; } @@ -93,13 +102,6 @@ a img.icon { margin: 0 0 .5em 0; } -/* -.card h3, -.card p { - margin: 0; -} -*/ - .card-title { margin-bottom: 1em; display: flex; diff --git a/admin/templates.go b/admin/templates.go index 3bae106..d9a74ca 100644 --- a/admin/templates.go +++ b/admin/templates.go @@ -18,6 +18,11 @@ var pages = map[string]*template.Template{ filepath.Join("views", "prideflag.html"), filepath.Join("admin", "views", "login.html"), )), + "login-totp": template.Must(template.ParseFiles( + filepath.Join("admin", "views", "layout.html"), + filepath.Join("views", "prideflag.html"), + filepath.Join("admin", "views", "login-totp.html"), + )), "register": template.Must(template.ParseFiles( filepath.Join("admin", "views", "layout.html"), filepath.Join("views", "prideflag.html"), diff --git a/admin/views/edit-account.html b/admin/views/edit-account.html index b1d083a..6c17088 100644 --- a/admin/views/edit-account.html +++ b/admin/views/edit-account.html @@ -40,11 +40,11 @@ {{range .TOTPs}}
{{.Name}}
-Added: {{.CreatedAt}}
+{{.TOTP.Name}}
+Added: {{.CreatedAtString}}