diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Trim the comments and dead code across the tree
Diffstat (limited to 'custom/extensions')
| -rw-r--r-- | custom/extensions/about-render.lua | 91 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/auth-file.lua | 73 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/auth-inline.lua | 66 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/email-gravatar.lua | 22 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/email-libravatar.lua | 19 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/link-commits.lua | 53 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | custom/extensions/syntax-highlight.lua | 67 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 files changed, 172 insertions, 219 deletions
diff --git a/custom/extensions/about-render.lua b/custom/extensions/about-render.lua index ea13746..f4e7685 100644 --- a/custom/extensions/about-render.lua +++ b/custom/extensions/about-render.lua @@ -1,20 +1,15 @@ -- Server-side rendering of a repository's about page, named by the -- about-filter setting in cgitrc and run inside cgit's embedded Lua --- interpreter so a readme costs no extra process per request. --- Markdown, man pages and plain text are the three formats, chosen from the --- readme's file extension, and anything that fails to parse falls back to --- escaped plain text. Adding a format takes a render function and a row in --- the handler table at the foot of this file, and nothing else. The wrappers --- it emits carry the classes that assets/cgit.css styles. It runs on Lua 5.1 --- through 5.4 and LuaJIT. +-- interpreter so a readme costs no extra process per request. Markdown, man +-- pages and plain text are the three formats, chosen from the readme's file +-- extension, and anything that fails to parse falls back to escaped plain +-- text. The wrappers it emits carry the classes that assets/cgit.css styles. +-- It runs on Lua 5.1 through 5.4 and LuaJIT. -- --- about-filter=lua:/usr/lib/cgit/filters/about-render.lua +-- about-filter=lua:/usr/local/lib/cgit/filters/about-render.lua --- Markdown and man pages are parsed with lpeg grammars, so where the parsing --- module is missing both fall back to escaped plain text and only plain text --- still renders. It has to be built for the Lua cgit is linked against. --- cgit's syntax highlighter needs it too, so a cgit that colours source --- already has it. +-- Markdown and man pages need lpeg, built for the Lua cgit is linked +-- against. Without it both fall back to escaped plain text. -- -- # Debian and Ubuntu -- sudo apt install lua-lpeg @@ -42,9 +37,8 @@ local function trim(text) return (text:gsub("^%s+", ""):gsub("%s+$", "")) end --- Split on newlines after normalising CRLF and CR, returning the lines --- without their terminators. A trailing newline yields a final empty line, --- which every caller treats as blank. +-- Normalise CRLF and CR to newlines, then split. A trailing newline yields +-- a final empty line, which every caller treats as blank. local function split_lines(text) text = text:gsub("\r\n?", "\n") local lines, start = {}, 1 @@ -59,8 +53,6 @@ local function split_lines(text) end end --- Split a table row into trimmed cells, dropping one optional leading and one --- optional trailing pipe. local function split_cells(row) row = trim(row):gsub("^|", ""):gsub("|$", "") local cells = {} @@ -70,11 +62,10 @@ local function split_cells(row) return cells end --- Return the URL if its scheme is safe, else nil. Control and whitespace --- bytes are stripped anywhere first because a browser ignores them when --- resolving the scheme, so "java\nscript:" must still be caught as --- javascript. The class is %c%s rather than a literal 0x00 range so it is --- safe on Lua 5.1, where an embedded zero byte ends a pattern. +-- Control and whitespace bytes are stripped before the scheme check because +-- a browser ignores them when resolving it, so "java\nscript:" must still be +-- caught as javascript. The class is %c%s rather than a literal 0x00 range +-- so it is safe on Lua 5.1, where an embedded zero byte ends a pattern. local function safe_url(url) url = url:gsub("[%c%s]", "") -- A leading "//" or "/\" is scheme-relative, which a browser @@ -94,14 +85,10 @@ local function safe_url(url) end --- The about page renders untrusted repository content, so the rule the two --- functions below keep is that every run of text reaches the page through --- cgit's own html_txt, every attribute value through html_attr, and every --- link or image target through safe_url before html_attr. Those three come --- from cgit's Lua filter host rather than from here, and the only thing --- passed to html is literal tag scaffolding. Because all output is routed --- through those sinks by construction, a bug in the parser can only --- mis-render, never inject markup or a URL with a javascript scheme. +-- The page renders untrusted repository content. Every run of text goes out +-- through cgit's html_txt, every attribute value through html_attr, and +-- every link or image target through safe_url before html_attr. html() only +-- ever gets literal tag scaffolding. local emit_inline @@ -198,16 +185,12 @@ local function render_plaintext(text) end --- Markdown here is a deliberate subset rather than CommonMark, covering --- headings, thematic breaks, fenced and inline code, blockquotes, pipe --- tables, single-level lists, links, images and emphasis, and leaving out --- reference links, raw HTML passthrough, nested lists and setext headings. --- Emphasis does not span a hard line break inside a paragraph. Man rendering --- covers the common macros, that is section headings, filled and no-fill --- paragraphs, bold and italic and the font escapes, and drops the rest. Both --- are parsed with lpeg into the node trees emit_blocks and emit_inline above --- consume, and parsing only builds a tree, so a parse that fails falls back --- to plain text without leaving half a page behind. +-- Markdown is a deliberate subset rather than CommonMark, leaving out +-- reference links, raw HTML passthrough, nested lists and setext headings, +-- and emphasis does not span a hard line break. Man rendering covers the +-- common macros and drops the rest. Both parse into a node tree before +-- anything is emitted, so a failed parse falls back to plain text without +-- leaving half a page behind. local render_markdown, render_man @@ -223,8 +206,6 @@ if has_lpeg then -- Bound the link and image inner scans. Without a cap a readme of -- unclosed brackets ("[[[[...") makes every position scan to the -- end of the line for a "]" that never comes, which is quadratic. - -- Real link text and urls sit far under this, and anything longer - -- simply renders as plain text. local max_scan = 512 local parse_inline @@ -275,8 +256,6 @@ if has_lpeg then return nodes end - -- Line matchers. Each is anchored at the start of a single line and - -- returns its captures, or nil when the line is not of that kind. local lang_char = R("az", "AZ", "09") + S("_.+#-") local heading_line = C(P("#") * P("#") ^ -5) * space ^ 1 * C(P(1) ^ 0) local function thematic(mark) @@ -434,20 +413,24 @@ if has_lpeg then html("</div>") end - -- Macro lines are matched with lpeg, and the roff inline font and - -- character escapes are a grammar producing a flat token list that - -- a fold turns into the same inline nodes markdown emits. Bold and - -- italic are the current font, which carries across a run rather - -- than being opened and closed, so the inline pass tokenises and - -- folds instead of nesting the way markdown does. + -- Roff fonts are a current state carried across a run rather than + -- opened and closed, so the inline pass tokenises to a flat list + -- and folds it into the nodes markdown emits, instead of nesting. local macro_line = S(".'") * space ^ 0 * C((1 - space) ^ 1) * space ^ 0 * C(P(1) ^ 0) local one_font = { B = "B", I = "I" } local two_font = { CB = "B", BI = "B", CI = "I" } local man_chars = { - aq = "'", cq = "'", oq = "'", dq = '"', lq = '"', rq = '"', - hy = "-", en = "-", em = "-", + aq = "'", + cq = "'", + oq = "'", + dq = '"', + lq = '"', + rq = '"', + hy = "-", + en = "-", + em = "-", } local backslash = P("\\") local function font_token(name) return { kind = "font", font = name } end @@ -610,7 +593,7 @@ function filter_write(str) end -- cgit takes filter output through a C string sink that stops at the first --- NUL byte, so a readme holding one is truncated there. +-- NUL byte, so a write holding one loses everything from the NUL on. function filter_close() local text = table.concat(chunks) chunks = {} diff --git a/custom/extensions/auth-file.lua b/custom/extensions/auth-file.lua index 74a04b6..957bd49 100644 --- a/custom/extensions/auth-file.lua +++ b/custom/extensions/auth-file.lua @@ -11,11 +11,9 @@ -- be the same Lua that cgit was built against. Lua 5.5 will not do, because -- luaossl has no 5.5 build. -- --- Serve cgit over HTTPS and terminate TLS in the web server in front of it. --- The session cookie is marked Secure by default, so a browser only sends it --- back over HTTPS, and on an instance served over plain HTTP with no TLS --- anywhere the cookie never comes back and login appears to loop until --- cookie_insecure below is set. +-- The session cookie is marked Secure by default, so a browser only sends +-- it back over HTTPS. On an instance served over plain HTTP login loops +-- until cookie_insecure below is set. -- -- Two libraries are needed. luaossl provides openssl.rand and openssl.hmac and -- lives at <https://github.com/wahern/luaossl>, and luaposix provides @@ -42,16 +40,10 @@ -- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)" -- luarocks install luaposix -- --- Some distributions package both as well, for example lua-luaossl and --- lua-posix on Debian, and such a package has to be built for the same Lua --- version as cgit. --- --- The cookie carries only a user name and there is no server-side session --- store, so deleting an account does not revoke a cookie already issued until --- it expires, and instances that share a secret file accept each other's --- cookies. The login form carries no CSRF token. Both are acceptable for --- gating read access to a git browser, so weigh them before guarding anything --- more sensitive. +-- There is no server-side session store and no CSRF token, so a deleted +-- account's cookie stays valid until it expires and instances sharing a +-- secret file accept each other's cookies. That is acceptable for gating +-- read access to a git browser, so weigh it before guarding anything more. local sysstat = require("posix.sys.stat") local unistd = require("posix.unistd") @@ -59,7 +51,6 @@ local rand = require("openssl.rand") local hmac = require("openssl.hmac") -- The values that follow are the configuration and are meant to be edited. --- Nothing below them needs changing for ordinary use. -- Accounts live one per line as username:hash. Generate a hash with -- mkpasswd -m sha-512 -R 300000 @@ -73,7 +64,7 @@ local groups_filename = "/etc/cgit-auth/groups" -- Per-repository access lives one per line as reponame:group1,group2 and so -- on. A repository named here is protected and one that is not named is -- public. The repository name has to match exactly, while group and user names --- match whatever their case. +-- match regardless of case. local repos_filename = "/etc/cgit-auth/repos" -- Where the cookie-signing secret is stored, created on first use. It must be @@ -91,8 +82,7 @@ local cookie_name = "cgitauth" -- more tightly. local cookie_path = "/" --- Leave this false so the cookie is marked Secure and only travels over HTTPS. --- Set it true only if cgit is served over plain HTTP with no TLS anywhere. +-- Set this true only if cgit is served over plain HTTP with no TLS anywhere. local cookie_insecure = false -- A throwaway hash of the documented shape, used only to spend the same work @@ -104,9 +94,8 @@ local dummy_hash = "$6$rounds=300000$0000000000000000$" -- open decodes is kept here for the calls that follow. local action, http, cgit, post --- The two lookups below, account_hash and repo_userset, are the only part of --- this script that differs from auth-inline.lua. Replacing them is all it --- takes to keep accounts somewhere else. +-- The two lookups below, account_hash and repo_userset, are the only part +-- of this script that differs from auth-inline.lua. local function trim(s) return (string.gsub(s, "^%s*(.-)%s*$", "%1")) @@ -118,14 +107,12 @@ local function add_names(list, set) end end --- A missing or unreadable users file is not fatal, and neither is a line that --- does not parse, so a broken file turns every login down rather than failing --- the request outright. +-- A missing, unreadable or unparsable users file turns every login down +-- rather than failing the request outright. -- --- The hash is trimmed as well as the name because reading by line strips the --- newline but not a carriage return, so a users file saved with CRLF endings --- would otherwise hand crypt a hash with a trailing \r and fail every login --- with nothing in the log to say why. +-- The hash is trimmed as well as the name because reading by line strips +-- the newline but not a carriage return, so a CRLF users file would hand +-- crypt a hash with a trailing \r and fail every login. function account_hash(user) if user == nil then return nil @@ -224,14 +211,9 @@ local function pattern_escape(s) return (string.gsub(s, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")) end --- The stored token was already URL encoded by secure_value, so it comes back --- verbatim and the write path in set_cookie stays symmetric with this read --- path. Decoding it here would break the signature check for any value --- carrying a percent escape. --- --- The name is escaped because it lands in a pattern. A cookie_name holding a --- magic character, say "cgit-auth", would otherwise read as a pattern and stop --- matching its own cookie while matching names nobody configured. +-- The token comes back still URL encoded by secure_value. Decoding it here +-- would break the signature check for any value carrying a percent escape. +-- The name is escaped because it lands in a Lua pattern. function get_cookie(cookies, name) cookies = string.gsub(";" .. (cookies or "") .. ";", "%s*;%s*", ";") return string.match(cookies, ";" .. pattern_escape(name) .. "=(.-);") @@ -516,18 +498,21 @@ function body() html_attr(secure_value("redirect", target, 0)) html("'>") html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autocomplete='username' autofocus></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' autocomplete='current-password'></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit'></td></tr>") + html("<tr><td><label for='username'>Username:</label></td><td>") + html("<input id='username' name='username'") + html(" autocomplete='username' autofocus></td></tr>") + html("<tr><td><label for='password'>Password:</label></td><td>") + html("<input id='password' name='password' type='password'") + html(" autocomplete='current-password'></td></tr>") + html("<tr><td colspan='2'>") + html("<input value='Login' type='submit'></td></tr>") html("</table></form>") return 0 end --- cgit calls filter_open with the action name followed by the request fields --- in a fixed order, so they are unpacked here into the tables the functions --- above read. Only a post reaches filter_write, carrying the form body, and --- filter_close is where the action finally runs and answers cgit. +-- filter_open unpacks the action and request fields cgit passes in fixed +-- order, filter_write collects a post body, and filter_close runs the action. local actions = {} actions["authenticate-post"] = authenticate_post diff --git a/custom/extensions/auth-inline.lua b/custom/extensions/auth-inline.lua index aa4b9f1..5489189 100644 --- a/custom/extensions/auth-inline.lua +++ b/custom/extensions/auth-inline.lua @@ -11,11 +11,9 @@ -- be the same Lua that cgit was built against. Lua 5.5 will not do, because -- luaossl has no 5.5 build. -- --- Serve cgit over HTTPS and terminate TLS in the web server in front of it. --- The session cookie is marked Secure by default, so a browser only sends it --- back over HTTPS, and on an instance served over plain HTTP with no TLS --- anywhere the cookie never comes back and login appears to loop until --- cookie_insecure below is set. +-- The session cookie is marked Secure by default, so a browser only sends +-- it back over HTTPS. On an instance served over plain HTTP login loops +-- until cookie_insecure below is set. -- -- Two libraries are needed. luaossl provides openssl.rand and openssl.hmac and -- lives at <https://github.com/wahern/luaossl>, and luaposix provides @@ -42,16 +40,10 @@ -- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)" -- luarocks install luaposix -- --- Some distributions package both as well, for example lua-luaossl and --- lua-posix on Debian, and such a package has to be built for the same Lua --- version as cgit. --- --- The cookie carries only a user name and there is no server-side session --- store, so deleting an account does not revoke a cookie already issued until --- it expires, and instances that share a secret file accept each other's --- cookies. The login form carries no CSRF token. Both are acceptable for --- gating read access to a git browser, so weigh them before guarding anything --- more sensitive. +-- There is no server-side session store and no CSRF token, so a deleted +-- account's cookie stays valid until it expires and instances sharing a +-- secret file accept each other's cookies. That is acceptable for gating +-- read access to a git browser, so weigh it before guarding anything more. local sysstat = require("posix.sys.stat") local unistd = require("posix.unistd") @@ -59,13 +51,11 @@ local rand = require("openssl.rand") local hmac = require("openssl.hmac") -- The values that follow are the configuration and are meant to be edited. --- Nothing below them needs changing for ordinary use. -- Protected repositories and the users allowed into each. A repository named -- here is protected and one that is not named is public. The repository key --- has to match exactly, while user names match whatever their case. Replace --- the examples below with your own. They are commented out, so an unedited --- copy protects nothing and grants no accounts. +-- has to match exactly, while user names match regardless of case. The +-- examples are commented out, so an unedited copy protects nothing. local protected_repos = { -- ["secret-repo"] = { alice = true, bob = true }, -- ["another"] = { alice = true }, @@ -73,8 +63,6 @@ local protected_repos = { -- Accounts as name and hash. Generate a hash with -- mkpasswd -m sha-512 -R 300000 --- Replace the examples below. They are not real credentials and must not be --- deployed as they stand. local users = { -- alice = "$6$rounds=300000$REPLACE_THIS_SALT$REPLACE_THIS_HASH", -- bob = "$6$rounds=300000$REPLACE_THIS_SALT$REPLACE_THIS_HASH", @@ -95,8 +83,7 @@ local cookie_name = "cgitauth" -- more tightly. local cookie_path = "/" --- Leave this false so the cookie is marked Secure and only travels over HTTPS. --- Set it true only if cgit is served over plain HTTP with no TLS anywhere. +-- Set this true only if cgit is served over plain HTTP with no TLS anywhere. local cookie_insecure = false -- A throwaway hash of the documented shape, used only to spend the same work @@ -108,9 +95,8 @@ local dummy_hash = "$6$rounds=300000$0000000000000000$" -- open decodes is kept here for the calls that follow. local action, http, cgit, post --- The two lookups below, account_hash and repo_userset, are the only part of --- this script that differs from auth-file.lua. Replacing them is all it takes --- to keep accounts somewhere else. +-- The two lookups below, account_hash and repo_userset, are the only part +-- of this script that differs from auth-file.lua. -- The configured tables are folded to lowercased user names once, so that a -- lookup matches whatever case the login form was filled in with, the way @@ -186,14 +172,9 @@ local function pattern_escape(s) return (string.gsub(s, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1")) end --- The stored token was already URL encoded by secure_value, so it comes back --- verbatim and the write path in set_cookie stays symmetric with this read --- path. Decoding it here would break the signature check for any value --- carrying a percent escape. --- --- The name is escaped because it lands in a pattern. A cookie_name holding a --- magic character, say "cgit-auth", would otherwise read as a pattern and stop --- matching its own cookie while matching names nobody configured. +-- The token comes back still URL encoded by secure_value. Decoding it here +-- would break the signature check for any value carrying a percent escape. +-- The name is escaped because it lands in a Lua pattern. function get_cookie(cookies, name) cookies = string.gsub(";" .. (cookies or "") .. ";", "%s*;%s*", ";") return string.match(cookies, ";" .. pattern_escape(name) .. "=(.-);") @@ -478,18 +459,21 @@ function body() html_attr(secure_value("redirect", target, 0)) html("'>") html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autocomplete='username' autofocus></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' autocomplete='current-password'></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit'></td></tr>") + html("<tr><td><label for='username'>Username:</label></td><td>") + html("<input id='username' name='username'") + html(" autocomplete='username' autofocus></td></tr>") + html("<tr><td><label for='password'>Password:</label></td><td>") + html("<input id='password' name='password' type='password'") + html(" autocomplete='current-password'></td></tr>") + html("<tr><td colspan='2'>") + html("<input value='Login' type='submit'></td></tr>") html("</table></form>") return 0 end --- cgit calls filter_open with the action name followed by the request fields --- in a fixed order, so they are unpacked here into the tables the functions --- above read. Only a post reaches filter_write, carrying the form body, and --- filter_close is where the action finally runs and answers cgit. +-- filter_open unpacks the action and request fields cgit passes in fixed +-- order, filter_write collects a post body, and filter_close runs the action. local actions = {} actions["authenticate-post"] = authenticate_post diff --git a/custom/extensions/email-gravatar.lua b/custom/extensions/email-gravatar.lua index 85947c4..6eb5376 100644 --- a/custom/extensions/email-gravatar.lua +++ b/custom/extensions/email-gravatar.lua @@ -27,29 +27,25 @@ -- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)" -- -- Every page view sends the visitor's IP address and a hash of each --- committer's email to a third-party service, so leave this filter off if that --- is not acceptable for your instance. Addresses are hashed with MD5, which --- Gravatar still accepts. Gravatar also supports SHA-256 now, so change the --- digest in hash_hex if you prefer it. +-- committer's email to a third-party service, so leave this filter off if +-- that is not acceptable for your instance. Addresses are hashed with MD5, +-- which Gravatar still accepts. local digest = require("openssl.digest") --- These are the values to change. The size is in pixels and serves both as the --- image asked of the service and as the width and height attributes. The --- default image is the style Gravatar draws for an address it has never seen, --- and its documented choices include retro, identicon, monsterid and mp. The --- endpoint is https so the icon is not blocked as mixed content on an https --- page. +-- The size is in pixels and serves both as the image asked of the service +-- and as the width and height attributes. The default image is what +-- Gravatar draws for an address it has never seen. The endpoint is https so +-- the icon is not blocked as mixed content on an https page. local avatar_size = 13 local default_image = "retro" local base_url = "https://www.gravatar.com/avatar/" local alt_text = "Gravatar" --- cgit calls filter_open once, then filter_write for each piece of the name, --- then filter_close, so what one call works out has to be left here for the --- next one. +-- One name reaches this filter as an open, writes and a close, so what the +-- open works out is kept here for the close. local buffer = "" local avatar_hash = nil diff --git a/custom/extensions/email-libravatar.lua b/custom/extensions/email-libravatar.lua index e958346..9b3d595 100644 --- a/custom/extensions/email-libravatar.lua +++ b/custom/extensions/email-libravatar.lua @@ -26,27 +26,24 @@ -- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)" -- -- Every page view sends the visitor's IP address and a hash of each --- committer's email to a third-party service, so leave this filter off if that --- is not acceptable for your instance. Addresses are hashed with MD5. +-- committer's email to a third-party service, so leave this filter off if +-- that is not acceptable for your instance. Addresses are hashed with MD5. local digest = require("openssl.digest") --- These are the values to change. The size is in pixels and serves both as the --- image asked of the service and as the width and height attributes. The --- default image is the style Libravatar draws for an address it has never --- seen, and its documented choices include retro, identicon, monsterid and mm. --- The endpoint is the secure CDN so the icon loads over https and is not --- blocked as mixed content on an https page. +-- The size is in pixels and serves both as the image asked of the service +-- and as the width and height attributes. The default image is what +-- Libravatar draws for an address it has never seen. The endpoint is the +-- secure CDN so the icon is not blocked as mixed content on an https page. local avatar_size = 13 local default_image = "retro" local base_url = "https://seccdn.libravatar.org/avatar/" local alt_text = "Libravatar" --- cgit calls filter_open once, then filter_write for each piece of the name, --- then filter_close, so what one call works out has to be left here for the --- next one. +-- One name reaches this filter as an open, writes and a close, so what the +-- open works out is kept here for the close. local buffer = "" local avatar_hash = nil diff --git a/custom/extensions/link-commits.lua b/custom/extensions/link-commits.lua index 3f2429d..42252f3 100644 --- a/custom/extensions/link-commits.lua +++ b/custom/extensions/link-commits.lua @@ -10,12 +10,10 @@ -- Object names are handled apart from the rules below because the length --- bound on them cannot be written as a plain Lua pattern. Recognition is by --- shape, since a commit-filter cannot ask the repository whether a hash is --- real, so any hex run within the bounds is linked whatever mix of digits and --- letters it has and abbreviated and all-digit names are both caught. The --- cost is that a long hex-looking number now and then links to an object that --- does not exist, which cgit renders as a harmless "bad object name" page. +-- bound on them cannot be written as a plain Lua pattern. A commit-filter +-- cannot ask the repository whether a hash is real, so matching is by shape +-- and a long hex number may link to an object that does not exist, which +-- cgit renders as a harmless "Bad object id" page. local objects = { -- Set false to stop linking bare hashes. enabled = true, @@ -32,24 +30,23 @@ local objects = { -- Text-reference rules, each one a Lua pattern with a single capture and a -- URL where %s is replaced by that capture, percent-encoded. The whole match -- is what gets shown and the capture is only what goes into the URL. Rules are --- tried in order and the leftmost match on the line wins, so put the more --- specific patterns first, and an empty list leaves only object names linked. +-- tried in order and the leftmost match wins, so put the more specific +-- patterns first, and an empty list leaves only object names linked. -- --- Lua patterns are not regular expressions. There is no alternation and no --- {n,m} repetition, %d is a digit, %a a letter, %w a letter or digit, %x a --- hex digit, and a literal magic character is escaped with %, so a literal --- dash is '%-'. The whole set is in the reference manual at +-- Lua patterns are not regular expressions. The reference is -- https://www.lua.org/manual/5.1/manual.html#5.4.1 -- --- Patterns run against the escaped message, so '&', '<' and '>' reach them as --- '&', '<' and '>'. Match those entity spellings rather than the --- bare character, and keep a pattern from ending part way through one, since --- the matched run is what gets wrapped in the anchor. +-- Patterns run against the escaped message, so match the entity spellings +-- '&', '<' and '>' rather than the bare characters, and keep a +-- pattern from ending part way through one. local rules = { { pattern = "#(%d+)", url = "https://bugs.example.com/?bug=%s" }, - -- { pattern = "CVE%-(%d%d%d%d%-%d+)", url = "https://www.cve.org/CVERecord?id=CVE-%s" }, - -- { pattern = "!(%d+)", url = "https://gitlab.example.com/group/repo/-/merge_requests/%s" }, - -- { pattern = "RFC%s?(%d+)", url = "https://www.rfc-editor.org/rfc/rfc%s" }, + -- { pattern = "CVE%-(%d%d%d%d%-%d+)", + -- url = "https://www.cve.org/CVERecord?id=CVE-%s" }, + -- { pattern = "!(%d+)", + -- url = "https://gitlab.example.com/my/repo/-/merge_requests/%s" }, + -- { pattern = "RFC%s?(%d+)", + -- url = "https://www.rfc-editor.org/rfc/rfc%s" }, } @@ -68,7 +65,9 @@ end -- for a gsub reference. local function make_link(url_template, capture, display) local encoded = url_encode(capture) - local href = string.gsub(url_template, "%%s", function() return encoded end) + local href = string.gsub(url_template, "%%s", function() + return encoded + end) return "<a href='" .. href .. "'>" .. display .. "</a>" end @@ -89,7 +88,9 @@ local function collect(text) capture = string.sub(text, start, stop) end candidates[#candidates + 1] = { - start = start, stop = stop, priority = priority, + start = start, + stop = stop, + priority = priority, link = make_link(rule.url, capture, string.sub(text, start, stop)), } @@ -106,9 +107,12 @@ local function collect(text) local start, stop, run = string.find(text, "%f[%w](%x+)%f[%W]", init) if not start then break end - if #run >= objects.min_length and #run <= objects.max_length then + if #run >= objects.min_length + and #run <= objects.max_length then candidates[#candidates + 1] = { - start = start, stop = stop, priority = priority, + start = start, + stop = stop, + priority = priority, link = make_link(objects.url, run, run), } end @@ -141,7 +145,8 @@ function filter_close() -- A candidate reaching back into one already emitted is -- dropped, so no run of text is ever wrapped twice. if candidate.start >= pos then - out[#out + 1] = string.sub(text, pos, candidate.start - 1) + out[#out + 1] = + string.sub(text, pos, candidate.start - 1) out[#out + 1] = candidate.link pos = candidate.stop + 1 end diff --git a/custom/extensions/syntax-highlight.lua b/custom/extensions/syntax-highlight.lua index 862965a..e2032aa 100644 --- a/custom/extensions/syntax-highlight.lua +++ b/custom/extensions/syntax-highlight.lua @@ -1,16 +1,13 @@ --- Server-side syntax highlighting for cgit's tree and blob views, run inside --- cgit's embedded Lua interpreter so a coloured blob costs no extra process --- per request. Colouring is deliberately left out of cgit itself, which --- serves plain escaped text on its own, so this filter is named by the --- source-filter setting and any other program could take its place. Tokens --- come from the Scintillua lexers and reach the page wrapped in span elements --- carrying the hl- classes that assets/cgit.css styles. Whenever a piece is --- missing or will not load, from lpeg down to a single lexer, the file falls --- back to plain escaped text instead of failing, so uncoloured code means a --- missing dependency rather than an error. It runs on Lua 5.1 through 5.5 and +-- Server-side syntax highlighting for cgit's tree and blob views, named by +-- the source-filter setting and run inside cgit's embedded Lua interpreter +-- so a coloured blob costs no extra process per request. Tokens come from the +-- Scintillua lexers and reach the page wrapped in span elements carrying the +-- hl- classes that assets/cgit.css styles. Whenever a piece is missing or +-- will not load, from lpeg down to a single lexer, the filter falls back to +-- plain escaped text instead of failing. It runs on Lua 5.1 through 5.5 and -- LuaJIT. -- --- source-filter=lua:/usr/lib/cgit/extensions/syntax-highlight.lua +-- source-filter=lua:/usr/local/lib/cgit/filters/syntax-highlight.lua -- Files larger than this many bytes are served escaped but unhighlighted, so @@ -28,12 +25,10 @@ local scintillua_env = "CGIT_SCINTILLUA_PATH" -- Directories probed for the lexers when that variable is not set, tried -- after the directory of $CGIT_CONFIG, so placing or symlinking a scintillua --- directory next to cgitrc is enough to be found. Scintillua is the lexer --- collection from the Textadept editor, around 160 languages as plain .lua --- files with nothing to compile, from --- https://orbitalquark.github.io/scintillua/. It does not bundle lpeg, which --- it needs and which has to be built for the Lua cgit is linked against, and --- forgetting that is the usual reason nothing is coloured. +-- directory next to cgitrc is enough for it to be found. The lexers come +-- from https://orbitalquark.github.io/scintillua/ and need lpeg, built for +-- the Lua cgit is linked against. Forgetting that is the usual reason +-- nothing is coloured. -- -- # Debian and Ubuntu -- sudo apt install lua-lpeg @@ -76,15 +71,23 @@ local css = { ["function"] = "hl-func", } --- Extension to lexer name fixes for the fallback path, reached only when this --- Scintillua has no detect(). Most extensions already equal their lexer name --- and these are the frequent exceptions. A wrong guess only falls back to --- plain text, so a best-effort entry costs nothing. +-- Extension to lexer name fixes for the fallback path, reached only when +-- this Scintillua has no detect(). Most extensions already equal their lexer +-- name and these are the frequent exceptions. local ext_lexer = { - py = "python", js = "javascript", ts = "typescript", - rb = "ruby", pl = "perl", pm = "perl", sh = "bash", - md = "markdown", htm = "html", yml = "yaml", - rs = "rust", c = "ansi_c", h = "ansi_c", + py = "python", + js = "javascript", + ts = "typescript", + rb = "ruby", + pl = "perl", + pm = "perl", + sh = "bash", + md = "markdown", + htm = "html", + yml = "yaml", + rs = "rust", + c = "ansi_c", + h = "ansi_c", } @@ -108,7 +111,8 @@ local function scintillua_path() if config then local dir = string.match(config, "^(.*)/[^/]+$") if dir then - candidates[#candidates + 1] = dir .. "/scintillua/lexers" + candidates[#candidates + 1] = + dir .. "/scintillua/lexers" end end for _, dir in ipairs(scintillua_dirs) do @@ -159,9 +163,6 @@ local function load_lexer_name(name) return nil end --- Resolve a lexer for the file, preferring Scintillua's own filename --- detection where this version provides it, then the extension map above, --- then the raw extension. local function lexer_for(name) if type(scintillua.detect) == "function" then local ok, lang = pcall(scintillua.detect, name) @@ -200,7 +201,8 @@ local function highlight(text) local part = escape(string.sub(text, pos, stop - 1)) local class = css[string.match(tag, "^[%w_]+")] if class and part ~= "" then - part = "<span class='" .. class .. "'>" .. part .. "</span>" + part = "<span class='" .. class .. "'>" + .. part .. "</span>" end out[#out + 1] = part pos = stop @@ -223,8 +225,9 @@ function filter_write(str) end -- cgit takes filter output through a C string sink that stops at the first --- NUL byte, so a blob holding one is truncated there. That reaches binary --- files which slip past cgit's text detection, not ordinary source. +-- NUL byte, so a write holding one loses everything from the NUL on. That +-- reaches binary files which slip past cgit's text detection, not ordinary +-- source. function filter_close() local text = table.concat(chunks) chunks = {} |
