Refactor entrypoint

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2026-03-05 15:39:50 +01:00
parent fea53b589a
commit 63bf983e59
24 changed files with 1442 additions and 361 deletions

View File

@@ -14,23 +14,20 @@
package probod
import (
"net"
)
// CorsConfig contains CORS settings.
type CorsConfig struct {
AllowedOrigins []string `json:"allowed-origins"`
}
type (
corsConfig struct {
AllowedOrigins []string `json:"allowed-origins"`
}
// ProxyProtocolConfig contains proxy protocol settings.
type ProxyProtocolConfig struct {
TrustedProxies []string `json:"trusted-proxies"`
}
proxyProtocolConfig struct {
TrustedProxies []net.IP `json:"trusted-proxies"`
}
apiConfig struct {
Addr string `json:"addr"`
ProxyProtocol proxyProtocolConfig `json:"proxy-protocol"`
Cors corsConfig `json:"cors"`
ExtraHeaderFields map[string]string `json:"extra-header-fields"`
}
)
// APIConfig contains HTTP API configuration.
type APIConfig struct {
Addr string `json:"addr"`
ProxyProtocol ProxyProtocolConfig `json:"proxy-protocol"`
Cors CorsConfig `json:"cors"`
ExtraHeaderFields map[string]string `json:"extra-header-fields"`
}

View File

