Expand README with desktop platform requirements (Windows x86, macOS ARM), helper build commands, gateway utility scripts, and updated local test flow. Add realistic MVP usage section clarifying current platform build status, gateway configuration needs, and admin debug profile behavior with client private key handling.
155 lines
4.3 KiB
Go
155 lines
4.3 KiB
Go
package device
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"nexavpn/backend/internal/gateway"
|
|
"nexavpn/backend/internal/ipam"
|
|
"nexavpn/backend/internal/policy"
|
|
"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) {
|
|
enrollment, err := s.repo.GetLatestEnrollmentByUser(ctx, userID)
|
|
if err != nil {
|
|
return EnrollmentResponse{}, err
|
|
}
|
|
return withDebugProfile(enrollment), nil
|
|
}
|
|
|
|
func (s *Service) GetEnrollmentByDeviceID(ctx context.Context, deviceID uuid.UUID) (EnrollmentResponse, error) {
|
|
enrollment, err := s.repo.GetEnrollmentByDeviceID(ctx, deviceID)
|
|
if err != nil {
|
|
return EnrollmentResponse{}, err
|
|
}
|
|
return withDebugProfile(enrollment), nil
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
func withDebugProfile(enrollment EnrollmentResponse) EnrollmentResponse {
|
|
enrollment.Profile = ProfileView{
|
|
Format: "wireguard",
|
|
Content: profile.BuildWireGuardConfig(profile.BuildInput{
|
|
PrivateKey: "__CLIENT_PRIVATE_KEY_REQUIRED__",
|
|
Address: enrollment.Peer.AssignedIP,
|
|
DNSServers: enrollment.Peer.DNSServers,
|
|
ServerPublicKey: enrollment.Peer.Gateway.PublicKey,
|
|
ServerEndpoint: enrollment.Peer.Gateway.Endpoint,
|
|
AllowedIPs: enrollment.Peer.AllowedIPs,
|
|
PersistentKeepal: 25,
|
|
}),
|
|
}
|
|
return enrollment
|
|
}
|