From 6be832494d45ebeb99b2d96428c7cfd3123f000a Mon Sep 17 00:00:00 2001 From: ReaJason Date: Fri, 28 Feb 2025 22:40:21 +0800 Subject: [PATCH] refactor(ui): separate each component into single file --- web/bun.lockb | Bin 207420 -> 197404 bytes web/package.json | 14 +- web/src/components/main-config-card.tsx | 410 ++---------------- web/src/components/results/agent.tsx | 60 +++ web/src/components/results/basic-info.tsx | 140 ++++++ web/src/components/results/feedback-alert.tsx | 49 +++ web/src/components/results/jar-result.tsx | 24 + web/src/components/results/multi-packer.tsx | 63 +++ .../components/results/result-component.tsx | 57 +++ web/src/components/shell-result.tsx | 380 +--------------- web/src/components/tools/antsword-tab.tsx | 64 +++ web/src/components/tools/behinder-tab.tsx | 64 +++ web/src/components/tools/classname-field.tsx | 37 ++ web/src/components/tools/command-tab.tsx | 44 ++ web/src/components/tools/godzilla-tab.tsx | 74 ++++ web/src/components/tools/neoreg-tab.tsx | 51 +++ web/src/components/tools/shelltype-field.tsx | 44 ++ web/src/components/tools/suo5-tab.tsx | 51 +++ web/src/components/tools/urlpattern-field.tsx | 26 ++ web/src/routes/index.tsx | 2 +- web/src/types/shell.ts | 18 + web/vite.config.ts | 2 +- 22 files changed, 925 insertions(+), 749 deletions(-) create mode 100644 web/src/components/results/agent.tsx create mode 100644 web/src/components/results/basic-info.tsx create mode 100644 web/src/components/results/feedback-alert.tsx create mode 100644 web/src/components/results/jar-result.tsx create mode 100644 web/src/components/results/multi-packer.tsx create mode 100644 web/src/components/results/result-component.tsx create mode 100644 web/src/components/tools/antsword-tab.tsx create mode 100644 web/src/components/tools/behinder-tab.tsx create mode 100644 web/src/components/tools/classname-field.tsx create mode 100644 web/src/components/tools/command-tab.tsx create mode 100644 web/src/components/tools/godzilla-tab.tsx create mode 100644 web/src/components/tools/neoreg-tab.tsx create mode 100644 web/src/components/tools/shelltype-field.tsx create mode 100644 web/src/components/tools/suo5-tab.tsx create mode 100644 web/src/components/tools/urlpattern-field.tsx diff --git a/web/bun.lockb b/web/bun.lockb index 7cc671c71eb7399cf5ffcfcda032279800adf0d9..fc1d67d763a8555cc3d555d3451093bce0b6b15e 100755 GIT binary patch delta 22399 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 U^*ZTqSe;%$&%VtSkJ_vM7lyVwV*mgE delta 26985 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 U=(E#WDsD;kfK_a9EI;G_0gl*K_5c6? diff --git a/web/package.json b/web/package.json index 653534fd..811a7389 100644 --- a/web/package.json +++ b/web/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@tanstack/router-plugin": "^1.111.7", + "@tanstack/router-plugin": "^1.112.0", "@types/node": "^22.13.5", "@types/react": "^19.0.10", "@types/react-copy-to-clipboard": "^5.0.7", @@ -23,7 +23,7 @@ "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-react": "^4.3.4", "rimraf": "^6.0.1", - "tailwindcss": "^4.0.8", + "tailwindcss": "^4.0.9", "typescript": "^5.7.3", "vite": "^6.2.0", "vite-bundle-visualizer": "^1.2.1" @@ -41,14 +41,14 @@ "@radix-ui/react-switch": "^1.1.3", "@radix-ui/react-tabs": "^1.1.3", "@radix-ui/react-tooltip": "^1.1.8", - "@tailwindcss/vite": "^4.0.8", - "@tanstack/react-query": "^5.66.9", - "@tanstack/react-router": "^1.111.7", - "@tanstack/router-devtools": "^1.111.7", + "@tailwindcss/vite": "^4.0.9", + "@tanstack/react-query": "^5.66.11", + "@tanstack/react-router": "^1.112.0", + "@tanstack/router-devtools": "^1.112.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "i18next": "^24.2.2", - "lucide-react": "^0.475.0", + "lucide-react": "^0.476.0", "react": "^19.0.0", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^19.0.0", diff --git a/web/src/components/main-config-card.tsx b/web/src/components/main-config-card.tsx index 8bd0f5d1..be0559d8 100644 --- a/web/src/components/main-config-card.tsx +++ b/web/src/components/main-config-card.tsx @@ -1,12 +1,10 @@ -import { UrlPatternTip } from "@/components/tips/url-pattern-tip.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 { Switch } from "@/components/ui/switch.tsx"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { FormSchema } from "@/types/schema.ts"; -import { MainConfig } from "@/types/shell.ts"; +import { JDKVersion, MainConfig, ShellToolType } from "@/types/shell.ts"; import { JreTip } from "@/components/tips/jre-tip.tsx"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"; @@ -23,25 +21,20 @@ import { import { JSX, useState } from "react"; import { FormProvider, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; - -const JDKVersion = [ - { name: "Java6", value: "50" }, - { name: "Java8", value: "52" }, - { name: "Java9", value: "53" }, - { name: "Java11", value: "55" }, - { name: "Java17", value: "61" }, - { name: "Java21", value: "65" }, -]; - -type ShellToolType = "Behinder" | "Godzilla" | "Command" | "AntSword" | "Suo5" | "Neo-reGeorg"; +import { AntSwordTabContent } from "./tools/antsword-tab"; +import { BehinderTabContent } from "./tools/behinder-tab"; +import { CommandTabContent } from "./tools/command-tab"; +import { GodzillaTabContent } from "./tools/godzilla-tab"; +import { NeoRegTabContent } from "./tools/neoreg-tab"; +import { Suo5TabContent } from "./tools/suo5-tab"; const shellToolIcons: Record = { - Behinder: , - Godzilla: , - Command: , - AntSword: , - Suo5: , - "Neo-reGeorg": , + [ShellToolType.Behinder]: , + [ShellToolType.Godzilla]: , + [ShellToolType.Command]: , + [ShellToolType.AntSword]: , + [ShellToolType.Suo5]: , + [ShellToolType.NeoreGeorg]: , }; export function MainConfigCard({ @@ -56,13 +49,13 @@ export function MainConfigCard({ const [shellToolMap, setShellToolMap] = useState<{ [toolName: string]: string[]; }>(); - const [shellTools, setShellTools] = useState([ - "Behinder", - "Godzilla", - "Command", - "AntSword", - "Suo5", - "Neo-reGeorg", + const [shellTools, setShellTools] = useState([ + ShellToolType.Godzilla, + ShellToolType.Behinder, + ShellToolType.AntSword, + ShellToolType.Command, + ShellToolType.Suo5, + ShellToolType.NeoreGeorg, ]); const [shellTypes, setShellTypes] = useState([]); const shellTool = form.watch("shellTool"); @@ -73,7 +66,7 @@ export function MainConfigCard({ const newShellToolMap = mainConfig[value]; setShellToolMap(newShellToolMap); const newShellTools = Object.keys(newShellToolMap); - setShellTools(newShellTools); + setShellTools(newShellTools.map((tool) => tool as ShellToolType)); if (newShellTools.length > 0) { const firstTool = newShellTools[0]; setShellTypes(newShellToolMap[firstTool]); @@ -126,22 +119,29 @@ export function MainConfigCard({ form.resetField("headerValue"); }; + const resetNeoreGeorg = () => { + form.setValue("headerName", "Referer"); + form.resetField("headerValue"); + }; + if (shellToolMap) { setShellTypes(shellToolMap[value]); form.resetField("urlPattern"); form.resetField("shellType"); form.resetField("shellClassName"); form.resetField("injectorClassName"); - if (value === "Godzilla") { + if (value === ShellToolType.Godzilla) { resetGodzilla(); - } else if (value === "Behinder") { + } else if (value === ShellToolType.Behinder) { resetBehinder(); - } else if (value === "Command") { + } else if (value === ShellToolType.Command) { resetCommand(); - } else if (value === "Suo5") { + } else if (value === ShellToolType.Suo5) { resetSuo5(); - } else if (value === "AntSword") { + } else if (value === ShellToolType.AntSword) { resetAntSword(); + } else if (value === ShellToolType.NeoreGeorg) { + resetNeoreGeorg(); } } form.setValue("shellTool", value); @@ -282,7 +282,7 @@ export function MainConfigCard({ }} className="w-full" > -
+
{shellTools.map((shellTool) => (
- + - + ); } - -function ShellTypeFormField({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { - const { t } = useTranslation(); - return ( - - ( - - {t("mainConfig.shellMountType")} - - - )} - /> - - ); -} - -function UrlPatternFormField({ form }: { form: UseFormReturn }) { - const { t } = useTranslation(); - return ( - - ( - - - {t("mainConfig.urlPattern")} - - - - )} - /> - - ); -} - -function OptionalClassFormField({ form }: { form: UseFormReturn }) { - const { t } = useTranslation(); - return ( - - ( - - - {t("mainConfig.shellClassName")} {t("optional")} - - - - )} - /> - ( - - - {t("mainConfig.injectorClassName")} {t("optional")} - - - - )} - /> - - ); -} - -function BehinderTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { - const { t } = useTranslation(); - return ( - - - - -
- - -
- ( - - {t("shellToolConfig.behinderPass")} - - - )} - /> -
- ( - - {t("shellToolConfig.headerName")} - - - )} - /> - ( - - {t("shellToolConfig.headerValue")} - - - )} - /> -
- -
-
-
-
- ); -} - -function GodzillaTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { - const { t } = useTranslation(); - return ( - - - - -
- - -
-
- ( - - {t("shellToolConfig.pass")} - - - )} - /> - ( - - {t("shellToolConfig.key")} - - - )} - /> - ( - - {t("shellToolConfig.headerName")} - - - )} - /> - ( - - {t("shellToolConfig.headerValue")} - - - )} - /> -
- -
-
-
-
- ); -} - -function CommandTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { - const { t } = useTranslation(); - return ( - - - - -
- - -
- ( - - {t("shellToolConfig.paramName")} - - - - - )} - /> - -
-
-
-
- ); -} - -function AntSwordTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { - const { t } = useTranslation(); - return ( - - - - -
- - -
- ( - - {t("shellToolConfig.antSwordPass")} - - - )} - /> -
- ( - - {t("shellToolConfig.headerName")} - - - )} - /> - ( - - {t("shellToolConfig.headerValue")} - - - )} - /> -
- -
-
-
-
- ); -} - -function Suo5TabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { - const { t } = useTranslation(); - return ( - - - - -
- - -
-
- ( - - {t("shellToolConfig.headerName")} - - - )} - /> - ( - - {t("shellToolConfig.headerValue")} - - - )} - /> -
- -
-
-
-
- ); -} - -function NeoreGeorgTabContent() { - return ( - - - -
- WIP -
-
-
-
- ); -} diff --git a/web/src/components/results/agent.tsx b/web/src/components/results/agent.tsx new file mode 100644 index 00000000..9cce853a --- /dev/null +++ b/web/src/components/results/agent.tsx @@ -0,0 +1,60 @@ +import { downloadBytes } from "@/lib/utils"; +import { GenerateResult } from "@/types/shell"; +import { Separator } from "@radix-ui/react-dropdown-menu"; +import { ScrollTextIcon } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { Button } from "../ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; + +export function AgentResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { + const { t } = useTranslation(); + return ( + + + + + {t("generateResult.usage")} + + + +
    +
  1. + {t("download")} MemShellAgent.jar + +
  2. +
  3. + {t("tips.download-jattach")} + +
  4. + +
  5. {t("tips.move-to-container")}
  6. +
  7. {t("tips.get-pid")}
  8. +
  9. {t("tips.execute-command")}
  10. +
  11. {t("tips.try-to-use-shell")}
  12. +
