From 24a9b563e639a00f0b1d82b68b4f80fe69579c18 Mon Sep 17 00:00:00 2001 From: ReaJason Date: Sat, 18 Jan 2025 20:00:24 +0800 Subject: [PATCH] refactor: enhance web ux --- web/bun.lockb | Bin 161588 -> 163060 bytes web/package.json | 26 +- web/src/components/code-viewer.tsx | 10 +- web/src/components/copyable-field.tsx | 24 +- web/src/components/main-config-card.tsx | 519 +++++++++++---------- web/src/components/package-config-card.tsx | 25 +- web/src/components/quick-usage.tsx | 20 + web/src/components/shell-result.tsx | 410 +++++++++------- web/src/components/tips/jre-tip.tsx | 6 +- web/src/config.ts | 8 +- web/src/main.tsx | 3 +- web/src/routes/index.tsx | 63 +-- web/src/types/shell.ts | 10 +- web/src/utils/transformer.ts | 1 + web/tsconfig.app.tsbuildinfo | 2 +- web/tsconfig.node.tsbuildinfo | 2 +- 16 files changed, 649 insertions(+), 480 deletions(-) create mode 100644 web/src/components/quick-usage.tsx diff --git a/web/bun.lockb b/web/bun.lockb index b59e5fa4de87b7612a6d3ffa623f894c485511f7..c7910757afc4438062b3add59e371df29163f278 100755 GIT binary patch delta 17204 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 IDg4L(2fIx3ssI20 diff --git a/web/package.json b/web/package.json index b3a4ff40..197cdc7a 100644 --- a/web/package.json +++ b/web/package.json @@ -13,21 +13,21 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@tanstack/router-plugin": "^1.93.0", - "@types/node": "^22.10.3", - "@types/react": "^19.0.2", - "@types/react-dom": "^19.0.2", + "@tanstack/router-plugin": "^1.97.1", + "@types/node": "^22.10.7", + "@types/react": "^19.0.7", + "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-syntax-highlighter": "^15.5.13", "autoprefixer": "^10.4.20", - "postcss": "^8.4.49", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", - "typescript": "^5.7.2", - "vite": "^6.0.6" + "typescript": "^5.7.3", + "vite": "^6.0.7" }, "dependencies": { - "@hookform/resolvers": "^3.9.1", + "@hookform/resolvers": "^3.10.0", "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-checkbox": "^1.1.3", "@radix-ui/react-dropdown-menu": "^2.1.4", @@ -39,19 +39,19 @@ "@radix-ui/react-switch": "^1.1.2", "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.6", - "@tanstack/react-query": "^5.62.11", - "@tanstack/react-router": "^1.93.0", - "@tanstack/router-devtools": "^1.93.0", + "@tanstack/react-query": "^5.64.1", + "@tanstack/react-router": "^1.97.1", + "@tanstack/router-devtools": "^1.97.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.469.0", + "lucide-react": "^0.473.0", "next-themes": "^0.4.4", "react": "^19.0.0", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^19.0.0", "react-hook-form": "^7.54.2", "react-syntax-highlighter": "^15.6.1", - "sonner": "^1.7.1", + "sonner": "^1.7.2", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "zod": "^3.24.1" diff --git a/web/src/components/code-viewer.tsx b/web/src/components/code-viewer.tsx index 1ae10e9e..68c1656c 100644 --- a/web/src/components/code-viewer.tsx +++ b/web/src/components/code-viewer.tsx @@ -1,6 +1,6 @@ import { Button, ButtonProps } from "@/components/ui/button.tsx"; import { cn } from "@/lib/utils.ts"; -import { CheckIcon, ClipboardIcon } from "lucide-react"; +import { Check, Copy } from "lucide-react"; import { HTMLProps, useEffect, useState } from "react"; import { CopyToClipboard } from "react-copy-to-clipboard"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; @@ -35,11 +35,11 @@ export function CopyButton({ value, className, src, variant = "ghost", ...props size="icon" type="button" variant={variant} - className={cn("relative z-10 h-6 w-6 text-zinc-50 hover:bg-zinc-700 hover:text-zinc-50", className)} + className={cn("relative z-10 h-8 w-8 text-zinc-50 hover:bg-zinc-700 hover:text-zinc-50", className)} {...props} > Copy - {hasCopied ? : } + {hasCopied ? : } ); @@ -50,11 +50,13 @@ export function CodeViewer({ language, showLineNumbers = true, wrapLongLines = false, + height = 500, }: { code: string; language: string; showLineNumbers?: boolean; wrapLongLines?: boolean; + height?: number; }) { const lineProps: lineTagPropsFunction | HTMLProps | undefined = wrapLongLines ? { style: { overflowWrap: "break-word", whiteSpace: "pre-wrap" } } @@ -73,7 +75,7 @@ export function CodeViewer({ paddingRight: showLineNumbers ? 0 : 24, paddingLeft: showLineNumbers ? 0 : 24, borderRadius: "var(--radius)", - height: 500, + height: height, whiteSpace: wrapLongLines ? "pre-wrap" : "pre", overflowWrap: wrapLongLines ? "normal" : "break-word", }} diff --git a/web/src/components/copyable-field.tsx b/web/src/components/copyable-field.tsx index 28f02cc3..0f39e288 100644 --- a/web/src/components/copyable-field.tsx +++ b/web/src/components/copyable-field.tsx @@ -8,10 +8,10 @@ import { toast } from "sonner"; interface CopyableFieldProps { label: string; value?: string; - size?: number; + text?: string; } -export function CopyableField({ label, value, size }: CopyableFieldProps) { +export function CopyableField({ label, value, text }: CopyableFieldProps) { const [copied, setCopied] = useState(false); const copyToClipboard = useCallback(() => { @@ -27,18 +27,18 @@ export function CopyableField({ label, value, size }: CopyableFieldProps) { }, [value, label]); return ( -

+
- -

- {value} {size != null && `(${size} bytes)`} -

+ +

{text}

- - - + {value && ( + + + + )}
); } diff --git a/web/src/components/main-config-card.tsx b/web/src/components/main-config-card.tsx index 86214079..59ef91ed 100644 --- a/web/src/components/main-config-card.tsx +++ b/web/src/components/main-config-card.tsx @@ -1,15 +1,17 @@ import { UrlPatternTip } from "@/components/tips/url-pattern-tip.tsx"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx"; import { Input } from "@/components/ui/input.tsx"; import { Label } from "@/components/ui/label.tsx"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx"; -import { Separator } from "@/components/ui/separator.tsx"; import { Switch } from "@/components/ui/switch.tsx"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { FormSchema } from "@/types/schema.ts"; import { MainConfig } from "@/types/shell.ts"; -import { ServerIcon } from "lucide-react"; +import { JreTip } from "@/components/tips/jre-tip.tsx"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; +import { cn } from "@/lib/utils.ts"; +import { ArrowUpRightIcon, ServerIcon } from "lucide-react"; import { useState } from "react"; import { FormProvider, UseFormReturn } from "react-hook-form"; @@ -32,14 +34,23 @@ export function MainConfigCard({ servers?: string[]; }) { const [shellToolMap, setShellToolMap] = useState<{ [toolName: string]: string[] }>(); - const [shellTools, setShellTools] = useState([]); + const [shellTools, setShellTools] = useState(["Behinder", "Godzilla", "Command"]); const [shellTypes, setShellTypes] = useState([]); + const shellTool = form.watch("shellTool"); const handleServerChange = (value: string) => { if (mainConfig) { - setShellToolMap(mainConfig[value]); - setShellTools(Object.keys(mainConfig[value])); - setShellTypes([]); + const newShellToolMap = mainConfig[value]; + setShellToolMap(newShellToolMap); + const newShellTools = Object.keys(newShellToolMap); + setShellTools(newShellTools); + if (newShellTools.length > 0) { + const firstTool = newShellTools[0]; + setShellTypes(newShellToolMap[firstTool]); + form.setValue("shellTool", firstTool); + } else { + setShellTypes([]); + } form.resetField("shellTool"); form.resetField("shellType"); } @@ -66,6 +77,9 @@ export function MainConfigCard({ if (shellToolMap) { setShellTypes(shellToolMap[value]); form.resetField("urlPattern"); + form.resetField("shellType"); + form.resetField("shellClassName"); + form.resetField("injectorClassName"); if (value === "Godzilla") { resetGodzilla(); } else if (value === "Behinder") { @@ -74,17 +88,18 @@ export function MainConfigCard({ resetCommand(); } } + form.setValue("shellTool", value); }; return ( - - - - - 核心配置 - - - + + + + + + 生成配置 + +
+ + 下拉列表找不到目标服务 ? + + 请求适配 + + + )} /> @@ -120,8 +147,10 @@ export function MainConfigCard({ control={form.control} name="targetJdkVersion" render={({ field }) => ( - - JRE(可选) + + - - )} - /> -
- ( - - 内存马工具类型 - - - )} - /> - ( - - 内存马挂载类型 - - - )} - /> - ( - - - + )} />
-
- {form.getValues().shellTool === "Godzilla" && ( -
- -
- ( - - - - - )} - /> - ( - - - - - )} - /> - ( - - - - - )} - /> - ( - - - - - )} - /> -
-
- )} - {form.getValues().shellTool === "Behinder" && ( -
- -
- ( - - - - - )} - /> - ( - - - - - )} - /> - ( - - - - - )} - /> -
-
- )} - {form.getValues().shellTool === "Command" && ( + + + { + handleShellToolChange(v); + }} + className="w-full" + > + + {shellTools.map((shellTool) => ( + + {shellTool} + + ))} + + + + + + + ); +} + +function ShellTypeFormField({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { + return ( + + ( + + 内存马挂载类型 + + + )} + /> + + ); +} + +function UrlPatternFormField({ form }: { form: UseFormReturn }) { + return ( + + ( + + + + + )} + /> + + ); +} + +function OptionalClassFormField({ form }: { form: UseFormReturn }) { + return ( + + ( + + 内存马类名(可选) + + + )} + /> + ( + + 注入器类名(可选) + + + )} + /> + + ); +} + +function BehinderTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { + return ( + + + + +
+ + +
+ ( + + 连接密码 + + + )} + /> +
( - 请求参数 - - - - 填写接收命令的请求参数,例如填 cmd 即 `?cmd=whoami` 来执行命令 + 请求头键 + )} /> - )} -
- - ( - - 注入器类名(可选) - - - )} - /> -
- - -
-
-
- + ( + + 请求头值 + + + )} + /> +
+ + + + + + ); +} + +function GodzillaTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { + return ( + + + + +
+ + +
+
+ ( + + 密码 + + + )} + /> + ( + + 密钥 + + + )} + /> + ( + + 请求头键 + + + )} + /> + ( + + 请求头值 + + + )} + /> +
+ +
+
+
+
+ ); +} + +function CommandTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { + return ( + + + + +
+ + +
+ ( + + 请求参数 + + + + 填写接收命令的请求参数,例如填 cmd 即 `?cmd=whoami` 来执行命令 + + )} + /> + +
+
+
+
); } diff --git a/web/src/components/package-config-card.tsx b/web/src/components/package-config-card.tsx index f1db2962..a1afdd80 100644 --- a/web/src/components/package-config-card.tsx +++ b/web/src/components/package-config-card.tsx @@ -4,6 +4,7 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group.tsx"; import { FormSchema } from "@/types/schema.ts"; import { PackerConfig } from "@/types/shell.ts"; import { PackageIcon } from "lucide-react"; +import { useEffect, useState } from "react"; import { FormProvider, UseFormReturn } from "react-hook-form"; export function PackageConfigCard({ @@ -13,6 +14,26 @@ export function PackageConfigCard({ packerConfig: PackerConfig | undefined; form: UseFormReturn; }) { + const [options, setOptions] = useState>>([]); + + const shellType = form.watch("shellType"); + + useEffect(() => { + const filteredOptions = Object.entries(packerConfig ?? {}).filter(([name, _]) => { + if (!shellType || shellType === " ") { + return true; + } + if (shellType.startsWith("Agent")) { + return name.startsWith("Agent"); + } + return !name.startsWith("Agent"); + }); + setOptions(filteredOptions); + if (filteredOptions.length > 0) { + form.setValue("packingMethod", filteredOptions[0][0]); + } + }, [form, packerConfig, shellType]); // Add shellType to the dependency array + return ( @@ -30,8 +51,8 @@ export function PackageConfigCard({ 打包方式 - - {Object.entries(packerConfig ?? {}).map(([name, value]) => ( + + {options.map(([name, value]) => ( diff --git a/web/src/components/quick-usage.tsx b/web/src/components/quick-usage.tsx new file mode 100644 index 00000000..8cf06ca9 --- /dev/null +++ b/web/src/components/quick-usage.tsx @@ -0,0 +1,20 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; + +export function QuickUsage() { + return ( + + + 快速使用 + + +
    +
  1. 选择目标服务
  2. +
  3. 选择内存马功能,Godzilla、Behinder 或者其他
  4. +
  5. 选择内存马挂载类型,Filter、Listener 或者其他
  6. +
  7. 选择打包方式
  8. +
  9. 点击生成内存马
  10. +
