diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d7563a5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +FROM docker.io/python:3.12.10-alpine3.21 + +ENV \ + LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 \ + # python: + PYTHONFAULTHANDLER=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONHASHSEED=random \ + PYTHONDONTWRITEBYTECODE=1 + +RUN apk add --update --no-cache zlib-dev libxml2-dev libxslt-dev libmemcached-dev \ + build-base gcc make alpine-sdk musl-dev postgresql-dev openldap-dev \ + py3-distutils-extra py3-distutils-extra-pyc shadow python3-dev linux-headers pcre-dev + +ENV VIRTUAL_ENV=/venv + +ENV DJANGO_CONFIGURATION=production + +ENV \ + # pip: + PIP_NO_CACHE_DIR=off \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=100 + + +RUN pip install --upgrade pip wheel +RUN python3 -m venv $VIRTUAL_ENV + +COPY requirements.txt . +RUN . /venv/bin/activate && pip install -r requirements.txt + +RUN mkdir -p /app +COPY ./ /app/ + +WORKDIR /app + +RUN . /venv/bin/activate && \ + DJANGO_SECRET_KEY=dummy \ + DJANGO_STATIC_ROOT=/app/static ./manage.py collectstatic --no-input + +RUN groupadd --gid 1001 app \ + && useradd --home-dir /app --shell /bin/bash --gid app --uid 1001 app + +RUN chown -R app:app ./ + +USER app + +ENV PATH="/venv/bin:$PATH" + diff --git a/ipv6ula/forms.py b/ipv6ula/forms.py index 0800a9f..400f21c 100644 --- a/ipv6ula/forms.py +++ b/ipv6ula/forms.py @@ -1,6 +1,8 @@ from django import forms - +import ipaddress from .models import validate_ula_prefix, ULA +from django.core.exceptions import ValidationError +import logging class ULAForm(forms.ModelForm): class Meta: @@ -17,3 +19,67 @@ class ULAGenerateForm(forms.ModelForm): class Meta: model = ULA fields = [ 'name', 'organization', 'website' ] + +class ULAUpdateForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + self.owner = kwargs.pop('owner', None) + super().__init__(*args, **kwargs) + + class Meta: + model = ULA + fields = [ 'prefix', 'name', 'organization', 'website' ] + + def clean_prefix(self): + prefix = self.cleaned_data.get("prefix") + if not prefix or not self.owner: + return prefix + + net_str = f"{prefix}/48" + net = ipaddress.IPv6Network(net_str, strict=False) + normalized_prefix = str(net[0]) + self.cleaned_data['prefix'] = normalized_prefix + + qs = ULA.objects.filter(prefix=normalized_prefix) + if self.instance.pk: + qs = qs.exclude(pk=self.instance.pk) + + if qs.exists(): + existing = qs.first() + if existing.owner != self.owner: + raise ValidationError("This prefix is already registered by another user.") + else: + self.instance = existing + return normalized_prefix + + +class ULADeleteForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + self.owner = kwargs.pop('owner', None) + super().__init__(*args, **kwargs) + + class Meta: + model = ULA + fields = [ 'prefix' ] + + def clean_prefix(self): + prefix = self.cleaned_data['prefix'] + + if not prefix or not self.owner: + return prefix + + net_str = f"{prefix}/48" + net = ipaddress.IPv6Network(net_str, strict=False) + normalized_prefix = str(net[0]) + self.cleaned_data['prefix'] = normalized_prefix + + try: + self.instance = ULA.objects.get(prefix=normalized_prefix, owner=self.owner) + except ULA.DoesNotExist: + raise ValidationError("No ULA with this prefix was found for the current user.") + + return normalized_prefix + + def delete(self): + if self.instance: + print(f"Deleting: {self.instance}") + self.instance.delete() diff --git a/ipv6ula/models.py b/ipv6ula/models.py index d7232ed..a91b964 100644 --- a/ipv6ula/models.py +++ b/ipv6ula/models.py @@ -31,7 +31,6 @@ def validate_ula_prefix(prefix): params = {'prefix': net } ) - class User(AbstractUser): pass @@ -41,7 +40,7 @@ class ULA(models.Model): on_delete=models.CASCADE ) - prefix = models.GenericIPAddressField(protocol='IPv6', unique=True, validators=[validate_ula_prefix]) + prefix = models.GenericIPAddressField(protocol='IPv6', unique=True) name = models.CharField(max_length=256) organization = models.CharField(max_length=256) website = models.URLField() @@ -54,7 +53,6 @@ class ULA(models.Model): net_str = f"{self.prefix}/48" net = ipaddress.IPv6Network(net_str, strict=False) self.prefix = str(net[0]) - super().save(*args, **kwargs) def __str__(self): diff --git a/ipv6ula/settings.py b/ipv6ula/settings.py index ab27519..12a7d55 100644 --- a/ipv6ula/settings.py +++ b/ipv6ula/settings.py @@ -140,7 +140,7 @@ USE_TZ = True STATIC_URL = '/static/' STATICFILES_DIRS = [ ] -STATIC_ROOT = "/home/app/app/static" +STATIC_ROOT = "/app/static" AUTHENTICATION_BACKENDS = [ diff --git a/ipv6ula/templates/ipv6ula/base.html b/ipv6ula/templates/ipv6ula/base.html index a005058..d9d6fb2 100644 --- a/ipv6ula/templates/ipv6ula/base.html +++ b/ipv6ula/templates/ipv6ula/base.html @@ -33,6 +33,14 @@ Submit existing prefix + + {% if user.is_authenticated %} Logged in as {{ user }}.