Squashed 'third_party/cgit/' changes from 8fc0c81bb..26ac84466

26ac84466 Bump version to 1.4.1
cc167887f Fix bad free in cgit_diff_tree
4a30da89c Bump version to 1.4.0
695515801 Tolerate short writes in print_slot
069d15447 git: update to v2.36.1
3374b0e7a git: update to v2.36.0
400fd7abb Use release_commit_memory()
93ce8fe3b Reset font size for blame oid
28c0cb6f7 Add a link to the parent commit in blame
c5809a429 Fix fmt() off-by-one error
129d8a158 Allow to give readme head from query
44a004809 Bump version to 1.3.0
76d9396e4 Update information for fork
d993e4be6 Remove Lua support
e4ce4fa74 Merge remote-tracking branch 'ch/git-2-35'
065ee253a Silence owner-info error
f92ba7ea8 Remove default favicon
03519c7bc Show about path in page title
20f0352d9 Generate valid Atom feeds
516175469 Merge up to git v2.32.0
12d91b897 Fix crash trying to print "this commit" on 404s
957855ffd Use owner-filter for repo page headers
f9c417f24 Fix tests for diff spans
be6a526a7 Use <pre> and <span> to print diffs
a8e11db65 Use buffered stdio
b2511f295 Remove redundant title on repo anchors
2d4c893db Improve button spacing for browsers w/o CSS
1e9f26ffb Improve decoration display for browsers without CSS
2843093cb Use <pre> for commit-msg
122f7a9be Improve pageheader display on text-based browsers
298f7d15f Use git raw note format
6524fe671 Add "this commit" option to switch form
8f9034884 Show subject in commit page title
41a17adaf Show symlink targets in tree listing
437d0b416 Disallow blame in robots.txt
e75fa957e Don't link to blame for binary blobs
8bf017ec5 Bail from blame if blob is binary
fa86ef6a3 Remove dependency on memrchr
bbbaa29a9 git: update to v2.35.1
73e98c16e git: update to v2.35.0
11be5b818 git: update to v2.34.1
b8f2b675d git: update to v2.34.0
45eff4065 git: update to v2.33.0
5258c297b git: update to v2.32.0
6dbbffe01 git: update to v2.31.1
62eb8db45 md2html: use proper formatting for hr
d889cae81 git: update to v2.31.0
4ffadc1e0 git: update to v2.30.1
bd6f5683f tests: t0107: support older and/or non-GNU tar
f69626c68 md2html: use sane_lists extension
cef27b670 git: update to v2.30.0
b1739247b git: update to v2.29.2
fe99c76ee git: update to v2.29.1
adcc4f822 tests: try with commit-graph
a1039ab17 tests: do not copy snapshots to /tmp/
a4de0e810 global: replace hard coded hash length
779631c6d global: replace references to 'sha1' with 'oid'
629659d2c git: update to v2.29.0
205837d46 git: update to v2.28.0
f780396c0 git: update to v2.27.0
0462f08d8 git: update to v2.26.0
55fa25adb Bump version
6a8d6d4b5 global: use proper accessors for maybe_tree
892ba8c3c ui-snapshot: add support for zstd compression
cc230bf04 tests: add tests for xz compressed snapshots
06671f4b2 ui-snapshot: add support for lzip compression
fde897b81 git: update to v2.25.1
5e49023b0 tests: allow to skip git version tests
fa146ccab Bump version
bd68c9887 git: update to v2.25.0
ca98c9e7b tests: skip tests if strace is not functional
d8e5dd25a git: update to v2.24.1
583aa5d80 ui-repolist: do not return unsigned (negative) value
bfabd4519 git: update to v2.24.0

git-subtree-dir: third_party/cgit
git-subtree-split: 26ac844661e95ee1ff3ddf4f8691de9904dad783
This commit is contained in:
sterni 2022-05-19 10:23:37 +02:00
parent 723dc8fbcb
commit 0c86e2ac3f
50 changed files with 567 additions and 1809 deletions

View file

@ -19,7 +19,7 @@ regex=''
# This expression generates links to commits referenced by their SHA1.
regex=$regex'
s|\b([0-9a-fA-F]{7,40})\b|<a href="./?id=\1">\1</a>|g'
s|\b([0-9a-fA-F]{7,64})\b|<a href="./?id=\1">\1</a>|g'
# This expression generates links to a fictional bugtracker.
regex=$regex'

View file

@ -1,35 +0,0 @@
-- This script may be used with the email-filter or repo.email-filter settings in cgitrc.
-- It adds gravatar icons to author names. It is designed to be used with the lua:
-- prefix in filters. It is much faster than the corresponding python script.
--
-- Requirements:
-- luaossl
-- <http://25thandclement.com/~william/projects/luaossl.html>
--
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
function filter_open(email, page)
buffer = ""
md5 = md5_hex(email:sub(2, -2):lower())
end
function filter_close()
html("<img src='//www.gravatar.com/avatar/" .. md5 .. "?s=13&amp;d=retro' width='13' height='13' alt='Gravatar' /> " .. buffer)
return 0
end
function filter_write(str)
buffer = buffer .. str
end

View file

