MikuMikuBeam/src/App.tsx

581 lines
19 KiB
TypeScript

import { Bot, ScrollText, Wand2, Wifi, Zap } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { io } from "socket.io-client";
function isHostLocal(host: string) {
return (
host === "localhost" ||
host === "127.0.0.1" ||
host.startsWith("::1") ||
host.startsWith("192.168") ||
host.startsWith("10.") ||
host.startsWith("172.")
);
}
function getSocketURL() {
const host = window.location.host.split(":")[0];
const isLocal = isHostLocal(host);
const socketURL = isLocal ? `http://${host}:3000` : "/";
return socketURL;
}
const socket = io(getSocketURL());
function ConfigureProxiesAndAgentsView() {
const [loadingConfiguration, setLoadingConfiguration] = useState(false);
const [configuration, setConfiguration] = useState<string[]>([]);
async function retrieveConfiguration(): Promise<string[]> {
const response = await fetch(`http://localhost:3000/configuration`);
const information = (await response.json()) as {
proxies: string;
uas: string;
};
const proxies = atob(information.proxies);
const uas = atob(information.uas);
return [proxies, uas];
}
useEffect(() => {
if (!loadingConfiguration) {
setLoadingConfiguration(true);
retrieveConfiguration().then((config) => {
setLoadingConfiguration(false);
setConfiguration(config);
});
}
}, []);
function saveConfiguration() {
const obj = {
proxies: btoa(configuration[0]),
uas: btoa(configuration[1]),
};
// console.log(obj)
const 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&#10;socks4://user:pass@0.0.0.0:12345"
></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);
const [animState, setAnimState] = useState(0);
const [logs, setLogs] = useState<string[]>([]);
const [progress, setProgress] = useState(0);
const [target, setTarget] = useState("");
const [attackMethod, setAttackMethod] = useState("http_flood");
const [packetSize, setPacketSize] = useState(64);
const [duration, setDuration] = useState(60);
const [packetDelay, setPacketDelay] = useState(100);
const [stats, setStats] = useState({
pps: 0,
bots: 0,
totalPackets: 0,
});
const [lastUpdatedPPS, setLastUpdatedPPS] = useState(Date.now());
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(() => {
if (audioRef.current) {
const audio = audioRef.current;
const handler = () => {
if (audio.paused) return;
if (
animState !== 2 &&
audio.currentTime > 5.24 &&
audio.currentTime < 9.4
) {
setAnimState(2);
}
if (audio.currentTime > 17.53) {
audio.currentTime = 15.86;
}
};
audio.addEventListener("timeupdate", handler);
return () => {
audio.removeEventListener("timeupdate", handler);
};
}
}, [audioRef]);
useEffect(() => {
if (!isAttacking) {
setActuallyAttacking(false);
setAnimState(0);
const audio = audioRef.current;
if (audio) {
audio.pause();
audio.currentTime = 0;
}
if (currentTask) {
clearTimeout(currentTask);
}
}
}, [isAttacking, currentTask]);
useEffect(() => {
const now = Date.now();
if (now - lastUpdatedPPS >= 500) {
setLastUpdatedPPS(now);
setStats((old) => ({
pps: (old.totalPackets - lastTotalPackets) / (now - lastUpdatedPPS),
bots: old.bots,
totalPackets: old.totalPackets,
}));
setLastTotalPackets(stats.totalPackets);
}
}, [lastUpdatedPPS, lastTotalPackets, stats.totalPackets]);
useEffect(() => {
socket.on("stats", (data) => {
setStats((old) => ({
pps: data.pps || old.pps,
bots: data.bots || old.bots,
totalPackets: data.totalPackets || old.totalPackets,
}));
if (data.log) addLog(data.log);
setProgress((prev) => (prev + 10) % 100);
});
socket.on("attackEnd", () => {
setIsAttacking(false);
});
return () => {
socket.off("stats");
socket.off("attackEnd");
};
}, []);
useEffect(() => {
if (audioRef.current) {
audioRef.current.volume = audioVol / 100;
}
}, [audioVol]);
const addLog = (message: string) => {
setLogs((prev) => [message, ...prev].slice(0, 12));
};
const startAttack = (isQuick?: boolean) => {
if (!target.trim()) {
alert("Please enter a target!");
return;
}
setIsAttacking(true);
setStats((old) => ({
pps: 0,
bots: old.bots,
totalPackets: 0,
}));
addLog("🍮 Preparing attack...");
// Play audio
if (audioRef.current) {
audioRef.current.currentTime = isQuick ? 9.5 : 0;
audioRef.current.volume = audioVol / 100;
audioRef.current.play();
}
if (!isQuick) setAnimState(1);
// Start attack after audio intro
const timeout = setTimeout(
() => {
setActuallyAttacking(true);
setAnimState(3);
socket.emit("startAttack", {
target,
packetSize,
duration,
packetDelay,
attackMethod,
});
},
isQuick ? 700 : 10250
);
setCurrentTask(timeout);
};
const stopAttack = () => {
socket.emit("stopAttack");
setIsAttacking(false);
};
return (
<div
className={`w-screen h-screen bg-gradient-to-br ${
animState === 0 || animState === 3
? "from-pink-100 to-blue-100"
: animState === 2
? "background-pulse"
: "bg-gray-950"
} p-8 overflow-y-auto ${actuallyAttacking ? "shake" : ""}`}
>
<audio ref={audioRef} src="/audio.mp3" />
<div className="max-w-2xl mx-auto space-y-8">
<div className="text-center">
<h1 className="mb-2 text-4xl font-bold text-pink-500">
Miku Miku Beam
</h1>
<p
className={`${
animState === 0 || animState === 3
? "text-gray-600"
: "text-white"
}`}
>
Because DDoS attacks are also cute and even more so when Miku does
them.
</p>
</div>
<div
className={`relative p-6 overflow-hidden rounded-lg shadow-xl ${
animState === 0 || animState === 3 ? "bg-white" : "bg-gray-950"
}`}
>
{/* Miku GIF */}
<div
className="flex justify-center w-full h-48 mb-6"
style={{
backgroundImage: "url('/miku.gif')",
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
backgroundSize: "cover",
opacity: animState === 0 || animState === 3 ? 1 : 0,
transition: "opacity 0.2s ease-in-out",
}}
></div>
{/* Attack Configuration */}
<div className="mb-6 space-y-4">
<div className="grid grid-cols-2 gap-4">
<input
type="text"
value={target}
onChange={(e) => setTarget(e.target.value)}
placeholder="Enter target URL or IP"
className={`${
animState === 0 || animState === 3 ? "" : "text-white"
} px-4 py-2 border border-pink-200 rounded-lg outline-none focus:border-pink-500 focus:ring-2 focus:ring-pink-200`}
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
? "bg-red-500 hover:bg-red-600"
: "bg-pink-500 hover:bg-pink-600"
}
flex items-center justify-center gap-2
`}
>
<Wand2 className="w-5 h-5" />
{isAttacking ? "Stop Beam" : "Start Miku Beam"}
</button>
<button
onClick={() =>
isAttacking ? stopAttack() : startAttack(true)
}
className={`
px-2 py-2 rounded-lg font-semibold text-white transition-all
${
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>
<div className="grid grid-cols-4 gap-4">
<div>
<label
className={`block mb-1 text-sm font-medium ${
animState === 0 || animState === 3
? "text-gray-700"
: "text-white"
}`}
>
Attack Method
</label>
<select
value={attackMethod}
onChange={(e) => setAttackMethod(e.target.value)}
className={`${
animState === 0 || animState === 3 ? "" : "text-gray-900"
} w-full px-4 py-2 border border-pink-200 rounded-lg outline-none focus:border-pink-500 focus:ring-2 focus:ring-pink-200`}
disabled={isAttacking}
>
<option value="http_flood">HTTP/Flood</option>
<option value="http_bypass">HTTP/Bypass</option>
<option value="http_slowloris">HTTP/Slowloris</option>
<option value="tcp_flood">TCP/Flood</option>
<option value="minecraft_ping">Minecraft/Ping</option>
</select>
</div>
<div>
<label
className={`block mb-1 text-sm font-medium ${
animState === 0 || animState === 3
? "text-gray-700"
: "text-white"
}`}
>
Packet Size (kb)
</label>
<input
type="number"
value={packetSize}
onChange={(e) => setPacketSize(Number(e.target.value))}
className={`${
animState === 0 || animState === 3 ? "" : "text-white"
} w-full px-4 py-2 border border-pink-200 rounded-lg outline-none focus:border-pink-500 focus:ring-2 focus:ring-pink-200`}
disabled={isAttacking}
min="1"
max="1500"
/>
</div>
<div>
<label
className={`block mb-1 text-sm font-medium ${
animState === 0 || animState === 3
? "text-gray-700"
: "text-white"
}`}
>
Duration (seconds)
</label>
<input
type="number"
value={duration}
onChange={(e) => setDuration(Number(e.target.value))}
className={`${
animState === 0 || animState === 3 ? "" : "text-white"
} w-full px-4 py-2 border border-pink-200 rounded-lg outline-none focus:border-pink-500 focus:ring-2 focus:ring-pink-200`}
disabled={isAttacking}
min="1"
max="300"
/>
</div>
<div>
<label
className={`block mb-1 text-sm font-medium ${
animState === 0 || animState === 3
? "text-gray-700"
: "text-white"
}`}
>
Packet Delay (ms)
</label>
<input
type="number"
value={packetDelay}
onChange={(e) => setPacketDelay(Number(e.target.value))}
className={`${
animState === 0 || animState === 3 ? "" : "text-white"
} w-full px-4 py-2 border border-pink-200 rounded-lg outline-none focus:border-pink-500 focus:ring-2 focus:ring-pink-200`}
disabled={isAttacking}
min="1"
max="1000"
/>
</div>
</div>
</div>
{/* Stats Widgets */}
<div className="grid grid-cols-3 gap-4 mb-6">
<div className="p-4 rounded-lg bg-gradient-to-br from-pink-500/10 to-blue-500/10">
<div className="flex items-center gap-2 mb-2 text-pink-600">
<Zap className="w-4 h-4" />
<span className="font-semibold">Packets/sec</span>
</div>
<div
className={`text-2xl font-bold ${
animState === 0 || animState === 3
? "text-gray-800"
: "text-white"
}`}
>
{stats.pps.toLocaleString()}
</div>
</div>
<div className="p-4 rounded-lg bg-gradient-to-br from-pink-500/10 to-blue-500/10">
<div className="flex items-center gap-2 mb-2 text-pink-600">
<Bot className="w-4 h-4" />
<span className="font-semibold">Active Bots</span>
</div>
<div
className={`text-2xl font-bold ${
animState === 0 || animState === 3
? "text-gray-800"
: "text-white"
}`}
>
{stats.bots.toLocaleString()}
</div>
</div>
<div className="p-4 rounded-lg bg-gradient-to-br from-pink-500/10 to-blue-500/10">
<div className="flex items-center gap-2 mb-2 text-pink-600">
<Wifi className="w-4 h-4" />
<span className="font-semibold">Total Packets</span>
</div>
<div
className={`text-2xl font-bold ${
animState === 0 || animState === 3
? "text-gray-800"
: "text-white"
}`}
>
{stats.totalPackets.toLocaleString()}
</div>
</div>
</div>
{/* Progress Bar */}
<div className="h-4 mb-6 overflow-hidden bg-gray-200 rounded-full">
<div
className="h-full transition-all duration-500 bg-gradient-to-r from-pink-500 to-blue-500"
style={{ width: `${progress}%` }}
/>
</div>
{/* Logs Section */}
<div className="p-4 font-mono text-sm bg-gray-900 rounded-lg">
<div className="text-green-400">
{logs.map((log, index) => (
<div key={index} className="py-1">
{`> ${log}`}
</div>
))}
{logs.length === 0 && (
<div className="italic text-gray-500">
{">"} Waiting for Miku's power...
</div>
)}
</div>
</div>
{/* Cute Animation Overlay */}
{isAttacking && (
<div className="absolute inset-0 pointer-events-none">
<div className="absolute inset-0 bg-gradient-to-r from-pink-500/10 to-blue-500/10 animate-pulse" />
<div className="absolute top-0 -translate-x-1/2 left-1/2">
<div className="w-2 h-2 bg-pink-500 rounded-full animate-bounce" />
</div>
</div>
)}
</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>
<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))}
/>
</span>
</div>
</div>
</div>
);
}
export default App;