feat: add more page

This commit is contained in:
ReaJason
2025-08-13 23:53:40 +08:00
parent afa8f9dd06
commit 83fe7cad8c
60 changed files with 2403 additions and 284 deletions
+802
View File
@@ -0,0 +1,802 @@
/** biome-ignore-all lint/suspicious/noThenProperty: no way */
import { yupResolver } from "@hookform/resolvers/yup";
import { AlertTriangle, Trash2 } from "lucide-react";
import * as React from "react";
import { useId, useState } from "react";
import { Controller, useFieldArray, useForm } from "react-hook-form";
import * as yup from "yup";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardFooter } from "@/components/ui/card";
import {
Form,
FormControl,
FormDescription,
FormField,
FormFieldItem,
FormFieldLabel,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
// --- 类型定义 ---
// 回显方式
type EchoMethod = "header" | "body" | "dnslog" | "httplog" | "sleep";
// 回显内容
type EchoContent = "middleware" | "os" | "jdk" | "bytecode" | "command";
// 表单值的完整类型
interface PayloadFormValues {
echoMethod: EchoMethod;
echoContent?: EchoContent;
// Header
headerName?: string;
// DNSLog / HTTPLog
logAddress?: string;
middlewareType?: "tomcat" | "jetty" | "springboot" | "weblogic";
paramSource?: "builtin" | "requestParam" | "requestHeader";
requestParamName?: string;
requestHeaderName?: string;
bytecodeBase64?: string;
command?: string;
// Sleep 选项
sleepMiddleware?: "tomcat" | "jetty" | "springboot" | "weblogic";
sleepMiddlewareDelay?: number;
sleepOsDelays?: { os: "linux" | "windows" | "macos"; delay: number }[];
sleepJdkDetectionType?: "version" | "type";
sleepJdkVersion?: "8" | "11" | "17";
sleepJdkType?: "jdk" | "jre";
sleepJdkDelay?: number;
sleepBytecodeSuccessDelay?: number;
}
const formSchema = yup.object().shape({
echoMethod: yup.string().required("请选择一种回显方式"),
// 条件:当 echoMethod 是 'header'
headerName: yup.string().when("echoMethod", {
is: "header",
then: (schema) => schema.required("必须填写 Header Name"),
otherwise: (schema) => schema.optional(),
}),
// 条件:当 echoMethod 是 'dnslog' 或 'httplog'
logAddress: yup.string().when("echoMethod", {
is: (val: EchoMethod) => val === "dnslog" || val === "httplog",
then: (schema) => schema.required("必须填写 Log 地址"),
otherwise: (schema) => schema.optional(),
}),
// 只有在选择了具体内容时才需要
echoContent: yup.string().required("请选择回显内容"),
// --- 嵌套条件验证 ---
// 中间件类型在特定组合下是必须的
middlewareType: yup.string().when(["echoMethod", "echoContent"], {
is: (echoMethod: EchoMethod, echoContent: EchoContent) =>
(echoMethod === "header" || echoMethod === "body") &&
(echoContent === "os" || echoContent === "jdk" || echoContent === "bytecode"),
then: (schema) => schema.required("请选择中间件类型"),
otherwise: (schema) => schema.optional(),
}),
// 字节码相关
paramSource: yup.string().when(["echoMethod", "echoContent"], {
is: (echoMethod: EchoMethod, echoContent: EchoContent) =>
(echoMethod === "header" || echoMethod === "body") && echoContent === "bytecode",
then: (schema) => schema.required("请选择字节码来源"),
otherwise: (schema) => schema.optional(),
}),
bytecodeBase64: yup.string().when(["echoContent", "paramSource"], {
is: (echoContent: EchoContent, paramSource: string) => echoContent === "bytecode" && paramSource === "builtin",
then: (schema) => schema.required("必须填写字节码 Base64"),
otherwise: (schema) => schema.optional(),
}),
requestParamName: yup.string().when("paramSource", {
is: (paramSource: string) => paramSource === "requestParam",
then: (schema) => schema.required("必须填写 Request Param Name"),
otherwise: (schema) => schema.optional(),
}),
requestHeaderName: yup.string().when("paramSource", {
is: (paramSource: string) => paramSource === "requestHeader",
then: (schema) => schema.required("必须填写 Request Header Name"),
otherwise: (schema) => schema.optional(),
}),
command: yup.string().when("echoContent", {
is: (echoContent: EchoContent) => echoContent === "command",
then: (schema) => schema.required("必须填写执行的命令"),
otherwise: (schema) => schema.optional(),
}),
// --- Sleep 相关验证 ---
sleepMiddleware: yup.string().when(["echoMethod", "echoContent"], {
is: (method: string, content: string) => method === "sleep" && content === "middleware",
then: (s) => s.required("请选择目标中间件"),
otherwise: (s) => s.optional(),
}),
sleepMiddlewareDelay: yup.number().when(["echoMethod", "echoContent"], {
is: (method: string, content: string) => method === "sleep" && content === "middleware",
then: (s) => s.required("请填写延迟时间").min(1, "延迟至少为 1 秒").typeError("请输入有效的秒数"),
otherwise: (s) => s.optional(),
}),
sleepOsDelays: yup.array().when(["echoMethod", "echoContent"], {
is: (method: string, content: string) => method === "sleep" && content === "os",
then: (s) =>
s
.of(
yup.object().shape({
os: yup.string().required(),
delay: yup.number().required("请填写延迟时间").min(1, "延迟至少为 1 秒").typeError("请输入有效的秒数"),
}),
)
.min(1, "至少需要一个操作系统延迟配置"),
otherwise: (s) => s.optional(),
}),
sleepJdkDetectionType: yup.string().when(["echoMethod", "echoContent"], {
is: (method: string, content: string) => method === "sleep" && content === "jdk",
then: (s) => s.required("请选择 JDK 探测类型"),
otherwise: (s) => s.optional(),
}),
sleepJdkVersion: yup.string().when("sleepJdkDetectionType", {
is: "version",
then: (s) => s.required("请选择 JDK 版本"),
otherwise: (s) => s.optional(),
}),
sleepJdkType: yup.string().when("sleepJdkDetectionType", {
is: "type",
then: (s) => s.required("请选择 JDK/JRE 类型"),
otherwise: (s) => s.optional(),
}),
sleepJdkDelay: yup.number().when(["echoMethod", "echoContent"], {
is: (method: string, content: string) => method === "sleep" && content === "jdk",
then: (s) => s.required("请填写延迟时间").min(1, "延迟至少为 1 秒").typeError("请输入有效的秒数"),
otherwise: (s) => s.optional(),
}),
sleepBytecodeSuccessDelay: yup.number().when(["echoMethod", "echoContent"], {
is: (method: string, content: string) => method === "sleep" && content === "bytecode",
then: (s) => s.required("请填写延迟时间").min(1, "延迟至少为 1 秒").typeError("请输入有效的秒数"),
otherwise: (s) => s.optional(),
}),
});
export default function EchoPayloadGenerator() {
const form = useForm<PayloadFormValues>({
resolver: yupResolver(formSchema) as any,
defaultValues: {
echoMethod: "header",
echoContent: undefined,
headerName: "X-Echo",
logAddress: "",
middlewareType: undefined,
paramSource: "builtin",
requestHeaderName: "X-Data",
requestParamName: "payload",
sleepOsDelays: [{ os: "linux", delay: 5 }],
sleepJdkDetectionType: "version",
sleepJdkType: "jdk",
sleepJdkVersion: "8",
sleepJdkDelay: 5,
sleepBytecodeSuccessDelay: 5,
sleepMiddlewareDelay: 5,
},
});
const { fields, append, remove } = useFieldArray({
control: form.control,
name: "sleepOsDelays",
});
// 监视表单值的变化以动态渲染 UI
const watchedEchoMethod = form.watch("echoMethod");
const watchedEchoContent = form.watch("echoContent");
const watchedParamSource = form.watch("paramSource");
const watchedSleepJdkDetectionType = form.watch("sleepJdkDetectionType");
// 重置子选项
React.useEffect(() => {
form.setValue("echoContent", undefined);
}, [form.setValue]);
function onSubmit(values: PayloadFormValues) {
// 在这里可以构建最终的 Payload
console.log("Form Submitted:", values);
}
// --- 动态内容渲染 ---
const [isFile, setIsFile] = useState(false);
const optionOneId = useId();
const optionTwoId = useId();
const renderContentOptions = () => {
const baseOptions: { value: EchoContent; label: string }[] = [
{ value: "middleware", label: "中间件类型" },
{ value: "os", label: "操作系统类型" },
{ value: "jdk", label: "JDK 信息" },
{ value: "command", label: "命令执行" },
{ value: "bytecode", label: "自定义字节码执行" },
];
let filteredOptions = baseOptions;
// 根据规则过滤选项
if (watchedEchoMethod === "header" || watchedEchoMethod === "body") {
filteredOptions = baseOptions.filter((opt) => opt.value !== "middleware");
}
if (watchedEchoMethod === "dnslog" || watchedEchoMethod === "httplog" || watchedEchoMethod === "sleep") {
filteredOptions = baseOptions.filter((opt) => opt.value !== "command" && opt.value !== "bytecode");
}
return (
<FormField
control={form.control}
name="echoContent"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel></FormFieldLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="请选择要回显的内容..." />
</SelectTrigger>
</FormControl>
<SelectContent>
{filteredOptions.map((opt) => (
<SelectItem key={opt.value} value={opt.value}>
{opt.label}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormFieldItem>
)}
/>
);
};
const renderDynamicFields = () => {
// --- Response Header / Body ---
if ((watchedEchoMethod === "header" || watchedEchoMethod === "body") && watchedEchoContent) {
return (
<>
{watchedEchoContent === "bytecode" && (
<div className="space-y-4 pt-4 border-t mt-4">
<FormField
control={form.control}
name="paramSource"
render={({ field }) => (
<FormFieldItem className="space-y-2">
<FormFieldLabel></FormFieldLabel>
<FormControl>
<RadioGroup onValueChange={field.onChange} defaultValue={field.value} className="flex gap-4">
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="builtin" />
</FormControl>
<FormLabel className="font-normal"></FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="requestHeader" />
</FormControl>
<FormLabel className="font-normal"> Request Header </FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="requestParam" />
</FormControl>
<FormLabel className="font-normal"> Request Param </FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
{watchedParamSource === "builtin" && (
<FormField
control={form.control}
name="bytecodeBase64"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel> Base64</FormFieldLabel>
<RadioGroup
value={isFile ? "file" : "base64"}
onValueChange={(value) => {
field.onChange("");
setIsFile(value === "file");
}}
className="flex items-center space-x-2"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="base64" id={optionOneId} />
<Label htmlFor={optionOneId}>Base64</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="file" id={optionTwoId} />
<Label htmlFor={optionTwoId}>File</Label>
</div>
</RadioGroup>
<FormControl className="mt-2 items-center">
{isFile ? (
<Input
onChange={(e) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
const base64String = (event.target?.result as string)?.split(",")[1] || "";
field.onChange(base64String);
};
reader.readAsDataURL(file);
}
}}
accept=".class"
placeholder="请输入"
type="file"
/>
) : (
<Textarea {...field} placeholder="请输入" className="h-24" />
)}
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{watchedParamSource === "requestParam" && (
<FormField
control={form.control}
name="requestParamName"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>Request Param Name</FormFieldLabel>
<FormControl>
<Input placeholder="例如: cmd, data, ..." {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{watchedParamSource === "requestHeader" && (
<FormField
control={form.control}
name="requestHeaderName"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>Request Header Name</FormFieldLabel>
<FormControl>
<Input placeholder="例如: cmd, data, ..." {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
</div>
)}
{watchedEchoContent === "command" && (
<div className="space-y-4 pt-4 border-t mt-4">
<FormField
control={form.control}
name="paramSource"
render={({ field }) => (
<FormFieldItem className="space-y-2">
<FormFieldLabel></FormFieldLabel>
<FormControl>
<RadioGroup onValueChange={field.onChange} defaultValue={field.value} className="flex gap-4">
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="builtin" />
</FormControl>
<FormLabel className="font-normal"></FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="requestHeader" />
</FormControl>
<FormLabel className="font-normal"> Request Header </FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="requestParam" />
</FormControl>
<FormLabel className="font-normal"> Request Param </FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
{watchedParamSource === "builtin" && (
<FormField
control={form.control}
name="command"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel></FormFieldLabel>
<FormControl>
<Input placeholder="例如: whoami, id, hostname" {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{watchedParamSource === "requestParam" && (
<FormField
control={form.control}
name="requestParamName"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>Request Param Name</FormFieldLabel>
<FormControl>
<Input placeholder="例如: cmd, data, ..." {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{watchedParamSource === "requestHeader" && (
<FormField
control={form.control}
name="requestHeaderName"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>Request Header Name</FormFieldLabel>
<FormControl>
<Input placeholder="例如: cmd, data, ..." {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
</div>
)}
</>
);
}
// --- Sleep Delay ---
if (watchedEchoMethod === "sleep" && watchedEchoContent) {
return (
<div className="space-y-4 pt-4 border-t mt-4">
{watchedEchoContent === "middleware" && (
<div className="space-y-4">
<FormField
control={form.control}
name="sleepMiddleware"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel></FormFieldLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="选择中间件..." />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="tomcat">Tomcat</SelectItem>
<SelectItem value="jetty">Jetty</SelectItem>
<SelectItem value="springboot">Spring Boot</SelectItem>
<SelectItem value="weblogic">WebLogic</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormFieldItem>
)}
/>
<FormField
control={form.control}
name="sleepMiddlewareDelay"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel> ()</FormFieldLabel>
<FormControl>
<Input
type="number"
placeholder="例如: 5"
{...field}
onChange={(event) => field.onChange(+event.target.value)}
/>
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
</div>
)}
{watchedEchoContent === "os" && (
<div className="space-y-4">
<FormFieldLabel></FormFieldLabel>
{fields.map((item, index) => (
<div key={item.id} className="flex items-center gap-2">
<Controller
control={form.control}
name={`sleepOsDelays.${index}.os`}
render={({ field }) => (
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="linux">Linux</SelectItem>
<SelectItem value="windows">Windows</SelectItem>
<SelectItem value="macos">macOS</SelectItem>
</SelectContent>
</Select>
)}
/>
<Controller
control={form.control}
name={`sleepOsDelays.${index}.delay`}
render={({ field }) => (
<Input
type="number"
placeholder="延迟(秒)"
{...field}
onChange={(event) => field.onChange(+event.target.value)}
/>
)}
/>
<Button type="button" variant="destructive" size="icon" onClick={() => remove(index)}>
<Trash2 className="h-4 w-4" />
</Button>
</div>
))}
<Button type="button" variant="outline" size="sm" onClick={() => append({ os: "windows", delay: 10 })}>
</Button>
<FormMessage>{form.formState.errors.sleepOsDelays?.message}</FormMessage>
</div>
)}
{watchedEchoContent === "jdk" && (
<div className="space-y-4">
<FormField
control={form.control}
name="sleepJdkDetectionType"
render={({ field }) => (
<FormFieldItem className="space-y-2">
<FormFieldLabel>JDK </FormFieldLabel>
<FormControl>
<RadioGroup onValueChange={field.onChange} defaultValue={field.value} className="flex gap-4">
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="version" />
</FormControl>
<FormLabel className="font-normal"> ()</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-2">
<FormControl>
<RadioGroupItem value="type" />
</FormControl>
<FormLabel className="font-normal"> (JDK/JRE)</FormLabel>
</FormItem>
</RadioGroup>
</FormControl>
</FormFieldItem>
)}
/>
{watchedSleepJdkDetectionType === "version" && (
<FormField
control={form.control}
name="sleepJdkVersion"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>JDK </FormFieldLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="8">JDK 8</SelectItem>
<SelectItem value="11">JDK 11</SelectItem>
<SelectItem value="17">JDK 17</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{watchedSleepJdkDetectionType === "type" && (
<FormField
control={form.control}
name="sleepJdkType"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel></FormFieldLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="jdk">JDK</SelectItem>
<SelectItem value="jre">JRE</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormFieldItem>
)}
/>
)}
<FormField
control={form.control}
name="sleepJdkDelay"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel> ()</FormFieldLabel>
<FormControl>
<Input
type="number"
placeholder="例如: 5"
{...field}
onChange={(event) => field.onChange(+event.target.value)}
/>
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
</div>
)}
{watchedEchoContent === "bytecode" && (
<FormField
control={form.control}
name="sleepBytecodeSuccessDelay"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel> ()</FormFieldLabel>
<FormControl>
<Input
type="number"
placeholder="例如: 8"
{...field}
onChange={(event) => field.onChange(+event.target.value)}
/>
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
</div>
);
}
return null;
};
return (
<div className="max-w-4xl mx-auto p-6 space-y-6">
<Card>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<CardContent className="mt-2">
<FormField
control={form.control}
name="echoMethod"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel></FormFieldLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="header">Response Header</SelectItem>
<SelectItem value="body">Response Body</SelectItem>
<SelectItem value="dnslog">DNSLog</SelectItem>
<SelectItem value="httplog">HTTPLog</SelectItem>
<SelectItem value="sleep">Sleep </SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormFieldItem>
)}
/>
{/* --- 根据回显方式出现的特定字段 --- */}
{(watchedEchoMethod === "header" || watchedEchoMethod === "body") && (
<FormField
control={form.control}
name="middlewareType"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel></FormFieldLabel>
<FormDescription> Request/Response </FormDescription>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="选择中间件..." />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="tomcat">Tomcat</SelectItem>
<SelectItem value="jetty">Jetty</SelectItem>
<SelectItem value="springboot">Spring Boot</SelectItem>
<SelectItem value="weblogic">WebLogic</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{watchedEchoMethod === "header" && (
<FormField
control={form.control}
name="headerName"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>Response Header Name</FormFieldLabel>
<FormControl>
<Input placeholder="例如: X-Echo-Result" {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
)}
{(watchedEchoMethod === "dnslog" || watchedEchoMethod === "httplog") && (
<>
<Alert className="mt-2 mb-2">
<AlertTriangle className="h-4 w-4" />
<AlertTitle></AlertTitle>
<AlertDescription>访 ()</AlertDescription>
</Alert>
<FormField
control={form.control}
name="logAddress"
render={({ field }) => (
<FormFieldItem>
<FormFieldLabel>{watchedEchoMethod === "dnslog" ? "DNSLog" : "HTTPLog"} </FormFieldLabel>
<FormControl>
<Input placeholder="例如: abcde.dnslog.cn" {...field} />
</FormControl>
<FormMessage />
</FormFieldItem>
)}
/>
</>
)}
{watchedEchoMethod && renderContentOptions()}
{renderDynamicFields()}
</CardContent>
<CardFooter className="mt-2">
<Button type="submit"></Button>
</CardFooter>
</form>
</Form>
</Card>
</div>
);
}
+296
View File
@@ -0,0 +1,296 @@
import { motion } from "framer-motion";
import {
CombineIcon,
GithubIcon,
MinimizeIcon,
ServerIcon,
ShellIcon,
Shield,
ShieldCheckIcon,
TerminalIcon,
ZapIcon,
} from "lucide-react";
import { NavLink } from "react-router-dom";
import { LineShadowText } from "@/components/magicui/line-shadow-text";
import { RainbowButton } from "@/components/magicui/rainbow-button";
import { useTheme } from "@/components/theme-provider";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
export default function MemShellPartyLandingPage() {
const features = [
{
icon: <ShieldCheckIcon className="w-8 h-8 text-green-400" />,
title: "Non-Intrusive",
description:
"Generated memshells don't interfere with normal middleware traffic, even with multiple shells injected.",
},
{
icon: <ZapIcon className="w-8 h-8 text-yellow-400" />,
title: "High Availability",
description: "Comes with comprehensive CI integration tests, covering mainstream middleware for reliability.",
},
{
icon: <MinimizeIcon className="w-8 h-8 text-blue-400" />,
title: "Minimal Size",
description: "The core code of the memshell is kept as concise as possible for efficient transfer and injection.",
},
{
icon: <CombineIcon className="w-8 h-8 text-purple-400" />,
title: "Strong Compatibility",
description: "Covers common middleware and frameworks like Tomcat, WebLogic, and Spring.",
},
];
const supportedMiddleware = [
"Tomcat",
"Jetty",
"GlassFish",
"Payara",
"Resin",
"SpringWebMVC",
"SpringWebFlux",
"XXL-JOB",
"JBossAS",
"JBossEAP",
"WildFly",
"Undertow",
"WebLogic",
"WebSphere",
"BES",
"TongWeb",
"InforSuite AS",
"Apusic AS",
"Primeton",
];
const supportedShells = [
"Godzilla",
"Behinder",
"AntSword",
"Suo5",
"Neo-reGeorg",
"Command Execution",
"Custom Shell",
];
const theme = useTheme();
const shadowColor = theme.theme === "dark" ? "#ffffff" : "#000000";
return (
<div className="min-h-screen font-sans bg-background text-foreground">
<section className="relative text-center py-20 overflow-hidden">
<div className="absolute top-0 left-0 w-full h-full bg-grid-black/[0.05] dark:bg-grid-white/[0.05] [mask-image:linear-gradient(to_bottom,white_10%,transparent_100%)]" />
<div className="container mx-auto px-4 relative z-10">
<motion.div initial={{ opacity: 0, y: -50 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8 }}>
<div className="inline-flex items-center px-4 py-2 rounded-full border sm:h-8 mb-8 transition-colors dark:bg-red-900/20 dark:border-red-800 dark:text-red-300 bg-red-50 border-red-200 text-red-700">
<Shield className="w-4 h-4 mr-2" />
<span className="text-sm">For Security Research & Authorized Testing Only</span>
</div>
<h1 className="text-5xl md:text-7xl font-bold mb-8">
<span className="dark:text-white text-gray-900">
MemShell
<LineShadowText className="italic" shadowColor={shadowColor}>
Party
</LineShadowText>
</span>
</h1>
<p className="text-xl md:text-2xl mb-12 max-w-4xl mx-auto leading-relaxed text-muted-foreground">
A self-hosted, visual platform for one-click generation of Java memory shells for common middleware and
frameworks. The ultimate learning platform for security researchers.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.3 }}
className="mt-8 flex justify-center gap-4 flex-wrap"
>
<NavLink to="/memshell">
<Button size="lg">
<TerminalIcon className="mr-2 h-5 w-5" />
Get Started
</Button>
</NavLink>
<a href="https://github.com/ReaJason/MemShellParty" target="_blank" rel="noopener noreferrer">
<Button size="lg" variant="outline">
<GithubIcon className="mr-2 h-5 w-5" />
View on GitHub
</Button>
</a>
</motion.div>
</div>
</section>
<section className="py-20 bg-secondary/30">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold tracking-tight">Why Choose MemShellParty?</h2>
<p className="mt-3 text-lg text-muted-foreground">Designed for modern offensive and defensive scenarios.</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{features.map((feature, index) => (
<motion.div
key={feature.title}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ delay: index * 0.1 }}
>
<Card className="h-full border-border/60 bg-card">
<CardHeader className="flex flex-row items-center gap-4">
{feature.icon}
<CardTitle className="text-lg">{feature.title}</CardTitle>
</CardHeader>
<CardContent>
<CardDescription>{feature.description}</CardDescription>
</CardContent>
</Card>
</motion.div>
))}
</div>
</div>
</section>
<section className="py-20">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold tracking-tight">Extensive Support Matrix</h2>
<p className="mt-3 text-lg text-muted-foreground">
Compatible with a wide range of industry-standard technologies.
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ duration: 0.5 }}
>
<Card className="h-full">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<ServerIcon className="w-6 h-6" />
Supported Middleware
</CardTitle>
</CardHeader>
<CardContent className="flex flex-wrap gap-2 mt-2">
{supportedMiddleware.map((tech) => (
<Badge key={tech} variant="secondary" className="text-base py-1 px-3">
{tech}
</Badge>
))}
</CardContent>
</Card>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ duration: 0.5 }}
>
<Card className="h-full">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<ShellIcon className="w-6 h-6" />
Supported Shell Tools
</CardTitle>
</CardHeader>
<CardContent className="flex flex-wrap gap-2 mt-2">
{supportedShells.map((shell) => (
<Badge key={shell} variant="secondary" className="text-base py-1 px-3">
{shell}
</Badge>
))}
</CardContent>
</Card>
</motion.div>
</div>
</div>
</section>
<section className="py-20">
<div className="container mx-auto px-4">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold tracking-tight">Get Your Shell in 3 Simple Steps</h2>
<p className="mt-3 text-lg text-muted-foreground">A streamlined process from selection to generation.</p>
</div>
<div className="max-w-4xl mx-auto grid grid-cols-1 md:grid-cols-3 gap-8 text-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ delay: 0.1 }}
className="flex flex-col items-center"
>
<div className="flex items-center justify-center w-16 h-16 rounded-full bg-primary text-primary-foreground text-2xl font-bold mb-4">
1
</div>
<h3 className="text-xl font-semibold mb-2">Select Middleware</h3>
<p className="text-muted-foreground">Choose your target environment like Tomcat or Spring.</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ delay: 0.2 }}
className="flex flex-col items-center"
>
<div className="flex items-center justify-center w-16 h-16 rounded-full bg-primary text-primary-foreground text-2xl font-bold mb-4">
2
</div>
<h3 className="text-xl font-semibold mb-2">Configure Shell</h3>
<p className="text-muted-foreground">Pick a shell type and set parameters like passwords or keys.</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.5 }}
transition={{ delay: 0.3 }}
className="flex flex-col items-center"
>
<div className="flex items-center justify-center w-16 h-16 rounded-full bg-primary text-primary-foreground text-2xl font-bold mb-4">
3
</div>
<h3 className="text-xl font-semibold mb-2">Generate Payload</h3>
<p className="text-muted-foreground">Click generate to get the final payload for your operation.</p>
</motion.div>
</div>
</div>
</section>
{/* --- Final CTA Section --- */}
<section className="py-20 text-center bg-secondary/30">
<div className="container mx-auto px-4">
<h2 className="text-3xl md:text-4xl font-bold tracking-tight">Ready to Join the Party?</h2>
<p className="mt-4 text-lg text-muted-foreground max-w-xl mx-auto">
Visit the GitHub repository to start your memshell exploration, or contribute to the project!
</p>
<div className="mt-8">
<a href="https://github.com/ReaJason/MemShellParty" target="_blank" rel="noopener noreferrer">
<RainbowButton size="lg">
<GithubIcon className="mr-2 h-5 w-5" />
Star & Fork on GitHub
</RainbowButton>
</a>
</div>
</div>
</section>
{/* --- Footer --- */}
<footer className="border-t py-8">
<div className="container mx-auto px-4 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between text-center sm:text-left">
<div>
<p className="text-sm font-semibold">MemShellParty</p>
<p className="text-xs">
Built with by{" "}
<a href="https://reajason.eu.org" rel="noreferrer noopener" target="_blank" className="font-medium">
ReaJason
</a>
</p>
</div>
</div>
</footer>
</div>
);
}
@@ -1,3 +1,10 @@
import { useQuery } from "@tanstack/react-query";
import { LoaderCircle, WandSparklesIcon } from "lucide-react";
import { useState, useTransition } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useLoaderData } from "react-router-dom";
import { toast } from "sonner";
import { MainConfigCard } from "@/components/main-config-card.tsx";
import { PackageConfigCard } from "@/components/package-config-card.tsx";
import { ShellResult } from "@/components/shell-result.tsx";
@@ -15,15 +22,8 @@ import {
ShellToolType,
} from "@/types/shell.ts";
import { transformToPostData } from "@/utils/transformer.ts";
import { useQuery } from "@tanstack/react-query";
import { LoaderCircle, WandSparklesIcon } from "lucide-react";
import { useState, useTransition } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { useLoaderData } from "react-router-dom";
import { toast } from "sonner";
export default function IndexPage() {
export default function MemShellPage() {
const urlParams = useLoaderData();
const { data: serverConfig } = useQuery<ServerConfig>({