From 274affb17e25bde8ac895a41fa3d3272fef7a2e0 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Thu, 16 Apr 2026 20:52:06 +0200 Subject: [PATCH] create default peers for newly created interfaces (#666) --- config.yml.sample | 5 +- docs/documentation/configuration/examples.md | 2 +- docs/documentation/configuration/overview.md | 26 +++- internal/adapters/database.go | 2 +- .../app/api/v0/handlers/endpoint_config.go | 2 +- internal/app/wireguard/wireguard.go | 45 ++++-- .../app/wireguard/wireguard_interfaces.go | 2 +- .../wireguard/wireguard_interfaces_test.go | 7 - internal/app/wireguard/wireguard_peers.go | 129 ++++++++++++++---- .../app/wireguard/wireguard_peers_test.go | 12 +- internal/config/config.go | 54 ++++++-- internal/domain/interface.go | 12 ++ internal/domain/interface_test.go | 26 ++++ internal/domain/user.go | 12 ++ internal/domain/user_test.go | 14 ++ 15 files changed, 284 insertions(+), 66 deletions(-) diff --git a/config.yml.sample b/config.yml.sample index 51a9680..7033456 100644 --- a/config.yml.sample +++ b/config.yml.sample @@ -6,8 +6,9 @@ advanced: core: admin_user: test@test.de admin_password: secret - create_default_peer: true - create_default_peer_on_creation: false + create_default_peer_on_login: true + create_default_peer_on_user_creation: false + create_default_peer_on_interface_creation: false web: external_url: http://localhost:8888 diff --git a/docs/documentation/configuration/examples.md b/docs/documentation/configuration/examples.md index 396c4c1..ea4d1e0 100644 --- a/docs/documentation/configuration/examples.md +++ b/docs/documentation/configuration/examples.md @@ -8,7 +8,7 @@ core: admin_password: password admin_api_token: super-s3cr3t-api-token-or-a-UUID import_existing: false - create_default_peer: true + create_default_peer_on_login: true self_provisioning_allowed: true backend: diff --git a/docs/documentation/configuration/overview.md b/docs/documentation/configuration/overview.md index 0b96c38..af3c632 100644 --- a/docs/documentation/configuration/overview.md +++ b/docs/documentation/configuration/overview.md @@ -155,17 +155,33 @@ More advanced options are found in the subsequent `Advanced` section. - **Environment Variable:** `WG_PORTAL_CORE_EDITABLE_KEYS` - **Description:** Allow editing of WireGuard key-pairs directly in the UI. -### `create_default_peer` +### `create_default_peer` (deprecated) +- **Default:** `false` +- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER` +- **Description:** **DEPRECATED** in favor of [create_default_peer_on_login](#create_default_peer_on_login). If set to `true`, this option is equivalent to enabling `create_default_peer_on_login`. It will be removed in a future release (2.4). + +### `create_default_peer_on_creation` (deprecated) +- **Default:** `false` +- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_CREATION` +- **Description:** **DEPRECATED** in favor of [create_default_peer_on_user_creation](#create_default_peer_on_user_creation) and [create_default_peer_on_interface_creation](#create_default_peer_on_interface_creation). If set to `true`, both of those options are enabled. It will be removed in a future release (2.4). + +### `create_default_peer_on_login` - **Default:** `false` - **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER` - **Description:** If a user logs in for the first time with no existing peers, automatically create a new WireGuard peer for all server interfaces where the "Create default peer" flag is set. - **Important:** This option is only effective for interfaces where the "Create default peer" flag is set (via the UI). -### `create_default_peer_on_creation` +### `create_default_peer_on_user_creation` - **Default:** `false` -- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_CREATION` -- **Description:** If an LDAP user is created (e.g., through LDAP sync) and has no peers, automatically create a new WireGuard peer for all server interfaces where the "Create default peer" flag is set. -- **Important:** This option requires [create_default_peer](#create_default_peer) to be enabled. +- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_USER_CREATION` +- **Description:** If a new user is created (e.g., through LDAP sync or registration) and has no peers, automatically create a new WireGuard peer for all server interfaces where the "Create default peer" flag is set. +- **Important:** This option is only effective for interfaces where the "Create default peer" flag is set (via the UI). + +### `create_default_peer_on_interface_creation` +- **Default:** `false` +- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_INTERFACE_CREATION` +- **Description:** When a new server interface is created with the "Create default peer" flag set, automatically create a default WireGuard peer on that interface for every existing user who does not yet have a peer on it. +- **Important:** This option is only effective for interfaces where the "Create default peer" flag is set (via the UI). ### `re_enable_peer_after_user_enable` - **Default:** `true` diff --git a/internal/adapters/database.go b/internal/adapters/database.go index c428c13..de3cf50 100644 --- a/internal/adapters/database.go +++ b/internal/adapters/database.go @@ -251,7 +251,7 @@ func (r *SqlRepo) migrate() error { if existingSysStat.SchemaVersion == 1 { const schemaVersion = 2 // Preserve existing behavior for installations that had default-peer-creation enabled. - if r.cfg.Core.CreateDefaultPeer { + if r.cfg.DefaultPeerCreationEnabled() { err := r.db.Model(&domain.Interface{}). Where("type = ?", domain.InterfaceTypeServer). Update("create_default_peer", true).Error diff --git a/internal/app/api/v0/handlers/endpoint_config.go b/internal/app/api/v0/handlers/endpoint_config.go index db6cc73..62da202 100644 --- a/internal/app/api/v0/handlers/endpoint_config.go +++ b/internal/app/api/v0/handlers/endpoint_config.go @@ -145,7 +145,7 @@ func (e ConfigEndpoint) handleSettingsGet() http.HandlerFunc { MinPasswordLength: e.cfg.Auth.MinPasswordLength, AvailableBackends: controllerFn(), LoginFormVisible: !e.cfg.Auth.HideLoginForm || !hasSocialLogin, - CreateDefaultPeer: e.cfg.Core.CreateDefaultPeer, + CreateDefaultPeer: e.cfg.DefaultPeerCreationEnabled(), }) } } diff --git a/internal/app/wireguard/wireguard.go b/internal/app/wireguard/wireguard.go index c564240..a2a135e 100644 --- a/internal/app/wireguard/wireguard.go +++ b/internal/app/wireguard/wireguard.go @@ -36,6 +36,7 @@ type InterfaceAndPeerDatabaseRepo interface { GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error) GetUsedIpsPerSubnet(ctx context.Context, subnets []domain.Cidr) (map[domain.Cidr][]domain.Cidr, error) GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) + GetAllUsers(ctx context.Context) ([]domain.User, error) } type WgQuickController interface { @@ -59,7 +60,8 @@ type Manager struct { db InterfaceAndPeerDatabaseRepo wg *ControllerManager - userLockMap *sync.Map + userLockMap *sync.Map + interfaceLockMap *sync.Map } func NewWireGuardManager( @@ -69,11 +71,12 @@ func NewWireGuardManager( db InterfaceAndPeerDatabaseRepo, ) (*Manager, error) { m := &Manager{ - cfg: cfg, - bus: bus, - wg: wg, - db: db, - userLockMap: &sync.Map{}, + cfg: cfg, + bus: bus, + wg: wg, + db: db, + userLockMap: &sync.Map{}, + interfaceLockMap: &sync.Map{}, } m.connectToMessageBus() @@ -93,10 +96,11 @@ func (m Manager) connectToMessageBus() { _ = m.bus.Subscribe(app.TopicUserDisabled, m.handleUserDisabledEvent) _ = m.bus.Subscribe(app.TopicUserEnabled, m.handleUserEnabledEvent) _ = m.bus.Subscribe(app.TopicUserDeleted, m.handleUserDeletedEvent) + _ = m.bus.Subscribe(app.TopicInterfaceCreated, m.handleInterfaceCreatedEvent) } func (m Manager) handleUserCreationEvent(user domain.User) { - if !m.cfg.Core.CreateDefaultPeerOnCreation { + if !m.cfg.Core.CreateDefaultPeerOnUserCreation { return } @@ -117,7 +121,7 @@ func (m Manager) handleUserCreationEvent(user domain.User) { } func (m Manager) handleUserLoginEvent(userId domain.UserIdentifier) { - if !m.cfg.Core.CreateDefaultPeer { + if !m.cfg.Core.CreateDefaultPeerOnLogin { return } @@ -269,6 +273,31 @@ func (m Manager) handleUserDeletedEvent(user domain.User) { } } +// handleInterfaceCreatedEvent creates default peers for all existing users when a new interface is created. +// This ensures users that already exist (e.g. imported via a prior LDAP sync that had no interface available) +// also receive a default peer for the newly created interface. +func (m Manager) handleInterfaceCreatedEvent(iface domain.Interface) { + if !m.cfg.Core.CreateDefaultPeerOnUserCreation { + return + } + + _, loaded := m.interfaceLockMap.LoadOrStore(iface.Identifier, "create") + if loaded { + return // another goroutine is already handling this interface + } + defer m.interfaceLockMap.Delete(iface.Identifier) + + slog.Debug("handling new interface event", "interface", iface.Identifier) + + ctx := domain.SetUserInfo(context.Background(), domain.SystemAdminContextUserInfo()) + + err := m.CreateDefaultPeers(ctx, iface.Identifier) + if err != nil { + slog.Error("failed to create default peers on new interface", + "interface", iface.Identifier, "error", err) + } +} + func (m Manager) runExpiredPeersCheck(ctx context.Context) { ctx = domain.SetUserInfo(ctx, domain.SystemAdminContextUserInfo()) diff --git a/internal/app/wireguard/wireguard_interfaces.go b/internal/app/wireguard/wireguard_interfaces.go index 455c2fd..c4d1923 100644 --- a/internal/app/wireguard/wireguard_interfaces.go +++ b/internal/app/wireguard/wireguard_interfaces.go @@ -387,7 +387,7 @@ func (m Manager) PrepareInterface(ctx context.Context) (*domain.Interface, error SaveConfig: m.cfg.Advanced.ConfigStoragePath != "", DisplayName: string(id), Type: domain.InterfaceTypeServer, - CreateDefaultPeer: m.cfg.Core.CreateDefaultPeer, + CreateDefaultPeer: m.cfg.DefaultPeerCreationEnabled(), DriverType: "", Disabled: nil, DisabledReason: "", diff --git a/internal/app/wireguard/wireguard_interfaces_test.go b/internal/app/wireguard/wireguard_interfaces_test.go index 80e56e0..4d15fd0 100644 --- a/internal/app/wireguard/wireguard_interfaces_test.go +++ b/internal/app/wireguard/wireguard_interfaces_test.go @@ -94,13 +94,6 @@ func TestImportPeer_AddressMapping(t *testing.T) { } } -func (f *mockDB) GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) { - return &domain.User{ - Identifier: id, - IsAdmin: false, - }, nil -} - func TestInterface_IsUserAllowed(t *testing.T) { cfg := &config.Config{ Auth: config.Auth{ diff --git a/internal/app/wireguard/wireguard_peers.go b/internal/app/wireguard/wireguard_peers.go index 4232942..60bb3da 100644 --- a/internal/app/wireguard/wireguard_peers.go +++ b/internal/app/wireguard/wireguard_peers.go @@ -15,6 +15,10 @@ import ( // CreateDefaultPeer creates a default peer for the given user on all server interfaces. func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdentifier) error { + if !m.cfg.DefaultPeerCreationEnabled() { + return nil + } + if err := domain.ValidateAdminAccessRights(ctx); err != nil { return err } @@ -24,39 +28,21 @@ func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdenti return fmt.Errorf("failed to fetch all interfaces: %w", err) } - userPeers, err := m.db.GetUserPeers(context.Background(), userId) + user, err := m.db.GetUser(ctx, userId) if err != nil { - return fmt.Errorf("failed to retrieve existing peers prior to default peer creation: %w", err) + return fmt.Errorf("failed to fetch user: %w", err) } var newPeers []domain.Peer for _, iface := range existingInterfaces { - if iface.Type != domain.InterfaceTypeServer { - continue // only create default peers for server interfaces - } - - if !iface.CreateDefaultPeer { - continue // only create default peers if the interface flag is set - } - - peerAlreadyCreated := slices.ContainsFunc(userPeers, func(peer domain.Peer) bool { - return peer.InterfaceIdentifier == iface.Identifier - }) - if peerAlreadyCreated { - continue // skip creation if a peer already exists for this interface - } - - peer, err := m.PreparePeer(ctx, iface.Identifier) + peer, err := m.prepareDefaultPeer(ctx, &iface, user) if err != nil { - return fmt.Errorf("failed to create default peer for interface %s: %w", iface.Identifier, err) + return fmt.Errorf("failed to prepare default peer: %w", err) } - peer.UserIdentifier = userId - peer.Notes = fmt.Sprintf("Default peer created for user %s", userId) - peer.AutomaticallyCreated = true - peer.GenerateDisplayName("Default") - - newPeers = append(newPeers, *peer) + if peer != nil { + newPeers = append(newPeers, *peer) + } } for i, peer := range newPeers { @@ -67,9 +53,61 @@ func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdenti } } - slog.InfoContext(ctx, "created default peers for user", - "user", userId, - "count", len(newPeers)) + slog.InfoContext(ctx, "created default peers for user", "user", userId, "count", len(newPeers)) + + return nil +} + +// CreateDefaultPeers creates default peers for all existing users on the given interface. +func (m Manager) CreateDefaultPeers(ctx context.Context, interfaceId domain.InterfaceIdentifier) error { + if !m.cfg.DefaultPeerCreationEnabled() { + return nil + } + + if err := domain.ValidateAdminAccessRights(ctx); err != nil { + return err + } + + iface, err := m.db.GetInterface(ctx, interfaceId) + if err != nil { + return fmt.Errorf("failed to fetch interface %s: %w", interfaceId, err) + } + + if !iface.CreateDefaultPeers() { + return nil + } + + users, err := m.db.GetAllUsers(ctx) + if err != nil { + return fmt.Errorf("failed to fetch all users: %w", err) + } + + var errs error + var peerCount int + for _, user := range users { + peer, err := m.prepareDefaultPeer(ctx, iface, &user) + if err != nil { + errs = errors.Join(errs, fmt.Errorf("failed to prepare default peer for user %s: %w", + user.Identifier, err)) + continue + } + if peer == nil { + continue + } + _, err = m.CreatePeer(ctx, peer) + if err != nil { + errs = errors.Join(errs, fmt.Errorf("failed to create default peer for user %s: %w", + user.Identifier, err)) + continue + } + peerCount++ + } + + if errs != nil { + return fmt.Errorf("failed to create default peers for interface %s: %w", interfaceId, errs) + } + + slog.InfoContext(ctx, "created default peers for interface", "interface", interfaceId, "count", peerCount) return nil } @@ -639,4 +677,39 @@ func (m Manager) checkInterfaceAccess(ctx context.Context, id domain.InterfaceId return nil } +func (m Manager) prepareDefaultPeer(ctx context.Context, iface *domain.Interface, user *domain.User) ( + *domain.Peer, + error, +) { + if !iface.CreateDefaultPeers() || !user.CreateDefaultPeers() { + return nil, nil + } + + userPeers, err := m.db.GetUserPeers(ctx, user.Identifier) + if err != nil { + return nil, fmt.Errorf("failed to retrieve existing peers prior to default peer creation: %w", err) + } + + peerAlreadyCreated := slices.ContainsFunc(userPeers, func(peer domain.Peer) bool { + // Ignore the AutomaticallyCreated flag on the peer. + // If a user already has a peer for a given interface, no default peer should be created. + return peer.InterfaceIdentifier == iface.Identifier + }) + if peerAlreadyCreated { + return nil, nil // skip creation if a peer already exists for this interface + } + + peer, err := m.PreparePeer(ctx, iface.Identifier) + if err != nil { + return nil, fmt.Errorf("failed to create default peer for interface %s: %w", iface.Identifier, err) + } + + peer.UserIdentifier = user.Identifier + peer.Notes = fmt.Sprintf("Default peer created for user %s", user.Identifier) + peer.AutomaticallyCreated = true + peer.GenerateDisplayName("Default") + + return peer, nil +} + // endregion helper-functions diff --git a/internal/app/wireguard/wireguard_peers_test.go b/internal/app/wireguard/wireguard_peers_test.go index 8ebb4b4..19dd1b2 100644 --- a/internal/app/wireguard/wireguard_peers_test.go +++ b/internal/app/wireguard/wireguard_peers_test.go @@ -61,6 +61,7 @@ type mockDB struct { savedPeers map[domain.PeerIdentifier]*domain.Peer iface *domain.Interface interfaces []domain.Interface + users []domain.User } func (f *mockDB) GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error) { @@ -141,6 +142,15 @@ func (f *mockDB) GetUsedIpsPerSubnet(ctx context.Context, subnets []domain.Cidr) ) { return map[domain.Cidr][]domain.Cidr{}, nil } +func (f *mockDB) GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) { + return &domain.User{ + Identifier: id, + IsAdmin: false, + }, nil +} +func (f *mockDB) GetAllUsers(ctx context.Context) ([]domain.User, error) { + return f.users, nil +} // --- Test --- @@ -205,7 +215,7 @@ func TestCreatePeer_SetsIdentifier_FromPublicKey(t *testing.T) { func TestCreateDefaultPeer_RespectsInterfaceFlag(t *testing.T) { // Arrange cfg := &config.Config{} - cfg.Core.CreateDefaultPeer = true + cfg.Core.CreateDefaultPeerOnLogin = true bus := &mockBus{} ctrlMgr := &ControllerManager{ diff --git a/internal/config/config.go b/internal/config/config.go index a88b2d1..fa3f1fc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,14 +21,17 @@ type Config struct { AdminPassword string `yaml:"admin_password"` AdminApiToken string `yaml:"admin_api_token"` // if set, the API access is enabled automatically - EditableKeys bool `yaml:"editable_keys"` - CreateDefaultPeer bool `yaml:"create_default_peer"` - CreateDefaultPeerOnCreation bool `yaml:"create_default_peer_on_creation"` - ReEnablePeerAfterUserEnable bool `yaml:"re_enable_peer_after_user_enable"` - DeletePeerAfterUserDeleted bool `yaml:"delete_peer_after_user_deleted"` - SelfProvisioningAllowed bool `yaml:"self_provisioning_allowed"` - ImportExisting bool `yaml:"import_existing"` - RestoreState bool `yaml:"restore_state"` + EditableKeys bool `yaml:"editable_keys"` + CreateDefaultPeer bool `yaml:"create_default_peer"` // DEPRECATED: in favor of CreateDefaultPeerOnLogin + CreateDefaultPeerOnCreation bool `yaml:"create_default_peer_on_creation"` // DEPRECATED: in favor of CreateDefaultPeerOnUserCreation + CreateDefaultPeerOnLogin bool `yaml:"create_default_peer_on_login"` + CreateDefaultPeerOnUserCreation bool `yaml:"create_default_peer_on_user_creation"` + CreateDefaultPeerOnInterfaceCreation bool `yaml:"create_default_peer_on_interface_creation"` + ReEnablePeerAfterUserEnable bool `yaml:"re_enable_peer_after_user_enable"` + DeletePeerAfterUserDeleted bool `yaml:"delete_peer_after_user_deleted"` + SelfProvisioningAllowed bool `yaml:"self_provisioning_allowed"` + ImportExisting bool `yaml:"import_existing"` + RestoreState bool `yaml:"restore_state"` } `yaml:"core"` Advanced struct { @@ -78,7 +81,7 @@ func (c *Config) LogStartupValues() { slog.Debug("Config Features", "editableKeys", c.Core.EditableKeys, - "createDefaultPeerOnCreation", c.Core.CreateDefaultPeerOnCreation, + "createDefaultPeerOnCreation", c.Core.CreateDefaultPeerOnUserCreation, "reEnablePeerAfterUserEnable", c.Core.ReEnablePeerAfterUserEnable, "deletePeerAfterUserDeleted", c.Core.DeletePeerAfterUserDeleted, "selfProvisioningAllowed", c.Core.SelfProvisioningAllowed, @@ -112,6 +115,13 @@ func (c *Config) LogStartupValues() { } +// DefaultPeerCreationEnabled returns true if at least one default peer generation mechanism is enabled. +func (c *Config) DefaultPeerCreationEnabled() bool { + return c.Core.CreateDefaultPeerOnLogin || + c.Core.CreateDefaultPeerOnInterfaceCreation || + c.Core.CreateDefaultPeerOnUserCreation +} + // defaultConfig returns the default configuration func defaultConfig() *Config { cfg := &Config{} @@ -122,8 +132,13 @@ func defaultConfig() *Config { cfg.Core.AdminApiToken = getEnvStr("WG_PORTAL_CORE_ADMIN_API_TOKEN", "") // by default, the API access is disabled cfg.Core.ImportExisting = getEnvBool("WG_PORTAL_CORE_IMPORT_EXISTING", true) cfg.Core.RestoreState = getEnvBool("WG_PORTAL_CORE_RESTORE_STATE", true) - cfg.Core.CreateDefaultPeer = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER", false) - cfg.Core.CreateDefaultPeerOnCreation = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_CREATION", false) + cfg.Core.CreateDefaultPeer = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER", false) // deprecated + cfg.Core.CreateDefaultPeerOnCreation = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_CREATION", + false) // deprecated + cfg.Core.CreateDefaultPeerOnLogin = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER", false) + cfg.Core.CreateDefaultPeerOnUserCreation = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_USER_CREATION", false) + cfg.Core.CreateDefaultPeerOnInterfaceCreation = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_INTERFACE_CREATION", + false) cfg.Core.EditableKeys = getEnvBool("WG_PORTAL_CORE_EDITABLE_KEYS", true) cfg.Core.SelfProvisioningAllowed = getEnvBool("WG_PORTAL_CORE_SELF_PROVISIONING_ALLOWED", false) cfg.Core.ReEnablePeerAfterUserEnable = getEnvBool("WG_PORTAL_CORE_RE_ENABLE_PEER_AFTER_USER_ENABLE", true) @@ -246,6 +261,8 @@ func GetConfig() (*Config, error) { } } + handleDeprecatedConfigValues(cfg) + return cfg, nil } @@ -339,3 +356,18 @@ func getEnvDuration(name string, fallback time.Duration) time.Duration { return d } + +func handleDeprecatedConfigValues(cfg *Config) { + // deprecated, will be removed in 2.4 + if cfg.Core.CreateDefaultPeer { + slog.Warn("DEPRECATION WARNING: deprecated core config option: create_default_peer (WG_PORTAL_CORE_CREATE_DEFAULT_PEER)") + cfg.Core.CreateDefaultPeerOnLogin = true + } + + // deprecated, will be removed in 2.4 + if cfg.Core.CreateDefaultPeerOnCreation { + slog.Warn("DEPRECATION WARNING: deprecated core config option: create_default_peer_on_creation (WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_CREATION)") + cfg.Core.CreateDefaultPeerOnUserCreation = true + cfg.Core.CreateDefaultPeerOnInterfaceCreation = true + } +} diff --git a/internal/domain/interface.go b/internal/domain/interface.go index 2efd5bf..fe484ec 100644 --- a/internal/domain/interface.go +++ b/internal/domain/interface.go @@ -240,6 +240,18 @@ func (i *Interface) GetRoutingTable() int { } } +// CreateDefaultPeers determines whether default peers should be created for this interface. +func (i *Interface) CreateDefaultPeers() bool { + if !i.CreateDefaultPeer { + return false // only create default peers if the interface flag is set + } + if i.Type != InterfaceTypeServer { + return false // only create default peers for server interfaces + } + + return true +} + type PhysicalInterface struct { Identifier InterfaceIdentifier // device name, for example: wg0 KeyPair // private/public Key of the server interface diff --git a/internal/domain/interface_test.go b/internal/domain/interface_test.go index 9f0ee50..a363cde 100644 --- a/internal/domain/interface_test.go +++ b/internal/domain/interface_test.go @@ -139,3 +139,29 @@ func TestInterface_GetRoutingTableNonLocal(t *testing.T) { iface.RoutingTable = "abc" assert.Equal(t, 0, iface.GetRoutingTable()) } + +func TestInterface_CreateDefaultPeers(t *testing.T) { + iface := &Interface{} + assert.False(t, iface.CreateDefaultPeers()) + + iface.CreateDefaultPeer = true + assert.False(t, iface.CreateDefaultPeers()) // still wrong type + + iface2 := &Interface{Type: InterfaceTypeServer} + assert.False(t, iface2.CreateDefaultPeers()) // CreateDefaultPeer flag is false + + iface2.CreateDefaultPeer = true + assert.True(t, iface2.CreateDefaultPeers()) + + iface3 := &Interface{Type: InterfaceTypeClient} + assert.False(t, iface3.CreateDefaultPeers()) + + iface3.CreateDefaultPeer = true + assert.False(t, iface3.CreateDefaultPeers()) + + iface4 := &Interface{Type: InterfaceTypeAny} + assert.False(t, iface4.CreateDefaultPeers()) + + iface4.CreateDefaultPeer = true + assert.False(t, iface4.CreateDefaultPeers()) +} diff --git a/internal/domain/user.go b/internal/domain/user.go index 872e52b..39fc982 100644 --- a/internal/domain/user.go +++ b/internal/domain/user.go @@ -270,6 +270,18 @@ func (u *User) DisplayName() string { return displayName } +// CreateDefaultPeers determines whether default peers should be created for this user. +func (u *User) CreateDefaultPeers() bool { + if u.IsDisabled() { + return false + } + if u.IsLocked() { + return false + } + + return true +} + // region webauthn func (u *User) WebAuthnID() []byte { diff --git a/internal/domain/user_test.go b/internal/domain/user_test.go index 515a41c..7100c2d 100644 --- a/internal/domain/user_test.go +++ b/internal/domain/user_test.go @@ -145,3 +145,17 @@ func TestUser_HashPassword(t *testing.T) { user.Password = "" assert.NoError(t, user.HashPassword()) } + +func TestUser_CreateDefaultPeers(t *testing.T) { + user := &User{} + assert.True(t, user.CreateDefaultPeers()) + + user2 := &User{Disabled: &time.Time{}} + assert.False(t, user2.CreateDefaultPeers()) + + user3 := &User{Locked: &time.Time{}} + assert.False(t, user3.CreateDefaultPeers()) + + user4 := &User{Disabled: &time.Time{}, Locked: &time.Time{}} + assert.False(t, user4.CreateDefaultPeers()) +}