120 lines
3.8 KiB
Go
120 lines
3.8 KiB
Go
package res_init
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.pcux.cn/xuans/Smail/config"
|
|
"git.pcux.cn/xuans/Smail/dto/parsemail"
|
|
"git.pcux.cn/xuans/Smail/services/verification"
|
|
appcontext "git.pcux.cn/xuans/Smail/utils/context"
|
|
"git.pcux.cn/xuans/Smail/utils/send"
|
|
)
|
|
|
|
func newVerificationDelivery() verification.Delivery {
|
|
return newVerificationDeliveryWithDependencies(
|
|
config.CurrentSMTPRuntimeSettings,
|
|
deliverVerificationWithSMTPRelay,
|
|
deliverVerificationWithProjectMail,
|
|
)
|
|
}
|
|
|
|
func newVerificationDeliveryWithDependencies(
|
|
loadSettings func() (config.SMTPRuntimeSettings, error),
|
|
deliverRelay func(config.SMTPRuntimeSettings, verification.Challenge, string) error,
|
|
deliverProject func(verification.Challenge, string) error,
|
|
) verification.Delivery {
|
|
return func(challenge verification.Challenge, code string) error {
|
|
if strings.TrimSpace(challenge.Email) == "" || strings.TrimSpace(code) == "" {
|
|
return verification.ErrInvalidChallenge
|
|
}
|
|
if loadSettings == nil || deliverRelay == nil || deliverProject == nil {
|
|
return verification.ErrProjectMailUnavailable
|
|
}
|
|
|
|
runtimeSettings, err := loadSettings()
|
|
if err != nil {
|
|
return fmt.Errorf("load verification mail settings: %w", err)
|
|
}
|
|
if smtpRelayRequested(runtimeSettings) {
|
|
return deliverRelay(runtimeSettings, challenge, code)
|
|
}
|
|
|
|
return deliverProject(challenge, code)
|
|
}
|
|
}
|
|
|
|
func smtpRelayRequested(settings config.SMTPRuntimeSettings) bool {
|
|
relay := settings.Relay
|
|
return strings.TrimSpace(relay.RelayHost) != "" ||
|
|
strings.TrimSpace(relay.Username) != "" ||
|
|
strings.TrimSpace(settings.Password) != "" ||
|
|
strings.TrimSpace(relay.From) != ""
|
|
}
|
|
|
|
func verificationSMTPSettings(settings config.SMTPRuntimeSettings) (verification.SMTPSettings, error) {
|
|
security, err := smtpSecurityMode(settings.Relay.Security)
|
|
if err != nil {
|
|
return verification.SMTPSettings{}, err
|
|
}
|
|
return verification.SMTPSettings{
|
|
Host: settings.Relay.RelayHost,
|
|
Port: settings.Relay.RelayPort,
|
|
Username: settings.Relay.Username,
|
|
Password: settings.Password,
|
|
Security: security,
|
|
From: settings.Relay.From,
|
|
FromDomain: settings.Relay.FromDomain,
|
|
}, nil
|
|
}
|
|
|
|
func deliverVerificationWithSMTPRelay(runtimeSettings config.SMTPRuntimeSettings, challenge verification.Challenge, code string) error {
|
|
settings, err := verificationSMTPSettings(runtimeSettings)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
delivery, err := verification.NewSMTPDelivery(settings)
|
|
if err != nil {
|
|
return fmt.Errorf("SMTP relay is unavailable: %w", err)
|
|
}
|
|
if err = delivery.Delivery()(challenge, code); err != nil {
|
|
return fmt.Errorf("%w: SMTP relay rejected delivery", verification.ErrMailDeliveryFailed)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func deliverVerificationWithProjectMail(challenge verification.Challenge, code string) error {
|
|
domain := strings.TrimSpace(config.CurrentMailDomains().Primary)
|
|
if domain == "" {
|
|
return fmt.Errorf("%w: primary mail domain is not configured", verification.ErrProjectMailUnavailable)
|
|
}
|
|
messageID, err := parsemail.GenerateMsgID(domain)
|
|
if err != nil {
|
|
return fmt.Errorf("%w: generate message id", verification.ErrProjectMailUnavailable)
|
|
}
|
|
subject, text := verification.CodeMessage(challenge.Purpose, code)
|
|
sender := &parsemail.User{
|
|
Name: "Smail 安全中心",
|
|
EmailAddress: "no-reply@" + domain,
|
|
}
|
|
message := &parsemail.Email{
|
|
From: sender,
|
|
Sender: sender,
|
|
To: []*parsemail.User{
|
|
{EmailAddress: challenge.Email},
|
|
},
|
|
Subject: subject,
|
|
Text: []byte(text),
|
|
MsgID: messageID,
|
|
}
|
|
ctx := &appcontext.Context{
|
|
Context: context.Background(),
|
|
Values: make(map[string]any),
|
|
}
|
|
if deliveryErr, _ := send.SendTriggered(ctx, message, "系统安全验证邮件"); deliveryErr != nil {
|
|
return fmt.Errorf("%w: project mail delivery failed", verification.ErrMailDeliveryFailed)
|
|
}
|
|
return nil
|
|
}
|