Skip to content

Commit 49e56d2

Browse files
committed
feat: java swing gui
1 parent b743793 commit 49e56d2

36 files changed

+2649
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
plugins {
2+
id("java")
3+
id("application")
4+
}
5+
6+
group = "com.reajason.javaweb"
7+
version = rootProject.version
8+
9+
java {
10+
toolchain {
11+
languageVersion = JavaLanguageVersion.of(8)
12+
}
13+
sourceCompatibility = JavaVersion.VERSION_1_8
14+
targetCompatibility = JavaVersion.VERSION_1_8
15+
}
16+
17+
dependencies {
18+
implementation(project(":generator"))
19+
implementation(project(":packer"))
20+
implementation("com.formdev:flatlaf:3.7")
21+
implementation("com.miglayout:miglayout-swing:5.3")
22+
23+
testImplementation(libs.junit.jupiter)
24+
testRuntimeOnly(libs.junit.platform.launcher)
25+
}
26+
27+
application {
28+
mainClass.set("com.reajason.javaweb.desktop.memshell.MemShellDesktopApplication")
29+
}
30+
31+
tasks.test {
32+
useJUnitPlatform()
33+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.reajason.javaweb.desktop.memshell;
2+
3+
import com.formdev.flatlaf.FlatLightLaf;
4+
import com.reajason.javaweb.desktop.memshell.ui.MemShellGeneratorFrame;
5+
6+
import javax.swing.*;
7+
8+
public class MemShellDesktopApplication {
9+
public static void main(String[] args) {
10+
FlatLightLaf.setup();
11+
SwingUtilities.invokeLater(() -> new MemShellGeneratorFrame().setVisible(true));
12+
}
13+
}
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
package com.reajason.javaweb.desktop.memshell.controller;
2+
3+
import com.reajason.javaweb.desktop.memshell.model.MemShellFormState;
4+
import com.reajason.javaweb.desktop.memshell.model.PackerCategoryModel;
5+
import com.reajason.javaweb.desktop.memshell.model.PackerEntryModel;
6+
import com.reajason.javaweb.desktop.memshell.model.PackerSchemaFieldModel;
7+
import com.reajason.javaweb.desktop.memshell.service.ConfigCatalogService;
8+
import com.reajason.javaweb.desktop.memshell.validation.MemShellValidator;
9+
import com.reajason.javaweb.memshell.ShellTool;
10+
11+
import java.util.*;
12+
13+
public class MemShellFormController {
14+
private final ConfigCatalogService configCatalogService;
15+
private final MemShellValidator validator;
16+
private final ConfigCatalogService.ConfigCatalog catalog;
17+
private final MemShellFormState state = new MemShellFormState();
18+
19+
public MemShellFormController(ConfigCatalogService configCatalogService, MemShellValidator validator) {
20+
this.configCatalogService = configCatalogService;
21+
this.validator = validator;
22+
this.catalog = configCatalogService.load();
23+
reconcileAfterServerChange(true);
24+
reconcilePackerSelection();
25+
}
26+
27+
public ConfigCatalogService getConfigCatalogService() { return configCatalogService; }
28+
public MemShellFormState getState() { return state; }
29+
public ConfigCatalogService.ConfigCatalog getCatalog() { return catalog; }
30+
public MemShellValidator getValidator() { return validator; }
31+
32+
public List<String> getServers() {
33+
return new ArrayList<>(catalog.getServers().keySet());
34+
}
35+
36+
public List<String> getServerVersionOptions() {
37+
return configCatalogService.getServerVersionOptions(state.getServer());
38+
}
39+
40+
public List<String> getShellTools() {
41+
Map<String, List<String>> toolMap = catalog.getCore().get(state.getServer());
42+
if (toolMap == null) return Collections.emptyList();
43+
LinkedHashSet<String> tools = new LinkedHashSet<>(toolMap.keySet());
44+
tools.add(ShellTool.Custom);
45+
return new ArrayList<>(tools);
46+
}
47+
48+
public List<String> getCustomShellTypes() {
49+
List<String> values = catalog.getServers().get(state.getServer());
50+
return new ArrayList<String>(values == null ? Collections.<String>emptyList() : values);
51+
}
52+
53+
public List<String> getShellTypesForCurrentTool() {
54+
Map<String, List<String>> toolMap = catalog.getCore().get(state.getServer());
55+
if (toolMap == null) return Collections.emptyList();
56+
if (ShellTool.Custom.equals(state.getShellTool())) {
57+
return getCustomShellTypes();
58+
}
59+
List<String> values = toolMap.get(state.getShellTool());
60+
return new ArrayList<String>(values == null ? Collections.<String>emptyList() : values);
61+
}
62+
63+
public List<PackerEntryModel> getFilteredPackers() {
64+
List<PackerEntryModel> out = new ArrayList<>();
65+
for (PackerCategoryModel c : catalog.getPackers()) {
66+
for (PackerEntryModel p : c.getPackers()) {
67+
if (p.isCategoryAnchor()) continue;
68+
String name = p.getName();
69+
String shellType = state.getShellType();
70+
String server = state.getServer();
71+
if (shellType != null && shellType.startsWith("Agent")) {
72+
if (name.startsWith("Agent")) out.add(p);
73+
continue;
74+
}
75+
if (server != null && server.startsWith("XXL")) {
76+
if (!name.startsWith("Agent")) out.add(p);
77+
continue;
78+
}
79+
if (!name.startsWith("Agent") && !name.toLowerCase(Locale.ROOT).startsWith("xxl")) {
80+
out.add(p);
81+
}
82+
}
83+
}
84+
return out;
85+
}
86+
87+
public PackerEntryModel getSelectedPackerEntry() {
88+
String selected = state.getPackingMethod();
89+
if (selected == null || selected.trim().isEmpty()) return null;
90+
for (PackerCategoryModel c : catalog.getPackers()) {
91+
for (PackerEntryModel p : c.getPackers()) {
92+
if (selected.equals(p.getName())) return p;
93+
}
94+
}
95+
return null;
96+
}
97+
98+
public List<PackerSchemaFieldModel> getSelectedPackerFields() {
99+
PackerEntryModel p = getSelectedPackerEntry();
100+
return p == null ? Collections.<PackerSchemaFieldModel>emptyList() : p.getFields();
101+
}
102+
103+
public List<String> getCommandEncryptors() { return catalog.getCommandEncryptors(); }
104+
public List<String> getCommandImplementationClasses() { return catalog.getCommandImplementationClasses(); }
105+
106+
public void setServer(String server) {
107+
state.setServer(server);
108+
reconcileAfterServerChange(false);
109+
reconcilePackerSelection();
110+
}
111+
112+
public void setServerVersion(String version) { state.setServerVersion(version); }
113+
114+
public void setTargetJdkVersion(String value) {
115+
state.setTargetJdkVersion(value);
116+
try {
117+
state.setByPassJavaModule(Integer.parseInt(value) >= 53);
118+
} catch (Exception ignored) {
119+
}
120+
}
121+
122+
public void setShellTool(String tool) {
123+
handleShellToolChange(tool);
124+
reconcilePackerSelection();
125+
}
126+
127+
public void setShellType(String shellType) {
128+
state.setShellType(shellType);
129+
state.setUrlPattern("");
130+
reconcilePackerSelection();
131+
}
132+
133+
public void setUrlPattern(String urlPattern) { state.setUrlPattern(urlPattern); }
134+
public void setDebug(boolean value) { state.setDebug(value); }
135+
public void setProbe(boolean value) { state.setProbe(value); }
136+
public void setByPassJavaModule(boolean value) { state.setByPassJavaModule(value); }
137+
public void setLambdaSuffix(boolean value) { state.setLambdaSuffix(value); }
138+
public void setShrink(boolean value) { state.setShrink(value); }
139+
public void setStaticInitialize(boolean value) { state.setStaticInitialize(value); }
140+
141+
public void setGodzillaPass(String v) { state.setGodzillaPass(v); }
142+
public void setGodzillaKey(String v) { state.setGodzillaKey(v); }
143+
public void setBehinderPass(String v) { state.setBehinderPass(v); }
144+
public void setAntSwordPass(String v) { state.setAntSwordPass(v); }
145+
public void setCommandParamName(String v) { state.setCommandParamName(v); }
146+
public void setCommandTemplate(String v) { state.setCommandTemplate(v); }
147+
public void setHeaderName(String v) { state.setHeaderName(v); }
148+
public void setHeaderValue(String v) { state.setHeaderValue(v); }
149+
public void setShellClassBase64(String v) { state.setShellClassBase64(v); }
150+
public void setEncryptor(String v) { state.setEncryptor(v); }
151+
public void setImplementationClass(String v) { state.setImplementationClass(v); }
152+
153+
public void setShellClassName(String v) {
154+
state.setShellClassName(v);
155+
autoDisableRandomIfManualNames();
156+
}
157+
158+
public void setInjectorClassName(String v) {
159+
state.setInjectorClassName(v);
160+
autoDisableRandomIfManualNames();
161+
}
162+
163+
public void setRandomClassName(boolean checked) {
164+
state.setRandomClassName(checked);
165+
if (checked) {
166+
state.setSavedShellClassName(state.getShellClassName());
167+
state.setSavedInjectorClassName(state.getInjectorClassName());
168+
state.setShellClassName("");
169+
state.setInjectorClassName("");
170+
} else {
171+
state.setShellClassName(state.getSavedShellClassName());
172+
state.setInjectorClassName(state.getSavedInjectorClassName());
173+
}
174+
}
175+
176+
public void setCustomInputMode(String mode) { state.setCustomInputMode(mode); }
177+
178+
public void setPacker(String packerName) {
179+
state.setPackingMethod(packerName);
180+
resetPackerCustomConfigToDefaults();
181+
}
182+
183+
public void setPackerCustomField(String key, Object value) {
184+
if (value == null) {
185+
state.getPackerCustomConfig().remove(key);
186+
} else {
187+
state.getPackerCustomConfig().put(key, value);
188+
}
189+
}
190+
191+
public Map<String, Object> getPackerCustomConfig() { return state.getPackerCustomConfig(); }
192+
193+
public boolean isUrlPatternVisible() {
194+
return validator.needsUrlPattern(state.getShellType());
195+
}
196+
197+
public boolean isCommandHeaderVisible() {
198+
return "BypassNginxWebSocket".equals(state.getShellType()) || "BypassNginxJakartaWebSocket".equals(state.getShellType());
199+
}
200+
201+
public boolean isProxyHeaderVisible() { return isCommandHeaderVisible(); }
202+
203+
public boolean isCommandParamVisible() {
204+
return state.getShellType() == null || !state.getShellType().contains("WebSocket");
205+
}
206+
207+
public MemShellValidator.Result validate() { return validator.validate(state); }
208+
209+
private void reconcileAfterServerChange(boolean initial) {
210+
List<String> serverVersions = getServerVersionOptions();
211+
if (!serverVersions.contains(state.getServerVersion())) {
212+
state.setServerVersion(serverVersions.get(0));
213+
}
214+
Map<String, List<String>> toolMap = catalog.getCore().get(state.getServer());
215+
if (toolMap == null || toolMap.isEmpty()) {
216+
return;
217+
}
218+
List<String> toolKeys = new ArrayList<>(toolMap.keySet());
219+
String currentTool = state.getShellTool();
220+
String nextTool = toolMap.containsKey(currentTool) ? currentTool : toolKeys.get(0);
221+
state.setShellTool(nextTool);
222+
223+
String currentTargetJdk = state.getTargetJdkVersion();
224+
int currentJdk = parseInt(currentTargetJdk, 50);
225+
boolean raise = ("SpringWebFlux".equals(state.getServer()) || "XXLJOB".equals(state.getServer())) && currentJdk <= 52;
226+
state.setTargetJdkVersion(raise ? "52" : "50");
227+
state.setByPassJavaModule(parseInt(state.getTargetJdkVersion(), 50) >= 53);
228+
if (!initial) {
229+
state.setUrlPattern("");
230+
}
231+
232+
if (!serverVersions.contains(state.getServerVersion())) {
233+
state.setServerVersion(serverVersions.get(0));
234+
}
235+
ensureShellTypeValidForCurrentTool();
236+
}
237+
238+
private void ensureShellTypeValidForCurrentTool() {
239+
List<String> shellTypes = getShellTypesForCurrentTool();
240+
if (shellTypes.isEmpty()) {
241+
state.setShellType("");
242+
return;
243+
}
244+
if (!shellTypes.contains(state.getShellType())) {
245+
state.setShellType(shellTypes.get(0));
246+
}
247+
}
248+
249+
private void handleShellToolChange(String value) {
250+
if (value == null || value.trim().isEmpty()) return;
251+
252+
state.setUrlPattern("");
253+
state.setShellClassName("");
254+
state.setInjectorClassName("");
255+
256+
if (ShellTool.Command.equals(value)) {
257+
state.setCommandParamName("");
258+
state.setImplementationClass("");
259+
state.setEncryptor("");
260+
} else if (ShellTool.Godzilla.equals(value)) {
261+
state.setGodzillaKey("");
262+
state.setGodzillaPass("");
263+
state.setHeaderName("User-Agent");
264+
state.setHeaderValue("");
265+
} else if (ShellTool.Behinder.equals(value)) {
266+
state.setBehinderPass("");
267+
state.setHeaderName("User-Agent");
268+
state.setHeaderValue("");
269+
} else if (ShellTool.Suo5.equals(value) || ShellTool.Suo5v2.equals(value)) {
270+
state.setHeaderName("User-Agent");
271+
state.setHeaderValue("");
272+
} else if (ShellTool.AntSword.equals(value)) {
273+
state.setAntSwordPass("");
274+
state.setHeaderName("User-Agent");
275+
state.setHeaderValue("");
276+
} else if (ShellTool.NeoreGeorg.equals(value)) {
277+
state.setHeaderName("Referer");
278+
state.setHeaderValue("");
279+
} else if (ShellTool.Custom.equals(value)) {
280+
state.setShellClassBase64("");
281+
} else if (ShellTool.Proxy.equals(value)) {
282+
state.setHeaderName("User-Agent");
283+
state.setHeaderValue("");
284+
}
285+
286+
state.setShellTool(value);
287+
ensureShellTypeValidForCurrentTool();
288+
}
289+
290+
private void reconcilePackerSelection() {
291+
List<PackerEntryModel> filtered = getFilteredPackers();
292+
if (filtered.isEmpty()) {
293+
state.setPackingMethod("");
294+
state.getPackerCustomConfig().clear();
295+
return;
296+
}
297+
boolean exists = filtered.stream().anyMatch(p -> p.getName().equals(state.getPackingMethod()));
298+
if (!exists) {
299+
state.setPackingMethod(filtered.get(0).getName());
300+
resetPackerCustomConfigToDefaults();
301+
} else if (state.getPackerCustomConfig().isEmpty()) {
302+
resetPackerCustomConfigToDefaults();
303+
}
304+
}
305+
306+
private void resetPackerCustomConfigToDefaults() {
307+
state.getPackerCustomConfig().clear();
308+
PackerEntryModel selected = getSelectedPackerEntry();
309+
if (selected != null) {
310+
state.getPackerCustomConfig().putAll(selected.getDefaultConfig());
311+
}
312+
}
313+
314+
private void autoDisableRandomIfManualNames() {
315+
if (state.isRandomClassName() && (!state.getShellClassName().trim().isEmpty() || !state.getInjectorClassName().trim().isEmpty())) {
316+
state.setRandomClassName(false);
317+
}
318+
if (!state.isRandomClassName()) {
319+
state.setSavedShellClassName(state.getShellClassName());
320+
state.setSavedInjectorClassName(state.getInjectorClassName());
321+
}
322+
}
323+
324+
private int parseInt(String v, int d) {
325+
try {
326+
return Integer.parseInt(v);
327+
} catch (Exception e) {
328+
return d;
329+
}
330+
}
331+
}

0 commit comments

Comments
 (0)