firewall + scripts working
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// src/components/FirewallTables.tsx
|
||||
import { ArrowDownOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { Alert, Button, Card, Divider, message, Modal, Space, Table, Typography } from 'antd';
|
||||
import { ArrowDownOutlined, DeleteOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import { Alert, Button, Card, Divider, Modal, notification, Space, Spin, Table, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { ReactElement, useCallback, useMemo, useState } from 'react';
|
||||
import { execFirewallRaw } from '../api/apiClient';
|
||||
@@ -12,18 +12,10 @@ const { Paragraph, Text, Title } = Typography;
|
||||
|
||||
/* ---------- Helpers ---------- */
|
||||
|
||||
/**
|
||||
* Render a human friendly one-line representation of a rule.
|
||||
* Accepts RuleOut (typed) but remains defensive against unexpected shapes.
|
||||
*/
|
||||
function renderRuleFriendly(rule: RuleOut | any): string {
|
||||
// prefer `text` if present
|
||||
if (rule?.text && typeof rule.text === 'string' && rule.text.trim() !== '') return rule.text;
|
||||
|
||||
// if expr is a string, show it
|
||||
if (rule?.expr && typeof rule.expr === 'string') return rule.expr;
|
||||
|
||||
// if expr is an array, try to pretty print common tokens
|
||||
const expr = rule?.expr ?? rule;
|
||||
if (Array.isArray(expr)) {
|
||||
const tokens: string[] = [];
|
||||
@@ -107,7 +99,6 @@ function renderRuleFriendly(rule: RuleOut | any): string {
|
||||
if (tokens.length > 0) return tokens.join(' ');
|
||||
}
|
||||
|
||||
// fallback: if expr is an object, stringify a short excerpt
|
||||
if (rule?.expr && typeof rule.expr === 'object') {
|
||||
try {
|
||||
return JSON.stringify(rule.expr, (_k, v) => (v === undefined ? null : v)).slice(0, 500);
|
||||
@@ -116,7 +107,6 @@ function renderRuleFriendly(rule: RuleOut | any): string {
|
||||
}
|
||||
}
|
||||
|
||||
// final fallback: stringify whole rule
|
||||
try {
|
||||
return JSON.stringify(rule, null, 2);
|
||||
} catch {
|
||||
@@ -180,12 +170,20 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
try {
|
||||
const res = await runCommands([cmd]);
|
||||
const first = res[0];
|
||||
if (!first.err) message.success('Rule deleted');
|
||||
else message.error('Delete returned error — check results panel');
|
||||
if (!first.err) {
|
||||
notification.success({ message: 'Rule deleted', description: cmd });
|
||||
} else {
|
||||
notification.error({ message: 'Delete returned error', description: first.err });
|
||||
}
|
||||
} catch (err: any) {
|
||||
message.error('Delete failed: ' + (err?.message ?? String(err)));
|
||||
notification.error({ message: 'Delete failed', description: err?.message ?? String(err) });
|
||||
} finally {
|
||||
await refresh();
|
||||
// auto-refresh after change (no refresh notification shown here)
|
||||
try {
|
||||
await refresh();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -212,12 +210,20 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
try {
|
||||
const res = await runCommands([cmd]);
|
||||
const first = res[0];
|
||||
if (!first.err) message.success(`Chain ${chain} deleted`);
|
||||
else message.error(`Chain deletion returned error — check results panel`);
|
||||
if (!first.err) {
|
||||
notification.success({ message: `Chain ${chain} deleted`, description: cmd });
|
||||
} else {
|
||||
notification.error({ message: 'Chain deletion returned error', description: first.err });
|
||||
}
|
||||
} catch (err: any) {
|
||||
message.error('Chain deletion failed: ' + (err?.message ?? String(err)));
|
||||
notification.error({ message: 'Chain deletion failed', description: err?.message ?? String(err) });
|
||||
} finally {
|
||||
await refresh();
|
||||
// auto-refresh after change (no notification)
|
||||
try {
|
||||
await refresh();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -244,12 +250,20 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
try {
|
||||
const res = await runCommands([cmd]);
|
||||
const first = res[0];
|
||||
if (!first.err) message.success(`Table ${table} deleted`);
|
||||
else message.error(`Table deletion returned error — check results panel`);
|
||||
if (!first.err) {
|
||||
notification.success({ message: `Table ${table} deleted`, description: cmd });
|
||||
} else {
|
||||
notification.error({ message: 'Table deletion returned error', description: first.err });
|
||||
}
|
||||
} catch (err: any) {
|
||||
message.error('Table deletion failed: ' + (err?.message ?? String(err)));
|
||||
notification.error({ message: 'Table deletion failed', description: err?.message ?? String(err) });
|
||||
} finally {
|
||||
await refresh();
|
||||
// auto-refresh after change (no notification)
|
||||
try {
|
||||
await refresh();
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -262,9 +276,10 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
setRefreshing(true);
|
||||
try {
|
||||
await refresh();
|
||||
message.success('Ruleset refreshed');
|
||||
} catch {
|
||||
// ignore
|
||||
// Only show notification when user pressed the refresh button
|
||||
notification.success({ message: 'Ruleset refreshed' });
|
||||
} catch (err: any) {
|
||||
notification.error({ message: 'Refresh failed', description: err?.message ?? String(err) });
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
}
|
||||
@@ -277,22 +292,40 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
|
||||
return (
|
||||
<>
|
||||
<FirewallAddTableModal open={isOpenTableCreatorModal} onClose={() => setIsOpenTableCreatorModal(false)} />
|
||||
{/* Pass onClose that accepts optional 'created' boolean. If the modal
|
||||
calls onClose(true) we will auto-refresh (no refresh notification). */}
|
||||
<FirewallAddTableModal
|
||||
open={isOpenTableCreatorModal}
|
||||
onClose={(created?: boolean) => {
|
||||
setIsOpenTableCreatorModal(false);
|
||||
if (created) {
|
||||
// auto-refresh after create (no notification)
|
||||
void refresh().catch(() => {});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Firewall Tables"
|
||||
extra={
|
||||
<Space>
|
||||
<Button onClick={handleRefresh} loading={refreshing}>
|
||||
Refresh
|
||||
<Button
|
||||
onClick={handleRefresh}
|
||||
loading={refreshing}
|
||||
icon={refreshing ? <Spin size="small" /> : <ReloadOutlined />}
|
||||
>
|
||||
Refresh Ruleset
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => setIsOpenTableCreatorModal(true)}>
|
||||
Add Table
|
||||
</Button>
|
||||
<Button onClick={() => setIsOpenTableCreatorModal(true)}>Add Table</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
{tablesToRender.length === 0 && (
|
||||
<Alert
|
||||
type="info"
|
||||
title="No firewall tables found"
|
||||
message="No firewall tables found"
|
||||
description="You can create a new table using the button above."
|
||||
style={{ marginBottom: 12 }}
|
||||
/>
|
||||
@@ -321,20 +354,25 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
<Space>
|
||||
<Button
|
||||
danger
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleDeleteTable(table.family, table.name)}
|
||||
/>
|
||||
<Button size="small" onClick={() => setIsOpenChainCreatorModal(true)}>
|
||||
<Button type="primary" onClick={() => setIsOpenChainCreatorModal(true)}>
|
||||
Add Chain
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{/* Chain modal: same optional 'created' signal */}
|
||||
<FirewallAddChainModal
|
||||
open={isOpenChainCreatorModal}
|
||||
onClose={() => setIsOpenChainCreatorModal(false)}
|
||||
onClose={(created?: boolean) => {
|
||||
setIsOpenChainCreatorModal(false);
|
||||
if (created) {
|
||||
void refresh().catch(() => {});
|
||||
}
|
||||
}}
|
||||
table={{ family: table.family ?? '', name: table.name }}
|
||||
/>
|
||||
|
||||
@@ -406,7 +444,6 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
<Space>
|
||||
<Button
|
||||
danger
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleDeleteChain(table.family, table.name, chain.name)}
|
||||
/>
|
||||
@@ -437,9 +474,7 @@ export default function FirewallTables({ tables, error, refreshRules: refresh }:
|
||||
<div key={i} style={{ marginBottom: 12 }}>
|
||||
<Text strong>{r.cmd}</Text>
|
||||
{r.err ? (
|
||||
<Paragraph type="danger" style={{ marginTop: 6 }}>
|
||||
{r.err}
|
||||
</Paragraph>
|
||||
<Paragraph style={{ color: 'var(--ant-error-color)', marginTop: 6 }}>{r.err}</Paragraph>
|
||||
) : r.out ? (
|
||||
<>
|
||||
<Paragraph>
|
||||
|
||||
Reference in New Issue
Block a user