diff options
context:
space:
mode:
-rw-r--r--assets/cgit.css18
-rw-r--r--assets/cgit.js3
-rw-r--r--source/ui-summary.c5
-rw-r--r--tests/t0200-security.sh4
4 files changed, 29 insertions, 1 deletion
diff --git a/assets/cgit.css b/assets/cgit.css
index 10fcf66..f441faa 100644
--- a/assets/cgit.css
+++ b/assets/cgit.css
@@ -496,6 +496,24 @@ div#cgit div#summary pre {
overflow-x: auto;
}
+/* A plaintext readme served without an about filter. Wrapped instead of
+ * scrolled, since prose is the common case. */
+div#cgit pre.plaintext {
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ font-family: var(--font-mono);
+ line-height: 1.5;
+ margin: 0;
+}
+
+/* Markdown source before the client-side renderer has run, and for good
+ * when scripting is off. Keeps the line structure so it reads as text. */
+div#cgit .markdown[data-markdown] {
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ font-family: var(--font-mono);
+}
+
div#cgit .markdown {
line-height: 1.6;
overflow-wrap: break-word;
diff --git a/assets/cgit.js b/assets/cgit.js
index 4e0ac70..347e977 100644
--- a/assets/cgit.js
+++ b/assets/cgit.js
@@ -300,6 +300,9 @@ document.addEventListener("DOMContentLoaded", function () {
continue;
try {
el.innerHTML = render(text);
+ /* The attribute doubles as the style hook for the
+ * unrendered source, so drop it once rendered. */
+ el.removeAttribute("data-markdown");
} catch (e) {
/* leave the escaped source in place on any failure */
}
diff --git a/source/ui-summary.c b/source/ui-summary.c
index b5a6a22..8dd191b 100644
--- a/source/ui-summary.c
+++ b/source/ui-summary.c
@@ -167,8 +167,10 @@ void cgit_print_repo_readme(const char *path)
/* No about-filter is configured, so there is nothing to turn
* the readme source into safe HTML. Escape it rather than serve
* repo content raw, which would let an untrusted repository
- * inject script into the about page.
+ * inject script into the about page. The pre keeps the line
+ * structure of the text, which bare escaped output loses.
*/
+ html("<pre class='plaintext'>");
if (ref) {
cgit_print_file(filename, ref, 1, 1);
} else {
@@ -177,6 +179,7 @@ void cgit_print_repo_readme(const char *path)
html_txt(sb.buf);
strbuf_release(&sb);
}
+ html("</pre>");
} else {
/* An about-filter is configured and is responsible for turning
* the source into safe HTML, so pass it through the filter raw.
diff --git a/tests/t0200-security.sh b/tests/t0200-security.sh
index afce715..d3ac472 100644
--- a/tests/t0200-security.sh
+++ b/tests/t0200-security.sh
@@ -100,6 +100,10 @@ test_expect_success 'non-markdown readme without a filter is escaped' '
! grep "<script>alert(2)</script>" tmp
'
+test_expect_success 'non-markdown readme keeps its line structure' '
+ grep "pre class=.plaintext." tmp
+'
+
# --- Auto-submitting selects carry no inline handlers ------------------------
# A Content-Security-Policy without unsafe-inline blocks inline onchange
# handlers, so the forms mark their selects and cgit.js wires them up.