import json from django.http import HttpRequest, JsonResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_GET, require_POST from common.auth import get_current_user from .models import Device, VpnLog from .services.device_service import issue_connect_token from .services.netmaker_client import NetmakerApiError, NetmakerClient, NetmakerConfigError @csrf_exempt @require_POST def connect_token(request: HttpRequest) -> JsonResponse: user = get_current_user(request) if user is None: return JsonResponse({"error": "unauthorized"}, status=401) body = json.loads(request.body or b"{}") device_name = body.get("device_name") or "unknown-device" fingerprint = body.get("device_fingerprint") or "" try: token = issue_connect_token(user, device_name, fingerprint) except PermissionError as error: return JsonResponse({"error": str(error)}, status=403) except NetmakerConfigError as error: return JsonResponse({"error": str(error)}, status=503) except NetmakerApiError as error: return JsonResponse({"error": str(error)}, status=502) return JsonResponse({"token": token}) @require_GET def status(request: HttpRequest) -> JsonResponse: user = get_current_user(request) if user is None: return JsonResponse({"error": "unauthorized"}, status=401) devices = list(user.devices.values("id", "device_name", "status", "netmaker_node_id", "updated_at")) logs = list( VpnLog.objects.filter(user=user) .select_related("device") .order_by("-created_at") .values("id", "device_id", "action", "detail", "created_at")[:20] ) return JsonResponse( { "user": { "id": user.id, "name": user.name, "email": user.email, }, "devices": devices, "logs": logs, } ) @csrf_exempt @require_POST def register_node(request: HttpRequest) -> JsonResponse: user = get_current_user(request) if user is None: return JsonResponse({"error": "unauthorized"}, status=401) body = json.loads(request.body or b"{}") fingerprint = body.get("device_fingerprint") or "" node_id = body.get("netmaker_node_id") or body.get("host_id") or body.get("node_id") or "" device_name = body.get("device_name") or "unknown-device" if not fingerprint: return JsonResponse({"error": "missing_device_fingerprint"}, status=400) if not node_id: return JsonResponse({"error": "missing_netmaker_node_id"}, status=400) device, _created = Device.objects.get_or_create( user=user, device_fingerprint=fingerprint, defaults={"device_name": device_name}, ) if device.status == Device.STATUS_REVOKED: return JsonResponse({"error": "device_revoked"}, status=403) changed_fields = [] if device.device_name != device_name: device.device_name = device_name changed_fields.append("device_name") if device.netmaker_node_id != node_id: device.netmaker_node_id = node_id changed_fields.append("netmaker_node_id") if changed_fields: changed_fields.append("updated_at") device.save(update_fields=changed_fields) VpnLog.objects.create( user=user, device=device, action="netmaker_node_registered", detail={"netmaker_node_id": node_id}, ) return JsonResponse({"status": "ok", "device_id": device.id}) @csrf_exempt @require_POST def disconnect_log(request: HttpRequest) -> JsonResponse: user = get_current_user(request) if user is None: return JsonResponse({"error": "unauthorized"}, status=401) body = json.loads(request.body or b"{}") fingerprint = body.get("device_fingerprint") or "" device = Device.objects.filter(user=user, device_fingerprint=fingerprint).first() VpnLog.objects.create(user=user, device=device, action="disconnect", detail={"device_fingerprint": fingerprint}) return JsonResponse({"status": "ok"}) @csrf_exempt @require_POST def revoke_device(request: HttpRequest) -> JsonResponse: user = get_current_user(request) if user is None: return JsonResponse({"error": "unauthorized"}, status=401) body = json.loads(request.body or b"{}") device = Device.objects.filter(user=user, id=body.get("device_id")).first() if device is None: return JsonResponse({"error": "device_not_found"}, status=404) netmaker_error = "" if device.netmaker_node_id: try: NetmakerClient().delete_node(device.netmaker_node_id) except (NetmakerConfigError, NetmakerApiError) as error: netmaker_error = str(error) device.status = Device.STATUS_REVOKED device.save(update_fields=["status", "updated_at"]) VpnLog.objects.create( user=user, device=device, action="device_revoked", detail={"device_id": device.id, "netmaker_error": netmaker_error}, ) return JsonResponse({"status": "ok", "netmaker_error": netmaker_error})