mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-06-14 15:30:16 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a7f5374acc |
@@ -31,23 +31,10 @@ import (
|
|||||||
// 2. HTTP server listeners - ding.RingNormal
|
// 2. HTTP server listeners - ding.RingNormal
|
||||||
// 3. Networking layers, user and label providers (e.g. ailscale service, kubernetes service) - ding.RingMajor
|
// 3. Networking layers, user and label providers (e.g. ailscale service, kubernetes service) - ding.RingMajor
|
||||||
// 4. Database connection - ding.RingCritical
|
// 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 {
|
type BootstrapApp struct {
|
||||||
config model.Config
|
config model.Config
|
||||||
runtime model.RuntimeConfig
|
runtime model.RuntimeConfig
|
||||||
services Services
|
services service.Services
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
@@ -56,6 +43,9 @@ type BootstrapApp struct {
|
|||||||
db *sql.DB
|
db *sql.DB
|
||||||
ding *ding.Ding
|
ding *ding.Ding
|
||||||
listeners []Listener
|
listeners []Listener
|
||||||
|
deps struct {
|
||||||
|
service *service.ServiceDependencies
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBootstrapApp(config model.Config) *BootstrapApp {
|
func NewBootstrapApp(config model.Config) *BootstrapApp {
|
||||||
@@ -233,7 +223,7 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
return configuredProviders[i].Name < configuredProviders[j].Name
|
return configuredProviders[i].Name < configuredProviders[j].Name
|
||||||
})
|
})
|
||||||
|
|
||||||
if app.services.authService.LocalAuthConfigured() {
|
if app.services.AuthService.LocalAuthConfigured() {
|
||||||
configuredProviders = append(configuredProviders, model.Provider{
|
configuredProviders = append(configuredProviders, model.Provider{
|
||||||
Name: "Local",
|
Name: "Local",
|
||||||
ID: "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{
|
configuredProviders = append(configuredProviders, model.Provider{
|
||||||
Name: "LDAP",
|
Name: "LDAP",
|
||||||
ID: "ldap",
|
ID: "ldap",
|
||||||
@@ -260,8 +250,8 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
app.runtime.ConfiguredProviders = configuredProviders
|
app.runtime.ConfiguredProviders = configuredProviders
|
||||||
|
|
||||||
// throw in tailscale if it's configured just before setting up the controllers
|
// throw in tailscale if it's configured just before setting up the controllers
|
||||||
if app.services.tailscaleService != nil {
|
if app.services.TailscaleService != nil {
|
||||||
app.runtime.TrustedDomains = append(app.runtime.TrustedDomains, "https://"+app.services.tailscaleService.GetHostname())
|
app.runtime.TrustedDomains = append(app.runtime.TrustedDomains, "https://"+app.services.TailscaleService.GetHostname())
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup router
|
// setup router
|
||||||
|
|||||||
@@ -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())
|
engine.Use(contextMiddleware.Middleware())
|
||||||
|
|
||||||
uiMiddleware, err := middleware.NewUIMiddleware()
|
uiMiddleware, err := middleware.NewUIMiddleware()
|
||||||
@@ -58,13 +58,13 @@ func (app *BootstrapApp) setupRouter() error {
|
|||||||
apiRouter := engine.Group("/api")
|
apiRouter := engine.Group("/api")
|
||||||
|
|
||||||
controller.NewContextController(app.log, app.config, app.runtime, apiRouter)
|
controller.NewContextController(app.log, app.config, app.runtime, apiRouter)
|
||||||
controller.NewOAuthController(app.log, app.config, 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.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.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.NewUserController(app.log, app.runtime, apiRouter, app.services.AuthService)
|
||||||
controller.NewResourcesController(app.config, &engine.RouterGroup)
|
controller.NewResourcesController(app.config, &engine.RouterGroup)
|
||||||
controller.NewHealthController(apiRouter)
|
controller.NewHealthController(apiRouter)
|
||||||
controller.NewWellKnownController(app.services.oidcService, &engine.RouterGroup)
|
controller.NewWellKnownController(app.services.OIDCService, &engine.RouterGroup)
|
||||||
|
|
||||||
app.router = engine
|
app.router = engine
|
||||||
return nil
|
return nil
|
||||||
@@ -99,7 +99,7 @@ func (app *BootstrapApp) calculateListenerPolicy() []Listener {
|
|||||||
l := []Listener{}
|
l := []Listener{}
|
||||||
|
|
||||||
if !app.config.Server.ConcurrentListenersEnabled {
|
if !app.config.Server.ConcurrentListenersEnabled {
|
||||||
if app.services.tailscaleService != nil {
|
if app.services.TailscaleService != nil {
|
||||||
l = append(l, ListenerTailscale)
|
l = append(l, ListenerTailscale)
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ func (app *BootstrapApp) calculateListenerPolicy() []Listener {
|
|||||||
l = append(l, ListenerUnix)
|
l = append(l, ListenerUnix)
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.services.tailscaleService != nil {
|
if app.services.TailscaleService != nil {
|
||||||
l = append(l, ListenerTailscale)
|
l = append(l, ListenerTailscale)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,9 +186,9 @@ func (app *BootstrapApp) serveUnix(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *BootstrapApp) serveTailscale(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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create tailscale listener: %w", err)
|
return fmt.Errorf("failed to create tailscale listener: %w", err)
|
||||||
|
|||||||
@@ -8,13 +8,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (app *BootstrapApp) setupServices() error {
|
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 {
|
if err != nil {
|
||||||
app.log.App.Warn().Err(err).Msg("Failed to initialize LDAP connection, will continue without it")
|
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()
|
labelProvider, err := app.getLabelProvider()
|
||||||
|
|
||||||
@@ -22,16 +32,18 @@ func (app *BootstrapApp) setupServices() error {
|
|||||||
return fmt.Errorf("failed to initialize label provider: %w", err)
|
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 {
|
if err != nil {
|
||||||
app.log.App.Warn().Err(err).Msg("Failed to initialize Tailscale connection, will continue without it")
|
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)
|
accessControlsService := service.NewAccessControlsService(app.deps.service)
|
||||||
app.services.accessControlService = accessControlsService
|
app.services.AccessControlService = accessControlsService
|
||||||
|
|
||||||
err = app.setupPolicyEngine()
|
err = app.setupPolicyEngine()
|
||||||
|
|
||||||
@@ -39,19 +51,19 @@ func (app *BootstrapApp) setupServices() error {
|
|||||||
return fmt.Errorf("failed to initialize policy engine: %w", err)
|
return fmt.Errorf("failed to initialize policy engine: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
oauthBrokerService := service.NewOAuthBrokerService(app.log, app.runtime.OAuthProviders, app.ctx)
|
oauthBrokerService := service.NewOAuthBrokerService(app.deps.service)
|
||||||
app.services.oauthBrokerService = oauthBrokerService
|
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)
|
authService := service.NewAuthService(app.deps.service)
|
||||||
app.services.authService = authService
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to initialize oidc service: %w", err)
|
return fmt.Errorf("failed to initialize oidc service: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.services.oidcService = oidcService
|
app.services.OIDCService = oidcService
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -69,19 +81,19 @@ func (app *BootstrapApp) getLabelProvider() (service.LabelProvider, error) {
|
|||||||
if useKubernetes {
|
if useKubernetes {
|
||||||
app.log.App.Debug().Msg("Using Kubernetes label provider")
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to initialize kubernetes service: %w", err)
|
return nil, fmt.Errorf("failed to initialize kubernetes service: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.services.kubernetesService = kubernetesService
|
app.services.KubernetesService = kubernetesService
|
||||||
return kubernetesService, nil
|
return kubernetesService, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
app.log.App.Debug().Msg("Using Docker label provider")
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to initialize docker service: %w", err)
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
app.services.dockerService = dockerService
|
app.services.DockerService = dockerService
|
||||||
return dockerService, nil
|
return dockerService, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid label provider: %s", app.config.LabelProvider)
|
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 {
|
func (app *BootstrapApp) setupPolicyEngine() error {
|
||||||
policyEngine, err := service.NewPolicyEngine(app.config, app.log)
|
policyEngine, err := service.NewPolicyEngine(app.deps.service)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to initialize policy engine: %w", err)
|
return fmt.Errorf("failed to initialize policy engine: %w", err)
|
||||||
@@ -129,6 +141,6 @@ func (app *BootstrapApp) setupPolicyEngine() error {
|
|||||||
Config: app.config,
|
Config: app.config,
|
||||||
})
|
})
|
||||||
|
|
||||||
app.services.policyEngine = policyEngine
|
app.services.PolicyEngine = policyEngine
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,19 +13,18 @@ type LabelProvider interface {
|
|||||||
|
|
||||||
type AccessControlsService struct {
|
type AccessControlsService struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
config model.Config
|
config *model.Config
|
||||||
labelProvider *LabelProvider
|
labelProvider *LabelProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAccessControlsService(
|
func NewAccessControlsService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
config model.Config,
|
) *AccessControlsService {
|
||||||
labelProvider *LabelProvider) *AccessControlsService {
|
|
||||||
|
|
||||||
return &AccessControlsService{
|
return &AccessControlsService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
config: config,
|
config: deps.StaticConfig,
|
||||||
labelProvider: labelProvider,
|
labelProvider: &deps.LabelProvider,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ type LoginAttempt struct {
|
|||||||
|
|
||||||
type AuthService struct {
|
type AuthService struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
config model.Config
|
config *model.Config
|
||||||
runtime model.RuntimeConfig
|
runtime *model.RuntimeConfig
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
ldap *LdapService
|
ldap *LdapService
|
||||||
@@ -83,27 +83,18 @@ type AuthService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthService(
|
func NewAuthService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
config model.Config,
|
|
||||||
runtime model.RuntimeConfig,
|
|
||||||
ctx context.Context,
|
|
||||||
dg *ding.Ding,
|
|
||||||
ldap *LdapService,
|
|
||||||
queries repository.Store,
|
|
||||||
oauthBroker *OAuthBrokerService,
|
|
||||||
tailscale *TailscaleService,
|
|
||||||
policy *PolicyEngine,
|
|
||||||
) *AuthService {
|
) *AuthService {
|
||||||
service := &AuthService{
|
service := &AuthService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
runtime: runtime,
|
runtime: deps.RuntimeConfig,
|
||||||
ctx: ctx,
|
ctx: deps.Ctx,
|
||||||
config: config,
|
config: deps.StaticConfig,
|
||||||
ldap: ldap,
|
ldap: deps.Services.LDAPService,
|
||||||
queries: queries,
|
queries: *deps.Queries,
|
||||||
oauthBroker: oauthBroker,
|
oauthBroker: deps.Services.OAuthBrokerService,
|
||||||
tailscale: tailscale,
|
tailscale: deps.Services.TailscaleService,
|
||||||
policyEngine: policy,
|
policyEngine: deps.Services.PolicyEngine,
|
||||||
}
|
}
|
||||||
|
|
||||||
// caches setup
|
// caches setup
|
||||||
@@ -115,7 +106,7 @@ func NewAuthService(
|
|||||||
service.caches.login = loginCache
|
service.caches.login = loginCache
|
||||||
service.caches.ldap = ldapCache
|
service.caches.ldap = ldapCache
|
||||||
|
|
||||||
dg.Go(func(ctx context.Context) {
|
deps.Ding.Go(func(ctx context.Context) {
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
ticker := time.NewTicker(1 * time.Minute)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ type DockerService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerService(
|
func NewDockerService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
ctx context.Context,
|
|
||||||
dg *ding.Ding,
|
|
||||||
) (*DockerService, error) {
|
) (*DockerService, error) {
|
||||||
|
|
||||||
client, err := client.NewClientWithOpts(client.FromEnv)
|
client, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
@@ -32,25 +30,25 @@ func NewDockerService(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
client.NegotiateAPIVersion(ctx)
|
client.NegotiateAPIVersion(deps.Ctx)
|
||||||
|
|
||||||
_, err = client.Ping(ctx)
|
_, err = client.Ping(deps.Ctx)
|
||||||
|
|
||||||
if err != nil {
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
service := &DockerService{
|
service := &DockerService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
client: client,
|
client: client,
|
||||||
context: ctx,
|
context: deps.Ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
service.isConnected = true
|
service.isConnected = true
|
||||||
service.log.App.Debug().Msg("Docker connected successfully")
|
service.log.App.Debug().Msg("Docker connected successfully")
|
||||||
|
|
||||||
dg.Go(service.watchAndClose, ding.RingMajor)
|
deps.Ding.Go(service.watchAndClose, ding.RingMajor)
|
||||||
|
|
||||||
return service, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,7 @@ type KubernetesService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewKubernetesService(
|
func NewKubernetesService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
ctx context.Context,
|
|
||||||
dg *ding.Ding,
|
|
||||||
) (*KubernetesService, error) {
|
) (*KubernetesService, error) {
|
||||||
cfg, err := rest.InClusterConfig()
|
cfg, err := rest.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -69,31 +67,31 @@ func NewKubernetesService(
|
|||||||
Resource: "ingresses",
|
Resource: "ingresses",
|
||||||
}
|
}
|
||||||
|
|
||||||
accessCtx, accessCancel := context.WithTimeout(ctx, 5*time.Second)
|
accessCtx, accessCancel := context.WithTimeout(deps.Ctx, 5*time.Second)
|
||||||
defer accessCancel()
|
defer accessCancel()
|
||||||
|
|
||||||
_, err = client.Resource(gvr).List(accessCtx, metav1.ListOptions{Limit: 1})
|
_, err = client.Resource(gvr).List(accessCtx, metav1.ListOptions{Limit: 1})
|
||||||
if err != nil {
|
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)
|
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{
|
service := &KubernetesService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
client: client,
|
client: client,
|
||||||
ingressApps: make(map[ingressKey][]ingressApp),
|
ingressApps: make(map[ingressKey][]ingressApp),
|
||||||
domainIndex: make(map[string]ingressAppKey),
|
domainIndex: make(map[string]ingressAppKey),
|
||||||
appNameIndex: 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)
|
service.watchGVR(gvr, ctx)
|
||||||
}, ding.RingMajor)
|
}, ding.RingMajor)
|
||||||
|
|
||||||
service.started = true
|
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
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,40 +17,38 @@ import (
|
|||||||
|
|
||||||
type LdapService struct {
|
type LdapService struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
config model.Config
|
config *model.Config
|
||||||
|
|
||||||
conn *ldapgo.Conn
|
conn *ldapgo.Conn
|
||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
cert *tls.Certificate
|
cert *tls.Certificate
|
||||||
|
ldapBindPw string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLdapService(
|
func NewLdapService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
config model.Config,
|
|
||||||
dg *ding.Ding,
|
|
||||||
) (*LdapService, error) {
|
) (*LdapService, error) {
|
||||||
if config.LDAP.Address == "" {
|
if deps.StaticConfig.LDAP.Address == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
secret := utils.GetSecret(config.LDAP.BindPassword, config.LDAP.BindPasswordFile)
|
ldapBindPw := utils.GetSecret(deps.StaticConfig.LDAP.BindPassword, deps.StaticConfig.LDAP.BindPasswordFile)
|
||||||
config.LDAP.BindPassword = secret
|
|
||||||
config.LDAP.BindPasswordFile = ""
|
|
||||||
|
|
||||||
ldap := &LdapService{
|
ldap := &LdapService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
config: config,
|
config: deps.StaticConfig,
|
||||||
|
ldapBindPw: ldapBindPw,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether authentication with client certificate is possible
|
// Check whether authentication with client certificate is possible
|
||||||
if config.LDAP.AuthCert != "" && config.LDAP.AuthKey != "" {
|
if deps.StaticConfig.LDAP.AuthCert != "" && deps.StaticConfig.LDAP.AuthKey != "" {
|
||||||
cert, err := tls.LoadX509KeyPair(config.LDAP.AuthCert, config.LDAP.AuthKey)
|
cert, err := tls.LoadX509KeyPair(deps.StaticConfig.LDAP.AuthCert, deps.StaticConfig.LDAP.AuthKey)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to initialize LDAP with mTLS authentication: %w", err)
|
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
|
ldap.cert = &cert
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ func NewLdapService(
|
|||||||
return nil, fmt.Errorf("failed to connect to ldap server: %w", err)
|
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")
|
ldap.log.App.Debug().Msg("Starting LDAP connection heartbeat routine")
|
||||||
|
|
||||||
ticker := time.NewTicker(5 * time.Minute)
|
ticker := time.NewTicker(5 * time.Minute)
|
||||||
|
|||||||
@@ -33,22 +33,20 @@ var presets = map[string]func(config model.OAuthServiceConfig, ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewOAuthBrokerService(
|
func NewOAuthBrokerService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
configs map[string]model.OAuthServiceConfig,
|
|
||||||
ctx context.Context,
|
|
||||||
) *OAuthBrokerService {
|
) *OAuthBrokerService {
|
||||||
service := &OAuthBrokerService{
|
service := &OAuthBrokerService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
services: make(map[string]OAuthServiceImpl),
|
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 {
|
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")
|
service.log.App.Debug().Str("service", name).Msg("Loaded OAuth service from preset")
|
||||||
} else {
|
} 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")
|
service.log.App.Debug().Str("service", name).Msg("Loaded OAuth service from custom config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ type UsedCodeEntry struct {
|
|||||||
|
|
||||||
type OIDCService struct {
|
type OIDCService struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
config model.Config
|
config *model.Config
|
||||||
runtime model.RuntimeConfig
|
runtime *model.RuntimeConfig
|
||||||
queries repository.Store
|
queries repository.Store
|
||||||
|
|
||||||
clients map[string]model.OIDCClientConfig
|
clients map[string]model.OIDCClientConfig
|
||||||
@@ -150,18 +150,15 @@ type OIDCService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewOIDCService(
|
func NewOIDCService(
|
||||||
log *logger.Logger,
|
deps *ServiceDependencies,
|
||||||
config model.Config,
|
) (*OIDCService, error) {
|
||||||
runtime model.RuntimeConfig,
|
|
||||||
queries repository.Store,
|
|
||||||
dg *ding.Ding) (*OIDCService, error) {
|
|
||||||
// If not configured, skip init
|
// If not configured, skip init
|
||||||
if len(runtime.OIDCClients) == 0 {
|
if len(deps.RuntimeConfig.OIDCClients) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure issuer is https
|
// Ensure issuer is https
|
||||||
uissuer, err := url.Parse(runtime.AppURL)
|
uissuer, err := url.Parse(deps.RuntimeConfig.AppURL)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse app url: %w", err)
|
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)
|
issuer := fmt.Sprintf("%s://%s", uissuer.Scheme, uissuer.Host)
|
||||||
|
|
||||||
// Create/load private and public keys
|
// Create/load private and public keys
|
||||||
if strings.TrimSpace(config.OIDC.PrivateKeyPath) == "" ||
|
if strings.TrimSpace(deps.StaticConfig.OIDC.PrivateKeyPath) == "" ||
|
||||||
strings.TrimSpace(config.OIDC.PublicKeyPath) == "" {
|
strings.TrimSpace(deps.StaticConfig.OIDC.PublicKeyPath) == "" {
|
||||||
return nil, errors.New("private key path and public key path are required")
|
return nil, errors.New("private key path and public key path are required")
|
||||||
}
|
}
|
||||||
|
|
||||||
var privateKey *rsa.PrivateKey
|
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) {
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -200,8 +197,8 @@ func NewOIDCService(
|
|||||||
Type: "RSA PRIVATE KEY",
|
Type: "RSA PRIVATE KEY",
|
||||||
Bytes: der,
|
Bytes: der,
|
||||||
})
|
})
|
||||||
log.App.Trace().Str("type", "RSA PRIVATE KEY").Msg("Generated private RSA key")
|
deps.Log.App.Trace().Str("type", "RSA PRIVATE KEY").Msg("Generated private RSA key")
|
||||||
err = os.WriteFile(config.OIDC.PrivateKeyPath, encoded, 0600)
|
err = os.WriteFile(deps.StaticConfig.OIDC.PrivateKeyPath, encoded, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to write private key to file: %w", err)
|
return nil, fmt.Errorf("failed to write private key to file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -210,7 +207,7 @@ func NewOIDCService(
|
|||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, errors.New("failed to decode private key")
|
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)
|
privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse private key: %w", err)
|
return nil, fmt.Errorf("failed to parse private key: %w", err)
|
||||||
@@ -219,7 +216,7 @@ func NewOIDCService(
|
|||||||
|
|
||||||
var publicKey crypto.PublicKey
|
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) {
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
return nil, fmt.Errorf("failed to read public key: %w", err)
|
return nil, fmt.Errorf("failed to read public key: %w", err)
|
||||||
@@ -235,8 +232,8 @@ func NewOIDCService(
|
|||||||
Type: "RSA PUBLIC KEY",
|
Type: "RSA PUBLIC KEY",
|
||||||
Bytes: der,
|
Bytes: der,
|
||||||
})
|
})
|
||||||
log.App.Trace().Str("type", "RSA PUBLIC KEY").Msg("Generated public RSA key")
|
deps.Log.App.Trace().Str("type", "RSA PUBLIC KEY").Msg("Generated public RSA key")
|
||||||
err = os.WriteFile(config.OIDC.PublicKeyPath, encoded, 0644)
|
err = os.WriteFile(deps.StaticConfig.OIDC.PublicKeyPath, encoded, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -245,7 +242,7 @@ func NewOIDCService(
|
|||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, errors.New("failed to decode public key")
|
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 {
|
switch block.Type {
|
||||||
case "RSA PUBLIC KEY":
|
case "RSA PUBLIC KEY":
|
||||||
publicKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
|
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
|
// We will reorganize the client into a map with the client ID as the key
|
||||||
clients := make(map[string]model.OIDCClientConfig)
|
clients := make(map[string]model.OIDCClientConfig)
|
||||||
|
|
||||||
for id, client := range config.OIDC.Clients {
|
for id, client := range deps.StaticConfig.OIDC.Clients {
|
||||||
client.ID = id
|
client.ID = id
|
||||||
if client.Name == "" {
|
if client.Name == "" {
|
||||||
client.Name = utils.Capitalize(client.ID)
|
client.Name = utils.Capitalize(client.ID)
|
||||||
@@ -291,15 +288,15 @@ func NewOIDCService(
|
|||||||
}
|
}
|
||||||
client.ClientSecretFile = ""
|
client.ClientSecretFile = ""
|
||||||
clients[id] = client
|
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
|
// Initialize the service
|
||||||
service := &OIDCService{
|
service := &OIDCService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
config: config,
|
config: deps.StaticConfig,
|
||||||
runtime: runtime,
|
runtime: deps.RuntimeConfig,
|
||||||
queries: queries,
|
queries: *deps.Queries,
|
||||||
|
|
||||||
clients: clients,
|
clients: clients,
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
@@ -308,7 +305,7 @@ func NewOIDCService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start cleanup routine
|
// Start cleanup routine
|
||||||
dg.Go(service.cleanupRoutine, ding.RingMinor)
|
deps.Ding.Go(service.cleanupRoutine, ding.RingMinor)
|
||||||
|
|
||||||
// Create caches
|
// Create caches
|
||||||
codeCash := NewCacheStore[AuthorizeCodeEntry](256)
|
codeCash := NewCacheStore[AuthorizeCodeEntry](256)
|
||||||
@@ -320,7 +317,7 @@ func NewOIDCService(
|
|||||||
service.caches.authorize = authorize
|
service.caches.authorize = authorize
|
||||||
|
|
||||||
// Start cache cleanup routine
|
// Start cache cleanup routine
|
||||||
dg.Go(func(ctx context.Context) {
|
deps.Ding.Go(func(ctx context.Context) {
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
ticker := time.NewTicker(1 * time.Minute)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
|||||||
@@ -40,21 +40,23 @@ type PolicyEngine struct {
|
|||||||
policy Policy
|
policy Policy
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPolicyEngine(config model.Config, log *logger.Logger) (*PolicyEngine, error) {
|
func NewPolicyEngine(
|
||||||
|
deps *ServiceDependencies,
|
||||||
|
) (*PolicyEngine, error) {
|
||||||
engine := PolicyEngine{
|
engine := PolicyEngine{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
rules: make(map[RuleName]Rule),
|
rules: make(map[RuleName]Rule),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch config.Auth.ACLs.Policy {
|
switch deps.StaticConfig.Auth.ACLs.Policy {
|
||||||
case string(PolicyAllow):
|
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
|
engine.policy = PolicyAllow
|
||||||
case string(PolicyDeny):
|
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
|
engine.policy = PolicyDeny
|
||||||
default:
|
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
|
return &engine, nil
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ type TailscaleWhoisResponse struct {
|
|||||||
|
|
||||||
type TailscaleService struct {
|
type TailscaleService struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
config model.Config
|
config *model.Config
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
srv *tsnet.Server
|
srv *tsnet.Server
|
||||||
@@ -34,22 +34,24 @@ type TailscaleService struct {
|
|||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTailscaleService(log *logger.Logger, config model.Config, ctx context.Context, dg *ding.Ding) (*TailscaleService, error) {
|
func NewTailscaleService(
|
||||||
if !config.Tailscale.Enabled {
|
deps *ServiceDependencies,
|
||||||
|
) (*TailscaleService, error) {
|
||||||
|
if !deps.StaticConfig.Tailscale.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := new(tsnet.Server)
|
srv := new(tsnet.Server)
|
||||||
|
|
||||||
// node options
|
// node options
|
||||||
srv.Dir = config.Tailscale.Dir
|
srv.Dir = deps.StaticConfig.Tailscale.Dir
|
||||||
srv.Hostname = config.Tailscale.Hostname
|
srv.Hostname = deps.StaticConfig.Tailscale.Hostname
|
||||||
srv.AuthKey = config.Tailscale.AuthKey
|
srv.AuthKey = deps.StaticConfig.Tailscale.AuthKey
|
||||||
srv.Ephemeral = config.Tailscale.Ephemeral
|
srv.Ephemeral = deps.StaticConfig.Tailscale.Ephemeral
|
||||||
|
|
||||||
// redirect logs to zerolog
|
// redirect logs to zerolog
|
||||||
srv.Logf = log.App.Printf
|
srv.Logf = deps.Log.App.Printf
|
||||||
srv.UserLogf = log.App.Printf
|
srv.UserLogf = deps.Log.App.Printf
|
||||||
|
|
||||||
err := srv.Start()
|
err := srv.Start()
|
||||||
|
|
||||||
@@ -65,14 +67,14 @@ func NewTailscaleService(log *logger.Logger, config model.Config, ctx context.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
service := &TailscaleService{
|
service := &TailscaleService{
|
||||||
log: log,
|
log: deps.Log,
|
||||||
config: config,
|
config: deps.StaticConfig,
|
||||||
ctx: ctx,
|
ctx: deps.Ctx,
|
||||||
srv: srv,
|
srv: srv,
|
||||||
lc: lc,
|
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()
|
defer cancel()
|
||||||
|
|
||||||
err = service.waitForConn(connectCtx)
|
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)
|
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
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user