mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-04 10:39:47 -06:00
[server] Password reset email
This commit is contained in:
@@ -16,7 +16,7 @@ func SetupCommand() *cobra.Command {
|
||||
}
|
||||
cmd.AddCommand([]*cobra.Command{
|
||||
setupInviteCommand(),
|
||||
setupResetPasswordCommand(),
|
||||
setupPasswordResetCommand(),
|
||||
setupUserModCommand(),
|
||||
setupUserListCommand(),
|
||||
setupUserPasswdCommand(),
|
||||
|
||||
@@ -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},
|
||||
)
|
||||
}
|
||||
|
||||
35
server/internal/command/user/password_reset.go
Normal file
35
server/internal/command/user/password_reset.go
Normal 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
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
13
server/internal/mail/emails/password_reset/body.html
Normal file
13
server/internal/mail/emails/password_reset/body.html
Normal 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>
|
||||
8
server/internal/mail/emails/password_reset/body.txt
Normal file
8
server/internal/mail/emails/password_reset/body.txt
Normal 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,
|
||||
1
server/internal/mail/emails/password_reset/subject
Normal file
1
server/internal/mail/emails/password_reset/subject
Normal file
@@ -0,0 +1 @@
|
||||
Reset your password
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
19
server/internal/mail/password_reset.go
Normal file
19
server/internal/mail/password_reset.go
Normal 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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user