feat: Notification providers config (#3212)

* feat: add login check lifetimes to login policy

* feat: org features test

* feat: debug notificatiaon events

* feat: debug notification file/log commands

* feat: add requests to proto

* feat: add api for debug notification providers file/log

* feat: add projection for debug notifiication providers

* feat: requests

* feat: merge v2

* feat: add settings proto to generate

* feat: notifiaction providers

* fix: remove unused code

* Update iam_converter.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi
2022-03-07 14:22:37 +01:00
committed by GitHub
parent 7d6c933485
commit 7899a0b851
47 changed files with 2489 additions and 200 deletions

View File

@@ -1,80 +0,0 @@
package chat
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/url"
"unicode/utf8"
"github.com/k3a/html2text"
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/notification/channels"
)
func InitChatChannel(config ChatConfig) (channels.NotificationChannel, error) {
url, err := url.Parse(config.Url)
if err != nil {
return nil, err
}
logging.Log("NOTIF-kSvPp").Debug("successfully initialized chat email and sms channel")
return channels.HandleMessageFunc(func(message channels.Message) error {
contentText := message.GetContent()
if config.Compact {
contentText = html2text.HTML2Text(contentText)
}
for _, splittedMsg := range splitMessage(contentText, config.SplitCount) {
if err := sendMessage(splittedMsg, url); err != nil {
return err
}
}
return nil
}), nil
}
func sendMessage(message string, chatUrl *url.URL) error {
chatMsg := &struct {
Text string `json:"text"`
}{Text: message}
req, err := json.Marshal(chatMsg)
if err != nil {
return caos_errs.ThrowInternal(err, "PROVI-s8uie", "Could not unmarshal content")
}
response, err := http.Post(chatUrl.String(), "application/json; charset=UTF-8", bytes.NewReader(req))
if err != nil {
return caos_errs.ThrowInternal(err, "PROVI-si93s", "unable to send message")
}
if response.StatusCode != 200 {
defer response.Body.Close()
bodyBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
return caos_errs.ThrowInternal(err, "PROVI-PSLd3", "unable to read response message")
}
logging.LogWithFields("PROVI-PS0kx", "Body", string(bodyBytes)).Warn("Chat Message post didnt get 200 OK")
return caos_errs.ThrowInternal(nil, "PROVI-LSopw", string(bodyBytes))
}
return nil
}
func splitMessage(message string, count int) []string {
if count == 0 {
return []string{message}
}
var splits []string
var l, r int
for l, r = 0, count; r < len(message); l, r = r, r+count {
for !utf8.RuneStart(message[r]) {
r--
}
splits = append(splits, message[l:r])
}
splits = append(splits, message[l:])
return splits
}

View File

@@ -1,9 +0,0 @@
package chat
type ChatConfig struct {
// Defaults to true if DebugMode is set to true
Enabled *bool
Url string
SplitCount int
Compact bool
}

View File

@@ -19,9 +19,11 @@ import (
"github.com/caos/zitadel/internal/notification/messages"
)
func InitFSChannel(config FSConfig) (channels.NotificationChannel, error) {
if err := os.MkdirAll(config.Path, os.ModePerm); err != nil {
func InitFSChannel(path string, config FSConfig) (channels.NotificationChannel, error) {
if path == "" {
return nil, nil
}
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return nil, err
}
@@ -46,6 +48,6 @@ func InitFSChannel(config FSConfig) (channels.NotificationChannel, error) {
return caos_errors.ThrowUnimplementedf(nil, "NOTIF-6f9a1", "filesystem provider doesn't support message type %T", message)
}
return ioutil.WriteFile(filepath.Join(config.Path, fileName), []byte(content), 0666)
return ioutil.WriteFile(filepath.Join(path, fileName), []byte(content), 0666)
}), nil
}

View File

@@ -2,6 +2,5 @@ package fs
type FSConfig struct {
Enabled bool
Path string
Compact bool
}

View File