+
+
+ ); +} diff --git a/web/src/components/results/basic-info.tsx b/web/src/components/results/basic-info.tsx new file mode 100644 index 00000000..e3ea4e02 --- /dev/null +++ b/web/src/components/results/basic-info.tsx @@ -0,0 +1,140 @@ +import { + AntSwordShellToolConfig, + BehinderShellToolConfig, + CommandShellToolConfig, + GenerateResult, + GodzillaShellToolConfig, + Suo5ShellToolConfig, +} from "@/types/shell"; +import { Separator } from "@radix-ui/react-dropdown-menu"; +import { FileTextIcon } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { Fragment } from "react/jsx-runtime"; +import { CopyableField } from "../copyable-field"; +import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"; +import { FeedbackAlert } from "./feedback-alert"; + +export function BasicInfo({ generateResult }: { generateResult?: GenerateResult }) { + const { t } = useTranslation(); + return ( + + + +
+ + {t("generateResult.basicInfo")} +
+ +
+
+ +
+ + + + +
+ + + {(generateResult?.shellConfig.shellTool === "Behinder" || + generateResult?.shellConfig.shellTool === "Godzilla" || + generateResult?.shellConfig.shellTool === "Command" || + generateResult?.shellConfig.shellTool === "AntSword" || + generateResult?.shellConfig.shellTool === "Suo5") && ( +
+ {/* Tool-specific fields */} + {generateResult?.shellConfig.shellTool === "Behinder" && ( + <> + + + + + + )} + {generateResult?.shellConfig.shellTool === "Godzilla" && ( + + + + + + + + )} + {generateResult?.shellConfig.shellTool === "Command" && ( + + + + )} + {generateResult?.shellConfig.shellTool === "Suo5" && ( + + + + )} + {generateResult?.shellConfig.shellTool === "AntSword" && ( + + + + + )} +
+ )} + +
+ + +
+
+
+ ); +} diff --git a/web/src/components/results/feedback-alert.tsx b/web/src/components/results/feedback-alert.tsx new file mode 100644 index 00000000..e9d2900a --- /dev/null +++ b/web/src/components/results/feedback-alert.tsx @@ -0,0 +1,49 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogTitle, + AlertDialogTrigger, +} from "@radix-ui/react-alert-dialog"; +import { CircleHelpIcon } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { AlertDialogFooter, AlertDialogHeader } from "../ui/alert-dialog"; +import { Button } from "../ui/button"; + +export function FeedbackAlert() { + const { t } = useTranslation(); + return ( + + + + + + + {t("shellNotWork.title")} + +
    +
  1. {t("shellNotWork.step1")}
  2. +
  3. {t("shellNotWork.step2")}
  4. +
+
+
+ + {t("cancel")} + + 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", + ) + } + > + {t("feedback")} + + +
+
+ ); +} diff --git a/web/src/components/results/jar-result.tsx b/web/src/components/results/jar-result.tsx new file mode 100644 index 00000000..3951e36a --- /dev/null +++ b/web/src/components/results/jar-result.tsx @@ -0,0 +1,24 @@ +import { downloadBytes } from "@/lib/utils"; +import { GenerateResult } from "@/types/shell"; +import { useTranslation } from "react-i18next"; +import { Button } from "../ui/button"; + +export function JarResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { + const { t } = useTranslation(); + return ( +
+ +
+ ); +} diff --git a/web/src/components/results/multi-packer.tsx b/web/src/components/results/multi-packer.tsx new file mode 100644 index 00000000..7d14642e --- /dev/null +++ b/web/src/components/results/multi-packer.tsx @@ -0,0 +1,63 @@ +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@radix-ui/react-select"; +import { TFunction } from "i18next"; +import { useEffect, useState } from "react"; +import { Fragment } from "react/jsx-runtime"; +import { CodeViewer } from "../code-viewer"; + +export function MultiPackResult({ + allPackResults, + packMethod, + t, +}: { + allPackResults: object | undefined; + packMethod: string; + t: TFunction; +}) { + const showCode = packMethod === "JSP"; + const packMethods = Object.keys(allPackResults ?? {}); + const [selectedMethod, setSelectedMethod] = useState(packMethods[0]); + const [packResult, setPackResult] = useState(allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? ""); + + useEffect(() => { + const methods = Object.keys(allPackResults ?? {}); + const firstMethod = methods[0]; + setSelectedMethod(firstMethod); + setPackResult(allPackResults?.[firstMethod as keyof typeof allPackResults] ?? ""); + }, [allPackResults]); + + return ( + + + + ({packResult?.length}) +
+ } + wrapLongLines={!showCode} + showLineNumbers={showCode} + language={showCode ? "java" : "text"} + height={350} + /> + + ); +} diff --git a/web/src/components/results/result-component.tsx b/web/src/components/results/result-component.tsx new file mode 100644 index 00000000..383b7daf --- /dev/null +++ b/web/src/components/results/result-component.tsx @@ -0,0 +1,57 @@ +import { GenerateResult } from "@/types/shell"; +import { TFunction } from "i18next"; +import { Fragment } from "react/jsx-runtime"; +import { CodeViewer } from "../code-viewer"; +import { AgentResult } from "./agent"; +import { JarResult } from "./jar-result"; +import { MultiPackResult } from "./multi-packer"; + +export function ResultComponent({ + packResult, + allPackResults, + packMethod, + t, + generateResult, +}: { + packResult: string | undefined; + allPackResults: Map | undefined; + packMethod: string; + t: TFunction; + generateResult?: GenerateResult; +}) { + const showCode = packMethod === "JSP"; + const isAgent = packMethod.startsWith("Agent"); + const isJar = packMethod === "Jar"; + if (allPackResults) { + return ; + } + + if (isAgent) { + return ; + } + if (isJar) { + return ; + } + if (!isAgent && !isJar) { + return ( + + + + {t("packageConfig.title")}:{packMethod} + + ({packResult?.length}) + + } + wrapLongLines={!showCode} + showLineNumbers={showCode} + language={showCode ? "java" : "text"} + height={350} + /> + + ); + } + return null; +} diff --git a/web/src/components/shell-result.tsx b/web/src/components/shell-result.tsx index e29adddd..41881e71 100644 --- a/web/src/components/shell-result.tsx +++ b/web/src/components/shell-result.tsx @@ -1,373 +1,15 @@ 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Separator } from "@/components/ui/separator.tsx"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx"; import { downloadBytes } from "@/lib/utils.ts"; -import { - AntSwordShellToolConfig, - BehinderShellToolConfig, - CommandShellToolConfig, - GenerateResult, - GodzillaShellToolConfig, - Suo5ShellToolConfig, -} from "@/types/shell.ts"; -import { TFunction } from "i18next"; -import { CircleHelpIcon, FileTextIcon, ScrollTextIcon, TriangleAlertIcon } from "lucide-react"; -import { Fragment, useEffect, useState } from "react"; +import { GenerateResult } from "@/types/shell.ts"; +import { TriangleAlertIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; - -function AgentResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { - const { t } = useTranslation(); - return ( - - - - - {t("generateResult.usage")} - - - -
    -
  1. - {t("download")} MemShellAgent.jar - -
  2. -
  3. - {t("tips.download-jattach")} - -
  4. - -
  5. {t("tips.move-to-container")}
  6. -
  7. {t("tips.get-pid")}
  8. -
  9. {t("tips.execute-command")}
  10. -
  11. {t("tips.try-to-use-shell")}
  12. -
