package device import ( "context" "github.com/google/uuid" "github.com/nexavpn/nexavpn/backend/internal/gateway" "github.com/nexavpn/nexavpn/backend/internal/ipam" "github.com/nexavpn/nexavpn/backend/internal/policy" "github.com/nexavpn/nexavpn/backend/internal/profile" ) type Service struct { repo Repository policyService *policy.Service gatewayService *gateway.Service ipamService *ipam.Service } func NewService(repo Repository, policyService *policy.Service, gatewayService *gateway.Service, ipamService *ipam.Service) *Service { return &Service{ repo: repo, policyService: policyService, gatewayService: gatewayService, ipamService: ipamService, } } func (s *Service) Enroll(ctx context.Context, userID uuid.UUID, input EnrollRequest, privateKeyPlaceholder string) (EnrollmentResponse, error) { selectedGateway, err := s.gatewayService.SelectActive(ctx) if err != nil { return EnrollmentResponse{}, err } assignedIP, err := s.ipamService.Allocate(selectedGateway.VPNCIDR, 10) if err != nil { return EnrollmentResponse{}, err } enrollment, err := s.repo.Enroll(ctx, userID, selectedGateway.ID, input, assignedIP, selectedGateway.DNSServers, nil) if err != nil { return EnrollmentResponse{}, err } destinations, err := s.policyService.ResolveDestinations(ctx, userID, &enrollment.Device.ID) if err != nil { return EnrollmentResponse{}, err } if len(destinations) == 0 { destinations = []string{"172.16.10.0/24"} } enrollment.Peer = PeerView{ AssignedIP: assignedIP, DNSServers: selectedGateway.DNSServers, AllowedIPs: destinations, Gateway: GatewayView{ ID: selectedGateway.ID, Name: selectedGateway.Name, Endpoint: selectedGateway.Endpoint, PublicKey: selectedGateway.PublicKey, }, ProfileRevision: 1, } for _, destination := range destinations { enrollment.Resources = append(enrollment.Resources, Resource{ Type: "cidr", Value: destination, Label: destination, }) } enrollment.Profile = ProfileView{ Format: "wireguard", Content: profile.BuildWireGuardConfig(profile.BuildInput{ PrivateKey: privateKeyPlaceholder, Address: assignedIP, DNSServers: selectedGateway.DNSServers, ServerPublicKey: selectedGateway.PublicKey, ServerEndpoint: selectedGateway.Endpoint, AllowedIPs: destinations, PersistentKeepal: 25, }), } return enrollment, nil } func (s *Service) ListByUser(ctx context.Context, userID uuid.UUID) ([]Device, error) { return s.repo.ListByUser(ctx, userID) } func (s *Service) ListAll(ctx context.Context) ([]Device, error) { return s.repo.ListAll(ctx) } func (s *Service) GetLatestEnrollmentByUser(ctx context.Context, userID uuid.UUID) (EnrollmentResponse, error) { return s.repo.GetLatestEnrollmentByUser(ctx, userID) } func (s *Service) GetEnrollmentByDeviceID(ctx context.Context, deviceID uuid.UUID) (EnrollmentResponse, error) { return s.repo.GetEnrollmentByDeviceID(ctx, deviceID) } func (s *Service) GetConnectionStatus(ctx context.Context, userID uuid.UUID) (ConnectionStatus, error) { enrollment, err := s.repo.GetLatestEnrollmentByUser(ctx, userID) if err != nil { return ConnectionStatus{ Status: "disconnected", Resources: []Resource{}, }, nil } lastSync := "just now" return ConnectionStatus{ Status: "provisioned", AssignedIP: enrollment.Peer.AssignedIP, LastSyncTime: &lastSync, Resources: enrollment.Resources, }, nil } func (s *Service) Revoke(ctx context.Context, deviceID uuid.UUID) error { return s.repo.Revoke(ctx, deviceID) } func (s *Service) Rotate(ctx context.Context, deviceID uuid.UUID) error { return s.repo.Rotate(ctx, deviceID) }