@@ -19,32 +19,33 @@ import (
"fmt"
)
type (
authConfig struct {
Cookie cookieConfig `json:"cookie"`
Password passwordConfig `json:"password"`
DisableSignup bool `json:"disable-signup"`
InvitationConfirmationTokenValidity int `json:"invitation-confirmation-token-validity"`
PasswordResetTokenValidity int `json:"password-reset-token-validity"`
MagicLinkTokenValidity int `json:"magic-link-token-validity"`
SAML samlConfig `json:"saml"`
}
// AuthConfig contains authentication configuration.
type AuthConfig struct {
Cookie CookieConfig `json:"cookie"`
Password PasswordConfig `json:"password"`
DisableSignup bool `json:"disable-signup"`
InvitationConfirmationTokenValidity int `json:"invitation-confirmation-token-validity"`
PasswordResetTokenValidity int `json:"password-reset-token-validity"`
MagicLinkTokenValidity int `json:"magic-link-token-validity"`
SAML SAMLConfig `json:"saml"`
}
cookieConfig struct {
Domain string `json:"domain"`
Secret string `json:"secret"`
Duration int `json:"duration"`
Name string `json:"name"`
Secure bool `json:"secure"`
}
// CookieConfig contains session cookie configuration.
type CookieConfig struct {
Domain string `json:"domain"`
Secret string `json:"secret"`
Duration int `json:"duration"`
Name string `json:"name"`
Secure bool `json:"secure"`
}
passwordConfig struct {
Iterations uint32 `json:"iterations"`
Pepper string `json:"pepper"`
}
)
// PasswordConfig contains password hashing configuration.
type PasswordConfig struct {
Iterations int `json:"iterations"`
Pepper string `json:"pepper"`
}
func (c authConfig) GetPepperBytes() ([]byte, error) {
func (c AuthConfig) GetPepperBytes() ([]byte, error) {
if c.Password.Pepper == "" {
return nil, fmt.Errorf("pepper cannot be empty")
}
@@ -63,7 +64,7 @@ func (c authConfig) GetPepperBytes() ([]byte, error) {
return []byte(c.Password.Pepper), nil
}
func (c authConfig) GetCookieSecretBytes() ([]byte, error) {
func (c AuthConfig) GetCookieSecretBytes() ([]byte, error) {
if c.Cookie.Secret == "" {
return nil, fmt.Errorf("cookie secret cannot be empty")
}

View File

@@ -14,13 +14,12 @@
package probod
type (
awsConfig struct {
Region string `json:"region"`
Bucket string `json:"bucket"`
AccessKeyID string `json:"access-key-id"`
SecretAccessKey string `json:"secret-access-key"`
Endpoint string `json:"endpoint"`
UsePathStyle bool `json:"use-path-style"`
}
)
// AWSConfig contains AWS S3 configuration.
type AWSConfig struct {
Region string `json:"region"`
Bucket string `json:"bucket"`
AccessKeyID string `json:"access-key-id"`
SecretAccessKey string `json:"secret-access-key"`
Endpoint string `json:"endpoint"`
UsePathStyle bool `json:"use-path-style"`
}

View File

@@ -23,26 +23,32 @@ import (
"go.probo.inc/probo/pkg/connector"
)
type (
connectorConfig struct {
Provider string `json:"provider"`
Protocol connector.ProtocolType `json:"protocol"`
Config connector.Connector `json:"-"`
Settings any `json:"-"`
// ConnectorConfig contains connector configuration.
type ConnectorConfig struct {
Provider string `json:"provider"`
Protocol connector.ProtocolType `json:"protocol"`
Config connector.Connector `json:"-"`
RawConfig any `json:"config,omitempty"`
Settings any `json:"-"`
RawSettings any `json:"settings,omitempty"`
}
// ConnectorConfigOAuth2 contains OAuth2 connector configuration.
type ConnectorConfigOAuth2 struct {
ClientID string `json:"client-id"`
ClientSecret string `json:"client-secret"`
RedirectURI string `json:"redirect-uri"`
AuthURL string `json:"auth-url"`
TokenURL string `json:"token-url"`
Scopes []string `json:"scopes"`
ExtraAuthParams map[string]string `json:"extra-auth-params,omitempty"`
}
func (c *Config) GetSlackSigningSecret() string {
if c.Notifications.Slack.SigningSecret != "" {
return c.Notifications.Slack.SigningSecret
}
connectorConfigOAuth2 struct {
ClientID string `json:"client-id"`
ClientSecret string `json:"client-secret"`
RedirectURI string `json:"redirect-uri"`
AuthURL string `json:"auth-url"`
TokenURL string `json:"token-url"`
Scopes []string `json:"scopes"`
ExtraAuthParams map[string]string `json:"extra-auth-params,omitempty"`
}
)
func (c *config) GetSlackSigningSecret() string {
for _, conn := range c.Connectors {
if conn.Provider == "SLACK" {
if settings, ok := conn.Settings.(map[string]any); ok {
@@ -55,7 +61,7 @@ func (c *config) GetSlackSigningSecret() string {
return ""
}
func (c *connectorConfig) UnmarshalJSON(data []byte) error {
func (c *ConnectorConfig) UnmarshalJSON(data []byte) error {
var tmp struct {
Provider string `json:"provider"`
Protocol string `json:"protocol"`
@@ -80,7 +86,7 @@ func (c *connectorConfig) UnmarshalJSON(data []byte) error {
switch c.Protocol {
case connector.ProtocolOAuth2:
var config connectorConfigOAuth2
var config ConnectorConfigOAuth2
if err := json.NewDecoder(bytes.NewReader(tmp.RawConfig)).Decode(&config); err != nil {
return fmt.Errorf("cannot unmarshal oauth2 connector config: %w", err)
}

View File

@@ -14,15 +14,17 @@
package probod
type customDomainsConfig struct {
// CustomDomainsConfig contains custom domain configuration.
type CustomDomainsConfig struct {
RenewalInterval int `json:"renewal-interval"`
ProvisionInterval int `json:"provision-interval"`
ResolverAddr string `json:"resolver-addr"`
CnameTarget string `json:"cname-target"`
ACME acmeConfig `json:"acme"`
ACME ACMEConfig `json:"acme"`
}
type acmeConfig struct {
// ACMEConfig contains ACME certificate configuration.
type ACMEConfig struct {
Directory string `json:"directory"`
Email string `json:"email"`
KeyType string `json:"key-type"`

View File

@@ -14,18 +14,18 @@
package probod
type (
mailerConfig struct {
MailerInterval int `json:"mailer-interval"`
SenderName string `json:"sender-name"`
SenderEmail string `json:"sender-email"`
SMTP smtpConfig `json:"smtp"`
}
// MailerConfig contains email mailer configuration.
type MailerConfig struct {
MailerInterval int `json:"mailer-interval"`
SenderName string `json:"sender-name"`
SenderEmail string `json:"sender-email"`
SMTP SMTPConfig `json:"smtp"`
}
smtpConfig struct {
Addr string `json:"addr"`
User string `json:"user"`
Password string `json:"password"`
TLSRequired bool `json:"tls-required"`
}
)
// SMTPConfig contains SMTP server configuration.
type SMTPConfig struct {
Addr string `json:"addr"`
User string `json:"user"`
Password string `json:"password"`
TLSRequired bool `json:"tls-required"`
}

View File

@@ -14,13 +14,15 @@
package probod
type notificationsConfig struct {
Mailer mailerConfig `json:"mailer"`
Slack slackConfig `json:"slack"`
Webhook webhookConfig `json:"webhook"`
// NotificationsConfig contains notification configuration.
type NotificationsConfig struct {
Mailer MailerConfig `json:"mailer"`
Slack SlackConfig `json:"slack"`
Webhook WebhookConfig `json:"webhook"`
}
type webhookConfig struct {
// WebhookConfig contains webhook configuration.
type WebhookConfig struct {
SenderInterval int `json:"sender-interval"`
CacheTTL int `json:"cache-ttl"`
}

View File

@@ -14,7 +14,8 @@
package probod
type openaiConfig struct {
// OpenAIConfig contains OpenAI API configuration.
type OpenAIConfig struct {
APIKey string `json:"api-key"`
Temperature float64 `json:"temperature"`
ModelName string `json:"model-name"`

View File

@@ -21,19 +21,18 @@ import (
"go.gearno.de/kit/pg"
)
type (
pgConfig struct {
Addr string `json:"addr"`
Username string `json:"username"`
Password string `json:"password"`
Database string `json:"database"`
PoolSize int32 `json:"pool-size"`
CACertBundle string `json:"ca-cert-bundle"`
Debug bool `json:"debug"`
}
)
// PgConfig contains PostgreSQL database configuration.
type PgConfig struct {
Addr string `json:"addr"`
Username string `json:"username"`
Password string `json:"password"`
Database string `json:"database"`
PoolSize int32 `json:"pool-size"`
CACertBundle string `json:"ca-cert-bundle"`
Debug bool `json:"debug"`
}
func (cfg pgConfig) Options(options ...pg.Option) []pg.Option {
func (cfg PgConfig) Options(options ...pg.Option) []pg.Option {
opts := []pg.Option{
pg.WithAddr(cfg.Addr),
pg.WithUser(cfg.Username),

View File

@@ -67,34 +67,64 @@ import (
type (
Implm struct {
cfg config
cfg Config
}
esignConfig struct {
// FullConfig represents the complete configuration file structure.
// This is used by bootstrap to generate the YAML config file.
FullConfig struct {
Unit UnitConfig `json:"unit"`
Probod Config `json:"probod"`
}
// UnitConfig contains unit framework configuration.
UnitConfig struct {
Metrics MetricsConfig `json:"metrics"`
Tracing TracingConfig `json:"tracing"`
}
// MetricsConfig contains metrics server configuration.
MetricsConfig struct {
Addr string `json:"addr"`
}
// TracingConfig contains tracing configuration.
TracingConfig struct {
Addr string `json:"addr"`
MaxBatchSize int `json:"max-batch-size"`
BatchTimeout int `json:"batch-timeout"`
ExportTimeout int `json:"export-timeout"`
MaxQueueSize int `json:"max-queue-size"`
}
// ESignConfig contains electronic signature configuration.
ESignConfig struct {
TSAURL string `json:"tsa-url"`
}
config struct {
BaseURL *baseurl.BaseURL `json:"base-url"`
EncryptionKey cipher.EncryptionKey `json:"encryption-key"`
Pg pgConfig `json:"pg"`
Api apiConfig `json:"api"`
Auth authConfig `json:"auth"`
TrustCenter trustCenterConfig `json:"trust-center"`
AWS awsConfig `json:"aws"`
Notifications notificationsConfig `json:"notifications"`
Connectors []connectorConfig `json:"connectors"`
OpenAI openaiConfig `json:"openai"`
ChromeDPAddr string `json:"chrome-dp-addr"`
CustomDomains customDomainsConfig `json:"custom-domains"`
SCIMBridge scimBridgeConfig `json:"scim-bridge"`
ESign esignConfig `json:"esign"`
// Config represents the probod application configuration.
Config struct {
BaseURL string `json:"base-url"`
EncryptionKey string `json:"encryption-key"`
Pg PgConfig `json:"pg"`
Api APIConfig `json:"api"`
Auth AuthConfig `json:"auth"`
TrustCenter TrustCenterConfig `json:"trust-center"`
AWS AWSConfig `json:"aws"`
Notifications NotificationsConfig `json:"notifications"`
Connectors []ConnectorConfig `json:"connectors"`
OpenAI OpenAIConfig `json:"openai"`
ChromeDPAddr string `json:"chrome-dp-addr"`
CustomDomains CustomDomainsConfig `json:"custom-domains"`
SCIMBridge SCIMBridgeConfig `json:"scim-bridge"`
ESign ESignConfig `json:"esign"`
}
trustCenterConfig struct {
// TrustCenterConfig contains trust center server configuration.
TrustCenterConfig struct {
HTTPAddr string `json:"http-addr"`
HTTPSAddr string `json:"https-addr"`
ProxyProtocol proxyProtocolConfig `json:"proxy-protocol"`
ProxyProtocol ProxyProtocolConfig `json:"proxy-protocol"`
}
)
@@ -105,12 +135,12 @@ var (
func New() *Implm {
return &Implm{
cfg: config{
BaseURL: baseurl.MustParse("http://localhost:8080"),
Api: apiConfig{
cfg: Config{
BaseURL: "http://localhost:8080",
Api: APIConfig{
Addr: "localhost:8080",
},
Pg: pgConfig{
Pg: PgConfig{
Addr: "localhost:5432",
Username: "postgres",
Password: "postgres",
@@ -118,12 +148,12 @@ func New() *Implm {
PoolSize: 100,
},
ChromeDPAddr: "localhost:9222",
Auth: authConfig{
Password: passwordConfig{
Auth: AuthConfig{
Password: PasswordConfig{
Pepper: "this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes",
Iterations: 1000000,
},
Cookie: cookieConfig{
Cookie: CookieConfig{
Name: "SSID",
Secret: "this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes",
Duration: 24,
@@ -134,53 +164,53 @@ func New() *Implm {
InvitationConfirmationTokenValidity: 3600,
PasswordResetTokenValidity: 3600,
MagicLinkTokenValidity: 900,
SAML: samlConfig{
SAML: SAMLConfig{
SessionDuration: 604800,
CleanupIntervalSeconds: 86400,
DomainVerificationIntervalSeconds: 60,
DomainVerificationResolverAddr: "8.8.8.8:53",
},
},
TrustCenter: trustCenterConfig{
TrustCenter: TrustCenterConfig{
HTTPAddr: ":80",
HTTPSAddr: ":443",
},
AWS: awsConfig{
AWS: AWSConfig{
Region: "us-east-1",
Bucket: "probod",
},
Notifications: notificationsConfig{
Mailer: mailerConfig{
Notifications: NotificationsConfig{
Mailer: MailerConfig{
MailerInterval: 60,
SenderEmail: "no-reply@notification.getprobo.com",
SenderName: "Probo",
SMTP: smtpConfig{
SMTP: SMTPConfig{
Addr: "localhost:1025",
},
},
Slack: slackConfig{
Slack: SlackConfig{
SenderInterval: 60,
},
Webhook: webhookConfig{
Webhook: WebhookConfig{
SenderInterval: 5,
CacheTTL: 86400,
},
},
CustomDomains: customDomainsConfig{
CustomDomains: CustomDomainsConfig{
RenewalInterval: 3600,
ProvisionInterval: 30,
ResolverAddr: "8.8.8.8:53",
ACME: acmeConfig{
ACME: ACMEConfig{
Directory: "https://acme-v02.api.letsencrypt.org/directory",
Email: "admin@getprobo.com",
KeyType: "EC256",
},
},
SCIMBridge: scimBridgeConfig{
SCIMBridge: SCIMBridgeConfig{
SyncInterval: 60, // 15 minutes
PollInterval: 30, // 30 seconds
},
ESign: esignConfig{
ESign: ESignConfig{
TSAURL: "http://timestamp.digicert.com",
},
},
@@ -201,6 +231,19 @@ func (impl *Implm) Run(
ctx, rootSpan := tracer.Start(parentCtx, "probod.Run")
defer rootSpan.End()
// Parse config values that need conversion from strings to complex types
baseURL, err := baseurl.Parse(impl.cfg.BaseURL)
if err != nil {
rootSpan.RecordError(err)
return fmt.Errorf("cannot parse base URL: %w", err)
}
var encryptionKey cipher.EncryptionKey
if err := encryptionKey.UnmarshalText([]byte(impl.cfg.EncryptionKey)); err != nil {
rootSpan.RecordError(err)
return fmt.Errorf("cannot parse encryption key: %w", err)
}
wg := sync.WaitGroup{}
ctx, cancel := context.WithCancelCause(ctx)
defer cancel(context.Canceled)
@@ -328,8 +371,8 @@ func (impl *Implm) Run(
SessionDuration: time.Duration(impl.cfg.Auth.Cookie.Duration) * time.Hour,
Bucket: impl.cfg.AWS.Bucket,
TokenSecret: impl.cfg.Auth.Cookie.Secret,
BaseURL: impl.cfg.BaseURL,
EncryptionKey: impl.cfg.EncryptionKey,
BaseURL: baseURL,
EncryptionKey: encryptionKey,
Certificate: samlCert,
PrivateKey: samlKey,
Logger: l.Named("iam"),
@@ -378,8 +421,8 @@ func (impl *Implm) Run(
slackService := slack.NewService(
pgClient,
impl.cfg.GetSlackSigningSecret(),
impl.cfg.BaseURL.String(),
impl.cfg.EncryptionKey,
baseURL.String(),
encryptionKey,
impl.cfg.Auth.Cookie.Secret,
l.Named("slack"),
)
@@ -395,11 +438,11 @@ func (impl *Implm) Run(
proboService, err := probo.NewService(
ctx,
impl.cfg.EncryptionKey,
encryptionKey,
pgClient,
s3Client,
impl.cfg.AWS.Bucket,
impl.cfg.BaseURL.String(),
baseURL.String(),
impl.cfg.Auth.Cookie.Secret,
agentConfig,
html2pdfConverter,
@@ -418,8 +461,8 @@ func (impl *Implm) Run(
pgClient,
s3Client,
impl.cfg.AWS.Bucket,
impl.cfg.BaseURL.String(),
impl.cfg.EncryptionKey,
baseURL.String(),
encryptionKey,
impl.cfg.GetSlackSigningSecret(),
iamService,
esignService,
@@ -439,7 +482,7 @@ func (impl *Implm) Run(
ESign: esignService,
Slack: slackService,
ConnectorRegistry: defaultConnectorRegistry,
BaseURL: impl.cfg.BaseURL,
BaseURL: baseURL,
Agent: agent,
CustomDomainCname: impl.cfg.CustomDomains.CnameTarget,
TokenSecret: impl.cfg.Auth.Cookie.Secret,
@@ -495,7 +538,7 @@ func (impl *Implm) Run(
)
slackSenderCtx, stopSlackSender := context.WithCancel(context.Background())
slackSender := slack.NewSender(pgClient, l.Named("slack-sender"), impl.cfg.EncryptionKey, slack.Config{
slackSender := slack.NewSender(pgClient, l.Named("slack-sender"), encryptionKey, slack.Config{
Interval: time.Duration(impl.cfg.Notifications.Slack.SenderInterval) * time.Second,
})
wg.Go(
@@ -510,7 +553,7 @@ func (impl *Implm) Run(
webhookSender := webhook.NewSender(pgClient, l.Named("webhook-sender"), webhook.Config{
Interval: time.Duration(impl.cfg.Notifications.Webhook.SenderInterval) * time.Second,
CacheTTL: time.Duration(impl.cfg.Notifications.Webhook.CacheTTL) * time.Second,
EncryptionKey: impl.cfg.EncryptionKey,
EncryptionKey: encryptionKey,
})
wg.Go(
func() {
@@ -560,6 +603,7 @@ func (impl *Implm) Run(
serverHandler.TrustCenterHandler(),
acmeService,
proboService,
encryptionKey,
); err != nil {
cancel(fmt.Errorf("trust center server crashed: %w", err))
}
@@ -633,7 +677,7 @@ func (impl *Implm) runApiServer(
}
if len(impl.cfg.Api.ProxyProtocol.TrustedProxies) > 0 {
policy := proxyproto.TrustProxyHeaderFrom(impl.cfg.Api.ProxyProtocol.TrustedProxies...)
policy := proxyproto.TrustProxyHeaderFrom(parseIPs(impl.cfg.Api.ProxyProtocol.TrustedProxies)...)
listener = &proxyproto.Listener{
Listener: listener,
@@ -725,14 +769,15 @@ func (impl *Implm) runTrustCenterServer(
trustRouter http.Handler,
acmeService *certmanager.ACMEService,
proboService *probo.Service,
encryptionKey cipher.EncryptionKey,
) error {
tracer := tp.Tracer("go.probo.inc/probo/pkg/probod")
ctx, span := tracer.Start(ctx, "probod.runTrustCenterServer")
defer span.End()
certSelector := certmanager.NewSelector(pgClient, impl.cfg.EncryptionKey)
certSelector := certmanager.NewSelector(pgClient, encryptionKey)
warmer := certmanager.NewCacheStore(pgClient, impl.cfg.EncryptionKey, l)
warmer := certmanager.NewCacheStore(pgClient, encryptionKey, l)
if err := warmer.WarmCache(ctx); err != nil {
span.RecordError(err)
l.ErrorCtx(ctx, "cannot warm certificate cache", log.Error(err))
@@ -743,13 +788,13 @@ func (impl *Implm) runTrustCenterServer(
renewalInterval = time.Hour
}
renewer := certmanager.NewRenewer(pgClient, acmeService, impl.cfg.EncryptionKey, renewalInterval, l)
renewer := certmanager.NewRenewer(pgClient, acmeService, encryptionKey, renewalInterval, l)
certProvisioningInterval := time.Duration(impl.cfg.CustomDomains.ProvisionInterval) * time.Second
if certProvisioningInterval == 0 {
certProvisioningInterval = 30 * time.Second
}
certProvisioner := certmanager.NewProvisioner(pgClient, acmeService, impl.cfg.EncryptionKey, impl.cfg.CustomDomains.CnameTarget, certProvisioningInterval, impl.cfg.CustomDomains.ResolverAddr, l)
certProvisioner := certmanager.NewProvisioner(pgClient, acmeService, encryptionKey, impl.cfg.CustomDomains.CnameTarget, certProvisioningInterval, impl.cfg.CustomDomains.ResolverAddr, l)
g, ctx := errgroup.WithContext(ctx)
@@ -772,7 +817,7 @@ func (impl *Implm) runTrustCenterServer(
httpACMEHandler := certmanager.NewACMEChallengeHandler(
pgClient,
impl.cfg.EncryptionKey,
encryptionKey,
l.Named("http_acme_handler"),
)
@@ -798,7 +843,7 @@ func (impl *Implm) runTrustCenterServer(
defer func() { _ = listener.Close() }()
if len(impl.cfg.TrustCenter.ProxyProtocol.TrustedProxies) > 0 {
policy := proxyproto.TrustProxyHeaderFrom(impl.cfg.TrustCenter.ProxyProtocol.TrustedProxies...)
policy := proxyproto.TrustProxyHeaderFrom(parseIPs(impl.cfg.TrustCenter.ProxyProtocol.TrustedProxies)...)
listener = &proxyproto.Listener{
Listener: listener,
@@ -818,7 +863,7 @@ func (impl *Implm) runTrustCenterServer(
acmeHandler := certmanager.NewACMEChallengeHandler(
pgClient,
impl.cfg.EncryptionKey,
encryptionKey,
l.Named("acme_handler"),
)
@@ -884,7 +929,7 @@ func (impl *Implm) runTrustCenterServer(
defer func() { _ = listener.Close() }()
if len(impl.cfg.TrustCenter.ProxyProtocol.TrustedProxies) > 0 {
policy := proxyproto.TrustProxyHeaderFrom(impl.cfg.TrustCenter.ProxyProtocol.TrustedProxies...)
policy := proxyproto.TrustProxyHeaderFrom(parseIPs(impl.cfg.TrustCenter.ProxyProtocol.TrustedProxies)...)
listener = &proxyproto.Listener{
Listener: listener,
@@ -935,3 +980,15 @@ func (impl *Implm) runTrustCenterServer(
return ctx.Err()
}
// parseIPs converts a slice of string IP addresses to net.IP.
// Invalid IPs are skipped.
func parseIPs(strs []string) []net.IP {
ips := make([]net.IP, 0, len(strs))
for _, s := range strs {
if ip := net.ParseIP(s); ip != nil {
ips = append(ips, ip)
}
}
return ips
}

View File

@@ -18,7 +18,8 @@ import (
"time"
)
type samlConfig struct {
// SAMLConfig contains SAML authentication configuration.
type SAMLConfig struct {
SessionDuration int `json:"session-duration"`
CleanupIntervalSeconds int `json:"cleanup-interval-seconds"`
Certificate string `json:"certificate"`
@@ -27,14 +28,14 @@ type samlConfig struct {
DomainVerificationResolverAddr string `json:"domain-verification-resolver-addr"`
}
func (c samlConfig) SessionDurationTime() time.Duration {
func (c SAMLConfig) SessionDurationTime() time.Duration {
if c.SessionDuration == 0 {
return 7 * 24 * time.Hour
}
return time.Duration(c.SessionDuration) * time.Second
}
func (c samlConfig) CleanupInterval() time.Duration {
func (c SAMLConfig) CleanupInterval() time.Duration {
if c.CleanupIntervalSeconds == 0 {
return 0
}
@@ -42,6 +43,6 @@ func (c samlConfig) CleanupInterval() time.Duration {
return time.Duration(c.CleanupIntervalSeconds) * time.Second
}
func (c samlConfig) DomainVerificationInterval() time.Duration {
func (c SAMLConfig) DomainVerificationInterval() time.Duration {
return time.Duration(c.DomainVerificationIntervalSeconds) * time.Second
}

View File

@@ -14,7 +14,8 @@
package probod
type scimBridgeConfig struct {
// SCIMBridgeConfig contains SCIM bridge configuration.
type SCIMBridgeConfig struct {
// SyncInterval is the time between sync attempts for each bridge (in seconds).
// Default: 900 (15 minutes)
SyncInterval int `json:"sync-interval"`

View File

@@ -14,9 +14,8 @@
package probod
type (
slackConfig struct {
SenderInterval int `json:"sender-interval"`
SigningSecret string `json:"signing-secret"`
}
)
// SlackConfig contains Slack notification configuration.
type SlackConfig struct {
SenderInterval int `json:"sender-interval"`
SigningSecret string `json:"signing-secret"`
}