This commit is contained in:
144
service/reg_token_service.go
Normal file
144
service/reg_token_service.go
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2025. Gardel <sunxinao@hotmail.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
"github.com/wneessen/go-mail"
|
||||
"text/template"
|
||||
"yggdrasil-go/model"
|
||||
"yggdrasil-go/util"
|
||||
)
|
||||
|
||||
type RegTokenService interface {
|
||||
SendTokenEmail(tokenType RegTokenType, email string) error
|
||||
VerifyToken(accessToken string) (string, error)
|
||||
}
|
||||
|
||||
type RegTokenType uint
|
||||
|
||||
const (
|
||||
RegisterToken RegTokenType = iota
|
||||
ResetPasswordToken
|
||||
)
|
||||
|
||||
type SmtpConfig struct {
|
||||
SmtpServer string
|
||||
SmtpPort int
|
||||
SmtpSsl bool
|
||||
EmailFrom string
|
||||
SmtpUser string
|
||||
SmtpPassword string
|
||||
TitlePrefix string
|
||||
RegisterTemplate string
|
||||
ResetPasswordTemplate string
|
||||
}
|
||||
|
||||
type regTokenServiceImpl struct {
|
||||
tokenCache *lru.Cache
|
||||
smtpServer string
|
||||
smtpPort int
|
||||
smtpSsl bool
|
||||
smtpUser string
|
||||
smtpPassword string
|
||||
emailFrom string
|
||||
titlePrefix string
|
||||
registerTemplate *template.Template
|
||||
resetPasswordTemplate *template.Template
|
||||
}
|
||||
|
||||
func NewRegTokenService(smtpCfg *SmtpConfig) RegTokenService {
|
||||
cache, _ := lru.New(10000000)
|
||||
impl := ®TokenServiceImpl{
|
||||
tokenCache: cache,
|
||||
smtpServer: smtpCfg.SmtpServer,
|
||||
smtpPort: smtpCfg.SmtpPort,
|
||||
smtpSsl: smtpCfg.SmtpSsl,
|
||||
smtpUser: smtpCfg.SmtpUser,
|
||||
smtpPassword: smtpCfg.SmtpPassword,
|
||||
emailFrom: smtpCfg.EmailFrom,
|
||||
titlePrefix: smtpCfg.TitlePrefix,
|
||||
registerTemplate: template.Must(template.New("register").Parse(smtpCfg.RegisterTemplate)),
|
||||
resetPasswordTemplate: template.Must(template.New("resetPassword").Parse(smtpCfg.ResetPasswordTemplate)),
|
||||
}
|
||||
return impl
|
||||
}
|
||||
|
||||
func (r *regTokenServiceImpl) SendTokenEmail(tokenType RegTokenType, email string) error {
|
||||
token := model.NewRegToken(email)
|
||||
r.tokenCache.Add(token.AccessToken, token)
|
||||
|
||||
var subject, body string
|
||||
buf := bytes.Buffer{}
|
||||
switch tokenType {
|
||||
case RegisterToken:
|
||||
subject = fmt.Sprintf("%s 注册验证码", r.titlePrefix)
|
||||
if err := r.registerTemplate.Execute(&buf, token); err != nil {
|
||||
return fmt.Errorf("execute registerTemplate error: %v", err)
|
||||
}
|
||||
body = buf.String()
|
||||
case ResetPasswordToken:
|
||||
subject = fmt.Sprintf("%s 重置密码验证码", r.titlePrefix)
|
||||
if err := r.resetPasswordTemplate.Execute(&buf, token); err != nil {
|
||||
return fmt.Errorf("execute resetPasswordTemplate error: %v", err)
|
||||
}
|
||||
body = buf.String()
|
||||
default:
|
||||
return fmt.Errorf("unknown token type")
|
||||
}
|
||||
|
||||
message := mail.NewMsg()
|
||||
if err := message.From(r.emailFrom); err != nil {
|
||||
return fmt.Errorf("failed to set From address: %s", err)
|
||||
}
|
||||
if err := message.To(email); err != nil {
|
||||
return fmt.Errorf("failed to set To address: %s", err)
|
||||
}
|
||||
message.Subject(subject)
|
||||
message.SetBodyString(mail.TypeTextHTML, body)
|
||||
client, err := mail.NewClient(r.smtpServer, mail.WithPort(r.smtpPort), mail.WithSMTPAuth(mail.SMTPAuthPlain),
|
||||
mail.WithUsername(r.smtpUser), mail.WithPassword(r.smtpPassword))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create mail client: %s", err)
|
||||
}
|
||||
if r.smtpSsl {
|
||||
client.SetSSL(true)
|
||||
}
|
||||
if err := client.DialAndSend(message); err != nil {
|
||||
return fmt.Errorf("failed to send mail: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *regTokenServiceImpl) VerifyToken(accessToken string) (string, error) {
|
||||
token, ok := r.tokenCache.Get(accessToken)
|
||||
if !ok {
|
||||
return "", util.NewIllegalArgumentError(util.MessageInvalidToken)
|
||||
}
|
||||
|
||||
if regToken, ok := token.(model.RegToken); ok {
|
||||
if regToken.IsValid() {
|
||||
r.tokenCache.Remove(accessToken)
|
||||
return regToken.Email, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", util.NewIllegalArgumentError("wrong access token or email")
|
||||
}
|
Reference in New Issue
Block a user