f69efb67ad
- Tauri desktop app (apps/desktop) - Python Django API service (services/api) - Deployment scripts and docs
143 lines
5.0 KiB
Python
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})
|