diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Replace the browser markdown renderer with a filter
The readme is now escaped plain text unless `about-filter` points at
the new `about-render.lua`, which renders markdown, man pages and plain
text server-side. `enable-markdown` goes away with the renderer.
Diffstat (limited to '')
| -rw-r--r-- | README.txt | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | assets/cgit.css | 8 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | assets/cgit.js | 164 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | cgitrc.5.txt | 19 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | examples/cgitrc | 19 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | extensions/about-render.lua | 592 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.c | 3 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.h | 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/ui-summary.c | 34 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | tests/t0200-security.sh | 4 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10 files changed, 613 insertions, 233 deletions
@@ -96,6 +96,8 @@ header lists the exact install commands for its own dependencies. `luaossl`. * The syntax highlighter (`syntax-highlight.lua`) needs `lpeg` and a Scintillua lexer set. +* The about-page renderer (`about-render.lua`) needs `lpeg` for markdown and + man pages. Plain text needs only Lua. These filters target Lua 5.1 through 5.4 and LuaJIT. `luaossl` has no Lua 5.5 build, so build cgit against 5.1 to 5.4 if you use the auth or email filters. diff --git a/assets/cgit.css b/assets/cgit.css index 3255068..ba7d7b1 100644 --- a/assets/cgit.css +++ b/assets/cgit.css @@ -520,14 +520,6 @@ div#cgit pre.plaintext { 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 10a34cd..6fe53ba 100644 --- a/assets/cgit.js +++ b/assets/cgit.js @@ -194,167 +194,3 @@ document.addEventListener("DOMContentLoaded", function () { }, false); })(); - -/* Built-in Markdown rendering for the about page. When no about-filter is - * configured, cgit escapes a markdown readme into a data-markdown container - * (see cgit_print_repo_readme) and this renders a deliberately small, safe - * subset client-side: headings, lists, blockquotes, rules, fenced and inline - * code, pipe tables, links, images and emphasis. Every run of text is escaped - * before any markup is added, and link and image URLs are restricted to http, - * https, mailto and relative targets, so a hostile readme cannot inject markup - * or scripts. Fenced code carries its language in data-lang as a styling - * hook. Without JavaScript the escaped source stays readable as plain text. - * - * This is intentionally a subset, not CommonMark: no reference links, raw HTML - * passthrough, nested lists or setext headings. Configure an about-filter to - * replace it, or set enable-markdown=0 to turn it off. */ - -(function () { - -var MAX_BYTES = 400000; - -function esc(s) { - return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); -} - -function escAttr(s) { - return esc(s).replace(/"/g, """).replace(/'/g, "'"); -} - -/* Return the url if its scheme is safe, else "". Whitespace and control bytes - * are stripped before the scheme is read because browsers ignore them when - * resolving it, so "java\nscript:..." must still be caught as javascript. */ -function safeUrl(url) { - url = (url || "").replace(/[\u0000-\u0020]+/g, ""); - var scheme = /^([a-z][a-z0-9+.\-]*):/i.exec(url); - if (scheme && !/^(https?|mailto)$/i.test(scheme[1])) - return ""; - return url; -} - -function link(text, url, image) { - var u = safeUrl(url); - if (!u) - return image ? esc("![" + text + "]") : inline(text); - if (image) - return "<img src='" + escAttr(u) + "' alt='" + escAttr(text) + "'/>"; - return "<a href='" + escAttr(u) + "'>" + inline(text) + "</a>"; -} - -/* Inline rendering over one block of text. Scans to the next marker character - * and bulk-escapes the plain text in between, so it stays roughly linear. */ -function inline(s) { - var out = "", i = 0, n = s.length, marker = /[`!\[*_]/g, m, rest; - while (i < n) { - marker.lastIndex = i; - m = marker.exec(s); - if (!m) { out += esc(s.slice(i)); break; } - if (m.index > i) { out += esc(s.slice(i, m.index)); i = m.index; } - rest = s.slice(i); - if ((m = /^`([^`]+)`/.exec(rest))) - out += "<code>" + esc(m[1]) + "</code>"; - else if ((m = /^!\[([^\]]*)\]\(\s*([^)\s]+)[^)]*\)/.exec(rest))) - out += link(m[1], m[2], true); - else if ((m = /^\[([^\]]*)\]\(\s*([^)\s]+)[^)]*\)/.exec(rest))) - out += link(m[1], m[2], false); - else if ((m = /^(\*\*|__)([\s\S]+?)\1/.exec(rest))) - out += "<strong>" + inline(m[2]) + "</strong>"; - else if ((m = /^(\*|_)([^\s][\s\S]*?)\1/.exec(rest))) - out += "<em>" + inline(m[2]) + "</em>"; - else { out += esc(s.charAt(i)); i++; continue; } - i += m[0].length; - } - return out; -} - -function cells(row) { - return row.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map(function (c) { - return c.trim(); - }); -} - -function render(src) { - var lines = src.replace(/\r\n?/g, "\n").split("\n"); - var out = "", i = 0, n = lines.length, line, m, k; - while (i < n) { - line = lines[i]; - if (/^\s*$/.test(line)) { i++; continue; } - if ((m = /^\s*(`{3,}|~{3,})\s*([\w.+#-]*)/.exec(line))) { - var fence = m[1].charAt(0) === "`" ? /^\s*`{3,}\s*$/ : /^\s*~{3,}\s*$/; - var lang = m[2], code = ""; - for (i++; i < n && !fence.test(lines[i]); i++) - code += lines[i] + "\n"; - i++; - out += "<pre><code" + (lang ? " data-lang='" + escAttr(lang) + "'" : "") + - ">" + esc(code) + "</code></pre>"; - continue; - } - if ((m = /^(#{1,6})\s+(.*?)\s*#*\s*$/.exec(line))) { - k = m[1].length; - out += "<h" + k + ">" + inline(m[2]) + "</h" + k + ">"; - i++; continue; - } - if (/^\s*([-*_])(\s*\1){2,}\s*$/.test(line)) { out += "<hr/>"; i++; continue; } - if (/^\s*>/.test(line)) { - var q = ""; - for (; i < n && /^\s*>/.test(lines[i]); i++) - q += lines[i].replace(/^\s*>\s?/, "") + "\n"; - out += "<blockquote>" + render(q) + "</blockquote>"; - continue; - } - if (line.indexOf("|") >= 0 && i + 1 < n && - /^\s*\|?(\s*:?-+:?\s*\|)+\s*:?-+:?\s*\|?\s*$/.test(lines[i + 1])) { - var head = cells(line), t = "<table><thead><tr>"; - for (k = 0; k < head.length; k++) - t += "<th>" + inline(head[k]) + "</th>"; - t += "</tr></thead><tbody>"; - for (i += 2; i < n && lines[i].indexOf("|") >= 0 && !/^\s*$/.test(lines[i]); i++) { - var row = cells(lines[i]); - t += "<tr>"; - for (k = 0; k < row.length; k++) - t += "<td>" + inline(row[k]) + "</td>"; - t += "</tr>"; - } - out += t + "</tbody></table>"; - continue; - } - if (/^\s*([-*+]|\d+[.)])\s+/.test(line)) { - var ordered = /^\s*\d/.test(line), tag = ordered ? "ol" : "ul"; - out += "<" + tag + ">"; - for (; i < n && (m = /^\s*([-*+]|\d+[.)])\s+(.*)$/.exec(lines[i])); i++) { - if ((/\d/.test(m[1])) !== ordered) break; - out += "<li>" + inline(m[2]) + "</li>"; - } - out += "</" + tag + ">"; - continue; - } - /* Always consume the current line so i advances even when it - * matched none of the block branches above. */ - var para = lines[i++]; - for (; i < n && !/^\s*$/.test(lines[i]) && - !/^\s*(#{1,6}\s|>|`{3,}|~{3,}|([-*+]|\d+[.)])\s)/.test(lines[i]); i++) - para += "\n" + lines[i]; - out += "<p>" + inline(para).replace(/\n/g, "<br/>") + "</p>"; - } - return out; -} - -document.addEventListener("DOMContentLoaded", function () { - var nodes = document.querySelectorAll("div#cgit [data-markdown]"), i, el, text; - for (i = 0; i < nodes.length; i++) { - el = nodes[i]; - text = el.textContent; - if (!text || text.length > MAX_BYTES) - 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 */ - } - } -}, false); - -})(); diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 049b234..32f8b86 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -32,8 +32,9 @@ about-filter:: get the content of the about-file on its STDIN, the name of the file as the first argument, and the STDOUT from the command will be included verbatim on the about page. Default value: none. When no - about-filter is set, a markdown readme is instead rendered by the - bundled cgit.js (see enable-markdown). See also: "FILTER API". + about-filter is set, the readme is escaped and served as plain text. + A bundled Lua filter, about-render.lua, renders markdown, man pages + and plain text when about-filter points at it. See also: "FILTER API". agefile:: Specifies a path, relative to each repository path, which can be used @@ -241,14 +242,6 @@ enable-tree-group-dirs:: in git's own order, with directories and files intermixed by name. Default value: "0". -enable-markdown:: - Flag which, when set to "1", renders a markdown readme on the about - page. cgit escapes the source and a small renderer bundled in cgit.js - formats it in the browser, so the page stays readable as plain text - when scripting is off. It applies only when no about-filter handles the - file, and only to names ending in .md, .markdown, .mkd or .mdown. - Default value: "1". - favicon:: Url used as link to the icon for cgit. Any path works, but keeping the value "/favicon.ico" is still worthwhile, since clients that do @@ -955,9 +948,9 @@ mimetype.svg=image/svg+xml # extensions/syntax-highlight.lua highlights through the Scintillua lexers. # source-filter=lua:/usr/share/cgit/extensions/syntax-highlight.lua -# Markdown about pages render client-side by default (see enable-markdown). -# For other formats such as manpages, point about-filter at your own script. -# about-filter=/var/www/cgit/filters/my-about-formatter +# About pages are escaped plain text unless an about-filter is set. The shipped +# extensions/about-render.lua renders markdown, man pages and plain text. +# about-filter=lua:/usr/share/cgit/extensions/about-render.lua ## ## Search for these files in the root of the default branch of repositories diff --git a/examples/cgitrc b/examples/cgitrc index 5626b58..bb87a9b 100644 --- a/examples/cgitrc +++ b/examples/cgitrc @@ -11,9 +11,9 @@ # directory, or list repositories by hand in the per-repository section at # the end of this file. # -# In this fork, markdown readmes are rendered in the browser, so no -# about-filter is needed for them. Source syntax highlighting is optional -# and ships as a source-filter, see the filter section below. +# About pages (markdown, man and plain-text readmes) render through the +# bundled about-render.lua about-filter, see the filter section below. Source +# syntax highlighting is optional and ships as a source-filter there too. # # One key=value pair per line. Lines starting with # are comments. @@ -237,10 +237,6 @@ enable-tree-linenumbers=1 # Default is 0. enable-tree-group-dirs=0 -# Render a markdown readme client-side on the about page. Values are 0 or 1. -# Default is 1. -enable-markdown=1 - # Default maximum statistics period. Leaving this unset disables statistics. # Values are week, month, quarter or year. Default is unset. #max-stats=week @@ -288,10 +284,10 @@ enable-http-clone=1 # 0 or 1. Default is 0. enable-filter-overrides=0 -# Filter command used to format about-page content. Markdown already renders -# in the browser, so this is only for other formats such as man pages. Value -# is a command optionally prefixed with exec or lua. Default is none. -#about-filter=exec:/path/to/your-command +# Filter command used to format about-page content. The bundled about-render.lua +# renders markdown, man pages and plain text. Value is a command optionally +# prefixed with exec or lua. Default is none. +#about-filter=lua:/usr/share/cgit/extensions/about-render.lua # Filter command used to format commit messages, for example to turn object # names and issue numbers into links. Value is a command optionally prefixed @@ -563,4 +559,3 @@ noplainemail=0 # enable-filter-overrides is 1. Value is a command. Default is the global # email-filter value. #repo.email-filter=lua:/usr/share/cgit/extensions/email-gravatar.lua - diff --git a/extensions/about-render.lua b/extensions/about-render.lua new file mode 100644 index 0000000..073b531 --- /dev/null +++ b/extensions/about-render.lua This diff is too large to be rendered inline. View it on its own page. diff --git a/source/cgit.c b/source/cgit.c index 5af2232..74600a7 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -211,8 +211,6 @@ static void config_cb(const char *name, const char *value) ctx.cfg.enable_tree_linenumbers = atoi(value); else if (!strcmp(name, "enable-tree-group-dirs")) ctx.cfg.enable_tree_group_dirs = atoi(value); - else if (!strcmp(name, "enable-markdown")) - ctx.cfg.enable_markdown = atoi(value); else if (!strcmp(name, "enable-git-config")) ctx.cfg.enable_git_config = atoi(value); else if (!strcmp(name, "enable-cache-list")) @@ -420,7 +418,6 @@ static void prepare_context(void) ctx.cfg.enable_http_clone = 1; ctx.cfg.enable_index_owner = 1; ctx.cfg.enable_tree_linenumbers = 1; - ctx.cfg.enable_markdown = 1; ctx.cfg.enable_git_config = 0; ctx.cfg.max_repo_count = 50; ctx.cfg.max_commit_count = 50; diff --git a/source/cgit.h b/source/cgit.h index b7caaf5..966851c 100644 --- a/source/cgit.h +++ b/source/cgit.h @@ -243,7 +243,6 @@ struct cgit_config { int enable_html_serving; int enable_tree_linenumbers; int enable_tree_group_dirs; - int enable_markdown; int enable_git_config; int enable_cache_list; int local_time; diff --git a/source/ui-summary.c b/source/ui-summary.c index 8dd191b..80d1e5b 100644 --- a/source/ui-summary.c +++ b/source/ui-summary.c @@ -105,17 +105,6 @@ static char* append_readme_path(const char *filename, const char *ref, const cha return full_path; } -static int readme_is_markdown(const char *filename) -{ - const char *ext = strrchr(filename, '.'); - - if (!ext || !ext[1]) - return 0; - ext++; - return !strcasecmp(ext, "md") || !strcasecmp(ext, "markdown") || - !strcasecmp(ext, "mkd") || !strcasecmp(ext, "mdown"); -} - void cgit_print_repo_readme(const char *path) { char *filename, *ref, *mimetype; @@ -146,29 +135,14 @@ void cgit_print_repo_readme(const char *path) } html("<div id='summary'>"); - if (!ctx.repo->about_filter && ctx.cfg.enable_markdown && - readme_is_markdown(filename)) { - /* No about-filter is set, so hand the markdown source to the - * built-in client-side renderer in cgit.js. The source is - * escaped here and rendered in the browser, and it degrades to - * readable plain text when scripting is off. - */ - html("<div class='markdown' data-markdown>"); - if (ref) { - cgit_print_file(filename, ref, 1, 1); - } else { - struct strbuf sb = STRBUF_INIT; - if (strbuf_read_file(&sb, filename, 0) >= 0) - html_txt(sb.buf); - strbuf_release(&sb); - } - html("</div>"); - } else if (!ctx.repo->about_filter) { + if (!ctx.repo->about_filter) { /* 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. The pre keeps the line - * structure of the text, which bare escaped output loses. + * structure of the text, which bare escaped output loses. Point + * about-filter at the bundled about-render.lua to render a + * markdown or man readme instead, see cgitrc.5.txt. */ html("<pre class='plaintext'>"); if (ref) { diff --git a/tests/t0200-security.sh b/tests/t0200-security.sh index 83cdbfd..425708e 100644 --- a/tests/t0200-security.sh +++ b/tests/t0200-security.sh @@ -73,7 +73,7 @@ test_expect_success 'a small blob is still served' ' ' # --- Readme rendering escapes untrusted repository content ------------------ -test_expect_success 'markdown readme is escaped and marked for the client' ' +test_expect_success 'markdown readme without a filter is escaped as plain text' ' { echo "virtual-root=/" && echo "cache-size=0" && @@ -82,7 +82,7 @@ test_expect_success 'markdown readme is escaped and marked for the client' ' echo "repo.readme=master:README.md" } >secmdrc && CGIT_CONFIG="$PWD/secmdrc" QUERY_STRING="url=md/about/" cgit >tmp && - grep "data-markdown" tmp && + grep "pre class=.plaintext." tmp && grep "<script>" tmp && ! grep "<script>alert(1)</script>" tmp ' |
