feat: support boot-ui

This commit is contained in:
ReaJason
2024-12-20 01:15:12 +08:00
parent 2b00c96a06
commit 534db31fa0
81 changed files with 1556 additions and 929 deletions
+24 -14
View File
@@ -1,9 +1,10 @@
import { Button, ButtonProps } from "@/components/ui/button.tsx";
import { cn } from "@/lib/utils.ts";
import { CheckIcon, ClipboardIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { HTMLProps, useEffect, useState } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { materialDark } from "react-syntax-highlighter/dist/esm/styles/prism";
import { toast } from "sonner";
interface CopyButtonProps extends ButtonProps {
value: string;
@@ -14,24 +15,21 @@ export function copyToClipboardWithMeta(value: string) {
navigator.clipboard.writeText(value);
}
export function CopyButton({
value,
className,
src,
variant = "ghost",
...props
}: CopyButtonProps) {
export function CopyButton({ value, className, src, variant = "ghost", ...props }: CopyButtonProps) {
const [hasCopied, setHasCopied] = useState(false);
useEffect(() => {
setTimeout(() => {
setHasCopied(false);
}, 2000);
}, []);
if (hasCopied) {
setTimeout(() => {
setHasCopied(false);
}, 1000);
}
}, [hasCopied]);
return (
<Button
size="icon"
type="button"
variant={variant}
className={cn(
"relative z-10 h-6 w-6 text-zinc-50 hover:bg-zinc-700 hover:text-zinc-50 [&_svg]:h-3 [&_svg]:w-3",
@@ -40,6 +38,7 @@ export function CopyButton({
onClick={() => {
copyToClipboardWithMeta(value);
setHasCopied(true);
toast.success("复制成功");
}}
{...props}
>
@@ -53,22 +52,33 @@ export function CodeViewer({
code,
language,
showLineNumbers = true,
wrapLongLines = false,
}: {
code: string;
language: string;
showLineNumbers?: boolean;
wrapLongLines?: boolean;
}) {
const lineProps: lineTagPropsFunction | HTMLProps<HTMLElement> | undefined = wrapLongLines
? { style: { overflowWrap: "break-word", whiteSpace: "pre-wrap" } }
: undefined;
return (
<div className="relative overflow-hidden text-xs">
<div className="relative overflow-hidden text-xs wrap-all">
<CopyButton value={code} className="absolute right-4 top-2" />
<SyntaxHighlighter
language={language}
style={materialDark}
showLineNumbers={showLineNumbers}
wrapLongLines={wrapLongLines}
lineProps={lineProps}
customStyle={{
margin: 0,
paddingRight: showLineNumbers ? 0 : 24,
paddingLeft: showLineNumbers ? 0 : 24,
borderRadius: "var(--radius)",
height: 600,
height: 500,
whiteSpace: wrapLongLines ? "pre-wrap" : "pre",
overflowWrap: wrapLongLines ? "normal" : "break-word",
}}
>
{code}
+297 -82
View File
@@ -1,17 +1,39 @@
import { UrlPatternTip } from "@/components/tips/url-pattern-tip.tsx";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx";
import { Input } from "@/components/ui/input.tsx";
import { Label } from "@/components/ui/label.tsx";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select.tsx";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx";
import { Separator } from "@/components/ui/separator.tsx";
import { Switch } from "@/components/ui/switch.tsx";
import { FormSchema } from "@/types/schema.ts";
import { MainConfig } from "@/types/shell.ts";
import { ServerIcon } from "lucide-react";
import { useState } from "react";
import { FormProvider, UseFormReturn } from "react-hook-form";
const JDKVersion = [
{ name: "Java6", value: "50" },
{ name: "Java8", value: "52" },
{ name: "Java9", value: "53" },
{ name: "Java11", value: "55" },
{ name: "Java17", value: "61" },
{ name: "Java21", value: "65" },
];
export function MainConfigCard({
mainConfig,
form,
servers,
}: {
mainConfig: MainConfig | undefined;
form: UseFormReturn<FormSchema>;
servers?: string[];
}) {
const [shellToolMap, setShellToolMap] = useState<{ [toolName: string]: string[] }>();
const [shellTools, setShellTools] = useState<string[]>([]);
const [shellTypes, setShellTypes] = useState<string[]>([]);
export function MainConfigCard() {
return (
<Card className="w-full">
<CardHeader className="pb-1">
@@ -20,87 +42,280 @@ export function MainConfigCard() {
<span></span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<div className="grid grid-cols-2 gap-2">
<div className="space-y-1">
<Label htmlFor="server" className="text-sm">
<FormProvider {...form}>
<CardContent>
<div className="grid grid-cols-2 gap-2">
<FormField
control={form.control}
name="server"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel></FormLabel>
<Select
onValueChange={(v) => {
field.onChange(v);
if (mainConfig) {
setShellToolMap(mainConfig[v]);
setShellTools(Object.keys(mainConfig[v]));
setShellTypes([]);
}
}}
value={field.value}
>
<FormControl>
<SelectTrigger className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
</FormControl>
<SelectContent>
{servers?.map((server: string) => (
<SelectItem key={server} value={server}>
{server}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
)}
/>
<FormField
control={form.control}
name="targetJdkVersion"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel>JRE()</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
</FormControl>
<SelectContent>
{JDKVersion.map((v) => (
<SelectItem key={v.value} value={v.value}>
{v.name}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
)}
/>
</div>
<div className="flex items-center space-x-4 mt-2">
<FormField
control={form.control}
name="debug"
render={({ field }) => (
<FormItem className="flex items-center space-x-2 space-y-0">
<FormControl>
<Switch id="debug" checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
<FormLabel htmlFor="debug"></FormLabel>
</FormItem>
)}
/>
<FormField
control={form.control}
name="bypassJavaModule"
render={({ field }) => (
<FormItem className="flex items-center space-x-2 space-y-0">
<FormControl>
<Switch id="bypassJavaModule" checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
<Label htmlFor="bypassJavaModule">bypassJavaModule</Label>
</FormItem>
)}
/>
<div className="flex items-center space-x-2">
<Switch id="lambda" disabled />
<Label htmlFor="lambda">Lambda (WIP)</Label>
</div>
<div className="flex items-center space-x-2">
<Switch id="obfuscate" disabled />
<Label htmlFor="obfuscate"> (WIP)</Label>
</div>
</div>
<Separator className="mt-4 mb-2" />
<FormField
control={form.control}
name="shellClassName"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel></FormLabel>
<Input id="shellClassName" {...field} placeholder="请输入" className="h-8" />
</FormItem>
)}
/>
<div className="grid grid-cols-3 gap-2 mt-2">
<FormField
control={form.control}
name="shellTool"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel></FormLabel>
<Select
value={field.value}
onValueChange={(value: string) => {
field.onChange(value);
if (shellToolMap) {
setShellTypes(shellToolMap[value]);
}
}}
>
<FormControl>
<SelectTrigger className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
</FormControl>
<SelectContent>
{shellTools.length ? (
shellTools.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
))
) : (
<SelectItem value=" "></SelectItem>
)}
</SelectContent>
</Select>
</FormItem>
)}
/>
<FormField
control={form.control}
name="shellType"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel></FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
</FormControl>
<SelectContent>
{shellTypes.length ? (
shellTypes.map((v) => (
<SelectItem key={v} value={v}>
{v}
</SelectItem>
))
) : (
<SelectItem value=" "></SelectItem>
)}
</SelectContent>
</Select>
</FormItem>
)}
/>
<FormField
control={form.control}
name="urlPattern"
render={({ field }) => (
<FormItem className="flex flex-col mt-1">
<Label className="flex items-center">
<UrlPatternTip />
</Label>
<Input {...field} placeholder="请输入" className="h-8" />
</FormItem>
)}
/>
</div>
<div className="mt-2">
{form.getValues().shellTool === "Godzilla" && (
<div className="space-y-1">
<Label>Godzilla </Label>
<div className="grid grid-cols-2 gap-2">
<FormField
control={form.control}
name="godzillaPass"
render={({ field }) => (
<FormItem className="space-y-1 flex items-center justify-start">
<Label className="text-xs whitespace-nowrap w-1/2"></Label>
<Input {...field} placeholder="Pass" className="h-8" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="godzillaKey"
render={({ field }) => (
<FormItem className="space-y-1 flex items-center justify-start">
<Label className="text-xs whitespace-nowrap w-1/2"></Label>
<Input {...field} placeholder="Key" className="h-8" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="godzillaHeaderName"
render={({ field }) => (
<FormItem className="space-y-1 flex items-center justify-start">
<Label className="text-xs whitespace-nowrap w-1/2"></Label>
<Input {...field} placeholder="Header Name" className="h-8" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="godzillaHeaderValue"
render={({ field }) => (
<FormItem className="space-y-1 flex items-center justify-start">
<Label className="text-xs whitespace-nowrap w-1/2"></Label>
<Input {...field} placeholder="Header Value" className="h-8" />
</FormItem>
)}
/>
</div>
</div>
)}
{form.getValues().shellTool === "Command" && (
<FormField
control={form.control}
name="commandParamName"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel></FormLabel>
<FormControl>
<Input {...field} placeholder="请输入" className="h-8" />
</FormControl>
<FormDescription> cmd `?cmd=whoami` </FormDescription>
</FormItem>
)}
/>
)}
</div>
<Separator className="mt-4 mb-2" />
<FormField
control={form.control}
name="injectorClassName"
render={({ field }) => (
<FormItem className="space-y-1">
<FormLabel></FormLabel>
<Input id="injectorClassName" {...field} placeholder="请输入" className="h-8" />
</FormItem>
)}
/>
<div className="space-y-1 mt-2">
<Label htmlFor="interface" className="flex items-center gap-2">
(WIP)
</Label>
<Select>
<SelectTrigger id="server" className="h-8">
<Select disabled>
<SelectTrigger id="interface" className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
<SelectContent>
<SelectItem value="tomcat">Tomcat</SelectItem>
<SelectItem value="jetty">Jetty</SelectItem>
<SelectItem value="undertow">Undertow</SelectItem>
<SelectItem value="jboss">JBoss</SelectItem>
<SelectItem value="wildfly">Wildfly</SelectItem>
<SelectItem value="springmvc">SpringMVC</SelectItem>
<SelectItem value="springwebflux">SpringWebflux</SelectItem>
<SelectItem value="weblogic">WebLogic</SelectItem>
<SelectItem value="websphere">WebSphere</SelectItem>
<SelectItem value="resin">Resin</SelectItem>
<SelectItem value="glassfish">Glassfish</SelectItem>
<SelectItem value="bes">BES</SelectItem>
<SelectItem value="tongweb">TongWeb</SelectItem>
<SelectItem value="JDK_AbstractTranslet">JDK_AbstractTranslet</SelectItem>
<SelectItem value="XALAN_AbstractTranslet">XALAN_AbstractTranslet</SelectItem>
<SelectItem value="FASTJSON_GroovyASTTransformation">FASTJSON_GroovyASTTransformation</SelectItem>
<SelectItem value="SnakeYaml_ScriptEngineFactory">SnakeYaml_ScriptEngineFactory</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-1">
<Label htmlFor="targetJdkVersion" className="text-sm">
JRE
</Label>
<Select defaultValue="6">
<SelectTrigger id="targetJdkVersion" className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
<SelectContent>
<SelectItem value="6">Java 6</SelectItem>
<SelectItem value="7">Java 7</SelectItem>
<SelectItem value="8">Java 8</SelectItem>
<SelectItem value="9">Java 9</SelectItem>
<SelectItem value="11">Java 11</SelectItem>
<SelectItem value="17">Java 17</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="grid grid-cols-2 gap-2">
<div>
<Label htmlFor="shellClassName" className="text-sm">
</Label>
<Input id="shellClassName" placeholder="请输入" className="h-8" />
</div>
<div>
<Label htmlFor="injectorClassName" className="text-sm">
</Label>
<Input id="injectorClassName" placeholder="请输入" className="h-8" />
</div>
</div>
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-2">
<Switch id="obfuscate" />
<Label htmlFor="obfuscate" className="text-sm">
</Label>
</div>
<div className="flex items-center space-x-2">
<Switch id="debug" />
<Label htmlFor="debug" className="text-sm">
</Label>
</div>
<div className="flex items-center space-x-2">
<Switch id="lambda" />
<Label htmlFor="debug" className="text-sm">
Lambda
</Label>
</div>
</div>
</CardContent>
</CardContent>
</FormProvider>
</Card>
);
}
+37 -70
View File
@@ -1,9 +1,18 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
import { Label } from "@/components/ui/label.tsx";
import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form.tsx";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group.tsx";
import { FormSchema } from "@/types/schema.ts";
import { PackerConfig } from "@/types/shell.ts";
import { PackageIcon } from "lucide-react";
import { FormProvider, UseFormReturn } from "react-hook-form";
export function PackageConfigCard() {
export function PackageConfigCard({
packerConfig,
form,
}: {
packerConfig: PackerConfig | undefined;
form: UseFormReturn<FormSchema>;
}) {
return (
<Card className="w-full">
<CardHeader className="pb-1">
@@ -12,74 +21,32 @@ export function PackageConfigCard() {
<span></span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<div className="space-y-1">
<Label className="text-sm"></Label>
<RadioGroup defaultValue="base64">
<div className="grid grid-cols-2 gap-2">
<div className="flex items-center space-x-2">
<RadioGroupItem value="base64" id="base64" />
<Label htmlFor="base64" className="text-xs">
Base64
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="jsp" id="jsp" />
<Label htmlFor="jsp" className="text-xs">
JSP
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="classFile" id="classFile" />
<Label htmlFor="classFile" className="text-xs">
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="scriptEngine" id="scriptEngine" />
<Label htmlFor="scriptEngine" className="text-xs">
ScriptEngine
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="elExpression" id="elExpression" />
<Label htmlFor="elExpression" className="text-xs">
EL Expression
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="ognlExpression" id="ognlExpression" />
<Label htmlFor="ognlExpression" className="text-xs">
OGNL Expression
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="spelExpression" id="spelExpression" />
<Label htmlFor="spelExpression" className="text-xs">
SpEL Expression
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="elExpression" id="elExpression" />
<Label htmlFor="elExpression" className="text-xs">
EL Expression
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="freemarkerExpression" id="freemarkerExpression" />
<Label htmlFor="freemarkerExpression" className="text-xs">
Freemarker
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="velocityExpression" id="velocityExpression" />
<Label htmlFor="velocityExpression" className="text-xs">
Velocity
</Label>
</div>
</div>
</RadioGroup>
</div>
<CardContent>
<FormProvider {...form}>
<FormField
control={form.control}
name="packingMethod"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel></FormLabel>
<FormControl>
<RadioGroup onValueChange={field.onChange} defaultValue={field.value} className="grid grid-cols-3">
{Object.entries(packerConfig ?? {}).map(([name, value]) => (
<FormItem key={value} className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem value={value} id={value} />
</FormControl>
<FormLabel className="text-xs" htmlFor={value}>
{name}
</FormLabel>
</FormItem>
))}
</RadioGroup>
</FormControl>
</FormItem>
)}
/>
</FormProvider>
</CardContent>
</Card>
);
-78
View File
@@ -1,78 +0,0 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx";
import { Input } from "@/components/ui/input.tsx";
import { Label } from "@/components/ui/label.tsx";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select.tsx";
import { FishSymbolIcon } from "lucide-react";
import { useState } from "react";
export function ShellConfigCard() {
const [shellTool, setShellTool] = useState<string>("");
return (
<Card className="w-full">
<CardHeader className="pb-1">
<CardTitle className="text-md flex items-center gap-2">
<FishSymbolIcon className="h-5" />
<span></span>
</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<div className="space-y-1">
<Label htmlFor="shellType" className="text-sm">
</Label>
<Select>
<SelectTrigger id="shellType" className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
<SelectContent>
<SelectItem value="filter">Filter</SelectItem>
<SelectItem value="servlet">Servlet</SelectItem>
<SelectItem value="listener">Listener</SelectItem>
<SelectItem value="agent">Agent</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-1">
<Label htmlFor="shellTool" className="text-sm">
</Label>
<Select onValueChange={(value: string) => setShellTool(value)}>
<SelectTrigger id="shellTool" className="h-8">
<SelectValue placeholder="请选择" />
</SelectTrigger>
<SelectContent>
<SelectItem value="command"></SelectItem>
<SelectItem value="fileList">File List</SelectItem>
<SelectItem value="gozilla">Godzilla</SelectItem>
</SelectContent>
</Select>
</div>
{shellTool === "gozilla" && (
<div className="space-y-1">
<Label className="text-sm">Godzilla </Label>
<div className="grid grid-cols-2 gap-2">
<Input placeholder="Pass" className="h-8 text-sm" />
<Input placeholder="Key" className="h-8 text-sm" />
<Input placeholder="Header Name" className="h-8 text-sm" />
<Input placeholder="Header Value" className="h-8 text-sm" />
</div>
</div>
)}
{shellTool === "command" && (
<div className="space-y-1">
<Label htmlFor="paramName" className="text-sm">
</Label>
<Input id="paramName" placeholder="请输入" className="h-8 text-sm" />
</div>
)}
</CardContent>
</Card>
);
}
File diff suppressed because one or more lines are too long
+2 -6
View File
@@ -26,9 +26,7 @@ export function ThemeProvider({
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
);
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem(storageKey) as Theme) || defaultTheme);
useEffect(() => {
const root = window.document.documentElement;
@@ -37,9 +35,7 @@ export function ThemeProvider({
root.removeAttribute(mode);
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
root.classList.add(systemTheme);
root.setAttribute(mode, systemTheme);
+18
View File
@@ -0,0 +1,18 @@
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx";
import { InfoIcon } from "lucide-react";
export function JRETip() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="cursor-pointer h-3" />
</TooltipTrigger>
<TooltipContent>
<p> JRE Java 6 </p>
<p> JDK8 使 lambda JDK9 </p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
@@ -0,0 +1,17 @@
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip.tsx";
import { InfoIcon } from "lucide-react";
export function UrlPatternTip() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="cursor-pointer h-4" />
</TooltipTrigger>
<TooltipContent>
<p>使 Servlet urlPattern使 /*使</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
+7 -13
View File
@@ -9,8 +9,7 @@ const alertVariants = cva(
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
@@ -29,21 +28,16 @@ Alert.displayName = "Alert";
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
<h5 ref={ref} className={cn("mb-1 font-medium leading-none tracking-tight", className)} {...props} />
),
);
AlertTitle.displayName = "AlertTitle";
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
));
const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
),
);
AlertDescription.displayName = "AlertDescription";
export { Alert, AlertTitle, AlertDescription };
+2 -5
View File
@@ -11,8 +11,7 @@ const buttonVariants = cva(
variant: {
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
@@ -40,9 +39,7 @@ export interface ButtonProps
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
);
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
},
);
Button.displayName = "Button";
+5 -17
View File
@@ -2,15 +2,9 @@ import * as React from "react";
import { cn } from "@/lib/utils";
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("rounded-xl border bg-card text-card-foreground shadow", className)}
{...props}
/>
),
);
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("rounded-xl border bg-card text-card-foreground shadow", className)} {...props} />
));
Card.displayName = "Card";
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
@@ -22,11 +16,7 @@ CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
{...props}
/>
<div ref={ref} className={cn("font-semibold leading-none tracking-tight", className)} {...props} />
),
);
CardTitle.displayName = "CardTitle";
@@ -39,9 +29,7 @@ const CardDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HT
CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
),
({ className, ...props }, ref) => <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />,
);
CardContent.displayName = "CardContent";
+2 -8
View File
@@ -152,18 +152,12 @@ const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
<DropdownMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />
);
return <span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />;
};
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
+136
View File
@@ -0,0 +1,136 @@
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot";
import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from "react-hook-form";
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label";
const Form = FormProvider;
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
name: TName;
};
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
...props
}: ControllerProps<TFieldValues, TName>) => {
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
);
};
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext);
const itemContext = React.useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>");
}
const { id } = itemContext;
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
};
};
type FormItemContextValue = {
id: string;
};
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => {
const id = React.useId();
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
);
},
);
FormItem.displayName = "FormItem";
const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField();
return <Label ref={ref} className={cn(error && "text-destructive", className)} htmlFor={formItemId} {...props} />;
});
FormLabel.displayName = "FormLabel";
const FormControl = React.forwardRef<React.ElementRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>>(
({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
aria-invalid={!!error}
{...props}
/>
);
},
);
FormControl.displayName = "FormControl";
const FormDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField();
return (
<p ref={ref} id={formDescriptionId} className={cn("text-[0.8rem] text-muted-foreground", className)} {...props} />
);
},
);
FormDescription.displayName = "FormDescription";
const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message) : children;
if (!body) {
return null;
}
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-[0.8rem] font-medium text-destructive", className)}
{...props}
>
{body}
</p>
);
},
);
FormMessage.displayName = "FormMessage";
export { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField };
+1 -3
View File
@@ -6,9 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
);
const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
+2 -10
View File
@@ -94,11 +94,7 @@ const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
<SelectPrimitive.Label ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", className)} {...props} />
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
@@ -128,11 +124,7 @@ const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
<SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
+20
View File
@@ -0,0 +1,20 @@
import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "@/lib/utils";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn("shrink-0 bg-border", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", className)}
{...props}
/>
));
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator };
+14
View File
@@ -0,0 +1,14 @@
import { Toaster as Sonner } from "sonner";
import { useTheme } from "@/components/theme-provider.tsx";
type ToasterProps = React.ComponentProps<typeof Sonner>;
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme();
return (
<Sonner theme={theme as ToasterProps["theme"]} richColors className="toaster group" toastOptions={{}} {...props} />
);
};
export { Toaster };
+30
View File
@@ -0,0 +1,30 @@
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</TooltipPrimitive.Portal>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
+32
View File
@@ -0,0 +1,32 @@
import * as z from "zod";
const EnvSchema = z.object({
API_URL: z.optional(z.string()),
});
const createEnv = () => {
// @ts-ignore
const envVars = Object.entries(import.meta.env).reduce<Record<string, string>>((acc, curr) => {
const [key, value] = curr;
if (key.startsWith("VITE_APP_")) {
if (typeof value === "string") {
acc[key.replace("VITE_APP_", "")] = value;
}
}
return acc;
}, {});
const parsedEnv = EnvSchema.safeParse(envVars);
if (!parsedEnv.success) {
throw new Error(
`Invalid env provided.
The following variables are missing or invalid:
${Object.entries(parsedEnv.error.flatten().fieldErrors)
.map(([k, v]) => `- ${k}: ${v}`)
.join("\n")}
`,
);
}
return parsedEnv.data;
};
export const env = createEnv();
+3
View File
@@ -29,6 +29,7 @@
--chart-5: 27 87% 67%;
--radius: 0.3rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
@@ -56,10 +57,12 @@
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
+26
View File
@@ -1,6 +1,32 @@
import { type ClassValue, clsx } from "clsx";
import { toast } from "sonner";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export function downloadJavaClass(base64String?: string, className?: string) {
if (!base64String || !className) {
toast.warning("内存马字节码为空,无法下载, 请先生成内存马");
return;
}
const byteCharacters = atob(base64String);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
// Create a Blob from the byte array
const blob = new Blob([byteArray], { type: "application/java-vm" });
// Create a download link
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = `${className.substring(className.lastIndexOf("."))}.class`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
+12 -3
View File
@@ -2,14 +2,17 @@ import { RouterProvider, createRouter } from "@tanstack/react-router";
import ReactDOM from "react-dom/client";
import { routeTree } from "./routeTree.gen";
import "./index.css";
import { TailwindIndicator } from "@/components/tailwind-indicator.tsx";
import { Toaster } from "@/components/ui/sonner.tsx";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
// Set up a Router instance
const router = createRouter({
routeTree,
defaultPreload: "intent",
});
// Register things for typesafety
declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
@@ -20,5 +23,11 @@ const rootElement = document.getElementById("app") as HTMLElement;
if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(<RouterProvider router={router} />);
root.render(
<QueryClientProvider client={queryClient}>
<Toaster />
<RouterProvider router={router} />
<TailwindIndicator />
</QueryClientProvider>,
);
}
+1 -3
View File
@@ -67,9 +67,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
};
export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>();
export const routeTree = rootRoute._addFileChildren(rootRouteChildren)._addFileTypes<FileRouteTypes>();
/* ROUTE_MANIFEST_START
{
-9
View File
@@ -1,10 +1,7 @@
import { ModeToggle } from "@/components/mode-toggle.tsx";
import { ThemeProvider } from "@/components/theme-provider.tsx";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx";
import { Button } from "@/components/ui/button.tsx";
import { Outlet, createRootRoute } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/router-devtools";
import { ServerOffIcon } from "lucide-react";
export const Route = createRootRoute({
component: RootComponent,
@@ -43,13 +40,7 @@ function RootComponent() {
</div>
</div>
</header>
<Alert className="px-4 border-0 border-b">
<ServerOffIcon className="h-4 w-4" />
<AlertTitle>!</AlertTitle>
<AlertDescription>.</AlertDescription>
</Alert>
<Outlet />
<TanStackRouterDevtools position="bottom-right" />
</div>
</ThemeProvider>
);
+120 -16
View File
@@ -1,30 +1,134 @@
import { MainConfigCard } from "@/components/main-config-card.tsx";
import { PackageConfigCard } from "@/components/package-config-card.tsx";
import { ShellConfigCard } from "@/components/shell-config-card.tsx";
import { ShellResult } from "@/components/shell-result.tsx";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert.tsx";
import { Button } from "@/components/ui/button";
import { Form } from "@/components/ui/form.tsx";
import { env } from "@/config.ts";
import { FormSchema, formSchema } from "@/types/schema.ts";
import { APIErrorResponse, ConfigResponseType, GenerateResponse, GenerateResult } from "@/types/shell.ts";
import { transformToPostData } from "@/utils/transformer.ts";
import { zodResolver } from "@hookform/resolvers/zod";
import { useQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { WandSparklesIcon } from "lucide-react";
import { ActivityIcon, LoaderCircle, ServerOffIcon, WandSparklesIcon } from "lucide-react";
import { useState, useTransition } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
export const Route = createFileRoute("/")({
component: AboutComponent,
component: IndexComponent,
});
function AboutComponent() {
function IndexComponent() {
const { isPending, isError, data } = useQuery<ConfigResponseType>({
queryKey: ["config"],
queryFn: async () => {
const response = await fetch(`${env.API_URL}/config`);
return await response.json();
},
});
const form = useForm<FormSchema>({
resolver: zodResolver(formSchema),
defaultValues: {
server: "",
targetJdkVersion: "50",
debug: false,
bypassJavaModule: false,
shellClassName: "",
shellTool: "",
shellType: "",
urlPattern: "/*",
godzillaPass: "pass",
godzillaKey: "key",
godzillaHeaderName: "User-Agent",
godzillaHeaderValue: "test",
commandParamName: "cmd",
injectorClassName: "",
packingMethod: "Base64",
},
});
const [packResult, setPackResult] = useState<string>("// 等待填写参数生成中");
const [generateResult, setGenerateResult] = useState<GenerateResult>();
const [packMethod, setPackMethod] = useState<string>("");
const [isActionPending, startTransition] = useTransition();
async function onSubmit(values: FormSchema) {
startTransition(async () => {
if (values.shellType.endsWith("Servlet") && values.urlPattern === "/*") {
toast.warning("Servlet 类型的需要填写具体的 URL Pattern,例如 /hello_servlet");
return;
}
const postData = transformToPostData(values);
try {
const response = await fetch(`${env.API_URL}/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(postData),
});
await new Promise((resolve) => setTimeout(resolve, 500));
if (response.ok) {
const json: GenerateResponse = await response.json();
setPackResult(json.packResult);
setGenerateResult(json.generateResult);
setPackMethod(values.packingMethod);
toast.success("生成成功");
} else {
const json: APIErrorResponse = await response.json();
toast.error(`生成失败,${json.error}`);
}
} catch (err) {
const error = err as Error;
toast.error(`生成失败,${error.message}`);
}
});
}
return (
<div className="flex flex-col md:flex-row gap-4 p-4">
<div className="w-full md:w-1/2 space-y-4">
<MainConfigCard />
<ShellConfigCard />
<PackageConfigCard />
<Button className="w-full">
<WandSparklesIcon />
Generate
</Button>
</div>
<div className="w-full md:w-1/2 space-y-4">
<ShellResult />
<div className="mt-4">
<div className="px-4">
{isPending && (
<Alert>
<LoaderCircle className="animate-spin h-4 w-4" />
<AlertTitle>Pending</AlertTitle>
<AlertDescription>~</AlertDescription>
</Alert>
)}
{isError && (
<Alert variant="destructive">
<ServerOffIcon className="h-4 w-4" />
<AlertTitle>Not Work!</AlertTitle>
<AlertDescription>.</AlertDescription>
</Alert>
)}
{data && (
<Alert>
<ActivityIcon className="h-4 w-4" />
<AlertTitle>It Work!</AlertTitle>
<AlertDescription>Let's start the party! 🎉</AlertDescription>
</Alert>
)}
</div>
<Form {...form}>
<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-2">
<MainConfigCard servers={data?.servers} mainConfig={data?.core} form={form} />
<PackageConfigCard packerConfig={data?.packers} form={form} />
<Button className="w-full" type="submit" disabled={isActionPending}>
{isActionPending ? <LoaderCircle className="animate-spin" /> : <WandSparklesIcon />}
Generate
</Button>
</div>
<div className="w-full xl:w-1/2 space-y-4">
<ShellResult packMethod={packMethod} generateResult={generateResult} packResult={packResult} />
</div>
</form>
</Form>
</div>
);
}
+21
View File
@@ -0,0 +1,21 @@
import * as z from "zod";
export const formSchema = z.object({
server: z.string().min(1),
targetJdkVersion: z.optional(z.string()),
debug: z.optional(z.boolean()),
bypassJavaModule: z.optional(z.boolean()),
shellClassName: z.string().optional(),
shellTool: z.string().min(1),
shellType: z.string().min(1),
urlPattern: z.optional(z.string()),
godzillaPass: z.optional(z.string()),
godzillaKey: z.optional(z.string()),
godzillaHeaderName: z.optional(z.string()),
godzillaHeaderValue: z.optional(z.string()),
commandParamName: z.optional(z.string()),
injectorClassName: z.optional(z.string()),
packingMethod: z.string().min(1, { message: "请选择打包方式" }),
});
export type FormSchema = z.infer<typeof formSchema>;
+73
View File
@@ -0,0 +1,73 @@
export interface ShellConfig {
server: string;
shellTool: string;
shellType: string;
targetJreVersion?: string;
debug?: boolean;
byPassJavaModule?: boolean;
obfuscate?: boolean;
}
export interface ShellToolConfig {
shellClassName?: string;
godzillaPass?: string;
godzillaKey?: string;
godzillaHeaderName?: string;
godzillaHeaderValue?: string;
commandParamName?: string;
}
export interface CommandShellToolConfig {
shellClassName?: string;
paramName?: string;
}
export interface GodzillaShellToolConfig {
shellClassName?: string;
pass?: string;
key?: string;
headerName?: string;
headerValue?: string;
}
export interface InjectorConfig {
className?: string;
urlPattern?: string;
}
export interface ConfigResponseType {
servers: string[];
core: MainConfig;
packers: PackerConfig;
}
export interface MainConfig {
[serverName: string]: {
[toolName: string]: string[];
};
}
export interface PackerConfig {
[packerName: string]: string;
}
export interface GenerateResponse {
packResult: string;
generateResult: GenerateResult;
}
export interface APIErrorResponse {
error: string;
}
export interface GenerateResult {
shellClassName: string;
shellSize: number;
shellBytesBase64Str: string;
injectorClassName: string;
injectorSize: number;
injectorBytesBase64Str: string;
shellConfig: ShellConfig;
shellToolConfig: CommandShellToolConfig | GodzillaShellToolConfig;
injectorConfig: InjectorConfig;
}
+31
View File
@@ -0,0 +1,31 @@
import { FormSchema } from "@/types/schema.ts";
import { InjectorConfig, ShellConfig, ShellToolConfig } from "@/types/shell.ts";
export function transformToPostData(formValue: FormSchema) {
const shellConfig: ShellConfig = {
server: formValue.server,
shellTool: formValue.shellTool,
shellType: formValue.shellType,
targetJreVersion: formValue.targetJdkVersion,
byPassJavaModule: formValue.bypassJavaModule,
};
const shellToolConfig: ShellToolConfig = {
shellClassName: formValue.shellClassName,
godzillaPass: formValue.godzillaPass,
godzillaKey: formValue.godzillaKey,
godzillaHeaderName: formValue.godzillaHeaderName,
godzillaHeaderValue: formValue.godzillaHeaderValue,
commandParamName: formValue.commandParamName,
};
const injectorConfig: InjectorConfig = {
urlPattern: formValue.urlPattern,
className: formValue.injectorClassName,
};
return {
shellConfig,
shellToolConfig,
injectorConfig,
packer: formValue.packingMethod,
};
}