scripting added
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 8s

This commit is contained in:
2026-02-09 21:56:12 +01:00
parent 69abb95140
commit 317946c7b7
9 changed files with 187 additions and 6 deletions

View File

@@ -13,13 +13,16 @@
"@tanstack/react-query-devtools": "^5.91.1", "@tanstack/react-query-devtools": "^5.91.1",
"antd": "^6.0.0", "antd": "^6.0.0",
"axios": "^1.13.2", "axios": "^1.13.2",
"prismjs": "^1.30.0",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-router-dom": "^7.9.4" "react-router-dom": "^7.9.4",
"react-simple-code-editor": "^0.14.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.36.0", "@eslint/js": "^9.36.0",
"@types/node": "^24.9.1", "@types/node": "^24.9.1",
"@types/prismjs": "^1.26.5",
"@types/react": "^19.2.2", "@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2", "@types/react-dom": "^19.2.2",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
@@ -2316,6 +2319,13 @@
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
}, },
"node_modules/@types/prismjs": {
"version": "1.26.5",
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz",
"integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "19.2.7", "version": "19.2.7",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
@@ -5204,6 +5214,15 @@
"url": "https://github.com/prettier/prettier?sponsor=1" "url": "https://github.com/prettier/prettier?sponsor=1"
} }
}, },
"node_modules/prismjs": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/proxy-from-env": { "node_modules/proxy-from-env": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -5305,6 +5324,16 @@
"react-dom": ">=18" "react-dom": ">=18"
} }
}, },
"node_modules/react-simple-code-editor": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.14.1.tgz",
"integrity": "sha512-BR5DtNRy+AswWJECyA17qhUDvrrCZ6zXOCfkQY5zSmb96BVUbpVAv03WpcjcwtCwiLbIANx3gebHOcXYn1EHow==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/reflect.getprototypeof": { "node_modules/reflect.getprototypeof": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",

View File

@@ -17,13 +17,16 @@
"@tanstack/react-query-devtools": "^5.91.1", "@tanstack/react-query-devtools": "^5.91.1",
"antd": "^6.0.0", "antd": "^6.0.0",
"axios": "^1.13.2", "axios": "^1.13.2",
"prismjs": "^1.30.0",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-router-dom": "^7.9.4" "react-router-dom": "^7.9.4",
"react-simple-code-editor": "^0.14.1"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.36.0", "@eslint/js": "^9.36.0",
"@types/node": "^24.9.1", "@types/node": "^24.9.1",
"@types/prismjs": "^1.26.5",
"@types/react": "^19.2.2", "@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2", "@types/react-dom": "^19.2.2",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",

View File

@@ -3,6 +3,7 @@ import { ApartmentOutlined, ApiOutlined, HomeOutlined, InfoCircleOutlined, Setti
import { Layout, Menu } from 'antd'; import { Layout, Menu } from 'antd';
import React from 'react'; import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import TerminalIcon from '../icons/TerminalIcon';
import { PATHS } from '../routes'; import { PATHS } from '../routes';
import '../theme/layout.less'; import '../theme/layout.less';
@@ -12,6 +13,11 @@ const menuItems = [
{ key: PATHS.HOME, icon: <HomeOutlined style={{ fontSize: '18px' }} />, label: 'Home' }, { key: PATHS.HOME, icon: <HomeOutlined style={{ fontSize: '18px' }} />, label: 'Home' },
{ key: PATHS.NETWORK, icon: <ApartmentOutlined style={{ fontSize: '18px' }} />, label: 'Network' }, { key: PATHS.NETWORK, icon: <ApartmentOutlined style={{ fontSize: '18px' }} />, label: 'Network' },
{ key: PATHS.SNIFFING, icon: <ApiOutlined style={{ fontSize: '18px' }} />, label: 'Sniffing' }, { key: PATHS.SNIFFING, icon: <ApiOutlined style={{ fontSize: '18px' }} />, label: 'Sniffing' },
{
key: PATHS.SCRIPTING,
icon: <TerminalIcon style={{ fontSize: '18px' }} width={18} height={18} />,
label: 'Scripting',
},
{ key: '/about', icon: <InfoCircleOutlined style={{ fontSize: '18px' }} />, label: 'About' }, { key: '/about', icon: <InfoCircleOutlined style={{ fontSize: '18px' }} />, label: 'About' },
{ key: '/settings', icon: <SettingOutlined style={{ fontSize: '18px' }} />, label: 'Settings' }, { key: '/settings', icon: <SettingOutlined style={{ fontSize: '18px' }} />, label: 'Settings' },
]; ];

View File

@@ -3,6 +3,7 @@ import { Navigate, Route, Routes } from 'react-router-dom';
import App from './App'; // your layout component (has <Outlet />) import App from './App'; // your layout component (has <Outlet />)
import Home from './pages/Home'; import Home from './pages/Home';
import Network from './pages/Network'; import Network from './pages/Network';
import Scripting from './pages/Scripting';
import Sniffing from './pages/Sniffing'; import Sniffing from './pages/Sniffing';
import { PATHS } from './routes'; import { PATHS } from './routes';
@@ -18,6 +19,7 @@ export default function AppRouter() {
<Route path={PATHS.HOME.slice(1)} element={<Home />} /> <Route path={PATHS.HOME.slice(1)} element={<Home />} />
<Route path={PATHS.NETWORK.slice(1)} element={<Network />} /> <Route path={PATHS.NETWORK.slice(1)} element={<Network />} />
<Route path={PATHS.SNIFFING.slice(1)} element={<Sniffing />} /> <Route path={PATHS.SNIFFING.slice(1)} element={<Sniffing />} />
<Route path={PATHS.SCRIPTING.slice(1)} element={<Scripting />} />
{/* Fallback (renders inside layout too) */} {/* Fallback (renders inside layout too) */}
<Route path="*" element={<NotFound />} /> <Route path="*" element={<NotFound />} />

View File

@@ -0,0 +1,54 @@
import Prism from 'prismjs';
import 'prismjs/components/prism-python';
import 'prismjs/themes/prism.css';
import { useCallback, useMemo } from 'react';
import Editor from 'react-simple-code-editor';
// Props for the editor
export type PythonEditorProps = {
value: string;
onChange: (code: string) => void;
readOnly?: boolean;
className?: string;
height?: string | number; // e.g. '200px' or 200
};
export default function PythonEditor({
value,
onChange,
readOnly = false,
height = 480,
className = '',
}: PythonEditorProps) {
const highlight = useCallback((code: string) => {
try {
return Prism.highlight(code, Prism.languages.python, 'python');
} catch (e) {
return code;
}
}, []);
const editorStyle = useMemo(
() => ({
fontFamily: '"JetBrains Mono", "Fira Code", monospace',
fontSize: 14,
height: typeof height === 'number' ? `${height}px` : height,
}),
[height],
);
return (
<div className={`python-editor ${className}`}>
<Editor
value={value}
onValueChange={(code) => onChange(code)}
highlight={highlight}
padding={12}
preClassName="language-python"
textareaId="python-editor"
style={editorStyle}
readOnly={readOnly}
/>
</div>
);
}

View File

@@ -0,0 +1,57 @@
import React, { forwardRef } from 'react';
export type IconProps = React.SVGProps<SVGSVGElement> & {
/**
* Width/height of the icon. If a number is provided it will be used as px.
* Default: 24
*/
size?: number | string;
/**
* Icon color — will be used as the fill for paths.
* Default: 'currentColor' so color can be controlled via CSS.
*/
color?: string;
/**
* Accessible title. If provided, title will be rendered and aria-hidden will be false.
*/
title?: string;
};
const TerminalIcon = forwardRef<SVGSVGElement, IconProps>(
({ size = 24, color = 'currentColor', title, ...rest }, ref) => {
// If user passed a numeric size, treat as px
const sizeValue = typeof size === 'number' ? `${size}px` : size;
return (
<svg
ref={ref}
width={sizeValue}
height={sizeValue}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden={title ? undefined : true}
role={title ? 'img' : 'presentation'}
{...rest}
>
{title ? <title>{title}</title> : null}
<path
d="M5.0333 14.8284L6.44751 16.2426L10.6902 12L6.44751 7.75733L5.0333 9.17155L7.86172 12L5.0333 14.8284Z"
fill={color}
/>
<path d="M15 14H11V16H15V14Z" fill={color} />
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2 2C0.895431 2 0 2.89543 0 4V20C0 21.1046 0.89543 22 2 22H22C23.1046 22 24 21.1046 24 20V4C24 2.89543 23.1046 2 22 2H2ZM22 4H2L2 20H22V4Z"
fill={color}
/>
</svg>
);
},
);
TerminalIcon.displayName = 'TerminalIcon';
export default TerminalIcon;

View File

@@ -76,10 +76,6 @@ a:hover {
/* === Code blocks / preformatted text === */ /* === Code blocks / preformatted text === */
pre, pre,
code { code {
background-color: #f0f0f0;
color: #262626;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-family: "JetBrains Mono", "Fira Code", monospace; font-family: "JetBrains Mono", "Fira Code", monospace;
} }

View File

@@ -0,0 +1,33 @@
import { Card, Tabs } from 'antd';
import { useState } from 'react';
import PythonEditor from '../components/PythonEditor';
const TwoTabsPage: React.FC = () => {
const [code, setCode] = useState<string>("print('hello world')\n");
const tabItems = [
{
key: '1',
label: 'Saved Scripts',
children: <></>,
},
{
key: '2',
label: 'Custom Script',
children: (
<div>
<h3>Python Editor</h3>
<PythonEditor value={code} onChange={setCode} />
</div>
),
},
];
return (
<Card style={{ width: '100%' }}>
<Tabs defaultActiveKey="1" items={tabItems} />
</Card>
);
};
export default TwoTabsPage;

View File

@@ -3,4 +3,5 @@ export const PATHS = {
HOME: '/home', HOME: '/home',
NETWORK: '/network', NETWORK: '/network',
SNIFFING: '/sniffing', SNIFFING: '/sniffing',
SCRIPTING: '/scripting',
}; };