@@ -24,12 +24,15 @@ type Email struct {
func InitSMTPChannel(ctx context.Context, getSMTPConfig func(ctx context.Context) (*EmailConfig, error)) (*Email, error) {
smtpConfig, err := getSMTPConfig(ctx)
if err != nil {
return nil, err
}
client, err := smtpConfig.SMTP.connectToSMTP(smtpConfig.Tls)
if err != nil {
return nil, err
}
logging.Log("NOTIF-4n4Ih").Debug("successfully initialized smtp email channel")
logging.New().Debug("successfully initialized smtp email channel")
return &Email{
smtpClient: client,

View File

@@ -18,10 +18,10 @@ type Config struct {
Repository eventsourcing.Config
}
func Start(config Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *sql.DB, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm) {
func Start(config Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *sql.DB, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm, smsCrypto *crypto.AESCrypto) {
statikFS, err := fs.NewWithNamespace("notification")
logging.OnError(err).Panic("unable to start listener")
_, err = eventsourcing.Start(config.Repository, statikFS, systemDefaults, command, queries, dbClient, assetsPrefix, smtpPasswordEncAlg)
_, err = eventsourcing.Start(config.Repository, statikFS, systemDefaults, command, queries, dbClient, assetsPrefix, smtpPasswordEncAlg, smsCrypto)
logging.OnError(err).Panic("unable to start app")
}

View File

@@ -34,7 +34,7 @@ func (h *handler) Eventstore() v1.Eventstore {
return h.es
}
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, command *command.Commands, queries *query.Queries, systemDefaults sd.SystemDefaults, dir http.FileSystem, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm) []queryv1.Handler {
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, command *command.Commands, queries *query.Queries, systemDefaults sd.SystemDefaults, dir http.FileSystem, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm, smsCrypto *crypto.AESCrypto) []queryv1.Handler {
aesCrypto, err := crypto.NewAESCrypto(systemDefaults.UserVerificationKey)
logging.OnError(err).Fatal("error create new aes crypto")
@@ -52,6 +52,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
dir,
assetsPrefix,
smtpPasswordEncAlg,
smsCrypto,
),
}
}

View File

@@ -7,6 +7,9 @@ import (
"time"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/twilio"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/command"
@@ -43,18 +46,10 @@ type Notification struct {
assetsPrefix string
queries *query.Queries
smtpPasswordCrypto crypto.EncryptionAlgorithm
smsTokenCrypto crypto.EncryptionAlgorithm
}
func newNotification(
handler handler,
command *command.Commands,
query *query.Queries,
defaults sd.SystemDefaults,
aesCrypto crypto.EncryptionAlgorithm,
statikDir http.FileSystem,
assetsPrefix string,
smtpPasswordEncAlg crypto.EncryptionAlgorithm,
) *Notification {
func newNotification(handler handler, command *command.Commands, query *query.Queries, defaults sd.SystemDefaults, aesCrypto crypto.EncryptionAlgorithm, statikDir http.FileSystem, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm, smsCrypto *crypto.AESCrypto) *Notification {
h := &Notification{
handler: handler,
command: command,
@@ -64,6 +59,7 @@ func newNotification(
assetsPrefix: assetsPrefix,
queries: query,
smtpPasswordCrypto: smtpPasswordEncAlg,
smsTokenCrypto: smsCrypto,
}
h.subscribe()
@@ -165,7 +161,7 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
return err
}
err = types.SendUserInitCode(ctx, string(template.Template), translator, user, initCode, n.systemDefaults, n.getSMTPConfig, n.AesCrypto, colors, n.assetsPrefix)
err = types.SendUserInitCode(ctx, string(template.Template), translator, user, initCode, n.systemDefaults, n.getSMTPConfig, n.getFileSystemProvider, n.getLogProvider, n.AesCrypto, colors, n.assetsPrefix)
if err != nil {
return err
}
@@ -203,7 +199,7 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) {
if err != nil {
return err
}
err = types.SendPasswordCode(ctx, string(template.Template), translator, user, pwCode, n.systemDefaults, n.getSMTPConfig, n.AesCrypto, colors, n.assetsPrefix)
err = types.SendPasswordCode(ctx, string(template.Template), translator, user, pwCode, n.systemDefaults, n.getSMTPConfig, n.getTwilioConfig, n.getFileSystemProvider, n.getLogProvider, n.AesCrypto, colors, n.assetsPrefix)
if err != nil {
return err
}
@@ -242,7 +238,7 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err
return err
}
err = types.SendEmailVerificationCode(ctx, string(template.Template), translator, user, emailCode, n.systemDefaults, n.getSMTPConfig, n.AesCrypto, colors, n.assetsPrefix)
err = types.SendEmailVerificationCode(ctx, string(template.Template), translator, user, emailCode, n.systemDefaults, n.getSMTPConfig, n.getFileSystemProvider, n.getLogProvider, n.AesCrypto, colors, n.assetsPrefix)
if err != nil {
return err
}
@@ -268,7 +264,7 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err
if err != nil {
return err
}
err = types.SendPhoneVerificationCode(translator, user, phoneCode, n.systemDefaults, n.AesCrypto)
err = types.SendPhoneVerificationCode(context.Background(), translator, user, phoneCode, n.systemDefaults, n.getTwilioConfig, n.getFileSystemProvider, n.getLogProvider, n.AesCrypto)
if err != nil {
return err
}
@@ -308,7 +304,7 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
return err
}
err = types.SendDomainClaimed(ctx, string(template.Template), translator, user, data["userName"], n.systemDefaults, n.getSMTPConfig, colors, n.assetsPrefix)
err = types.SendDomainClaimed(ctx, string(template.Template), translator, user, data["userName"], n.systemDefaults, n.getSMTPConfig, n.getFileSystemProvider, n.getLogProvider, colors, n.assetsPrefix)
if err != nil {
return err
}
@@ -355,7 +351,7 @@ func (n *Notification) handlePasswordlessRegistrationLink(event *models.Event) (
return err
}
err = types.SendPasswordlessRegistrationLink(ctx, string(template.Template), translator, user, addedEvent, n.systemDefaults, n.getSMTPConfig, n.AesCrypto, colors, n.assetsPrefix)
err = types.SendPasswordlessRegistrationLink(ctx, string(template.Template), translator, user, addedEvent, n.systemDefaults, n.getSMTPConfig, n.getFileSystemProvider, n.getLogProvider, n.AesCrypto, colors, n.assetsPrefix)
if err != nil {
return err
}
@@ -394,7 +390,7 @@ func (n *Notification) getUserEvents(userID string, sequence uint64) ([]*models.
}
func (n *Notification) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-s9opc", "id", event.AggregateID, "sequence", event.Sequence).WithError(err).Warn("something went wrong in notification handler")
logging.WithFields("id", event.AggregateID, "sequence", event.Sequence).WithError(err).Warn("something went wrong in notification handler")
return spooler.HandleError(event, err, n.view.GetLatestNotificationFailedEvent, n.view.ProcessedNotificationFailedEvent, n.view.ProcessedNotificationSequence, n.errorCountUntilSkip)
}
@@ -437,6 +433,48 @@ func (n *Notification) getSMTPConfig(ctx context.Context) (*smtp.EmailConfig, er
}, nil
}
// Read iam twilio config
func (n *Notification) getTwilioConfig(ctx context.Context) (*twilio.TwilioConfig, error) {
config, err := n.queries.SMSProviderConfigByID(ctx, domain.IAMID)
if err != nil {
return nil, err
}
if config.TwilioConfig == nil {
return nil, errors.ThrowNotFound(nil, "HANDLER-8nfow", "Errors.SMS.Twilio.NotFound")
}
token, err := crypto.Decrypt(config.TwilioConfig.Token, n.smtpPasswordCrypto)
if err != nil {
return nil, err
}
return &twilio.TwilioConfig{
SID: config.TwilioConfig.SID,
Token: string(token),
SenderNumber: config.TwilioConfig.SenderNumber,
}, nil
}
// Read iam filesystem provider config
func (n *Notification) getFileSystemProvider(ctx context.Context) (*fs.FSConfig, error) {
config, err := n.queries.NotificationProviderByIDAndType(ctx, domain.IAMID, domain.NotificationProviderTypeFile)
if err != nil {
return nil, err
}
return &fs.FSConfig{
Compact: config.Compact,
}, nil
}
// Read iam log provider config
func (n *Notification) getLogProvider(ctx context.Context) (*log.LogConfig, error) {
config, err := n.queries.NotificationProviderByIDAndType(ctx, domain.IAMID, domain.NotificationProviderTypeLog)
if err != nil {
return nil, err
}
return &log.LogConfig{
Compact: config.Compact,
}, nil
}
func (n *Notification) getTranslatorWithOrgTexts(orgID, textType string) (*i18n.Translator, error) {
ctx := context.Background()
translator, err := i18n.NewTranslator(n.statikDir, i18n.TranslatorConfig{DefaultLanguage: n.queries.GetDefaultLanguage(ctx)})

View File

@@ -22,7 +22,7 @@ type EsRepository struct {
spooler *es_spol.Spooler
}
func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *sql.DB, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm) (*EsRepository, error) {
func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *sql.DB, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm, smsCrypto *crypto.AESCrypto) (*EsRepository, error) {
es, err := v1.Start(dbClient)
if err != nil {
return nil, err
@@ -33,7 +33,7 @@ func Start(conf Config, dir http.FileSystem, systemDefaults sd.SystemDefaults, c
return nil, err
}
spool := spooler.StartSpooler(conf.Spooler, es, view, dbClient, command, queries, systemDefaults, dir, assetsPrefix, smtpPasswordEncAlg)
spool := spooler.StartSpooler(conf.Spooler, es, view, dbClient, command, queries, systemDefaults, dir, assetsPrefix, smtpPasswordEncAlg, smsCrypto)
return &EsRepository{
spool,

View File

@@ -21,12 +21,12 @@ type SpoolerConfig struct {
Handlers handler.Configs
}
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, command *command.Commands, queries *query.Queries, systemDefaults sd.SystemDefaults, dir http.FileSystem, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm) *spooler.Spooler {
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, command *command.Commands, queries *query.Queries, systemDefaults sd.SystemDefaults, dir http.FileSystem, assetsPrefix string, smtpPasswordEncAlg crypto.EncryptionAlgorithm, smsCrypto *crypto.AESCrypto) *spooler.Spooler {
spoolerConfig := spooler.Config{
Eventstore: es,
Locker: &locker{dbClient: sql},
ConcurrentWorkers: c.ConcurrentWorkers,
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, queries, systemDefaults, dir, assetsPrefix, smtpPasswordEncAlg),
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, command, queries, systemDefaults, dir, assetsPrefix, smtpPasswordEncAlg, smsCrypto),
}
spool := spoolerConfig.New()
spool.Start()

View File

@@ -22,3 +22,7 @@ func (c *Chain) HandleMessage(message channels.Message) error {
}
return nil
}
func (c *Chain) Len() int {
return len(c.channels)
}

