Smail/backend/services/auth/protocol_notification.go
smail 9be7a6f990
Some checks are pending
Security Checks / security (push) Waiting to run
检查点:保留通知授权开发状态,开始用户分组隔离
2026-09-25 21:19:28 +08:00

68 lines
2.2 KiB
Go

package auth
import (
"strings"
"time"
"git.pcux.cn/xuans/Smail/db"
"git.pcux.cn/xuans/Smail/models"
"git.pcux.cn/xuans/Smail/services/notification"
)
// 通知身份拥有独立用户名空间,不会回退到普通协议或网页认证。
func authenticateNotification(protocol, remoteAddress, account, plain string) (*models.User, *ProtocolSession, error) {
account = strings.ToLower(strings.TrimSpace(account))
identifier := strings.TrimPrefix(account, notification.UsernamePrefix)
remote := protocolRemoteHost(remoteAddress)
pairKey := hashedProtocolLoginKey("pair", "notification", remote, identifier)
accountKey := hashedProtocolLoginKey("account", identifier)
remoteKey := hashedProtocolLoginKey("remote", remote)
fail := func() (*models.User, *ProtocolSession, error) {
protocolPairAttempts.recordFailure(pairKey)
protocolAccountAttempts.recordFailure(accountKey)
protocolRemoteAttempts.recordFailure(remoteKey)
return nil, nil, notification.ErrDenied
}
if protocolPairAttempts.blocked(pairKey) || protocolAccountAttempts.blocked(accountKey) || protocolRemoteAttempts.blocked(remoteKey) {
return nil, nil, notification.ErrDenied
}
if protocol != "smtp" || db.Instance == nil {
return fail()
}
identifier, err := NormalizeProtocolIdentifier(identifier)
if err != nil {
return fail()
}
identity, err := ResolveIdentifier(identifier)
if err != nil || identity.UserID <= 0 {
return fail()
}
var user models.User
found, err := db.Instance.ID(identity.UserID).Get(&user)
if err != nil || !found {
return fail()
}
grant, err := notification.Authenticate(db.Instance, user, plain)
if err != nil {
return fail()
}
session := &ProtocolSession{user: user, notification: grant}
if err := session.Check(); err != nil {
return fail()
}
protocolPairAttempts.clear(pairKey)
protocolAccountAttempts.clear(accountKey)
return &user, session, nil
}
func (s *ProtocolSession) IsNotification() bool {
return s != nil && s.notification != nil
}
func (s *ProtocolSession) ReserveNotification(recipients int) error {
if !s.IsNotification() || s.Check() != nil {
return notification.ErrDenied
}
return s.notification.Reserve(db.Instance, recipients, time.Now())
}