[server] Password reset email

This commit is contained in:
Abhishek Shroff
2025-05-24 19:37:04 +05:30
parent 59880932c5
commit cdf3eb0454
12 changed files with 95 additions and 56 deletions

View File

@@ -16,7 +16,7 @@ func SetupCommand() *cobra.Command {
}
cmd.AddCommand([]*cobra.Command{
setupInviteCommand(),
setupResetPasswordCommand(),
setupPasswordResetCommand(),
setupUserModCommand(),
setupUserListCommand(),
setupUserPasswdCommand(),

View File

@@ -79,7 +79,7 @@ func setupInviteCommand() *cobra.Command {
os.Exit(1)
}
fmt.Println("User created")
if sendInviteEmail(u) != nil {
if mail.SendWelcomeEmail(u) != nil {
fmt.Println("unable to send email: " + err.Error())
os.Exit(1)
}
@@ -90,41 +90,3 @@ func setupInviteCommand() *cobra.Command {
cmd.Flags().BoolP("no-create-home", "M", false, "Do not make home directory")
return cmd
}
func setupResetPasswordCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "pwreset email",
Short: "pwreset email",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
email := args[0]
manager := user.ManagerFromContext(context.Background())
if user, err := manager.UserByEmail(email); err != nil {
fmt.Println("unable to find user" + email + ": " + err.Error())
os.Exit(1)
} else if token, err := manager.CreateResetToken(user); err != nil {
fmt.Println("unable to create reset token: " + err.Error())
os.Exit(1)
} else if err := sendResetToken(user, token); err != nil {
fmt.Println("unable to send email: " + err.Error())
os.Exit(1)
}
},
}
return cmd
}
func sendInviteEmail(user user.User) error {
return mail.SendWelcomeEmail(
mail.Recipient{Email: user.Email, Name: user.DisplayName},
mail.WelcomeParams{Name: user.DisplayName},
)
}
func sendResetToken(user user.User, token string) error {
return mail.SendWelcomeEmail(
mail.Recipient{Email: user.Email, Name: user.DisplayName},
mail.WelcomeParams{Name: user.DisplayName},
)
}

View File

@@ -0,0 +1,35 @@
package user
import (
"context"
"fmt"
"os"
"github.com/shroff/phylum/server/internal/core/user"
"github.com/shroff/phylum/server/internal/mail"
"github.com/spf13/cobra"
)
func setupPasswordResetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "pwreset email",
Short: "pwreset email",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
email := args[0]
manager := user.ManagerFromContext(context.Background())
if user, err := manager.UserByEmail(email); err != nil {
fmt.Println("unable to find user" + email + ": " + err.Error())
os.Exit(1)
} else if token, err := manager.CreateResetToken(user); err != nil {
fmt.Println("unable to create reset token: " + err.Error())
os.Exit(1)
} else if err := mail.SendPasswordResetEmail(user, token); err != nil {
fmt.Println("unable to send email: " + err.Error())
os.Exit(1)
}
},
}
return cmd
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/shroff/phylum/server/internal/core/util/rand"
)
const resetTokenLength = 16
const resetTokenLength = 64
const resetTokenDuration = 10 * time.Minute
func (m manager) CreateResetToken(user User) (string, error) {

View File

@@ -0,0 +1,13 @@
<html>
<body>
Hi {{.name}},
You can reset your password by clicking <a href="{{.base_url}}/reset_password?email={{.email}}&token={{.token}}">here</a>.
If the link above doesn't work, then you can enter the following token in the password reset prompt, along with your email address:
{{.token}}
Thank you,
</body>
</html>

View File

@@ -0,0 +1,8 @@
Hi {{.name}},
You can reset your password at {{.base_url}}/reset_password?email={{.email}}&token={{.token}}
If the link above doesn't work, then you can enter the following token in the password reset prompt, along with your email address:
{{.token}}
Thank you,

View File

@@ -0,0 +1 @@
Reset your password

View File

@@ -1,8 +1,8 @@
<html>
<body>
Hi {{.Name}},
Hi {{.name}},
Someone invited you to use Phylum at <a href="{{.URL}}">{{.URL}}</a>
Someone invited you to use Phylum at <a href="{{.base_url}}">{{.base_url}}</a>
Please visit the URL above and reset your password to get started.

View File

@@ -1,6 +1,6 @@
Hi {{.Name}},
Hi {{.name}},
Someone invited you to use Phylum at {{.URL}}
Someone invited you to use Phylum at {{.base_url}}
Please visit the URL above and reset your password to get started.

View File

@@ -3,6 +3,7 @@ package mail
import (
"io"
"github.com/shroff/phylum/server/internal/core/user"
gomail "gopkg.in/mail.v2"
)
@@ -21,11 +22,11 @@ func dialer() *gomail.Dialer {
return d
}
func send(e Email, rcpt Recipient, params any) error {
func send(e Email, rcpt user.User, params any) error {
d := dialer()
msg := gomail.NewMessage()
msg.SetAddressHeader("From", Cfg.From.Email, Cfg.From.Name)
msg.SetAddressHeader("To", rcpt.Email, rcpt.Name)
msg.SetAddressHeader("To", rcpt.Email, rcpt.DisplayName)
msg.SetHeader("Subject", e.Subject)
msg.SetBodyWriter("text/plain", func(w io.Writer) error {
return e.Plain.Execute(w, params)

View File

@@ -0,0 +1,19 @@
package mail
import "github.com/shroff/phylum/server/internal/core/user"
type ResetPasswordParams struct {
Name string
URL string
}
func SendPasswordResetEmail(u user.User, token string) error {
email := emails["password_reset"]
params := map[string]string{
"name": u.DisplayName,
"email": u.Email,
"base_url": Cfg.URL,
"token": token,
}
return send(email, u, params)
}

View File

@@ -1,15 +1,15 @@
package mail
type WelcomeParams struct {
Name string
URL string
}
import "github.com/shroff/phylum/server/internal/core/user"
func SendWelcomeEmail(rcpt Recipient, params WelcomeParams) error {
func SendWelcomeEmail(u user.User) error {
email := emails["welcome"]
if params.Name == "" {
params.Name = "there"
params := map[string]string{
"name": u.DisplayName,
"url": Cfg.URL,
}
params.URL = Cfg.URL
return send(email, rcpt, params)
if u.DisplayName == "" {
params["name"] = "there"
}
return send(email, u, params)
}