diff --git a/core/api_views.py b/core/api_views.py
index bf6ee2ba..2f01b503 100644
--- a/core/api_views.py
+++ b/core/api_views.py
@@ -5,7 +5,13 @@ import ipaddress
from rest_framework import viewsets, status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
-from .models import UserAgent, StreamProfile, CoreSettings, STREAM_HASH_KEY
+from .models import (
+ UserAgent,
+ StreamProfile,
+ CoreSettings,
+ STREAM_HASH_KEY,
+ NETWORK_ACCESS,
+)
from .serializers import (
UserAgentSerializer,
StreamProfileSerializer,
@@ -63,18 +69,41 @@ class CoreSettingsViewSet(viewsets.ModelViewSet):
def check(self, request, *args, **kwargs):
data = request.data
- client_ip = ipaddress.ip_address(get_client_ip(request))
- in_network = []
- key = data.get("key")
- value = json.loads(data.get("value", "{}"))
- for key, val in value.items():
- cidrs = val.split(",")
- for cidr in cidrs:
- network = ipaddress.ip_network(cidr)
- if client_ip not in network:
- in_network.append(cidr)
+ if data.get("key") == NETWORK_ACCESS:
+ client_ip = ipaddress.ip_address(get_client_ip(request))
- return Response(in_network, status=status.HTTP_200_OK)
+ in_network = {}
+ invalid = []
+
+ value = json.loads(data.get("value", "{}"))
+ for key, val in value.items():
+ in_network[key] = []
+ cidrs = val.split(",")
+ for cidr in cidrs:
+ try:
+ network = ipaddress.ip_network(cidr)
+
+ if client_ip in network:
+ in_network[key] = []
+ break
+
+ in_network[key].append(cidr)
+ except:
+ invalid.append(cidr)
+
+ if len(invalid) > 0:
+ return Response(
+ {
+ "error": True,
+ "message": "Invalid CIDR(s)",
+ "data": invalid,
+ },
+ status=status.HTTP_200_OK,
+ )
+
+ return Response(in_network, status=status.HTTP_200_OK)
+
+ return Response({}, status=status.HTTP_200_OK)
@swagger_auto_schema(
diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx
index b4fc37cc..073af337 100644
--- a/frontend/src/pages/Settings.jsx
+++ b/frontend/src/pages/Settings.jsx
@@ -34,6 +34,7 @@ const SettingsPage = () => {
const [accordianValue, setAccordianValue] = useState(null);
const [networkAccessSaved, setNetworkAccessSaved] = useState(false);
+ const [networkAccessError, setNetworkAccessError] = useState(null);
const [networkAccessConfirmOpen, setNetworkAccessConfirmOpen] =
useState(false);
const [netNetworkAccessConfirmCIDRs, setNetNetworkAccessConfirmCIDRs] =
@@ -316,6 +317,21 @@ const SettingsPage = () => {
acc[key] = '0.0.0.0/0';
return acc;
}, {}),
+ validate: Object.keys(NETWORK_ACCESS_OPTIONS).reduce((acc, key) => {
+ acc[key] = (value) => {
+ const cidrs = value.split(',');
+ for (const cidr of cidrs) {
+ if (cidr.match(/^([0-9]{1,3}\.){3}[0-9]{1,3}\/\d+$/)) {
+ continue;
+ }
+
+ return 'Invalid CIDR range';
+ }
+
+ return null;
+ };
+ return acc;
+ }, {}),
});
useEffect(() => {
@@ -383,16 +399,24 @@ const SettingsPage = () => {
const onNetworkAccessSubmit = async () => {
setNetworkAccessSaved(false);
+ setNetworkAccessError(null);
const check = await API.checkSetting({
...settings['network-access'],
value: JSON.stringify(networkAccessForm.getValues()),
});
- if (check.length == 0) {
+ if (check.error && check.message) {
+ setNetworkAccessError(`${check.message}: ${check.data}`);
+ return;
+ }
+
+ // For now, only warn if we're blocking the UI
+ const blockedAccess = check.UI;
+ if (blockedAccess.length == 0) {
return saveNetworkAccess();
}
- setNetNetworkAccessConfirmCIDRs(check);
+ setNetNetworkAccessConfirmCIDRs(blockedAccess);
setNetworkAccessConfirmOpen(true);
};
@@ -627,6 +651,13 @@ const SettingsPage = () => {
title="Saved Successfully"
>
)}
+ {networkAccessError && (
+