Merge branch 'main' of github.com:Pwnzer0tt1/firegex
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
# Needed for start.py to detect the Dockerfile
|
# Needed for start.py to detect the Dockerfile
|
||||||
|
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM oven/bun AS frontend
|
FROM --platform=$BUILDPLATFORM oven/bun AS frontend
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ADD ./frontend/package.json .
|
ADD ./frontend/package.json .
|
||||||
ADD ./frontend/bun.lockb .
|
ADD ./frontend/bun.lockb .
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from utils import API_VERSION, FIREGEX_PORT, JWT_ALGORITHM, get_interfaces, sock
|
|||||||
from utils.loader import frontend_deploy, load_routers
|
from utils.loader import frontend_deploy, load_routers
|
||||||
from utils.models import ChangePasswordModel, IpInterface, PasswordChangeForm, PasswordForm, ResetRequest, StatusModel, StatusMessageModel
|
from utils.models import ChangePasswordModel, IpInterface, PasswordChangeForm, PasswordForm, ResetRequest, StatusModel, StatusMessageModel
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
# DB init
|
# DB init
|
||||||
db = SQLite('db/firegex.db')
|
db = SQLite('db/firegex.db')
|
||||||
@@ -32,6 +33,9 @@ async def lifespan(app):
|
|||||||
app = FastAPI(debug=DEBUG, redoc_url=None, lifespan=lifespan)
|
app = FastAPI(debug=DEBUG, redoc_url=None, lifespan=lifespan)
|
||||||
utils.socketio = SocketManager(app, "/sock", socketio_path="")
|
utils.socketio = SocketManager(app, "/sock", socketio_path="")
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
|
||||||
|
|
||||||
def APP_STATUS(): return "init" if db.get("password") is None else "run"
|
def APP_STATUS(): return "init" if db.get("password") is None else "run"
|
||||||
def JWT_SECRET(): return db.get("secret")
|
def JWT_SECRET(): return db.get("secret")
|
||||||
|
|
||||||
@@ -158,7 +162,7 @@ if __name__ == '__main__':
|
|||||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"app:app",
|
"app:app",
|
||||||
host="0.0.0.0" if DEBUG else None,
|
host="::" if DEBUG else None,
|
||||||
port=FIREGEX_PORT,
|
port=FIREGEX_PORT,
|
||||||
reload=DEBUG,
|
reload=DEBUG,
|
||||||
access_log=True,
|
access_log=True,
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 364 KiB After Width: | Height: | Size: 354 KiB |
Binary file not shown.
@@ -1,40 +1,34 @@
|
|||||||
{
|
{
|
||||||
"name": "firegex-frontend",
|
"name": "firegex-frontend",
|
||||||
|
"type": "module",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.0",
|
"@hello-pangea/dnd": "^16.6.0",
|
||||||
"@hello-pangea/dnd": "^16.3.0",
|
"@mantine/core": "^7.13.2",
|
||||||
"@mantine/core": "^6.0.21",
|
"@mantine/form": "^7.13.2",
|
||||||
"@mantine/form": "^6.0.21",
|
"@mantine/hooks": "^7.13.2",
|
||||||
"@mantine/hooks": "^6.0.21",
|
"@mantine/modals": "^7.13.2",
|
||||||
"@mantine/modals": "^6.0.21",
|
"@mantine/notifications": "^7.13.2",
|
||||||
"@mantine/notifications": "^6.0.21",
|
"@tanstack/react-query": "^4.36.1",
|
||||||
"@mantine/prism": "^6.0.21",
|
|
||||||
"@mantine/spotlight": "^6.0.21",
|
|
||||||
"@tanstack/react-query": "^4.35.3",
|
|
||||||
"@testing-library/dom": "^9.3.0",
|
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
|
||||||
"@testing-library/react": "^13.3.0",
|
|
||||||
"@testing-library/user-event": "^13.5.0",
|
|
||||||
"@types/jest": "^27.5.2",
|
"@types/jest": "^27.5.2",
|
||||||
"@types/node": "^20.2.5",
|
"@types/node": "^20.16.11",
|
||||||
"@types/react": "^18.0.12",
|
"@types/react": "^18.3.11",
|
||||||
"@types/react-dom": "^18.0.5",
|
"@types/react-dom": "^18.3.1",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"react": "^18.1.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^4.4.0",
|
"react-icons": "^5.3.0",
|
||||||
"react-router-dom": "^6.3.0",
|
"react-router-dom": "^6.27.0",
|
||||||
"sass": "^1.62.1",
|
"socket.io-client": "^4.8.0",
|
||||||
"socket.io-client": "^4.5.1",
|
"typescript": "^4.9.5",
|
||||||
"typescript": "^4.7.3",
|
"web-vitals": "^2.1.4",
|
||||||
"web-vitals": "^2.1.4"
|
"zustand": "^5.0.0-rc.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"serve": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
@@ -55,10 +49,10 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tanstack/react-query-devtools": "^4.35.3",
|
"@tanstack/react-query-devtools": "^4.36.1",
|
||||||
"@vitejs/plugin-react": "^4.0.0",
|
"@vitejs/plugin-react": "^4.3.2",
|
||||||
"vite": "^4.3.9",
|
"vite": "^4.5.5",
|
||||||
"vite-plugin-svgr": "^3.2.0",
|
"vite-plugin-svgr": "^3.3.0",
|
||||||
"vite-tsconfig-paths": "^4.2.0"
|
"vite-tsconfig-paths": "^4.3.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 74 KiB |
31
frontend/src/.dockerignore
Normal file
31
frontend/src/.dockerignore
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
Dockerfile
|
||||||
|
|
||||||
|
**/*.pyc
|
||||||
|
**/__pycache__/
|
||||||
|
**/.vscode/**
|
||||||
|
**/.vscode/
|
||||||
|
**/.mypy_cache/**
|
||||||
|
**/.mypy_cache/
|
||||||
|
|
||||||
|
**/node_modules
|
||||||
|
**/.pnp
|
||||||
|
**/.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
/build/
|
||||||
|
/build/**
|
||||||
|
/node_modules/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
**/.DS_Store
|
||||||
|
**/.env.local
|
||||||
|
**/.env.development.local
|
||||||
|
**/.env.test.local
|
||||||
|
**/.env.production.local
|
||||||
|
|
||||||
|
**/npm-debug.log*
|
||||||
|
**/yarn-debug.log*
|
||||||
|
**/yarn-error.log*
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Group, Loader, LoadingOverlay, Notification, Space, PasswordInput, Title } from '@mantine/core';
|
import { Button, Group, Loader, LoadingOverlay, Notification, Space, PasswordInput, Title, Box } from '@mantine/core';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { ImCross } from 'react-icons/im';
|
import { ImCross } from 'react-icons/im';
|
||||||
@@ -66,15 +66,15 @@ function App() {
|
|||||||
if (loading){
|
if (loading){
|
||||||
return <LoadingOverlay visible/>
|
return <LoadingOverlay visible/>
|
||||||
}else if (reqError){
|
}else if (reqError){
|
||||||
return <div className='center-flex-row' style={{padding:"100px"}}>
|
return <Box className='center-flex-row' style={{padding:"100px"}}>
|
||||||
<Title order={1} align="center">Error launching Firegex! 🔥</Title>
|
<Title order={1} style={{textAlign:"center"}}>Error launching Firegex! 🔥</Title>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Title order={4} align="center">Error communicating with backend</Title>
|
<Title order={4} style={{textAlign:"center"}}>Error communicating with backend</Title>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
Error: {reqError}
|
Error: {reqError}
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</Box>
|
||||||
}else if (systemStatus.status === "init"){
|
}else if (systemStatus.status === "init"){
|
||||||
|
|
||||||
const submitRequest = async (values:PasswordSend) => {
|
const submitRequest = async (values:PasswordSend) => {
|
||||||
@@ -90,8 +90,8 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return <div className='center-flex-row' style={{padding:"100px"}}>
|
return <Box className='center-flex-row' style={{padding:"100px"}}>
|
||||||
<Title order={3} align="center">Setup: Choose the password for access to the firewall 🔒</Title>
|
<Title order={3} style={{textAlign:"center"}}>Setup: Choose the password for access to the firewall 🔒</Title>
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<form onSubmit={form.onSubmit(submitRequest)} style={{width:"80%"}}>
|
<form onSubmit={form.onSubmit(submitRequest)} style={{width:"80%"}}>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
@@ -99,7 +99,7 @@ function App() {
|
|||||||
placeholder="$3cr3t"
|
placeholder="$3cr3t"
|
||||||
{...form.getInputProps('password')}
|
{...form.getInputProps('password')}
|
||||||
/>
|
/>
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={loadinBtn} type="submit">Set Password</Button>
|
<Button loading={loadinBtn} type="submit">Set Password</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</form>
|
</form>
|
||||||
@@ -108,7 +108,7 @@ function App() {
|
|||||||
<Notification icon={<ImCross size={14} />} color="red" onClose={()=>{setError(null)}}>
|
<Notification icon={<ImCross size={14} />} color="red" onClose={()=>{setError(null)}}>
|
||||||
Error: {error}
|
Error: {error}
|
||||||
</Notification><Space h="md" /></>:null}
|
</Notification><Space h="md" /></>:null}
|
||||||
</div>
|
</Box>
|
||||||
}else if (systemStatus.status === "run" && !systemStatus.loggined){
|
}else if (systemStatus.status === "run" && !systemStatus.loggined){
|
||||||
const submitRequest = async (values:PasswordSend) => {
|
const submitRequest = async (values:PasswordSend) => {
|
||||||
setLoadingBtn(true)
|
setLoadingBtn(true)
|
||||||
@@ -123,10 +123,10 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return <div className='center-flex-row' style={{padding:"100px"}}>
|
return <Box className='center-flex-row' style={{padding:"100px"}}>
|
||||||
<Title order={2} align="center">Welcome to Firegex 🔥</Title>
|
<Title order={2} style={{textAlign:"center"}}>Welcome to Firegex 🔥</Title>
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<Title order={2} align="center">Before you use the firewall, insert the password 🔒</Title>
|
<Title order={2} style={{textAlign:"center"}}>Before you use the firewall, insert the password 🔒</Title>
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<form onSubmit={form.onSubmit(submitRequest)} style={{width:"80%"}}>
|
<form onSubmit={form.onSubmit(submitRequest)} style={{width:"80%"}}>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
@@ -134,7 +134,7 @@ function App() {
|
|||||||
placeholder="$3cr3t"
|
placeholder="$3cr3t"
|
||||||
{...form.getInputProps('password')}
|
{...form.getInputProps('password')}
|
||||||
/>
|
/>
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={loadinBtn} type="submit">Login</Button>
|
<Button loading={loadinBtn} type="submit">Login</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</form>
|
</form>
|
||||||
@@ -143,7 +143,7 @@ function App() {
|
|||||||
<Notification icon={<ImCross size={14} />} color="red" onClose={()=>{setError(null)}}>
|
<Notification icon={<ImCross size={14} />} color="red" onClose={()=>{setError(null)}}>
|
||||||
Error: {error}
|
Error: {error}
|
||||||
</Notification><Space h="md" /></>:null}
|
</Notification><Space h="md" /></>:null}
|
||||||
</div>
|
</Box>
|
||||||
}else if (systemStatus.status === "run" && systemStatus.loggined){
|
}else if (systemStatus.status === "run" && systemStatus.loggined){
|
||||||
return <Routes>
|
return <Routes>
|
||||||
<Route element={<MainLayout><Outlet /></MainLayout>}>
|
<Route element={<MainLayout><Outlet /></MainLayout>}>
|
||||||
@@ -159,11 +159,11 @@ function App() {
|
|||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
}else{
|
}else{
|
||||||
return <div className='center-flex-row' style={{padding:"100px"}}>
|
return <Box className='center-flex-row' style={{padding:"100px"}}>
|
||||||
<Title order={1} align="center">Error launching Firegex! 🔥</Title>
|
<Title order={1} style={{textAlign:"center"}}>Error launching Firegex! 🔥</Title>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Title order={4} align="center">Error communicating with backend</Title>
|
<Title order={4} style={{textAlign:"center"}}>Error communicating with backend</Title>
|
||||||
</div>
|
</Box>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
$primary_color: #242a33;
|
|
||||||
$secondary_color: #1A1B1E;
|
|
||||||
$third_color:#25262b;
|
|
||||||
@@ -108,7 +108,7 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=>
|
|||||||
<Alert variant="light" color="yellow" radius="lg" title="You are using whitelists" icon={<AiFillWarning />}>
|
<Alert variant="light" color="yellow" radius="lg" title="You are using whitelists" icon={<AiFillWarning />}>
|
||||||
Using whitelist means that EVERY packet that doesn't match the regex will be DROPPED... In most cases this cause the service interruption.
|
Using whitelist means that EVERY packet that doesn't match the regex will be DROPPED... In most cases this cause the service interruption.
|
||||||
</Alert></>:null}
|
</Alert></>:null}
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Add Filter</Button>
|
<Button loading={submitLoading} type="submit">Add Filter</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Box, Center, SegmentedControl } from "@mantine/core";
|
import { Box, Center, SegmentedControl } from "@mantine/core";
|
||||||
import React from "react";
|
|
||||||
import { FaListAlt } from "react-icons/fa";
|
import { FaListAlt } from "react-icons/fa";
|
||||||
import { TiCancel } from "react-icons/ti";
|
import { TiCancel } from "react-icons/ti";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
@use "../../vars" as *;
|
|
||||||
@use "../../index.scss" as *;
|
|
||||||
|
|
||||||
.footer{
|
|
||||||
margin-top: 50px;
|
|
||||||
background-color: $primary_color;
|
|
||||||
@extend .center-flex;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { Footer, Space } from '@mantine/core';
|
|
||||||
import image from "./pwnzer0tt1.svg"
|
|
||||||
|
|
||||||
import style from "./index.module.scss";
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
|
||||||
function FooterPage() {
|
|
||||||
return <Footer id="footer" height={70} className={style.footer}>
|
|
||||||
<img src={image} width={25} height={25} /> <Space w="xs" />Made by <div style={{marginLeft:"5px"}} /> <Link to="https://pwnzer0tt1.it">Pwnzer0tt1</Link> <Space w="xs" /> <img src={image} width={25} height={25} />
|
|
||||||
</Footer>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FooterPage;
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 139 KiB |
@@ -47,7 +47,7 @@ function ResetModal({ opened, onClose }:{ opened: boolean, onClose: () => void }
|
|||||||
{...form.getInputProps('delete_data', { type: 'checkbox' })}
|
{...form.getInputProps('delete_data', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={loadingBtn} onClick={close} >Cancel</Button>
|
<Button loading={loadingBtn} onClick={close} >Cancel</Button>
|
||||||
<Button loading={loadingBtn} type="submit" color="red">Reset</Button>
|
<Button loading={loadingBtn} type="submit" color="red">Reset</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ function ResetPasswordModal({ opened, onClose }:{ opened: boolean, onClose: () =
|
|||||||
{...form.getInputProps('expire', { type: 'checkbox' })}
|
{...form.getInputProps('expire', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={loadingBtn} type="submit">Change Password</Button>
|
<Button loading={loadingBtn} type="submit">Change Password</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
@use "../../vars" as *;
|
|
||||||
@use "../../index.scss" as *;
|
|
||||||
|
|
||||||
.header{
|
|
||||||
width: 100%;
|
|
||||||
background-color: $primary_color;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.divlogo{
|
|
||||||
width: 110px;
|
|
||||||
height: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
@extend .center-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbtn{
|
|
||||||
@extend .center-flex;
|
|
||||||
width: 30px;
|
|
||||||
margin:0;
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { ActionIcon, Divider, Image, Menu, Tooltip, Burger, Space, Header, Button, ThemeIcon } from '@mantine/core';
|
import { ActionIcon, Divider, Image, Menu, Tooltip, Burger, Space, AppShell, Box, Title } from '@mantine/core';
|
||||||
import style from "./index.module.scss";
|
import { errorNotify, getMainPath, isLargeScreen, logout } from '../../js/utils';
|
||||||
import { errorNotify, getmainpath, isLargeScreen, logout } from '../../js/utils';
|
|
||||||
import { AiFillHome } from "react-icons/ai"
|
import { AiFillHome } from "react-icons/ai"
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { FaLock } from 'react-icons/fa';
|
import { FaLock } from 'react-icons/fa';
|
||||||
@@ -10,11 +9,13 @@ import { ImExit } from 'react-icons/im';
|
|||||||
import ResetPasswordModal from './ResetPasswordModal';
|
import ResetPasswordModal from './ResetPasswordModal';
|
||||||
import ResetModal from './ResetModal';
|
import ResetModal from './ResetModal';
|
||||||
import { MenuDropDownWithButton } from '../MainLayout';
|
import { MenuDropDownWithButton } from '../MainLayout';
|
||||||
|
import { useNavbarStore } from '../../js/store';
|
||||||
|
|
||||||
|
|
||||||
function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:React.Dispatch<React.SetStateAction<boolean>>}) {
|
function HeaderPage(props: any) {
|
||||||
|
|
||||||
const navigator = useNavigate()
|
const navigator = useNavigate()
|
||||||
|
const { navOpened, toggleNav } = useNavbarStore()
|
||||||
|
|
||||||
const logout_action = () => {
|
const logout_action = () => {
|
||||||
logout().then(r => {
|
logout().then(r => {
|
||||||
@@ -25,40 +26,42 @@ function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:Reac
|
|||||||
}
|
}
|
||||||
|
|
||||||
const go_to_home = () => {
|
const go_to_home = () => {
|
||||||
navigator(`/${getmainpath()}`)
|
navigator(`/${getMainPath()}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [changePasswordModal, setChangePasswordModal] = useState(false);
|
const [changePasswordModal, setChangePasswordModal] = useState(false);
|
||||||
const [resetFiregexModal, setResetFiregexModal] = useState(false);
|
const [resetFiregexModal, setResetFiregexModal] = useState(false);
|
||||||
const [tooltipHomeOpened, setTooltipHomeOpened] = useState(false);
|
const [tooltipHomeOpened, setTooltipHomeOpened] = useState(false);
|
||||||
const [tooltipLogoutOpened,setTooltipLogoutOpened] = useState(false);
|
const [tooltipLogoutOpened,setTooltipLogoutOpened] = useState(false);
|
||||||
const isLarge = isLargeScreen()
|
return <AppShell.Header className="firegex__header__header" {...props}>
|
||||||
console.log(isLarge)
|
<Burger
|
||||||
return <Header height={100} className={style.header} {...other}>
|
hiddenFrom='md'
|
||||||
<Space w="lg" />
|
ml="lg"
|
||||||
{isLarge?null:<div>
|
opened={navOpened}
|
||||||
<Burger
|
className="firegex__header__navbtn"
|
||||||
opened={navOpen}
|
onClick={toggleNav}
|
||||||
className={style.navbtn}
|
size="sm"
|
||||||
onClick={() => setNav((o) => !o)}
|
/>
|
||||||
size="sm"
|
<Box style={{ display: "flex", justifyContent: "center", alignItems: "center"}} ml={5}>
|
||||||
mr="xl"
|
<Box className="firegex__header__divlogo">
|
||||||
/>
|
<Tooltip zIndex={0} label="Home" openDelay={1000} color="dark" position="right" >
|
||||||
</div>}
|
<Image src="/header-logo.png" alt="Firegex logo" w={50} onClick={()=>navigator("/")}/>
|
||||||
<div className={style.divlogo}>
|
</Tooltip>
|
||||||
<Tooltip zIndex={0} label="Home" openDelay={1000}color="dark" position="right" >
|
</Box>
|
||||||
<Image src="/header-logo.png" alt="Firegex logo" onClick={()=>navigator("/")}/>
|
<Box display="flex" style={{ flexDirection: "column" }} visibleFrom='xs'>
|
||||||
</Tooltip>
|
<Title order={2} >[Fi]*regex</Title>
|
||||||
</div>
|
<p style={{margin: 0, fontSize: "70%"}}>By <a href="https://pwnzer0tt1.it">Pwnzer0tt1</a></p>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<div className="flex-spacer" />
|
<Box className="flex-spacer" />
|
||||||
|
|
||||||
<MenuDropDownWithButton>
|
<MenuDropDownWithButton>
|
||||||
<Menu.Label>Firewall Access</Menu.Label>
|
<Menu.Label>Firewall Access</Menu.Label>
|
||||||
<Menu.Item icon={<FaLock size={14} />} onClick={() => setChangePasswordModal(true)}>Change Password</Menu.Item>
|
<Menu.Item leftSection={<FaLock size={14} />} onClick={() => setChangePasswordModal(true)}>Change Password</Menu.Item>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Menu.Label>Actions</Menu.Label>
|
<Menu.Label>Actions</Menu.Label>
|
||||||
<Menu.Item color="red" icon={<MdOutlineSettingsBackupRestore size={18} />} onClick={() => setResetFiregexModal(true)}>Reset Firegex</Menu.Item>
|
<Menu.Item color="red" leftSection={<MdOutlineSettingsBackupRestore size={18} />} onClick={() => setResetFiregexModal(true)}>Reset Firegex</Menu.Item>
|
||||||
</MenuDropDownWithButton>
|
</MenuDropDownWithButton>
|
||||||
<Space w="md" />
|
<Space w="md" />
|
||||||
<Tooltip label="Home" position='bottom' color="teal" opened={tooltipHomeOpened}>
|
<Tooltip label="Home" position='bottom' color="teal" opened={tooltipHomeOpened}>
|
||||||
@@ -78,7 +81,7 @@ function HeaderPage({navOpen, setNav, ...other}: { navOpen: boolean, setNav:Reac
|
|||||||
<ResetPasswordModal opened={changePasswordModal} onClose={() => setChangePasswordModal(false)} />
|
<ResetPasswordModal opened={changePasswordModal} onClose={() => setChangePasswordModal(false)} />
|
||||||
<ResetModal opened={resetFiregexModal} onClose={() => setResetFiregexModal(false)} />
|
<ResetModal opened={resetFiregexModal} onClose={() => setResetFiregexModal(false)} />
|
||||||
<Space w="xl" />
|
<Space w="xl" />
|
||||||
</Header>
|
</AppShell.Header>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HeaderPage;
|
export default HeaderPage;
|
||||||
|
|||||||
@@ -1,55 +1,119 @@
|
|||||||
import { AutocompleteItem, Select, SelectProps } from "@mantine/core";
|
import { Combobox, TextInput, useCombobox } from "@mantine/core";
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { ipInterfacesQuery } from "../js/utils";
|
import { ipInterfacesQuery } from "../js/utils";
|
||||||
|
|
||||||
|
interface ItemProps{
|
||||||
const AutoCompleteItem = React.forwardRef<HTMLDivElement, ItemProps>(
|
value: string
|
||||||
({ netint, value, ...props }: ItemProps, ref) => <div ref={ref} {...props}>
|
|
||||||
( <b>{netint}</b> ) -{">"} <b>{value}</b>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
interface ItemProps extends AutocompleteItem {
|
|
||||||
netint: string;
|
netint: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InterfaceInputProps extends Omit<SelectProps, "data">{
|
interface InterfaceInputProps{
|
||||||
initialCustomInterfaces?:AutocompleteItem[],
|
initialCustomInterfaces?:ItemProps[],
|
||||||
includeInterfaceNames?:boolean
|
includeInterfaceNames?:boolean,
|
||||||
|
onChange?: (value:string) => void,
|
||||||
|
value?:string,
|
||||||
|
defaultValue?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InterfaceInput = ({ initialCustomInterfaces, includeInterfaceNames, ...props }:InterfaceInputProps) => {
|
export const InterfaceInput = ({ initialCustomInterfaces, includeInterfaceNames, onChange, value, defaultValue }:InterfaceInputProps) => {
|
||||||
|
|
||||||
const [customIpInterfaces, setCustomIpInterfaces] = useState<AutocompleteItem[]>(initialCustomInterfaces??[]);
|
const [customIpInterfaces, setCustomIpInterfaces] = useState<ItemProps[]>(initialCustomInterfaces??[]);
|
||||||
const interfacesQuery = ipInterfacesQuery()
|
const interfacesQuery = ipInterfacesQuery()
|
||||||
|
|
||||||
const getInterfaces = () => {
|
const getInterfaces = () => {
|
||||||
if (interfacesQuery.isLoading || !interfacesQuery.data) return []
|
if (interfacesQuery.isLoading || !interfacesQuery.data) return []
|
||||||
if(includeInterfaceNames){
|
if(includeInterfaceNames){
|
||||||
const result = interfacesQuery.data.map(item => ({netint:"IP", value:item.addr, label:item.addr})) as AutocompleteItem[]
|
const result = interfacesQuery.data.map(item => ({netint:"IP", value:item.addr})) as ItemProps[]
|
||||||
interfacesQuery.data.map(item => item.name).filter((item, index, arr) => arr.indexOf(item) === index).forEach(item => result.push({netint:"INT", value:item, label:item}))
|
interfacesQuery.data.map(item => item.name).filter((item, index, arr) => arr.indexOf(item) === index).forEach(item => result.push({netint:"INT", value:item}))
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
return (interfacesQuery.data.map(item => ({netint:item.name, value:item.addr, label:item.addr})) as AutocompleteItem[])
|
return (interfacesQuery.data.map(item => ({netint:item.name, value:item.addr})) as ItemProps[])
|
||||||
}
|
}
|
||||||
|
|
||||||
const interfaces = getInterfaces()
|
const interfaces = getInterfaces()
|
||||||
|
|
||||||
return <Select
|
const combobox = useCombobox({
|
||||||
placeholder="10.1.1.1"
|
onDropdownClose: () => {
|
||||||
itemComponent={AutoCompleteItem}
|
combobox.resetSelectedOption()
|
||||||
data={[...customIpInterfaces, ...interfaces]}
|
},
|
||||||
searchable
|
});
|
||||||
dropdownPosition="bottom"
|
|
||||||
maxDropdownHeight={200}
|
const data = [...customIpInterfaces, ...interfaces]
|
||||||
creatable
|
const [selectedValue, setSelectedValue] = useState<string | null>(null);
|
||||||
getCreateLabel={(query) => `+ Use this: ${query}`}
|
const [search, setSearch] = useState('');
|
||||||
onCreate={(query) => {
|
|
||||||
const item = { value: query, netint: "CUSTOM", label: query };
|
const exactOptionMatch: ItemProps|undefined = data.find((item) => item.value === search);
|
||||||
setCustomIpInterfaces((current) => [...current, item]);
|
|
||||||
return item;
|
const filteredOptions = data.filter((item) => item.value.toLowerCase().includes(search.toLowerCase().trim())).sort((a, b) => {
|
||||||
|
if (exactOptionMatch != null) {
|
||||||
|
if (a.value == exactOptionMatch.value) return -1
|
||||||
|
if (b.value == exactOptionMatch.value) return 1
|
||||||
|
}
|
||||||
|
return a.value.localeCompare(b.value)
|
||||||
|
});
|
||||||
|
|
||||||
|
const options = filteredOptions.map((item) => (
|
||||||
|
<Combobox.Option value={item.value} key={item.value}>
|
||||||
|
( <b>{item.netint}</b> ) -{">"} <b>{item.value}</b>
|
||||||
|
</Combobox.Option>
|
||||||
|
));
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<Combobox
|
||||||
|
store={combobox}
|
||||||
|
withinPortal={false}
|
||||||
|
position="bottom-end"
|
||||||
|
onOptionSubmit={(value) => {
|
||||||
|
if (value === '$create') {
|
||||||
|
const item = { value: search, netint: "CUSTOM" };
|
||||||
|
setCustomIpInterfaces((current) => [...current, item]);
|
||||||
|
setSelectedValue(search);
|
||||||
|
onChange?.(search)
|
||||||
|
} else {
|
||||||
|
setSelectedValue(value);
|
||||||
|
setSearch(value);
|
||||||
|
onChange?.(value)
|
||||||
|
}
|
||||||
|
combobox.closeDropdown();
|
||||||
}}
|
}}
|
||||||
style={props.style?{width:"100%", ...props.style}:{width:"100%"}}
|
>
|
||||||
{...props}
|
|
||||||
/>
|
<Combobox.Target>
|
||||||
|
<TextInput
|
||||||
|
style={{width:"100%"}}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
rightSection={<Combobox.Chevron />}
|
||||||
|
value={value??(defaultValue?undefined:search)}
|
||||||
|
placeholder="10.1.1.1"
|
||||||
|
rightSectionPointerEvents="none"
|
||||||
|
onChange={(event) => {
|
||||||
|
combobox.openDropdown();
|
||||||
|
combobox.updateSelectedOptionIndex();
|
||||||
|
setSearch(event.currentTarget.value)
|
||||||
|
onChange?.(event.currentTarget.value)
|
||||||
|
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
combobox.openDropdown()
|
||||||
|
}}
|
||||||
|
onFocus={(e) => {
|
||||||
|
combobox.openDropdown()
|
||||||
|
}}
|
||||||
|
onBlur={(e) => {
|
||||||
|
combobox.closeDropdown();
|
||||||
|
setSearch(selectedValue??'');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Combobox.Target>
|
||||||
|
|
||||||
|
<Combobox.Dropdown>
|
||||||
|
<Combobox.Options mah={100} style={{ overflowY: 'auto' }}>
|
||||||
|
{options}
|
||||||
|
{(exactOptionMatch==null) && search.trim().length > 0 && (
|
||||||
|
<Combobox.Option value="$create">+ Use this: {search}</Combobox.Option>
|
||||||
|
)}
|
||||||
|
</Combobox.Options>
|
||||||
|
</Combobox.Dropdown>
|
||||||
|
</Combobox>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
@@ -1,44 +1,38 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { ActionIcon, Container, Menu, Space } from '@mantine/core';
|
import { ActionIcon, Container, Menu, Space } from '@mantine/core';
|
||||||
import { AppShell } from '@mantine/core';
|
import { AppShell } from '@mantine/core';
|
||||||
import NavBar from './NavBar';
|
import NavBar from './NavBar';
|
||||||
import FooterPage from './Footer';
|
|
||||||
import HeaderPage from './Header';
|
import HeaderPage from './Header';
|
||||||
import { getmainpath } from '../js/utils';
|
import { getMainPath } from '../js/utils';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { RiMenu5Fill } from 'react-icons/ri';
|
import { RiMenu5Fill } from 'react-icons/ri';
|
||||||
|
import { useNavbarStore } from '../js/store';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function MainLayout({ children }:{ children:any }) {
|
function MainLayout({ children }:{ children:any }) {
|
||||||
const [opened, setOpened] = useState(false);
|
const { navOpened } = useNavbarStore()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if (location.pathname !== "/"){
|
if (location.pathname !== "/"){
|
||||||
sessionStorage.setItem('home_section', getmainpath())
|
sessionStorage.setItem('home_section', getMainPath())
|
||||||
}
|
}
|
||||||
},[location.pathname])
|
},[location.pathname])
|
||||||
|
return <AppShell
|
||||||
|
header={{ height: 70 }}
|
||||||
return <>
|
navbar={{ width: 300 , breakpoint: "md", collapsed: { mobile: !navOpened } }}
|
||||||
|
p="md"
|
||||||
<AppShell
|
|
||||||
padding="md"
|
|
||||||
fixed
|
|
||||||
navbar={<NavBar closeNav={()=>setOpened(false)} opened={opened} />}
|
|
||||||
header={<HeaderPage navOpen={opened} setNav={setOpened} />}
|
|
||||||
footer={<FooterPage />}
|
|
||||||
>
|
>
|
||||||
<Container size="lg">
|
<HeaderPage />
|
||||||
{children}
|
<NavBar />
|
||||||
</Container>
|
<AppShell.Main>
|
||||||
|
<Container size="lg">
|
||||||
|
{children}
|
||||||
|
</Container>
|
||||||
|
</AppShell.Main>
|
||||||
<Space h="lg" />
|
<Space h="lg" />
|
||||||
|
|
||||||
</AppShell>
|
</AppShell>
|
||||||
|
|
||||||
</>
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MainLayout;
|
export default MainLayout;
|
||||||
@@ -46,7 +40,7 @@ export default MainLayout;
|
|||||||
export const MenuDropDownWithButton = ({children}:{children:any}) => <Menu withArrow>
|
export const MenuDropDownWithButton = ({children}:{children:any}) => <Menu withArrow>
|
||||||
<Menu.Target>
|
<Menu.Target>
|
||||||
<ActionIcon variant='transparent'>
|
<ActionIcon variant='transparent'>
|
||||||
<RiMenu5Fill size={24} />
|
<RiMenu5Fill size={24} color='#FFF'/>
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl } from '@mantine/core';
|
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl, Box } from '@mantine/core';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { okNotify, regex_ipv4, regex_ipv6 } from '../../js/utils';
|
import { okNotify, regex_ipv4, regex_ipv6 } from '../../js/utils';
|
||||||
@@ -71,12 +71,12 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
|||||||
<PortAndInterface form={form} int_name="ip_int" port_name="port" label={"Public IP Interface and port (ipv4/ipv6 + CIDR allowed)"} />
|
<PortAndInterface form={form} int_name="ip_int" port_name="port" label={"Public IP Interface and port (ipv4/ipv6 + CIDR allowed)"} />
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
|
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Switch
|
<Switch
|
||||||
label="Auto-Start Service"
|
label="Auto-Start Service"
|
||||||
{...form.getInputProps('autostart', { type: 'checkbox' })}
|
{...form.getInputProps('autostart', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
<div className="flex-spacer"></div>
|
<Box className="flex-spacer"></Box>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
data={[
|
data={[
|
||||||
{ label: 'TCP', value: 'tcp' },
|
{ label: 'TCP', value: 'tcp' },
|
||||||
@@ -84,9 +84,9 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
|||||||
]}
|
]}
|
||||||
{...form.getInputProps('proto')}
|
{...form.getInputProps('proto')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Box>
|
||||||
|
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Add Service</Button>
|
<Button loading={submitLoading} type="submit">Add Service</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
|
|||||||
placeholder="Awesome Service Name!"
|
placeholder="Awesome Service Name!"
|
||||||
{...form.getInputProps('name')}
|
{...form.getInputProps('name')}
|
||||||
/>
|
/>
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Rename</Button>
|
<Button loading={submitLoading} type="submit">Rename</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
|
|
||||||
@use "../../../index.scss" as *;
|
|
||||||
|
|
||||||
.row{
|
|
||||||
width: 95%;
|
|
||||||
padding: 30px 0px;
|
|
||||||
border-radius: 20px;
|
|
||||||
margin: 10px;
|
|
||||||
@extend .center-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name{
|
|
||||||
font-size: 2.3em;
|
|
||||||
font-weight: bolder;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-bottom: 13px;
|
|
||||||
color:#FFF;
|
|
||||||
max-width: 300px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.name:hover{
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
import { ActionIcon, Badge, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FaPlay, FaStop } from 'react-icons/fa';
|
import { FaPlay, FaStop } from 'react-icons/fa';
|
||||||
import { nfregex, Service, serviceQueryKey } from '../utils';
|
import { nfregex, Service, serviceQueryKey } from '../utils';
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md"
|
import { MdOutlineArrowForwardIos } from "react-icons/md"
|
||||||
import style from "./index.module.scss";
|
|
||||||
import YesNoModal from '../../YesNoModal';
|
import YesNoModal from '../../YesNoModal';
|
||||||
import { errorNotify, isMediumScreen, okNotify, regex_ipv4 } from '../../../js/utils';
|
import { errorNotify, isMediumScreen, okNotify, regex_ipv4 } from '../../../js/utils';
|
||||||
import { BsTrashFill } from 'react-icons/bs';
|
import { BsTrashFill } from 'react-icons/bs';
|
||||||
@@ -72,71 +71,73 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Grid className={style.row} justify="flex-end" style={{width:"100%"}}>
|
<Box className='firegex__nfregex__rowbox'>
|
||||||
<Grid.Col md={4} xs={12}>
|
<Grid className="firegex__nfregex__row" justify="flex-end" style={{width:"100%"}}>
|
||||||
|
<Grid.Col span={{ md:4, xs: 12 }}>
|
||||||
|
|
||||||
<div className={isMedium?"center-flex-row":"center-flex"}>
|
<Box className={"center-flex-row"}>
|
||||||
<div className="center-flex">
|
<Title className="firegex__nfregex__name">
|
||||||
<Title className={style.name}>
|
|
||||||
{service.name}
|
{service.name}
|
||||||
</Title>
|
</Title>
|
||||||
<Badge size="xl" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient">
|
<Box className="center-flex" style={{ gap: 6 }}>
|
||||||
:{service.port}
|
<Badge color={status_color} radius="md" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
|
||||||
</Badge>
|
<Badge size="lg" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient" radius="md">
|
||||||
</div>
|
:{service.port}
|
||||||
<Badge style={isMedium?{}:{marginLeft:"20px"}} color={status_color} radius="sm" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
|
</Badge>
|
||||||
{isMedium?null:<Space w="xl" />}
|
</Box>
|
||||||
</div>
|
{isMedium?null:<Space w="xl" />}
|
||||||
{!isMedium?<Space h="xl" />:null}
|
</Box>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|
||||||
<Grid.Col className="center-flex" md={8} xs={12}>
|
|
||||||
{!isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
|
|
||||||
|
|
||||||
<div className="center-flex-row">
|
<Grid.Col className={isMedium?"center-flex":"center-flex-row"} span={{ md:8, xs: 12 }}>
|
||||||
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
|
<Box visibleFrom='md' className='flex-spacer' />
|
||||||
<Space h="xs" />
|
<Space hiddenFrom='md' h="md" />
|
||||||
<Badge color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
|
<Space hiddenFrom='md' w="xl" />
|
||||||
<Space h="xs" />
|
<Space hiddenFrom='md' w="md" />
|
||||||
<Badge color={service.ip_int.match(regex_ipv4)?"cyan":"pink"} radius="sm" size="md" variant="filled">{service.ip_int} on {service.proto}</Badge>
|
<Box className="center-flex-row">
|
||||||
</div>
|
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
|
||||||
{isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
|
<Space h="xs" />
|
||||||
<div className="center-flex">
|
<Badge color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
|
||||||
<MenuDropDownWithButton>
|
<Space h="xs" />
|
||||||
<Menu.Label><b>Rename service</b></Menu.Label>
|
<Badge color={service.ip_int.match(regex_ipv4)?"cyan":"pink"} radius="sm" size="md" variant="filled">{service.ip_int} on {service.proto}</Badge>
|
||||||
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
</Box>
|
||||||
<Divider />
|
{isMedium?<Box className='flex-spacer' />:<Space h="xl" />}
|
||||||
<Menu.Label><b>Danger zone</b></Menu.Label>
|
<Box className="center-flex">
|
||||||
<Menu.Item color="red" icon={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
|
<MenuDropDownWithButton>
|
||||||
</MenuDropDownWithButton>
|
<Menu.Label><b>Rename service</b></Menu.Label>
|
||||||
<Space w="md"/>
|
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
||||||
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
|
<Divider />
|
||||||
<ActionIcon color="red" loading={buttonLoading}
|
<Menu.Label><b>Danger zone</b></Menu.Label>
|
||||||
onClick={stopService} size="xl" radius="md" variant="filled"
|
<Menu.Item color="red" leftSection={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
|
||||||
disabled={service.status === "stop"}
|
</MenuDropDownWithButton>
|
||||||
aria-describedby="tooltip-stop-id"
|
<Space w="md"/>
|
||||||
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
|
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
|
||||||
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
|
<ActionIcon color="red" loading={buttonLoading}
|
||||||
<FaStop size="20px" />
|
onClick={stopService} size="xl" radius="md" variant="filled"
|
||||||
</ActionIcon>
|
disabled={service.status === "stop"}
|
||||||
</Tooltip>
|
aria-describedby="tooltip-stop-id"
|
||||||
<Space w="md"/>
|
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
|
||||||
<Tooltip label="Start service" zIndex={0} color="teal">
|
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
|
||||||
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
|
<FaStop size="20px" />
|
||||||
variant="filled" disabled={!["stop","pause"].includes(service.status)?true:false}>
|
</ActionIcon>
|
||||||
<FaPlay size="20px" />
|
</Tooltip>
|
||||||
</ActionIcon>
|
<Space w="md"/>
|
||||||
</Tooltip>
|
<Tooltip label="Start service" zIndex={0} color="teal">
|
||||||
</div>
|
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
|
||||||
<Space w="xl" /><Space w="xl" />
|
variant="filled" disabled={!["stop","pause"].includes(service.status)?true:false}>
|
||||||
{onClick?<div>
|
<FaPlay size="20px" />
|
||||||
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={45} />
|
</ActionIcon>
|
||||||
<Space w="xl" />
|
</Tooltip>
|
||||||
</div>:null}
|
{isMedium?<Space w="xl" />:<Space w="md" />}
|
||||||
{isMedium?<><Space w="xl" /><Space w="xl" /></>:null}
|
{onClick?<Box style={{ backgroundColor: "var(--secondary_color)", borderRadius: "38%", width:"35px", height:"35px", display:"flex", justifyContent: "center", alignItems: "center", border:"#AAA 2px solid"}}>
|
||||||
</Grid.Col>
|
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={25} />
|
||||||
</Grid>
|
</Box>:null}
|
||||||
<Divider size="md" style={{width:"100%"}}/>
|
{isMedium?<Space w="xl" />:null}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
<YesNoModal
|
<YesNoModal
|
||||||
title='Are you sure to delete this service?'
|
title='Are you sure to delete this service?'
|
||||||
description={`You are going to delete the service '${service.port}', causing the stopping of the firewall and deleting all the regex associated. This will cause the shutdown of your service! ⚠️`}
|
description={`You are going to delete the service '${service.port}', causing the stopping of the firewall and deleting all the regex associated. This will cause the shutdown of your service! ⚠️`}
|
||||||
|
|||||||
@@ -1,29 +1,19 @@
|
|||||||
import { Collapse, Divider, Group, MantineColor, Navbar, ScrollArea, Text, ThemeIcon, Title, UnstyledButton } from "@mantine/core";
|
import { Collapse, Divider, Group, MantineColor, ScrollArea, Text, ThemeIcon, Title, UnstyledButton, Box, AppShell } from "@mantine/core";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { IoMdGitNetwork } from "react-icons/io";
|
import { IoMdGitNetwork } from "react-icons/io";
|
||||||
import { MdOutlineExpandLess, MdOutlineExpandMore, MdTransform } from "react-icons/md";
|
import { MdOutlineExpandLess, MdOutlineExpandMore, MdTransform } from "react-icons/md";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { getmainpath } from "../../js/utils";
|
|
||||||
import { GrDirections } from "react-icons/gr";
|
import { GrDirections } from "react-icons/gr";
|
||||||
import { PiWallLight } from "react-icons/pi";
|
import { PiWallLight } from "react-icons/pi";
|
||||||
|
import { useNavbarStore } from "../../js/store";
|
||||||
|
import { getMainPath } from "../../js/utils";
|
||||||
|
|
||||||
function NavBarButton({ navigate, closeNav, name, icon, color, disabled, onClick }:
|
function NavBarButton({ navigate, closeNav, name, icon, color, disabled, onClick }:
|
||||||
{ navigate?: string, closeNav: () => void, name:string, icon:any, color:MantineColor, disabled?:boolean, onClick?:CallableFunction }) {
|
{ navigate?: string, closeNav: () => void, name:string, icon:any, color:MantineColor, disabled?:boolean, onClick?:CallableFunction }) {
|
||||||
const navigator = useNavigate()
|
const navigator = useNavigate()
|
||||||
|
return <UnstyledButton
|
||||||
return <UnstyledButton sx={(theme) => ({
|
className={`firegex__navbar__unstyled_button${navigate==getMainPath()?" selected":""}${disabled?" disabled":""}`}
|
||||||
display: 'block',
|
onClick={()=>{
|
||||||
width: '100%',
|
|
||||||
padding: theme.spacing.xs,
|
|
||||||
borderRadius: theme.radius.sm,
|
|
||||||
opacity: disabled ? 0.4 : 1,
|
|
||||||
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
|
|
||||||
backgroundColor:(navigate===getmainpath()?(theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0]):"transparent"),
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor:
|
|
||||||
theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
|
|
||||||
},
|
|
||||||
})} onClick={()=>{
|
|
||||||
if(navigate){navigator(`/${navigate}`);closeNav()}
|
if(navigate){navigator(`/${navigate}`);closeNav()}
|
||||||
if (onClick) onClick()
|
if (onClick) onClick()
|
||||||
}} disabled={disabled}>
|
}} disabled={disabled}>
|
||||||
@@ -36,17 +26,16 @@ function NavBarButton({ navigate, closeNav, name, icon, color, disabled, onClick
|
|||||||
</UnstyledButton>
|
</UnstyledButton>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NavBar({ closeNav, opened }: {closeNav: () => void, opened: boolean}) {
|
export default function NavBar() {
|
||||||
const [toggle, setToggleState] = useState(false);
|
const [toggle, setToggleState] = useState(false);
|
||||||
|
const { navOpened, closeNav } = useNavbarStore()
|
||||||
|
|
||||||
|
return <AppShell.Navbar p="md" hidden={!navOpened}>
|
||||||
return <Navbar p="md" hiddenBreakpoint="md" hidden={!opened} width={{ md: 300 }}>
|
<Box px="xs" mt="xs">
|
||||||
<Navbar.Section px="xs" mt="xs">
|
<Title order={4}>Options ⚙️</Title>
|
||||||
<Title order={3}>[Fi]*regex 🔥</Title>
|
</Box>
|
||||||
</Navbar.Section>
|
|
||||||
<Divider my="xs" />
|
<Divider my="xs" />
|
||||||
|
<Box style={{flexGrow: 1}} component={ScrollArea} px="xs" mt="xs">
|
||||||
<Navbar.Section grow component={ScrollArea} px="xs" mt="xs">
|
|
||||||
<NavBarButton navigate="nfregex" closeNav={closeNav} name="Netfilter Regex" color="lime" icon={<IoMdGitNetwork />} />
|
<NavBarButton navigate="nfregex" closeNav={closeNav} name="Netfilter Regex" color="lime" icon={<IoMdGitNetwork />} />
|
||||||
<NavBarButton navigate="firewall" closeNav={closeNav} name="Firewall Rules" color="red" icon={<PiWallLight />} />
|
<NavBarButton navigate="firewall" closeNav={closeNav} name="Firewall Rules" color="red" icon={<PiWallLight />} />
|
||||||
<NavBarButton navigate="porthijack" closeNav={closeNav} name="Hijack Port to Proxy" color="blue" icon={<GrDirections />} />
|
<NavBarButton navigate="porthijack" closeNav={closeNav} name="Hijack Port to Proxy" color="blue" icon={<GrDirections />} />
|
||||||
@@ -55,7 +44,7 @@ export default function NavBar({ closeNav, opened }: {closeNav: () => void, open
|
|||||||
<Collapse in={toggle}>
|
<Collapse in={toggle}>
|
||||||
<NavBarButton navigate="regexproxy" closeNav={closeNav} name="TCP Proxy Regex Filter" color="grape" icon={<MdTransform />} />
|
<NavBarButton navigate="regexproxy" closeNav={closeNav} name="TCP Proxy Regex Filter" color="grape" icon={<MdTransform />} />
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Navbar.Section>
|
</Box>
|
||||||
|
|
||||||
</Navbar>
|
</AppShell.Navbar>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { ActionIcon, ActionIconProps } from "@mantine/core"
|
import { ActionIcon, ActionIconProps, PolymorphicComponentProps } from "@mantine/core"
|
||||||
import { ImCheckmark, ImCross } from "react-icons/im"
|
import { ImCheckmark, ImCross } from "react-icons/im"
|
||||||
import { TiTick } from "react-icons/ti"
|
|
||||||
import {PolymorphicComponentProps} from "@mantine/utils"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface IOnOffButtonProps extends Omit<PolymorphicComponentProps<"button",ActionIconProps>, "value">{
|
interface IOnOffButtonProps extends Omit<PolymorphicComponentProps<"button",ActionIconProps>, "value">{
|
||||||
value: boolean,
|
value: boolean,
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
import { AutocompleteItem, Select, Space, Title } from "@mantine/core"
|
import { Box, Space, Title } from "@mantine/core"
|
||||||
import React, { useEffect, useState } from "react"
|
import React from "react"
|
||||||
import { ipInterfacesQuery } from "../js/utils";
|
|
||||||
import PortInput from "./PortInput";
|
import PortInput from "./PortInput";
|
||||||
import { UseFormReturnType } from "@mantine/form/lib/types";
|
import { UseFormReturnType } from "@mantine/form/lib/types";
|
||||||
import { InterfaceInput } from "./InterfaceInput";
|
import { InterfaceInput } from "./InterfaceInput";
|
||||||
|
|
||||||
interface ItemProps extends AutocompleteItem {
|
type ItemProps = {
|
||||||
|
value: string;
|
||||||
netint: string;
|
netint: string;
|
||||||
}
|
} & any
|
||||||
|
|
||||||
const AutoCompleteItem = React.forwardRef<HTMLDivElement, ItemProps>(
|
const AutoCompleteItem = React.forwardRef<HTMLDivElement, ItemProps>(
|
||||||
({ netint, value, ...props }: ItemProps, ref) => <div ref={ref} {...props}>
|
({ netint, value, ...props }, ref) => <Box ref={ref} {...props}>
|
||||||
( <b>{netint}</b> ) -{">"} <b>{value}</b>
|
( <b>{netint}</b> ) -{">"} <b>{value}</b>
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
export default function PortAndInterface({ form, int_name, port_name, label, orientation }:{ form:UseFormReturnType<any>, int_name:string, port_name:string, label?:string, orientation?:"line"|"column" }) {
|
export default function PortAndInterface({ form, int_name, port_name, label, orientation }:{ form:UseFormReturnType<any>, int_name:string, port_name:string, label?:string, orientation?:"line"|"column" }) {
|
||||||
|
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ export default function PortAndInterface({ form, int_name, port_name, label, ori
|
|||||||
{label?<>
|
{label?<>
|
||||||
<Title order={6}>{label}</Title>
|
<Title order={6}>{label}</Title>
|
||||||
<Space h="xs" /></> :null}
|
<Space h="xs" /></> :null}
|
||||||
<div className={(!orientation || orientation == "line")?'center-flex':"center-flex-row"} style={{width:"100%"}}>
|
<Box className={(!orientation || orientation == "line")?'center-flex':"center-flex-row"} style={{width:"100%"}}>
|
||||||
<InterfaceInput
|
<InterfaceInput
|
||||||
{...form.getInputProps(int_name)}
|
{...form.getInputProps(int_name)}
|
||||||
/>
|
/>
|
||||||
@@ -32,6 +31,6 @@ export default function PortAndInterface({ form, int_name, port_name, label, ori
|
|||||||
<><Space w="sm" /><span style={{marginTop:"-3px", fontSize:"1.5em"}}>:</span><Space w="sm" /></>:
|
<><Space w="sm" /><span style={{marginTop:"-3px", fontSize:"1.5em"}}>:</span><Space w="sm" /></>:
|
||||||
<Space h="md" />}
|
<Space h="md" />}
|
||||||
<PortInput {...form.getInputProps(port_name)} />
|
<PortInput {...form.getInputProps(port_name)} />
|
||||||
</div>
|
</Box>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl } from '@mantine/core';
|
import { Button, Group, Space, TextInput, Notification, Modal, Switch, SegmentedControl, Box } from '@mantine/core';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { okNotify, regex_ipv6_no_cidr, regex_ipv4_no_cidr } from '../../js/utils';
|
import { okNotify, regex_ipv6_no_cidr, regex_ipv4_no_cidr } from '../../js/utils';
|
||||||
@@ -79,12 +79,12 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
|||||||
<PortAndInterface form={form} int_name="ip_dst" port_name="proxy_port" label="Proxy/Internal IP Address and port (ipv4/ipv6)" />
|
<PortAndInterface form={form} int_name="ip_dst" port_name="proxy_port" label="Proxy/Internal IP Address and port (ipv4/ipv6)" />
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
|
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Switch
|
<Switch
|
||||||
label="Auto-Start Service"
|
label="Auto-Start Service"
|
||||||
{...form.getInputProps('autostart', { type: 'checkbox' })}
|
{...form.getInputProps('autostart', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
<div className="flex-spacer"></div>
|
<Box className="flex-spacer" />
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
data={[
|
data={[
|
||||||
{ label: 'TCP', value: 'tcp' },
|
{ label: 'TCP', value: 'tcp' },
|
||||||
@@ -92,9 +92,9 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
|||||||
]}
|
]}
|
||||||
{...form.getInputProps('proto')}
|
{...form.getInputProps('proto')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Box>
|
||||||
|
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Add Service</Button>
|
<Button loading={submitLoading} type="submit">Add Service</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ function ChangeDestination({ opened, onClose, service }:{ opened:boolean, onClos
|
|||||||
<form onSubmit={form.onSubmit(submitRequest)}>
|
<form onSubmit={form.onSubmit(submitRequest)}>
|
||||||
|
|
||||||
<PortAndInterface form={form} int_name="ip_dst" port_name="proxy_port" />
|
<PortAndInterface form={form} int_name="ip_dst" port_name="proxy_port" />
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Change</Button>
|
<Button loading={submitLoading} type="submit">Change</Button>
|
||||||
</Group>
|
</Group>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
|
|||||||
placeholder="Awesome Service Name!"
|
placeholder="Awesome Service Name!"
|
||||||
{...form.getInputProps('name')}
|
{...form.getInputProps('name')}
|
||||||
/>
|
/>
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Rename</Button>
|
<Button loading={submitLoading} type="submit">Rename</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
|
|
||||||
@use "../../../index.scss" as *;
|
|
||||||
|
|
||||||
.row{
|
|
||||||
width: 95%;
|
|
||||||
padding: 15px 0px;
|
|
||||||
border-radius: 20px;
|
|
||||||
margin: 10px;
|
|
||||||
@extend .center-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.row-mobile{
|
|
||||||
@extend .row;
|
|
||||||
@extend .center-flex-row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name{
|
|
||||||
font-size: 2.3em;
|
|
||||||
font-weight: bolder;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-bottom: 13px;
|
|
||||||
color:#FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.portInput *{
|
|
||||||
color: #FFF;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1em;
|
|
||||||
margin-top: -1px;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ActionIcon, Badge, Divider, Menu, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { FaPlay, FaStop } from 'react-icons/fa';
|
import { FaPlay, FaStop } from 'react-icons/fa';
|
||||||
import { porthijack, Service } from '../utils';
|
import { porthijack, Service } from '../utils';
|
||||||
import style from "./index.module.scss";
|
|
||||||
import YesNoModal from '../../YesNoModal';
|
import YesNoModal from '../../YesNoModal';
|
||||||
import { errorNotify, isMediumScreen, okNotify } from '../../../js/utils';
|
import { errorNotify, isMediumScreen, okNotify } from '../../../js/utils';
|
||||||
import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs';
|
import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs';
|
||||||
@@ -90,86 +89,91 @@ function ServiceRow({ service }:{ service:Service }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className={isMedium?style.row:style.row_mobile} style={{width:"100%"}}>
|
<Box className='firegex__nfregex__rowbox'>
|
||||||
<Space w="xl" /><Space w="xl" />
|
<Grid className="firegex__nfregex__row" justify="flex-end" style={{width:"100%"}}>
|
||||||
<div>
|
<Grid.Col span={{ md:4, xs: 12 }}>
|
||||||
<div className="center-flex-row">
|
<Box className={"center-flex-row"}>
|
||||||
<Title order={4} className={style.name}>{service.name}</Title>
|
<Title className="firegex__nfregex__name">
|
||||||
<div className="center-flex">
|
{service.name}
|
||||||
<Badge color={status_color} radius="sm" size="md" variant="filled">Status: <u>{service.active?"ENABLED":"DISABLED"}</u></Badge>
|
</Title>
|
||||||
<Space w="sm" />
|
<Box className="center-flex" style={{ gap: 6 }}>
|
||||||
<Badge color={service.proto === "tcp"?"cyan":"orange"} radius="sm" size="md" variant="filled">
|
<Badge color={status_color} radius="md" size="lg" variant="filled">Status: <u>{service.active?"ENABLED":"DISABLED"}</u></Badge>
|
||||||
{service.proto}
|
<Badge color={service.proto === "tcp"?"cyan":"orange"} radius="md" size="lg" variant="filled">
|
||||||
</Badge>
|
{service.proto}
|
||||||
</div>
|
</Badge>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
{isMedium?null:<Space w="xl" />}
|
||||||
|
</Box>
|
||||||
<div className='flex-spacer' />
|
</Grid.Col>
|
||||||
{isMedium?null:<Space h="xl" />}
|
|
||||||
<div className='center-flex'>
|
|
||||||
<div className="center-flex-row">
|
|
||||||
<Badge color="lime" radius="sm" size="md" variant="filled">
|
|
||||||
FROM {service.ip_src} : {service.public_port}
|
|
||||||
</Badge>
|
|
||||||
<Space h="sm" />
|
|
||||||
<Badge color="blue" radius="sm" size="md" variant="filled">
|
|
||||||
<div className="center-flex">
|
|
||||||
TO {service.ip_dst} :
|
|
||||||
<form onSubmit={form.onSubmit((v)=>portInputRef.current?.blur())}>
|
|
||||||
<PortInput
|
|
||||||
defaultValue={service.proxy_port}
|
|
||||||
size="xs"
|
|
||||||
variant="unstyled"
|
|
||||||
style={{
|
|
||||||
width: (10+form.values.proxy_port.toString().length*6.2) +"px"
|
|
||||||
}}
|
|
||||||
className={style.portInput}
|
|
||||||
onBlur={(e)=>{onChangeProxyPort({proxy_port:parseInt(e.target.value)})}}
|
|
||||||
ref={portInputRef}
|
|
||||||
{...form.getInputProps("proxy_port")}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Space w="xl" /><Space w="xl" />
|
|
||||||
<div className="center-flex">
|
|
||||||
<MenuDropDownWithButton>
|
|
||||||
<Menu.Label><b>Rename service</b></Menu.Label>
|
|
||||||
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
|
||||||
<Menu.Label><b>Change destination</b></Menu.Label>
|
|
||||||
<Menu.Item icon={<BsArrowRepeat size={18} />} onClick={()=>setChangeDestModal(true)}>Change hijacking destination</Menu.Item>
|
|
||||||
<Divider />
|
|
||||||
<Menu.Label><b>Danger zone</b></Menu.Label>
|
|
||||||
<Menu.Item color="red" icon={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
|
|
||||||
</MenuDropDownWithButton>
|
|
||||||
<Space w="md"/>
|
|
||||||
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
|
|
||||||
<ActionIcon color="red" loading={buttonLoading}
|
|
||||||
onClick={stopService} size="xl" radius="md" variant="filled"
|
|
||||||
disabled={!service.active}
|
|
||||||
aria-describedby="tooltip-stop-id"
|
|
||||||
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
|
|
||||||
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
|
|
||||||
<FaStop size="20px" />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
<Space w="md"/>
|
|
||||||
<Tooltip label="Start service" zIndex={0} color="teal">
|
|
||||||
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
|
|
||||||
variant="filled" disabled={service.active}>
|
|
||||||
<FaPlay size="20px" />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{isMedium?null:<Space h="xl" />}
|
|
||||||
<Space w="xl" /><Space w="xl" />
|
|
||||||
|
|
||||||
</div>
|
<Grid.Col className={isMedium?"center-flex":"center-flex-row"} span={{ md:8, xs: 12 }}>
|
||||||
<Divider size="sm" style={{width:"100%"}}/>
|
<Box visibleFrom='md' className='flex-spacer' />
|
||||||
|
<Space hiddenFrom='md' h="md" />
|
||||||
|
<Space hiddenFrom='md' w="xl" />
|
||||||
|
<Space hiddenFrom='md' w="md" />
|
||||||
|
|
||||||
|
<Box className="center-flex-row">
|
||||||
|
<Badge color="lime" radius="sm" size="md" variant="filled">
|
||||||
|
FROM {service.ip_src} : {service.public_port}
|
||||||
|
</Badge>
|
||||||
|
<Space h="sm" />
|
||||||
|
<Badge color="blue" radius="sm" size="md" variant="filled">
|
||||||
|
<Box className="center-flex">
|
||||||
|
TO {service.ip_dst} :
|
||||||
|
<form onSubmit={form.onSubmit((v)=>portInputRef.current?.blur())}>
|
||||||
|
<PortInput
|
||||||
|
defaultValue={service.proxy_port}
|
||||||
|
size="xs"
|
||||||
|
variant="unstyled"
|
||||||
|
style={{
|
||||||
|
width: (10+form.values.proxy_port.toString().length*6.2) +"px"
|
||||||
|
}}
|
||||||
|
className="firegex__porthijack__servicerow__portInput"
|
||||||
|
onBlur={(e)=>{onChangeProxyPort({proxy_port:parseInt(e.target.value)})}}
|
||||||
|
ref={portInputRef}
|
||||||
|
{...form.getInputProps("proxy_port")}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</Box>
|
||||||
|
</Badge>
|
||||||
|
</Box>
|
||||||
|
{isMedium?<Box className='flex-spacer' />:<Space h="xl" />}
|
||||||
|
<Box className="center-flex">
|
||||||
|
<MenuDropDownWithButton>
|
||||||
|
<Menu.Label><b>Rename service</b></Menu.Label>
|
||||||
|
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
||||||
|
<Menu.Label><b>Change destination</b></Menu.Label>
|
||||||
|
<Menu.Item leftSection={<BsArrowRepeat size={18} />} onClick={()=>setChangeDestModal(true)}>Change hijacking destination</Menu.Item>
|
||||||
|
<Divider />
|
||||||
|
<Menu.Label><b>Danger zone</b></Menu.Label>
|
||||||
|
<Menu.Item color="red" leftSection={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
|
||||||
|
</MenuDropDownWithButton>
|
||||||
|
<Space w="md"/>
|
||||||
|
<Tooltip label="Stop service" zIndex={0} color="red" opened={tooltipStopOpened}>
|
||||||
|
<ActionIcon color="red" loading={buttonLoading}
|
||||||
|
onClick={stopService} size="xl" radius="md" variant="filled"
|
||||||
|
disabled={!service.active}
|
||||||
|
aria-describedby="tooltip-stop-id"
|
||||||
|
onFocus={() => setTooltipStopOpened(false)} onBlur={() => setTooltipStopOpened(false)}
|
||||||
|
onMouseEnter={() => setTooltipStopOpened(true)} onMouseLeave={() => setTooltipStopOpened(false)}>
|
||||||
|
<FaStop size="20px" />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
<Space w="md"/>
|
||||||
|
<Tooltip label="Start service" zIndex={0} color="teal">
|
||||||
|
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
|
||||||
|
variant="filled" disabled={service.active}>
|
||||||
|
<FaPlay size="20px" />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
</Box>
|
||||||
|
{isMedium?<Space w="xl" />:null}
|
||||||
|
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
<YesNoModal
|
<YesNoModal
|
||||||
title='Are you sure to delete this service?'
|
title='Are you sure to delete this service?'
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void })
|
|||||||
{...form.getInputProps('chosenInternalPort', { type: 'checkbox' })}
|
{...form.getInputProps('chosenInternalPort', { type: 'checkbox' })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Add Service</Button>
|
<Button loading={submitLoading} type="submit">Add Service</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ function ChangePortModal({ service, opened, onClose }:{ service:Service, opened:
|
|||||||
|
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
|
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} disabled={
|
<Button loading={submitLoading} disabled={
|
||||||
service.internal_port === form.values.internalPort && service.public_port === form.values.port
|
service.internal_port === form.values.internalPort && service.public_port === form.values.port
|
||||||
} type="submit">Change Port</Button>
|
} type="submit">Change Port</Button>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v
|
|||||||
placeholder="Awesome Service Name!"
|
placeholder="Awesome Service Name!"
|
||||||
{...form.getInputProps('name')}
|
{...form.getInputProps('name')}
|
||||||
/>
|
/>
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} type="submit">Rename</Button>
|
<Button loading={submitLoading} type="submit">Rename</Button>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
|
|
||||||
@use "../../../index.scss" as *;
|
|
||||||
|
|
||||||
.row{
|
|
||||||
width: 95%;
|
|
||||||
padding: 30px 0px;
|
|
||||||
border-radius: 20px;
|
|
||||||
margin: 10px;
|
|
||||||
@extend .center-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name{
|
|
||||||
font-size: 2.3em;
|
|
||||||
font-weight: bolder;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-bottom: 13px;
|
|
||||||
color:#FFF;
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ActionIcon, Badge, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Badge, Box, Divider, Grid, Menu, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { FaPause, FaPlay, FaStop } from 'react-icons/fa';
|
import { FaPause, FaPlay, FaStop } from 'react-icons/fa';
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md"
|
import { MdOutlineArrowForwardIos } from "react-icons/md"
|
||||||
import style from "./ServiceRow.module.scss";
|
|
||||||
import YesNoModal from '../../YesNoModal';
|
import YesNoModal from '../../YesNoModal';
|
||||||
import { errorNotify, isMediumScreen, okNotify } from '../../../js/utils';
|
import { errorNotify, isMediumScreen, okNotify } from '../../../js/utils';
|
||||||
import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs';
|
import { BsArrowRepeat, BsTrashFill } from 'react-icons/bs';
|
||||||
@@ -101,34 +100,34 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Grid className={style.row} justify="flex-end" style={{width:"100%"}}>
|
<Grid className="firegex__servicerow__row" justify="flex-end" style={{width:"100%"}}>
|
||||||
<Grid.Col md={4} xs={12}>
|
<Grid.Col span={{ md:4, xs: 12 }}>
|
||||||
<div className={isMedium?"center-flex-row":"center-flex"}>
|
<Box className={isMedium?"center-flex-row":"center-flex"}>
|
||||||
<div className="center-flex"><Title className={style.name}>{service.name}</Title> <Badge size="xl" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient">:{service.public_port}</Badge></div>
|
<Box className="center-flex"><Title className="firegex__servicerow__name">{service.name}</Title> <Badge size="xl" gradient={{ from: 'indigo', to: 'cyan' }} variant="gradient">:{service.public_port}</Badge></Box>
|
||||||
<Badge color={status_color} size="lg" radius="md">{service.internal_port} {"->"} {service.public_port}</Badge>
|
<Badge color={status_color} size="lg" radius="md">{service.internal_port} {"->"} {service.public_port}</Badge>
|
||||||
</div>
|
</Box>
|
||||||
{!isMedium?<Space h="xl" />:null}
|
{!isMedium?<Space h="xl" />:null}
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|
||||||
<Grid.Col className="center-flex" md={8} xs={12}>
|
<Grid.Col className="center-flex" span={{ md:8, xs: 12 }}>
|
||||||
{!isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
|
{!isMedium?<Box className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
|
||||||
<div className="center-flex-row">
|
<Box className="center-flex-row">
|
||||||
<Badge style={{marginBottom:"20px"}} color={status_color} radius="sm" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
|
<Badge style={{marginBottom:"20px"}} color={status_color} radius="sm" size="lg" variant="filled">Status: <u>{service.status}</u></Badge>
|
||||||
<Badge style={{marginBottom:"8px"}}color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
|
<Badge style={{marginBottom:"8px"}}color="violet" radius="sm" size="md" variant="filled">Regex: {service.n_regex}</Badge>
|
||||||
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
|
<Badge color="yellow" radius="sm" size="md" variant="filled">Connections Blocked: {service.n_packets}</Badge>
|
||||||
</div>
|
</Box>
|
||||||
{isMedium?<div className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
|
{isMedium?<Box className='flex-spacer' />:<><Space w="xl" /><Space w="xl" /></>}
|
||||||
<div className="center-flex">
|
<Box className="center-flex">
|
||||||
<MenuDropDownWithButton>
|
<MenuDropDownWithButton>
|
||||||
<Menu.Label><b>Rename service</b></Menu.Label>
|
<Menu.Label><b>Rename service</b></Menu.Label>
|
||||||
<Menu.Item icon={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
<Menu.Item leftSection={<BiRename size={18} />} onClick={()=>setRenameModal(true)}>Change service name</Menu.Item>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Menu.Label><b>Change ports</b></Menu.Label>
|
<Menu.Label><b>Change ports</b></Menu.Label>
|
||||||
<Menu.Item icon={<TbNumbers size={18} />} onClick={()=>setChoosePortModal(true)}>Change port</Menu.Item>
|
<Menu.Item leftSection={<TbNumbers size={18} />} onClick={()=>setChoosePortModal(true)}>Change port</Menu.Item>
|
||||||
<Menu.Item icon={<BsArrowRepeat size={18} />} onClick={()=>setChangePortModal(true)}>Regen proxy port</Menu.Item>
|
<Menu.Item leftSection={<BsArrowRepeat size={18} />} onClick={()=>setChangePortModal(true)}>Regen proxy port</Menu.Item>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Menu.Label><b>Danger zone</b></Menu.Label>
|
<Menu.Label><b>Danger zone</b></Menu.Label>
|
||||||
<Menu.Item color="red" icon={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
|
<Menu.Item color="red" leftSection={<BsTrashFill size={18} />} onClick={()=>setDeleteModal(true)}>Delete Service</Menu.Item>
|
||||||
</MenuDropDownWithButton>
|
</MenuDropDownWithButton>
|
||||||
<Space w="md"/>
|
<Space w="md"/>
|
||||||
{["pause","wait"].includes(service.status)?
|
{["pause","wait"].includes(service.status)?
|
||||||
@@ -158,12 +157,12 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void })
|
|||||||
<FaPlay size="20px" />
|
<FaPlay size="20px" />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
<Space w="xl" /><Space w="xl" />
|
<Space w="xl" /><Space w="xl" />
|
||||||
{onClick?<div>
|
{onClick?<Box>
|
||||||
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={45} />
|
<MdOutlineArrowForwardIos onClick={onClick} style={{cursor:"pointer"}} size={45} />
|
||||||
<Space w="xl" />
|
<Space w="xl" />
|
||||||
</div>:null}
|
</Box>:null}
|
||||||
{!isMedium?<><Space w="xl" /><Space w="xl" /></>:null}
|
{!isMedium?<><Space w="xl" /><Space w="xl" /></>:null}
|
||||||
|
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
@use "../../vars" as *;
|
|
||||||
|
|
||||||
.box{
|
|
||||||
padding:30px;
|
|
||||||
margin:5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.outer_regex_text{
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.regex_text{
|
|
||||||
padding: 10px;
|
|
||||||
background-color: $third_color;
|
|
||||||
overflow-x: hidden;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.regex_text:hover{
|
|
||||||
overflow-x: auto;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ import { Grid, Text, Title, Badge, Space, ActionIcon, Tooltip, Box } from '@mant
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { RegexFilter } from '../../js/models';
|
import { RegexFilter } from '../../js/models';
|
||||||
import { b64decode, errorNotify, getapiobject, okNotify } from '../../js/utils';
|
import { b64decode, errorNotify, getapiobject, okNotify } from '../../js/utils';
|
||||||
import style from "./index.module.scss";
|
|
||||||
import { BsTrashFill } from "react-icons/bs"
|
import { BsTrashFill } from "react-icons/bs"
|
||||||
import YesNoModal from '../YesNoModal';
|
import YesNoModal from '../YesNoModal';
|
||||||
import FilterTypeSelector from '../FilterTypeSelector';
|
import FilterTypeSelector from '../FilterTypeSelector';
|
||||||
@@ -43,14 +42,14 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
|
|||||||
}).catch( err => errorNotify(`Regex ${regex_expr} ${regexInfo.active?"deactivation":"activation"} failed!`,`Error: ${err}`))
|
}).catch( err => errorNotify(`Regex ${regex_expr} ${regexInfo.active?"deactivation":"activation"} failed!`,`Error: ${err}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className={style.box}>
|
return <Box className="firegex__regexview__box">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Col span={2} className="center-flex">
|
<Grid.Col span={2} className="center-flex">
|
||||||
<Title order={4}>Regex:</Title>
|
<Title order={4}>Regex:</Title>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={8}>
|
<Grid.Col span={8}>
|
||||||
<Box className={style.outer_regex_text}>
|
<Box className="firegex__regexview__outer_regex_text">
|
||||||
<Text className={style.regex_text} onClick={()=>{
|
<Text className="firegex__regexview__regex_text" onClick={()=>{
|
||||||
clipboard.copy(regex_expr)
|
clipboard.copy(regex_expr)
|
||||||
okNotify("Regex copied to clipboard!",`The regex '${regex_expr}' has been copied to the clipboard!`)
|
okNotify("Regex copied to clipboard!",`The regex '${regex_expr}' has been copied to the clipboard!`)
|
||||||
}}>{regex_expr}</Text>
|
}}>{regex_expr}</Text>
|
||||||
@@ -74,7 +73,7 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
|
|||||||
|
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col className='center-flex' span={12}>
|
<Grid.Col className='center-flex' span={12}>
|
||||||
<div className='center-flex-row'>
|
<Box className='center-flex-row'>
|
||||||
<FilterTypeSelector
|
<FilterTypeSelector
|
||||||
size="md"
|
size="md"
|
||||||
color="gray"
|
color="gray"
|
||||||
@@ -82,23 +81,23 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
|
|||||||
value={regexInfo.is_blacklist?"blacklist":"whitelist"}
|
value={regexInfo.is_blacklist?"blacklist":"whitelist"}
|
||||||
/>
|
/>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Badge size="md" color="cyan" variant="filled">Service: {regexInfo.service_id}</Badge>
|
<Badge size="md" color="cyan" variant="filled">Service: {regexInfo.service_id}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Badge size="md" color={regexInfo.active?"lime":"red"} variant="filled">{regexInfo.active?"ACTIVE":"DISABLED"}</Badge>
|
<Badge size="md" color={regexInfo.active?"lime":"red"} variant="filled">{regexInfo.active?"ACTIVE":"DISABLED"}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Badge size="md" color="gray" variant="filled">ID: {regexInfo.id}</Badge>
|
<Badge size="md" color="gray" variant="filled">ID: {regexInfo.id}</Badge>
|
||||||
|
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
<div className='flex-spacer' />
|
<Box className='flex-spacer' />
|
||||||
<div className='center-flex-row'>
|
<Box className='center-flex-row'>
|
||||||
<Badge size="md" color={regexInfo.is_case_sensitive?"grape":"pink"} variant="filled">Case: {regexInfo.is_case_sensitive?"SENSIIVE":"INSENSITIVE"}</Badge>
|
<Badge size="md" color={regexInfo.is_case_sensitive?"grape":"pink"} variant="filled">Case: {regexInfo.is_case_sensitive?"SENSIIVE":"INSENSITIVE"}</Badge>
|
||||||
<Space h="xs" />
|
<Space h="xs" />
|
||||||
<Badge size="md" color="yellow" variant="filled">Packets filtered: {regexInfo.n_packets}</Badge>
|
<Badge size="md" color="yellow" variant="filled">Packets filtered: {regexInfo.n_packets}</Badge>
|
||||||
<Space h="xs" />
|
<Space h="xs" />
|
||||||
<Badge size="md" color="blue" variant="filled">Mode: {mode_string}</Badge>
|
<Badge size="md" color="blue" variant="filled">Mode: {mode_string}</Badge>
|
||||||
</div>
|
</Box>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
<YesNoModal
|
<YesNoModal
|
||||||
@@ -109,7 +108,7 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
|
|||||||
opened={deleteModal}
|
opened={deleteModal}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</Box>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RegexView;
|
export default RegexView;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ function YesNoModal( { title, description, action, onClose, opened}:{ title:stri
|
|||||||
|
|
||||||
return <Modal size="xl" title={title} opened={opened} onClose={onClose} centered>
|
return <Modal size="xl" title={title} opened={opened} onClose={onClose} centered>
|
||||||
{description}
|
{description}
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button onClick={()=>{
|
<Button onClick={()=>{
|
||||||
onClose()
|
onClose()
|
||||||
action()
|
action()
|
||||||
|
|||||||
213
frontend/src/index.css
Normal file
213
frontend/src/index.css
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Lato&display=swap');
|
||||||
|
|
||||||
|
:root{
|
||||||
|
--primary_color: #242a33;
|
||||||
|
--secondary_color: #1A1B1E;
|
||||||
|
--third_color:#25262b;
|
||||||
|
--fourth_color: #25262b99;
|
||||||
|
--mantine-color-body: var(--secondary_color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Lato', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-flex{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-flex-row{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-spacer{
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
margin:3px;
|
||||||
|
background: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #757575;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mantine-Modal-content {
|
||||||
|
overflow-y: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__header__header{
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--primary_color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__header__divlogo{
|
||||||
|
width: 65px;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__header__navbtn{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 30px;
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__regexview__box{
|
||||||
|
padding:30px;
|
||||||
|
margin:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__regexview__outer_regex_text{
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__regexview__regex_text{
|
||||||
|
padding: 10px;
|
||||||
|
background-color: var(--third_color);
|
||||||
|
overflow-x: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__regexview__regex_text:hover{
|
||||||
|
overflow-x: auto;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__porthijack__servicerow__row{
|
||||||
|
width: 95%;
|
||||||
|
padding: 15px 0px;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__porthijack__servicerow__row-mobile{
|
||||||
|
width: 95%;
|
||||||
|
padding: 15px 0px;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__porthijack__servicerow__name{
|
||||||
|
font-size: 1.8em;
|
||||||
|
font-weight: bolder;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 13px;
|
||||||
|
color:#FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__porthijack__servicerow__portInput *{
|
||||||
|
color: #FFF;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1em;
|
||||||
|
margin-top: -1px;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.firegex__nfregex__row{
|
||||||
|
width: 95%;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__nfregex__name{
|
||||||
|
font-size: 1.8em;
|
||||||
|
font-weight: bolder;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 13px;
|
||||||
|
color:#FFF;
|
||||||
|
max-width: 300px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__nfregex__name:hover{
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__navbar__unstyled_button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--mantine-spacing-xs);
|
||||||
|
border-radius: var(--mantine-radius-sm);
|
||||||
|
color: var(--mantine-color-dark-0);
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__navbar__unstyled_button.disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__navbar__unstyled_button.selected{
|
||||||
|
background-color: var(--mantine-color-dark-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__navbar__unstyled_button:hover {
|
||||||
|
background-color: var(--mantine-color-dark-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__footer{
|
||||||
|
margin-top: 50px;
|
||||||
|
background-color: var(--primary_color);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__servicerow__row{
|
||||||
|
width: 95%;
|
||||||
|
padding: 30px 0px;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__servicerow__name{
|
||||||
|
font-size: 1.8em;
|
||||||
|
font-weight: bolder;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 13px;
|
||||||
|
color:#FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.firegex__nfregex__rowbox{
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--fourth_color);
|
||||||
|
border-radius: 20px;
|
||||||
|
border: #444 3px solid;
|
||||||
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
|
|
||||||
@use "vars" as *;
|
|
||||||
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Lato&display=swap');
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: 'Lato', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-flex{
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-flex-row{
|
|
||||||
@extend .center-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-spacer{
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
margin:3px;
|
|
||||||
background: #333;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: #757575;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mantine-Modal-content {
|
|
||||||
overflow-y: visible;
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import { BrowserRouter } from "react-router-dom"
|
import { BrowserRouter } from "react-router-dom"
|
||||||
import './index.scss';
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import { MantineProvider } from '@mantine/core';
|
import { createTheme, MantineProvider } from '@mantine/core';
|
||||||
import { Notifications } from '@mantine/notifications';
|
import { Notifications } from '@mantine/notifications';
|
||||||
import {
|
import {
|
||||||
QueryClientProvider,
|
QueryClientProvider,
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
import { queryClient } from './js/utils';
|
import { queryClient } from './js/utils';
|
||||||
|
import '@mantine/core/styles.css';
|
||||||
|
import '@mantine/notifications/styles.css';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById('root') as HTMLElement
|
document.getElementById('root') as HTMLElement
|
||||||
@@ -16,10 +17,10 @@ const root = ReactDOM.createRoot(
|
|||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<MantineProvider theme={{ colorScheme: 'dark' }} withGlobalStyles withNormalizeCSS>
|
<MantineProvider defaultColorScheme='dark'>
|
||||||
<Notifications />
|
<Notifications />
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<App />
|
<App />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</MantineProvider>
|
</MantineProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
|||||||
17
frontend/src/js/store.ts
Normal file
17
frontend/src/js/store.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { create } from 'zustand'
|
||||||
|
|
||||||
|
type NavbarStore = {
|
||||||
|
navOpened: boolean,
|
||||||
|
setOpenNav: (opened: boolean) => void,
|
||||||
|
closeNav: () => void,
|
||||||
|
openNav: () => void,
|
||||||
|
toggleNav: () => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNavbarStore = create<NavbarStore>()((set) => ({
|
||||||
|
navOpened: false,
|
||||||
|
setOpenNav: (opened: boolean) => set({ navOpened: opened }),
|
||||||
|
closeNav: () => set({ navOpened: false }),
|
||||||
|
openNav: () => set({ navOpened: true }),
|
||||||
|
toggleNav: () => set((state) => ({ navOpened: !state.navOpened })),
|
||||||
|
}))
|
||||||
@@ -101,14 +101,14 @@ export async function postapi(path:string,data:any,is_form:boolean=false):Promis
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getmainpath(){
|
export function getMainPath(){
|
||||||
const paths = window.location.pathname.split("/")
|
const paths = window.location.pathname.split("/")
|
||||||
if (paths.length > 1) return paths[1]
|
if (paths.length > 1) return paths[1]
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getapiobject(){
|
export function getapiobject(){
|
||||||
switch(getmainpath()){
|
switch(getMainPath()){
|
||||||
case "nfregex":
|
case "nfregex":
|
||||||
return nfregex
|
return nfregex
|
||||||
case "regexproxy":
|
case "regexproxy":
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function SettingsModal({ opened, onClose }:{ opened:boolean, onClose:()=>
|
|||||||
<Switch label="Drop invalid packet" checked={settings.drop_invalid} onChange={v => setSettings({...settings, drop_invalid:v.target.checked})}/>
|
<Switch label="Drop invalid packet" checked={settings.drop_invalid} onChange={v => setSettings({...settings, drop_invalid:v.target.checked})}/>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Switch label="Allow DHCP" checked={settings.allow_dhcp} onChange={v => setSettings({...settings, allow_dhcp:v.target.checked})}/>
|
<Switch label="Allow DHCP" checked={settings.allow_dhcp} onChange={v => setSettings({...settings, allow_dhcp:v.target.checked})}/>
|
||||||
<Group position="right" mt="md">
|
<Group align="right" mt="md">
|
||||||
<Button loading={submitLoading} onClick={submitRequest}>Save Setting</Button>
|
<Button loading={submitLoading} onClick={submitRequest}>Save Setting</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ActionIcon, Badge, Button, Divider, LoadingOverlay, Space, Switch, TextInput, Title, Tooltip, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, Badge, Box, Button, Divider, LoadingOverlay, Space, Switch, TextInput, Title, Tooltip, useMantineTheme } from "@mantine/core"
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { BsPlusLg, BsTrashFill } from "react-icons/bs"
|
import { BsPlusLg, BsTrashFill } from "react-icons/bs"
|
||||||
import { rem } from '@mantine/core';
|
import { rem } from '@mantine/core';
|
||||||
@@ -37,8 +37,8 @@ export const Firewall = () => {
|
|||||||
const [applyChangeModal, setApplyChangeModal] = useState(false)
|
const [applyChangeModal, setApplyChangeModal] = useState(false)
|
||||||
const [settingsModal, setSettingsModal] = useState(false)
|
const [settingsModal, setSettingsModal] = useState(false)
|
||||||
const theme = useMantineTheme();
|
const theme = useMantineTheme();
|
||||||
const isMedium = useMediaQuery(`(min-width: 950px)`)
|
const isMedium = useMediaQuery(`(min-width: 950px)`)??true
|
||||||
const isSmall = useMediaQuery(`(max-width: 600px)`)
|
const isSmall = useMediaQuery(`(max-width: 600px)`)??false
|
||||||
|
|
||||||
const [updateMevalueinternal, internalUpdateme] = useState(false)
|
const [updateMevalueinternal, internalUpdateme] = useState(false)
|
||||||
const updateMe = () => {
|
const updateMe = () => {
|
||||||
@@ -104,7 +104,7 @@ export const Firewall = () => {
|
|||||||
|
|
||||||
const condDiv = (val:React.ReactNode, cond:boolean) => {
|
const condDiv = (val:React.ReactNode, cond:boolean) => {
|
||||||
if (cond)
|
if (cond)
|
||||||
return <div>{val}</div>
|
return <Box>{val}</Box>
|
||||||
else
|
else
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
@@ -201,18 +201,18 @@ export const Firewall = () => {
|
|||||||
dst_port: disabletab.dst_port?disable_style:{}
|
dst_port: disabletab.dst_port?disable_style:{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div
|
return <Box
|
||||||
ref={provided.innerRef}
|
ref={provided.innerRef}
|
||||||
{...provided.draggableProps}
|
{...provided.draggableProps}
|
||||||
>
|
>
|
||||||
<div className='center-flex' style={{width:"100%"}}>
|
<Box className='center-flex' style={{width:"100%"}}>
|
||||||
<div {...provided.dragHandleProps}>
|
<Box {...provided.dragHandleProps}>
|
||||||
<TbGripVertical style={{ width: rem(30), height: rem(40) }} />
|
<TbGripVertical style={{ width: rem(30), height: rem(40) }} />
|
||||||
</div>
|
</Box>
|
||||||
<Space w="sm" />
|
<Space w="sm" />
|
||||||
<div className={isMedium?"center-flex":"center-flex-row"} style={{width:"100%"}}>
|
<Box className={isMedium?"center-flex":"center-flex-row"} style={{width:"100%"}}>
|
||||||
<div className="center-flex-row" style={{width:"100%"}}>
|
<Box className="center-flex-row" style={{width:"100%"}}>
|
||||||
<div className="center-flex" style={{width:"97%"}}>
|
<Box className="center-flex" style={{width:"97%"}}>
|
||||||
<Switch
|
<Switch
|
||||||
checked={item.active}
|
checked={item.active}
|
||||||
onChange={() =>{
|
onChange={() =>{
|
||||||
@@ -239,10 +239,10 @@ export const Firewall = () => {
|
|||||||
<ActionIcon color="red" onClick={()=>handlers.remove(index)} size="lg" radius="md" variant="filled"><BsTrashFill size={18} /></ActionIcon>
|
<ActionIcon color="red" onClick={()=>handlers.remove(index)} size="lg" radius="md" variant="filled"><BsTrashFill size={18} /></ActionIcon>
|
||||||
<Space w="sm" />
|
<Space w="sm" />
|
||||||
<TextInput defaultValue={item.name} onChange={(v)=>{item.name = v.target.value;updateMe()}} style={{width:"100%"}}/>
|
<TextInput defaultValue={item.name} onChange={(v)=>{item.name = v.target.value;updateMe()}} style={{width:"100%"}}/>
|
||||||
</div>
|
</Box>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<div className="center-flex" style={{width:"97%"}}>
|
<Box className="center-flex" style={{width:"97%"}}>
|
||||||
<div style={{width:"100%"}}>
|
<Box style={{width:"100%"}}>
|
||||||
<InterfaceInput
|
<InterfaceInput
|
||||||
initialCustomInterfaces={[...src_custom_int, ...customInt]}
|
initialCustomInterfaces={[...src_custom_int, ...customInt]}
|
||||||
value={item.src}
|
value={item.src}
|
||||||
@@ -250,7 +250,7 @@ export const Firewall = () => {
|
|||||||
includeInterfaceNames
|
includeInterfaceNames
|
||||||
/>
|
/>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<div className="center-flex" style={{width:"100%"}}>
|
<Box className="center-flex" style={{width:"100%"}}>
|
||||||
<OnOffButton value={srcPortEnabled} onClick={() =>{
|
<OnOffButton value={srcPortEnabled} onClick={() =>{
|
||||||
const value = !srcPortEnabled
|
const value = !srcPortEnabled
|
||||||
setSrcPortEnabled(value)
|
setSrcPortEnabled(value)
|
||||||
@@ -270,12 +270,12 @@ export const Firewall = () => {
|
|||||||
error={!disabletab.src_port && !srcPortValue}
|
error={!disabletab.src_port && !srcPortValue}
|
||||||
style={{width:"100%", ...additionalStyle.src_port}}
|
style={{width:"100%", ...additionalStyle.src_port}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
<Space w="lg" />
|
<Space w="lg" />
|
||||||
<LuArrowBigRightDash size={100} />
|
<LuArrowBigRightDash size={100} />
|
||||||
<Space w="lg" />
|
<Space w="lg" />
|
||||||
<div style={{width:"100%"}}>
|
<Box style={{width:"100%"}}>
|
||||||
<InterfaceInput
|
<InterfaceInput
|
||||||
initialCustomInterfaces={[...dst_custom_int, ...customInt]}
|
initialCustomInterfaces={[...dst_custom_int, ...customInt]}
|
||||||
defaultValue={item.dst}
|
defaultValue={item.dst}
|
||||||
@@ -283,7 +283,7 @@ export const Firewall = () => {
|
|||||||
includeInterfaceNames
|
includeInterfaceNames
|
||||||
/>
|
/>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<div className="center-flex" style={{width:"100%"}}>
|
<Box className="center-flex" style={{width:"100%"}}>
|
||||||
<OnOffButton value={dstPortEnabled} onClick={() =>{
|
<OnOffButton value={dstPortEnabled} onClick={() =>{
|
||||||
const value = !dstPortEnabled
|
const value = !dstPortEnabled
|
||||||
setDstPortEnabled(value)
|
setDstPortEnabled(value)
|
||||||
@@ -303,12 +303,12 @@ export const Firewall = () => {
|
|||||||
error={!disabletab.dst_port && !dstPortValue}
|
error={!disabletab.dst_port && !dstPortValue}
|
||||||
style={{width:"100%", ...additionalStyle.dst_port}}
|
style={{width:"100%", ...additionalStyle.dst_port}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
{!isMedium?<Space h="sm" />:null}
|
{!isMedium?<Space h="sm" />:null}
|
||||||
<div className={isMedium?"center-flex-row":"center-flex"} style={isMedium?{}:{width:"100%", justifyContent:"space-around"}}>
|
<Box className={isMedium?"center-flex-row":"center-flex"} style={isMedium?{}:{width:"100%", justifyContent:"space-around"}}>
|
||||||
{condDiv(<>{condDiv(<ModeSelector
|
{condDiv(<>{condDiv(<ModeSelector
|
||||||
value={item.mode}
|
value={item.mode}
|
||||||
onChange={(value)=>{item.mode = value as RuleMode;updateMe()}}
|
onChange={(value)=>{item.mode = value as RuleMode;updateMe()}}
|
||||||
@@ -326,13 +326,13 @@ export const Firewall = () => {
|
|||||||
onChange={(value)=>{item.action = value as ActionType;updateMe()}}
|
onChange={(value)=>{item.action = value as ActionType;updateMe()}}
|
||||||
style={{width:"100%"}}
|
style={{width:"100%"}}
|
||||||
/>, !isMedium)}
|
/>, !isMedium)}
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Divider />
|
<Divider />
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
</div>
|
</Box>
|
||||||
}}
|
}}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
));
|
));
|
||||||
@@ -341,10 +341,10 @@ export const Firewall = () => {
|
|||||||
return <>
|
return <>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<LoadingOverlay visible={rules.isLoading} />
|
<LoadingOverlay visible={rules.isLoading} />
|
||||||
<div className={isMedium?'center-flex':'center-flex-row'}>
|
<Box className={isMedium?'center-flex':'center-flex-row'}>
|
||||||
<Title order={3}>Firewall Rules</Title>
|
<Title order={3}>Firewall Rules</Title>
|
||||||
{isMedium?<div className='flex-spacer' />:<Space h="sm" />}
|
{isMedium?<Box className='flex-spacer' />:<Space h="sm" />}
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
Enabled: <Space w="sm" /> <Switch checked={fwEnabled} onChange={switchState} />
|
Enabled: <Space w="sm" /> <Switch checked={fwEnabled} onChange={switchState} />
|
||||||
<Space w="sm" />
|
<Space w="sm" />
|
||||||
Policy:
|
Policy:
|
||||||
@@ -353,9 +353,9 @@ export const Firewall = () => {
|
|||||||
value={currentPolicy}
|
value={currentPolicy}
|
||||||
onChange={(value)=>setCurrentPolicy(value as ActionType)}
|
onChange={(value)=>setCurrentPolicy(value as ActionType)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Box>
|
||||||
{isMedium?<div className='flex-spacer' />:<Space h="sm" />}
|
{isMedium?<Box className='flex-spacer' />:<Space h="sm" />}
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Badge size="sm" color="green" variant="filled">Rules: {rules.isLoading?0:rules.data?.rules.length}</Badge>
|
<Badge size="sm" color="green" variant="filled">Rules: {rules.isLoading?0:rules.data?.rules.length}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
@@ -385,8 +385,8 @@ export const Firewall = () => {
|
|||||||
disabled={!valuesChanged}
|
disabled={!valuesChanged}
|
||||||
><TiTick size={22} /></ActionIcon>
|
><TiTick size={22} /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<Divider />
|
<Divider />
|
||||||
{items.length > 0?<DragDropContext
|
{items.length > 0?<DragDropContext
|
||||||
@@ -397,22 +397,22 @@ export const Firewall = () => {
|
|||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Droppable droppableId="dnd-list" direction="vertical">
|
<Droppable droppableId="dnd-list" direction="vertical">
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
<Box {...provided.droppableProps} ref={provided.innerRef}>
|
||||||
{items}
|
{items}
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
</div>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>:<>
|
</DragDropContext>:<>
|
||||||
<Space h="xl"/> <Title className='center-flex' align='center' order={3}>No rule found! Add one clicking the "+" buttons</Title>
|
<Space h="xl"/> <Title className='center-flex' style={{textAlign:"center"}} order={3}>No rule found! Add one clicking the "+" buttons</Title>
|
||||||
<Space h="xl" /> <Space h="xl" />
|
<Space h="xl" /> <Space h="xl" />
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Tooltip label="Add a new rule" color="blue" opened={tooltipAddRulOpened}>
|
<Tooltip label="Add a new rule" color="blue" opened={tooltipAddRulOpened}>
|
||||||
<ActionIcon color="blue" onClick={emptyRuleAdd} size="xl" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={emptyRuleAdd} size="xl" radius="md" variant="filled"
|
||||||
onFocus={() => setTooltipAddRulOpened(false)} onBlur={() => setTooltipAddRulOpened(false)}
|
onFocus={() => setTooltipAddRulOpened(false)} onBlur={() => setTooltipAddRulOpened(false)}
|
||||||
onMouseEnter={() => setTooltipAddRulOpened(true)} onMouseLeave={() => setTooltipAddRulOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
onMouseEnter={() => setTooltipAddRulOpened(true)} onMouseLeave={() => setTooltipAddRulOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</>}
|
</>}
|
||||||
|
|
||||||
<YesNoModal
|
<YesNoModal
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ActionIcon, Grid, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Box, Grid, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Navigate, useParams } from 'react-router-dom';
|
import { Navigate, useParams } from 'react-router-dom';
|
||||||
import RegexView from '../../components/RegexView';
|
import RegexView from '../../components/RegexView';
|
||||||
@@ -23,19 +23,19 @@ function ServiceDetailsNFRegex() {
|
|||||||
<ServiceRow service={serviceInfo} />
|
<ServiceRow service={serviceInfo} />
|
||||||
{(!regexesList.data || regexesList.data.length == 0)?<>
|
{(!regexesList.data || regexesList.data.length == 0)?<>
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<Title className='center-flex' align='center' order={3}>No regex found for this service! Add one by clicking the "+" buttons</Title>
|
<Title className='center-flex' style={{textAlign:"center"}} order={3}>No regex found for this service! Add one by clicking the "+" buttons</Title>
|
||||||
<Space h="xl" /> <Space h="xl" />
|
<Space h="xl" /> <Space h="xl" />
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Tooltip label="Add a new regex" zIndex={0} color="blue" opened={tooltipAddRegexOpened}>
|
<Tooltip label="Add a new regex" zIndex={0} color="blue" opened={tooltipAddRegexOpened}>
|
||||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
||||||
aria-describedby="tooltip-AddRegex-id"
|
aria-describedby="tooltip-AddRegex-id"
|
||||||
onFocus={() => setTooltipAddRegexOpened(false)} onBlur={() => setTooltipAddRegexOpened(false)}
|
onFocus={() => setTooltipAddRegexOpened(false)} onBlur={() => setTooltipAddRegexOpened(false)}
|
||||||
onMouseEnter={() => setTooltipAddRegexOpened(true)} onMouseLeave={() => setTooltipAddRegexOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
onMouseEnter={() => setTooltipAddRegexOpened(true)} onMouseLeave={() => setTooltipAddRegexOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</>:
|
</>:
|
||||||
<Grid>
|
<Grid>
|
||||||
{regexesList.data?.map( (regexInfo) => <Grid.Col key={regexInfo.id} lg={6} xs={12}><RegexView regexInfo={regexInfo} /></Grid.Col>)}
|
{regexesList.data?.map( (regexInfo) => <Grid.Col key={regexInfo.id} span={{ lg:6, xs: 12 }}><RegexView regexInfo={regexInfo} /></Grid.Col>)}
|
||||||
</Grid>
|
</Grid>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ActionIcon, Badge, Divider, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Badge, Box, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { BsPlusLg } from "react-icons/bs";
|
import { BsPlusLg } from "react-icons/bs";
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
@@ -32,19 +32,19 @@ function NFRegex({ children }: { children: any }) {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<div className={isMedium?'center-flex':'center-flex-row'}>
|
<Box className={isMedium?'center-flex':'center-flex-row'}>
|
||||||
<Title order={4}>Netfilter Regex</Title>
|
<Title order={4}>Netfilter Regex</Title>
|
||||||
{isMedium?<div className='flex-spacer' />:<Space h="sm" />}
|
{isMedium?<Box className='flex-spacer' />:<Space h="sm" />}
|
||||||
<div className='center-flex' >
|
<Box className='center-flex' >
|
||||||
<Badge size="sm" color="green" variant="filled">Services: {services.isLoading?0:services.data?.length}</Badge>
|
<Badge size="sm" color="green" variant="filled">Services: {services.isLoading?0:services.data?.length}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Badge size="sm" color="yellow" variant="filled">Filtered Connections: {services.isLoading?0:services.data?.reduce((acc, s)=> acc+=s.n_packets, 0)}</Badge>
|
<Badge size="sm" color="yellow" variant="filled">Filtered Connections: {services.isLoading?0:services.data?.reduce((acc, s)=> acc+=s.n_packets, 0)}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Badge size="sm" color="violet" variant="filled">Regexes: {services.isLoading?0:services.data?.reduce((acc, s)=> acc+=s.n_regex, 0)}</Badge>
|
<Badge size="sm" color="violet" variant="filled">Regexes: {services.isLoading?0:services.data?.reduce((acc, s)=> acc+=s.n_regex, 0)}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
</div>
|
</Box>
|
||||||
{isMedium?null:<Space h="md" />}
|
{isMedium?null:<Space h="md" />}
|
||||||
<div className='center-flex' >
|
<Box className='center-flex' >
|
||||||
{ srv?
|
{ srv?
|
||||||
<Tooltip label="Add a new regex" position='bottom' color="blue" opened={tooltipAddOpened}>
|
<Tooltip label="Add a new regex" position='bottom' color="blue" opened={tooltipAddOpened}>
|
||||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="lg" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="lg" radius="md" variant="filled"
|
||||||
@@ -64,28 +64,26 @@ function NFRegex({ children }: { children: any }) {
|
|||||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
<Space h="md" />
|
<Space h="md" />
|
||||||
<Divider size="md" style={{width:"100%"}}/>
|
<Box className="center-flex-row" style={{gap: 20}}>
|
||||||
<div id="service-list" className="center-flex-row">
|
|
||||||
{srv?null:<>
|
{srv?null:<>
|
||||||
<LoadingOverlay visible={services.isLoading} />
|
<LoadingOverlay visible={services.isLoading} />
|
||||||
{(services.data && services.data?.length > 0)?services.data.map( srv => <ServiceRow service={srv} key={srv.service_id} onClick={()=>{
|
{(services.data && services.data?.length > 0)?services.data.map( srv => <ServiceRow service={srv} key={srv.service_id} onClick={()=>{
|
||||||
navigator("/nfregex/"+srv.service_id)
|
navigator("/nfregex/"+srv.service_id)
|
||||||
}} />):<><Space h="xl"/> <Title className='center-flex' align='center' order={3}>No services found! Add one clicking the "+" buttons</Title>
|
}} />):<><Space h="xl"/> <Title className='center-flex' style={{textAlign:"center"}} order={3}>No services found! Add one clicking the "+" buttons</Title>
|
||||||
<Space h="xl" /> <Space h="xl" />
|
<Box className='center-flex'>
|
||||||
<div className='center-flex'>
|
|
||||||
<Tooltip label="Add a new service" color="blue" opened={tooltipAddServOpened}>
|
<Tooltip label="Add a new service" color="blue" opened={tooltipAddServOpened}>
|
||||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
||||||
onFocus={() => setTooltipAddServOpened(false)} onBlur={() => setTooltipAddServOpened(false)}
|
onFocus={() => setTooltipAddServOpened(false)} onBlur={() => setTooltipAddServOpened(false)}
|
||||||
onMouseEnter={() => setTooltipAddServOpened(true)} onMouseLeave={() => setTooltipAddServOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
onMouseEnter={() => setTooltipAddServOpened(true)} onMouseLeave={() => setTooltipAddServOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</>}
|
</>}
|
||||||
<AddNewService opened={open} onClose={closeModal} />
|
<AddNewService opened={open} onClose={closeModal} />
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</Box>
|
||||||
{srv?children:null}
|
{srv?children:null}
|
||||||
{srv?
|
{srv?
|
||||||
<AddNewRegex opened={open} onClose={closeModal} service={srv} />:
|
<AddNewRegex opened={open} onClose={closeModal} service={srv} />:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ActionIcon, Badge, Divider, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Badge, Box, Divider, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { BsPlusLg } from "react-icons/bs";
|
import { BsPlusLg } from "react-icons/bs";
|
||||||
import ServiceRow from '../../components/PortHijack/ServiceRow';
|
import ServiceRow from '../../components/PortHijack/ServiceRow';
|
||||||
@@ -29,10 +29,10 @@ function PortHijack() {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<div className={isMedium?'center-flex':'center-flex-row'}>
|
<Box className={isMedium?'center-flex':'center-flex-row'}>
|
||||||
<Title order={4}>Hijack port to proxy</Title>
|
<Title order={4}>Hijack port to proxy</Title>
|
||||||
{isMedium?<div className='flex-spacer' />:<Space h="sm" />}
|
{isMedium?<Box className='flex-spacer' />:<Space h="sm" />}
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Badge size="sm" color="yellow" variant="filled">Services: {services.isLoading?0:services.data?.length}</Badge>
|
<Badge size="sm" color="yellow" variant="filled">Services: {services.isLoading?0:services.data?.length}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Tooltip label="Add a new service" position='bottom' color="blue" opened={tooltipAddOpened}>
|
<Tooltip label="Add a new service" position='bottom' color="blue" opened={tooltipAddOpened}>
|
||||||
@@ -47,25 +47,23 @@ function PortHijack() {
|
|||||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
<Space h="md" /><Divider size="sm" style={{width:"100%"}}/>
|
<Space h="md" />
|
||||||
<div id="service-list" className="center-flex-row">
|
<Box className="center-flex-row" style={{gap: 20}}>
|
||||||
<LoadingOverlay visible={services.isLoading} />
|
<LoadingOverlay visible={services.isLoading} />
|
||||||
|
|
||||||
{(services.data && services.data.length > 0) ?services.data.map( srv => <ServiceRow service={srv} key={srv.service_id} />):<>
|
{(services.data && services.data.length > 0) ?services.data.map( srv => <ServiceRow service={srv} key={srv.service_id} />):<>
|
||||||
<Space h="xl"/> <Title className='center-flex' align='center' order={3}>No services found! Add one clicking the "+" buttons</Title>
|
<Space h="xl"/> <Title className='center-flex' style={{textAlign:"center"}} order={3}>No services found! Add one clicking the "+" buttons</Title>
|
||||||
<Space h="xl" /> <Space h="xl" />
|
<Box className='center-flex'>
|
||||||
<div className='center-flex'>
|
|
||||||
<Tooltip label="Add a new service" color="blue" opened={tooltipAddServOpened}>
|
<Tooltip label="Add a new service" color="blue" opened={tooltipAddServOpened}>
|
||||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
||||||
onFocus={() => setTooltipAddServOpened(false)} onBlur={() => setTooltipAddServOpened(false)}
|
onFocus={() => setTooltipAddServOpened(false)} onBlur={() => setTooltipAddServOpened(false)}
|
||||||
onMouseEnter={() => setTooltipAddServOpened(true)} onMouseLeave={() => setTooltipAddServOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
onMouseEnter={() => setTooltipAddServOpened(true)} onMouseLeave={() => setTooltipAddServOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</>}
|
</>}
|
||||||
<AddNewService opened={open} onClose={closeModal} />
|
<AddNewService opened={open} onClose={closeModal} />
|
||||||
</div>
|
</Box>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ActionIcon, Grid, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Box, Grid, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Navigate, useParams } from 'react-router-dom';
|
import { Navigate, useParams } from 'react-router-dom';
|
||||||
import { BsPlusLg } from "react-icons/bs";
|
import { BsPlusLg } from "react-icons/bs";
|
||||||
@@ -18,31 +18,31 @@ function ServiceDetailsProxyRegex() {
|
|||||||
|
|
||||||
if (!srv || !serviceInfo || regexesList.isError) return <Navigate to="/" replace />
|
if (!srv || !serviceInfo || regexesList.isError) return <Navigate to="/" replace />
|
||||||
|
|
||||||
return <div>
|
return <Box>
|
||||||
<LoadingOverlay visible={regexesList.isLoading} />
|
<LoadingOverlay visible={regexesList.isLoading} />
|
||||||
<ServiceRow service={serviceInfo} />
|
<ServiceRow service={serviceInfo} />
|
||||||
{(!regexesList.data || regexesList.data.length == 0)?<>
|
{(!regexesList.data || regexesList.data.length == 0)?<>
|
||||||
<Space h="xl" />
|
<Space h="xl" />
|
||||||
<Title className='center-flex' align='center' order={3}>No regex found for this service! Add one by clicking the "+" buttons</Title>
|
<Title className='center-flex' style={{textAlign:"center"}} order={3}>No regex found for this service! Add one by clicking the "+" buttons</Title>
|
||||||
<Space h="xl" /> <Space h="xl" />
|
<Space h="xl" /> <Space h="xl" />
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Tooltip label="Add a new regex" zIndex={0} color="blue" opened={tooltipAddRegexOpened}>
|
<Tooltip label="Add a new regex" zIndex={0} color="blue" opened={tooltipAddRegexOpened}>
|
||||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
||||||
aria-describedby="tooltip-AddRegex-id"
|
aria-describedby="tooltip-AddRegex-id"
|
||||||
onFocus={() => setTooltipAddRegexOpened(false)} onBlur={() => setTooltipAddRegexOpened(false)}
|
onFocus={() => setTooltipAddRegexOpened(false)} onBlur={() => setTooltipAddRegexOpened(false)}
|
||||||
onMouseEnter={() => setTooltipAddRegexOpened(true)} onMouseLeave={() => setTooltipAddRegexOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
onMouseEnter={() => setTooltipAddRegexOpened(true)} onMouseLeave={() => setTooltipAddRegexOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</>:
|
</>:
|
||||||
<Grid>
|
<Grid>
|
||||||
{regexesList.data.map( (regexInfo) => <Grid.Col key={regexInfo.id} lg={6} xs={12}><RegexView regexInfo={regexInfo} /></Grid.Col>)}
|
{regexesList.data.map( (regexInfo) => <Grid.Col key={regexInfo.id} span={{ lg:6, xs: 12 }}><RegexView regexInfo={regexInfo} /></Grid.Col>)}
|
||||||
</Grid>
|
</Grid>
|
||||||
}
|
}
|
||||||
|
|
||||||
{srv?<AddNewRegex opened={open} onClose={() => {setOpen(false)}} service={srv} />:null}
|
{srv?<AddNewRegex opened={open} onClose={() => {setOpen(false)}} service={srv} />:null}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</Box>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ServiceDetailsProxyRegex;
|
export default ServiceDetailsProxyRegex;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ActionIcon, Badge, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
import { ActionIcon, Badge, Box, LoadingOverlay, Space, Title, Tooltip } from '@mantine/core';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { BsPlusLg } from "react-icons/bs";
|
import { BsPlusLg } from "react-icons/bs";
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
@@ -33,9 +33,9 @@ function RegexProxy({ children }: { children: any }) {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Title order={4}>TCP Proxy Regex Filter (IPv4 Only)</Title>
|
<Title order={4}>TCP Proxy Regex Filter (IPv4 Only)</Title>
|
||||||
<div className='flex-spacer' />
|
<Box className='flex-spacer' />
|
||||||
<Badge size="sm" color="green" variant="filled">Services: {services.isLoading?0:services.data?.length}</Badge>
|
<Badge size="sm" color="green" variant="filled">Services: {services.isLoading?0:services.data?.length}</Badge>
|
||||||
<Space w="xs" />
|
<Space w="xs" />
|
||||||
<Badge size="sm" color="yellow" variant="filled">Filtered Connections: {services.isLoading?0:services.data?.reduce((acc, s)=> acc+=s.n_packets, 0)}</Badge>
|
<Badge size="sm" color="yellow" variant="filled">Filtered Connections: {services.isLoading?0:services.data?.reduce((acc, s)=> acc+=s.n_packets, 0)}</Badge>
|
||||||
@@ -61,25 +61,25 @@ function RegexProxy({ children }: { children: any }) {
|
|||||||
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
onFocus={() => setTooltipRefreshOpened(false)} onBlur={() => setTooltipRefreshOpened(false)}
|
||||||
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
onMouseEnter={() => setTooltipRefreshOpened(true)} onMouseLeave={() => setTooltipRefreshOpened(false)}><TbReload size={18} /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
<div id="service-list" className="center-flex-row">
|
<Box className="center-flex-row">
|
||||||
{srv?null:<>
|
{srv?null:<>
|
||||||
<LoadingOverlay visible={services.isLoading} />
|
<LoadingOverlay visible={services.isLoading} />
|
||||||
{(services.data && services.data?.length > 0)?services.data.map( srv => <ServiceRow service={srv} key={srv.id} onClick={()=>{
|
{(services.data && services.data?.length > 0)?services.data.map( srv => <ServiceRow service={srv} key={srv.id} onClick={()=>{
|
||||||
navigator("/regexproxy/"+srv.id)
|
navigator("/regexproxy/"+srv.id)
|
||||||
}} />):<><Space h="xl"/> <Title className='center-flex' align='center' order={3}>No services found! Add one clicking the "+" buttons</Title>
|
}} />):<><Space h="xl"/> <Title className='center-flex' style={{textAlign:"center"}} order={3}>No services found! Add one clicking the "+" buttons</Title>
|
||||||
<Space h="xl" /> <Space h="xl" />
|
<Space h="xl" /> <Space h="xl" />
|
||||||
<div className='center-flex'>
|
<Box className='center-flex'>
|
||||||
<Tooltip label="Add a new service" color="blue" opened={tooltipAddServOpened}>
|
<Tooltip label="Add a new service" color="blue" opened={tooltipAddServOpened}>
|
||||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled"
|
||||||
onFocus={() => setTooltipAddServOpened(false)} onBlur={() => setTooltipAddServOpened(false)}
|
onFocus={() => setTooltipAddServOpened(false)} onBlur={() => setTooltipAddServOpened(false)}
|
||||||
onMouseEnter={() => setTooltipAddServOpened(true)} onMouseLeave={() => setTooltipAddServOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
onMouseEnter={() => setTooltipAddServOpened(true)} onMouseLeave={() => setTooltipAddServOpened(false)}><BsPlusLg size="20px" /></ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</Box>
|
||||||
</>}
|
</>}
|
||||||
<AddNewService opened={open} onClose={closeModal} />
|
<AddNewService opened={open} onClose={closeModal} />
|
||||||
</>}
|
</>}
|
||||||
</div>
|
</Box>
|
||||||
{srv?children:null}
|
{srv?children:null}
|
||||||
{srv?
|
{srv?
|
||||||
<AddNewRegex opened={open} onClose={closeModal} service={srv} />:
|
<AddNewRegex opened={open} onClose={closeModal} service={srv} />:
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { defineConfig } from 'vite';
|
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
import viteTsconfigPaths from 'vite-tsconfig-paths';
|
||||||
import svgrPlugin from 'vite-plugin-svgr';
|
import svgrPlugin from 'vite-plugin-svgr';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), viteTsconfigPaths(), svgrPlugin()],
|
plugins: [react(), viteTsconfigPaths(), svgrPlugin()],
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user