126 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package email
import (
"context"
"crypto/rsa"
"errors"
"fmt"
"math/rand"
"time"
"github.com/samber/lo"
"github.com/wneessen/go-mail"
"github.com/xmdhs/authlib-skin/config"
"github.com/xmdhs/authlib-skin/db/cache"
)
type EmailConfig struct {
Host string
Port int
SSL bool
Name string
Pass string
}
type Email struct {
emailConfig []EmailConfig
pri *rsa.PrivateKey
config config.Config
cache cache.Cache
}
func NewEmail(emailConfig []EmailConfig, pri *rsa.PrivateKey, config config.Config, cache cache.Cache) Email {
return Email{
emailConfig: emailConfig,
pri: pri,
config: config,
cache: cache,
}
}
func (e Email) getRandEmailUser() EmailConfig {
i := rand.Intn(len(e.emailConfig))
return e.emailConfig[i]
}
func (e Email) SendEmail(ctx context.Context, to string, subject, body string) error {
u := e.getRandEmailUser()
m := mail.NewMsg()
err := m.From(u.Name)
if err != nil {
return fmt.Errorf("SendRegVerify: %w", err)
}
err = m.To(to)
if err != nil {
return fmt.Errorf("SendRegVerify: %w", err)
}
m.Subject(subject)
m.SetBodyString(mail.TypeTextHTML, body)
c, err := mail.NewClient(u.Host, mail.WithPort(u.Port), mail.WithSMTPAuth(mail.SMTPAuthPlain),
mail.WithUsername(u.Name), mail.WithPassword(u.Pass))
if err != nil {
return fmt.Errorf("SendRegVerify: %w", err)
}
if u.SSL {
c.SetSSL(true)
}
defer c.Close()
err = c.DialAndSendWithContext(ctx, m)
if err != nil {
return fmt.Errorf("SendRegVerify: %w", err)
}
return nil
}
func (e Email) SendVerifyCode(ctx context.Context, email string, interval int) error {
sendKey := []byte("SendEmail" + email)
sendB, err := e.cache.Get(sendKey)
if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err)
}
if sendB == nil {
return fmt.Errorf("SendRegVerifyCode: %w", ErrSendLimit)
}
err = e.cache.Put(sendKey, []byte{1}, time.Now().Add(time.Second*time.Duration(interval)))
if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err)
}
code := lo.RandomString(8, append(lo.NumbersCharset, lo.UpperCaseLettersCharset...))
err = e.cache.Put([]byte("VerifyCode"+email), []byte(code), time.Now().Add(5*time.Minute))
if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err)
}
err = e.SendEmail(ctx, email, "验证你的邮箱", fmt.Sprintf("验证码:%v五分钟内有效", code))
if err != nil {
return fmt.Errorf("SendRegVerifyCode: %w", err)
}
return nil
}
var (
ErrCodeNotValid = errors.New("验证码无效")
ErrSendLimit = errors.New("邮件发送限制")
)
func (e Email) VerifyCode(email, code string) error {
key := []byte("VerifyCode" + email)
codeb, err := e.cache.Get(key)
if err != nil {
return fmt.Errorf("VerifyCode: %w", err)
}
if string(codeb) != code {
err := e.cache.Del(key)
if err != nil {
return fmt.Errorf("VerifyCode: %w", err)
}
return ErrCodeNotValid
}
return nil
}