-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathemail_verification.go
More file actions
96 lines (79 loc) · 2.85 KB
/
Copy pathemail_verification.go
File metadata and controls
96 lines (79 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package limen
import (
"context"
"time"
)
// EmailVerificationEnabled reports whether email verification is enabled.
func (c *LimenCore) EmailVerificationEnabled() bool {
return c.config.Email.verification.enabled
}
// RequestEmailVerification looks up the user by email, ensures the address
// is not already verified, creates a verification token and optionally sends
// the email.
func (c *LimenCore) RequestEmailVerification(ctx context.Context, user *User, shouldSendEmail bool) (*Verification, error) {
user, err := c.DBAction.FindUserByEmail(ctx, user.Email)
if err != nil {
return nil, err
}
if user.EmailVerifiedAt != nil {
return nil, ErrEmailAlreadyVerified
}
verification, err := c.CreateEmailVerification(ctx, user)
if err != nil {
return nil, err
}
if shouldSendEmail && verification != nil {
c.SendEmailVerificationMail(user, verification)
}
return verification, nil
}
// CreateEmailVerification creates a new verification token for the user.
func (c *LimenCore) CreateEmailVerification(ctx context.Context, user *User) (*Verification, error) {
normalizedUser := *user
normalizedUser.Email = NormalizeEmail(user.Email)
user = &normalizedUser
token, err := c.generateEmailVerificationToken(user)
if err != nil {
return nil, err
}
return c.DBAction.CreateVerification(ctx, EmailVerificationAction, user.Email, token, c.config.Email.verification.expiration)
}
// SendEmailVerificationMail dispatches the verification email when a callback is configured.
func (c *LimenCore) SendEmailVerificationMail(user *User, verification *Verification) {
if c.config.Email.verification.sendEmail != nil {
c.config.Email.verification.sendEmail(user.Email, verification.Value)
}
}
// VerifyEmail validates the token, marks the user's email as verified, and
// deletes the consumed token. It returns the verified email address.
func (c *LimenCore) VerifyEmail(ctx context.Context, token string) (string, error) {
verification, err := c.DBAction.FindValidVerificationByToken(ctx, token)
if err != nil {
return "", ErrEmailVerificationTokenInvalid
}
action, identifier := ParseVerificationAction(verification.Subject)
if action != EmailVerificationAction {
return "", ErrEmailVerificationTokenInvalid
}
email := NormalizeEmail(identifier)
now := time.Now()
err = c.WithTransaction(ctx, func(ctx context.Context) error {
if err := c.DBAction.UpdateUser(ctx, &User{EmailVerifiedAt: &now},
[]Where{
Eq(c.Schema.User.GetEmailField(), email),
}); err != nil {
return err
}
return c.DBAction.DeleteVerificationToken(ctx, verification.Value)
})
if err != nil {
return "", err
}
return email, nil
}
func (c *LimenCore) generateEmailVerificationToken(user *User) (string, error) {
if c.config.Email.verification.generateToken != nil {
return c.config.Email.verification.generateToken(user)
}
return generateCryptoSecureRandomString(), nil
}