fix multi-peer generation, fix prefix handling (#491)

This commit is contained in:
Christoph Haas 2025-08-09 15:55:29 +02:00
parent 3f76aa416f
commit c20f17cddf
No known key found for this signature in database
7 changed files with 41 additions and 45 deletions

View File

@ -32,7 +32,7 @@ const selectedInterface = computed(() => {
function freshForm() { function freshForm() {
return { return {
Identifiers: [], Identifiers: [],
Suffix: "", Prefix: "",
} }
} }
@ -102,7 +102,7 @@ async function save() {
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="form-label mt-4">{{ $t('modals.peer-multi-create.prefix.label') }}</label> <label class="form-label mt-4">{{ $t('modals.peer-multi-create.prefix.label') }}</label>
<input type="text" class="form-control" :placeholder="$t('modals.peer-multi-create.prefix.placeholder')" v-model="formData.Suffix"> <input type="text" class="form-control" :placeholder="$t('modals.peer-multi-create.prefix.placeholder')" v-model="formData.Prefix">
<small class="form-text text-muted">{{ $t('modals.peer-multi-create.prefix.description') }}</small> <small class="form-text text-muted">{{ $t('modals.peer-multi-create.prefix.description') }}</small>
</div> </div>
</fieldset> </fieldset>

View File

@ -1969,7 +1969,7 @@
"type": "string" "type": "string"
} }
}, },
"Suffix": { "Prefix": {
"type": "string" "type": "string"
} }
} }

View File

@ -206,7 +206,7 @@ definitions:
items: items:
type: string type: string
type: array type: array
Suffix: Prefix:
type: string type: string
type: object type: object
model.Peer: model.Peer:

View File

@ -139,7 +139,8 @@ func (s *Server) setupRoutes(endpoints ...ApiEndpointSetupFunc) {
s.versions[version].HandleFunc("GET /swagger/index.html", s.rapiDocHandler(version)) // Deprecated: old link s.versions[version].HandleFunc("GET /swagger/index.html", s.rapiDocHandler(version)) // Deprecated: old link
s.versions[version].HandleFunc("GET /doc.html", s.rapiDocHandler(version)) s.versions[version].HandleFunc("GET /doc.html", s.rapiDocHandler(version))
groupSetupFn(s.versions[version]) versionGroup := s.versions[version].Group()
groupSetupFn(versionGroup)
} }
} }
} }

View File

