package main import ( "fmt" "sync" "time" "github.com/tinode/chat/server/logs" "github.com/tinode/chat/server/store" "github.com/tinode/chat/server/store/types" "github.com/tinode/chat/server/validate" ) const registrationSMSConfigCacheTTL = 30 * time.Second var registrationSMSConfigCache struct { sync.Mutex value bool loaded bool loadedAt time.Time loadValue func() (bool, error) } func registrationSMSEnabled(now time.Time) bool { registrationSMSConfigCache.Lock() defer registrationSMSConfigCache.Unlock() if registrationSMSConfigCache.loaded && now.Sub(registrationSMSConfigCache.loadedAt) < registrationSMSConfigCacheTTL { return registrationSMSConfigCache.value } loader := registrationSMSConfigCache.loadValue if loader == nil { loader = func() (bool, error) { if store.RegistrationConfig == nil { return true, types.ErrUnsupported } return store.RegistrationConfig.SMSEnabled() } } value, err := loader() if err != nil { if registrationSMSConfigCache.loaded { logs.Warn.Println("registration SMS config read failed; using cached value:", err) return registrationSMSConfigCache.value } logs.Warn.Println("registration SMS config read failed; defaulting to enabled:", err) return true } registrationSMSConfigCache.value = value registrationSMSConfigCache.loaded = true registrationSMSConfigCache.loadedAt = now return value } func isValidIMInviteCode(value string) bool { if len(value) != 5 { return false } for i := range value { if (value[i] < 'A' || value[i] > 'Z') && (value[i] < 'a' || value[i] > 'z') { return false } } return true } var sendIMVerificationCode = func(tenantID types.TenantID, recipient, lang, scene, code string) error { if store.Store == nil { return types.ErrInternal } validatorImpl := store.Store.GetValidator("tel") sender, ok := validatorImpl.(validate.CodeSender) if !ok || !validatorImpl.IsInitialized() { return types.ErrUnsupported } if err := sender.SendCode(tenantID, recipient, lang, scene, code); err != nil { return fmt.Errorf("send verification code: %w", err) } return nil }