diff --git a/cfg/dev.yaml b/cfg/dev.yaml index 7536f10ce..524af4dde 100644 --- a/cfg/dev.yaml +++ b/cfg/dev.yaml @@ -55,16 +55,16 @@ probod: secret-access-key: "thisisnotasecret" endpoint: "http://127.0.0.1:9000" - mailer: - sender-name: "Probo" - sender-email: "no-reply@notification.getprobo.com" - smtp: - addr: "localhost:1025" - tls-required: false - - slack: - sender-interval: 60 - signing-secret: "this-is-not-a-secret-for-slack-signing" + notifications: + mailer: + sender-name: "Probo" + sender-email: "no-reply@notification.getprobo.com" + smtp: + addr: "localhost:1025" + tls-required: false + mailer-interval: 60 + slack: + sender-interval: 60 openai: api-key: "thisisnotasecret" @@ -94,3 +94,5 @@ probod: - "chat:write" - "channels:join" - "incoming-webhook" + settings: + signing-secret: "this-is-not-a-secret-for-slack-signing" diff --git a/pkg/mailer/mailer.go b/pkg/mailer/mailer.go index 50f19742f..f134363fa 100644 --- a/pkg/mailer/mailer.go +++ b/pkg/mailer/mailer.go @@ -32,9 +32,10 @@ import ( type ( Mailer struct { - pg *pg.Client - l *log.Logger - cfg Config + pg *pg.Client + l *log.Logger + cfg Config + interval time.Duration } Config struct { @@ -45,6 +46,7 @@ type ( User string Password string TLSRequired bool + Interval time.Duration } ) @@ -53,7 +55,8 @@ func NewMailer(pg *pg.Client, l *log.Logger, cfg Config) *Mailer { if cfg.Timeout == 0 { cfg.Timeout = 10 * time.Second } - return &Mailer{pg: pg, l: l, cfg: cfg} + + return &Mailer{pg: pg, l: l, cfg: cfg, interval: cfg.Interval} } func (m *Mailer) Run(ctx context.Context) error { @@ -61,7 +64,7 @@ LOOP: select { case <-ctx.Done(): return ctx.Err() - case <-time.After(60 * time.Second): + case <-time.After(m.interval): ctx := context.Background() if err := m.batchSendEmails(ctx); err != nil { m.l.ErrorCtx(ctx, "cannot send email", log.Error(err)) diff --git a/pkg/probod/connector_config.go b/pkg/probod/connector_config.go index 661230aab..9a2d32c69 100644 --- a/pkg/probod/connector_config.go +++ b/pkg/probod/connector_config.go @@ -15,6 +15,7 @@ package probod import ( + "bytes" "encoding/json" "fmt" "strings" @@ -27,6 +28,7 @@ type ( Provider string `json:"provider"` Protocol connector.ProtocolType `json:"protocol"` Config connector.Connector `json:"-"` + Settings any `json:"-"` } connectorConfigOAuth2 struct { @@ -39,24 +41,46 @@ type ( } ) +func (c *config) GetSlackSigningSecret() string { + for _, conn := range c.Connectors { + if conn.Provider == "SLACK" { + if settings, ok := conn.Settings.(map[string]any); ok { + if signingSecret, ok := settings["signing-secret"].(string); ok { + return signingSecret + } + } + } + } + return "" +} + func (c *connectorConfig) UnmarshalJSON(data []byte) error { var tmp struct { Provider string `json:"provider"` Protocol string `json:"protocol"` RawConfig json.RawMessage `json:"config"` + Settings json.RawMessage `json:"settings"` } - if err := json.Unmarshal(data, &tmp); err != nil { + if err := json.NewDecoder(bytes.NewReader(data)).Decode(&tmp); err != nil { return fmt.Errorf("cannot unmarshal connector config: %w", err) } c.Provider = strings.ToUpper(tmp.Provider) c.Protocol = connector.ProtocolType(strings.ToUpper(tmp.Protocol)) + if len(tmp.Settings) > 0 { + var settings map[string]any + if err := json.NewDecoder(bytes.NewReader(tmp.Settings)).Decode(&settings); err != nil { + return fmt.Errorf("cannot unmarshal settings: %w", err) + } + c.Settings = settings + } + switch c.Protocol { case connector.ProtocolOAuth2: var config connectorConfigOAuth2 - if err := json.Unmarshal(tmp.RawConfig, &config); err != nil { + if err := json.NewDecoder(bytes.NewReader(tmp.RawConfig)).Decode(&config); err != nil { return fmt.Errorf("cannot unmarshal oauth2 connector config: %w", err) } diff --git a/pkg/probod/mailer_config.go b/pkg/probod/mailer_config.go index 10e3fa164..03c583e6e 100644 --- a/pkg/probod/mailer_config.go +++ b/pkg/probod/mailer_config.go @@ -16,9 +16,10 @@ package probod type ( mailerConfig struct { - SenderName string `json:"sender-name"` - SenderEmail string `json:"sender-email"` - SMTP smtpConfig `json:"smtp"` + MailerInterval int `json:"mailer-interval"` + SenderName string `json:"sender-name"` + SenderEmail string `json:"sender-email"` + SMTP smtpConfig `json:"smtp"` } smtpConfig struct { diff --git a/pkg/probod/notifications_config.go b/pkg/probod/notifications_config.go new file mode 100644 index 000000000..af0d2eee8 --- /dev/null +++ b/pkg/probod/notifications_config.go @@ -0,0 +1,20 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package probod + +type notificationsConfig struct { + Mailer mailerConfig `json:"mailer"` + Slack slackConfig `json:"slack"` +} diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index ee43c941b..003e8805f 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -72,8 +72,7 @@ type ( TrustAuth trustAuthConfig `json:"trust-auth"` TrustCenter trustCenterConfig `json:"trust-center"` AWS awsConfig `json:"aws"` - Mailer mailerConfig `json:"mailer"` - Slack slackConfig `json:"slack"` + Notifications notificationsConfig `json:"notifications"` Connectors []connectorConfig `json:"connectors"` OpenAI openaiConfig `json:"openai"` ChromeDPAddr string `json:"chrome-dp-addr"` @@ -138,15 +137,18 @@ func New() *Implm { Region: "us-east-1", Bucket: "probod", }, - Mailer: mailerConfig{ - SenderEmail: "no-reply@notification.getprobo.com", - SenderName: "Probo", - SMTP: smtpConfig{ - Addr: "localhost:1025", + Notifications: notificationsConfig{ + Mailer: mailerConfig{ + MailerInterval: 60, + SenderEmail: "no-reply@notification.getprobo.com", + SenderName: "Probo", + SMTP: smtpConfig{ + Addr: "localhost:1025", + }, + }, + Slack: slackConfig{ + SenderInterval: 60, }, - }, - Slack: slackConfig{ - SenderInterval: 60, }, CustomDomains: customDomainsConfig{ RenewalInterval: 3600, @@ -346,7 +348,7 @@ func (impl *Implm) Run( impl.cfg.Hostname, impl.cfg.EncryptionKey, impl.cfg.TrustAuth.TokenSecret, - impl.cfg.Slack.SigningSecret, + impl.cfg.GetSlackSigningSecret(), authService, html2pdfConverter, fileManagerService, @@ -405,13 +407,14 @@ func (impl *Implm) Run( mailerCtx, stopMailer := context.WithCancel(context.Background()) mailer := mailer.NewMailer(pgClient, l, mailer.Config{ - SenderEmail: impl.cfg.Mailer.SenderEmail, - SenderName: impl.cfg.Mailer.SenderName, - Addr: impl.cfg.Mailer.SMTP.Addr, - User: impl.cfg.Mailer.SMTP.User, - Password: impl.cfg.Mailer.SMTP.Password, - TLSRequired: impl.cfg.Mailer.SMTP.TLSRequired, + SenderEmail: impl.cfg.Notifications.Mailer.SenderEmail, + SenderName: impl.cfg.Notifications.Mailer.SenderName, + Addr: impl.cfg.Notifications.Mailer.SMTP.Addr, + User: impl.cfg.Notifications.Mailer.SMTP.User, + Password: impl.cfg.Notifications.Mailer.SMTP.Password, + TLSRequired: impl.cfg.Notifications.Mailer.SMTP.TLSRequired, Timeout: time.Second * 10, + Interval: time.Duration(impl.cfg.Notifications.Mailer.MailerInterval) * time.Second, }) wg.Go( func() { @@ -423,7 +426,7 @@ func (impl *Implm) Run( slackSenderCtx, stopSlackSender := context.WithCancel(context.Background()) slackSender := slack.NewSender(pgClient, l.Named("slack-sender"), impl.cfg.EncryptionKey, slack.Config{ - Interval: time.Duration(impl.cfg.Slack.SenderInterval) * time.Second, + Interval: time.Duration(impl.cfg.Notifications.Slack.SenderInterval) * time.Second, }) wg.Go( func() {