implemented a frontend editor for the uas.txt and proxies.txt files.

This commit is contained in:
rainwashed 2025-01-22 10:03:59 -05:00
parent 2c58140dcc
commit 124e5d6d13
10 changed files with 147 additions and 29 deletions

View file

@ -79,6 +79,12 @@ Once the server is up and running, you can interact with it via the frontend:
}
```
## Adding Proxies and User-Agents
Access to the ``data/proxies.txt`` and ``data/uas.txt`` can now be done fully in the frontend. Click the text button to the right of the beam button to open up the editor.
![AnnotatedImage](docs/annotated-button.png)
## Worker-Based Attack Handling 🔧💡
Each attack type is handled in a separate worker thread, ensuring that the main server remains responsive. The attack workers are dynamically loaded based on the selected attack method (HTTP, etc...).

BIN
bun.lockb

Binary file not shown.

View file

@ -1,5 +1,5 @@
socks4://199.58.184.97:4145
socks4://192.111.139.163:19404
socks4://199.187.210.54:4145
socks4://46.105.127.74:45108
socks4://199.58.184.97:4145
socks4://192.111.139.163:19404
socks4://199.187.210.54:4145
socks4://46.105.127.74:45108
socks4://98.188.47.150:4145

BIN
docs/annotated-button.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 370 KiB

View file

@ -13,6 +13,7 @@
},
"dependencies": {
"axios": "^1.7.9",
"body-parser": "^1.20.3",
"concurrently": "^9.1.2",
"express": "^4.21.2",
"lucide-react": "^0.344.0",

BIN
public/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

View file

@ -3,7 +3,7 @@ import { join } from "path";
import { Proxy } from "./lib";
const currentPath = () => {
export const currentPath = () => {
const path = process.cwd();
return path === "/" ? "." : path;
};

View file

@ -1,13 +1,15 @@
import express from "express";
import { createServer } from "http";
import { dirname, join } from "path";
import { readFileSync, writeFileSync } from "fs";
import { Server } from "socket.io";
import { fileURLToPath } from "url";
import { Worker } from "worker_threads";
import { loadProxies, loadUserAgents } from "./fileLoader";
import { currentPath, loadProxies, loadUserAgents } from "./fileLoader";
import { AttackMethod } from "./lib";
import { filterProxies } from "./proxyUtils";
import bodyParser from "body-parser";
// Define the workers based on attack type
const attackWorkers: { [key in AttackMethod]: string } = {
@ -26,6 +28,7 @@ const io = new Server(httpServer, {
cors: {
origin: "http://localhost:5173",
methods: ["GET", "POST"],
allowedHeaders: ["Content-Type"]
},
});
@ -105,6 +108,47 @@ io.on("connection", (socket) => {
});
});
app.get("/configuration", (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173")
res.setHeader("Content-Type", "application/json");
let proxiesText = readFileSync(join(currentPath(), "data", "proxies.txt"), "utf-8");
let uasText = readFileSync(join(currentPath(), "data", "uas.txt"), "utf-8");
res.send({
proxies: btoa(proxiesText),
uas: btoa(uasText),
})
})
app.options('/configuration', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5173');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.send();
});
app.post("/configuration", bodyParser.json(), (req, res) => {
res.setHeader("Access-Control-Allow-Methods", "POST");
res.setHeader("Access-Control-Allow-Headers", "Content-Type")
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173")
res.setHeader("Content-Type", "application/text");
// console.log(req.body)
// atob and btoa are used to avoid the problems in sending data with // characters, etc.
let proxies = atob(req.body["proxies"]);
let uas = atob(req.body["uas"]);
writeFileSync(join(currentPath(), "data", "proxies.txt"), proxies, {
encoding: "utf-8"
});
writeFileSync(join(currentPath(), "data", "uas.txt"), uas, {
encoding: "utf-8"
});
res.send("OK")
})
const PORT = 3000;
httpServer.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);

View file

@ -1,9 +1,69 @@
import { Bot, Wand2, Wifi, Zap } from "lucide-react";
import { Bot, ScrollText, Wand2, Wifi, Zap } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { io } from "socket.io-client";
const socket = io("http://localhost:3000");
function ConfigureProxiesAndAgentsView() {
let [loadingConfiguration, setLoadingConfiguration] = useState(false);
let [configuration, setConfiguration] = useState<string[]>([]);
async function retrieveConfiguration(): Promise<string[]> {
let response = await fetch(`http://localhost:3000/configuration`);
let information = await response.json() as {
proxies: string,
uas: string,
}
let proxies = atob(information.proxies);
let uas = atob(information.uas);
return [proxies, uas]
}
useEffect(() => {
if (!loadingConfiguration) {
setLoadingConfiguration(true);
retrieveConfiguration().then((config) => {
setLoadingConfiguration(false);
setConfiguration(config);
})
}
}, [])
function saveConfiguration() {
let obj = {
proxies: btoa(configuration[0]),
uas: btoa(configuration[1])
}
// console.log(obj)
let response = fetch(`http://localhost:3000/configuration`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(obj),
});
response.then(() => {
alert("Saved")
window.location.reload();
})
}
return <div className="fixed grid p-8 mx-auto -translate-x-1/2 -translate-y-1/2 bg-white rounded-md shadow-lg max-w-7xl place-items-center left-1/2 top-1/2">
{loadingConfiguration ? <div className="flex flex-col items-center justify-center space-y-2"><img src="/loading.gif" className="rounded-sm shadow-sm" /><p>Loading proxies.txt and uas.txt...</p></div> : <div className="w-[56rem] flex flex-col">
<p className="pl-1 mb-1 italic">proxies.txt</p>
<textarea value={configuration[0]} className="w-full h-40 p-2 border-black/10 border-[1px] rounded-sm resize-none" onChange={(e) => setConfiguration([e.target.value, configuration[1]])} placeholder="socks5://0.0.0.0"></textarea>
<p className="pl-1 mt-2 mb-1 italic">uas.txt</p>
<textarea value={configuration[1]} className="w-full h-40 p-2 border-black/10 border-[1px] rounded-sm resize-none" onChange={(e) => setConfiguration([configuration[0], e.target.value])} placeholder="Mozilla/5.0 (Linux; Android 10; K)..."></textarea>
<button onClick={saveConfiguration} className="p-4 mt-4 text-white bg-gray-800 rounded-md hover:bg-gray-900">Write Changes</button>
</div>}
</div>
}
function App() {
const [isAttacking, setIsAttacking] = useState(false);
const [actuallyAttacking, setActuallyAttacking] = useState(false);
@ -23,6 +83,8 @@ function App() {
const [lastTotalPackets, setLastTotalPackets] = useState(0);
const [currentTask, setCurrentTask] = useState<NodeJS.Timeout | null>(null);
const [audioVol, setAudioVol] = useState(100);
const [openedConfig, setOpenedConfig] = useState(false);
const audioRef = useRef<HTMLAudioElement>(null);
useEffect(() => {
@ -91,13 +153,13 @@ function App() {
};
}, []);
useEffect(() => {
if (audioRef.current) {
audioRef.current.volume = audioVol / 100;
}
}, [audioVol])
const addLog = (message: string) => {
setLogs((prev) => [message, ...prev].slice(0, 12));
@ -148,9 +210,8 @@ function App() {
return (
<div
className={`w-screen h-screen bg-gradient-to-br from-pink-100 to-blue-100 p-8 overflow-y-auto ${
actuallyAttacking ? "shake" : ""
}`}
className={`w-screen h-screen bg-gradient-to-br from-pink-100 to-blue-100 p-8 overflow-y-auto ${actuallyAttacking ? "shake" : ""
}`}
>
<audio ref={audioRef} src="/audio.mp3" />
@ -189,15 +250,15 @@ function App() {
disabled={isAttacking}
/>
<div className="flex items-center gap-2">
<button
onClick={() => (isAttacking ? stopAttack() : startAttack())}
className={`
px-8 py-2 rounded-lg font-semibold text-white transition-all w-full
${
isAttacking
${isAttacking
? "bg-red-500 hover:bg-red-600"
: "bg-pink-500 hover:bg-pink-600"
}
}
flex items-center justify-center gap-2
`}
>
@ -210,16 +271,20 @@ function App() {
}
className={`
px-2 py-2 rounded-lg font-semibold text-white transition-all
${
isAttacking
${isAttacking
? "bg-gray-500 hover:bg-red-600"
: "bg-cyan-500 hover:bg-cyan-600"
}
}
flex items-center justify-center gap-2
`}
>
<Zap className="w-5 h-5" />
</button>
<button className={`px-2 py-2 rounded-lg font-semibold text-white transition-all flex items-center justify-center gap-2 bg-slate-800 hover:bg-slate-900`} onClick={() => setOpenedConfig(true)}>
<ScrollText className="w-5 h-5" />
</button>
</div>
</div>
@ -351,20 +416,22 @@ function App() {
)}
</div>
{openedConfig ? <ConfigureProxiesAndAgentsView /> : undefined}
<div className="flex flex-col items-center">
<span className="text-sm text-center text-gray-500">
🎵 v1.0 made by{" "}
<a
href="https://github.com/sammwyy/mikumikubeam"
target="_blank"
rel="noreferrer"
>
@Sammwy
</a>{" "}
🎵
<span className="text-sm text-center text-gray-500">
🎵 v1.0 made by{" "}
<a
href="https://github.com/sammwyy/mikumikubeam"
target="_blank"
rel="noreferrer"
>
@Sammwy
</a>{" "}
🎵
</span>
<span>
<input className="shadow-sm volume_bar focus:border-pink-500" type="range" min="0" max="100" step="5" draggable="false" value={audioVol} onChange={(e) => setAudioVol(parseInt(e.target?.value))} />
<input className="shadow-sm volume_bar focus:border-pink-500" type="range" min="0" max="100" step="5" draggable="false" value={audioVol} onChange={(e) => setAudioVol(parseInt(e.target?.value))} />
</span>
</div>
</div>