Render git:// links in Markdown README.md and other Markdown pages sometimes contains links to Git repositories using git:// protocol. This is by default rejected by Soy sanitizers, but its reasonable to allow within the context of a Markdown page in a Git repository. Change-Id: Ibfa389335a25d2315d929c9f67082b4099328bac
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java index 2dcebdd..d5218e7 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
@@ -364,6 +364,11 @@ String href(String target) { if (target.startsWith("#") || HtmlBuilder.isValidHttpUri(target)) { return target; + } else if (target.startsWith("git:")) { + if (HtmlBuilder.isValidGitUri(target)) { + return target; + } + return FilterNormalizeUri.INSTANCE.getInnocuousOutput(); } String anchor = "";
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java index 9639176..3239fe1 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
@@ -85,6 +85,17 @@ private static final FilterNormalizeUri URI = FilterNormalizeUri.INSTANCE; private static final FilterImageDataUri IMAGE_DATA = FilterImageDataUri.INSTANCE; + private static final Pattern GIT_URI = + Pattern.compile( + "^" + + + // Reject paths containing /../ or ending in /.. + "(?![^#?]*/(?:\\.|%2E){2}(?:[/?#]|\\z))" + + + // Accept git://host/path + "git://[^/]+/.+", + Pattern.CASE_INSENSITIVE); + public static boolean isValidCssDimension(String val) { return val != null && val.matches("(?:[1-9][0-9]*px|100%|[1-9][0-9]?%)"); } @@ -99,6 +110,10 @@ return IMAGE_DATA.getValueFilter().matcher(url).find(); } + public static boolean isValidGitUri(String val) { + return GIT_URI.matcher(val).find(); + } + private final StringBuilder htmlBuf; private final Appendable textBuf; private String tag; @@ -159,7 +174,7 @@ } private String anchorHref(String val) { - if (URI.getValueFilter().matcher(val).find()) { + if (URI.getValueFilter().matcher(val).find() || isValidGitUri(val)) { return URI.escape(val); } return URI.getInnocuousOutput();
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java index 9d2b437..25f3d7f 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/doc/DocServletTest.java
@@ -132,4 +132,20 @@ String html = buildHtml("/repo/+doc/master/README.md"); assertThat(html).contains("<a href=\"/b/repo/+/master/x\">c</a>"); } + + @Test + public void gitUrlLink() throws Exception { + repo.branch("master").commit().add("README.md", "[c](git://example.com/repo.git)").create(); + + String html = buildHtml("/repo/+doc/master/README.md"); + assertThat(html).contains("<a href=\"git://example.com/repo.git\">c</a>"); + } + + @Test + public void invalidGitUrlLink() throws Exception { + repo.branch("master").commit().add("README.md", "[c](git://example.com/repo/..)").create(); + + String html = buildHtml("/repo/+doc/master/README.md"); + assertThat(html).contains("<a href=\"#zSoyz\">c</a>"); + } }
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java index fdffffc..ad9f941 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/doc/LinkTest.java
@@ -63,6 +63,25 @@ } @Test + public void gitLink() { + MarkdownToHtml md = + MarkdownToHtml.builder() + .setGitilesView(view) + .setConfig(new MarkdownConfig(config)) + .setFilePath("index.md") + .build(); + String url; + + url = "git://example.com/repo.git"; + assertThat(md.href(url)).isEqualTo(url); + + assertThat(md.href("git:example.com/repo.git")).isEqualTo("#zSoyz"); + assertThat(md.href("git://")).isEqualTo("#zSoyz"); + assertThat(md.href("git://example.com/../root")).isEqualTo("#zSoyz"); + assertThat(md.href("git://example.com/root/..")).isEqualTo("#zSoyz"); + } + + @Test public void absolutePath() { MarkdownToHtml md = MarkdownToHtml.builder()