+
+
+ ); +} diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index 5585281b..aeaa14f3 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -1,57 +1,194 @@ import { CodeViewer } from "@/components/code-viewer.tsx"; import { CopyableField } from "@/components/copyable-field.tsx"; +import { QuickUsage } from "@/components/quick-usage.tsx"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx"; import { Button } from "@/components/ui/button.tsx"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; -import { Label } from "@/components/ui/label.tsx"; import { Separator } from "@/components/ui/separator.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx"; import { downloadBytes } from "@/lib/utils.ts"; -import { GenerateResult } from "@/types/shell.ts"; -import { TicketsIcon, TriangleAlertIcon } from "lucide-react"; +import { + BehinderShellToolConfig, + CommandShellToolConfig, + GenerateResult, + GodzillaShellToolConfig, +} from "@/types/shell.ts"; +import { CircleHelpIcon, TriangleAlertIcon } from "lucide-react"; +import { Fragment } from "react"; function AgentResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { return ( -
-
    -
  1. - 下载 MemShellAgent.jar - +
  2. +
  3. + 下载 Jattach 工具(后期考虑直接封装在 Jar 中) + +
  4. + +
  5. 将 MemShellAgent.jar 和 jattach 移动到容器中(如果测试环境使用容器部署)
  6. +
  7. 获取目标 jvm 的进程 pid (使用 jps 或 ps)
  8. +
  9. 执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar
  10. +
  11. 尝试利用内存马
  12. +
