Generate password reset tokens upon submission.
This commit is contained in:
parent
aa42451611
commit
b4de8e58f9
4 changed files with 47 additions and 3 deletions
30
auth/auth.go
30
auth/auth.go
|
|
@ -1,6 +1,8 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"goweb/config"
|
"goweb/config"
|
||||||
|
|
@ -83,3 +85,31 @@ func (c *Client) HashPassword(password string) (string, error) {
|
||||||
func (c *Client) CheckPassword(password, hash string) error {
|
func (c *Client) CheckPassword(password, hash string) error {
|
||||||
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
return bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GeneratePasswordResetToken(ctx echo.Context, userID int) (string, *ent.PasswordToken, error) {
|
||||||
|
// Generate the token, which is what will go in the URL, but not the database
|
||||||
|
token := c.RandomToken(64)
|
||||||
|
|
||||||
|
// Hash the token, which is what will be stored in the database
|
||||||
|
hash, err := c.HashPassword(token)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and save the password reset token
|
||||||
|
pt, err := c.orm.PasswordToken.
|
||||||
|
Create().
|
||||||
|
SetHash(hash).
|
||||||
|
SetUserID(userID).
|
||||||
|
Save(ctx.Request().Context())
|
||||||
|
|
||||||
|
return token, pt, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RandomToken(length int) string {
|
||||||
|
b := make([]byte, length)
|
||||||
|
if _, err := rand.Read(b); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(b)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ func NewPage(c echo.Context) Page {
|
||||||
p.CSRF = csrf.(string)
|
p.CSRF = csrf.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Use container?
|
||||||
if u := c.Get(context.AuthenticatedUserKey); u != nil {
|
if u := c.Get(context.AuthenticatedUserKey); u != nil {
|
||||||
p.IsAuth = true
|
p.IsAuth = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"goweb/context"
|
"goweb/context"
|
||||||
"goweb/controller"
|
"goweb/controller"
|
||||||
"goweb/ent"
|
"goweb/ent"
|
||||||
|
|
@ -42,6 +44,7 @@ func (f *ForgotPassword) Post(c echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
succeed := func() error {
|
succeed := func() error {
|
||||||
|
c.Set(context.FormKey, nil)
|
||||||
msg.Success(c, "An email containing a link to reset your password will be sent to this address if it exists in our system.")
|
msg.Success(c, "An email containing a link to reset your password will be sent to this address if it exists in our system.")
|
||||||
return f.Get(c)
|
return f.Get(c)
|
||||||
}
|
}
|
||||||
|
|
@ -74,10 +77,18 @@ func (f *ForgotPassword) Post(c echo.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: generate and email a token
|
// Generate the token
|
||||||
if u != nil {
|
token, _, err := f.Container.Auth.GeneratePasswordResetToken(c, u.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fail("error generating password reset token", err)
|
||||||
|
}
|
||||||
|
c.Logger().Infof("generated password reset token for user %d", u.ID)
|
||||||
|
|
||||||
|
// Email the user
|
||||||
|
err = f.Container.Mail.Send(c, u.Email, fmt.Sprintf("Go here to reset your password: %s", token)) // TODO: route
|
||||||
|
if err != nil {
|
||||||
|
return fail("error sending password reset email", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.Redirect(c, "home")
|
return succeed()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ type Logout struct {
|
||||||
func (l *Logout) Get(c echo.Context) error {
|
func (l *Logout) Get(c echo.Context) error {
|
||||||
if err := l.Container.Auth.Logout(c); err == nil {
|
if err := l.Container.Auth.Logout(c); err == nil {
|
||||||
msg.Success(c, "You have been logged out successfully.")
|
msg.Success(c, "You have been logged out successfully.")
|
||||||
|
} else {
|
||||||
|
msg.Danger(c, "An error occurred. Please try again.")
|
||||||
}
|
}
|
||||||
return l.Redirect(c, "home")
|
return l.Redirect(c, "home")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue