Files
arthur_chen f69efb67ad Initial commit: abyssVpn project
- Tauri desktop app (apps/desktop)
- Python Django API service (services/api)
- Deployment scripts and docs
2026-05-15 09:06:10 +08:00

143 lines
5.0 KiB
Python

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})