Initial open source release

This commit is contained in:
A 2026-06-04 01:37:39 +08:00
commit 74992e893f
377 changed files with 118084 additions and 0 deletions

View file

@ -0,0 +1,158 @@
package account
import (
"context"
"telesrv/internal/domain"
"telesrv/internal/store"
)
var defaultSecureRandom = []byte("telesrv-tdesktop-dev-secure-rand")
// Service 提供账号安全配置查询。
type Service struct {
passwords store.PasswordStore
reactions store.AccountReactionSettingsStore
}
// ServiceOption 调整 account 服务依赖。
type ServiceOption func(*Service)
// WithReactionSettings 注入账号级 reaction 设置持久化。
func WithReactionSettings(reactions store.AccountReactionSettingsStore) ServiceOption {
return func(s *Service) {
s.reactions = reactions
}
}
// NewService 创建 account 服务。
func NewService(passwords store.PasswordStore, opts ...ServiceOption) *Service {
s := &Service{passwords: passwords}
for _, opt := range opts {
opt(s)
}
return s
}
// GetPassword 返回当前账号 2FA 配置。未登录或无记录时返回持久化策略的默认 no-password 配置。
func (s *Service) GetPassword(ctx context.Context, userID int64) (domain.PasswordSettings, error) {
if s == nil || s.passwords == nil || userID == 0 {
return defaultPasswordSettings(), nil
}
settings, found, err := s.passwords.GetByUser(ctx, userID)
if err != nil {
return domain.PasswordSettings{}, err
}
if !found {
return defaultPasswordSettings(), nil
}
if len(settings.SecureRandom) == 0 {
settings.SecureRandom = append([]byte(nil), defaultSecureRandom...)
}
return settings, nil
}
func defaultPasswordSettings() domain.PasswordSettings {
return domain.PasswordSettings{SecureRandom: append([]byte(nil), defaultSecureRandom...)}
}
// GetReactionSettings returns account-level reaction preferences.
func (s *Service) GetReactionSettings(ctx context.Context, userID int64) (domain.AccountReactionSettings, error) {
if s == nil || s.reactions == nil || userID == 0 {
return domain.DefaultAccountReactionSettings(), nil
}
settings, found, err := s.reactions.GetReactionSettings(ctx, userID)
if err != nil {
return domain.AccountReactionSettings{}, err
}
if !found {
return domain.DefaultAccountReactionSettings(), nil
}
return normalizeReactionSettings(settings), nil
}
// SetReactionsNotifySettings stores reaction notification preferences.
func (s *Service) SetReactionsNotifySettings(ctx context.Context, userID int64, notify domain.ReactionsNotifySettings) (domain.AccountReactionSettings, error) {
settings, err := s.GetReactionSettings(ctx, userID)
if err != nil {
return domain.AccountReactionSettings{}, err
}
settings.Notify = normalizeNotifySettings(notify)
return s.saveReactionSettings(ctx, userID, settings)
}
// SetDefaultReaction stores the account default quick reaction.
func (s *Service) SetDefaultReaction(ctx context.Context, userID int64, reaction domain.MessageReaction) (domain.AccountReactionSettings, error) {
settings, err := s.GetReactionSettings(ctx, userID)
if err != nil {
return domain.AccountReactionSettings{}, err
}
if reaction.Type == "" || reaction.Emoticon == "" {
reaction = domain.DefaultAccountReactionSettings().DefaultReaction
}
settings.DefaultReaction = reaction
return s.saveReactionSettings(ctx, userID, settings)
}
// SetPaidReactionPrivacy stores the account default paid reaction privacy.
func (s *Service) SetPaidReactionPrivacy(ctx context.Context, userID int64, privacy domain.PaidReactionPrivacy) (domain.AccountReactionSettings, error) {
settings, err := s.GetReactionSettings(ctx, userID)
if err != nil {
return domain.AccountReactionSettings{}, err
}
settings.PaidPrivacy = normalizePaidPrivacy(privacy)
return s.saveReactionSettings(ctx, userID, settings)
}
func (s *Service) saveReactionSettings(ctx context.Context, userID int64, settings domain.AccountReactionSettings) (domain.AccountReactionSettings, error) {
settings = normalizeReactionSettings(settings)
if s == nil || s.reactions == nil || userID == 0 {
return settings, nil
}
return settings, s.reactions.SaveReactionSettings(ctx, userID, settings)
}
func normalizeReactionSettings(settings domain.AccountReactionSettings) domain.AccountReactionSettings {
defaults := domain.DefaultAccountReactionSettings()
settings.Notify = normalizeNotifySettings(settings.Notify)
if settings.DefaultReaction.Type == "" || settings.DefaultReaction.Emoticon == "" {
settings.DefaultReaction = defaults.DefaultReaction
}
settings.PaidPrivacy = normalizePaidPrivacy(settings.PaidPrivacy)
return settings
}
func normalizeNotifySettings(settings domain.ReactionsNotifySettings) domain.ReactionsNotifySettings {
if !validNotifyFrom(settings.MessagesFrom) {
settings.MessagesFrom = domain.ReactionNotifyFromContacts
}
if !validNotifyFrom(settings.StoriesFrom) {
settings.StoriesFrom = domain.ReactionNotifyFromContacts
}
if !validNotifyFrom(settings.PollVotesFrom) {
settings.PollVotesFrom = domain.ReactionNotifyFromContacts
}
return settings
}
func validNotifyFrom(value domain.ReactionNotifyFrom) bool {
switch value {
case domain.ReactionNotifyFromNone, domain.ReactionNotifyFromContacts, domain.ReactionNotifyFromAll:
return true
default:
return false
}
}
func normalizePaidPrivacy(privacy domain.PaidReactionPrivacy) domain.PaidReactionPrivacy {
switch privacy.Kind {
case domain.PaidReactionPrivacyAnonymous:
return domain.PaidReactionPrivacy{Kind: domain.PaidReactionPrivacyAnonymous}
case domain.PaidReactionPrivacyPeer:
if privacy.Peer != nil && privacy.Peer.ID != 0 {
peer := *privacy.Peer
return domain.PaidReactionPrivacy{Kind: domain.PaidReactionPrivacyPeer, Peer: &peer}
}
}
return domain.PaidReactionPrivacy{Kind: domain.PaidReactionPrivacyDefault}
}