Diffstat (limited to 'filters')
| -rwxr-xr-x | filters/ci-jenkins.sh | 58 | ||||
| -rwxr-xr-x | filters/commit-links.sh | 2 | ||||
| -rw-r--r-- | filters/email-gravatar.lua | 17 | ||||
| -rw-r--r-- | filters/email-libravatar.lua | 17 | ||||
| -rw-r--r-- | filters/file-authentication.lua | 359 | ||||
| -rw-r--r-- | filters/gentoo-ldap-authentication.lua | 76 | ||||
| -rwxr-xr-x | filters/html-converters/md2html | 104 | ||||
| -rw-r--r-- | filters/simple-authentication.lua | 90 | ||||
| -rwxr-xr-x | filters/syntax-highlighting.py | 45 | ||||
| -rwxr-xr-x | filters/syntax-highlighting.sh | 14 |
10 files changed, 90 insertions, 692 deletions
diff --git a/filters/ci-jenkins.sh b/filters/ci-jenkins.sh deleted file mode 100755 index 842af21..0000000 --- a/filters/ci-jenkins.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh -# This script may be used with the ci-filter or repo.ci-filter setting in -# cgitrc to hide the "ci" tab for refs which have no pipeline on a Jenkins -# instance. -# -# Arguments: -# $1 the name of the branch or tag being viewed -# $2 "branch" or "tag" -# $3 the ci url which the "ci" tab would redirect to -# -# Exit with a zero status to show the tab, non-zero to hide it. This script -# must not write anything to standard output, as that would end up in the -# middle of the page cgit is rendering. -# -# The filter is consulted while rendering every repository page, so the -# verdict is cached on disk to keep Jenkins from being hammered, and the -# probe is given a short timeout so that an unreachable Jenkins degrades -# into a missing tab rather than a hanging web server. -# -# Set CI_NETRC to a netrc(5) file if the Jenkins instance requires -# authentication; without it a private job answers 403 and the tab is -# hidden even though the pipeline exists. - -CI_CACHE_DIR="${CI_CACHE_DIR:-/var/cache/cgit/ci-filter}" -CI_CACHE_TTL_MINUTES="${CI_CACHE_TTL_MINUTES:-5}" -CI_TIMEOUT="${CI_TIMEOUT:-2}" - -url="$3" -test -n "$url" || exit 1 - -# Jenkins job pages are often not readable anonymously, so query the REST -# API rather than the page the tab points at. -probe="$url/api/json?tree=name" - -key="$(printf '%s' "$url" | cksum | tr -cd '0-9')" -cache="$CI_CACHE_DIR/$key" - -mkdir -p "$CI_CACHE_DIR" 2>/dev/null - -if test -f "$cache" && - test -z "$(find "$cache" -mmin "+$CI_CACHE_TTL_MINUTES" 2>/dev/null)" -then - exit "$(cat "$cache")" -fi - -status=0 -curl --silent --fail --head --output /dev/null \ - --max-time "$CI_TIMEOUT" \ - ${CI_NETRC:+--netrc-file "$CI_NETRC"} \ - "$probe" >/dev/null 2>&1 || status=1 - -if test -d "$CI_CACHE_DIR" -then - printf '%s\n' "$status" >"$cache.$$" 2>/dev/null && - mv "$cache.$$" "$cache" 2>/dev/null -fi - -exit "$status" diff --git a/filters/commit-links.sh b/filters/commit-links.sh index 796ac30..5881952 100755 --- a/filters/commit-links.sh +++ b/filters/commit-links.sh @@ -19,7 +19,7 @@ regex='' # This expression generates links to commits referenced by their SHA1. regex=$regex' -s|\b([0-9a-fA-F]{7,64})\b|<a href="./?id=\1">\1</a>|g' +s|\b([0-9a-fA-F]{7,40})\b|<a href="./?id=\1">\1</a>|g' # This expression generates links to a fictional bugtracker. regex=$regex' diff --git a/filters/email-gravatar.lua b/filters/email-gravatar.lua index c39b490..52cf426 100644 --- a/filters/email-gravatar.lua +++ b/filters/email-gravatar.lua @@ -3,24 +3,15 @@ -- prefix in filters. It is much faster than the corresponding python script. -- -- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> +-- luacrypto >= 0.3 +-- <http://mkottman.github.io/luacrypto/> -- -local digest = require("openssl.digest") - -function md5_hex(input) - local b = digest.new("md5"):final(input) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end +local crypto = require("crypto") function filter_open(email, page) buffer = "" - md5 = md5_hex(email:sub(2, -2):lower()) + md5 = crypto.digest("md5", email:sub(2, -2):lower()) end function filter_close() diff --git a/filters/email-libravatar.lua b/filters/email-libravatar.lua index 7336baf..b0e2447 100644 --- a/filters/email-libravatar.lua +++ b/filters/email-libravatar.lua @@ -3,24 +3,15 @@ -- prefix in filters. -- -- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> +-- luacrypto >= 0.3 +-- <http://mkottman.github.io/luacrypto/> -- -local digest = require("openssl.digest") - -function md5_hex(input) - local b = digest.new("md5"):final(input) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end +local crypto = require("crypto") function filter_open(email, page) buffer = "" - md5 = md5_hex(email:sub(2, -2):lower()) + md5 = crypto.digest("md5", email:sub(2, -2):lower()) end function filter_close() diff --git a/filters/file-authentication.lua b/filters/file-authentication.lua deleted file mode 100644 index 0248804..0000000 --- a/filters/file-authentication.lua +++ /dev/null @@ -1,359 +0,0 @@ --- This script may be used with the auth-filter. --- --- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- luaposix --- <https://github.com/luaposix/luaposix> --- -local sysstat = require("posix.sys.stat") -local unistd = require("posix.unistd") -local rand = require("openssl.rand") -local hmac = require("openssl.hmac") - --- This file should contain a series of lines in the form of: --- username1:hash1 --- username2:hash2 --- username3:hash3 --- ... --- Hashes can be generated using something like `mkpasswd -m sha-512 -R 300000`. --- This file should not be world-readable. -local users_filename = "/etc/cgit-auth/users" - --- This file should contain a series of lines in the form of: --- groupname1:username1,username2,username3,... --- ... -local groups_filename = "/etc/cgit-auth/groups" - --- This file should contain a series of lines in the form of: --- reponame1:groupname1,groupname2,groupname3,... --- ... -local repos_filename = "/etc/cgit-auth/repos" - --- Set this to a path this script can write to for storing a persistent --- cookie secret, which should not be world-readable. -local secret_filename = "/var/cache/cgit/auth-secret" - --- --- --- Authentication functions follow below. Swap these out if you want different authentication semantics. --- --- - --- Looks up a hash for a given user. -function lookup_hash(user) - local line - for line in io.lines(users_filename) do - local u, h = string.match(line, "(.-):(.+)") - if u:lower() == user:lower() then - return h - end - end - return nil -end - --- Looks up users for a given repo. -function lookup_users(repo) - local users = nil - local groups = nil - local line, group, user - for line in io.lines(repos_filename) do - local r, g = string.match(line, "(.-):(.+)") - if r == repo then - groups = { } - for group in string.gmatch(g, "([^,]+)") do - groups[group:lower()] = true - end - break - end - end - if groups == nil then - return nil - end - for line in io.lines(groups_filename) do - local g, u = string.match(line, "(.-):(.+)") - if groups[g:lower()] then - if users == nil then - users = { } - end - for user in string.gmatch(u, "([^,]+)") do - users[user:lower()] = true - end - end - end - return users -end - - --- Sets HTTP cookie headers based on post and sets up redirection. -function authenticate_post() - local hash = lookup_hash(post["username"]) - local redirect = validate_value("redirect", post["redirect"]) - - if redirect == nil then - not_found() - return 0 - end - - redirect_to(redirect) - - if hash == nil or hash ~= unistd.crypt(post["password"], hash) then - set_cookie("cgitauth", "") - else - -- One week expiration time - local username = secure_value("username", post["username"], os.time() + 604800) - set_cookie("cgitauth", username) - end - - html("\n") - return 0 -end - - --- Returns 1 if the cookie is valid and 0 if it is not. -function authenticate_cookie() - accepted_users = lookup_users(cgit["repo"]) - if accepted_users == nil then - -- We return as valid if the repo is not protected. - return 1 - end - - local username = validate_value("username", get_cookie(http["cookie"], "cgitauth")) - if username == nil or not accepted_users[username:lower()] then - return 0 - else - return 1 - end -end - --- Prints the html for the login form. -function body() - html("<h2>Authentication Required</h2>") - html("<form method='post' action='") - html_attr(cgit["login"]) - html("'>") - html("<input type='hidden' name='redirect' value='") - html_attr(secure_value("redirect", cgit["url"], 0)) - html("' />") - html("<table>") - html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") - html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") - html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") - html("</table></form>") - - return 0 -end - - - --- --- --- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. --- --- - -local actions = {} -actions["authenticate-post"] = authenticate_post -actions["authenticate-cookie"] = authenticate_cookie -actions["body"] = body - -function filter_open(...) - action = actions[select(1, ...)] - - http = {} - http["cookie"] = select(2, ...) - http["method"] = select(3, ...) - http["query"] = select(4, ...) - http["referer"] = select(5, ...) - http["path"] = select(6, ...) - http["host"] = select(7, ...) - http["https"] = select(8, ...) - - cgit = {} - cgit["repo"] = select(9, ...) - cgit["page"] = select(10, ...) - cgit["url"] = select(11, ...) - cgit["login"] = select(12, ...) - -end - -function filter_close() - return action() -end - -function filter_write(str) - post = parse_qs(str) -end - - --- --- --- Utility functions based on keplerproject/wsapi. --- --- - -function url_decode(str) - if not str then - return "" - end - str = string.gsub(str, "+", " ") - str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) - str = string.gsub(str, "\r\n", "\n") - return str -end - -function url_encode(str) - if not str then - return "" - end - str = string.gsub(str, "\n", "\r\n") - str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) - str = string.gsub(str, " ", "+") - return str -end - -function parse_qs(qs) - local tab = {} - for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do - tab[url_decode(key)] = url_decode(val) - end - return tab -end - -function get_cookie(cookies, name) - cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") - return url_decode(string.match(cookies, ";" .. name .. "=(.-);")) -end - -function tohex(b) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end - --- --- --- Cookie construction and validation helpers. --- --- - -local secret = nil - --- Loads a secret from a file, creates a secret, or returns one from memory. -function get_secret() - if secret ~= nil then - return secret - end - local secret_file = io.open(secret_filename, "r") - if secret_file == nil then - local old_umask = sysstat.umask(63) - local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) - local temporary_file = io.open(temporary_filename, "w") - if temporary_file == nil then - os.exit(177) - end - temporary_file:write(tohex(rand.bytes(32))) - temporary_file:close() - unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. - unistd.unlink(temporary_filename) - sysstat.umask(old_umask) - secret_file = io.open(secret_filename, "r") - end - if secret_file == nil then - os.exit(177) - end - secret = secret_file:read() - secret_file:close() - if secret:len() ~= 64 then - os.exit(177) - end - return secret -end - --- Returns value of cookie if cookie is valid. Otherwise returns nil. -function validate_value(expected_field, cookie) - local i = 0 - local value = "" - local field = "" - local expiration = 0 - local salt = "" - local chmac = "" - - if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then - return nil - end - - for component in string.gmatch(cookie, "[^|]+") do - if i == 0 then - field = component - elseif i == 1 then - value = component - elseif i == 2 then - expiration = tonumber(component) - if expiration == nil then - expiration = -1 - end - elseif i == 3 then - salt = component - elseif i == 4 then - chmac = component - else - break - end - i = i + 1 - end - - if chmac == nil or chmac:len() == 0 then - return nil - end - - -- Lua hashes strings, so these comparisons are time invariant. - if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then - return nil - end - - if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then - return nil - end - - if url_decode(field) ~= expected_field then - return nil - end - - return url_decode(value) -end - -function secure_value(field, value, expiration) - if value == nil or value:len() <= 0 then - return "" - end - - local authstr = "" - local salt = tohex(rand.bytes(16)) - value = url_encode(value) - field = url_encode(field) - authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) - return authstr -end - -function set_cookie(cookie, value) - html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") - if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then - html("; secure") - end - html("\n") -end - -function redirect_to(url) - html("Status: 302 Redirect\n") - html("Cache-Control: no-cache, no-store\n") - html("Location: " .. url .. "\n") -end - -function not_found() - html("Status: 404 Not Found\n") - html("Cache-Control: no-cache, no-store\n\n") -end diff --git a/filters/gentoo-ldap-authentication.lua b/filters/gentoo-ldap-authentication.lua index 673c88d..c1e382f 100644 --- a/filters/gentoo-ldap-authentication.lua +++ b/filters/gentoo-ldap-authentication.lua @@ -1,18 +1,12 @@ -- This script may be used with the auth-filter. Be sure to configure it as you wish. -- -- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> +-- luacrypto >= 0.3 +-- <http://mkottman.github.io/luacrypto/> -- lualdap >= 1.2 -- <https://git.zx2c4.com/lualdap/about/> --- luaposix --- <https://github.com/luaposix/luaposix> -- -local sysstat = require("posix.sys.stat") -local unistd = require("posix.unistd") -local lualdap = require("lualdap") -local rand = require("openssl.rand") -local hmac = require("openssl.hmac") + -- -- @@ -27,9 +21,11 @@ local protected_repos = { portage = "dev" } --- Set this to a path this script can write to for storing a persistent --- cookie secret, which should be guarded. -local secret_filename = "/var/cache/cgit/auth-secret" + +-- All cookies will be authenticated based on this secret. Make it something +-- totally random and impossible to guess. It should be large. +local secret = "BE SURE TO CUSTOMIZE THIS STRING TO SOMETHING BIG AND RANDOM" + -- @@ -106,9 +102,11 @@ end -- -- +local lualdap = require("lualdap") + function gentoo_ldap_user_groups(username, password) -- Ensure the user is alphanumeric - if username == nil or username:match("%W") then + if username:match("%W") then return nil end @@ -226,13 +224,6 @@ function get_cookie(cookies, name) return string.match(cookies, ";" .. name .. "=(.-);") end -function tohex(b) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end -- -- @@ -240,38 +231,7 @@ end -- -- -local secret = nil - --- Loads a secret from a file, creates a secret, or returns one from memory. -function get_secret() - if secret ~= nil then - return secret - end - local secret_file = io.open(secret_filename, "r") - if secret_file == nil then - local old_umask = sysstat.umask(63) - local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) - local temporary_file = io.open(temporary_filename, "w") - if temporary_file == nil then - os.exit(177) - end - temporary_file:write(tohex(rand.bytes(32))) - temporary_file:close() - unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. - unistd.unlink(temporary_filename) - sysstat.umask(old_umask) - secret_file = io.open(secret_filename, "r") - end - if secret_file == nil then - os.exit(177) - end - secret = secret_file:read() - secret_file:close() - if secret:len() ~= 64 then - os.exit(177) - end - return secret -end +local crypto = require("crypto") -- Returns value of cookie if cookie is valid. Otherwise returns nil. function validate_value(expected_field, cookie) @@ -280,7 +240,7 @@ function validate_value(expected_field, cookie) local field = "" local expiration = 0 local salt = "" - local chmac = "" + local hmac = "" if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then return nil @@ -299,19 +259,19 @@ function validate_value(expected_field, cookie) elseif i == 3 then salt = component elseif i == 4 then - chmac = component + hmac = component else break end i = i + 1 end - if chmac == nil or chmac:len() == 0 then + if hmac == nil or hmac:len() == 0 then return nil end -- Lua hashes strings, so these comparisons are time invariant. - if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then + if hmac ~= crypto.hmac.digest("sha256", field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt, secret) then return nil end @@ -332,11 +292,11 @@ function secure_value(field, value, expiration) end local authstr = "" - local salt = tohex(rand.bytes(16)) + local salt = crypto.hex(crypto.rand.bytes(16)) value = url_encode(value) field = url_encode(field) authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) + authstr = authstr .. "|" .. crypto.hmac.digest("sha256", authstr, secret) return authstr end diff --git a/filters/html-converters/md2html b/filters/html-converters/md2html index 4f6ad37..ebf3856 100755 --- a/filters/html-converters/md2html +++ b/filters/html-converters/md2html @@ -2,46 +2,7 @@ import markdown import sys import io -from markdown.extensions.toc import TocExtension - -# Pygments' token classes, mapped onto the --syn-* custom properties that -# cgit.css defines. The fallbacks are the palette those properties default to, -# so that the output stays readable under a stylesheet without them. -SYNTAX_COLORS = ( - (('k', 'kc', 'kd', 'kn', 'kr'), '--syn-keyword', '#000', - 'font-weight: bold'), - (('kp',), '--syn-keyword', '#000', None), - (('kt',), '--syn-type', '#010181', None), - (('nc', 'nf', 'nn', 'ne'), '--syn-keyword-alt', '#0057ae', None), - (('s', 'sa', 'sb', 'sc', 'dl', 'sd', 's2', 'sh', 'sx', 'sr', 's1', 'ss'), - '--syn-string', '#bf0303', None), - (('se',), '--syn-escape', '#f0f', None), - (('si',), '--syn-interpolation', '#0057ae', None), - (('c', 'ch', 'cm', 'c1', 'cs'), '--syn-comment', '#838183', - 'font-style: italic'), - (('cp', 'cpf'), '--syn-preproc', '#008200', None), - (('m', 'mb', 'mf', 'mh', 'mi', 'mo', 'il'), '--syn-number', '#b07e00', - None), - (('o', 'ow', 'p'), '--syn-operator', '#000', None), - (('err',), '--syn-error', '#bf0303', None), - (('gd',), '--red', 'red', None), - (('gi',), '--green', 'green', None), - (('lineno', 'linenos'), '--syn-linenum', '#555', None), -) - - -def style_defs(prefix='.highlight'): - rules = [] - for classes, prop, fallback, extra in SYNTAX_COLORS: - selector = ', '.join('%s .%s' % (prefix, c) for c in classes) - decls = 'color: var(%s, %s)' % (prop, fallback) - if extra: - decls += '; ' + extra - rules.append('%s { %s }' % (selector, decls)) - rules.append('%s .hll { background-color: var(--syn-mark-bg, #ffb) }' - % prefix) - return '\n'.join(rules) + '\n' - +from pygments.formatters import HtmlFormatter sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stdout.write(''' @@ -58,7 +19,7 @@ sys.stdout.write(''' margin-bottom: 0 !important; } .markdown-body a.absent { - color: var(--red-mid, #c00); + color: #c00; } .markdown-body a.anchor { display: block; @@ -80,32 +41,28 @@ sys.stdout.write(''' } .markdown-body h1 .mini-icon-link, .markdown-body h2 .mini-icon-link, .markdown-body h3 .mini-icon-link, .markdown-body h4 .mini-icon-link, .markdown-body h5 .mini-icon-link, .markdown-body h6 .mini-icon-link { display: none; - color: var(--fg-strong, #000); + color: #000; } .markdown-body h1:hover a.anchor, .markdown-body h2:hover a.anchor, .markdown-body h3:hover a.anchor, .markdown-body h4:hover a.anchor, .markdown-body h5:hover a.anchor, .markdown-body h6:hover a.anchor { text-decoration: none; line-height: 1; padding-left: 0; margin-left: -22px; - top: 15%; -} + top: 15%} .markdown-body h1:hover a.anchor .mini-icon-link, .markdown-body h2:hover a.anchor .mini-icon-link, .markdown-body h3:hover a.anchor .mini-icon-link, .markdown-body h4:hover a.anchor .mini-icon-link, .markdown-body h5:hover a.anchor .mini-icon-link, .markdown-body h6:hover a.anchor .mini-icon-link { display: inline-block; } -div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div#cgit .markdown-body h3 a.toclink, div#cgit .markdown-body h4 a.toclink, div#cgit .markdown-body h5 a.toclink, div#cgit .markdown-body h6 a.toclink { - color: var(--fg-strong, #000); -} .markdown-body h1 tt, .markdown-body h1 code, .markdown-body h2 tt, .markdown-body h2 code, .markdown-body h3 tt, .markdown-body h3 code, .markdown-body h4 tt, .markdown-body h4 code, .markdown-body h5 tt, .markdown-body h5 code, .markdown-body h6 tt, .markdown-body h6 code { font-size: inherit; } .markdown-body h1 { font-size: 28px; - color: var(--fg-strong, #000); + color: #000; } .markdown-body h2 { font-size: 24px; - border-bottom: 1px solid var(--border, #ccc); - color: var(--fg-strong, #000); + border-bottom: 1px solid #ccc; + color: #000; } .markdown-body h3 { font-size: 18px; @@ -117,14 +74,18 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# font-size: 14px; } .markdown-body h6 { - color: var(--fg-mute, #777); + color: #777; font-size: 14px; } .markdown-body p, .markdown-body blockquote, .markdown-body ul, .markdown-body ol, .markdown-body dl, .markdown-body table, .markdown-body pre { margin: 15px 0; } .markdown-body hr { - border: 2px solid var(--border, #ccc); + background: transparent url("/dirty-shade.png") repeat-x 0 0; + border: 0 none; + color: #ccc; + height: 4px; + padding: 0; } .markdown-body>h2:first-child, .markdown-body>h1:first-child, .markdown-body>h1:first-child+h2, .markdown-body>h3:first-child, .markdown-body>h4:first-child, .markdown-body>h5:first-child, .markdown-body>h6:first-child { margin-top: 0; @@ -186,9 +147,9 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# margin-bottom: 0px; } .markdown-body blockquote { - border-left: 4px solid var(--border, #ddd); + border-left: 4px solid #DDD; padding: 0 15px; - color: var(--fg-mute, #777); + color: #777; } .markdown-body blockquote>:first-child { margin-top: 0px; @@ -200,15 +161,15 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# font-weight: bold; } .markdown-body table th, .markdown-body table td { - border: 1px solid var(--border, #ccc); + border: 1px solid #ccc; padding: 6px 13px; } .markdown-body table tr { - border-top: 1px solid var(--border, #ccc); - background-color: var(--bg, #fff); + border-top: 1px solid #ccc; + background-color: #fff; } .markdown-body table tr:nth-child(2n) { - background-color: var(--bg-zebra, #f8f8f8); + background-color: #f8f8f8; } .markdown-body img { max-width: 100%; @@ -220,7 +181,7 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# overflow: hidden; } .markdown-body span.frame>span { - border: 1px solid var(--border, #ddd); + border: 1px solid #ddd; display: block; float: left; overflow: hidden; @@ -234,7 +195,7 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# } .markdown-body span.frame span span { clear: both; - color: var(--fg, #333); + color: #333; display: block; padding: 5px 0 0; } @@ -292,8 +253,8 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# .markdown-body code, .markdown-body tt { margin: 0 2px; padding: 0px 5px; - border: 1px solid var(--border, #eaeaea); - background-color: var(--bg-zebra, #f8f8f8); + border: 1px solid #eaeaea; + background-color: #f8f8f8; border-radius: 3px; } .markdown-body code { @@ -307,8 +268,8 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# background: transparent; } .markdown-body .highlight pre, .markdown-body pre { - background-color: var(--bg-zebra, #f8f8f8); - border: 1px solid var(--border, #ccc); + background-color: #f8f8f8; + border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; @@ -322,21 +283,12 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# border: none; } ''') -sys.stdout.write(style_defs('.highlight')) +sys.stdout.write(HtmlFormatter(style='pastie').get_style_defs('.highlight')) sys.stdout.write(''' -</style> +</style> ''') sys.stdout.write("<div class='markdown-body'>") sys.stdout.flush() # Note: you may want to run this through bleach for sanitization -markdown.markdownFromFile( - output_format="html5", - extensions=[ - "markdown.extensions.fenced_code", - "markdown.extensions.codehilite", - "markdown.extensions.tables", - "markdown.extensions.sane_lists", - TocExtension(anchorlink=True)], - extension_configs={ - "markdown.extensions.codehilite":{"css_class":"highlight"}}) +markdown.markdownFromFile(output_format="html5", extensions=["markdown.extensions.fenced_code", "markdown.extensions.codehilite", "markdown.extensions.tables"], extension_configs={"markdown.extensions.codehilite":{"css_class":"highlight"}}) sys.stdout.write("</div>") diff --git a/filters/simple-authentication.lua b/filters/simple-authentication.lua index 23d3457..596c041 100644 --- a/filters/simple-authentication.lua +++ b/filters/simple-authentication.lua @@ -1,15 +1,10 @@ -- This script may be used with the auth-filter. Be sure to configure it as you wish. -- -- Requirements: --- luaossl --- <http://25thandclement.com/~william/projects/luaossl.html> --- luaposix --- <https://github.com/luaposix/luaposix> +-- luacrypto >= 0.3 +-- <http://mkottman.github.io/luacrypto/> -- -local sysstat = require("posix.sys.stat") -local unistd = require("posix.unistd") -local rand = require("openssl.rand") -local hmac = require("openssl.hmac") + -- -- @@ -23,16 +18,24 @@ local protected_repos = { qt = { jason = true, bob = true } } --- A list of users and hashes, generated with `mkpasswd -m sha-512 -R 300000`. +-- Please note that, in production, you'll want to replace this simple lookup +-- table with either a table of salted and hashed passwords (using something +-- smart like scrypt), or replace this table lookup with an external support, +-- such as consulting your system's pam / shadow system, or an external +-- database, or an external validating web service. For testing, or for +-- extremely low-security usage, you may be able, however, to get away with +-- compromising on hardcoding the passwords in cleartext, as we have done here. local users = { - jason = "$6$rounds=300000$YYJct3n/o.ruYK$HhpSeuCuW1fJkpvMZOZzVizeLsBKcGA/aF2UPuV5v60JyH2MVSG6P511UMTj2F3H75.IT2HIlnvXzNb60FcZH1", - laurent = "$6$rounds=300000$dP0KNHwYb3JKigT$pN/LG7rWxQ4HniFtx5wKyJXBJUKP7R01zTNZ0qSK/aivw8ywGAOdfYiIQFqFhZFtVGvr11/7an.nesvm8iJUi.", - bob = "$6$rounds=300000$jCLCCt6LUpTz$PI1vvd1yaVYcCzqH8QAJFcJ60b6W/6sjcOsU7mAkNo7IE8FRGW1vkjF8I/T5jt/auv5ODLb1L4S2s.CAyZyUC" + jason = "secretpassword", + laurent = "s3cr3t", + bob = "ilikelua" } --- Set this to a path this script can write to for storing a persistent --- cookie secret, which should be guarded. -local secret_filename = "/var/cache/cgit/auth-secret" +-- All cookies will be authenticated based on this secret. Make it something +-- totally random and impossible to guess. It should be large. +local secret = "BE SURE TO CUSTOMIZE THIS STRING TO SOMETHING BIG AND RANDOM" + + -- -- @@ -42,7 +45,7 @@ local secret_filename = "/var/cache/cgit/auth-secret" -- Sets HTTP cookie headers based on post and sets up redirection. function authenticate_post() - local hash = users[post["username"]] + local password = users[post["username"]] local redirect = validate_value("redirect", post["redirect"]) if redirect == nil then @@ -52,7 +55,8 @@ function authenticate_post() redirect_to(redirect) - if hash == nil or hash ~= unistd.crypt(post["password"], hash) then + -- Lua hashes strings, so these comparisons are time invariant. + if password == nil or password ~= post["password"] then set_cookie("cgitauth", "") else -- One week expiration time @@ -180,13 +184,6 @@ function get_cookie(cookies, name) return url_decode(string.match(cookies, ";" .. name .. "=(.-);")) end -function tohex(b) - local x = "" - for i = 1, #b do - x = x .. string.format("%.2x", string.byte(b, i)) - end - return x -end -- -- @@ -194,38 +191,7 @@ end -- -- -local secret = nil - --- Loads a secret from a file, creates a secret, or returns one from memory. -function get_secret() - if secret ~= nil then - return secret - end - local secret_file = io.open(secret_filename, "r") - if secret_file == nil then - local old_umask = sysstat.umask(63) - local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) - local temporary_file = io.open(temporary_filename, "w") - if temporary_file == nil then - os.exit(177) - end - temporary_file:write(tohex(rand.bytes(32))) - temporary_file:close() - unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. - unistd.unlink(temporary_filename) - sysstat.umask(old_umask) - secret_file = io.open(secret_filename, "r") - end - if secret_file == nil then - os.exit(177) - end - secret = secret_file:read() - secret_file:close() - if secret:len() ~= 64 then - os.exit(177) - end - return secret -end +local crypto = require("crypto") -- Returns value of cookie if cookie is valid. Otherwise returns nil. function validate_value(expected_field, cookie) @@ -234,7 +200,7 @@ function validate_value(expected_field, cookie) local field = "" local expiration = 0 local salt = "" - local chmac = "" + local hmac = "" if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then return nil @@ -253,19 +219,19 @@ function validate_value(expected_field, cookie) elseif i == 3 then salt = component elseif i == 4 then - chmac = component + hmac = component else break end i = i + 1 end - if chmac == nil or chmac:len() == 0 then + if hmac == nil or hmac:len() == 0 then return nil end -- Lua hashes strings, so these comparisons are time invariant. - if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then + if hmac ~= crypto.hmac.digest("sha256", field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt, secret) then return nil end @@ -286,11 +252,11 @@ function secure_value(field, value, expiration) end local authstr = "" - local salt = tohex(rand.bytes(16)) + local salt = crypto.hex(crypto.rand.bytes(16)) value = url_encode(value) field = url_encode(field) authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) + authstr = authstr .. "|" .. crypto.hmac.digest("sha256", authstr, secret) return authstr end diff --git a/filters/syntax-highlighting.py b/filters/syntax-highlighting.py index d757e2d..e912594 100755 --- a/filters/syntax-highlighting.py +++ b/filters/syntax-highlighting.py @@ -30,50 +30,11 @@ from pygments.lexers import guess_lexer_for_filename from pygments.formatters import HtmlFormatter -# Pygments' token classes, mapped onto the --syn-* custom properties that -# cgit.css defines. The fallbacks are the palette those properties default to, -# so that the output stays readable under a stylesheet without them. -SYNTAX_COLORS = ( - (('k', 'kc', 'kd', 'kn', 'kr'), '--syn-keyword', '#000', - 'font-weight: bold'), - (('kp',), '--syn-keyword', '#000', None), - (('kt',), '--syn-type', '#010181', None), - (('nc', 'nf', 'nn', 'ne'), '--syn-keyword-alt', '#0057ae', None), - (('s', 'sa', 'sb', 'sc', 'dl', 'sd', 's2', 'sh', 'sx', 'sr', 's1', 'ss'), - '--syn-string', '#bf0303', None), - (('se',), '--syn-escape', '#f0f', None), - (('si',), '--syn-interpolation', '#0057ae', None), - (('c', 'ch', 'cm', 'c1', 'cs'), '--syn-comment', '#838183', - 'font-style: italic'), - (('cp', 'cpf'), '--syn-preproc', '#008200', None), - (('m', 'mb', 'mf', 'mh', 'mi', 'mo', 'il'), '--syn-number', '#b07e00', - None), - (('o', 'ow', 'p'), '--syn-operator', '#000', None), - (('err',), '--syn-error', '#bf0303', None), - (('gd',), '--red', 'red', None), - (('gi',), '--green', 'green', None), - (('lineno', 'linenos'), '--syn-linenum', '#555', None), -) - - -def style_defs(prefix='.highlight'): - rules = [] - for classes, prop, fallback, extra in SYNTAX_COLORS: - selector = ', '.join('%s .%s' % (prefix, c) for c in classes) - decls = 'color: var(%s, %s)' % (prop, fallback) - if extra: - decls += '; ' + extra - rules.append('%s { %s }' % (selector, decls)) - rules.append('%s .hll { background-color: var(--syn-mark-bg, #ffb) }' - % prefix) - return '\n'.join(rules) + '\n' - - sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8', errors='replace') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') data = sys.stdin.read() filename = sys.argv[1] -formatter = HtmlFormatter(nobackground=True) +formatter = HtmlFormatter(style='pastie', nobackground=True) try: lexer = guess_lexer_for_filename(filename, data) @@ -87,8 +48,8 @@ except TypeError: lexer = TextLexer() # highlight! :-) -# printout the css definitions for pygments' token classes as well +# printout pygments' css definitions as well sys.stdout.write('<style>') -sys.stdout.write(style_defs('.highlight')) +sys.stdout.write(formatter.get_style_defs('.highlight')) sys.stdout.write('</style>') sys.stdout.write(highlight(data, lexer, formatter, outfile=None)) diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh index bb8d60c..840bc34 100755 --- a/filters/syntax-highlighting.sh +++ b/filters/syntax-highlighting.sh @@ -8,10 +8,8 @@ # might have to use an external call to sed instead. # # Note: the highlight command (http://www.andre-simon.de/) uses css for syntax -# highlighting. cgit.css defines these classes in terms of its --syn-* custom -# properties, so nothing has to be added when using the default stylesheet. -# The palette below, from highlight 3.13, is what those properties default to; -# a custom stylesheet wanting the same colors can use it directly: +# highlighting, so you'll probably want something like the following included +# in your css file: # # Style definition file generated by highlight 2.4.8, http://www.andre-simon.de/ # @@ -116,12 +114,8 @@ EXTENSION="${BASENAME##*.}" # Version 2 can be found (for example) on EPEL 5, while version 3 can be # found (for example) on EPEL 6. # -# Note that -I (--include-style) is not used: the stylesheet it embeds in the -# output would override the .hl rules in cgit.css and with them any theming -# done through the --syn-* custom properties. -# # This is for version 2 -exec highlight --force -f -X -S "$EXTENSION" 2>/dev/null +exec highlight --force -f -I -X -S "$EXTENSION" 2>/dev/null # This is for version 3 -#exec highlight --force -f -O xhtml -S "$EXTENSION" 2>/dev/null +#exec highlight --force -f -I -O xhtml -S "$EXTENSION" 2>/dev/null |