use single loop for telegram auth and notify

This commit is contained in:
Dmitry Verkhoturov
2021-11-09 02:04:51 -06:00
committed by Umputun
parent c751fbaf37
commit be3643ed10
+68 -53
View File
@@ -454,7 +454,12 @@ func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
return nil, errors.Wrap(err, "failed to make avatar store")
}
authRefreshCache := newAuthRefreshCache()
authenticator, err := s.makeAuthenticator(ctx, dataService, avatarStore, adminStore, authRefreshCache)
authenticator := s.getAuthenticator(dataService, avatarStore, adminStore, authRefreshCache)
telegramAuth := s.makeTelegramAuth(authenticator) // telegram auth requires TelegramAPI listener which is constructed below
telegramService, telegramBotUsername := s.startTelegramAuthAndNotify(ctx, telegramAuth)
err = s.addAuthProviders(authenticator)
if err != nil {
_ = dataService.Close()
return nil, errors.Wrap(err, "failed to make authenticator")
@@ -478,26 +483,7 @@ func (s *ServerCommand) newServerApp(ctx context.Context) (*serverApp, error) {
log.Printf("[WARN] failed to prepare notify destinations, %s", err)
}
// telegramService is used for getting user replies for both notifications and authorization
var telegramService *notify.Telegram
if contains("telegram", s.Notify.Users) || contains("telegram", s.Notify.Admins) || s.Auth.Telegram {
telegramService, err = s.makeTelegramNotify()
if err != nil {
log.Printf("[WARN] failed to make telegram notify service, %s", err)
}
}
var telegramBotUsername string
if telegramService != nil {
if contains("telegram", s.Notify.Users) {
telegramBotUsername = telegramService.GetBotUsername()
}
notifyDestinations = append(notifyDestinations, telegramService)
// start generic update for both notify and auth services
go providers.DispatchTelegramUpdates(ctx, telegramService, []providers.TGUpdatesReceiver{telegramService}, time.Second*5)
}
notifyService := s.makeNotifyService(dataService, notifyDestinations)
notifyService := s.makeNotifyService(dataService, notifyDestinations, telegramService)
imgProxy := &proxy.Image{
HTTP2HTTPS: s.ImageProxy.HTTP2HTTPS,
@@ -785,9 +771,12 @@ func (s *ServerCommand) makeCache() (LoadingCache, error) {
return nil, errors.Errorf("unsupported cache type %s", s.Cache.Type)
}
func (s *ServerCommand) addAuthProviders(ctx context.Context, authenticator *auth.Service) error {
func (s *ServerCommand) addAuthProviders(authenticator *auth.Service) error {
providersCount := 0
if s.Auth.Telegram {
providersCount++
}
if s.Auth.Google.CID != "" && s.Auth.Google.CSEC != "" {
authenticator.AddProvider("google", s.Auth.Google.CID, s.Auth.Google.CSEC)
providersCount++
@@ -816,27 +805,6 @@ func (s *ServerCommand) addAuthProviders(ctx context.Context, authenticator *aut
authenticator.AddProvider("patreon", s.Auth.Patreon.CID, s.Auth.Patreon.CSEC)
providersCount++
}
if s.Auth.Telegram {
telegram := &provider.TelegramHandler{
ProviderName: "telegram",
ErrorMsg: "❌ Invalid auth request. Please try requesting the link again.",
SuccessMsg: "✅ You have successfully authenticated, check the web!",
Telegram: provider.NewTelegramAPI(s.Telegram.Token, &http.Client{Timeout: s.Telegram.Timeout}),
L: log.Default(),
TokenService: authenticator.TokenService(),
AvatarSaver: authenticator.AvatarProxy(),
}
// Run Telegram provider in the background
go func() {
err := telegram.Run(ctx)
if err != nil {
log.Printf("[ERROR] telegram auth error %+v", err)
}
}()
authenticator.AddCustomHandler(telegram)
providersCount++
}
if s.Auth.Dev {
log.Print("[INFO] dev access enabled")
@@ -921,7 +889,31 @@ func (s *ServerCommand) loadEmailTemplate() (string, error) {
return string(file), nil
}
func (s *ServerCommand) makeNotifyService(dataStore *service.DataStore, destinations []notify.Destination) *notify.Service {
// creates and registers telegram auth, which we need separately from other auth providers
func (s *ServerCommand) makeTelegramAuth(authenticator *auth.Service) providers.TGUpdatesReceiver {
if s.Auth.Telegram {
telegram := &provider.TelegramHandler{
ProviderName: "telegram",
SuccessMsg: "✅ You have successfully authenticated, check the web!",
Telegram: provider.NewTelegramAPI(s.Telegram.Token, &http.Client{Timeout: s.Telegram.Timeout}),
L: log.Default(),
TokenService: authenticator.TokenService(),
AvatarSaver: authenticator.AvatarProxy(),
}
authenticator.AddCustomHandler(telegram)
return telegram
}
return nil
}
func (s *ServerCommand) makeNotifyService(dataStore *service.DataStore, destinations []notify.Destination, telegram *notify.Telegram) *notify.Service {
if destinations == nil {
destinations = []notify.Destination{}
}
if telegram != nil {
destinations = append(destinations, telegram)
}
if len(destinations) > 0 {
log.Printf("[INFO] make notify, for users: %s, for admins: %s", s.Notify.Users, s.Notify.Admins)
return notify.NewService(dataStore, s.Notify.QueueSize, destinations...)
@@ -1058,8 +1050,9 @@ func (s *ServerCommand) makeSSLConfig() (config api.SSLConfig, err error) {
return config, err
}
func (s *ServerCommand) makeAuthenticator(ctx context.Context, ds *service.DataStore, avas avatar.Store, admns admin.Store, authRefreshCache *authRefreshCache) (*auth.Service, error) {
authenticator := auth.NewService(auth.Opts{
// getAuthenticator creates new authenticator service, which doesn't have any auth providers enabled
func (s *ServerCommand) getAuthenticator(ds *service.DataStore, avas avatar.Store, admns admin.Store, authRefreshCache *authRefreshCache) *auth.Service {
return auth.NewService(auth.Opts{
URL: strings.TrimSuffix(s.RemarkURL, "/"),
Issuer: "remark42",
TokenDuration: s.Auth.TTL.JWT,
@@ -1114,12 +1107,6 @@ func (s *ServerCommand) makeAuthenticator(ctx context.Context, ds *service.DataS
RefreshCache: authRefreshCache,
UseGravatar: true,
})
if err := s.addAuthProviders(ctx, authenticator); err != nil {
return nil, err
}
return authenticator, nil
}
func (s *ServerCommand) parseSameSite(ss string) http.SameSite {
@@ -1137,6 +1124,34 @@ func (s *ServerCommand) parseSameSite(ss string) http.SameSite {
}
}
// startTelegramAuthAndNotify initializes telegram notify and auth Telegram Bot listen loop.
// Does nothing if telegram auth and notifications are disabled.
// Doesn't return telegram bot username if user notifications are disabled, as that is the way frontend knows they are enabled.
func (s *ServerCommand) startTelegramAuthAndNotify(ctx context.Context, telegramAuth providers.TGUpdatesReceiver) (tg *notify.Telegram, telegramBotUsername string) {
if !contains("telegram", s.Notify.Users) && !contains("telegram", s.Notify.Admins) && !s.Auth.Telegram {
return nil, ""
}
var err error
if tg, err = s.makeTelegramNotify(); err != nil {
log.Printf("[WARN] failed to make telegram notify service, %s", err)
return nil, ""
}
if contains("telegram", s.Notify.Users) {
telegramBotUsername = tg.GetBotUsername()
}
telegramReceivers := []providers.TGUpdatesReceiver{tg}
if telegramAuth != nil {
telegramReceivers = append(telegramReceivers, telegramAuth)
}
// start bot messages receiver for both notify and auth services
go providers.DispatchTelegramUpdates(ctx, tg, telegramReceivers, time.Second*5)
return tg, telegramBotUsername
}
// splitAtCommas split s at commas, ignoring commas in strings.
// Eliminate leading and trailing dbl quotes in each element only if both presented
// based on https://stackoverflow.com/a/59318708