fix(firewall): NAT-Regeln nach Priorität sortieren + Port-Range-Validierung (v1.1.137)

- dataSource: data→sortedNAT — Up/Down-Pfeile zeigten auf falschen Nachbarn
- Form.Item dependencies: dportEnd/targetPortEnd validiert ≥ Start-Port
- Modal destroyOnHidden: Formular-State nach Schließen zurückgesetzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-28 16:51:07 +02:00
parent 76b5a4586c
commit 2a9310e947
7 changed files with 34 additions and 7 deletions

View File

@@ -1 +1 @@
1.1.136 1.1.137

View File

@@ -60,7 +60,7 @@ import (
usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users" usersvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/users"
) )
var version = "1.1.136" var version = "1.1.137"
func main() { func main() {
addr := os.Getenv("EDGEGUARD_API_ADDR") addr := os.Getenv("EDGEGUARD_API_ADDR")

View File

@@ -11,7 +11,7 @@ import (
"git.netcell-it.de/projekte/edgeguard-native/internal/services/setup" "git.netcell-it.de/projekte/edgeguard-native/internal/services/setup"
) )
var version = "1.1.136" var version = "1.1.137"
const usage = `edgeguard-ctl — EdgeGuard CLI const usage = `edgeguard-ctl — EdgeGuard CLI

View File

@@ -41,7 +41,7 @@ import (
"git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts"
) )
var version = "1.1.136" var version = "1.1.137"
const ( const (
// renewTickInterval — how often we re-evaluate expiring certs. // renewTickInterval — how often we re-evaluate expiring certs.

View File

@@ -142,6 +142,7 @@
"matchSrcCidr": "Source-CIDR (Match)", "matchDstCidr": "Dest-CIDR (Match)", "matchSrcCidr": "Source-CIDR (Match)", "matchDstCidr": "Dest-CIDR (Match)",
"matchDstCidrHint": "leer = jede dest-IP (z.B. öffentliche IP der Box)", "matchDstCidrHint": "leer = jede dest-IP (z.B. öffentliche IP der Box)",
"dportStart": "Port (Start)", "dportEnd": "Port (Ende)", "dportStart": "Port (Start)", "dportEnd": "Port (Ende)",
"portRangeError": "End-Port muss ≥ Start-Port sein",
"targetAddr": "Ziel-Adresse", "targetPortStart": "Ziel-Port (Start)", "targetPortEnd": "Ziel-Port (Ende)", "targetAddr": "Ziel-Adresse", "targetPortStart": "Ziel-Port (Start)", "targetPortEnd": "Ziel-Port (Ende)",
"comment": "Kommentar", "comment": "Kommentar",
"add": "NAT-Regel hinzufügen", "edit": "NAT-Regel bearbeiten", "add": "NAT-Regel hinzufügen", "edit": "NAT-Regel bearbeiten",

View File

@@ -142,6 +142,7 @@
"matchSrcCidr": "Source CIDR (match)", "matchDstCidr": "Dest. CIDR (match)", "matchSrcCidr": "Source CIDR (match)", "matchDstCidr": "Dest. CIDR (match)",
"matchDstCidrHint": "empty = any dest IP (e.g. box's public IP)", "matchDstCidrHint": "empty = any dest IP (e.g. box's public IP)",
"dportStart": "Port (start)", "dportEnd": "Port (end)", "dportStart": "Port (start)", "dportEnd": "Port (end)",
"portRangeError": "End port must be ≥ start port",
"targetAddr": "Target address", "targetPortStart": "Target port (start)", "targetPortEnd": "Target port (end)", "targetAddr": "Target address", "targetPortStart": "Target port (start)", "targetPortEnd": "Target port (end)",
"comment": "Comment", "comment": "Comment",
"add": "Add NAT rule", "edit": "Edit NAT rule", "add": "Add NAT rule", "edit": "Edit NAT rule",

View File

@@ -216,7 +216,7 @@ export default function NATRulesTab() {
<DataTable <DataTable
rowKey="id" rowKey="id"
loading={isLoading} loading={isLoading}
dataSource={data ?? []} dataSource={sortedNAT}
columns={columns} columns={columns}
emptyContent={ emptyContent={
<EmptyState <EmptyState
@@ -237,6 +237,7 @@ export default function NATRulesTab() {
onCancel={() => { setEditing(null); setCreating(false) }} onCancel={() => { setEditing(null); setCreating(false) }}
onOk={() => { void form.submit() }} onOk={() => { void form.submit() }}
confirmLoading={create.isPending || update.isPending} confirmLoading={create.isPending || update.isPending}
destroyOnHidden
width={560} width={560}
> >
<Form <Form
@@ -289,7 +290,19 @@ export default function NATRulesTab() {
<Form.Item label={t('fw.nat.dportStart')} name="match_dport_start" rules={[{ required: true }]}> <Form.Item label={t('fw.nat.dportStart')} name="match_dport_start" rules={[{ required: true }]}>
<InputNumber min={1} max={65535} /> <InputNumber min={1} max={65535} />
</Form.Item> </Form.Item>
<Form.Item label={t('fw.nat.dportEnd')} name="match_dport_end"> <Form.Item
label={t('fw.nat.dportEnd')}
name="match_dport_end"
dependencies={['match_dport_start']}
rules={[({ getFieldValue }) => ({
validator(_, val) {
if (!val) return Promise.resolve()
return val >= getFieldValue('match_dport_start')
? Promise.resolve()
: Promise.reject(new Error(t('fw.nat.portRangeError')))
},
})]}
>
<InputNumber min={1} max={65535} /> <InputNumber min={1} max={65535} />
</Form.Item> </Form.Item>
</Space> </Space>
@@ -305,7 +318,19 @@ export default function NATRulesTab() {
<Form.Item label={t('fw.nat.targetPortStart')} name="target_port_start"> <Form.Item label={t('fw.nat.targetPortStart')} name="target_port_start">
<InputNumber min={1} max={65535} /> <InputNumber min={1} max={65535} />
</Form.Item> </Form.Item>
<Form.Item label={t('fw.nat.targetPortEnd')} name="target_port_end"> <Form.Item
label={t('fw.nat.targetPortEnd')}
name="target_port_end"
dependencies={['target_port_start']}
rules={[({ getFieldValue }) => ({
validator(_, val) {
if (!val) return Promise.resolve()
return val >= getFieldValue('target_port_start')
? Promise.resolve()
: Promise.reject(new Error(t('fw.nat.portRangeError')))
},
})]}
>
<InputNumber min={1} max={65535} /> <InputNumber min={1} max={65535} />
</Form.Item> </Form.Item>
</Space> </Space>