mirror of
https://github.com/daniviga/django-ram.git
synced 2025-08-04 13:17:50 +02:00
Add firewall and auth on driver API
This commit is contained in:
@@ -3,4 +3,27 @@ from solo.admin import SingletonModelAdmin
|
||||
|
||||
from driver.models import DriverConfiguration
|
||||
|
||||
admin.site.register(DriverConfiguration, SingletonModelAdmin)
|
||||
|
||||
@admin.register(DriverConfiguration)
|
||||
class DriverConfigurationAdmin(SingletonModelAdmin):
|
||||
fieldsets = (
|
||||
(
|
||||
"Remote DCC-EX configuration",
|
||||
{
|
||||
"fields": (
|
||||
"remote_host",
|
||||
"remote_port",
|
||||
"timeout",
|
||||
)
|
||||
},
|
||||
),
|
||||
(
|
||||
"Firewall setting",
|
||||
{
|
||||
"fields": (
|
||||
"network",
|
||||
"subnet_mask",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.0.3 on 2022-04-10 15:46
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('driver', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='driverconfiguration',
|
||||
name='network',
|
||||
field=models.GenericIPAddressField(default='192.168.4.0', protocol='IPv4'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='driverconfiguration',
|
||||
name='subnet_mask',
|
||||
field=models.GenericIPAddressField(default='255.255.255.0', protocol='IPv4'),
|
||||
),
|
||||
]
|
@@ -0,0 +1,28 @@
|
||||
# Generated by Django 4.0.3 on 2022-04-10 16:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('driver', '0002_driverconfiguration_network_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='driverconfiguration',
|
||||
name='network',
|
||||
field=models.GenericIPAddressField(blank=True, default='192.168.4.0', null=True, protocol='IPv4'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='driverconfiguration',
|
||||
name='remote_host',
|
||||
field=models.GenericIPAddressField(blank=True, default='192.168.4.1', null=True, protocol='IPv4'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='driverconfiguration',
|
||||
name='subnet_mask',
|
||||
field=models.GenericIPAddressField(blank=True, default='255.255.255.0', null=True, protocol='IPv4'),
|
||||
),
|
||||
]
|
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.0.3 on 2022-04-10 16:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('driver', '0003_alter_driverconfiguration_network_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='driverconfiguration',
|
||||
name='remote_host',
|
||||
field=models.GenericIPAddressField(default='192.168.4.1', protocol='IPv4'),
|
||||
),
|
||||
]
|
@@ -1,16 +1,41 @@
|
||||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
from ipaddress import IPv4Address, IPv4Network
|
||||
from solo.models import SingletonModel
|
||||
|
||||
|
||||
class DriverConfiguration(SingletonModel):
|
||||
remote_host = models.GenericIPAddressField(
|
||||
protocol="IPv4", default="192.168.4.1"
|
||||
protocol="IPv4",
|
||||
default="192.168.4.1"
|
||||
)
|
||||
remote_port = models.SmallIntegerField(default=2560)
|
||||
timeout = models.SmallIntegerField(default=250)
|
||||
|
||||
network = models.GenericIPAddressField(
|
||||
protocol="IPv4",
|
||||
default="192.168.4.0",
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
subnet_mask = models.GenericIPAddressField(
|
||||
protocol="IPv4",
|
||||
default="255.255.255.0",
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "Configuration"
|
||||
|
||||
def clean(self, *args, **kwargs):
|
||||
if self.network:
|
||||
try:
|
||||
IPv4Network(
|
||||
"{0}/{1}".format(self.network, self.subnet_mask))
|
||||
except ValueError as e:
|
||||
raise ValidationError(e)
|
||||
super().clean(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Configuration"
|
||||
|
@@ -1,10 +1,17 @@
|
||||
from ipaddress import IPv4Address, IPv4Network
|
||||
from django.http import Http404
|
||||
from django.utils.decorators import method_decorator
|
||||
from rest_framework import status, serializers
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import (
|
||||
IsAuthenticated,
|
||||
BasePermission,
|
||||
SAFE_METHODS
|
||||
)
|
||||
|
||||
from dcc.parsers import PlainTextParser
|
||||
from driver.models import DriverConfiguration
|
||||
from driver.connector import Connector
|
||||
from driver.serializers import (
|
||||
FunctionSerializer,
|
||||
@@ -27,12 +34,35 @@ def addresschecker(f):
|
||||
return addresslookup
|
||||
|
||||
|
||||
class Firewall(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
config = DriverConfiguration.get_solo()
|
||||
if not config.network:
|
||||
return request.method in SAFE_METHODS
|
||||
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = IPv4Address(x_forwarded_for.split(',')[0])
|
||||
else:
|
||||
ip = IPv4Address(request.META.get("REMOTE_ADDR"))
|
||||
|
||||
network = IPv4Network("{0}/{1}".format(
|
||||
config.network,
|
||||
config.subnet_mask
|
||||
))
|
||||
|
||||
# accept IP configured is settings or localhost
|
||||
if ip in network or ip in IPv4Network("127.0.0.0/8"):
|
||||
return request.method in SAFE_METHODS
|
||||
|
||||
|
||||
class Test(APIView):
|
||||
"""
|
||||
Send a test <s> command
|
||||
"""
|
||||
|
||||
parser_classes = [PlainTextParser]
|
||||
permission_classes = [IsAuthenticated | Firewall]
|
||||
|
||||
def get(self, request):
|
||||
response = Connector().passthrough("<s>")
|
||||
@@ -47,6 +77,7 @@ class SendCommand(APIView):
|
||||
"""
|
||||
|
||||
parser_classes = [PlainTextParser]
|
||||
permission_classes = [IsAuthenticated | Firewall]
|
||||
|
||||
def put(self, request):
|
||||
data = request.data
|
||||
@@ -70,6 +101,7 @@ class Function(APIView):
|
||||
"""
|
||||
Send "Function" commands to a valid DCC address
|
||||
"""
|
||||
permission_classes = [IsAuthenticated | Firewall]
|
||||
|
||||
def put(self, request, address):
|
||||
serializer = FunctionSerializer(data=request.data)
|
||||
@@ -85,6 +117,7 @@ class Cab(APIView):
|
||||
"""
|
||||
Send "Cab" commands to a valid DCC address
|
||||
"""
|
||||
permission_classes = [IsAuthenticated | Firewall]
|
||||
|
||||
def put(self, request, address):
|
||||
serializer = CabSerializer(data=request.data)
|
||||
@@ -99,6 +132,7 @@ class Infra(APIView):
|
||||
"""
|
||||
Send "Infra" commands to a valid DCC address
|
||||
"""
|
||||
permission_classes = [IsAuthenticated | Firewall]
|
||||
|
||||
def put(self, request):
|
||||
serializer = InfraSerializer(data=request.data)
|
||||
@@ -113,6 +147,7 @@ class Emergency(APIView):
|
||||
"""
|
||||
Send an "Emergency" stop, no matter the HTTP method used
|
||||
"""
|
||||
permission_classes = [IsAuthenticated | Firewall]
|
||||
|
||||
def put(self, request):
|
||||
Connector().emergency()
|
||||
|
@@ -1,3 +1,7 @@
|
||||
.card > a > img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#footer > p {
|
||||
display: inline;
|
||||
}
|
||||
|
@@ -5,8 +5,12 @@
|
||||
<p class="float-end mb-1">
|
||||
<a href="#">Back to top</a>
|
||||
</p>
|
||||
<p class="mb-1">© {% now "Y" %} {{ site_conf.footer | markdown | safe }}</p>
|
||||
<p class="mb-0">{{ site_conf.footer_extended | markdown | safe }}</p>
|
||||
<div id="footer" class="mb-1">
|
||||
<p>© {% now "Y" %}</p> {{ site_conf.footer | markdown | safe }}
|
||||
</div>
|
||||
<div id="footer_extended" class="mb-0">
|
||||
{{ site_conf.footer_extended | markdown | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% if site_conf.show_version %}
|
||||
<div class="container">
|
||||
|
Reference in New Issue
Block a user