@ -1,8 +1,5 @@
#!/usr/bin/env python3
# Please prefer the email-gravatar.lua using lua: as a prefix over this script. This
# script is very slow, in comparison.
#
# This script may be used with the email-filter or repo.email-filter settings in cgitrc.
#
# The following environment variables can be used to retrieve the configuration

View file

@ -1,36 +0,0 @@
-- This script may be used with the email-filter or repo.email-filter settings in cgitrc.
-- It adds libravatar icons to author names. It is designed to be used with the lua:
-- prefix in filters.
--
-- Requirements:
-- luaossl
-- <http://25thandclement.com/~william/projects/luaossl.html>
--
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
function filter_open(email, page)
buffer = ""
md5 = md5_hex(email:sub(2, -2):lower())
end
function filter_close()
baseurl = os.getenv("HTTPS") and "https://seccdn.libravatar.org/" or "http://cdn.libravatar.org/"
html("<img src='" .. baseurl .. "avatar/" .. md5 .. "?s=13&amp;d=retro' width='13' height='13' alt='Libravatar' /> " .. buffer)
return 0
end
function filter_write(str)
buffer = buffer .. str
end

View file

@ -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

View file

@ -1,360 +0,0 @@
-- 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>
-- 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")
--
--
-- Configure these variables for your settings.
--
--
-- A list of password protected repositories, with which gentooAccess
-- group is allowed to access each one.
local protected_repos = {
glouglou = "infra",
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"
--
--
-- Authentication functions follow below. Swap these out if you want different authentication semantics.
--
--
-- Sets HTTP cookie headers based on post and sets up redirection.
function authenticate_post()
local redirect = validate_value("redirect", post["redirect"])
if redirect == nil then
not_found()
return 0
end
redirect_to(redirect)
local groups = gentoo_ldap_user_groups(post["username"], post["password"])
if groups == nil then
set_cookie("cgitauth", "")
else
-- One week expiration time
set_cookie("cgitauth", secure_value("gentoogroups", table.concat(groups, ","), os.time() + 604800))
end
html("\n")
return 0
end
-- Returns 1 if the cookie is valid and 0 if it is not.
function authenticate_cookie()
local required_group = protected_repos[cgit["repo"]]
if required_group == nil then
-- We return as valid if the repo is not protected.
return 1
end
local user_groups = validate_value("gentoogroups", get_cookie(http["cookie"], "cgitauth"))
if user_groups == nil or user_groups == "" then
return 0
end
for group in string.gmatch(user_groups, "[^,]+") do
if group == required_group then
return 1
end
end
return 0
end
-- Prints the html for the login form.
function body()
html("<h2>Gentoo LDAP 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
--
--
-- Gentoo LDAP support.
--
--
function gentoo_ldap_user_groups(username, password)
-- Ensure the user is alphanumeric
if username == nil or username:match("%W") then
return nil
end
local who = "uid=" .. username .. ",ou=devs,dc=gentoo,dc=org"
local ldap, err = lualdap.open_simple {
uri = "ldap://ldap1.gentoo.org",
who = who,
password = password,
starttls = true,
certfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.crt",
keyfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.key",
cacertfile = "/var/www/uwsgi/cgit/gentoo-ldap/ca.pem"
}
if ldap == nil then
return nil
end
local group_suffix = ".group"
local group_suffix_len = group_suffix:len()
local groups = {}
for dn, attribs in ldap:search { base = who, scope = "subtree" } do
local access = attribs["gentooAccess"]
if dn == who and access ~= nil then
for i, v in ipairs(access) do
local vlen = v:len()
if vlen > group_suffix_len and v:sub(-group_suffix_len) == group_suffix then
table.insert(groups, v:sub(1, vlen - group_suffix_len))
end
end
end
end
ldap:close()
return groups
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 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

View file

@ -86,11 +86,7 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div#
margin: 15px 0;
}
.markdown-body hr {
background: transparent url("/dirty-shade.png") repeat-x 0 0;
border: 0 none;
color: #ccc;
height: 4px;
padding: 0;
border: 2px solid #ccc;
}
.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;
@ -301,6 +297,7 @@ markdown.markdownFromFile(
"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"}})

View file

@ -1,17 +0,0 @@
-- This script is an example of an owner-filter. It replaces the
-- usual query link with one to a fictional homepage. This script may
-- be used with the owner-filter or repo.owner-filter settings in
-- cgitrc with the `lua:` prefix.
function filter_open()
buffer = ""
end
function filter_close()
html(string.format("<a href=\"%s\">%s</a>", "http://wiki.example.com/about/" .. buffer, buffer))
return 0
end
function filter_write(str)
buffer = buffer .. str
end

View file

@ -1,314 +0,0 @@
-- 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>
--
local sysstat = require("posix.sys.stat")
local unistd = require("posix.unistd")
local rand = require("openssl.rand")
local hmac = require("openssl.hmac")
--
--
-- Configure these variables for your settings.
--
--
-- A list of password protected repositories along with the users who can access them.
local protected_repos = {
glouglou = { laurent = true, jason = true },
qt = { jason = true, bob = true }
}
-- A list of users and hashes, generated with `mkpasswd -m sha-512 -R 300000`.
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"
}
-- 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"
--
--
-- Authentication functions follow below. Swap these out if you want different authentication semantics.
--
--
-- Sets HTTP cookie headers based on post and sets up redirection.
function authenticate_post()
local hash = users[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 = protected_repos[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