100 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import base64
 | 
						|
 | 
						|
from django.contrib.auth import get_user_model
 | 
						|
from django.utils.translation import gettext_lazy as _
 | 
						|
from rest_framework import serializers
 | 
						|
 | 
						|
from .models import *
 | 
						|
 | 
						|
class VPNPoolSerializer(serializers.ModelSerializer):
 | 
						|
    class Meta:
 | 
						|
        model = VPNPool
 | 
						|
        fields = '__all__'
 | 
						|
 | 
						|
class VPNNetworkReservationSerializer(serializers.ModelSerializer):
 | 
						|
    class Meta:
 | 
						|
        model = VPNNetworkReservation
 | 
						|
        fields = '__all__'
 | 
						|
 | 
						|
 | 
						|
class VPNNetworkSerializer(serializers.ModelSerializer):
 | 
						|
    class Meta:
 | 
						|
        model = VPNNetwork
 | 
						|
        fields = '__all__'
 | 
						|
 | 
						|
    # This is required for finding the VPN pool, but does not
 | 
						|
    # exist in the model
 | 
						|
    network_size = serializers.IntegerField(min_value=0,
 | 
						|
                                            max_value=128,
 | 
						|
                                            write_only=True)
 | 
						|
 | 
						|
    def validate_wireguard_public_key(self, value):
 | 
						|
        msg = _("Supplied key is not a valid wireguard public key")
 | 
						|
 | 
						|
        """ FIXME: verify that this does not create broken wireguard config files,
 | 
						|
        i.e. contains \n or similar!
 | 
						|
        We might even need to be more strict to not break wireguard...
 | 
						|
        """
 | 
						|
 | 
						|
        try:
 | 
						|
            base64.standard_b64decode(value)
 | 
						|
        except Exception as e:
 | 
						|
            raise serializers.ValidationError(msg)
 | 
						|
 | 
						|
        if '\n' in value:
 | 
						|
            raise serializers.ValidationError(msg)
 | 
						|
 | 
						|
        return value
 | 
						|
 | 
						|
    def validate(self, data):
 | 
						|
 | 
						|
        # FIXME: filter for status = active or similar
 | 
						|
        all_pools = VPNPool.objects.all()
 | 
						|
        sizes = [ p.subnetwork_size for p in all_pools ]
 | 
						|
 | 
						|
        pools = VPNPool.objects.filter(subnetwork_size=data['network_size'])
 | 
						|
 | 
						|
        if len(pools) == 0:
 | 
						|
            msg = _("No pool available for networks with size = {}. Available are: {}".format(data['network_size'], sizes))
 | 
						|
            raise serializers.ValidationError(msg)
 | 
						|
 | 
						|
        return data
 | 
						|
 | 
						|
    def create(self, validated_data):
 | 
						|
        """
 | 
						|
        Creating a new vpnnetwork - there are a couple of race conditions,
 | 
						|
        especially when run in parallel.
 | 
						|
 | 
						|
        What we should be doing:
 | 
						|
 | 
						|
        - create a reservation race free
 | 
						|
        - map the reservation to a network (?)
 | 
						|
        """
 | 
						|
 | 
						|
        pools = VPNPool.objects.filter(subnetwork_size=validated_data['network_size'])
 | 
						|
 | 
						|
        vpn_network = None
 | 
						|
 | 
						|
        for pool in pools:
 | 
						|
            if pool.num_free_networks > 0:
 | 
						|
                next_address = pool.next_free_network
 | 
						|
 | 
						|
                reservation, created = VPNNetworkReservation.objects.update_or_create(
 | 
						|
                    vpnpool=pool, address=next_address,
 | 
						|
                    defaults = {
 | 
						|
                        'status': 'used'
 | 
						|
                    })
 | 
						|
 | 
						|
                vpn_network = VPNNetwork.objects.create(
 | 
						|
                    owner=self.context['request'].user,
 | 
						|
                    network=reservation,
 | 
						|
                    wireguard_public_key=validated_data['wireguard_public_key']
 | 
						|
                )
 | 
						|
 | 
						|
                break
 | 
						|
        if not vpn_network:
 | 
						|
            # FIXME: use correct exception
 | 
						|
            raise Exception("Did not find any free pool")
 | 
						|
 | 
						|
 | 
						|
        return vpn_network
 |