mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: support i18n namespace
This commit is contained in:
@@ -6,7 +6,7 @@ export function LanguageSwitcher() {
|
|||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
const toggleLanguage = () => {
|
const toggleLanguage = () => {
|
||||||
const newLang = i18n.language === "en" ? "zh" : "en";
|
const newLang = i18n.language === "en" ? "zh-CN" : "en";
|
||||||
i18n.changeLanguage(newLang);
|
i18n.changeLanguage(newLang);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { InfoIcon } from "lucide-react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx";
|
|
||||||
|
|
||||||
export function JreTip() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
return (
|
|
||||||
<TooltipProvider>
|
|
||||||
<Tooltip>
|
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<InfoIcon className="cursor-pointer h-4" />
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>{t("tips.jreTip")}</p>
|
|
||||||
<p>{t("tips.jreTip2")}</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</TooltipProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -92,7 +92,7 @@ export default function MainConfigCard({
|
|||||||
]);
|
]);
|
||||||
const [shellTypes, setShellTypes] = useState<string[]>([]);
|
const [shellTypes, setShellTypes] = useState<string[]>([]);
|
||||||
const shellTool = form.watch("shellTool");
|
const shellTool = form.watch("shellTool");
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "memshell"]);
|
||||||
|
|
||||||
const [serverVersionOptions, setServerVersionOptions] = useState(
|
const [serverVersionOptions, setServerVersionOptions] = useState(
|
||||||
defaultServerVersionOptions,
|
defaultServerVersionOptions,
|
||||||
@@ -137,7 +137,7 @@ export default function MainConfigCard({
|
|||||||
) {
|
) {
|
||||||
form.setValue("targetJdkVersion", "52");
|
form.setValue("targetJdkVersion", "52");
|
||||||
} else {
|
} else {
|
||||||
form.resetField("targetJdkVersion");
|
form.setValue("targetJdkVersion", "50");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 特殊的服务需要指定版本
|
// 特殊的服务需要指定版本
|
||||||
@@ -259,7 +259,7 @@ export default function MainConfigCard({
|
|||||||
<CardHeader className="pb-1">
|
<CardHeader className="pb-1">
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<ServerIcon className="h-5" />
|
<ServerIcon className="h-5" />
|
||||||
<span>{t("configs.main-config")}</span>
|
<span>{t("common:mainConfig.title")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -269,7 +269,7 @@ export default function MainConfigCard({
|
|||||||
name="server"
|
name="server"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("mainConfig.server")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:server")}</FormFieldLabel>
|
||||||
<Select
|
<Select
|
||||||
onValueChange={(v) => {
|
onValueChange={(v) => {
|
||||||
field.onChange(v);
|
field.onChange(v);
|
||||||
@@ -279,7 +279,9 @@ export default function MainConfigCard({
|
|||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t("placeholders.select")} />
|
<SelectValue
|
||||||
|
placeholder={t("common:placeholders.select")}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -291,14 +293,14 @@ export default function MainConfigCard({
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FormDescription className="flex items-center">
|
<FormDescription className="flex items-center">
|
||||||
{t("tips.targetServerNotFound")}
|
{t("memshell:tips.targetServerNotFound")}
|
||||||
<a
|
<a
|
||||||
href="https://github.com/ReaJason/MemShellParty/issues/new?template=%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D.md"
|
href="https://github.com/ReaJason/MemShellParty/issues/new?template=%E8%AF%B7%E6%B1%82%E9%80%82%E9%85%8D.md"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className="flex items-center underline"
|
className="flex items-center underline"
|
||||||
>
|
>
|
||||||
{t("tips.targetServerRequest")}
|
{t("memshell:tips.targetServerRequest")}
|
||||||
<ArrowUpRightIcon className="h-4" />
|
<ArrowUpRightIcon className="h-4" />
|
||||||
</a>
|
</a>
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
@@ -310,11 +312,13 @@ export default function MainConfigCard({
|
|||||||
name="serverVersion"
|
name="serverVersion"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("mainConfig.serverVersion")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:serverVersion")}</FormFieldLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value}>
|
<Select onValueChange={field.onChange} value={field.value}>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t("placeholders.select")} />
|
<SelectValue
|
||||||
|
placeholder={t("common:placeholders.select")}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -337,9 +341,13 @@ export default function MainConfigCard({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch id={debugId} checked={field.value} onCheckedChange={field.onChange} />
|
<Switch
|
||||||
|
id="debug"
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormLabel htmlFor={debugId}>{t("mainConfig.debug")}</FormLabel>
|
<FormLabel htmlFor="debug">{t("common:debug")}</FormLabel>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -349,9 +357,13 @@ export default function MainConfigCard({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch id={bypassId} checked={field.value} onCheckedChange={field.onChange} />
|
<Switch
|
||||||
|
id="bypass"
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Label htmlFor={bypassId}>{t("mainConfig.byPassJavaModule")}</Label>
|
<Label htmlFor="bypass">{t("common:byPassJavaModule")}</Label>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -361,9 +373,13 @@ export default function MainConfigCard({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Switch id={shrinkId} checked={field.value} onCheckedChange={field.onChange} />
|
<Switch
|
||||||
|
id="shrink"
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<Label htmlFor={shrinkId}>{t("mainConfig.shrink")}</Label>
|
<Label htmlFor="shrink">{t("common:shrink")}</Label>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export default function PackageConfigCard({
|
|||||||
|
|
||||||
const shellType = form.watch("shellType");
|
const shellType = form.watch("shellType");
|
||||||
const server = form.watch("server");
|
const server = form.watch("server");
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation("common");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filteredOptions = (packerConfig ?? []).filter((name) => {
|
const filteredOptions = (packerConfig ?? []).filter((name) => {
|
||||||
@@ -52,7 +52,7 @@ export default function PackageConfigCard({
|
|||||||
|
|
||||||
const mappedOptions = filteredOptions.map((name) => {
|
const mappedOptions = filteredOptions.map((name) => {
|
||||||
return {
|
return {
|
||||||
name: t(`packageConfig.packer.${name}`),
|
name: t(name),
|
||||||
value: name,
|
value: name,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -72,7 +72,7 @@ export default function PackageConfigCard({
|
|||||||
<CardHeader className="pb-1">
|
<CardHeader className="pb-1">
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<PackageIcon className="h-5" />
|
<PackageIcon className="h-5" />
|
||||||
<span>{t("configs.package-config")}</span>
|
<span>{t("packerConfig.title")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -83,7 +83,7 @@ export default function PackageConfigCard({
|
|||||||
name="packingMethod"
|
name="packingMethod"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="space-y-3">
|
<FormItem className="space-y-3">
|
||||||
<FormLabel>{t("packageConfig.title")}</FormLabel>
|
<FormLabel>{t("packerMethod")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
|
|||||||
@@ -8,22 +8,22 @@ import {
|
|||||||
} from "@/components/ui/card.tsx";
|
} from "@/components/ui/card.tsx";
|
||||||
|
|
||||||
export function QuickUsage() {
|
export function QuickUsage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "memshell"]);
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<ScrollTextIcon className="h-5" />
|
<ScrollTextIcon className="h-5" />
|
||||||
<span>{t("quickUsage.title")}</span>
|
<span>{t("common:quickUsage.title")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ol className="list-decimal list-inside space-y-4 text-sm">
|
<ol className="list-decimal list-inside space-y-4 text-sm">
|
||||||
<li>{t("quickUsage.step1")}</li>
|
<li>{t("memshell:quickUsage.step1")}</li>
|
||||||
<li>{t("quickUsage.step2")}</li>
|
<li>{t("memshell:quickUsage.step2")}</li>
|
||||||
<li>{t("quickUsage.step3")}</li>
|
<li>{t("memshell:quickUsage.step3")}</li>
|
||||||
<li>{t("quickUsage.step4")}</li>
|
<li>{t("memshell:quickUsage.step4")}</li>
|
||||||
<li>{t("quickUsage.step5")}</li>
|
<li>{t("memshell:quickUsage.step5")}</li>
|
||||||
</ol>
|
</ol>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ export function AgentResult({
|
|||||||
packMethod,
|
packMethod,
|
||||||
packResult,
|
packResult,
|
||||||
generateResult,
|
generateResult,
|
||||||
}: Readonly<{ packMethod: string; packResult: string; generateResult?: MemShellResult }>) {
|
}: Readonly<{
|
||||||
|
packMethod: string;
|
||||||
|
packResult: string;
|
||||||
|
generateResult?: MemShellResult;
|
||||||
|
}>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isPureAgent = packMethod === "AgentJar";
|
const isPureAgent = packMethod === "AgentJar";
|
||||||
return (
|
return (
|
||||||
@@ -18,14 +22,15 @@ export function AgentResult({
|
|||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<ScrollTextIcon className="h-5" />
|
<ScrollTextIcon className="h-5" />
|
||||||
<span>{t("generateResult.usage")}</span>
|
<span>{t("common:usage")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ol className="list-decimal list-inside space-y-4 text-sm">
|
<ol className="list-decimal list-inside space-y-4 text-sm">
|
||||||
<li className="flex items-center justify-between">
|
<li className="flex items-center justify-between">
|
||||||
<span>
|
<span>
|
||||||
{t("download")} MemShellAgent.jar ({formatBytes(atob(packResult).length)})
|
{t("common:download")} MemShellAgent.jar (
|
||||||
|
{formatBytes(atob(packResult).length)})
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
@@ -40,28 +45,38 @@ export function AgentResult({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("download")}
|
{t("common:download")}
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
{isPureAgent && (
|
{isPureAgent && (
|
||||||
<li className="flex items-center justify-between">
|
<li className="flex items-center justify-between">
|
||||||
<span>{t("tips.download-jattach")}</span>
|
<span>{t("memshell:tips.download-jattach")}</span>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-28"
|
className="w-28"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => window.open("https://github.com/jattach/jattach/releases")}
|
onClick={() =>
|
||||||
|
window.open("https://github.com/jattach/jattach/releases")
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t("download")}
|
{t("common:download")}
|
||||||
</Button>
|
</Button>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
<Separator />
|
<Separator />
|
||||||
<li>{isPureAgent ? t("tips.agent-move-to-target") : t("tips.agent-move-to-target1")}</li>
|
<li>
|
||||||
<li>{t("tips.get-pid")}</li>
|
{isPureAgent
|
||||||
<li>{isPureAgent ? t("tips.execute-command") : t("tips.execute-command1")}</li>
|
? t("memshell:tips.agent-move-to-target")
|
||||||
<li>{t("tips.try-to-use-shell")}</li>
|
: t("memshell:tips.agent-move-to-target1")}
|
||||||
|
</li>
|
||||||
|
<li>{t("memshell:tips.get-pid")}</li>
|
||||||
|
<li>
|
||||||
|
{isPureAgent
|
||||||
|
? t("memshell:tips.execute-command")
|
||||||
|
: t("memshell:tips.execute-command1")}
|
||||||
|
</li>
|
||||||
|
<li>{t("memshell:tips.try-to-use-shell")}</li>
|
||||||
</ol>
|
</ol>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -16,24 +16,35 @@ import {
|
|||||||
import { CopyableField } from "../../copyable-field";
|
import { CopyableField } from "../../copyable-field";
|
||||||
import { FeedbackAlert } from "./feedback-alert";
|
import { FeedbackAlert } from "./feedback-alert";
|
||||||
|
|
||||||
export function BasicInfo({ generateResult }: Readonly<{ generateResult?: MemShellResult }>) {
|
export function BasicInfo({
|
||||||
const { t } = useTranslation();
|
generateResult,
|
||||||
|
}: Readonly<{ generateResult?: MemShellResult }>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="flex items-center justify-between">
|
<CardTitle className="flex items-center justify-between">
|
||||||
<div className="text-md flex items-center gap-2">
|
<div className="text-md flex items-center gap-2">
|
||||||
<FileTextIcon className="h-5" />
|
<FileTextIcon className="h-5" />
|
||||||
<span>{t("generateResult.basicInfo")}</span>
|
<span>{t("common:basicInfo")}</span>
|
||||||
</div>
|
</div>
|
||||||
<FeedbackAlert />
|
<FeedbackAlert />
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
<CopyableField label={t("mainConfig.server")} text={generateResult?.shellConfig.server} />
|
<CopyableField
|
||||||
<CopyableField label={t("mainConfig.shellTool")} text={generateResult?.shellConfig.shellTool} />
|
label={t("common:server")}
|
||||||
<CopyableField label={t("mainConfig.shellMountType")} text={generateResult?.shellConfig.shellType} />
|
text={generateResult?.shellConfig.server}
|
||||||
|
/>
|
||||||
|
<CopyableField
|
||||||
|
label={t("mainConfig.shellTool")}
|
||||||
|
text={generateResult?.shellConfig.shellTool}
|
||||||
|
/>
|
||||||
|
<CopyableField
|
||||||
|
label={t("mainConfig.shellMountType")}
|
||||||
|
text={generateResult?.shellConfig.shellType}
|
||||||
|
/>
|
||||||
{!shouldHidden(generateResult?.shellConfig?.shellType) && (
|
{!shouldHidden(generateResult?.shellConfig?.shellType) && (
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("mainConfig.urlPattern")}
|
label={t("mainConfig.urlPattern")}
|
||||||
@@ -42,22 +53,33 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: MemShe
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{generateResult?.shellConfig.shellTool !== ShellToolType.Custom && <Separator className="my-1" />}
|
{generateResult?.shellConfig.shellTool !== ShellToolType.Custom && (
|
||||||
|
<Separator className="my-1" />
|
||||||
|
)}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
{generateResult?.shellConfig.shellTool === ShellToolType.Behinder && (
|
{generateResult?.shellConfig.shellTool === ShellToolType.Behinder && (
|
||||||
<>
|
<>
|
||||||
<CopyableField label={t("shellToolConfig.behinderScriptType")} text="jsp" />
|
<CopyableField
|
||||||
|
label={t("shellToolConfig.behinderScriptType")}
|
||||||
|
text="jsp"
|
||||||
|
/>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.behinderEncryptType")}
|
label={t("shellToolConfig.behinderEncryptType")}
|
||||||
text={t("shellToolConfig.behinderDefaultEncryptType")}
|
text={t("shellToolConfig.behinderDefaultEncryptType")}
|
||||||
/>
|
/>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.behinderPass")}
|
label={t("shellToolConfig.behinder.pass")}
|
||||||
text={(generateResult?.shellToolConfig as BehinderShellToolConfig).pass}
|
text={
|
||||||
value={(generateResult?.shellToolConfig as BehinderShellToolConfig).pass}
|
(generateResult?.shellToolConfig as BehinderShellToolConfig)
|
||||||
|
.pass
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
(generateResult?.shellToolConfig as BehinderShellToolConfig)
|
||||||
|
.pass
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.customHeader")}
|
label={t("shellToolConfig.behinder.header")}
|
||||||
text={`${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerValue}`}
|
text={`${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerValue}`}
|
||||||
value={`${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerValue}`}
|
value={`${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as BehinderShellToolConfig).headerValue}`}
|
||||||
/>
|
/>
|
||||||
@@ -66,18 +88,33 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: MemShe
|
|||||||
{generateResult?.shellConfig.shellTool === ShellToolType.Godzilla && (
|
{generateResult?.shellConfig.shellTool === ShellToolType.Godzilla && (
|
||||||
<>
|
<>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.pass")}
|
label={t("shellToolConfig.godzilla.pass")}
|
||||||
text={(generateResult?.shellToolConfig as GodzillaShellToolConfig).pass}
|
text={
|
||||||
value={(generateResult?.shellToolConfig as GodzillaShellToolConfig).pass}
|
(generateResult?.shellToolConfig as GodzillaShellToolConfig)
|
||||||
|
.pass
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
(generateResult?.shellToolConfig as GodzillaShellToolConfig)
|
||||||
|
.pass
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.key")}
|
label={t("shellToolConfig.godzilla.key")}
|
||||||
text={(generateResult?.shellToolConfig as GodzillaShellToolConfig).key}
|
text={
|
||||||
value={(generateResult?.shellToolConfig as GodzillaShellToolConfig).key}
|
(generateResult?.shellToolConfig as GodzillaShellToolConfig)
|
||||||
|
.key
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
(generateResult?.shellToolConfig as GodzillaShellToolConfig)
|
||||||
|
.key
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<CopyableField label={t("shellToolConfig.godzillaEncryptor")} text="JAVA_AES_BASE64" />
|
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.godzillaHeader")}
|
label={t("shellToolConfig.godzilla.encryptor")}
|
||||||
|
text="JAVA_AES_BASE64"
|
||||||
|
/>
|
||||||
|
<CopyableField
|
||||||
|
label={t("shellToolConfig.godzilla.header")}
|
||||||
text={`${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerValue}`}
|
text={`${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerValue}`}
|
||||||
value={`${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerValue}`}
|
value={`${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as GodzillaShellToolConfig).headerValue}`}
|
||||||
/>
|
/>
|
||||||
@@ -85,9 +122,15 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: MemShe
|
|||||||
)}
|
)}
|
||||||
{generateResult?.shellConfig.shellTool === ShellToolType.Command && (
|
{generateResult?.shellConfig.shellTool === ShellToolType.Command && (
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.paramName")}
|
label={t("common:paramName")}
|
||||||
text={(generateResult?.shellToolConfig as CommandShellToolConfig).paramName}
|
text={
|
||||||
value={(generateResult?.shellToolConfig as CommandShellToolConfig).paramName}
|
(generateResult?.shellToolConfig as CommandShellToolConfig)
|
||||||
|
.paramName
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
(generateResult?.shellToolConfig as CommandShellToolConfig)
|
||||||
|
.paramName
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{generateResult?.shellConfig.shellTool === ShellToolType.Suo5 && (
|
{generateResult?.shellConfig.shellTool === ShellToolType.Suo5 && (
|
||||||
@@ -100,9 +143,15 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: MemShe
|
|||||||
{generateResult?.shellConfig.shellTool === ShellToolType.AntSword && (
|
{generateResult?.shellConfig.shellTool === ShellToolType.AntSword && (
|
||||||
<>
|
<>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.antSwordPass")}
|
label={t("shellToolConfig.antSword.pass")}
|
||||||
text={(generateResult?.shellToolConfig as AntSwordShellToolConfig).pass}
|
text={
|
||||||
value={(generateResult?.shellToolConfig as AntSwordShellToolConfig).pass}
|
(generateResult?.shellToolConfig as AntSwordShellToolConfig)
|
||||||
|
.pass
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
(generateResult?.shellToolConfig as AntSwordShellToolConfig)
|
||||||
|
.pass
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.httpHeader")}
|
label={t("shellToolConfig.httpHeader")}
|
||||||
@@ -111,9 +160,14 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: MemShe
|
|||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{generateResult?.shellConfig.shellTool === ShellToolType.NeoreGeorg && (
|
{generateResult?.shellConfig.shellTool ===
|
||||||
|
ShellToolType.NeoreGeorg && (
|
||||||
<>
|
<>
|
||||||
<CopyableField label={t("shellToolConfig.neoreGeorgKey")} text="key" value="key" />
|
<CopyableField
|
||||||
|
label={t("shellToolConfig.neoreGeorgKey")}
|
||||||
|
text="key"
|
||||||
|
value="key"
|
||||||
|
/>
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("shellToolConfig.neoreGeorgHeader")}
|
label={t("shellToolConfig.neoreGeorgHeader")}
|
||||||
text={`${(generateResult?.shellToolConfig as NeoreGeorgShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as NeoreGeorgShellToolConfig).headerValue}`}
|
text={`${(generateResult?.shellToolConfig as NeoreGeorgShellToolConfig).headerName}: ${(generateResult?.shellToolConfig as NeoreGeorgShellToolConfig).headerValue}`}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
export function FeedbackAlert() {
|
export function FeedbackAlert() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation("memshell");
|
||||||
return (
|
return (
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
@@ -33,7 +33,7 @@ export function FeedbackAlert() {
|
|||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<AlertDialogCancel>{t("cancel")}</AlertDialogCancel>
|
<AlertDialogCancel>{t("common:cancel")}</AlertDialogCancel>
|
||||||
<AlertDialogAction
|
<AlertDialogAction
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
window.open(
|
window.open(
|
||||||
@@ -41,7 +41,7 @@ export function FeedbackAlert() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("feedback")}
|
{t("common:feedback")}
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</AlertDialogFooter>
|
</AlertDialogFooter>
|
||||||
</AlertDialogContent>
|
</AlertDialogContent>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function JarResult({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{t("download")} Jar
|
{t("common:download")} Jar
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,16 +17,20 @@ export function MultiPackResult({
|
|||||||
packMethod: string;
|
packMethod: string;
|
||||||
}>) {
|
}>) {
|
||||||
const showCode = packMethod === "JSP";
|
const showCode = packMethod === "JSP";
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
const packMethods = Object.keys(allPackResults ?? {});
|
const packMethods = Object.keys(allPackResults ?? {});
|
||||||
const [selectedMethod, setSelectedMethod] = useState(packMethods[0]);
|
const [selectedMethod, setSelectedMethod] = useState(packMethods[0]);
|
||||||
const [packResult, setPackResult] = useState(allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? "");
|
const [packResult, setPackResult] = useState(
|
||||||
|
allPackResults?.[selectedMethod as keyof typeof allPackResults] ?? "",
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const methods = Object.keys(allPackResults ?? {});
|
const methods = Object.keys(allPackResults ?? {});
|
||||||
const firstMethod = methods[0];
|
const firstMethod = methods[0];
|
||||||
setSelectedMethod(firstMethod);
|
setSelectedMethod(firstMethod);
|
||||||
setPackResult(allPackResults?.[firstMethod as keyof typeof allPackResults] ?? "");
|
setPackResult(
|
||||||
|
allPackResults?.[firstMethod as keyof typeof allPackResults] ?? "",
|
||||||
|
);
|
||||||
}, [allPackResults]);
|
}, [allPackResults]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -44,7 +48,9 @@ export function MultiPackResult({
|
|||||||
value={selectedMethod}
|
value={selectedMethod}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-7 text-xs [&_svg]:h-4 [&_svg]:w-4">
|
<SelectTrigger className="h-7 text-xs [&_svg]:h-4 [&_svg]:w-4">
|
||||||
<span className="text-muted-foreground">{t("packageConfig.title")}: </span>
|
<span className="text-muted-foreground">
|
||||||
|
{t("common:packerMethod")}:
|
||||||
|
</span>
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|||||||
@@ -53,9 +53,11 @@ export function ResultComponent({
|
|||||||
header={
|
header={
|
||||||
<div className="flex items-center justify-between text-xs gap-2">
|
<div className="flex items-center justify-between text-xs gap-2">
|
||||||
<span>
|
<span>
|
||||||
{t("packageConfig.title")}:{packMethod}
|
{t("common:packerMethod")}:{packMethod}
|
||||||
|
</span>
|
||||||
|
<span className="text-muted-foreground">
|
||||||
|
({packResult?.length})
|
||||||
</span>
|
</span>
|
||||||
<span className="text-muted-foreground">({packResult?.length})</span>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
wrapLongLines={!showCode}
|
wrapLongLines={!showCode}
|
||||||
|
|||||||
@@ -27,16 +27,20 @@ export default function ShellResult({
|
|||||||
packMethod: string;
|
packMethod: string;
|
||||||
generateResult?: MemShellResult;
|
generateResult?: MemShellResult;
|
||||||
}>) {
|
}>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "memshell"]);
|
||||||
if (!generateResult) {
|
if (!generateResult) {
|
||||||
return <QuickUsage />;
|
return <QuickUsage />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Tabs defaultValue="packResult">
|
<Tabs defaultValue="packResult">
|
||||||
<TabsList className="grid w-full grid-cols-3">
|
<TabsList className="grid w-full grid-cols-3">
|
||||||
<TabsTrigger value="packResult">{t("generateResult.title1")}</TabsTrigger>
|
<TabsTrigger value="packResult">
|
||||||
<TabsTrigger value="shell">{t("generateResult.title2")}</TabsTrigger>
|
{t("common:generateResult")}
|
||||||
<TabsTrigger value="injector">{t("generateResult.title3")}</TabsTrigger>
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="shell">{t("memshell:shellClass")}</TabsTrigger>
|
||||||
|
<TabsTrigger value="injector">
|
||||||
|
{t("memshell:injectorClass")}
|
||||||
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="packResult" className="my-2 space-y-4">
|
<TabsContent value="packResult" className="my-2 space-y-4">
|
||||||
<BasicInfo generateResult={generateResult} />
|
<BasicInfo generateResult={generateResult} />
|
||||||
@@ -50,7 +54,11 @@ export default function ShellResult({
|
|||||||
<TabsContent value="shell" className="mt-4">
|
<TabsContent value="shell" className="mt-4">
|
||||||
<CodeViewer
|
<CodeViewer
|
||||||
showLineNumbers={false}
|
showLineNumbers={false}
|
||||||
header={<div className="text-xs truncate">{generateResult?.shellClassName}</div>}
|
header={
|
||||||
|
<div className="text-xs truncate">
|
||||||
|
{generateResult?.shellClassName}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
button={
|
button={
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -59,10 +67,13 @@ export default function ShellResult({
|
|||||||
className="h-7 w-7 [&_svg]:h-4 [&_svg]:w-4"
|
className="h-7 w-7 [&_svg]:h-4 [&_svg]:w-4"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!generateResult?.shellBytesBase64Str) {
|
if (!generateResult?.shellBytesBase64Str) {
|
||||||
toast.warning(t("tips.shellBytesEmpty"));
|
toast.warning(t("memshell:tips.shellBytesEmpty"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
downloadBytes(generateResult?.shellBytesBase64Str, generateResult?.shellClassName);
|
downloadBytes(
|
||||||
|
generateResult?.shellBytesBase64Str,
|
||||||
|
generateResult?.shellClassName,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DownloadIcon className="h-4 w-4" />
|
<DownloadIcon className="h-4 w-4" />
|
||||||
@@ -78,7 +89,9 @@ export default function ShellResult({
|
|||||||
<CodeViewer
|
<CodeViewer
|
||||||
showLineNumbers={false}
|
showLineNumbers={false}
|
||||||
wrapLongLines={true}
|
wrapLongLines={true}
|
||||||
header={<div className="text-xs">{generateResult?.injectorClassName}</div>}
|
header={
|
||||||
|
<div className="text-xs">{generateResult?.injectorClassName}</div>
|
||||||
|
}
|
||||||
button={
|
button={
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -87,10 +100,13 @@ export default function ShellResult({
|
|||||||
className="h-7 w-7 [&_svg]:h-4 [&_svg]:w-4"
|
className="h-7 w-7 [&_svg]:h-4 [&_svg]:w-4"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!generateResult?.injectorBytesBase64Str) {
|
if (!generateResult?.injectorBytesBase64Str) {
|
||||||
toast.warning(t("tips.shellBytesEmpty"));
|
toast.warning(t("memshell:tips.shellBytesEmpty"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
downloadBytes(generateResult?.injectorBytesBase64Str, generateResult?.injectorClassName);
|
downloadBytes(
|
||||||
|
generateResult?.injectorBytesBase64Str,
|
||||||
|
generateResult?.injectorClassName,
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DownloadIcon className="h-4 w-4" />
|
<DownloadIcon className="h-4 w-4" />
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export function AntSwordTabContent({
|
export function AntSwordTabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="AntSword">
|
<TabsContent value="AntSword">
|
||||||
@@ -34,9 +37,12 @@ export function AntSwordTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.antSwordPass")} {t("optional")}
|
{t("shellToolConfig.antSword.pass")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -46,9 +52,12 @@ export function AntSwordTabContent({
|
|||||||
name="headerName"
|
name="headerName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.headerName")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
@@ -59,9 +68,12 @@ export function AntSwordTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.headerValue")} {t("optional")}
|
{t("common:headerValue")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export function BehinderTabContent({
|
export function BehinderTabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="Behinder">
|
<TabsContent value="Behinder">
|
||||||
@@ -29,9 +32,12 @@ export function BehinderTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.behinderPass")} {t("optional")}
|
{t("shellToolConfig.behinder.pass")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -41,8 +47,11 @@ export function BehinderTabContent({
|
|||||||
name="headerName"
|
name="headerName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.headerName")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -52,9 +61,12 @@ export function BehinderTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.headerValue")} {t("optional")}
|
{t("common:headerValue")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import {
|
|||||||
import { Input } from "@/components/ui/input.tsx";
|
import { Input } from "@/components/ui/input.tsx";
|
||||||
import type { MemShellFormSchema } from "@/types/schema.ts";
|
import type { MemShellFormSchema } from "@/types/schema.ts";
|
||||||
|
|
||||||
export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
export function OptionalClassFormField({
|
||||||
const { t } = useTranslation();
|
form,
|
||||||
|
}: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
const [showAdvanced, setShowAdvanced] = useState(false);
|
const [showAdvanced, setShowAdvanced] = useState(false);
|
||||||
const shellClassNameId = useId();
|
|
||||||
const injectClassNameId = useId();
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="pt-2">
|
<div className="pt-2">
|
||||||
@@ -28,7 +28,11 @@ export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn<
|
|||||||
>
|
>
|
||||||
<Settings className="h-4 w-4" />
|
<Settings className="h-4 w-4" />
|
||||||
{t("classNameOptions")}
|
{t("classNameOptions")}
|
||||||
{showAdvanced ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
|
{showAdvanced ? (
|
||||||
|
<ChevronUp className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{showAdvanced && (
|
{showAdvanced && (
|
||||||
@@ -38,10 +42,14 @@ export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn<
|
|||||||
name="shellClassName"
|
name="shellClassName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel htmlFor={shellClassNameId}>
|
<FormFieldLabel htmlFor="shellClassName">
|
||||||
{t("mainConfig.shellClassName")} {t("optional")}
|
{t("mainConfig.shellClassName")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input id={shellClassNameId} {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
id="shellClassName"
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -50,10 +58,14 @@ export function OptionalClassFormField({ form }: Readonly<{ form: UseFormReturn<
|
|||||||
name="injectorClassName"
|
name="injectorClassName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel htmlFor={injectClassNameId}>
|
<FormFieldLabel htmlFor="injectClassName">
|
||||||
{t("mainConfig.injectorClassName")} {t("optional")}
|
{t("mainConfig.injectorClassName")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input id={injectClassNameId} {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
id="injectClassName"
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -26,9 +26,15 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export function CommandTabContent({
|
export function CommandTabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
const { data } = useQuery<{ encryptors: Array<string>; implementationClasses: Array<string> }>({
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
|
const { data } = useQuery<{
|
||||||
|
encryptors: Array<string>;
|
||||||
|
implementationClasses: Array<string>;
|
||||||
|
}>({
|
||||||
queryKey: ["commandConfigs"],
|
queryKey: ["commandConfigs"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const response = await fetch(`${env.API_URL}/config/command/configs`);
|
const response = await fetch(`${env.API_URL}/config/command/configs`);
|
||||||
@@ -51,10 +57,13 @@ export function CommandTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.paramName")} {t("optional")}
|
{t("common:paramName")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
@@ -65,11 +74,17 @@ export function CommandTabContent({
|
|||||||
name="encryptor"
|
name="encryptor"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.encryptor")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:encryptor")}</FormFieldLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value} defaultValue="RAW">
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
value={field.value}
|
||||||
|
defaultValue="RAW"
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t("placeholders.select")} />
|
<SelectValue
|
||||||
|
placeholder={t("common:placeholders.select")}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -88,11 +103,19 @@ export function CommandTabContent({
|
|||||||
name="implementationClass"
|
name="implementationClass"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.implementationClass")}</FormFieldLabel>
|
<FormFieldLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value} defaultValue="RuntimeExec">
|
{t("common:implementationClass")}
|
||||||
|
</FormFieldLabel>
|
||||||
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
value={field.value}
|
||||||
|
defaultValue="RuntimeExec"
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t("placeholders.select")} />
|
<SelectValue
|
||||||
|
placeholder={t("common:placeholders.select")}
|
||||||
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export default function CustomTabContent({
|
export default function CustomTabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
const [isFile, setIsFile] = useState(false);
|
const [isFile, setIsFile] = useState(false);
|
||||||
const optionOneId = useId();
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
const optionTwoId = useId();
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="Custom">
|
<TabsContent value="Custom">
|
||||||
@@ -40,7 +42,7 @@ export default function CustomTabContent({
|
|||||||
name="shellClassBase64"
|
name="shellClassBase64"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.base64String")}</FormFieldLabel>
|
<FormFieldLabel>{t("shellClass")}</FormFieldLabel>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
value={isFile ? "file" : "base64"}
|
value={isFile ? "file" : "base64"}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
@@ -50,12 +52,12 @@ export default function CustomTabContent({
|
|||||||
className="flex items-center space-x-2"
|
className="flex items-center space-x-2"
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem value="base64" id={optionOneId} />
|
<RadioGroupItem value="base64" id="optionOne" />
|
||||||
<Label htmlFor={optionOneId}>Base64</Label>
|
<Label htmlFor="optionOne">Base64</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<RadioGroupItem value="file" id={optionTwoId} />
|
<RadioGroupItem value="file" id="optionTwo" />
|
||||||
<Label htmlFor={optionTwoId}>File</Label>
|
<Label htmlFor="optionTwo">File</Label>
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
<FormControl className="mt-2">
|
<FormControl className="mt-2">
|
||||||
@@ -66,18 +68,25 @@ export default function CustomTabContent({
|
|||||||
if (file) {
|
if (file) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (event) => {
|
reader.onload = (event) => {
|
||||||
const base64String = (event.target?.result as string)?.split(",")[1] || "";
|
const base64String =
|
||||||
|
(event.target?.result as string)?.split(
|
||||||
|
",",
|
||||||
|
)[1] || "";
|
||||||
field.onChange(base64String);
|
field.onChange(base64String);
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
accept=".class"
|
accept=".class"
|
||||||
placeholder={t("placeholders.input")}
|
placeholder={t("common:placeholders.input")}
|
||||||
type="file"
|
type="file"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Textarea {...field} placeholder={t("placeholders.input")} className="h-24" />
|
<Textarea
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
className="h-24"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export function GodzillaTabContent({
|
export function GodzillaTabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="Godzilla">
|
<TabsContent value="Godzilla">
|
||||||
@@ -30,9 +33,13 @@ export function GodzillaTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.pass")} {t("optional")}
|
{t("shellToolConfig.godzilla.pass")}{" "}
|
||||||
|
{t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -42,9 +49,12 @@ export function GodzillaTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.key")} {t("optional")}
|
{t("shellToolConfig.godzilla.key")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -53,8 +63,11 @@ export function GodzillaTabContent({
|
|||||||
name="headerName"
|
name="headerName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.headerName")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -64,9 +77,12 @@ export function GodzillaTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.headerValue")} {t("optional")}
|
{t("common:headerValue")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export function NeoRegTabContent({
|
export function NeoRegTabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="NeoreGeorg">
|
<TabsContent value="NeoreGeorg">
|
||||||
@@ -29,8 +32,11 @@ export function NeoRegTabContent({
|
|||||||
name="headerName"
|
name="headerName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.headerName")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -40,9 +46,12 @@ export function NeoRegTabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.headerValue")} {t("optional")}
|
{t("common:headerValue")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -18,8 +18,11 @@ import type { MemShellFormSchema } from "@/types/schema.ts";
|
|||||||
export function ShellTypeFormField({
|
export function ShellTypeFormField({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<FormField
|
<FormField
|
||||||
@@ -37,7 +40,7 @@ export function ShellTypeFormField({
|
|||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder={t("placeholders.select")} />
|
<SelectValue placeholder={t("common:placeholders.select")} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent key={shellTypes?.join(",")}>
|
<SelectContent key={shellTypes?.join(",")}>
|
||||||
@@ -48,7 +51,9 @@ export function ShellTypeFormField({
|
|||||||
</SelectItem>
|
</SelectItem>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<SelectItem value=" ">{t("tips.shellToolNotSelected")}</SelectItem>
|
<SelectItem value=" ">
|
||||||
|
{t("tips.shellToolNotSelected")}
|
||||||
|
</SelectItem>
|
||||||
)}
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@@ -12,8 +12,11 @@ import { UrlPatternFormField } from "./urlpattern-field";
|
|||||||
export function Suo5TabContent({
|
export function Suo5TabContent({
|
||||||
form,
|
form,
|
||||||
shellTypes,
|
shellTypes,
|
||||||
}: Readonly<{ form: UseFormReturn<MemShellFormSchema>; shellTypes: Array<string> }>) {
|
}: Readonly<{
|
||||||
const { t } = useTranslation();
|
form: UseFormReturn<MemShellFormSchema>;
|
||||||
|
shellTypes: Array<string>;
|
||||||
|
}>) {
|
||||||
|
const { t } = useTranslation(["memshell", "common"]);
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<TabsContent value="Suo5">
|
<TabsContent value="Suo5">
|
||||||
@@ -29,8 +32,11 @@ export function Suo5TabContent({
|
|||||||
name="headerName"
|
name="headerName"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>{t("shellToolConfig.headerName")}</FormFieldLabel>
|
<FormFieldLabel>{t("common:headerName")}</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -40,9 +46,12 @@ export function Suo5TabContent({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>
|
<FormFieldLabel>
|
||||||
{t("shellToolConfig.headerValue")} {t("optional")}
|
{t("common:headerValue")} {t("common:optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder={t("common:placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import { Input } from "@/components/ui/input.tsx";
|
|||||||
import { shouldHidden } from "@/lib/utils";
|
import { shouldHidden } from "@/lib/utils";
|
||||||
import type { MemShellFormSchema } from "@/types/schema.ts";
|
import type { MemShellFormSchema } from "@/types/schema.ts";
|
||||||
|
|
||||||
export function UrlPatternFormField({ form }: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
export function UrlPatternFormField({
|
||||||
const { t } = useTranslation();
|
form,
|
||||||
|
}: Readonly<{ form: UseFormReturn<MemShellFormSchema> }>) {
|
||||||
|
const { t } = useTranslation("common");
|
||||||
const shellType = form.watch("shellType");
|
const shellType = form.watch("shellType");
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
@@ -19,8 +21,10 @@ export function UrlPatternFormField({ form }: Readonly<{ form: UseFormReturn<Mem
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="urlPattern"
|
name="urlPattern"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem className={shouldHidden(shellType) ? "hidden" : "grid"}>
|
<FormFieldItem
|
||||||
<FormFieldLabel>{t("mainConfig.urlPattern")}</FormFieldLabel>
|
className={shouldHidden(shellType) ? "hidden" : "grid"}
|
||||||
|
>
|
||||||
|
<FormFieldLabel>{t("urlPattern")}</FormFieldLabel>
|
||||||
<Input {...field} placeholder={t("placeholders.input")} />
|
<Input {...field} placeholder={t("placeholders.input")} />
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import { FeedbackAlert } from "@/components/memshell/results/feedback-alert";
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import type { ProbeShellResult } from "@/types/probeshell";
|
import type { ProbeShellResult } from "@/types/probeshell";
|
||||||
|
|
||||||
export function BasicInfo({ generateResult }: Readonly<{ generateResult?: ProbeShellResult }>) {
|
export function BasicInfo({
|
||||||
|
generateResult,
|
||||||
|
}: Readonly<{ generateResult?: ProbeShellResult }>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
@@ -13,7 +15,7 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: ProbeS
|
|||||||
<CardTitle className="flex items-center justify-between">
|
<CardTitle className="flex items-center justify-between">
|
||||||
<div className="text-md flex items-center gap-2">
|
<div className="text-md flex items-center gap-2">
|
||||||
<FileTextIcon className="h-5" />
|
<FileTextIcon className="h-5" />
|
||||||
<span>{t("generateResult.basicInfo")}</span>
|
<span>{t("common:basicInfo")}</span>
|
||||||
</div>
|
</div>
|
||||||
<FeedbackAlert />
|
<FeedbackAlert />
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
@@ -21,7 +23,7 @@ export function BasicInfo({ generateResult }: Readonly<{ generateResult?: ProbeS
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-1 gap-2">
|
<div className="grid grid-cols-1 gap-2">
|
||||||
<CopyableField
|
<CopyableField
|
||||||
label={t("mainConfig.shellClassName")}
|
label={t("probeshell:shellClassName")}
|
||||||
value={generateResult?.shellClassName}
|
value={generateResult?.shellClassName}
|
||||||
text={`${generateResult?.shellClassName} (${generateResult?.shellSize} bytes)`}
|
text={`${generateResult?.shellClassName} (${generateResult?.shellSize} bytes)`}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -14,18 +14,23 @@ import {
|
|||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import type { ServerConfig } from "@/types/memshell";
|
import type { ServerConfig } from "@/types/memshell";
|
||||||
import type { ProbeShellFormSchema } from "@/types/schema";
|
import type { ProbeShellFormSchema } from "@/types/schema";
|
||||||
import { Separator } from "../ui/separator";
|
import { Separator } from "../ui/separator";
|
||||||
|
|
||||||
// 常量提取到组件外部
|
|
||||||
const PROBE_OPTIONS = [
|
const PROBE_OPTIONS = [
|
||||||
{ value: "Server" as const, label: "中间件类型" },
|
{ value: "Server" as const, label: "server" },
|
||||||
{ value: "JDK" as const, label: "JDK 信息" },
|
{ value: "JDK" as const, label: "jdk" },
|
||||||
{ value: "Command" as const, label: "命令执行" },
|
{ value: "Command" as const, label: "command" },
|
||||||
{ value: "Bytecode" as const, label: "自定义字节码执行" },
|
{ value: "Bytecode" as const, label: "bytecode" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const MIDDLEWARE_OPTIONS = [
|
const MIDDLEWARE_OPTIONS = [
|
||||||
@@ -45,12 +50,11 @@ const MIDDLEWARE_OPTIONS = [
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const PROBE_METHOD_OPTIONS = [
|
const PROBE_METHOD_OPTIONS = [
|
||||||
{ value: "Sleep", label: "Sleep 延迟探测" },
|
{ value: "Sleep", label: "Sleep" },
|
||||||
{ value: "DNSLog", label: "DNSLog" },
|
{ value: "DNSLog", label: "DNSLog" },
|
||||||
{ value: "ResponseBody", label: "ResponseBody" },
|
{ value: "ResponseBody", label: "ResponseBody" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// 默认值配置
|
|
||||||
const DEFAULT_FORM_VALUES = {
|
const DEFAULT_FORM_VALUES = {
|
||||||
reqParamName: "payload",
|
reqParamName: "payload",
|
||||||
reqHeaderName: "X-PAYLOAD",
|
reqHeaderName: "X-PAYLOAD",
|
||||||
@@ -64,7 +68,7 @@ interface MainConfigCardProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "probeshell"]);
|
||||||
const watchedProbeMethod = form.watch("probeMethod");
|
const watchedProbeMethod = form.watch("probeMethod");
|
||||||
const watchedProbeContent = form.watch("probeContent");
|
const watchedProbeContent = form.watch("probeContent");
|
||||||
|
|
||||||
@@ -75,12 +79,13 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
Sleep: ["Server"],
|
Sleep: ["Server"],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const allowedValues = filterMap[watchedProbeMethod as keyof typeof filterMap];
|
const allowedValues =
|
||||||
|
filterMap[watchedProbeMethod as keyof typeof filterMap];
|
||||||
|
|
||||||
if (!allowedValues) return PROBE_OPTIONS;
|
if (!allowedValues) return PROBE_OPTIONS;
|
||||||
|
|
||||||
return PROBE_OPTIONS.filter(opt =>
|
return PROBE_OPTIONS.filter((opt) =>
|
||||||
allowedValues.includes(opt.value as never)
|
allowedValues.includes(opt.value as never),
|
||||||
);
|
);
|
||||||
}, [watchedProbeMethod]);
|
}, [watchedProbeMethod]);
|
||||||
|
|
||||||
@@ -100,64 +105,70 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
resetFormValues();
|
resetFormValues();
|
||||||
}, [resetFormValues]);
|
}, [resetFormValues]);
|
||||||
|
|
||||||
const ContentOptionsSelect = useMemo(() => (
|
const ContentOptionsSelect = useMemo(
|
||||||
<FormField
|
() => (
|
||||||
control={form.control}
|
|
||||||
name="probeContent"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormFieldItem>
|
|
||||||
<FormFieldLabel>探测内容</FormFieldLabel>
|
|
||||||
<Select onValueChange={field.onChange} value={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>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
), [form.control, filteredOptions]);
|
|
||||||
|
|
||||||
const RequestParamField = useMemo(() => (
|
|
||||||
<div className="space-y-4 pt-4 border-t mt-4">
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="reqParamName"
|
name="probeContent"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>Request Param Name</FormFieldLabel>
|
<FormFieldLabel>{t("probeshell:probeContent")}</FormFieldLabel>
|
||||||
<FormControl>
|
<Select onValueChange={field.onChange} value={field.value || ""}>
|
||||||
<Input placeholder="例如: cmd, data, ..." {...field} />
|
<FormControl>
|
||||||
</FormControl>
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder={t("common:placeholders.select")} />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
{filteredOptions.map((opt) => (
|
||||||
|
<SelectItem key={opt.value} value={opt.value}>
|
||||||
|
{t(`probeshell:probeContent.${opt.label}`)}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
),
|
||||||
), [form.control]);
|
[form.control, filteredOptions, t],
|
||||||
|
);
|
||||||
|
|
||||||
const SleepFields = useMemo(() => (
|
const RequestParamField = useMemo(
|
||||||
<div className="space-y-4 pt-4 border-t mt-4">
|
() => (
|
||||||
<div className="space-y-4">
|
<div className="space-y-2 pt-4 border-t mt-4">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="reqParamName"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormFieldItem>
|
||||||
|
<FormFieldLabel>{t("common:paramName")}</FormFieldLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder={t("placeholders.input")} {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormFieldItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[form.control, t],
|
||||||
|
);
|
||||||
|
|
||||||
|
const SleepFields = useMemo(
|
||||||
|
() => (
|
||||||
|
<div className="space-y-2 pt-4 border-t mt-4">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="sleepServer"
|
name="sleepServer"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>探测中间件</FormFieldLabel>
|
<FormFieldLabel>{t("probeshell:sleepServer")}</FormFieldLabel>
|
||||||
<Select onValueChange={field.onChange} value={field.value || ""}>
|
<Select onValueChange={field.onChange} value={field.value || ""}>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="选择中间件..." />
|
<SelectValue placeholder={t("placeholders.select")} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -177,11 +188,11 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
name="seconds"
|
name="seconds"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>命中延迟时间 (秒)</FormFieldLabel>
|
<FormFieldLabel>{t("probeshell:sleepSeconds")}</FormFieldLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="例如: 5"
|
placeholder={t("placeholders.input")}
|
||||||
{...field}
|
{...field}
|
||||||
onChange={(event) => field.onChange(+event.target.value)}
|
onChange={(event) => field.onChange(+event.target.value)}
|
||||||
/>
|
/>
|
||||||
@@ -191,12 +202,14 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
),
|
||||||
), [form.control]);
|
[form.control, t],
|
||||||
|
);
|
||||||
|
|
||||||
const renderDynamicFields = useCallback(() => {
|
const renderDynamicFields = useCallback(() => {
|
||||||
const isBodyMethod = watchedProbeMethod === "ResponseBody";
|
const isBodyMethod = watchedProbeMethod === "ResponseBody";
|
||||||
const isCommandOrBytecode = watchedProbeContent === "Command" || watchedProbeContent === "Bytecode";
|
const isCommandOrBytecode =
|
||||||
|
watchedProbeContent === "Command" || watchedProbeContent === "Bytecode";
|
||||||
const isSleepMethod = watchedProbeMethod === "Sleep";
|
const isSleepMethod = watchedProbeMethod === "Sleep";
|
||||||
const isServerContent = watchedProbeContent === "Server";
|
const isServerContent = watchedProbeContent === "Server";
|
||||||
|
|
||||||
@@ -211,90 +224,110 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
return null;
|
return null;
|
||||||
}, [watchedProbeMethod, watchedProbeContent, RequestParamField, SleepFields]);
|
}, [watchedProbeMethod, watchedProbeContent, RequestParamField, SleepFields]);
|
||||||
|
|
||||||
|
const DNSLogSection = useMemo(
|
||||||
const DNSLogSection = useMemo(() => (
|
() => (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="host"
|
name="host"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>DNSLog 地址</FormFieldLabel>
|
<FormFieldLabel>{t("probeshell:dnslog.host")}</FormFieldLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input placeholder="例如: abcde.DNSLog.cn" {...field} />
|
<Input placeholder={t("placeholders.input")} {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
), [form.control]);
|
),
|
||||||
|
[form.control, t],
|
||||||
|
);
|
||||||
|
|
||||||
const MiddlewareSelect = useMemo(() => (
|
const MiddlewareSelect = useMemo(
|
||||||
<FormField
|
() => (
|
||||||
control={form.control}
|
<FormField
|
||||||
name="server"
|
control={form.control}
|
||||||
render={({ field }) => (
|
name="server"
|
||||||
<FormFieldItem>
|
render={({ field }) => (
|
||||||
<FormFieldLabel>中间件类型</FormFieldLabel>
|
<FormFieldItem>
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
<FormFieldLabel>{t("server")}</FormFieldLabel>
|
||||||
<FormControl>
|
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||||
<SelectTrigger>
|
<FormControl>
|
||||||
<SelectValue placeholder="选择中间件..." />
|
<SelectTrigger>
|
||||||
</SelectTrigger>
|
<SelectValue placeholder={t("placeholders.select")} />
|
||||||
</FormControl>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
</FormControl>
|
||||||
{Object.keys(servers ?? {}).map((server: string) => (
|
<SelectContent>
|
||||||
<SelectItem key={server} value={server}>
|
{Object.keys(servers ?? {}).map((server: string) => (
|
||||||
{server}
|
<SelectItem key={server} value={server}>
|
||||||
</SelectItem>
|
{server}
|
||||||
))}
|
</SelectItem>
|
||||||
</SelectContent>
|
))}
|
||||||
</Select>
|
</SelectContent>
|
||||||
<FormMessage />
|
</Select>
|
||||||
</FormFieldItem>
|
<FormMessage />
|
||||||
)}
|
</FormFieldItem>
|
||||||
/>
|
)}
|
||||||
), [form.control, servers]);
|
/>
|
||||||
|
),
|
||||||
|
[form.control, servers, t],
|
||||||
|
);
|
||||||
|
|
||||||
const SwitchGroup = useMemo(() => (
|
const SwitchGroup = useMemo(
|
||||||
<div className="flex gap-4 mt-4 flex-col sm:flex-row">
|
() => (
|
||||||
<FormField
|
<div className="flex gap-4 mt-4 flex-col sm:flex-row">
|
||||||
control={form.control}
|
<FormField
|
||||||
name="debug"
|
control={form.control}
|
||||||
render={({ field }) => (
|
name="debug"
|
||||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
render={({ field }) => (
|
||||||
<FormControl>
|
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||||
<Switch id="debug" checked={field.value} onCheckedChange={field.onChange} />
|
<FormControl>
|
||||||
</FormControl>
|
<Switch
|
||||||
<FormLabel htmlFor="debug">{t("mainConfig.debug")}</FormLabel>
|
id="debug"
|
||||||
</FormItem>
|
checked={field.value}
|
||||||
)}
|
onCheckedChange={field.onChange}
|
||||||
/>
|
/>
|
||||||
<FormField
|
</FormControl>
|
||||||
control={form.control}
|
<FormLabel htmlFor="debug">{t("debug")}</FormLabel>
|
||||||
name="byPassJavaModule"
|
</FormItem>
|
||||||
render={({ field }) => (
|
)}
|
||||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
/>
|
||||||
<FormControl>
|
<FormField
|
||||||
<Switch id="bypass" checked={field.value} onCheckedChange={field.onChange} />
|
control={form.control}
|
||||||
</FormControl>
|
name="byPassJavaModule"
|
||||||
<Label htmlFor="bypass">{t("mainConfig.byPassJavaModule")}</Label>
|
render={({ field }) => (
|
||||||
</FormItem>
|
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||||
)}
|
<FormControl>
|
||||||
/>
|
<Switch
|
||||||
<FormField
|
id="bypass"
|
||||||
control={form.control}
|
checked={field.value}
|
||||||
name="shrink"
|
onCheckedChange={field.onChange}
|
||||||
render={({ field }) => (
|
/>
|
||||||
<FormItem className="flex items-center space-x-2 space-y-0">
|
</FormControl>
|
||||||
<FormControl>
|
<Label htmlFor="bypass">{t("byPassJavaModule")}</Label>
|
||||||
<Switch id="shrink" checked={field.value} onCheckedChange={field.onChange} />
|
</FormItem>
|
||||||
</FormControl>
|
)}
|
||||||
<Label htmlFor="shrink">{t("mainConfig.shrink")}</Label>
|
/>
|
||||||
</FormItem>
|
<FormField
|
||||||
)}
|
control={form.control}
|
||||||
/>
|
name="shrink"
|
||||||
</div>
|
render={({ field }) => (
|
||||||
), [form.control, t]);
|
<FormItem className="flex items-center space-x-2 space-y-0">
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
id="shrink"
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<Label htmlFor="shrink">{t("shrink")}</Label>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[form.control, t],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
@@ -302,17 +335,20 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
<CardHeader className="pb-1">
|
<CardHeader className="pb-1">
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<ServerIcon className="h-5 w-5" />
|
<ServerIcon className="h-5 w-5" />
|
||||||
<span>{t("configs.main-config")}</span>
|
<span>{t("mainConfig.title")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-2">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="probeMethod"
|
name="probeMethod"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel>探测方式</FormFieldLabel>
|
<FormFieldLabel>{t("probeshell:probeMethod")}</FormFieldLabel>
|
||||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
<Select
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
defaultValue={field.value}
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
@@ -343,9 +379,13 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormFieldItem>
|
<FormFieldItem>
|
||||||
<FormFieldLabel htmlFor="shellClassName">
|
<FormFieldLabel htmlFor="shellClassName">
|
||||||
{t("mainConfig.shellClassName")} {t("optional")}
|
{t("probeshell:shellClassName")} {t("optional")}
|
||||||
</FormFieldLabel>
|
</FormFieldLabel>
|
||||||
<Input id="shellClassName" {...field} placeholder={t("placeholders.input")} />
|
<Input
|
||||||
|
id="shellClassName"
|
||||||
|
{...field}
|
||||||
|
placeholder={t("placeholders.input")}
|
||||||
|
/>
|
||||||
</FormFieldItem>
|
</FormFieldItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@@ -353,4 +393,4 @@ export default function MainConfigCard({ form, servers }: MainConfigCardProps) {
|
|||||||
</Card>
|
</Card>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,18 @@ import { PackageIcon } from "lucide-react";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
import { FormProvider, type UseFormReturn } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
|
import {
|
||||||
import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx";
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card.tsx";
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
} from "@/components/ui/form.tsx";
|
||||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group.tsx";
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group.tsx";
|
||||||
import type { PackerConfig } from "@/types/memshell";
|
import type { PackerConfig } from "@/types/memshell";
|
||||||
import type { ProbeShellFormSchema } from "@/types/schema";
|
import type { ProbeShellFormSchema } from "@/types/schema";
|
||||||
@@ -21,7 +31,7 @@ export default function PackageConfigCard({
|
|||||||
form: UseFormReturn<ProbeShellFormSchema>;
|
form: UseFormReturn<ProbeShellFormSchema>;
|
||||||
}>) {
|
}>) {
|
||||||
const [options, setOptions] = useState<Array<Option>>([]);
|
const [options, setOptions] = useState<Array<Option>>([]);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation("common");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filteredOptions = (packerConfig ?? []).filter((name) => {
|
const filteredOptions = (packerConfig ?? []).filter((name) => {
|
||||||
@@ -30,24 +40,27 @@ export default function PackageConfigCard({
|
|||||||
|
|
||||||
const mappedOptions = filteredOptions.map((name) => {
|
const mappedOptions = filteredOptions.map((name) => {
|
||||||
return {
|
return {
|
||||||
name: t(`packageConfig.packer.${name}`),
|
name: name,
|
||||||
value: name,
|
value: name,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
setOptions(mappedOptions);
|
setOptions(mappedOptions);
|
||||||
const currentValue = form.getValues("packingMethod");
|
const currentValue = form.getValues("packingMethod");
|
||||||
if (filteredOptions.length > 0 && (!currentValue || !filteredOptions.includes(currentValue))) {
|
if (
|
||||||
|
filteredOptions.length > 0 &&
|
||||||
|
(!currentValue || !filteredOptions.includes(currentValue))
|
||||||
|
) {
|
||||||
form.setValue("packingMethod", filteredOptions[0]);
|
form.setValue("packingMethod", filteredOptions[0]);
|
||||||
}
|
}
|
||||||
}, [form, packerConfig, t]);
|
}, [form, packerConfig]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="w-full">
|
<Card className="w-full">
|
||||||
<CardHeader className="pb-1">
|
<CardHeader className="pb-1">
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<PackageIcon className="h-5" />
|
<PackageIcon className="h-5" />
|
||||||
<span>{t("configs.package-config")}</span>
|
<span>{t("packerConfig.title")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -58,7 +71,7 @@ export default function PackageConfigCard({
|
|||||||
name="packingMethod"
|
name="packingMethod"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="space-y-3">
|
<FormItem className="space-y-3">
|
||||||
<FormLabel>{t("packageConfig.title")}</FormLabel>
|
<FormLabel>{t("packerMethod")}</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
onValueChange={field.onChange}
|
onValueChange={field.onChange}
|
||||||
@@ -66,7 +79,10 @@ export default function PackageConfigCard({
|
|||||||
className="grid grid-cols-2 md:grid-cols-3"
|
className="grid grid-cols-2 md:grid-cols-3"
|
||||||
>
|
>
|
||||||
{options.map(({ name, value }) => (
|
{options.map(({ name, value }) => (
|
||||||
<FormItem key={value} className="flex items-center space-x-3 space-y-0">
|
<FormItem
|
||||||
|
key={value}
|
||||||
|
className="flex items-center space-x-3 space-y-0"
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<RadioGroupItem value={value} id={value} />
|
<RadioGroupItem value={value} id={value} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -84,7 +100,9 @@ export default function PackageConfigCard({
|
|||||||
) : (
|
) : (
|
||||||
<div className="flex items-center justify-center p-4 space-x-2">
|
<div className="flex items-center justify-center p-4 space-x-2">
|
||||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
|
||||||
<span className="text-sm text-muted-foreground">{t("loading")}</span>
|
<span className="text-sm text-muted-foreground">
|
||||||
|
{t("loading")}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
import { ScrollTextIcon } from "lucide-react";
|
import { ScrollTextIcon } from "lucide-react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card.tsx";
|
||||||
|
|
||||||
export function QuickUsage() {
|
export function QuickUsage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "probeshell"]);
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-md flex items-center gap-2">
|
<CardTitle className="text-md flex items-center gap-2">
|
||||||
<ScrollTextIcon className="h-5" />
|
<ScrollTextIcon className="h-5" />
|
||||||
<span>{t("quickUsage.title")}</span>
|
<span>{t("common:quickUsage.title")}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<ol className="list-decimal list-inside space-y-4 text-sm">
|
<ol className="list-decimal list-inside space-y-4 text-sm">
|
||||||
<li>{t("quickUsage.step1")}</li>
|
<li>{t("probeshell:quickUsage.step1")}</li>
|
||||||
<li>{t("quickUsage.step2")}</li>
|
<li>{t("probeshell:quickUsage.step2")}</li>
|
||||||
<li>{t("quickUsage.step3")}</li>
|
<li>{t("probeshell:quickUsage.step3")}</li>
|
||||||
<li>{t("quickUsage.step4")}</li>
|
|
||||||
<li>{t("quickUsage.step5")}</li>
|
|
||||||
</ol>
|
</ol>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { QuickUsage } from "@/components/probeshell/quick-usage";
|
import { QuickUsage } from "@/components/probeshell/quick-usage";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs.tsx";
|
import {
|
||||||
|
Tabs,
|
||||||
|
TabsContent,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
} from "@/components/ui/tabs.tsx";
|
||||||
import type { ProbeShellResult } from "@/types/probeshell";
|
import type { ProbeShellResult } from "@/types/probeshell";
|
||||||
import CodeViewer from "../code-viewer";
|
import CodeViewer from "../code-viewer";
|
||||||
import { MultiPackResult } from "../memshell/results/multi-packer";
|
import { MultiPackResult } from "../memshell/results/multi-packer";
|
||||||
@@ -25,32 +30,37 @@ export default function ShellResult({
|
|||||||
return (
|
return (
|
||||||
<Tabs defaultValue="packResult">
|
<Tabs defaultValue="packResult">
|
||||||
<TabsList className="grid w-full grid-cols-1">
|
<TabsList className="grid w-full grid-cols-1">
|
||||||
<TabsTrigger value="packResult">{t("generateResult.title1")}</TabsTrigger>
|
<TabsTrigger value="packResult">
|
||||||
|
{t("common:generateResult")}
|
||||||
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="packResult" className="my-2 space-y-4">
|
<TabsContent value="packResult" className="my-2 space-y-4">
|
||||||
<BasicInfo generateResult={generateResult} />
|
<BasicInfo generateResult={generateResult} />
|
||||||
{
|
{allPackResults && (
|
||||||
allPackResults && <MultiPackResult allPackResults={allPackResults} packMethod={packMethod} />
|
<MultiPackResult
|
||||||
}
|
allPackResults={allPackResults}
|
||||||
{
|
packMethod={packMethod}
|
||||||
packResult && (
|
/>
|
||||||
<CodeViewer
|
)}
|
||||||
code={packResult}
|
{packResult && (
|
||||||
header={
|
<CodeViewer
|
||||||
<div className="flex items-center justify-between text-xs gap-2">
|
code={packResult}
|
||||||
<span>
|
header={
|
||||||
{t("packageConfig.title")}:{packMethod}
|
<div className="flex items-center justify-between text-xs gap-2">
|
||||||
</span>
|
<span>
|
||||||
<span className="text-muted-foreground">({packResult?.length})</span>
|
{t("common:packerMethod")}:{packMethod}
|
||||||
</div>
|
</span>
|
||||||
}
|
<span className="text-muted-foreground">
|
||||||
wrapLongLines={!showCode}
|
({packResult?.length})
|
||||||
showLineNumbers={showCode}
|
</span>
|
||||||
language={showCode ? "java" : "text"}
|
</div>
|
||||||
height={350}
|
}
|
||||||
/>
|
wrapLongLines={!showCode}
|
||||||
)
|
showLineNumbers={showCode}
|
||||||
}
|
language={showCode ? "java" : "text"}
|
||||||
|
height={350}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"about": "About",
|
||||||
|
"basicInfo": "BasicInfo",
|
||||||
|
"byPassJavaModule": "Bypass JavaModule",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"copyLabelSuccess": "Copy {{label}} successfully",
|
||||||
|
"copySuccess": "Copy successfully",
|
||||||
|
"debug": "Debug Mode",
|
||||||
|
"download": "Downlaod",
|
||||||
|
"encryptor": "Encryptor",
|
||||||
|
"feedback": "Feedback",
|
||||||
|
"generateResult": "Generate Result",
|
||||||
|
"generator": "Generator",
|
||||||
|
"headerName": "HeaderName",
|
||||||
|
"headerValue": "HeaderValue",
|
||||||
|
"implementationClass": "ImplementationClass",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"mainConfig.title": "Main Config",
|
||||||
|
"MemShellGenerator": "MemShellGenerator",
|
||||||
|
"optional": "(Optional)",
|
||||||
|
"packerConfig.title": "Package Config",
|
||||||
|
"packerMethod": "Package Method",
|
||||||
|
"paramName": "ParamName",
|
||||||
|
"placeholders.input": "Please input",
|
||||||
|
"placeholders.select": "Please select",
|
||||||
|
"ProbeShellGenerator": "ProbeShellGenerator",
|
||||||
|
"quickUsage.title": "Quick Usage",
|
||||||
|
"server": "Server",
|
||||||
|
"serverVersion": "Server Version",
|
||||||
|
"shrink": "Shrink",
|
||||||
|
"toast.generateError": "Generation failed, {{error}}",
|
||||||
|
"toast.generateSuccess": "Generation successful",
|
||||||
|
"urlPattern": "URL Pattern",
|
||||||
|
"usage": "Usage",
|
||||||
|
"version.updateAvailable": "Update Available",
|
||||||
|
"version.updateAvailableTooltip": "Click to Open Github Release Page ( v{{currentVersion}} -> v{{latestVersion}})"
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"about": "关于",
|
||||||
|
"basicInfo": "基本信息",
|
||||||
|
"byPassJavaModule": "绕过 Java 模块限制",
|
||||||
|
"cancel": "取消",
|
||||||
|
"copyLabelSuccess": "复制 {{label}} 成功",
|
||||||
|
"copySuccess": "复制成功",
|
||||||
|
"debug": "调试模式",
|
||||||
|
"download": "下载",
|
||||||
|
"encryptor": "加密器",
|
||||||
|
"feedback": "反馈",
|
||||||
|
"generateResult": "生成结果",
|
||||||
|
"generator": "生成器",
|
||||||
|
"headerName": "请求头名称",
|
||||||
|
"headerValue": "请求头值",
|
||||||
|
"implementationClass": "实现类",
|
||||||
|
"loading": "加载中...",
|
||||||
|
"mainConfig.title": "核心配置",
|
||||||
|
"MemShellGenerator": "内存马生成器",
|
||||||
|
"optional": "(可选)",
|
||||||
|
"packerConfig.title": "打包配置",
|
||||||
|
"packerMethod": "打包方式",
|
||||||
|
"paramName": "参数名称",
|
||||||
|
"placeholders.input": "请输入",
|
||||||
|
"placeholders.select": "请选择",
|
||||||
|
"ProbeShellGenerator": "探测马生成器",
|
||||||
|
"quickUsage.title": "快速使用",
|
||||||
|
"server": "服务类型",
|
||||||
|
"serverVersion": "服务版本",
|
||||||
|
"shrink": "缩小字节码",
|
||||||
|
"toast.generateError": "生成失败,{{error}}",
|
||||||
|
"toast.generateSuccess": "生成成功",
|
||||||
|
"urlPattern": "请求路径",
|
||||||
|
"usage": "使用指南",
|
||||||
|
"version.updateAvailable": "有可用升级",
|
||||||
|
"version.updateAvailableTooltip": "点击前往 GitHub Release ( v{{currentVersion}} -> v{{latestVersion}})"
|
||||||
|
}
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
{
|
|
||||||
"basicInfo.classInfo": "ShellClass",
|
|
||||||
"basicInfo.serverInfo": "TargetServer",
|
|
||||||
"basicInfo.toolInfo": "ShellTool",
|
|
||||||
"buttons.generate": "Generate Shell",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"configs.main-config": "Main Config",
|
|
||||||
"configs.package-config": "Package Config",
|
|
||||||
"copyLabelSuccess": "Copy {{label}} successfully",
|
|
||||||
"copySuccess": "Copy successfully",
|
|
||||||
"download": "Downlaod",
|
|
||||||
"errors.generationFailed": "Generation failed, {{error}}",
|
|
||||||
"feedback": "Feedback",
|
|
||||||
"generateResult.basicInfo": "Basic Info",
|
|
||||||
"generateResult.title1": "Generate Result",
|
|
||||||
"generateResult.title2": "Shell Class",
|
|
||||||
"generateResult.title3": "Injector Class",
|
|
||||||
"generateResult.usage": "Usage",
|
|
||||||
"loading": "Loading...",
|
|
||||||
"mainConfig.byPassJavaModule": "Bypass Java Module",
|
|
||||||
"mainConfig.debug": "Debug Mode",
|
|
||||||
"mainConfig.injectorClassName": "Injector ClassName",
|
|
||||||
"mainConfig.jre": "Target JRE Version",
|
|
||||||
"mainConfig.server": "Target Server",
|
|
||||||
"mainConfig.serverVersion": "Target Server Version",
|
|
||||||
"mainConfig.shellClassName": "Shell ClassName",
|
|
||||||
"mainConfig.shellMountType": "Shell Mount Type",
|
|
||||||
"mainConfig.shellTool": "Shell Tool",
|
|
||||||
"mainConfig.shrink": "Shrink Bytecode",
|
|
||||||
"mainConfig.urlPattern": "URL Pattern",
|
|
||||||
"optional": "(Optional)",
|
|
||||||
"packageConfig.packer.AgentJar": "AgentJar",
|
|
||||||
"packageConfig.packer.Aviator": "Aviator",
|
|
||||||
"packageConfig.packer.BCEL": "BCEL",
|
|
||||||
"packageConfig.packer.Base64": "Base64",
|
|
||||||
"packageConfig.packer.BeanShell": "BeanShell",
|
|
||||||
"packageConfig.packer.EL": "EL",
|
|
||||||
"packageConfig.packer.Freemarker": "Freemarker",
|
|
||||||
"packageConfig.packer.Groovy": "Groovy",
|
|
||||||
"packageConfig.packer.GzipBase64": "GzipBase64",
|
|
||||||
"packageConfig.packer.Hessian2Deserialize": "Hessian2Deserialize",
|
|
||||||
"packageConfig.packer.HessianDeserialize": "HessianDeserialize",
|
|
||||||
"packageConfig.packer.JEXL": "JEXL",
|
|
||||||
"packageConfig.packer.JSP": "JSP",
|
|
||||||
"packageConfig.packer.JXPath": "JXPath",
|
|
||||||
"packageConfig.packer.Jar": "Jar",
|
|
||||||
"packageConfig.packer.JavaDeserialize": "JavaDeserialize",
|
|
||||||
"packageConfig.packer.JinJava": "JinJava",
|
|
||||||
"packageConfig.packer.MVEL": "MVEL",
|
|
||||||
"packageConfig.packer.OGNL": "OGNL",
|
|
||||||
"packageConfig.packer.Rhino": "Rhino",
|
|
||||||
"packageConfig.packer.ScriptEngine": "ScriptEngine",
|
|
||||||
"packageConfig.packer.SpEL": "SpEL",
|
|
||||||
"packageConfig.packer.Velocity": "Velocity",
|
|
||||||
"packageConfig.packer.XxlJob": "XXL-JOB Executor",
|
|
||||||
"packageConfig.packer.AgentJarWithJDKAttacher": "AgentJarWithJDKAttacher",
|
|
||||||
"packageConfig.packer.AgentJarWithJREAttacher": "AgentJarWithJREAttacher",
|
|
||||||
"packageConfig.packer.H2": "H2 JDBC",
|
|
||||||
"packageConfig.packer.XMLDecoder": "XMLDecoder",
|
|
||||||
"packageConfig.title": "Package Method",
|
|
||||||
"placeholders.input": "Please input",
|
|
||||||
"placeholders.select": "Please select",
|
|
||||||
"quickUsage.step1": "Select Target Server",
|
|
||||||
"quickUsage.step2": "Select Shell Tool, Godzilla, Behinder, etc.",
|
|
||||||
"quickUsage.step3": "Select Shell Mount Type, Filter, Listener, etc.",
|
|
||||||
"quickUsage.step4": "Select Packing Method",
|
|
||||||
"quickUsage.step5": "Click Generate Shell",
|
|
||||||
"quickUsage.title": "Quick Usage",
|
|
||||||
"shellNotWork.step1": "1. Try to enable the debug mode, regenerate the memory shell and inject it, check the console or log",
|
|
||||||
"shellNotWork.step2": "2. If an exception stack trace is displayed, or no exception is seen, please take a screenshot of the current generation interface and the exception log, and describe the target environment as much as possible for feedback",
|
|
||||||
"shellNotWork.title": "Shell Not Work ?",
|
|
||||||
"shellToolConfig.antSwordPass": "Shell pwd",
|
|
||||||
"shellToolConfig.behinder": "Behinder",
|
|
||||||
"shellToolConfig.behinderDefaultEncryptType": "Default",
|
|
||||||
"shellToolConfig.behinderEncryptType": "Encrypt Type",
|
|
||||||
"shellToolConfig.behinderPass": "Pass",
|
|
||||||
"shellToolConfig.behinderScriptType": "Script Type",
|
|
||||||
"shellToolConfig.command": "Command",
|
|
||||||
"shellToolConfig.customHeader": "Custom Header",
|
|
||||||
"shellToolConfig.godzilla": "Godzilla",
|
|
||||||
"shellToolConfig.godzillaEncryptor": "Encryptor",
|
|
||||||
"shellToolConfig.godzillaHeader": "Request Config -> Request Header",
|
|
||||||
"shellToolConfig.godzillaPayload": "Payload",
|
|
||||||
"shellToolConfig.headerName": "Header Name",
|
|
||||||
"shellToolConfig.headerValue": "Header Value",
|
|
||||||
"shellToolConfig.httpHeader": "HTTP -> HTTP HEADERS",
|
|
||||||
"shellToolConfig.key": "Key",
|
|
||||||
"shellToolConfig.neoreGeorgHeader": "Custom Header",
|
|
||||||
"shellToolConfig.neoreGeorgKey": "Connection Key",
|
|
||||||
"shellToolConfig.paramName": "Param Name",
|
|
||||||
"shellToolConfig.pass": "Pass",
|
|
||||||
"shellToolConfig.suo5Header": "AdvanceConfiguration -> Request Header",
|
|
||||||
"shellToolConfig.base64String": "Shell Class",
|
|
||||||
"shellToolConfig.encryptor": "Encryptor",
|
|
||||||
"shellToolConfig.implementationClass": "ImplementationClass",
|
|
||||||
"success.generated": "Generation successful",
|
|
||||||
"tips.controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller",
|
|
||||||
"tips.decompileTip": "Decompilation is still under development, so the current only sees the base64 encoding format",
|
|
||||||
"tips.download-jattach": "Download the Jattach tool",
|
|
||||||
"tips.execute-command": "Execute the command to inject: /path/to/jattach pid load instrument false /path/to/agent.jar",
|
|
||||||
"tips.execute-command1": "Execute the command to inject: java -jar /path/to/agent.jar pid",
|
|
||||||
"tips.get-pid": "Get the process pid of the target jvm (use jps or ps)",
|
|
||||||
"tips.handlerUrlPattern": "HandlerMethod/HandlerFunction type requires a specific URL Pattern, e.g., /hello_handler",
|
|
||||||
"tips.jreTip": "Target JRE version, generally speaking, Java 6 is the default version for maximum compatibility, and Java high versions can load low version bytecode.",
|
|
||||||
"tips.jreTip2": "In specific cases, such as JDK8 being able to use lambda expressions, and JDK9 and above having module restrictions, a specific version is required.",
|
|
||||||
"tips.agent-move-to-target": "Move MemShellAgent.jar and jattach to target host",
|
|
||||||
"tips.agent-move-to-target1": "Move MemShellAgent.jar to target host",
|
|
||||||
"tips.servletUrlPattern": "Servlet type requires a specific URL Pattern, e.g., /hello_servlet",
|
|
||||||
"tips.specificUrlPattern": "URL Pattern must be specified, e.g., /hello",
|
|
||||||
"tips.shellBytesEmpty": "Shell bytes is empty, please generate shell first",
|
|
||||||
"tips.shellToolNotSelected": "Please select a shell tool type first",
|
|
||||||
"tips.targetServerNotFound": "Target server not found?",
|
|
||||||
"tips.targetServerRequest": "Request",
|
|
||||||
"tips.try-to-use-shell": "Try to use the memory shell",
|
|
||||||
"tips.waitingForGeneration": "// Waiting for generation...",
|
|
||||||
"tips.customShellClass": "Custom shell class is required, base64 or classfile",
|
|
||||||
"tips.serverVersion": "serverVersion is required for TongWeb Valve",
|
|
||||||
"version.updateAvailable": "Update Available",
|
|
||||||
"version.updateAvailableTooltip": "Click to Open Github Release Page ( v{{currentVersion}} -> v{{latestVersion}})",
|
|
||||||
"generator": "Generator",
|
|
||||||
"about": "About",
|
|
||||||
"classNameOptions": "classNameOptions"
|
|
||||||
}
|
|
||||||
+34
-9
@@ -1,28 +1,53 @@
|
|||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
import { resources } from "./translations";
|
import commonEN from "@/i18n/common/en.json";
|
||||||
|
import commonZH from "@/i18n/common/zh-CN.json";
|
||||||
|
import memshellEN from "@/i18n/memshell/en.json";
|
||||||
|
import memshellZH from "@/i18n/memshell/zh-CN.json";
|
||||||
|
import probeshellEN from "@/i18n/probeshell/en.json";
|
||||||
|
import probeshellZH from "@/i18n/probeshell/zh-CN.json";
|
||||||
|
|
||||||
const getStoredLanguage = () => {
|
const getStoredLanguage = () => {
|
||||||
const storedLang = localStorage.getItem("i18nextLng");
|
const storedLang = localStorage.getItem("i18nextLng");
|
||||||
if (storedLang && ["en", "zh"].includes(storedLang)) {
|
if (storedLang && ["en", "zh-CN"].includes(storedLang)) {
|
||||||
return storedLang;
|
return storedLang;
|
||||||
}
|
}
|
||||||
const browserLang = navigator.language.split("-")[0];
|
const browserLang = navigator.language.split("-")[0];
|
||||||
return ["en", "zh"].includes(browserLang) ? browserLang : "en";
|
return ["en", "zh-CN"].includes(browserLang) ? browserLang : "en";
|
||||||
|
};
|
||||||
|
|
||||||
|
const fallbackLng = "en";
|
||||||
|
export const ns = [
|
||||||
|
"default",
|
||||||
|
"common",
|
||||||
|
"memshell",
|
||||||
|
"probeshell",
|
||||||
|
"errors",
|
||||||
|
] as const;
|
||||||
|
export const defaultNS = "default" as const;
|
||||||
|
|
||||||
|
const resources = {
|
||||||
|
"zh-CN": {
|
||||||
|
common: commonZH,
|
||||||
|
memshell: memshellZH,
|
||||||
|
probeshell: probeshellZH,
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
common: commonEN,
|
||||||
|
memshell: memshellEN,
|
||||||
|
probeshell: probeshellEN,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
i18n.use(initReactI18next).init({
|
i18n.use(initReactI18next).init({
|
||||||
|
ns,
|
||||||
|
defaultNS,
|
||||||
resources,
|
resources,
|
||||||
lng: getStoredLanguage(),
|
lng: getStoredLanguage(),
|
||||||
fallbackLng: "en",
|
fallbackLng,
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false,
|
escapeValue: false,
|
||||||
},
|
},
|
||||||
detection: {
|
|
||||||
order: ["localStorage", "navigator"],
|
|
||||||
},
|
|
||||||
saveMissing: true,
|
|
||||||
load: "languageOnly",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
i18n.on("languageChanged", (lng) => {
|
i18n.on("languageChanged", (lng) => {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"basicInfo.classInfo": "ShellClass",
|
||||||
|
"basicInfo.serverInfo": "TargetServer",
|
||||||
|
"basicInfo.toolInfo": "ShellTool",
|
||||||
|
"buttons.generate": "Generate Shell",
|
||||||
|
"classNameOptions": "ClassNameOptions",
|
||||||
|
"injectorClass": "InjectorClass",
|
||||||
|
"mainConfig.injectorClassName": "Injector ClassName",
|
||||||
|
"mainConfig.shellClassName": "Shell ClassName",
|
||||||
|
"mainConfig.shellMountType": "Shell Mount Type",
|
||||||
|
"mainConfig.shellTool": "ShellTool",
|
||||||
|
"quickUsage.step1": "Select Target Server",
|
||||||
|
"quickUsage.step2": "Select Shell Tool, Godzilla, Behinder, etc.",
|
||||||
|
"quickUsage.step3": "Select Shell Mount Type, Filter, Listener, etc.",
|
||||||
|
"quickUsage.step4": "Select Packing Method",
|
||||||
|
"quickUsage.step5": "Click Generate Shell",
|
||||||
|
"shellClass": "ShellClass",
|
||||||
|
"shellNotWork.step1": "1. Try to enable the debug mode, regenerate the memory shell and inject it, check the console or log",
|
||||||
|
"shellNotWork.step2": "2. If an exception stack trace is displayed, or no exception is seen, please take a screenshot of the current generation interface and the exception log, and describe the target environment as much as possible for feedback",
|
||||||
|
"shellNotWork.title": "Shell Not Work ?",
|
||||||
|
"shellToolConfig.antSword.pass": "Shell pwd",
|
||||||
|
"shellToolConfig.behinder": "Behinder",
|
||||||
|
"shellToolConfig.behinder.header": "Custom Header",
|
||||||
|
"shellToolConfig.behinder.pass": "Pass",
|
||||||
|
"shellToolConfig.behinderDefaultEncryptType": "Default",
|
||||||
|
"shellToolConfig.behinderEncryptType": "Encrypt Type",
|
||||||
|
"shellToolConfig.behinderScriptType": "Script Type",
|
||||||
|
"shellToolConfig.command": "Command",
|
||||||
|
"shellToolConfig.godzilla": "Godzilla",
|
||||||
|
"shellToolConfig.godzilla.encryptor": "Encryptor",
|
||||||
|
"shellToolConfig.godzilla.header": "Request Config -> Request Header",
|
||||||
|
"shellToolConfig.godzilla.key": "Key",
|
||||||
|
"shellToolConfig.godzilla.pass": "Pass",
|
||||||
|
"shellToolConfig.godzilla.payload": "Payload",
|
||||||
|
"shellToolConfig.httpHeader": "HTTP -> HTTP HEADERS",
|
||||||
|
"shellToolConfig.neoreGeorgHeader": "Custom Header",
|
||||||
|
"shellToolConfig.neoreGeorgKey": "Connection Key",
|
||||||
|
"shellToolConfig.suo5Header": "AdvanceConfiguration -> Request Header",
|
||||||
|
"tips.agent-move-to-target": "Move MemShellAgent.jar and jattach to target host",
|
||||||
|
"tips.agent-move-to-target1": "Move MemShellAgent.jar to target host",
|
||||||
|
"tips.controllerUrlPattern": "ControllerHandler type requires a specific URL Pattern, e.g., /hello_controller",
|
||||||
|
"tips.customShellClass": "Custom shell class is required, base64 or classfile",
|
||||||
|
"tips.download-jattach": "Download the Jattach tool",
|
||||||
|
"tips.execute-command": "Execute the command to inject: /path/to/jattach pid load instrument false /path/to/agent.jar",
|
||||||
|
"tips.execute-command1": "Execute the command to inject: java -jar /path/to/agent.jar pid",
|
||||||
|
"tips.get-pid": "Get the process pid of the target jvm (use jps or ps)",
|
||||||
|
"tips.handlerUrlPattern": "HandlerMethod/HandlerFunction type requires a specific URL Pattern, e.g., /hello_handler",
|
||||||
|
"tips.serverVersion": "serverVersion is required for TongWeb Valve",
|
||||||
|
"tips.servletUrlPattern": "Servlet type requires a specific URL Pattern, e.g., /hello_servlet",
|
||||||
|
"tips.shellBytesEmpty": "Shell bytes is empty, please generate shell first",
|
||||||
|
"tips.shellToolNotSelected": "Please select a shell tool type first",
|
||||||
|
"tips.specificUrlPattern": "URL Pattern must be specified, e.g., /hello",
|
||||||
|
"tips.targetServerNotFound": "Target server not found?",
|
||||||
|
"tips.targetServerRequest": "Request",
|
||||||
|
"tips.try-to-use-shell": "Try to use the memory shell"
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"basicInfo.classInfo": "内存马类信息",
|
||||||
|
"basicInfo.serverInfo": "目标服务信息",
|
||||||
|
"basicInfo.toolInfo": "内存马工具信息",
|
||||||
|
"buttons.generate": "生成内存马",
|
||||||
|
"injectorClass": "注入器",
|
||||||
|
"shellClass": "内存马",
|
||||||
|
"classNameOptions": "类名配置项",
|
||||||
|
"mainConfig.injectorClassName": "注入器类名",
|
||||||
|
"mainConfig.shellClassName": "内存马类名",
|
||||||
|
"mainConfig.shellMountType": "内存马挂载类型",
|
||||||
|
"mainConfig.shellTool": "内存马功能",
|
||||||
|
"quickUsage.step1": "选择目标服务",
|
||||||
|
"quickUsage.step2": "选择内存马功能,Godzilla、Behinder 或者其他",
|
||||||
|
"quickUsage.step3": "选择内存马挂载类型,Filter、Listener 或者其他",
|
||||||
|
"quickUsage.step4": "选择打包方式",
|
||||||
|
"quickUsage.step5": "点击生成内存马",
|
||||||
|
"shellNotWork.step1": "1. 尝试开启调试模式,重新生成并注入,查看控制台或日志",
|
||||||
|
"shellNotWork.step2": "2. 如果出现异常堆栈信息,或未见异常,请截图当前生成界面以及异常日志,并尽可能描述目标环境进行反馈",
|
||||||
|
"shellNotWork.title": "利用失败?",
|
||||||
|
"shellToolConfig.antSword.pass": "连接密码",
|
||||||
|
"shellToolConfig.behinder": "冰蝎",
|
||||||
|
"shellToolConfig.behinder.header": "自定义请求头",
|
||||||
|
"shellToolConfig.behinder.pass": "连接密码",
|
||||||
|
"shellToolConfig.behinderDefaultEncryptType": "默认",
|
||||||
|
"shellToolConfig.behinderEncryptType": "加密类型",
|
||||||
|
"shellToolConfig.behinderScriptType": "脚本类型",
|
||||||
|
"shellToolConfig.command": "命令回显",
|
||||||
|
"shellToolConfig.godzilla": "哥斯拉",
|
||||||
|
"shellToolConfig.godzilla.encryptor": "加密器",
|
||||||
|
"shellToolConfig.godzilla.header": "请求配置 -> 请求头",
|
||||||
|
"shellToolConfig.godzilla.key": "密钥",
|
||||||
|
"shellToolConfig.godzilla.pass": "密码",
|
||||||
|
"shellToolConfig.godzilla.payload": "有效载荷",
|
||||||
|
"shellToolConfig.httpHeader": "请求信息 -> HTTP HEADERS",
|
||||||
|
"shellToolConfig.neoreGeorgHeader": "自定义请求头",
|
||||||
|
"shellToolConfig.neoreGeorgKey": "连接密钥",
|
||||||
|
"shellToolConfig.suo5Header": "高级配置 -> 请求头",
|
||||||
|
"tips.agent-move-to-target": "将 MemShellAgent.jar 和 jattach 移到到目标服务磁盘上",
|
||||||
|
"tips.agent-move-to-target1": "将 MemShellAgent.jar 移到到目标服务磁盘上",
|
||||||
|
"tips.controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller",
|
||||||
|
"tips.customShellClass": "请输入自定义内存马类,base64 或类文件",
|
||||||
|
"tips.download-jattach": "下载 Jattach 工具",
|
||||||
|
"tips.execute-command": "执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar",
|
||||||
|
"tips.execute-command1": "执行命令进行注入:java -jar /path/to/agent.jar pid",
|
||||||
|
"tips.get-pid": "获取目标 jvm 的进程 pid(使用 jps 或 ps)",
|
||||||
|
"tips.handlerUrlPattern": "HandlerMethod/HandlerFunction 类型的需要填写具体的 URL Pattern,例如 /hello_handler",
|
||||||
|
"tips.serverVersion": "TongWeb Valve 需要指定 serverVersion",
|
||||||
|
"tips.servletUrlPattern": "Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet",
|
||||||
|
"tips.shellBytesEmpty": "内存马字节码为空,无法下载,请先生成内存马",
|
||||||
|
"tips.shellToolNotSelected": "请先选择内存马工具类型",
|
||||||
|
"tips.specificUrlPattern": "必须指定 URL Pattern,例如 /hello",
|
||||||
|
"tips.targetServerNotFound": "找不到目标服务?",
|
||||||
|
"tips.targetServerRequest": "请求适配",
|
||||||
|
"tips.try-to-use-shell": "尝试利用内存马",
|
||||||
|
"shellNotWork": {
|
||||||
|
"title": "利用失败?"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"buttons.generate": "Generate Shell",
|
||||||
|
"dnslog.host": "DNSLog Host",
|
||||||
|
"probeContent": "ProbeContent",
|
||||||
|
"probeContent.bytecode": "Bytecode",
|
||||||
|
"probeContent.command": "Command",
|
||||||
|
"probeContent.jdk": "JDK",
|
||||||
|
"probeContent.server": "Server",
|
||||||
|
"probeMethod": "ProbeMethod",
|
||||||
|
"quickUsage.step1": "Select Probe Method, DNSLog, Response, etc.",
|
||||||
|
"quickUsage.step2": "Select Probe Content, JDK, Server, etc.",
|
||||||
|
"quickUsage.step3": "Click Generate Shell",
|
||||||
|
"shellClassName": "ShellClassName",
|
||||||
|
"sleepSeconds": "SleepTime (seconds)",
|
||||||
|
"sleepServer": "SleepServer",
|
||||||
|
"tips.dnslog.host.required": "DNSLog host required",
|
||||||
|
"tips.response.reqParamName.required": "ParamName required"
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"buttons.generate": "生成探测马",
|
||||||
|
"dnslog.host": "DNSLog 地址",
|
||||||
|
"probeContent": "探测内容",
|
||||||
|
"probeContent.bytecode": "自定义字节码执行",
|
||||||
|
"probeContent.command": "命令执行",
|
||||||
|
"probeContent.jdk": "JDK 信息",
|
||||||
|
"probeContent.server": "服务类型",
|
||||||
|
"probeMethod": "探测方法",
|
||||||
|
"quickUsage.step1": "选择探测方法,DNSLog、Response 或者其他",
|
||||||
|
"quickUsage.step2": "选择探测内容,JDK、服务类型 或者其他",
|
||||||
|
"quickUsage.step3": "点击生成探测马",
|
||||||
|
"shellClassName": "探测马类名",
|
||||||
|
"sleepSeconds": "延迟时间(秒)",
|
||||||
|
"sleepServer": "探测服务",
|
||||||
|
"tips.dnslog.host.required": "DNSLog 地址必填",
|
||||||
|
"tips.response.reqParamName.required": "参数名称必填"
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import en from "./en.json";
|
|
||||||
import zh from "./zh-CN.json";
|
|
||||||
export const resources = {
|
|
||||||
en: {
|
|
||||||
translation: en,
|
|
||||||
},
|
|
||||||
zh: {
|
|
||||||
translation: zh,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
{
|
|
||||||
"basicInfo.classInfo": "内存马类信息",
|
|
||||||
"basicInfo.serverInfo": "目标服务信息",
|
|
||||||
"basicInfo.toolInfo": "内存马工具信息",
|
|
||||||
"buttons.generate": "生成内存马",
|
|
||||||
"cancel": "取消",
|
|
||||||
"configs.main-config": "核心配置",
|
|
||||||
"configs.package-config": "打包配置",
|
|
||||||
"copyLabelSuccess": "复制 {{label}} 成功",
|
|
||||||
"copySuccess": "复制成功",
|
|
||||||
"download": "下载",
|
|
||||||
"errors.generationFailed": "生成失败,{{error}}",
|
|
||||||
"feedback": "反馈",
|
|
||||||
"generateResult.basicInfo": "基本信息",
|
|
||||||
"generateResult.title1": "生成结果",
|
|
||||||
"generateResult.title2": "内存马类",
|
|
||||||
"generateResult.title3": "注入器类",
|
|
||||||
"generateResult.usage": "使用方法",
|
|
||||||
"loading": "加载中...",
|
|
||||||
"mainConfig.byPassJavaModule": "绕过 Java 模块限制",
|
|
||||||
"mainConfig.debug": "调试模式",
|
|
||||||
"mainConfig.injectorClassName": "注入器类名",
|
|
||||||
"mainConfig.jre": "目标 JRE 版本",
|
|
||||||
"mainConfig.server": "目标服务",
|
|
||||||
"mainConfig.serverVersion": "目标服务版本",
|
|
||||||
"mainConfig.shellClassName": "内存马类名",
|
|
||||||
"mainConfig.shellMountType": "内存马挂载类型",
|
|
||||||
"mainConfig.shellTool": "内存马功能",
|
|
||||||
"mainConfig.shrink": "缩小字节码",
|
|
||||||
"mainConfig.urlPattern": "请求路径",
|
|
||||||
"optional": "(可选)",
|
|
||||||
"packageConfig.packer.AgentJar": "AgentJar",
|
|
||||||
"packageConfig.packer.Aviator": "Aviator 表达式",
|
|
||||||
"packageConfig.packer.BCEL": "BCEL",
|
|
||||||
"packageConfig.packer.Base64": "Base64",
|
|
||||||
"packageConfig.packer.BeanShell": "BeanShell 表达式",
|
|
||||||
"packageConfig.packer.EL": "EL 表达式",
|
|
||||||
"packageConfig.packer.Freemarker": "Freemarker",
|
|
||||||
"packageConfig.packer.Groovy": "Groovy",
|
|
||||||
"packageConfig.packer.GzipBase64": "GzipBase64",
|
|
||||||
"packageConfig.packer.Hessian2Deserialize": "Hessian2 反序列化",
|
|
||||||
"packageConfig.packer.HessianDeserialize": "Hessian 反序列化",
|
|
||||||
"packageConfig.packer.JEXL": "JEXL 表达式",
|
|
||||||
"packageConfig.packer.JSP": "JSP",
|
|
||||||
"packageConfig.packer.JXPath": "JXPath 表达式",
|
|
||||||
"packageConfig.packer.Jar": "Jar",
|
|
||||||
"packageConfig.packer.JavaDeserialize": "Java 反序列化",
|
|
||||||
"packageConfig.packer.JinJava": "JinJava",
|
|
||||||
"packageConfig.packer.MVEL": "MVEL 表达式",
|
|
||||||
"packageConfig.packer.OGNL": "OGNL 表达式",
|
|
||||||
"packageConfig.packer.Rhino": "Rhino 脚本引擎",
|
|
||||||
"packageConfig.packer.ScriptEngine": "内置脚本引擎",
|
|
||||||
"packageConfig.packer.SpEL": "SpEL 表达式",
|
|
||||||
"packageConfig.packer.Velocity": "Velocity",
|
|
||||||
"packageConfig.packer.XxlJob": "XXL-JOB Executor",
|
|
||||||
"packageConfig.packer.AgentJarWithJDKAttacher": "AgentJarWithJDKAttacher",
|
|
||||||
"packageConfig.packer.AgentJarWithJREAttacher": "AgentJarWithJREAttacher",
|
|
||||||
"packageConfig.title": "打包方式",
|
|
||||||
"placeholders.input": "请输入",
|
|
||||||
"placeholders.select": "请选择",
|
|
||||||
"quickUsage.step1": "选择目标服务",
|
|
||||||
"quickUsage.step2": "选择内存马功能,Godzilla、Behinder 或者其他",
|
|
||||||
"quickUsage.step3": "选择内存马挂载类型,Filter、Listener 或者其他",
|
|
||||||
"quickUsage.step4": "选择打包方式",
|
|
||||||
"quickUsage.step5": "点击生成内存马",
|
|
||||||
"quickUsage.title": "快速使用",
|
|
||||||
"shellNotWork.step1": "1. 尝试开启调试模式,重新生成内存马并注入,查看控制台或日志",
|
|
||||||
"shellNotWork.step2": "2. 如果出现异常堆栈信息,或未见异常,请截图当前生成界面以及异常日志,并尽可能描述目标环境进行反馈",
|
|
||||||
"shellNotWork.title": "内存马利用失败?",
|
|
||||||
"shellToolConfig.antSwordPass": "连接密码",
|
|
||||||
"shellToolConfig.behinder": "冰蝎",
|
|
||||||
"shellToolConfig.behinderDefaultEncryptType": "默认",
|
|
||||||
"shellToolConfig.behinderEncryptType": "加密类型",
|
|
||||||
"shellToolConfig.behinderPass": "连接密码",
|
|
||||||
"shellToolConfig.behinderScriptType": "脚本类型",
|
|
||||||
"shellToolConfig.command": "命令回显",
|
|
||||||
"shellToolConfig.customHeader": "自定义请求头",
|
|
||||||
"shellToolConfig.godzilla": "哥斯拉",
|
|
||||||
"shellToolConfig.godzillaEncryptor": "加密器",
|
|
||||||
"shellToolConfig.godzillaHeader": "请求配置 -> 请求头",
|
|
||||||
"shellToolConfig.godzillaPayload": "有效载荷",
|
|
||||||
"shellToolConfig.headerName": "请求头键",
|
|
||||||
"shellToolConfig.headerValue": "请求头值",
|
|
||||||
"shellToolConfig.httpHeader": "请求信息 -> HTTP HEADERS",
|
|
||||||
"shellToolConfig.key": "密钥",
|
|
||||||
"shellToolConfig.neoreGeorgHeader": "自定义请求头",
|
|
||||||
"shellToolConfig.neoreGeorgKey": "连接密钥",
|
|
||||||
"shellToolConfig.paramName": "请求参数",
|
|
||||||
"shellToolConfig.pass": "密码",
|
|
||||||
"shellToolConfig.suo5Header": "高级配置 -> 请求头",
|
|
||||||
"shellToolConfig.base64String": "内存马类",
|
|
||||||
"shellToolConfig.encryptor": "加密器",
|
|
||||||
"shellToolConfig.implementationClass": "实现类",
|
|
||||||
"success.generated": "生成成功",
|
|
||||||
"tips.controllerUrlPattern": "ControllerHandler 类型的需要填写具体的 URL Pattern,例如 /hello_controller",
|
|
||||||
"tips.decompileTip": "反编译还在开发中,因此当前仅能看到 base64 编码格式",
|
|
||||||
"tips.download-jattach": "下载 Jattach 工具",
|
|
||||||
"tips.execute-command": "执行命令进行注入:/path/to/jattach pid load instrument false /path/to/agent.jar",
|
|
||||||
"tips.execute-command1": "执行命令进行注入:java -jar /path/to/agent.jar pid",
|
|
||||||
"tips.get-pid": "获取目标 jvm 的进程 pid(使用 jps 或 ps)",
|
|
||||||
"tips.handlerUrlPattern": "HandlerMethod/HandlerFunction 类型的需要填写具体的 URL Pattern,例如 /hello_handler",
|
|
||||||
"tips.jreTip": "目标 JRE 版本,一般而言为了最大的兼容性,默认 Java 6 即可,Java 高版本能加载低版本的字节码。",
|
|
||||||
"tips.jreTip2": "特定情况下,例如 JDK8 才能使用 lambda 表达式,JDK9 以上存在模块限制时才需要选择特定的版本。",
|
|
||||||
"tips.agent-move-to-target": "将 MemShellAgent.jar 和 jattach 移到到目标服务磁盘上",
|
|
||||||
"tips.agent-move-to-target1": "将 MemShellAgent.jar 移到到目标服务磁盘上",
|
|
||||||
"tips.servletUrlPattern": "Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet",
|
|
||||||
"tips.shellBytesEmpty": "内存马字节码为空,无法下载,请先生成内存马",
|
|
||||||
"tips.shellToolNotSelected": "请先选择内存马工具类型",
|
|
||||||
"tips.targetServerNotFound": "找不到目标服务?",
|
|
||||||
"tips.targetServerRequest": "请求适配",
|
|
||||||
"tips.try-to-use-shell": "尝试利用内存马",
|
|
||||||
"tips.waitingForGeneration": "// 等待填写参数生成中...",
|
|
||||||
"tips.customShellClass": "请输入自定义内存马类,base64 或类文件",
|
|
||||||
"tips.specificUrlPattern": "必须指定 URL Pattern,例如 /hello",
|
|
||||||
"tips.serverVersion": "TongWeb Valve 需要指定 serverVersion",
|
|
||||||
"version.updateAvailable": "有可用升级",
|
|
||||||
"version.updateAvailableTooltip": "点击前往 GitHub Release ( v{{currentVersion}} -> v{{latestVersion}})",
|
|
||||||
"about": "关于",
|
|
||||||
"generator": "生成器",
|
|
||||||
"classNameOptions": "类名配置项"
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,12 @@ export const siteConfig = {
|
|||||||
name: "MemShellParty",
|
name: "MemShellParty",
|
||||||
url: "https://party.memshell.news",
|
url: "https://party.memshell.news",
|
||||||
github: "https://github.com/ReaJason/MemShellParty",
|
github: "https://github.com/ReaJason/MemShellParty",
|
||||||
|
latestRelease: "https://github.com/ReaJason/MemShellParty/releases/latest",
|
||||||
|
docSite: "https://github.com/ReaJason/MemShellParty/wiki",
|
||||||
|
author: "ReaJason",
|
||||||
|
authorGithub: "https://github.com/ReaJason",
|
||||||
|
authorIntro: "Java RASP Developer",
|
||||||
|
blog: "https://reajason.eu.org",
|
||||||
navItems: [
|
navItems: [
|
||||||
{
|
{
|
||||||
href: "/memshell",
|
href: "/memshell",
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default function MemShellPage() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "memshell"]);
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
resolver: useYupValidationResolver(memShellFormSchema, t),
|
resolver: useYupValidationResolver(memShellFormSchema, t),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@@ -103,7 +103,7 @@ export default function MemShellPage() {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const json: APIErrorResponse = await response.json();
|
const json: APIErrorResponse = await response.json();
|
||||||
toast.error(t("errors.generationFailed", { error: json.error }));
|
toast.error(t("toast.generateError", { error: json.error }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,22 +112,35 @@ export default function MemShellPage() {
|
|||||||
setPackResult(result.packResult);
|
setPackResult(result.packResult);
|
||||||
setAllPackResults(result.allPackResults);
|
setAllPackResults(result.allPackResults);
|
||||||
setPackMethod(data.packingMethod);
|
setPackMethod(data.packingMethod);
|
||||||
toast.success(t("success.generated"));
|
toast.success(t("toast.generateSuccess"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(t("errors.generationFailed", { error: (error as Error).message }));
|
toast.error(
|
||||||
|
t("toast.generateError", { error: (error as Error).message }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col xl:flex-row gap-4 p-4">
|
<form
|
||||||
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
|
className="flex flex-col xl:flex-row gap-4 p-4"
|
||||||
|
>
|
||||||
<div className="w-full xl:w-1/2 space-y-4">
|
<div className="w-full xl:w-1/2 space-y-4">
|
||||||
<MainConfigCard servers={serverConfig} mainConfig={mainConfig} form={form} />
|
<MainConfigCard
|
||||||
|
servers={serverConfig}
|
||||||
|
mainConfig={mainConfig}
|
||||||
|
form={form}
|
||||||
|
/>
|
||||||
<PackageConfigCard packerConfig={packerConfig} form={form} />
|
<PackageConfigCard packerConfig={packerConfig} form={form} />
|
||||||
<Button className="w-full" type="submit" disabled={isActionPending}>
|
<Button className="w-full" type="submit" disabled={isActionPending}>
|
||||||
{isActionPending ? <LoaderCircle className="animate-spin" /> : <WandSparklesIcon />}
|
{isActionPending ? (
|
||||||
{t("buttons.generate")}
|
<LoaderCircle className="animate-spin" />
|
||||||
|
) : (
|
||||||
|
<WandSparklesIcon />
|
||||||
|
)}
|
||||||
|
{t("memshell:buttons.generate")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full xl:w-1/2 space-y-4">
|
<div className="w-full xl:w-1/2 space-y-4">
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export default function ProbeShellGenerator() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation(["common", "probeshell"]);
|
||||||
|
|
||||||
const form = useForm<ProbeShellFormSchema>({
|
const form = useForm<ProbeShellFormSchema>({
|
||||||
resolver: useYupValidationProbeResolver(probeShellFormSchema, t),
|
resolver: useYupValidationProbeResolver(probeShellFormSchema, t),
|
||||||
@@ -82,7 +82,7 @@ export default function ProbeShellGenerator() {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const json: APIErrorResponse = await response.json();
|
const json: APIErrorResponse = await response.json();
|
||||||
toast.error(t("errors.generationFailed", { error: json.error }));
|
toast.error(t("toast.generateError", { error: json.error }));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,21 +91,30 @@ export default function ProbeShellGenerator() {
|
|||||||
setPackResult(result.packResult);
|
setPackResult(result.packResult);
|
||||||
setAllPackResults(result.allPackResults);
|
setAllPackResults(result.allPackResults);
|
||||||
setPackMethod(data.packingMethod);
|
setPackMethod(data.packingMethod);
|
||||||
toast.success(t("success.generated"));
|
toast.success(t("toast.generateSuccess"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(t("errors.generationFailed", { error: (error as Error).message }));
|
toast.error(
|
||||||
|
t("toast.generateError", { error: (error as Error).message }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col xl:flex-row gap-4 p-4">
|
<form
|
||||||
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
|
className="flex flex-col xl:flex-row gap-4 p-4"
|
||||||
|
>
|
||||||
<div className="w-full xl:w-1/2 space-y-4">
|
<div className="w-full xl:w-1/2 space-y-4">
|
||||||
<MainConfigCard form={form} servers={serverConfig} />
|
<MainConfigCard form={form} servers={serverConfig} />
|
||||||
<PackageConfigCard form={form} packerConfig={packerConfig} />
|
<PackageConfigCard form={form} packerConfig={packerConfig} />
|
||||||
<Button className="w-full" type="submit" disabled={isActionPending}>
|
<Button className="w-full" type="submit" disabled={isActionPending}>
|
||||||
{isActionPending ? <LoaderCircle className="animate-spin" /> : <WandSparklesIcon />}
|
{isActionPending ? (
|
||||||
{t("buttons.generate")}
|
<LoaderCircle className="animate-spin" />
|
||||||
|
) : (
|
||||||
|
<WandSparklesIcon />
|
||||||
|
)}
|
||||||
|
{t("probeshell:buttons.generate")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full xl:w-1/2 space-y-4">
|
<div className="w-full xl:w-1/2 space-y-4">
|
||||||
|
|||||||
+43
-16
@@ -1,8 +1,8 @@
|
|||||||
import type {TFunction} from "i18next";
|
import type { TFunction } from "i18next";
|
||||||
import {useCallback} from "react";
|
import { useCallback } from "react";
|
||||||
import type {FieldErrors} from "react-hook-form";
|
import type { FieldErrors } from "react-hook-form";
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
import {ShellToolType} from "./memshell";
|
import { ShellToolType } from "./memshell";
|
||||||
|
|
||||||
export const memShellFormSchema = yup.object({
|
export const memShellFormSchema = yup.object({
|
||||||
server: yup.string().required().min(1),
|
server: yup.string().required().min(1),
|
||||||
@@ -48,9 +48,15 @@ const urlPatternIsNeeded = (shellType: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isInvalidUrl = (urlPattern: string | undefined) =>
|
const isInvalidUrl = (urlPattern: string | undefined) =>
|
||||||
urlPattern === "/" || urlPattern === "/*" || !urlPattern?.startsWith("/") || !urlPattern;
|
urlPattern === "/" ||
|
||||||
|
urlPattern === "/*" ||
|
||||||
|
!urlPattern?.startsWith("/") ||
|
||||||
|
!urlPattern;
|
||||||
|
|
||||||
export const useYupValidationResolver = (validationSchema: yup.ObjectSchema<any>, t: TFunction) =>
|
export const useYupValidationResolver = (
|
||||||
|
validationSchema: yup.ObjectSchema<any>,
|
||||||
|
t: TFunction,
|
||||||
|
) =>
|
||||||
useCallback(
|
useCallback(
|
||||||
async (data: MemShellFormSchema): Promise<ValidationResult> => {
|
async (data: MemShellFormSchema): Promise<ValidationResult> => {
|
||||||
try {
|
try {
|
||||||
@@ -63,22 +69,32 @@ export const useYupValidationResolver = (validationSchema: yup.ObjectSchema<any>
|
|||||||
const serverVersion: keyof MemShellFormSchema = "serverVersion";
|
const serverVersion: keyof MemShellFormSchema = "serverVersion";
|
||||||
const errors = {} as any;
|
const errors = {} as any;
|
||||||
|
|
||||||
if (urlPatternIsNeeded(values?.shellType) && isInvalidUrl(values?.urlPattern)) {
|
if (
|
||||||
|
urlPatternIsNeeded(values?.shellType) &&
|
||||||
|
isInvalidUrl(values?.urlPattern)
|
||||||
|
) {
|
||||||
errors[urlPattern] = {
|
errors[urlPattern] = {
|
||||||
type: "custom",
|
type: "custom",
|
||||||
message: t("tips.specificUrlPattern"),
|
message: t("memshell:tips.specificUrlPattern"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (values.shellTool === ShellToolType.Custom && !values.shellClassBase64) {
|
if (
|
||||||
|
values.shellTool === ShellToolType.Custom &&
|
||||||
|
!values.shellClassBase64
|
||||||
|
) {
|
||||||
errors[shellClassBase64] = {
|
errors[shellClassBase64] = {
|
||||||
type: "custom",
|
type: "custom",
|
||||||
message: t("tips.customShellClass"),
|
message: t("memshell:tips.customShellClass"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (values.server === "TongWeb" && values.shellType === "Valve" && values.serverVersion === "unknown") {
|
if (
|
||||||
|
values.server === "TongWeb" &&
|
||||||
|
values.shellType === "Valve" &&
|
||||||
|
values.serverVersion === "unknown"
|
||||||
|
) {
|
||||||
errors[serverVersion] = {
|
errors[serverVersion] = {
|
||||||
type: "custom",
|
type: "custom",
|
||||||
message: t("tips.serverVersion"),
|
message: t("memshell:tips.serverVersion"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +159,10 @@ interface ProbeValidationResult {
|
|||||||
errors: FieldErrors<ProbeShellFormSchema>;
|
errors: FieldErrors<ProbeShellFormSchema>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useYupValidationProbeResolver = (validationSchema: yup.ObjectSchema<any>, t: TFunction) =>
|
export const useYupValidationProbeResolver = (
|
||||||
|
validationSchema: yup.ObjectSchema<any>,
|
||||||
|
t: TFunction,
|
||||||
|
) =>
|
||||||
useCallback(
|
useCallback(
|
||||||
async (data: ProbeShellFormSchema): Promise<ProbeValidationResult> => {
|
async (data: ProbeShellFormSchema): Promise<ProbeValidationResult> => {
|
||||||
try {
|
try {
|
||||||
@@ -152,12 +171,20 @@ export const useYupValidationProbeResolver = (validationSchema: yup.ObjectSchema
|
|||||||
})) as ProbeShellFormSchema;
|
})) as ProbeShellFormSchema;
|
||||||
|
|
||||||
const host: keyof ProbeShellFormSchema = "host";
|
const host: keyof ProbeShellFormSchema = "host";
|
||||||
|
const reqParamName: keyof ProbeShellFormSchema = "reqParamName";
|
||||||
const errors = {} as any;
|
const errors = {} as any;
|
||||||
|
|
||||||
if (values.probeMethod === "DNSLog" && !values.host) {
|
if (values.probeMethod === "DNSLog" && !values.host) {
|
||||||
errors[host] = {
|
errors[host] = {
|
||||||
type: "custom",
|
type: "custom",
|
||||||
message: t("tips.customShellClass"),
|
message: t("probeshell:tips.dnslog.host.required"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.probeMethod === "ResponseBody" && !values.reqParamName) {
|
||||||
|
errors[reqParamName] = {
|
||||||
|
type: "custom",
|
||||||
|
message: t("probeshell:tips.response.reqParamName.required"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -174,7 +201,7 @@ export const useYupValidationProbeResolver = (validationSchema: yup.ObjectSchema
|
|||||||
type: currentError.type ?? "validation",
|
type: currentError.type ?? "validation",
|
||||||
message: currentError.message,
|
message: currentError.message,
|
||||||
};
|
};
|
||||||
console.log(allErrors)
|
console.log(allErrors);
|
||||||
return allErrors;
|
return allErrors;
|
||||||
},
|
},
|
||||||
{} as FieldErrors<ProbeShellFormSchema>,
|
{} as FieldErrors<ProbeShellFormSchema>,
|
||||||
@@ -194,4 +221,4 @@ export const useYupValidationProbeResolver = (validationSchema: yup.ObjectSchema
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
[validationSchema, t],
|
[validationSchema, t],
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user