mirror of
https://github.com/h44z/wg-portal.git
synced 2026-04-17 13:06:21 +00:00
create default peers for newly created interfaces (#666)
This commit is contained in:
@@ -6,8 +6,9 @@ advanced:
|
|||||||
core:
|
core:
|
||||||
admin_user: test@test.de
|
admin_user: test@test.de
|
||||||
admin_password: secret
|
admin_password: secret
|
||||||
create_default_peer: true
|
create_default_peer_on_login: true
|
||||||
create_default_peer_on_creation: false
|
create_default_peer_on_user_creation: false
|
||||||
|
create_default_peer_on_interface_creation: false
|
||||||
|
|
||||||
web:
|
web:
|
||||||
external_url: http://localhost:8888
|
external_url: http://localhost:8888
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ core:
|
|||||||
admin_password: password
|
admin_password: password
|
||||||
admin_api_token: super-s3cr3t-api-token-or-a-UUID
|
admin_api_token: super-s3cr3t-api-token-or-a-UUID
|
||||||
import_existing: false
|
import_existing: false
|
||||||
create_default_peer: true
|
create_default_peer_on_login: true
|
||||||
self_provisioning_allowed: true
|
self_provisioning_allowed: true
|
||||||
|
|
||||||
backend:
|
backend:
|
||||||
|
|||||||
@@ -155,17 +155,33 @@ More advanced options are found in the subsequent `Advanced` section.
|
|||||||
- **Environment Variable:** `WG_PORTAL_CORE_EDITABLE_KEYS`
|
- **Environment Variable:** `WG_PORTAL_CORE_EDITABLE_KEYS`
|
||||||
- **Description:** Allow editing of WireGuard key-pairs directly in the UI.
|
- **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`
|
- **Default:** `false`
|
||||||
- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER`
|
- **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.
|
- **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).
|
- **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`
|
- **Default:** `false`
|
||||||
- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_CREATION`
|
- **Environment Variable:** `WG_PORTAL_CORE_CREATE_DEFAULT_PEER_ON_USER_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.
|
- **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 requires [create_default_peer](#create_default_peer) to be enabled.
|
- **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`
|
### `re_enable_peer_after_user_enable`
|
||||||
- **Default:** `true`
|
- **Default:** `true`
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ func (r *SqlRepo) migrate() error {
|
|||||||
if existingSysStat.SchemaVersion == 1 {
|
if existingSysStat.SchemaVersion == 1 {
|
||||||
const schemaVersion = 2
|
const schemaVersion = 2
|
||||||
// Preserve existing behavior for installations that had default-peer-creation enabled.
|
// 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{}).
|
err := r.db.Model(&domain.Interface{}).
|
||||||
Where("type = ?", domain.InterfaceTypeServer).
|
Where("type = ?", domain.InterfaceTypeServer).
|
||||||
Update("create_default_peer", true).Error
|
Update("create_default_peer", true).Error
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ func (e ConfigEndpoint) handleSettingsGet() http.HandlerFunc {
|
|||||||
MinPasswordLength: e.cfg.Auth.MinPasswordLength,
|
MinPasswordLength: e.cfg.Auth.MinPasswordLength,
|
||||||
AvailableBackends: controllerFn(),
|
AvailableBackends: controllerFn(),
|
||||||
LoginFormVisible: !e.cfg.Auth.HideLoginForm || !hasSocialLogin,
|
LoginFormVisible: !e.cfg.Auth.HideLoginForm || !hasSocialLogin,
|
||||||
CreateDefaultPeer: e.cfg.Core.CreateDefaultPeer,
|
CreateDefaultPeer: e.cfg.DefaultPeerCreationEnabled(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type InterfaceAndPeerDatabaseRepo interface {
|
|||||||
GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error)
|
GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error)
|
||||||
GetUsedIpsPerSubnet(ctx context.Context, subnets []domain.Cidr) (map[domain.Cidr][]domain.Cidr, error)
|
GetUsedIpsPerSubnet(ctx context.Context, subnets []domain.Cidr) (map[domain.Cidr][]domain.Cidr, error)
|
||||||
GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error)
|
GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error)
|
||||||
|
GetAllUsers(ctx context.Context) ([]domain.User, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type WgQuickController interface {
|
type WgQuickController interface {
|
||||||
@@ -60,6 +61,7 @@ type Manager struct {
|
|||||||
wg *ControllerManager
|
wg *ControllerManager
|
||||||
|
|
||||||
userLockMap *sync.Map
|
userLockMap *sync.Map
|
||||||
|
interfaceLockMap *sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWireGuardManager(
|
func NewWireGuardManager(
|
||||||
@@ -74,6 +76,7 @@ func NewWireGuardManager(
|
|||||||
wg: wg,
|
wg: wg,
|
||||||
db: db,
|
db: db,
|
||||||
userLockMap: &sync.Map{},
|
userLockMap: &sync.Map{},
|
||||||
|
interfaceLockMap: &sync.Map{},
|
||||||
}
|
}
|
||||||
|
|
||||||
m.connectToMessageBus()
|
m.connectToMessageBus()
|
||||||
@@ -93,10 +96,11 @@ func (m Manager) connectToMessageBus() {
|
|||||||
_ = m.bus.Subscribe(app.TopicUserDisabled, m.handleUserDisabledEvent)
|
_ = m.bus.Subscribe(app.TopicUserDisabled, m.handleUserDisabledEvent)
|
||||||
_ = m.bus.Subscribe(app.TopicUserEnabled, m.handleUserEnabledEvent)
|
_ = m.bus.Subscribe(app.TopicUserEnabled, m.handleUserEnabledEvent)
|
||||||
_ = m.bus.Subscribe(app.TopicUserDeleted, m.handleUserDeletedEvent)
|
_ = m.bus.Subscribe(app.TopicUserDeleted, m.handleUserDeletedEvent)
|
||||||
|
_ = m.bus.Subscribe(app.TopicInterfaceCreated, m.handleInterfaceCreatedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Manager) handleUserCreationEvent(user domain.User) {
|
func (m Manager) handleUserCreationEvent(user domain.User) {
|
||||||
if !m.cfg.Core.CreateDefaultPeerOnCreation {
|
if !m.cfg.Core.CreateDefaultPeerOnUserCreation {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +121,7 @@ func (m Manager) handleUserCreationEvent(user domain.User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m Manager) handleUserLoginEvent(userId domain.UserIdentifier) {
|
func (m Manager) handleUserLoginEvent(userId domain.UserIdentifier) {
|
||||||
if !m.cfg.Core.CreateDefaultPeer {
|
if !m.cfg.Core.CreateDefaultPeerOnLogin {
|
||||||
return
|
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) {
|
func (m Manager) runExpiredPeersCheck(ctx context.Context) {
|
||||||
ctx = domain.SetUserInfo(ctx, domain.SystemAdminContextUserInfo())
|
ctx = domain.SetUserInfo(ctx, domain.SystemAdminContextUserInfo())
|
||||||
|
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ func (m Manager) PrepareInterface(ctx context.Context) (*domain.Interface, error
|
|||||||
SaveConfig: m.cfg.Advanced.ConfigStoragePath != "",
|
SaveConfig: m.cfg.Advanced.ConfigStoragePath != "",
|
||||||
DisplayName: string(id),
|
DisplayName: string(id),
|
||||||
Type: domain.InterfaceTypeServer,
|
Type: domain.InterfaceTypeServer,
|
||||||
CreateDefaultPeer: m.cfg.Core.CreateDefaultPeer,
|
CreateDefaultPeer: m.cfg.DefaultPeerCreationEnabled(),
|
||||||
DriverType: "",
|
DriverType: "",
|
||||||
Disabled: nil,
|
Disabled: nil,
|
||||||
DisabledReason: "",
|
DisabledReason: "",
|
||||||
|
|||||||
@@ -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) {
|
func TestInterface_IsUserAllowed(t *testing.T) {
|
||||||
cfg := &config.Config{
|
cfg := &config.Config{
|
||||||
Auth: config.Auth{
|
Auth: config.Auth{
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ import (
|
|||||||
|
|
||||||
// CreateDefaultPeer creates a default peer for the given user on all server interfaces.
|
// CreateDefaultPeer creates a default peer for the given user on all server interfaces.
|
||||||
func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdentifier) error {
|
func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdentifier) error {
|
||||||
|
if !m.cfg.DefaultPeerCreationEnabled() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := domain.ValidateAdminAccessRights(ctx); err != nil {
|
if err := domain.ValidateAdminAccessRights(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -24,40 +28,22 @@ func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdenti
|
|||||||
return fmt.Errorf("failed to fetch all interfaces: %w", err)
|
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 {
|
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
|
var newPeers []domain.Peer
|
||||||
for _, iface := range existingInterfaces {
|
for _, iface := range existingInterfaces {
|
||||||
if iface.Type != domain.InterfaceTypeServer {
|
peer, err := m.prepareDefaultPeer(ctx, &iface, user)
|
||||||
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)
|
|
||||||
if err != nil {
|
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
|
if peer != nil {
|
||||||
peer.Notes = fmt.Sprintf("Default peer created for user %s", userId)
|
|
||||||
peer.AutomaticallyCreated = true
|
|
||||||
peer.GenerateDisplayName("Default")
|
|
||||||
|
|
||||||
newPeers = append(newPeers, *peer)
|
newPeers = append(newPeers, *peer)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i, peer := range newPeers {
|
for i, peer := range newPeers {
|
||||||
_, err := m.CreatePeer(ctx, &newPeers[i])
|
_, err := m.CreatePeer(ctx, &newPeers[i])
|
||||||
@@ -67,9 +53,61 @@ func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdenti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.InfoContext(ctx, "created default peers for user",
|
slog.InfoContext(ctx, "created default peers for user", "user", userId, "count", len(newPeers))
|
||||||
"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
|
return nil
|
||||||
}
|
}
|
||||||
@@ -639,4 +677,39 @@ func (m Manager) checkInterfaceAccess(ctx context.Context, id domain.InterfaceId
|
|||||||
return nil
|
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
|
// endregion helper-functions
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ type mockDB struct {
|
|||||||
savedPeers map[domain.PeerIdentifier]*domain.Peer
|
savedPeers map[domain.PeerIdentifier]*domain.Peer
|
||||||
iface *domain.Interface
|
iface *domain.Interface
|
||||||
interfaces []domain.Interface
|
interfaces []domain.Interface
|
||||||
|
users []domain.User
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *mockDB) GetInterface(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, error) {
|
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
|
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 ---
|
// --- Test ---
|
||||||
|
|
||||||
@@ -205,7 +215,7 @@ func TestCreatePeer_SetsIdentifier_FromPublicKey(t *testing.T) {
|
|||||||
func TestCreateDefaultPeer_RespectsInterfaceFlag(t *testing.T) {
|
func TestCreateDefaultPeer_RespectsInterfaceFlag(t *testing.T) {
|
||||||
// Arrange
|
// Arrange
|
||||||
cfg := &config.Config{}
|
cfg := &config.Config{}
|
||||||
cfg.Core.CreateDefaultPeer = true
|
cfg.Core.CreateDefaultPeerOnLogin = true
|
||||||
|
|
||||||
bus := &mockBus{}
|
bus := &mockBus{}
|
||||||
ctrlMgr := &ControllerManager{
|
ctrlMgr := &ControllerManager{
|
||||||
|
|||||||
@@ -22,8 +22,11 @@ type Config struct {
|
|||||||
AdminApiToken string `yaml:"admin_api_token"` // if set, the API access is enabled automatically
|
AdminApiToken string `yaml:"admin_api_token"` // if set, the API access is enabled automatically
|
||||||
|
|
||||||
EditableKeys bool `yaml:"editable_keys"`
|
EditableKeys bool `yaml:"editable_keys"`
|
||||||
CreateDefaultPeer bool `yaml:"create_default_peer"`
|
CreateDefaultPeer bool `yaml:"create_default_peer"` // DEPRECATED: in favor of CreateDefaultPeerOnLogin
|
||||||
CreateDefaultPeerOnCreation bool `yaml:"create_default_peer_on_creation"`
|
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"`
|
ReEnablePeerAfterUserEnable bool `yaml:"re_enable_peer_after_user_enable"`
|
||||||
DeletePeerAfterUserDeleted bool `yaml:"delete_peer_after_user_deleted"`
|
DeletePeerAfterUserDeleted bool `yaml:"delete_peer_after_user_deleted"`
|
||||||
SelfProvisioningAllowed bool `yaml:"self_provisioning_allowed"`
|
SelfProvisioningAllowed bool `yaml:"self_provisioning_allowed"`
|
||||||
@@ -78,7 +81,7 @@ func (c *Config) LogStartupValues() {
|
|||||||
|
|
||||||
slog.Debug("Config Features",
|
slog.Debug("Config Features",
|
||||||
"editableKeys", c.Core.EditableKeys,
|
"editableKeys", c.Core.EditableKeys,
|
||||||
"createDefaultPeerOnCreation", c.Core.CreateDefaultPeerOnCreation,
|
"createDefaultPeerOnCreation", c.Core.CreateDefaultPeerOnUserCreation,
|
||||||
"reEnablePeerAfterUserEnable", c.Core.ReEnablePeerAfterUserEnable,
|
"reEnablePeerAfterUserEnable", c.Core.ReEnablePeerAfterUserEnable,
|
||||||
"deletePeerAfterUserDeleted", c.Core.DeletePeerAfterUserDeleted,
|
"deletePeerAfterUserDeleted", c.Core.DeletePeerAfterUserDeleted,
|
||||||
"selfProvisioningAllowed", c.Core.SelfProvisioningAllowed,
|
"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
|
// defaultConfig returns the default configuration
|
||||||
func defaultConfig() *Config {
|
func defaultConfig() *Config {
|
||||||
cfg := &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.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.ImportExisting = getEnvBool("WG_PORTAL_CORE_IMPORT_EXISTING", true)
|
||||||
cfg.Core.RestoreState = getEnvBool("WG_PORTAL_CORE_RESTORE_STATE", true)
|
cfg.Core.RestoreState = getEnvBool("WG_PORTAL_CORE_RESTORE_STATE", true)
|
||||||
cfg.Core.CreateDefaultPeer = getEnvBool("WG_PORTAL_CORE_CREATE_DEFAULT_PEER", 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)
|
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.EditableKeys = getEnvBool("WG_PORTAL_CORE_EDITABLE_KEYS", true)
|
||||||
cfg.Core.SelfProvisioningAllowed = getEnvBool("WG_PORTAL_CORE_SELF_PROVISIONING_ALLOWED", false)
|
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)
|
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
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,3 +356,18 @@ func getEnvDuration(name string, fallback time.Duration) time.Duration {
|
|||||||
|
|
||||||
return d
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 {
|
type PhysicalInterface struct {
|
||||||
Identifier InterfaceIdentifier // device name, for example: wg0
|
Identifier InterfaceIdentifier // device name, for example: wg0
|
||||||
KeyPair // private/public Key of the server interface
|
KeyPair // private/public Key of the server interface
|
||||||
|
|||||||
@@ -139,3 +139,29 @@ func TestInterface_GetRoutingTableNonLocal(t *testing.T) {
|
|||||||
iface.RoutingTable = "abc"
|
iface.RoutingTable = "abc"
|
||||||
assert.Equal(t, 0, iface.GetRoutingTable())
|
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())
|
||||||
|
}
|
||||||
|
|||||||
@@ -270,6 +270,18 @@ func (u *User) DisplayName() string {
|
|||||||
return displayName
|
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
|
// region webauthn
|
||||||
|
|
||||||
func (u *User) WebAuthnID() []byte {
|
func (u *User) WebAuthnID() []byte {
|
||||||
|
|||||||
@@ -145,3 +145,17 @@ func TestUser_HashPassword(t *testing.T) {
|
|||||||
user.Password = ""
|
user.Password = ""
|
||||||
assert.NoError(t, user.HashPassword())
|
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())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user