From a7f5374acc1314bbfb806d54f6d9c4cca60e6836 Mon Sep 17 00:00:00 2001 From: Stavros Date: Sat, 13 Jun 2026 17:14:47 +0300 Subject: [PATCH] refactor: use one struct for service deps --- internal/bootstrap/app_bootstrap.go | 26 ++++------- internal/bootstrap/router_bootstrap.go | 20 ++++---- internal/bootstrap/service_bootstrap.go | 48 +++++++++++-------- internal/service/access_controls_service.go | 13 +++--- internal/service/auth_service.go | 35 ++++++-------- internal/service/docker_service.go | 16 +++---- internal/service/kubernetes_service.go | 16 +++---- internal/service/ldap_service.go | 32 ++++++------- internal/service/oauth_broker_service.go | 14 +++--- internal/service/oidc_service.go | 51 ++++++++++----------- internal/service/policy_engine.go | 14 +++--- internal/service/service.go | 33 +++++++++++++ internal/service/tailscale_service.go | 30 ++++++------ 13 files changed, 183 insertions(+), 165 deletions(-) create mode 100644 internal/service/service.go diff --git a/internal/bootstrap/app_bootstrap.go b/internal/bootstrap/app_bootstrap.go index 7fc0cb54..6ef92c56 100644 --- a/internal/bootstrap/app_bootstrap.go +++ b/internal/bootstrap/app_bootstrap.go @@ -31,23 +31,10 @@ import ( // 2. HTTP server listeners - ding.RingNormal // 3. Networking layers, user and label providers (e.g. ailscale service, kubernetes service) - ding.RingMajor // 4. Database connection - ding.RingCritical - -type Services struct { - accessControlService *service.AccessControlsService - authService *service.AuthService - dockerService *service.DockerService - kubernetesService *service.KubernetesService - ldapService *service.LdapService - oauthBrokerService *service.OAuthBrokerService - oidcService *service.OIDCService - tailscaleService *service.TailscaleService - policyEngine *service.PolicyEngine -} - type BootstrapApp struct { config model.Config runtime model.RuntimeConfig - services Services + services service.Services log *logger.Logger ctx context.Context cancel context.CancelFunc @@ -56,6 +43,9 @@ type BootstrapApp struct { db *sql.DB ding *ding.Ding listeners []Listener + deps struct { + service *service.ServiceDependencies + } } func NewBootstrapApp(config model.Config) *BootstrapApp { @@ -233,7 +223,7 @@ func (app *BootstrapApp) Setup() error { return configuredProviders[i].Name < configuredProviders[j].Name }) - if app.services.authService.LocalAuthConfigured() { + if app.services.AuthService.LocalAuthConfigured() { configuredProviders = append(configuredProviders, model.Provider{ Name: "Local", ID: "local", @@ -241,7 +231,7 @@ func (app *BootstrapApp) Setup() error { }) } - if app.services.authService.LDAPAuthConfigured() { + if app.services.AuthService.LDAPAuthConfigured() { configuredProviders = append(configuredProviders, model.Provider{ Name: "LDAP", ID: "ldap", @@ -260,8 +250,8 @@ func (app *BootstrapApp) Setup() error { app.runtime.ConfiguredProviders = configuredProviders // throw in tailscale if it's configured just before setting up the controllers - if app.services.tailscaleService != nil { - app.runtime.TrustedDomains = append(app.runtime.TrustedDomains, "https://"+app.services.tailscaleService.GetHostname()) + if app.services.TailscaleService != nil { + app.runtime.TrustedDomains = append(app.runtime.TrustedDomains, "https://"+app.services.TailscaleService.GetHostname()) } // setup router diff --git a/internal/bootstrap/router_bootstrap.go b/internal/bootstrap/router_bootstrap.go index 5244ab20..6f082a06 100644 --- a/internal/bootstrap/router_bootstrap.go +++ b/internal/bootstrap/router_bootstrap.go @@ -40,7 +40,7 @@ func (app *BootstrapApp) setupRouter() error { } } - contextMiddleware := middleware.NewContextMiddleware(app.log, app.runtime, app.services.authService, app.services.oauthBrokerService, app.services.tailscaleService) + contextMiddleware := middleware.NewContextMiddleware(app.log, app.runtime, app.services.AuthService, app.services.OAuthBrokerService, app.services.TailscaleService) engine.Use(contextMiddleware.Middleware()) uiMiddleware, err := middleware.NewUIMiddleware() @@ -58,13 +58,13 @@ func (app *BootstrapApp) setupRouter() error { apiRouter := engine.Group("/api") controller.NewContextController(app.log, app.config, app.runtime, apiRouter) - controller.NewOAuthController(app.log, app.config, app.runtime, apiRouter, app.services.authService) - controller.NewOIDCController(app.log, app.services.oidcService, app.runtime, apiRouter, &engine.RouterGroup) - controller.NewProxyController(app.log, app.runtime, apiRouter, app.services.accessControlService, app.services.authService, app.services.policyEngine) - controller.NewUserController(app.log, app.runtime, apiRouter, app.services.authService) + controller.NewOAuthController(app.log, app.config, app.runtime, apiRouter, app.services.AuthService) + controller.NewOIDCController(app.log, app.services.OIDCService, app.runtime, apiRouter, &engine.RouterGroup) + controller.NewProxyController(app.log, app.runtime, apiRouter, app.services.AccessControlService, app.services.AuthService, app.services.PolicyEngine) + controller.NewUserController(app.log, app.runtime, apiRouter, app.services.AuthService) controller.NewResourcesController(app.config, &engine.RouterGroup) controller.NewHealthController(apiRouter) - controller.NewWellKnownController(app.services.oidcService, &engine.RouterGroup) + controller.NewWellKnownController(app.services.OIDCService, &engine.RouterGroup) app.router = engine return nil @@ -99,7 +99,7 @@ func (app *BootstrapApp) calculateListenerPolicy() []Listener { l := []Listener{} if !app.config.Server.ConcurrentListenersEnabled { - if app.services.tailscaleService != nil { + if app.services.TailscaleService != nil { l = append(l, ListenerTailscale) return l } @@ -117,7 +117,7 @@ func (app *BootstrapApp) calculateListenerPolicy() []Listener { l = append(l, ListenerUnix) } - if app.services.tailscaleService != nil { + if app.services.TailscaleService != nil { l = append(l, ListenerTailscale) } @@ -186,9 +186,9 @@ func (app *BootstrapApp) serveUnix(ctx context.Context) error { } func (app *BootstrapApp) serveTailscale(ctx context.Context) error { - app.log.App.Info().Msgf("Starting Tailscale server on %s", fmt.Sprintf("https://%s", app.services.tailscaleService.GetHostname())) + app.log.App.Info().Msgf("Starting Tailscale server on %s", fmt.Sprintf("https://%s", app.services.TailscaleService.GetHostname())) - listener, err := app.services.tailscaleService.CreateListener() + listener, err := app.services.TailscaleService.CreateListener() if err != nil { return fmt.Errorf("failed to create tailscale listener: %w", err) diff --git a/internal/bootstrap/service_bootstrap.go b/internal/bootstrap/service_bootstrap.go index bf94c5c4..b8fa2475 100644 --- a/internal/bootstrap/service_bootstrap.go +++ b/internal/bootstrap/service_bootstrap.go @@ -8,13 +8,23 @@ import ( ) func (app *BootstrapApp) setupServices() error { - ldapService, err := service.NewLdapService(app.log, app.config, app.ding) + app.deps.service = &service.ServiceDependencies{ + Log: app.log, + StaticConfig: &app.config, + RuntimeConfig: &app.runtime, + Ctx: app.ctx, + Ding: app.ding, + Services: &app.services, + Queries: &app.queries, + } + + ldap, err := service.NewLdapService(app.deps.service) if err != nil { app.log.App.Warn().Err(err).Msg("Failed to initialize LDAP connection, will continue without it") } - app.services.ldapService = ldapService + app.services.LDAPService = ldap labelProvider, err := app.getLabelProvider() @@ -22,16 +32,18 @@ func (app *BootstrapApp) setupServices() error { return fmt.Errorf("failed to initialize label provider: %w", err) } - tailscaleService, err := service.NewTailscaleService(app.log, app.config, app.ctx, app.ding) + app.deps.service.LabelProvider = labelProvider + + tailscaleService, err := service.NewTailscaleService(app.deps.service) if err != nil { app.log.App.Warn().Err(err).Msg("Failed to initialize Tailscale connection, will continue without it") } - app.services.tailscaleService = tailscaleService + app.services.TailscaleService = tailscaleService - accessControlsService := service.NewAccessControlsService(app.log, app.config, &labelProvider) - app.services.accessControlService = accessControlsService + accessControlsService := service.NewAccessControlsService(app.deps.service) + app.services.AccessControlService = accessControlsService err = app.setupPolicyEngine() @@ -39,19 +51,19 @@ func (app *BootstrapApp) setupServices() error { return fmt.Errorf("failed to initialize policy engine: %w", err) } - oauthBrokerService := service.NewOAuthBrokerService(app.log, app.runtime.OAuthProviders, app.ctx) - app.services.oauthBrokerService = oauthBrokerService + oauthBrokerService := service.NewOAuthBrokerService(app.deps.service) + app.services.OAuthBrokerService = oauthBrokerService - authService := service.NewAuthService(app.log, app.config, app.runtime, app.ctx, app.ding, app.services.ldapService, app.queries, app.services.oauthBrokerService, app.services.tailscaleService, app.services.policyEngine) - app.services.authService = authService + authService := service.NewAuthService(app.deps.service) + app.services.AuthService = authService - oidcService, err := service.NewOIDCService(app.log, app.config, app.runtime, app.queries, app.ding) + oidcService, err := service.NewOIDCService(app.deps.service) if err != nil { return fmt.Errorf("failed to initialize oidc service: %w", err) } - app.services.oidcService = oidcService + app.services.OIDCService = oidcService return nil } @@ -69,19 +81,19 @@ func (app *BootstrapApp) getLabelProvider() (service.LabelProvider, error) { if useKubernetes { app.log.App.Debug().Msg("Using Kubernetes label provider") - kubernetesService, err := service.NewKubernetesService(app.log, app.ctx, app.ding) + kubernetesService, err := service.NewKubernetesService(app.deps.service) if err != nil { return nil, fmt.Errorf("failed to initialize kubernetes service: %w", err) } - app.services.kubernetesService = kubernetesService + app.services.KubernetesService = kubernetesService return kubernetesService, nil } app.log.App.Debug().Msg("Using Docker label provider") - dockerService, err := service.NewDockerService(app.log, app.ctx, app.ding) + dockerService, err := service.NewDockerService(app.deps.service) if err != nil { return nil, fmt.Errorf("failed to initialize docker service: %w", err) @@ -94,7 +106,7 @@ func (app *BootstrapApp) getLabelProvider() (service.LabelProvider, error) { return nil, nil } - app.services.dockerService = dockerService + app.services.DockerService = dockerService return dockerService, nil default: return nil, fmt.Errorf("invalid label provider: %s", app.config.LabelProvider) @@ -102,7 +114,7 @@ func (app *BootstrapApp) getLabelProvider() (service.LabelProvider, error) { } func (app *BootstrapApp) setupPolicyEngine() error { - policyEngine, err := service.NewPolicyEngine(app.config, app.log) + policyEngine, err := service.NewPolicyEngine(app.deps.service) if err != nil { return fmt.Errorf("failed to initialize policy engine: %w", err) @@ -129,6 +141,6 @@ func (app *BootstrapApp) setupPolicyEngine() error { Config: app.config, }) - app.services.policyEngine = policyEngine + app.services.PolicyEngine = policyEngine return nil } diff --git a/internal/service/access_controls_service.go b/internal/service/access_controls_service.go index 64c4d6fc..75b63d3e 100644 --- a/internal/service/access_controls_service.go +++ b/internal/service/access_controls_service.go @@ -13,19 +13,18 @@ type LabelProvider interface { type AccessControlsService struct { log *logger.Logger - config model.Config + config *model.Config labelProvider *LabelProvider } func NewAccessControlsService( - log *logger.Logger, - config model.Config, - labelProvider *LabelProvider) *AccessControlsService { + deps *ServiceDependencies, +) *AccessControlsService { return &AccessControlsService{ - log: log, - config: config, - labelProvider: labelProvider, + log: deps.Log, + config: deps.StaticConfig, + labelProvider: &deps.LabelProvider, } } diff --git a/internal/service/auth_service.go b/internal/service/auth_service.go index ef3e9e08..2c7a773a 100644 --- a/internal/service/auth_service.go +++ b/internal/service/auth_service.go @@ -57,8 +57,8 @@ type LoginAttempt struct { type AuthService struct { log *logger.Logger - config model.Config - runtime model.RuntimeConfig + config *model.Config + runtime *model.RuntimeConfig ctx context.Context ldap *LdapService @@ -83,27 +83,18 @@ type AuthService struct { } func NewAuthService( - log *logger.Logger, - config model.Config, - runtime model.RuntimeConfig, - ctx context.Context, - dg *ding.Ding, - ldap *LdapService, - queries repository.Store, - oauthBroker *OAuthBrokerService, - tailscale *TailscaleService, - policy *PolicyEngine, + deps *ServiceDependencies, ) *AuthService { service := &AuthService{ - log: log, - runtime: runtime, - ctx: ctx, - config: config, - ldap: ldap, - queries: queries, - oauthBroker: oauthBroker, - tailscale: tailscale, - policyEngine: policy, + log: deps.Log, + runtime: deps.RuntimeConfig, + ctx: deps.Ctx, + config: deps.StaticConfig, + ldap: deps.Services.LDAPService, + queries: *deps.Queries, + oauthBroker: deps.Services.OAuthBrokerService, + tailscale: deps.Services.TailscaleService, + policyEngine: deps.Services.PolicyEngine, } // caches setup @@ -115,7 +106,7 @@ func NewAuthService( service.caches.login = loginCache service.caches.ldap = ldapCache - dg.Go(func(ctx context.Context) { + deps.Ding.Go(func(ctx context.Context) { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() diff --git a/internal/service/docker_service.go b/internal/service/docker_service.go index 6525b7f7..19f33ed5 100644 --- a/internal/service/docker_service.go +++ b/internal/service/docker_service.go @@ -22,9 +22,7 @@ type DockerService struct { } func NewDockerService( - log *logger.Logger, - ctx context.Context, - dg *ding.Ding, + deps *ServiceDependencies, ) (*DockerService, error) { client, err := client.NewClientWithOpts(client.FromEnv) @@ -32,25 +30,25 @@ func NewDockerService( return nil, err } - client.NegotiateAPIVersion(ctx) + client.NegotiateAPIVersion(deps.Ctx) - _, err = client.Ping(ctx) + _, err = client.Ping(deps.Ctx) if err != nil { - log.App.Debug().Err(err).Msg("Docker not connected") + deps.Log.App.Debug().Err(err).Msg("Docker not connected") return nil, nil } service := &DockerService{ - log: log, + log: deps.Log, client: client, - context: ctx, + context: deps.Ctx, } service.isConnected = true service.log.App.Debug().Msg("Docker connected successfully") - dg.Go(service.watchAndClose, ding.RingMajor) + deps.Ding.Go(service.watchAndClose, ding.RingMajor) return service, nil } diff --git a/internal/service/kubernetes_service.go b/internal/service/kubernetes_service.go index 9cef6759..84fc5732 100644 --- a/internal/service/kubernetes_service.go +++ b/internal/service/kubernetes_service.go @@ -49,9 +49,7 @@ type KubernetesService struct { } func NewKubernetesService( - log *logger.Logger, - ctx context.Context, - dg *ding.Ding, + deps *ServiceDependencies, ) (*KubernetesService, error) { cfg, err := rest.InClusterConfig() if err != nil { @@ -69,31 +67,31 @@ func NewKubernetesService( Resource: "ingresses", } - accessCtx, accessCancel := context.WithTimeout(ctx, 5*time.Second) + accessCtx, accessCancel := context.WithTimeout(deps.Ctx, 5*time.Second) defer accessCancel() _, err = client.Resource(gvr).List(accessCtx, metav1.ListOptions{Limit: 1}) if err != nil { - log.App.Warn().Err(err).Str("api", gvr.GroupVersion().String()).Msg("Failed to access Ingress API, Kubernetes label provider will be disabled") + deps.Log.App.Warn().Err(err).Str("api", gvr.GroupVersion().String()).Msg("Failed to access Ingress API, Kubernetes label provider will be disabled") return nil, fmt.Errorf("failed to access ingress api: %w", err) } - log.App.Debug().Str("api", gvr.GroupVersion().String()).Msg("Successfully accessed Ingress API, starting watcher") + deps.Log.App.Debug().Str("api", gvr.GroupVersion().String()).Msg("Successfully accessed Ingress API, starting watcher") service := &KubernetesService{ - log: log, + log: deps.Log, client: client, ingressApps: make(map[ingressKey][]ingressApp), domainIndex: make(map[string]ingressAppKey), appNameIndex: make(map[string]ingressAppKey), } - dg.Go(func(ctx context.Context) { + deps.Ding.Go(func(ctx context.Context) { service.watchGVR(gvr, ctx) }, ding.RingMajor) service.started = true - log.App.Debug().Msg("Kubernetes label provider started successfully") + deps.Log.App.Debug().Msg("Kubernetes label provider started successfully") return service, nil } diff --git a/internal/service/ldap_service.go b/internal/service/ldap_service.go index 819cb9d3..3126431e 100644 --- a/internal/service/ldap_service.go +++ b/internal/service/ldap_service.go @@ -17,40 +17,38 @@ import ( type LdapService struct { log *logger.Logger - config model.Config + config *model.Config - conn *ldapgo.Conn - mutex sync.RWMutex - cert *tls.Certificate + conn *ldapgo.Conn + mutex sync.RWMutex + cert *tls.Certificate + ldapBindPw string } func NewLdapService( - log *logger.Logger, - config model.Config, - dg *ding.Ding, + deps *ServiceDependencies, ) (*LdapService, error) { - if config.LDAP.Address == "" { + if deps.StaticConfig.LDAP.Address == "" { return nil, nil } - secret := utils.GetSecret(config.LDAP.BindPassword, config.LDAP.BindPasswordFile) - config.LDAP.BindPassword = secret - config.LDAP.BindPasswordFile = "" + ldapBindPw := utils.GetSecret(deps.StaticConfig.LDAP.BindPassword, deps.StaticConfig.LDAP.BindPasswordFile) ldap := &LdapService{ - log: log, - config: config, + log: deps.Log, + config: deps.StaticConfig, + ldapBindPw: ldapBindPw, } // Check whether authentication with client certificate is possible - if config.LDAP.AuthCert != "" && config.LDAP.AuthKey != "" { - cert, err := tls.LoadX509KeyPair(config.LDAP.AuthCert, config.LDAP.AuthKey) + if deps.StaticConfig.LDAP.AuthCert != "" && deps.StaticConfig.LDAP.AuthKey != "" { + cert, err := tls.LoadX509KeyPair(deps.StaticConfig.LDAP.AuthCert, deps.StaticConfig.LDAP.AuthKey) if err != nil { return nil, fmt.Errorf("failed to initialize LDAP with mTLS authentication: %w", err) } - log.App.Info().Msg("LDAP mTLS authentication configured successfully") + ldap.log.App.Info().Msg("LDAP mTLS authentication configured successfully") ldap.cert = &cert @@ -72,7 +70,7 @@ func NewLdapService( return nil, fmt.Errorf("failed to connect to ldap server: %w", err) } - dg.Go(func(ctx context.Context) { + deps.Ding.Go(func(ctx context.Context) { ldap.log.App.Debug().Msg("Starting LDAP connection heartbeat routine") ticker := time.NewTicker(5 * time.Minute) diff --git a/internal/service/oauth_broker_service.go b/internal/service/oauth_broker_service.go index fdb5e1e0..1aae894d 100644 --- a/internal/service/oauth_broker_service.go +++ b/internal/service/oauth_broker_service.go @@ -33,22 +33,20 @@ var presets = map[string]func(config model.OAuthServiceConfig, ctx context.Conte } func NewOAuthBrokerService( - log *logger.Logger, - configs map[string]model.OAuthServiceConfig, - ctx context.Context, + deps *ServiceDependencies, ) *OAuthBrokerService { service := &OAuthBrokerService{ - log: log, + log: deps.Log, services: make(map[string]OAuthServiceImpl), - configs: configs, + configs: deps.RuntimeConfig.OAuthProviders, } - for name, cfg := range configs { + for name, cfg := range service.configs { if presetFunc, exists := presets[name]; exists { - service.services[name] = presetFunc(cfg, ctx) + service.services[name] = presetFunc(cfg, deps.Ctx) service.log.App.Debug().Str("service", name).Msg("Loaded OAuth service from preset") } else { - service.services[name] = NewOAuthService(cfg, name, ctx) + service.services[name] = NewOAuthService(cfg, name, deps.Ctx) service.log.App.Debug().Str("service", name).Msg("Loaded OAuth service from custom config") } } diff --git a/internal/service/oidc_service.go b/internal/service/oidc_service.go index 3fec6f48..1fad2841 100644 --- a/internal/service/oidc_service.go +++ b/internal/service/oidc_service.go @@ -133,8 +133,8 @@ type UsedCodeEntry struct { type OIDCService struct { log *logger.Logger - config model.Config - runtime model.RuntimeConfig + config *model.Config + runtime *model.RuntimeConfig queries repository.Store clients map[string]model.OIDCClientConfig @@ -150,18 +150,15 @@ type OIDCService struct { } func NewOIDCService( - log *logger.Logger, - config model.Config, - runtime model.RuntimeConfig, - queries repository.Store, - dg *ding.Ding) (*OIDCService, error) { + deps *ServiceDependencies, +) (*OIDCService, error) { // If not configured, skip init - if len(runtime.OIDCClients) == 0 { + if len(deps.RuntimeConfig.OIDCClients) == 0 { return nil, nil } // Ensure issuer is https - uissuer, err := url.Parse(runtime.AppURL) + uissuer, err := url.Parse(deps.RuntimeConfig.AppURL) if err != nil { return nil, fmt.Errorf("failed to parse app url: %w", err) @@ -174,14 +171,14 @@ func NewOIDCService( issuer := fmt.Sprintf("%s://%s", uissuer.Scheme, uissuer.Host) // Create/load private and public keys - if strings.TrimSpace(config.OIDC.PrivateKeyPath) == "" || - strings.TrimSpace(config.OIDC.PublicKeyPath) == "" { + if strings.TrimSpace(deps.StaticConfig.OIDC.PrivateKeyPath) == "" || + strings.TrimSpace(deps.StaticConfig.OIDC.PublicKeyPath) == "" { return nil, errors.New("private key path and public key path are required") } var privateKey *rsa.PrivateKey - fprivateKey, err := os.ReadFile(config.OIDC.PrivateKeyPath) + fprivateKey, err := os.ReadFile(deps.StaticConfig.OIDC.PrivateKeyPath) if err != nil && !errors.Is(err, os.ErrNotExist) { return nil, err @@ -200,8 +197,8 @@ func NewOIDCService( Type: "RSA PRIVATE KEY", Bytes: der, }) - log.App.Trace().Str("type", "RSA PRIVATE KEY").Msg("Generated private RSA key") - err = os.WriteFile(config.OIDC.PrivateKeyPath, encoded, 0600) + deps.Log.App.Trace().Str("type", "RSA PRIVATE KEY").Msg("Generated private RSA key") + err = os.WriteFile(deps.StaticConfig.OIDC.PrivateKeyPath, encoded, 0600) if err != nil { return nil, fmt.Errorf("failed to write private key to file: %w", err) } @@ -210,7 +207,7 @@ func NewOIDCService( if block == nil { return nil, errors.New("failed to decode private key") } - log.App.Trace().Str("type", block.Type).Msg("Loaded private key") + deps.Log.App.Trace().Str("type", block.Type).Msg("Loaded private key") privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("failed to parse private key: %w", err) @@ -219,7 +216,7 @@ func NewOIDCService( var publicKey crypto.PublicKey - fpublicKey, err := os.ReadFile(config.OIDC.PublicKeyPath) + fpublicKey, err := os.ReadFile(deps.StaticConfig.OIDC.PublicKeyPath) if err != nil && !errors.Is(err, os.ErrNotExist) { return nil, fmt.Errorf("failed to read public key: %w", err) @@ -235,8 +232,8 @@ func NewOIDCService( Type: "RSA PUBLIC KEY", Bytes: der, }) - log.App.Trace().Str("type", "RSA PUBLIC KEY").Msg("Generated public RSA key") - err = os.WriteFile(config.OIDC.PublicKeyPath, encoded, 0644) + deps.Log.App.Trace().Str("type", "RSA PUBLIC KEY").Msg("Generated public RSA key") + err = os.WriteFile(deps.StaticConfig.OIDC.PublicKeyPath, encoded, 0644) if err != nil { return nil, err } @@ -245,7 +242,7 @@ func NewOIDCService( if block == nil { return nil, errors.New("failed to decode public key") } - log.App.Trace().Str("type", block.Type).Msg("Loaded public key") + deps.Log.App.Trace().Str("type", block.Type).Msg("Loaded public key") switch block.Type { case "RSA PUBLIC KEY": publicKey, err = x509.ParsePKCS1PublicKey(block.Bytes) @@ -275,7 +272,7 @@ func NewOIDCService( // We will reorganize the client into a map with the client ID as the key clients := make(map[string]model.OIDCClientConfig) - for id, client := range config.OIDC.Clients { + for id, client := range deps.StaticConfig.OIDC.Clients { client.ID = id if client.Name == "" { client.Name = utils.Capitalize(client.ID) @@ -291,15 +288,15 @@ func NewOIDCService( } client.ClientSecretFile = "" clients[id] = client - log.App.Debug().Str("clientId", client.ClientID).Msg("Loaded OIDC client configuration") + deps.Log.App.Debug().Str("clientId", client.ClientID).Msg("Loaded OIDC client configuration") } // Initialize the service service := &OIDCService{ - log: log, - config: config, - runtime: runtime, - queries: queries, + log: deps.Log, + config: deps.StaticConfig, + runtime: deps.RuntimeConfig, + queries: *deps.Queries, clients: clients, privateKey: privateKey, @@ -308,7 +305,7 @@ func NewOIDCService( } // Start cleanup routine - dg.Go(service.cleanupRoutine, ding.RingMinor) + deps.Ding.Go(service.cleanupRoutine, ding.RingMinor) // Create caches codeCash := NewCacheStore[AuthorizeCodeEntry](256) @@ -320,7 +317,7 @@ func NewOIDCService( service.caches.authorize = authorize // Start cache cleanup routine - dg.Go(func(ctx context.Context) { + deps.Ding.Go(func(ctx context.Context) { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() diff --git a/internal/service/policy_engine.go b/internal/service/policy_engine.go index 7f301da6..f27068f2 100644 --- a/internal/service/policy_engine.go +++ b/internal/service/policy_engine.go @@ -40,21 +40,23 @@ type PolicyEngine struct { policy Policy } -func NewPolicyEngine(config model.Config, log *logger.Logger) (*PolicyEngine, error) { +func NewPolicyEngine( + deps *ServiceDependencies, +) (*PolicyEngine, error) { engine := PolicyEngine{ - log: log, + log: deps.Log, rules: make(map[RuleName]Rule), } - switch config.Auth.ACLs.Policy { + switch deps.StaticConfig.Auth.ACLs.Policy { case string(PolicyAllow): - log.App.Debug().Msg("Using 'allow' ACL policy: access to apps will be allowed by default unless explicitly blocked") + deps.Log.App.Debug().Msg("Using 'allow' ACL policy: access to apps will be allowed by default unless explicitly blocked") engine.policy = PolicyAllow case string(PolicyDeny): - log.App.Debug().Msg("Using 'deny' ACL policy: access to apps will be blocked by default unless explicitly allowed") + deps.Log.App.Debug().Msg("Using 'deny' ACL policy: access to apps will be blocked by default unless explicitly allowed") engine.policy = PolicyDeny default: - return nil, fmt.Errorf("invalid acl policy: %s", config.Auth.ACLs.Policy) + return nil, fmt.Errorf("invalid acl policy: %s", deps.StaticConfig.Auth.ACLs.Policy) } return &engine, nil diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 00000000..bf3f4836 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,33 @@ +package service + +import ( + "context" + + "github.com/steveiliop56/ding" + "github.com/tinyauthapp/tinyauth/internal/model" + "github.com/tinyauthapp/tinyauth/internal/repository" + "github.com/tinyauthapp/tinyauth/internal/utils/logger" +) + +type Services struct { + AccessControlService *AccessControlsService + AuthService *AuthService + DockerService *DockerService + KubernetesService *KubernetesService + LDAPService *LdapService + OAuthBrokerService *OAuthBrokerService + OIDCService *OIDCService + TailscaleService *TailscaleService + PolicyEngine *PolicyEngine +} + +type ServiceDependencies struct { + Log *logger.Logger + StaticConfig *model.Config + RuntimeConfig *model.RuntimeConfig + Ctx context.Context + Ding *ding.Ding + Services *Services + LabelProvider LabelProvider + Queries *repository.Store +} diff --git a/internal/service/tailscale_service.go b/internal/service/tailscale_service.go index c869c671..93b16f89 100644 --- a/internal/service/tailscale_service.go +++ b/internal/service/tailscale_service.go @@ -25,7 +25,7 @@ type TailscaleWhoisResponse struct { type TailscaleService struct { log *logger.Logger - config model.Config + config *model.Config ctx context.Context srv *tsnet.Server @@ -34,22 +34,24 @@ type TailscaleService struct { mu sync.Mutex } -func NewTailscaleService(log *logger.Logger, config model.Config, ctx context.Context, dg *ding.Ding) (*TailscaleService, error) { - if !config.Tailscale.Enabled { +func NewTailscaleService( + deps *ServiceDependencies, +) (*TailscaleService, error) { + if !deps.StaticConfig.Tailscale.Enabled { return nil, nil } srv := new(tsnet.Server) // node options - srv.Dir = config.Tailscale.Dir - srv.Hostname = config.Tailscale.Hostname - srv.AuthKey = config.Tailscale.AuthKey - srv.Ephemeral = config.Tailscale.Ephemeral + srv.Dir = deps.StaticConfig.Tailscale.Dir + srv.Hostname = deps.StaticConfig.Tailscale.Hostname + srv.AuthKey = deps.StaticConfig.Tailscale.AuthKey + srv.Ephemeral = deps.StaticConfig.Tailscale.Ephemeral // redirect logs to zerolog - srv.Logf = log.App.Printf - srv.UserLogf = log.App.Printf + srv.Logf = deps.Log.App.Printf + srv.UserLogf = deps.Log.App.Printf err := srv.Start() @@ -65,14 +67,14 @@ func NewTailscaleService(log *logger.Logger, config model.Config, ctx context.Co } service := &TailscaleService{ - log: log, - config: config, - ctx: ctx, + log: deps.Log, + config: deps.StaticConfig, + ctx: deps.Ctx, srv: srv, lc: lc, } - connectCtx, cancel := context.WithTimeout(ctx, 2*time.Minute) // large enough timeout to allow for user to manually authenticate with link if needed + connectCtx, cancel := context.WithTimeout(deps.Ctx, 2*time.Minute) // large enough timeout to allow for user to manually authenticate with link if needed defer cancel() err = service.waitForConn(connectCtx) @@ -82,7 +84,7 @@ func NewTailscaleService(log *logger.Logger, config model.Config, ctx context.Co return nil, fmt.Errorf("failed to connect to tailscale network: %w", err) } - dg.Go(service.watchAndClose, ding.RingMajor) + deps.Ding.Go(service.watchAndClose, ding.RingMajor) return service, nil }