-
-
- ); -} - -function JarResult({ packResult, generateResult }: { packResult: string; generateResult?: GenerateResult }) { - const { t } = useTranslation(); - return ( -
- -
- ); -} - -function FeedbackAlert() { - const { t } = useTranslation(); - return ( - - - - - - - {t("shellNotWork.title")} - -
    -
  1. {t("shellNotWork.step1")}
  2. -
  3. {t("shellNotWork.step2")}
  4. -
-
-
- - {t("cancel")} - - 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", - ) - } - > - {t("feedback")} - - -
-
- ); -} - -function BasicInfo({ generateResult }: { generateResult?: GenerateResult }) { - const { t } = useTranslation(); - return ( - - - -
- - {t("generateResult.basicInfo")} -
- -
-
- -
- - - - -
- - - {(generateResult?.shellConfig.shellTool === "Behinder" || - generateResult?.shellConfig.shellTool === "Godzilla" || - generateResult?.shellConfig.shellTool === "Command" || - generateResult?.shellConfig.shellTool === "AntSword" || - generateResult?.shellConfig.shellTool === "Suo5") && ( -
- {/* Tool-specific fields */} - {generateResult?.shellConfig.shellTool === "Behinder" && ( - <> - - - - - - )} - {generateResult?.shellConfig.shellTool === "Godzilla" && ( - - - - - - - - )} - {generateResult?.shellConfig.shellTool === "Command" && ( - - - - )} - {generateResult?.shellConfig.shellTool === "Suo5" && ( - - - - )} - {generateResult?.shellConfig.shellTool === "AntSword" && ( - - - - - )} -
- )} - -
- - -
-
-
- ); -} - -function MultiPackResult({ - allPackResults, - packMethod, - t, -}: { - allPackResults: object | undefined; - packMethod: string; - t: TFunction; -}) { - const showCode = packMethod === "JSP"; - const packMethods = Object.keys(allPackResults ?? {}); - const [selectedMethod, setSelectedMethod] = useState(packMethods[0]); - const [packResult, setPackResult] = useState(allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? ""); - - useEffect(() => { - const methods = Object.keys(allPackResults ?? {}); - const firstMethod = methods[0]; - setSelectedMethod(firstMethod); - setPackResult(allPackResults?.[firstMethod as keyof typeof allPackResults] ?? ""); - }, [allPackResults]); - - return ( - - - - ({packResult?.length}) - - } - wrapLongLines={!showCode} - showLineNumbers={showCode} - language={showCode ? "java" : "text"} - height={350} - /> - - ); -} - -function renderResultComponent( - packResult: string | undefined, - allPackResults: Map | undefined, - packMethod: string, - t: TFunction, - generateResult?: GenerateResult, -) { - const showCode = packMethod === "JSP"; - const isAgent = packMethod.startsWith("Agent"); - const isJar = packMethod === "Jar"; - if (allPackResults) { - return ; - } - - if (isAgent) { - return ; - } - if (isJar) { - return ; - } - if (!isAgent && !isJar) { - return ( - - - - {t("packageConfig.title")}:{packMethod} - - ({packResult?.length}) - - } - wrapLongLines={!showCode} - showLineNumbers={showCode} - language={showCode ? "java" : "text"} - height={350} - /> - - ); - } - return null; -} +import { BasicInfo } from "./results/basic-info"; +import { ResultComponent } from "./results/result-component"; export function ShellResult({ packResult, @@ -391,11 +33,15 @@ export function ShellResult({ {t("generateResult.title2")} {t("generateResult.title3")} - -
- -
- {renderResultComponent(packResult, allPackResults, packMethod, t, generateResult)} + + + diff --git a/web/src/components/tools/antsword-tab.tsx b/web/src/components/tools/antsword-tab.tsx new file mode 100644 index 00000000..03ea2d61 --- /dev/null +++ b/web/src/components/tools/antsword-tab.tsx @@ -0,0 +1,64 @@ +import { FormSchema } from "@/types/schema"; +import { TabsContent } from "@radix-ui/react-tabs"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Card, CardContent } from "../ui/card"; +import { FormField, FormItem, FormLabel } from "../ui/form"; +import { Input } from "../ui/input"; +import { OptionalClassFormField } from "./classname-field"; +import { ShellTypeFormField } from "./shelltype-field"; +import { UrlPatternFormField } from "./urlpattern-field"; + +export function AntSwordTabContent({ + form, + shellTypes, +}: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + + + +
+ + +
+ ( + + {t("shellToolConfig.antSwordPass")} + + + )} + /> +
+ ( + + {t("shellToolConfig.headerName")} + + + )} + /> + ( + + {t("shellToolConfig.headerValue")} + + + )} + /> +
+ +
+
+
+
+ ); +} diff --git a/web/src/components/tools/behinder-tab.tsx b/web/src/components/tools/behinder-tab.tsx new file mode 100644 index 00000000..0c207d6d --- /dev/null +++ b/web/src/components/tools/behinder-tab.tsx @@ -0,0 +1,64 @@ +import { FormSchema } from "@/types/schema"; +import { TabsContent } from "@radix-ui/react-tabs"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Card, CardContent } from "../ui/card"; +import { FormField, FormItem, FormLabel } from "../ui/form"; +import { Input } from "../ui/input"; +import { OptionalClassFormField } from "./classname-field"; +import { ShellTypeFormField } from "./shelltype-field"; +import { UrlPatternFormField } from "./urlpattern-field"; + +export function BehinderTabContent({ + form, + shellTypes, +}: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + + + +
+ + +
+ ( + + {t("shellToolConfig.behinderPass")} + + + )} + /> +
+ ( + + {t("shellToolConfig.headerName")} + + + )} + /> + ( + + {t("shellToolConfig.headerValue")} + + + )} + /> +
+ +
+
+
+
+ ); +} diff --git a/web/src/components/tools/classname-field.tsx b/web/src/components/tools/classname-field.tsx new file mode 100644 index 00000000..443d9eba --- /dev/null +++ b/web/src/components/tools/classname-field.tsx @@ -0,0 +1,37 @@ +import { FormField, FormItem, FormLabel } from "@/components/ui/form.tsx"; +import { Input } from "@/components/ui/input.tsx"; +import { FormSchema } from "@/types/schema.ts"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; + +export function OptionalClassFormField({ form }: { form: UseFormReturn }) { + const { t } = useTranslation(); + return ( + + ( + + + {t("mainConfig.shellClassName")} {t("optional")} + + + + )} + /> + ( + + + {t("mainConfig.injectorClassName")} {t("optional")} + + + + )} + /> + + ); +} diff --git a/web/src/components/tools/command-tab.tsx b/web/src/components/tools/command-tab.tsx new file mode 100644 index 00000000..c03cb9e5 --- /dev/null +++ b/web/src/components/tools/command-tab.tsx @@ -0,0 +1,44 @@ +import { FormSchema } from "@/types/schema"; +import { TabsContent } from "@radix-ui/react-tabs"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Card, CardContent } from "../ui/card"; +import { FormControl, FormField, FormItem, FormLabel } from "../ui/form"; +import { Input } from "../ui/input"; +import { OptionalClassFormField } from "./classname-field"; +import { ShellTypeFormField } from "./shelltype-field"; +import { UrlPatternFormField } from "./urlpattern-field"; + +export function CommandTabContent({ + form, + shellTypes, +}: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + + + +
+ + +
+ ( + + {t("shellToolConfig.paramName")} + + + + + )} + /> + +
+
+
+
+ ); +} diff --git a/web/src/components/tools/godzilla-tab.tsx b/web/src/components/tools/godzilla-tab.tsx new file mode 100644 index 00000000..a9ecad5b --- /dev/null +++ b/web/src/components/tools/godzilla-tab.tsx @@ -0,0 +1,74 @@ +import { FormSchema } from "@/types/schema"; +import { TabsContent } from "@radix-ui/react-tabs"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Card, CardContent } from "../ui/card"; +import { FormField, FormItem, FormLabel } from "../ui/form"; +import { Input } from "../ui/input"; +import { OptionalClassFormField } from "./classname-field"; +import { ShellTypeFormField } from "./shelltype-field"; +import { UrlPatternFormField } from "./urlpattern-field"; + +export function GodzillaTabContent({ + form, + shellTypes, +}: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + + + +
+ + +
+
+ ( + + {t("shellToolConfig.pass")} + + + )} + /> + ( + + {t("shellToolConfig.key")} + + + )} + /> + ( + + {t("shellToolConfig.headerName")} + + + )} + /> + ( + + {t("shellToolConfig.headerValue")} + + + )} + /> +
+ +
+
+
+
+ ); +} diff --git a/web/src/components/tools/neoreg-tab.tsx b/web/src/components/tools/neoreg-tab.tsx new file mode 100644 index 00000000..99308f04 --- /dev/null +++ b/web/src/components/tools/neoreg-tab.tsx @@ -0,0 +1,51 @@ +import { FormSchema } from "@/types/schema"; +import { TabsContent } from "@radix-ui/react-tabs"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Card, CardContent } from "../ui/card"; +import { FormField, FormItem, FormLabel } from "../ui/form"; +import { Input } from "../ui/input"; +import { OptionalClassFormField } from "./classname-field"; +import { ShellTypeFormField } from "./shelltype-field"; +import { UrlPatternFormField } from "./urlpattern-field"; + +export function NeoRegTabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + + + +
+ + +
+
+ ( + + {t("shellToolConfig.headerName")} + + + )} + /> + ( + + {t("shellToolConfig.headerValue")} + + + )} + /> +
+ +
+
+
+
+ ); +} diff --git a/web/src/components/tools/shelltype-field.tsx b/web/src/components/tools/shelltype-field.tsx new file mode 100644 index 00000000..1eedbde6 --- /dev/null +++ b/web/src/components/tools/shelltype-field.tsx @@ -0,0 +1,44 @@ +import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx"; +import { FormSchema } from "@/types/schema.ts"; + +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; + +export function ShellTypeFormField({ + form, + shellTypes, +}: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + ( + + {t("mainConfig.shellMountType")} + + + )} + /> + + ); +} diff --git a/web/src/components/tools/suo5-tab.tsx b/web/src/components/tools/suo5-tab.tsx new file mode 100644 index 00000000..ba07f27c --- /dev/null +++ b/web/src/components/tools/suo5-tab.tsx @@ -0,0 +1,51 @@ +import { FormSchema } from "@/types/schema"; +import { TabsContent } from "@radix-ui/react-tabs"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { Card, CardContent } from "../ui/card"; +import { FormField, FormItem, FormLabel } from "../ui/form"; +import { Input } from "../ui/input"; +import { OptionalClassFormField } from "./classname-field"; +import { ShellTypeFormField } from "./shelltype-field"; +import { UrlPatternFormField } from "./urlpattern-field"; + +export function Suo5TabContent({ form, shellTypes }: { form: UseFormReturn; shellTypes: Array }) { + const { t } = useTranslation(); + return ( + + + + +
+ + +
+
+ ( + + {t("shellToolConfig.headerName")} + + + )} + /> + ( + + {t("shellToolConfig.headerValue")} + + + )} + /> +
+ +
+
+
+
+ ); +} diff --git a/web/src/components/tools/urlpattern-field.tsx b/web/src/components/tools/urlpattern-field.tsx new file mode 100644 index 00000000..0fbfc08f --- /dev/null +++ b/web/src/components/tools/urlpattern-field.tsx @@ -0,0 +1,26 @@ +import { UrlPatternTip } from "@/components/tips/url-pattern-tip.tsx"; +import { FormField, FormItem, FormLabel } from "@/components/ui/form.tsx"; +import { Input } from "@/components/ui/input.tsx"; +import { FormSchema } from "@/types/schema.ts"; +import { FormProvider, UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; + +export function UrlPatternFormField({ form }: { form: UseFormReturn }) { + const { t } = useTranslation(); + return ( + + ( + + + {t("mainConfig.urlPattern")} + + + + )} + /> + + ); +} diff --git a/web/src/routes/index.tsx b/web/src/routes/index.tsx index e557a31d..962cbfaf 100644 --- a/web/src/routes/index.tsx +++ b/web/src/routes/index.tsx @@ -37,7 +37,7 @@ function IndexComponent() { debug: false, bypassJavaModule: false, shellClassName: "", - shellTool: "Behinder", + shellTool: "Godzilla", shellType: "", urlPattern: "/*", godzillaPass: "pass", diff --git a/web/src/types/shell.ts b/web/src/types/shell.ts index 5c2e6c08..eb489563 100644 --- a/web/src/types/shell.ts +++ b/web/src/types/shell.ts @@ -94,3 +94,21 @@ export interface GenerateResult { shellToolConfig: CommandShellToolConfig | GodzillaShellToolConfig | BehinderShellToolConfig | AntSwordShellToolConfig; injectorConfig: InjectorConfig; } + +export const JDKVersion = [ + { name: "Java6", value: "50" }, + { name: "Java8", value: "52" }, + { name: "Java9", value: "53" }, + { name: "Java11", value: "55" }, + { name: "Java17", value: "61" }, + { name: "Java21", value: "65" }, +]; + +export enum ShellToolType { + Behinder = "Behinder", + Godzilla = "Godzilla", + Command = "Command", + AntSword = "AntSword", + Suo5 = "Suo5", + NeoreGeorg = "NeoreGeorg", +} diff --git a/web/vite.config.ts b/web/vite.config.ts index e912c489..e96f8f42 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -6,7 +6,7 @@ import { defineConfig } from "vite"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [TanStackRouterVite(), react(), tailwindcss()], + plugins: [TanStackRouterVite({ autoCodeSplitting: true }), react(), tailwindcss()], resolve: { alias: { "@": path.resolve(__dirname, "./src"),