View File

@@ -1,45 +1,28 @@
package senders
import (
"context"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/notification/channels"
"github.com/caos/zitadel/internal/notification/channels/chat"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
)
func debugChannels(config systemdefaults.Notifications) (channels.NotificationChannel, error) {
func debugChannels(ctx context.Context, config systemdefaults.Notifications, getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error)) (*Chain, error) {
var (
providers []channels.NotificationChannel
enableChat bool
providers []channels.NotificationChannel
)
if config.Providers.Chat.Enabled != nil {
enableChat = *config.Providers.Chat.Enabled
} else {
// ensures backward compatible configuration
enableChat = config.DebugMode
}
if enableChat {
p, err := chat.InitChatChannel(config.Providers.Chat)
if err != nil {
return nil, err
if fsProvider, err := getFileSystemProvider(ctx); err == nil {
p, err := fs.InitFSChannel(config.FileSystemPath, *fsProvider)
if err == nil {
providers = append(providers, p)
}
providers = append(providers, p)
}
if config.Providers.FileSystem.Enabled {
p, err := fs.InitFSChannel(config.Providers.FileSystem)
if err != nil {
return nil, err
}
providers = append(providers, p)
}
if config.Providers.Log.Enabled {
providers = append(providers, log.InitStdoutChannel(config.Providers.Log))
if logProvider, err := getLogProvider(ctx); err == nil {
providers = append(providers, log.InitStdoutChannel(*logProvider))
}
return chainChannels(providers...), nil

View File

@@ -3,25 +3,21 @@ package senders
import (
"context"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/notification/channels"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
)
func EmailChannels(ctx context.Context, config systemdefaults.Notifications, emailConfig func(ctx context.Context) (*smtp.EmailConfig, error)) (channels.NotificationChannel, error) {
debug, err := debugChannels(config)
func EmailChannels(ctx context.Context, config systemdefaults.Notifications, emailConfig func(ctx context.Context) (*smtp.EmailConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error)) (chain *Chain, err error) {
p, err := smtp.InitSMTPChannel(ctx, emailConfig)
if err == nil {
chain.channels = append(chain.channels, p)
}
chain, err = debugChannels(ctx, config, getFileSystemProvider, getLogProvider)
if err != nil {
return nil, err
logging.New().Info("Error in creating debug channels")
}
if !config.DebugMode {
p, err := smtp.InitSMTPChannel(ctx, emailConfig)
if err != nil {
return nil, err
}
return chainChannels(debug, p), nil
}
return debug, nil
return chain, nil
}

View File

@@ -1,21 +1,21 @@
package senders
import (
"context"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/notification/channels"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/twilio"
)
func SMSChannels(config systemdefaults.Notifications) (channels.NotificationChannel, error) {
debug, err := debugChannels(config)
func SMSChannels(ctx context.Context, config systemdefaults.Notifications, twilioConfig *twilio.TwilioConfig, getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error)) (chain *Chain, err error) {
if twilioConfig != nil {
chain.channels = append(chain.channels, twilio.InitTwilioChannel(*twilioConfig))
}
chain, err = debugChannels(ctx, config, getFileSystemProvider, getLogProvider)
if err != nil {
return nil, err
}
if !config.DebugMode {
return chainChannels(debug, twilio.InitTwilioChannel(config.Providers.Twilio)), nil
}
return debug, nil
return chain, nil
}

View File

@@ -7,6 +7,8 @@ import (
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/query"
@@ -18,7 +20,7 @@ type DomainClaimedData struct {
URL string
}
func SendDomainClaimed(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, username string, systemDefaults systemdefaults.SystemDefaults, emailConfig func(ctx context.Context) (*smtp.EmailConfig, error), colors *query.LabelPolicy, assetsPrefix string) error {
func SendDomainClaimed(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, username string, systemDefaults systemdefaults.SystemDefaults, emailConfig func(ctx context.Context) (*smtp.EmailConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), colors *query.LabelPolicy, assetsPrefix string) error {
url, err := templates.ParseTemplateText(systemDefaults.Notifications.Endpoints.DomainClaimed, &UrlData{UserID: user.ID})
if err != nil {
return err
@@ -35,5 +37,5 @@ func SendDomainClaimed(ctx context.Context, mailhtml string, translator *i18n.Tr
if err != nil {
return err
}
return generateEmail(ctx, user, domainClaimedData.Subject, template, systemDefaults.Notifications, emailConfig, true)
return generateEmail(ctx, user, domainClaimedData.Subject, template, systemDefaults.Notifications, emailConfig, getFileSystemProvider, getLogProvider, true)
}

View File

@@ -7,6 +7,8 @@ import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/query"
@@ -19,7 +21,7 @@ type EmailVerificationCodeData struct {
URL string
}
func SendEmailVerificationCode(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.EmailCode, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
func SendEmailVerificationCode(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.EmailCode, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
codeString, err := crypto.DecryptString(code.Code, alg)
if err != nil {
return err
@@ -41,5 +43,5 @@ func SendEmailVerificationCode(ctx context.Context, mailhtml string, translator
if err != nil {
return err
}
return generateEmail(ctx, user, emailCodeData.Subject, template, systemDefaults.Notifications, smtpConfig, true)
return generateEmail(ctx, user, emailCodeData.Subject, template, systemDefaults.Notifications, smtpConfig, getFileSystemProvider, getLogProvider, true)
}

View File

@@ -7,6 +7,8 @@ import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/query"
@@ -25,7 +27,7 @@ type UrlData struct {
PasswordSet bool
}
func SendUserInitCode(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.InitUserCode, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
func SendUserInitCode(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.InitUserCode, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
codeString, err := crypto.DecryptString(code.Code, alg)
if err != nil {
return err
@@ -45,5 +47,5 @@ func SendUserInitCode(ctx context.Context, mailhtml string, translator *i18n.Tra
if err != nil {
return err
}
return generateEmail(ctx, user, initCodeData.Subject, template, systemDefaults.Notifications, smtpConfig, true)
return generateEmail(ctx, user, initCodeData.Subject, template, systemDefaults.Notifications, smtpConfig, getFileSystemProvider, getLogProvider, true)
}

View File

@@ -7,7 +7,10 @@ import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/notification/channels/twilio"
"github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/query"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
@@ -21,7 +24,7 @@ type PasswordCodeData struct {
URL string
}
func SendPasswordCode(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.PasswordCode, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
func SendPasswordCode(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.PasswordCode, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), getTwilioConfig func(ctx context.Context) (*twilio.TwilioConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
codeString, err := crypto.DecryptString(code.Code, alg)
if err != nil {
return err
@@ -44,8 +47,8 @@ func SendPasswordCode(ctx context.Context, mailhtml string, translator *i18n.Tra
return err
}
if code.NotificationType == int32(domain.NotificationTypeSms) {
return generateSms(user, passwordResetData.Text, systemDefaults.Notifications, false)
return generateSms(ctx, user, passwordResetData.Text, systemDefaults.Notifications, getTwilioConfig, getFileSystemProvider, getLogProvider, false)
}
return generateEmail(ctx, user, passwordResetData.Subject, template, systemDefaults.Notifications, smtpConfig, true)
return generateEmail(ctx, user, passwordResetData.Subject, template, systemDefaults.Notifications, smtpConfig, getFileSystemProvider, getLogProvider, true)
}

View File

@@ -7,6 +7,8 @@ import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/notification/templates"
"github.com/caos/zitadel/internal/query"
@@ -19,7 +21,7 @@ type PasswordlessRegistrationLinkData struct {
URL string
}
func SendPasswordlessRegistrationLink(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *user.HumanPasswordlessInitCodeRequestedEvent, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
func SendPasswordlessRegistrationLink(ctx context.Context, mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *user.HumanPasswordlessInitCodeRequestedEvent, systemDefaults systemdefaults.SystemDefaults, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), alg crypto.EncryptionAlgorithm, colors *query.LabelPolicy, assetsPrefix string) error {
codeString, err := crypto.DecryptString(code.Code, alg)
if err != nil {
return err
@@ -36,5 +38,5 @@ func SendPasswordlessRegistrationLink(ctx context.Context, mailhtml string, tran
if err != nil {
return err
}
return generateEmail(ctx, user, emailCodeData.Subject, template, systemDefaults.Notifications, smtpConfig, true)
return generateEmail(ctx, user, emailCodeData.Subject, template, systemDefaults.Notifications, smtpConfig, getFileSystemProvider, getLogProvider, true)
}

View File

@@ -1,12 +1,16 @@
package types
import (
"context"
"fmt"
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/i18n"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/twilio"
"github.com/caos/zitadel/internal/notification/templates"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
@@ -16,7 +20,7 @@ type PhoneVerificationCodeData struct {
UserID string
}
func SendPhoneVerificationCode(translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.PhoneCode, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm) error {
func SendPhoneVerificationCode(ctx context.Context, translator *i18n.Translator, user *view_model.NotifyUser, code *es_model.PhoneCode, systemDefaults systemdefaults.SystemDefaults, getTwilioConfig func(ctx context.Context) (*twilio.TwilioConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), alg crypto.EncryptionAlgorithm) error {
codeString, err := crypto.DecryptString(code.Code, alg)
if err != nil {
return err
@@ -31,5 +35,5 @@ func SendPhoneVerificationCode(translator *i18n.Translator, user *view_model.Not
if err != nil {
return err
}
return generateSms(user, template, systemDefaults.Notifications, true)
return generateSms(ctx, user, template, systemDefaults.Notifications, getTwilioConfig, getFileSystemProvider, getLogProvider, true)
}

View File

@@ -4,6 +4,9 @@ import (
"context"
"html"
caos_errors "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/smtp"
"github.com/caos/zitadel/internal/notification/messages"
"github.com/caos/zitadel/internal/notification/senders"
@@ -12,7 +15,7 @@ import (
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
func generateEmail(ctx context.Context, user *view_model.NotifyUser, subject, content string, config systemdefaults.Notifications, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), lastEmail bool) error {
func generateEmail(ctx context.Context, user *view_model.NotifyUser, subject, content string, config systemdefaults.Notifications, smtpConfig func(ctx context.Context) (*smtp.EmailConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), lastEmail bool) error {
content = html.UnescapeString(content)
message := &messages.Email{
Recipients: []string{user.VerifiedEmail},
@@ -23,12 +26,15 @@ func generateEmail(ctx context.Context, user *view_model.NotifyUser, subject, co
message.Recipients = []string{user.LastEmail}
}
channels, err := senders.EmailChannels(ctx, config, smtpConfig)
channelChain, err := senders.EmailChannels(ctx, config, smtpConfig, getFileSystemProvider, getLogProvider)
if err != nil {
return err
}
return channels.HandleMessage(message)
if channelChain.Len() == 0 {
return caos_errors.ThrowPreconditionFailed(nil, "MAIL-83nof", "Errors.Notification.Channels.NotPresent")
}
return channelChain.HandleMessage(message)
}
func mapNotifyUserToArgs(user *view_model.NotifyUser) map[string]interface{} {

View File

@@ -1,15 +1,26 @@
package types
import (
"context"
"github.com/caos/zitadel/internal/config/systemdefaults"
caos_errors "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/notification/channels/fs"
"github.com/caos/zitadel/internal/notification/channels/log"
"github.com/caos/zitadel/internal/notification/channels/twilio"
"github.com/caos/zitadel/internal/notification/messages"
"github.com/caos/zitadel/internal/notification/senders"
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
)
func generateSms(user *view_model.NotifyUser, content string, config systemdefaults.Notifications, lastPhone bool) error {
func generateSms(ctx context.Context, user *view_model.NotifyUser, content string, config systemdefaults.Notifications, getTwilioProvider func(ctx context.Context) (*twilio.TwilioConfig, error), getFileSystemProvider func(ctx context.Context) (*fs.FSConfig, error), getLogProvider func(ctx context.Context) (*log.LogConfig, error), lastPhone bool) error {
number := ""
twilio, err := getTwilioProvider(ctx)
if err == nil {
number = twilio.SenderNumber
}
message := &messages.SMS{
SenderPhoneNumber: config.Providers.Twilio.SenderNumber,
SenderPhoneNumber: number,
RecipientPhoneNumber: user.VerifiedPhone,
Content: content,
}
@@ -17,9 +28,10 @@ func generateSms(user *view_model.NotifyUser, content string, config systemdefau
message.RecipientPhoneNumber = user.LastPhone
}
channels, err := senders.SMSChannels(config)
if err != nil {
return err
channelChain, err := senders.SMSChannels(ctx, config, twilio, getFileSystemProvider, getLogProvider)
if channelChain.Len() == 0 {
return caos_errors.ThrowPreconditionFailed(nil, "PHONE-w8nfow", "Errors.Notification.Channels.NotPresent")
}
return channels.HandleMessage(message)
return channelChain.HandleMessage(message)
}