Skip to content

Commit

Permalink
Fixed MarkdownSanitizer altering URL symbols
Browse files Browse the repository at this point in the history
-Suggested by EclipsedSolari in issue discord-jda#2378
-The algorithm implemented searches and replaces all URLs by a placeholder, and replaces them back after the majority of the compute method finishes.
-Also added a test method in the MarkdownTest class.
  • Loading branch information
LaFriska committed Jul 16, 2023
1 parent ec41b86 commit 7204263
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 1 deletion.
65 changes: 64 additions & 1 deletion src/main/java/net/dv8tion/jda/api/utils/MarkdownSanitizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
Expand Down Expand Up @@ -92,6 +93,8 @@ public class MarkdownSanitizer
tokens.put(STRIKE, "~~");
}

private Matcher urlMatcher;
private int urlReplacementIteration;
private int ignored;
private SanitizationStrategy strategy;

Expand Down Expand Up @@ -553,6 +556,11 @@ private boolean isIgnored(int nextRegion)
public String compute(@Nonnull String sequence)
{
Checks.notNull(sequence, "Input");

setUrlMatcher(sequence);
String[][] urlSubBox = getURLSubBox(sequence);
sequence = replaceURLs(sequence, urlSubBox, true);

StringBuilder builder = new StringBuilder();
String end = handleQuote(sequence);
if (end != null) return end;
Expand Down Expand Up @@ -590,7 +598,10 @@ public String compute(@Nonnull String sequence)
applyStrategy(nextRegion, handleRegion(i + delta, endRegion, sequence, nextRegion), builder);
i = endRegion + delta;
}
return builder.toString();

sequence = replaceURLs(builder.toString(), urlSubBox, false);

return sequence;
}

private String handleQuote(@Nonnull String sequence)
Expand Down Expand Up @@ -630,4 +641,56 @@ public enum SanitizationStrategy
*/
ESCAPE,
}

//URL Handling Methods

private String[][] getURLSubBox(@Nonnull String sequence){
int urlCount = countURLs();
String[][] urlSubBox = new String[2][urlCount];
urlReplacementIteration = 10000000;
urlMatcher.reset();
for(int i = 0; i <= urlCount - 1; i++){
//System.out.println(i);
urlSubBox[1][i] = generateURLReplacement(sequence);
urlMatcher.find();
urlSubBox[0][i] = urlMatcher.group();
}
return urlSubBox;
}

private String replaceURLs(@Nonnull String sequence, String[][] subBox, boolean start){
StringBuilder builder = new StringBuilder(sequence);
String url;
for(int i = 0; i <= subBox[1].length - 1; i++){
url = subBox[start ? 0 : 1][i];
builder.replace(builder.indexOf(url), builder.indexOf(url) + url.length(), subBox[start ? 1 : 0][i]);
}
return builder.toString();
}

private int countURLs(){ //Returns true if there is a URL in the sequence
try {
int i = 0;
while(urlMatcher.find()){
i++;
}
return i;
} catch (RuntimeException e) {
return 0;
}
}

private void setUrlMatcher(@Nonnull String sequence){
String urlPattern = "(http|https)://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,3}(/\\S*)?";
urlMatcher = Pattern.compile(urlPattern).matcher(sequence);
}

private String generateURLReplacement(@Nonnull String sequence){
String urlReplacement = "URL-" + (urlReplacementIteration);
if(sequence.contains(urlReplacement)){
urlReplacementIteration++;
return generateURLReplacement(sequence);
}
else return urlReplacement;
}
}
16 changes: 16 additions & 0 deletions src/test/java/MarkdownTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,22 @@ class EscapeMarkdownTest
{
private MarkdownSanitizer markdown;

@Test
public void testUrl()
{
//Tests Markdown sanitizer's reaction to URLs symbols
Assertions.assertEquals("https://www.google.com/", markdown.compute("https://www.google.com/"));
Assertions.assertEquals("https://www.google.com/search?q=_test_", markdown.compute("https://www.google.com/search?q=_test_"));
Assertions.assertEquals("https://www.google.com/search?q=__test__", markdown.compute("https://www.google.com/search?q=__test__"));
Assertions.assertEquals("https://www.google.com/search?q=*test*", markdown.compute("https://www.google.com/search?q=*test*"));
Assertions.assertEquals("https://www.google.com/search?q=**test**", markdown.compute("https://www.google.com/search?q=**test**"));
Assertions.assertEquals("https://www.google.com/search?q=***test***", markdown.compute("https://www.google.com/search?q=***test***"));
Assertions.assertEquals("https://www.google.com/search?q=~test~", markdown.compute("https://www.google.com/search?q=~test~"));
Assertions.assertEquals("\\*\\*Hello\\*\\* \\_\\_Hello\\_\\_ https://www.google.com/search?q=__test__", markdown.compute("**Hello** __Hello__ https://www.google.com/search?q=__test__"));
Assertions.assertEquals("\\*\\*Hello\\*\\* https://github.com/__discord-jda__/JDA/**issues**/2378_ Quick brown fox https://www.google.com/search?q=__test__ \\*Test\\* \\_\\_Test\\_\\_ https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork", markdown.compute("**Hello** https://github.com/__discord-jda__/JDA/**issues**/2378_ Quick brown fox https://www.google.com/search?q=__test__ *Test* __Test__ https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork"));
Assertions.assertEquals("URL-10000000 \\*\\*Hello\\*\\* https://www.google.com/search?q=**test**", markdown.compute("URL-10000000 **Hello** https://www.google.com/search?q=**test**"));
}

@BeforeEach
public void setup()
{
Expand Down

0 comments on commit 7204263

Please sign in to comment.