11package ppn ;
22
3+ import net .kyori .adventure .text .Component ;
4+ import net .kyori .adventure .text .minimessage .MiniMessage ;
5+ import net .kyori .adventure .text .serializer .legacy .LegacyComponentSerializer ;
6+ import net .kyori .adventure .text .serializer .plain .PlainTextComponentSerializer ;
7+
38import java .io .OutputStream ;
49import java .net .HttpURLConnection ;
510import java .net .URL ;
611import java .nio .charset .StandardCharsets ;
12+ import java .util .regex .Pattern ;
713
814public class Webhook {
15+
16+ private static final MiniMessage MINI_MESSAGE = MiniMessage .miniMessage ();
17+ private static final PlainTextComponentSerializer PLAIN_SERIALIZER = PlainTextComponentSerializer .plainText ();
18+ private static final LegacyComponentSerializer AMPERSAND_SERIALIZER = LegacyComponentSerializer .legacyAmpersand ();
19+ private static final LegacyComponentSerializer SECTION_SERIALIZER = LegacyComponentSerializer .legacySection ();
20+ private static final Pattern LEGACY_CODE_PATTERN = Pattern .compile ("(?i)[&§][0-9A-FK-ORX]" );
21+ private static final Pattern RGB_HEX_PATTERN = Pattern .compile ("(?i)&#[0-9A-F]{6}" );
22+ private static final Pattern SHORT_RGB_HEX_PATTERN = Pattern .compile ("(?i)&#[0-9A-F]{3}" );
23+ private static final Pattern BUKKIT_HEX_PATTERN = Pattern .compile ("(?i)&x(?:&[0-9A-F]){6}" );
24+
925 public static void send (String url , String content ) {
1026 if (url == null || url .isEmpty ()) {
1127 return ;
@@ -15,7 +31,8 @@ public static void send(String url, String content) {
1531 connection .setRequestMethod ("POST" );
1632 connection .setDoOutput (true );
1733 connection .setRequestProperty ("Content-Type" , "application/json" );
18- String payload = "{\" content\" :\" " + content .replace ("\" " , "\\ \" " ) + "\" }" ;
34+ String sanitized = sanitize (content );
35+ String payload = "{\" content\" :\" " + escapeJson (sanitized ) + "\" }" ;
1936 try (OutputStream os = connection .getOutputStream ()) {
2037 os .write (payload .getBytes (StandardCharsets .UTF_8 ));
2138 }
@@ -33,13 +50,49 @@ public static void sendEmbed(String url, String description, int color) {
3350 connection .setRequestMethod ("POST" );
3451 connection .setDoOutput (true );
3552 connection .setRequestProperty ("Content-Type" , "application/json" );
36- String safe = description == null ? "" : description . replace ( " \" " , " \\ \" " );
37- String payload = "{\" embeds\" :[{\" description\" :\" " + safe + "\" ,\" color\" :" + color + "}]}" ;
53+ String sanitized = sanitize ( description );
54+ String payload = "{\" embeds\" :[{\" description\" :\" " + escapeJson ( sanitized ) + "\" ,\" color\" :" + color + "}]}" ;
3855 try (OutputStream os = connection .getOutputStream ()) {
3956 os .write (payload .getBytes (StandardCharsets .UTF_8 ));
4057 }
4158 connection .getInputStream ().close ();
4259 } catch (Exception ignored ) {
4360 }
4461 }
62+
63+ private static String sanitize (String input ) {
64+ if (input == null || input .isEmpty ()) {
65+ return "" ;
66+ }
67+ String sanitized = input ;
68+
69+ try {
70+ Component component = MINI_MESSAGE .deserialize (input );
71+ sanitized = PLAIN_SERIALIZER .serialize (component );
72+ } catch (Exception ignored ) {
73+ }
74+
75+ if (LEGACY_CODE_PATTERN .matcher (input ).find ()) {
76+ Component legacyComponent = AMPERSAND_SERIALIZER .deserialize (input );
77+ sanitized = PLAIN_SERIALIZER .serialize (legacyComponent );
78+ } else if (input .indexOf ('§' ) >= 0 ) {
79+ Component legacyComponent = SECTION_SERIALIZER .deserialize (input );
80+ sanitized = PLAIN_SERIALIZER .serialize (legacyComponent );
81+ }
82+
83+ sanitized = RGB_HEX_PATTERN .matcher (sanitized ).replaceAll ("" );
84+ sanitized = SHORT_RGB_HEX_PATTERN .matcher (sanitized ).replaceAll ("" );
85+ sanitized = BUKKIT_HEX_PATTERN .matcher (sanitized ).replaceAll ("" );
86+ sanitized = LEGACY_CODE_PATTERN .matcher (sanitized ).replaceAll ("" );
87+ return sanitized ;
88+ }
89+
90+ private static String escapeJson (String input ) {
91+ if (input == null || input .isEmpty ()) {
92+ return "" ;
93+ }
94+ String escaped = input .replace ("\\ " , "\\ \\ " ).replace ("\" " , "\\ \" " );
95+ escaped = escaped .replace ("\n " , "\\ n" ).replace ("\r " , "\\ r" ).replace ("\t " , "\\ t" );
96+ return escaped ;
97+ }
4598}
0 commit comments