diff --git a/frontend/src/components/Firewall/ActionTypeSelector.tsx b/frontend/src/components/Firewall/ActionTypeSelector.tsx new file mode 100644 index 0000000..5230e99 --- /dev/null +++ b/frontend/src/components/Firewall/ActionTypeSelector.tsx @@ -0,0 +1,23 @@ +import { SegmentedControl, SegmentedControlProps } from "@mantine/core"; +import { ActionType } from "./utils"; + + +export const ActionTypeSelector = (props:Omit) => ( + +) \ No newline at end of file diff --git a/frontend/src/components/Firewall/ModeSelector.tsx b/frontend/src/components/Firewall/ModeSelector.tsx new file mode 100644 index 0000000..b6a18d2 --- /dev/null +++ b/frontend/src/components/Firewall/ModeSelector.tsx @@ -0,0 +1,20 @@ +import { SegmentedControl, SegmentedControlProps } from "@mantine/core"; +import { RuleMode } from "./utils"; + + + +export const ModeSelector = (props:Omit) => ( + +) \ No newline at end of file diff --git a/frontend/src/components/Firewall/ProtocolSelector.tsx b/frontend/src/components/Firewall/ProtocolSelector.tsx new file mode 100644 index 0000000..bd91f91 --- /dev/null +++ b/frontend/src/components/Firewall/ProtocolSelector.tsx @@ -0,0 +1,23 @@ +import { SegmentedControl, SegmentedControlProps } from "@mantine/core"; +import { Protocol } from "./utils"; + + +export const ProtocolSelector = (props:Omit) => ( + +) \ No newline at end of file diff --git a/frontend/src/components/InterfaceInput.tsx b/frontend/src/components/InterfaceInput.tsx new file mode 100644 index 0000000..a2409cd --- /dev/null +++ b/frontend/src/components/InterfaceInput.tsx @@ -0,0 +1,48 @@ +import { AutocompleteItem, Select, SelectProps } from "@mantine/core"; +import React, { useState } from "react"; +import { ipInterfacesQuery } from "../js/utils"; + + +const AutoCompleteItem = React.forwardRef( + ({ netint, value, ...props }: ItemProps, ref) =>
+ ( {netint} ) -{">"} {value} +
+); + +interface ItemProps extends AutocompleteItem { + netint: string; +} + +interface InterfaceInputProps extends Omit{ + initialCustomInterfaces?:AutocompleteItem[] +} + +export const InterfaceInput = (props:InterfaceInputProps) => { + + const { initialCustomInterfaces, ...propeties } = props + + const [customIpInterfaces, setCustomIpInterfaces] = useState(initialCustomInterfaces??[]); + const interfacesQuery = ipInterfacesQuery() + + const interfaces = (!interfacesQuery.isLoading? + (interfacesQuery.data!.map(item => ({netint:item.name, value:item.addr, label:item.addr})) as AutocompleteItem[]): + []) + + return `+ Use this: ${query}`} - onCreate={(query) => { - const item = { value: query, netint: "CUSTOM", label: query }; - setIpInterfaces((current) => [...current, item]); - return item; - }} +
+ - : + {(!orientation || orientation == "line")? + <>:: + }
diff --git a/frontend/src/components/PortInput.tsx b/frontend/src/components/PortInput.tsx index 2440b9f..01b63fa 100644 --- a/frontend/src/components/PortInput.tsx +++ b/frontend/src/components/PortInput.tsx @@ -1,10 +1,22 @@ -import { NumberInput, NumberInputProps } from "@mantine/core" +import { Input, NumberInput, NumberInputProps, TextInput, TextInputProps } from "@mantine/core" import React, { useState } from "react" interface PortInputProps extends NumberInputProps { fullWidth?: boolean } +const valueParse = (raw_value:string, oldValue:string = "") => { + const value = parseInt(raw_value) + if (value > 65535) { + return oldValue + } else if (value < 1) { + return oldValue + }else{ + return value.toString() + } +} + + const PortInput = React.forwardRef( (props, ref) => { const [oldValue, setOldValue] = useState(props.defaultValue?props.defaultValue.toString():"") const {fullWidth, ...propeties} = props @@ -16,15 +28,9 @@ const PortInput = React.forwardRef( (props, r max={props.max?props.min:65535} style={fullWidth?props.style:{ width: "75px", ...props.style }} onInput={(e) => { - const value = parseInt((e.target as HTMLInputElement).value) - if (value > 65535) { - (e.target as HTMLInputElement).value = oldValue - } else if (value < 1) { - (e.target as HTMLInputElement).value = oldValue - }else{ - (e.target as HTMLInputElement).value = value.toString() - } - setOldValue((e.target as HTMLInputElement).value) + const target = e.target as HTMLInputElement + target.value = target.value?valueParse(target.value, oldValue):"" + setOldValue(target.value) props.onInput?.(e) }} ref={ref} @@ -33,4 +39,43 @@ const PortInput = React.forwardRef( (props, r }) + +interface PortRangeInputProps extends TextInputProps { + fullWidth?: boolean, + defaultValues?: number[] +} + +export const PortRangeInput = React.forwardRef( (props, ref) => { + const oldValueStates = [ + useState(props.defaultValue?props.defaultValue?.toString().split("-")[0]:""), + useState(props.defaultValue?.toString().split("-")[1]) + ] + const {fullWidth, defaultValues, ...propeties} = props + let defaultValuesInt = defaultValues + if (defaultValuesInt?.length == 2 && defaultValuesInt[0] == defaultValuesInt[1]){ + defaultValuesInt = [defaultValuesInt[0]] + } + + return { + const target = e.target as HTMLInputElement + const splitted = target.value.split("-") + const parsedValues = [splitted[0], splitted[1]].map((value, index) => { + const res = value?valueParse(value,oldValueStates[index][0]):value + if (res != oldValueStates[index][0]) oldValueStates[index][1](value) + return res + }) + target.value = parsedValues.filter((v, i) => (v !== undefined && (i != 0 || v !== ""))).join("-") + props.onInput?.(e) + }} + ref={ref} + defaultValue={defaultValuesInt?defaultValuesInt.map(v => v.toString()).join("-"):props.defaultValue} + {...propeties} + /> + +}) + export default PortInput \ No newline at end of file diff --git a/frontend/src/js/utils.tsx b/frontend/src/js/utils.tsx index a19c0c0..7d9a59a 100644 --- a/frontend/src/js/utils.tsx +++ b/frontend/src/js/utils.tsx @@ -6,7 +6,7 @@ import { nfregex } from "../components/NFRegex/utils"; import { regexproxy } from "../components/RegexProxy/utils"; import { ChangePassword, IpInterface, LoginResponse, PasswordSend, ServerResponse, ServerResponseToken, ServerStatusResponse } from "./models"; import { Buffer } from "buffer" -import { QueryClient } from "@tanstack/react-query"; +import { QueryClient, useQuery } from "@tanstack/react-query"; export const IS_DEV = import.meta.env.DEV @@ -111,6 +111,8 @@ export async function resetfiregex(delete_data:boolean = false){ return (status === "ok"?undefined:status) } +export const ipInterfacesQuery = () => useQuery(["ipinterfaces"], getipinterfaces) + export async function getipinterfaces(){ return await getapi("interfaces") as IpInterface[]; } diff --git a/frontend/src/pages/Firewall/index.tsx b/frontend/src/pages/Firewall/index.tsx index a55d055..a3a4a3f 100644 --- a/frontend/src/pages/Firewall/index.tsx +++ b/frontend/src/pages/Firewall/index.tsx @@ -1,4 +1,4 @@ -import { ActionIcon, Badge, LoadingOverlay, NativeSelect, SegmentedControl, Space, Switch, Title, Tooltip } from "@mantine/core" +import { ActionIcon, Badge, LoadingOverlay, Space, Switch, Title, Tooltip } from "@mantine/core" import { useEffect, useState } from "react"; import { BsPlusLg } from "react-icons/bs" import { rem, Text } from '@mantine/core'; @@ -12,6 +12,11 @@ import classes from './DndListHandle.module.scss'; import { useQueryClient } from "@tanstack/react-query"; import { TiTick } from "react-icons/ti"; import YesNoModal from "../../components/YesNoModal"; +import { PortRangeInput } from "../../components/PortInput"; +import { InterfaceInput } from "../../components/InterfaceInput"; +import { ActionTypeSelector } from "../../components/Firewall/ActionTypeSelector"; +import { ProtocolSelector } from "../../components/Firewall/ProtocolSelector"; +import { ModeSelector } from "../../components/Firewall/ModeSelector"; /* { @@ -148,8 +153,14 @@ export const Firewall = () => { const items = state.map((item, index) => ( - {(provided, snapshot) => ( -
{ + const customInt = [ + { value: "0.0.0.0/0", netint: "ANY IPv4", label: "0.0.0.0/0" }, + { value: "::/0", netint: "ANY IPv6", label: "::/0" } + ] + const src_custom_int = customInt.map(v => v.value).includes(item.ip_src)?[]:[{ value: item.ip_src, netint: "SELECTED", label: item.ip_src }] + const dst_custom_int = customInt.map(v => v.value).includes(item.ip_dst)?[]:[{ value: item.ip_src, netint: "SELECTED", label: item.ip_dst }] + return
{
- +
{item.name} - - {JSON.stringify(item)} - + + + + + + +
- )} + }}
)); @@ -184,21 +202,7 @@ export const Firewall = () => { Policy: - setCurrentPolicy(value as ActionType)} />