feat: introduce "Create Default Peer" flag for interfaces (#513)

This commit is contained in:
Christoph Haas
2026-01-06 00:16:08 +01:00
parent 1b56acac87
commit 2a9d5e3ea8
14 changed files with 135 additions and 24 deletions

View File

@@ -145,6 +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,
})
}
}

View File

@@ -14,6 +14,7 @@ type Settings struct {
MinPasswordLength int `json:"MinPasswordLength"`
AvailableBackends []SettingsBackendNames `json:"AvailableBackends"`
LoginFormVisible bool `json:"LoginFormVisible"`
CreateDefaultPeer bool `json:"CreateDefaultPeer"`
}
type SettingsBackendNames struct {

View File

@@ -9,15 +9,16 @@ import (
)
type Interface struct {
Identifier string `json:"Identifier" example:"wg0"` // device name, for example: wg0
DisplayName string `json:"DisplayName"` // a nice display name/ description for the interface
Mode string `json:"Mode" example:"server"` // the interface type, either 'server', 'client' or 'any'
Backend string `json:"Backend" example:"local"` // the backend used for this interface e.g., local, mikrotik, ...
PrivateKey string `json:"PrivateKey" example:"abcdef=="` // private Key of the server interface
PublicKey string `json:"PublicKey" example:"abcdef=="` // public Key of the server interface
Disabled bool `json:"Disabled"` // flag that specifies if the interface is enabled (up) or not (down)
DisabledReason string `json:"DisabledReason"` // the reason why the interface has been disabled
SaveConfig bool `json:"SaveConfig"` // automatically persist config changes to the wgX.conf file
Identifier string `json:"Identifier" example:"wg0"` // device name, for example: wg0
DisplayName string `json:"DisplayName"` // a nice display name/ description for the interface
Mode string `json:"Mode" example:"server"` // the interface type, either 'server', 'client' or 'any'
Backend string `json:"Backend" example:"local"` // the backend used for this interface e.g., local, mikrotik, ...
PrivateKey string `json:"PrivateKey" example:"abcdef=="` // private Key of the server interface
PublicKey string `json:"PublicKey" example:"abcdef=="` // public Key of the server interface
Disabled bool `json:"Disabled"` // flag that specifies if the interface is enabled (up) or not (down)
DisabledReason string `json:"DisabledReason"` // the reason why the interface has been disabled
SaveConfig bool `json:"SaveConfig"` // automatically persist config changes to the wgX.conf file
CreateDefaultPeer bool `json:"CreateDefaultPeer"` // if true, default peers will be created for this interface
ListenPort int `json:"ListenPort"` // the listening port, for example: 51820
Addresses []string `json:"Addresses"` // the interface ip addresses
@@ -65,6 +66,7 @@ func NewInterface(src *domain.Interface, peers []domain.Peer) *Interface {
Disabled: src.IsDisabled(),
DisabledReason: src.DisabledReason,
SaveConfig: src.SaveConfig,
CreateDefaultPeer: src.CreateDefaultPeer,
ListenPort: src.ListenPort,
Addresses: domain.CidrsToStringSlice(src.Addresses),
Dns: internal.SliceString(src.DnsStr),
@@ -151,6 +153,7 @@ func NewDomainInterface(src *Interface) *domain.Interface {
PreDown: src.PreDown,
PostDown: src.PostDown,
SaveConfig: src.SaveConfig,
CreateDefaultPeer: src.CreateDefaultPeer,
DisplayName: src.DisplayName,
Type: domain.InterfaceType(src.Mode),
Backend: domain.InterfaceBackend(src.Backend),

View File

@@ -374,6 +374,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,
DriverType: "",
Disabled: nil,
DisabledReason: "",

View File

@@ -35,6 +35,10 @@ func (m Manager) CreateDefaultPeer(ctx context.Context, userId domain.UserIdenti
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
})

View File

@@ -78,7 +78,12 @@ func (f *mockDB) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceId
func (f *mockDB) GetPeersStats(ctx context.Context, ids ...domain.PeerIdentifier) ([]domain.PeerStatus, error) {
return nil, nil
}
func (f *mockDB) GetAllInterfaces(ctx context.Context) ([]domain.Interface, error) { return nil, nil }
func (f *mockDB) GetAllInterfaces(ctx context.Context) ([]domain.Interface, error) {
if f.iface != nil {
return []domain.Interface{*f.iface}, nil
}
return nil, nil
}
func (f *mockDB) GetInterfaceIps(ctx context.Context) (map[domain.InterfaceIdentifier][]domain.Cidr, error) {
return nil, nil
}
@@ -192,3 +197,58 @@ func TestCreatePeer_SetsIdentifier_FromPublicKey(t *testing.T) {
t.Fatalf("expected peer with identifier %q to be saved in DB", expectedId)
}
}
func TestCreateDefaultPeer_RespectsInterfaceFlag(t *testing.T) {
// Arrange
cfg := &config.Config{}
cfg.Core.CreateDefaultPeer = true
bus := &mockBus{}
ctrlMgr := &ControllerManager{
controllers: map[domain.InterfaceBackend]backendInstance{
config.LocalBackendName: {Implementation: &mockController{}},
},
}
db := &mockDB{
iface: &domain.Interface{
Identifier: "wg0",
Type: domain.InterfaceTypeServer,
CreateDefaultPeer: false, // Flag is disabled!
},
}
m := Manager{
cfg: cfg,
bus: bus,
db: db,
wg: ctrlMgr,
}
userId := domain.UserIdentifier("user@example.com")
ctx := domain.SetUserInfo(context.Background(), &domain.ContextUserInfo{Id: userId, IsAdmin: true})
// Act
err := m.CreateDefaultPeer(ctx, userId)
// Assert
if err != nil {
t.Fatalf("CreateDefaultPeer returned error: %v", err)
}
if len(db.savedPeers) != 0 {
t.Fatalf("expected no peers to be created because interface flag is false, but got %d", len(db.savedPeers))
}
// Now enable the flag and try again
db.iface.CreateDefaultPeer = true
err = m.CreateDefaultPeer(ctx, userId)
if err != nil {
t.Fatalf("CreateDefaultPeer returned error after enabling flag: %v", err)
}
if len(db.savedPeers) != 1 {
t.Fatalf("expected 1 peer to be created because interface flag is true, but got %d", len(db.savedPeers))
}
}