+ + + ); +} + +function FeedbackAlert() { + return ( + + + + + + + 内存马利用失败 ? + +
    +
  1. 1. 尝试开启调试模式,重新生成内存马并注入,查看控制台或日志
  2. +
  3. 2. 如果出现异常堆栈信息,或未见异常,请截图当前生成界面以及异常日志,并尽可能描述目标环境进行反馈
  4. +
+
+
+ + 取消 + - downloadBytes( - packResult, - undefined, - `${generateResult?.shellConfig.server}${generateResult?.shellConfig.shellTool}MemShellAgent`, + window.open( + "https://github.com/ReaJason/MemShellParty/issues/new?template=%E5%86%85%E5%AD%98%E9%A9%AC%E7%94%9F%E6%88%90-bug-%E4%B8%8A%E6%8A%A5.md", ) } > - 下载 Jar - - -
  • - 下载 Jattach 工具(后期考虑直接封装在 Jar 中) - -
  • - -

    使用方法:

    -
  • 将 MemShellAgent.jar 和 jattach 移动到容器中(如果测试环境使用容器部署)
  • -
  • 获取目标 jvm 的进程 pid (使用 jps 或 ps)
  • -
  • 执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar
  • -
  • 尝试连接测试
  • - -
    + 反馈 + + + + + ); +} + +function BasicInfo({ generateResult }: { generateResult?: GenerateResult }) { + return ( + + + + 基础信息 + + + + +
    + + +
    + + + {generateResult?.shellConfig.shellTool === "Behinder" && ( + + + + + + + )} + {generateResult?.shellConfig.shellTool === "Godzilla" && ( + + + + + + + + )} + {generateResult?.shellConfig.shellTool === "Command" && ( + + + + )} + + +
    +
    ); } @@ -63,125 +200,80 @@ export function ShellResult({ const showCode = packMethod === "JSP"; const isAgent = packMethod.startsWith("Agent"); return ( - - - - - FBI - - - - - - 打包结果 - 内存马类 - 注入器类 - - - {generateResult && !isAgent && ( -
    - - -
    - )} - {!isAgent && ( - - )} - {isAgent && } -
    - - - - Warning - 反编译还在开发中,因此当前仅能看到 base64 编码格式 - -
    - {generateResult && ( -
    -
    - -

    {generateResult?.shellClassName}

    -
    -
    - -

    {generateResult?.shellSize ?? 0} bytes

    -
    -
    - )} - {generateResult && ( - - )} -
    - -
    - - - - Warning - 反编译还在开发中,因此当前仅能看到 base64 编码格式 - -
    - {generateResult && ( -
    -
    - -

    {generateResult?.injectorClassName}

    -
    -
    - -

    {generateResult?.injectorSize ?? 0} bytes

    -
    -
    - )} - {generateResult && ( - - )} -
    - -
    -
    -
    -
    + + + 打包结果 + 内存马类 + 注入器类 + + +
    + {generateResult && } + {!generateResult && } +
    + {!isAgent && ( + + )} + {isAgent && } +
    + + + + Warning + 反编译还在开发中,因此当前仅能看到 base64 编码格式 + +
    + {generateResult && ( + + )} +
    + +
    + + + + Warning + 反编译还在开发中,因此当前仅能看到 base64 编码格式 + +
    + {generateResult && ( + + )} +
    + +
    +
    ); } diff --git a/web/src/components/tips/jre-tip.tsx b/web/src/components/tips/jre-tip.tsx index fedd5cad..2fdad5ed 100644 --- a/web/src/components/tips/jre-tip.tsx +++ b/web/src/components/tips/jre-tip.tsx @@ -1,15 +1,15 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx"; import { InfoIcon } from "lucide-react"; -export function JRETip() { +export function JreTip() { return ( - + -

    目标 JRE 版本,一般而言为了最大的兼容性,默认 Java 6 即可。

    +

    目标 JRE 版本,一般而言为了最大的兼容性,默认 Java 6 即可,Java 高版本能加载低版本的字节码。

    特定情况下,例如 JDK8 才能使用 lambda 表达式,JDK9 以上存在模块限制时才需要选择特定的版本。

    diff --git a/web/src/config.ts b/web/src/config.ts index 6998524b..729555e3 100644 --- a/web/src/config.ts +++ b/web/src/config.ts @@ -2,16 +2,20 @@ import * as z from "zod"; const EnvSchema = z.object({ API_URL: z.optional(z.string()), + MODE: z.string(), }); const createEnv = () => { // @ts-ignore const envVars = Object.entries(import.meta.env).reduce>((acc, curr) => { const [key, value] = curr; - if (key.startsWith("VITE_APP_")) { - if (typeof value === "string") { + if (typeof value === "string") { + if (key.startsWith("VITE_APP_")) { acc[key.replace("VITE_APP_", "")] = value; } + if (key === "MODE") { + acc[key] = value; + } } return acc; }, {}); diff --git a/web/src/main.tsx b/web/src/main.tsx index 84c89347..969f6d6e 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -4,6 +4,7 @@ import { routeTree } from "./routeTree.gen"; import "./index.css"; import { TailwindIndicator } from "@/components/tailwind-indicator.tsx"; import { Toaster } from "@/components/ui/sonner.tsx"; +import { env } from "@/config.ts"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; const queryClient = new QueryClient(); @@ -27,7 +28,7 @@ if (!rootElement.innerHTML) { - + {env.MODE !== "production" && } , ); } diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index 667aeed1..1a84b809 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -1,7 +1,6 @@ import { MainConfigCard } from "@/components/main-config-card.tsx"; import { PackageConfigCard } from "@/components/package-config-card.tsx"; import { ShellResult } from "@/components/shell-result.tsx"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx"; import { Button } from "@/components/ui/button"; import { Form } from "@/components/ui/form.tsx"; import { env } from "@/config.ts"; @@ -11,7 +10,7 @@ import { transformToPostData } from "@/utils/transformer.ts"; import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery } from "@tanstack/react-query"; import { createFileRoute } from "@tanstack/react-router"; -import { ActivityIcon, LoaderCircle, ServerOffIcon, WandSparklesIcon } from "lucide-react"; +import { LoaderCircle, WandSparklesIcon } from "lucide-react"; import { useState, useTransition } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -21,7 +20,7 @@ export const Route = createFileRoute("/")({ }); function IndexComponent() { - const { isPending, isError, data } = useQuery({ + const { data } = useQuery({ queryKey: ["config"], queryFn: async () => { const response = await fetch(`${env.API_URL}/config`); @@ -36,7 +35,7 @@ function IndexComponent() { debug: false, bypassJavaModule: false, shellClassName: "", - shellTool: "", + shellTool: "Behinder", shellType: "", urlPattern: "/*", godzillaPass: "pass", @@ -123,46 +122,20 @@ function IndexComponent() { } return ( -
    -
    - {isPending && ( - - - Pending - 正在全力搜索可用的后端服务~ - - )} - {isError && ( - - - Not Work! - 未检测到可用后端服务,生成功能暂不可用. - - )} - - {!isError && data && ( - - - It Work! - Let's start the party! 🎉 - - )} -
    -
    - -
    - - - -
    -
    - -
    -
    - -
    +
    + +
    + + + +
    +
    + +
    +
    + ); } diff --git a/web/src/types/shell.ts b/web/src/types/shell.ts index 49afd18a..2146e9ed 100644 --- a/web/src/types/shell.ts +++ b/web/src/types/shell.ts @@ -33,8 +33,16 @@ export interface GodzillaShellToolConfig { headerValue?: string; } +export interface BehinderShellToolConfig { + shellClassName?: string; + pass?: string; + headerName?: string; + headerValue?: string; +} + export interface InjectorConfig { className?: string; + classInheritance?: string; urlPattern?: string; } @@ -71,6 +79,6 @@ export interface GenerateResult { injectorSize: number; injectorBytesBase64Str: string; shellConfig: ShellConfig; - shellToolConfig: CommandShellToolConfig | GodzillaShellToolConfig; + shellToolConfig: CommandShellToolConfig | GodzillaShellToolConfig | BehinderShellToolConfig; injectorConfig: InjectorConfig; } diff --git a/web/src/utils/transformer.ts b/web/src/utils/transformer.ts index 03a354e6..ddeb85a8 100644 --- a/web/src/utils/transformer.ts +++ b/web/src/utils/transformer.ts @@ -6,6 +6,7 @@ export function transformToPostData(formValue: FormSchema) { server: formValue.server, shellTool: formValue.shellTool, shellType: formValue.shellType, + debug: formValue.debug, targetJreVersion: formValue.targetJdkVersion, byPassJavaModule: formValue.bypassJavaModule, }; diff --git a/web/tsconfig.app.tsbuildinfo b/web/tsconfig.app.tsbuildinfo index 0e95ab56..8bc8a6b8 100644 --- a/web/tsconfig.app.tsbuildinfo +++ b/web/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/config.ts","./src/main.tsx","./src/routetree.gen.ts","./src/components/code-viewer.tsx","./src/components/main-config-card.tsx","./src/components/mode-toggle.tsx","./src/components/package-config-card.tsx","./src/components/shell-result.tsx","./src/components/tailwind-indicator.tsx","./src/components/theme-provider.tsx","./src/components/tips/jre-tip.tsx","./src/components/tips/url-pattern-tip.tsx","./src/components/ui/alert.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/form.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/radio-group.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sonner.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/components/ui/tooltip.tsx","./src/lib/utils.ts","./src/routes/__root.tsx","./src/routes/index.tsx","./src/types/schema.ts","./src/types/shell.ts","./src/utils/transformer.ts"],"version":"5.7.2"} \ No newline at end of file +{"root":["./src/config.ts","./src/main.tsx","./src/routetree.gen.ts","./src/components/code-viewer.tsx","./src/components/copyable-field.tsx","./src/components/main-config-card.tsx","./src/components/mode-toggle.tsx","./src/components/package-config-card.tsx","./src/components/quick-usage.tsx","./src/components/shell-result.tsx","./src/components/tailwind-indicator.tsx","./src/components/theme-provider.tsx","./src/components/tips/jre-tip.tsx","./src/components/tips/url-pattern-tip.tsx","./src/components/ui/alert-dialog.tsx","./src/components/ui/alert.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/checkbox.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/form.tsx","./src/components/ui/input.tsx","./src/components/ui/label.tsx","./src/components/ui/radio-group.tsx","./src/components/ui/select.tsx","./src/components/ui/separator.tsx","./src/components/ui/sonner.tsx","./src/components/ui/switch.tsx","./src/components/ui/tabs.tsx","./src/components/ui/textarea.tsx","./src/components/ui/tooltip.tsx","./src/lib/utils.ts","./src/routes/__root.tsx","./src/routes/index.tsx","./src/types/schema.ts","./src/types/shell.ts","./src/utils/transformer.ts"],"version":"5.7.3"} \ No newline at end of file diff --git a/web/tsconfig.node.tsbuildinfo b/web/tsconfig.node.tsbuildinfo index 1e7ed279..0440098c 100644 --- a/web/tsconfig.node.tsbuildinfo +++ b/web/tsconfig.node.tsbuildinfo @@ -1 +1 @@ -{"root":["./vite.config.ts"],"version":"5.7.2"} \ No newline at end of file +{"root":["./vite.config.ts"],"version":"5.7.3"} \ No newline at end of file