Creating backend to handler password resets

This commit is contained in:
vinchent 2024-08-21 12:54:25 +02:00
parent 333499f76e
commit b98b61aa76
8 changed files with 77 additions and 6 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/stripe/stripe-go/v79" "github.com/stripe/stripe-go/v79"
"golang.org/x/crypto/bcrypt"
) )
type stripePayload struct { type stripePayload struct {
@ -465,3 +466,45 @@ func (app *application) SendPasswordResetEmail(w http.ResponseWriter, r *http.Re
app.writeJSON(w, http.StatusCreated, resp) app.writeJSON(w, http.StatusCreated, resp)
} }
func (app *application) ResetPassword(w http.ResponseWriter, r *http.Request) {
var payload struct {
Email string `json:"email"`
Password string `json:"password"`
}
err := app.readJSON(w, r, &payload)
if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err)
return
}
user, err := app.DB.GetUserByEmail(payload.Email)
if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err)
return
}
newHash, err := bcrypt.GenerateFromPassword([]byte(payload.Password), 12)
if err != nil {
app.errorLog.Println(err)
app.badRequest(w, r, err)
return
}
err = app.DB.UpdatePasswordForUser(user, string(newHash))
if err != nil {
app.badRequest(w, r, err)
return
}
var resp struct {
Error bool `json:"error"`
Message string `json:"message"`
}
resp.Error = false
resp.Message = "Password reset."
app.writeJSON(w, http.StatusCreated, resp)
}

View File

@ -27,13 +27,14 @@ func (app *application) routes() http.Handler {
mux.Route("/api/admin", func(mux chi.Router) { mux.Route("/api/admin", func(mux chi.Router) {
mux.Use(app.Auth) mux.Use(app.Auth)
mux.Get("/test", func(w http.ResponseWriter, r *http.Request) { // mux.Get("/test", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("got in")) // w.Write([]byte("got in"))
}) // })
mux.Post("/virtual-terminal-succeeded", app.VirtualTerminalPaymentSucceeded) mux.Post("/virtual-terminal-succeeded", app.VirtualTerminalPaymentSucceeded)
}) })
mux.Post("/api/forgot-password", app.SendPasswordResetEmail) mux.Post("/api/forgot-password", app.SendPasswordResetEmail)
mux.Post("/api/reset-password", app.ResetPassword)
return mux return mux
} }

View File

@ -12,6 +12,7 @@
<p> <p>
<a href="{{.Link}}">{{.Link}}</a> <a href="{{.Link}}">{{.Link}}</a>
</p> </p>
<p>This link expires in 10 minutes.</p>
<p> <p>
-- --
<br> <br>

View File

@ -7,6 +7,8 @@ Click on the link below to get started:
{{.Link}} {{.Link}}
This link expires in 10 minutes.
-- --
Widget Co. Widget Co.
{{ end }} {{ end }}

View File

@ -340,6 +340,13 @@ func (app *application) ShowResetPassword(w http.ResponseWriter, r *http.Request
return return
} }
// make sure not expired
expired := signer.Expired(testURL, 10)
if expired {
app.errorLog.Println("Link expired")
return
}
data := make(map[string]interface{}) data := make(map[string]interface{})
data["email"] = r.URL.Query().Get("email") data["email"] = r.URL.Query().Get("email")
if err := app.renderTemplate(w, r, "reset-password", &templateData{ if err := app.renderTemplate(w, r, "reset-password", &templateData{

View File

@ -44,7 +44,7 @@ Reset Password
<script type="module"> <script type="module">
import {reset} from "/static/js/login.js" import {reset} from "/static/js/login.js"
document.getElementById("reset-btn").addEventListener("click", () => { document.getElementById("reset-btn").addEventListener("click", () => {
reset({{.API}}); reset({{.API}}, {{index .Data "email"}});
}) })
</script> </script>
{{end}} {{end}}

View File

@ -280,3 +280,16 @@ func (m *DBModel) Authenticate(email, password string) (int, error) {
return id, nil return id, nil
} }
func (m *DBModel) UpdatePasswordForUser(u User, hash string) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
stmt := `UPDATE users SET password = ? where id = ?`
_, err := m.DB.ExecContext(ctx, stmt, hash, u.ID)
if err != nil {
return err
}
return nil
}

View File

@ -81,7 +81,7 @@ export function forgot(api) {
}); });
} }
export function reset(api) { export function reset(api, email) {
let form = document.getElementById("reset-form"); let form = document.getElementById("reset-form");
if (form.checkValidity() === false) { if (form.checkValidity() === false) {
@ -98,7 +98,8 @@ export function reset(api) {
} }
let payload = { let payload = {
email: document.getElementById("email").value, password: document.getElementById("password").value,
email: email,
}; };
const requestOptions = { const requestOptions = {
@ -116,6 +117,9 @@ export function reset(api) {
console.log(response) console.log(response)
if (response.error === false) { if (response.error === false) {
showSuccess("reset-messages", "Password reset") showSuccess("reset-messages", "Password reset")
setTimeout(function () {
location.href = "/login"
}, 2000)
} else { } else {
showError("reset-messages", response.message) showError("reset-messages", response.message)
} }