@ -172,13 +172,13 @@ func NewDomainPeer(src *Peer) *domain.Peer {
type MultiPeerRequest struct { type MultiPeerRequest struct {
Identifiers []string `json:"Identifiers"` Identifiers []string `json:"Identifiers"`
Suffix string `json:"Suffix"` Prefix string `json:"Prefix"`
} }
func NewDomainPeerCreationRequest(src *MultiPeerRequest) *domain.PeerCreationRequest { func NewDomainPeerCreationRequest(src *MultiPeerRequest) *domain.PeerCreationRequest {
return &domain.PeerCreationRequest{ return &domain.PeerCreationRequest{
UserIdentifiers: src.Identifiers, UserIdentifiers: src.Identifiers,
Suffix: src.Suffix, Prefix: src.Prefix,
} }
} }

View File

@ -188,29 +188,29 @@ func (m Manager) CreatePeer(ctx context.Context, peer *domain.Peer) (*domain.Pee
sessionUser := domain.GetUserInfo(ctx) sessionUser := domain.GetUserInfo(ctx)
// Enforce peer limit for non-admin users if LimitAdditionalUserPeers is set // Enforce peer limit for non-admin users if LimitAdditionalUserPeers is set
if m.cfg.Core.SelfProvisioningAllowed && !sessionUser.IsAdmin && m.cfg.Advanced.LimitAdditionalUserPeers > 0 { if m.cfg.Core.SelfProvisioningAllowed && !sessionUser.IsAdmin && m.cfg.Advanced.LimitAdditionalUserPeers > 0 {
peers, err := m.db.GetUserPeers(ctx, peer.UserIdentifier) peers, err := m.db.GetUserPeers(ctx, peer.UserIdentifier)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch peers for user %s: %w", peer.UserIdentifier, err) return nil, fmt.Errorf("failed to fetch peers for user %s: %w", peer.UserIdentifier, err)
} }
// Count enabled peers (disabled IS NULL) // Count enabled peers (disabled IS NULL)
peerCount := 0 peerCount := 0
for _, p := range peers { for _, p := range peers {
if !p.IsDisabled() { if !p.IsDisabled() {
peerCount++ peerCount++
} }
} }
totalAllowedPeers := 1 + m.cfg.Advanced.LimitAdditionalUserPeers // 1 default peer + x additional peers totalAllowedPeers := 1 + m.cfg.Advanced.LimitAdditionalUserPeers // 1 default peer + x additional peers
if peerCount >= totalAllowedPeers { if peerCount >= totalAllowedPeers {
slog.WarnContext(ctx, "peer creation blocked due to limit", slog.WarnContext(ctx, "peer creation blocked due to limit",
"user", peer.UserIdentifier, "user", peer.UserIdentifier,
"current_count", peerCount, "current_count", peerCount,
"allowed_count", totalAllowedPeers) "allowed_count", totalAllowedPeers)
return nil, fmt.Errorf("peer limit reached (%d peers allowed): %w", totalAllowedPeers, domain.ErrNoPermission) return nil, fmt.Errorf("peer limit reached (%d peers allowed): %w", totalAllowedPeers,
} domain.ErrNoPermission)
} }
}
existingPeer, err := m.db.GetPeer(ctx, peer.Identifier) existingPeer, err := m.db.GetPeer(ctx, peer.Identifier)
if err != nil && !errors.Is(err, domain.ErrNotFound) { if err != nil && !errors.Is(err, domain.ErrNotFound) {
@ -257,7 +257,7 @@ func (m Manager) CreateMultiplePeers(
return nil, err return nil, err
} }
var newPeers []*domain.Peer createdPeers := make([]domain.Peer, 0, len(r.UserIdentifiers))
for _, id := range r.UserIdentifiers { for _, id := range r.UserIdentifiers {
freshPeer, err := m.PreparePeer(ctx, interfaceId) freshPeer, err := m.PreparePeer(ctx, interfaceId)
@ -266,27 +266,22 @@ func (m Manager) CreateMultiplePeers(
} }
freshPeer.UserIdentifier = domain.UserIdentifier(id) // use id as user identifier. peers are allowed to have invalid user identifiers freshPeer.UserIdentifier = domain.UserIdentifier(id) // use id as user identifier. peers are allowed to have invalid user identifiers
if r.Suffix != "" { if r.Prefix != "" {
freshPeer.DisplayName += " " + r.Suffix freshPeer.DisplayName = r.Prefix + " " + freshPeer.DisplayName
} }
if err := m.validatePeerCreation(ctx, nil, freshPeer); err != nil { if err := m.validatePeerCreation(ctx, nil, freshPeer); err != nil {
return nil, fmt.Errorf("creation not allowed: %w", err) return nil, fmt.Errorf("creation not allowed: %w", err)
} }
newPeers = append(newPeers, freshPeer) // Save immediately to reserve the assigned IPs so the next prepared peer gets the next free IPs
} if err := m.savePeers(ctx, freshPeer); err != nil {
return nil, fmt.Errorf("failed to create new peer %s: %w", freshPeer.Identifier, err)
}
err := m.savePeers(ctx, newPeers...) createdPeers = append(createdPeers, *freshPeer)
if err != nil {
return nil, fmt.Errorf("failed to create new peers: %w", err)
}
createdPeers := make([]domain.Peer, len(newPeers)) m.bus.Publish(app.TopicPeerCreated, *freshPeer)
for i := range newPeers {
createdPeers[i] = *newPeers[i]
m.bus.Publish(app.TopicPeerCreated, *newPeers[i])
} }
return createdPeers, nil return createdPeers, nil

View File

@ -269,5 +269,5 @@ func MergeToPhysicalPeer(pp *PhysicalPeer, p *Peer) {
type PeerCreationRequest struct { type PeerCreationRequest struct {
UserIdentifiers []string UserIdentifiers []string
Suffix string Prefix string
} }