From 4393288f44a9f318f88d1857e85ea8c57ceb3009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 11 Oct 2022 01:22:15 +0200 Subject: Force current filters. --- hugo-authentication.lua | 183 +++++++++++++++++++++++++++--------------------- hugo-highlighting.sh | 138 ++++++++++++++++++++++++++++++++++++ hugo-pre.sh | 26 +++++++ 3 files changed, 266 insertions(+), 81 deletions(-) create mode 100755 hugo-highlighting.sh create mode 100755 hugo-pre.sh diff --git a/hugo-authentication.lua b/hugo-authentication.lua index 4a56bd2..a6187c1 100644 --- a/hugo-authentication.lua +++ b/hugo-authentication.lua @@ -1,10 +1,15 @@ -- This script may be used with the auth-filter. Be sure to configure it as you wish. -- -- Requirements: --- luacrypto >= 0.3 --- +-- luaossl +-- +-- luaposix +-- -- - +local sysstat = require("posix.sys.stat") +local unistd = require("posix.unistd") +local rand = require("openssl.rand") +local hmac = require("openssl.hmac") -- -- @@ -13,25 +18,51 @@ -- -- A list of password protected repositories along with the users who can access them. -local public_repos = { - vimwiki = true +local protected_repos = { + glouglou = { laurent = true, jason = true }, + qt = { jason = true, bob = true } } --- 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 public_repos = {} +public_repos["wiki-public"] = true +public_repos["lyslib"] = true +public_repos["calp"] = true +public_repos["texttv"] = true +public_repos["scheme-monad"] = true +public_repos["scheme/math-parse"] = true +public_repos["file-descriptor-graph"] = true +public_repos["rss-filter"] = true +public_repos["puppet-mpd"] = true +public_repos["aur-runner"] = true +public_repos["guile-dns"] = true +public_repos["puppet/blog"] = true +public_repos["puppet/cgit"] = true +public_repos["puppet/dns_record"] = true +public_repos["puppet/image-shower"] = true +public_repos["puppet/networking"] = true +public_repos["puppet/nspawn"] = true +public_repos["puppet/nsupdate"] = true +public_repos["puppet/pacman"] = true +public_repos["puppet/profiles"] = true +public_repos["puppet/rss_filter"] = true +public_repos["puppet/shiori"] = true +public_repos["puppet/syslinux"] = true +public_repos["puppet/systemd_mount"] = true +public_repos["puppet/uwsgi"] = true +public_repos["puppet/webdav_server"] = true +public_repos["puppet/wpa_supplicant"] = true +public_repos["puppet/envvar"] = true + +-- A list of users and hashes, generated with `mkpasswd -m sha-512 -R 300000`. local users = { - hugo = "password" + hugo = "$6$13z1Pf.U8itrCRX6$g2BZpaMk1CLiT6117paWXB2qdQFRc3rsGWL4iF5h5QbHo27oljTdHk69oQWAvqlVf13aLTUF3nYw65lEp88r/1", + gitlab = "$6$rounds=300000$G/80.k.yO$FCzj0kOmxTMQHPsNHEQVZQI4ofPYz3ae6G0bWNEp3v7GnMkEQufpvWK9lvFqG3oPoy3heIC5sSdSmipUf8QVU/", + ove = "$6$rounds=30000$SGWXbaxWPHt$RQsAiAq3xPIyF32X5OZCEfT8gxesN87tqECeFd8h/QmUPpKfzqoJBkN0NRlYodjHImeI5LOrwG.FW9ktPQH/v/", } --- All cookies will be authenticated based on this secret. Make it something --- totally random and impossible to guess. It should be large. -local secret = "Ianae4woof3ial9ahdahng7ahth9yoo2ri6zuw7eeYaengai0s" - +-- 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" -- -- @@ -39,53 +70,9 @@ local secret = "Ianae4woof3ial9ahdahng7ahth9yoo2ri6zuw7eeYaengai0s" -- -- -function printenv(arg) - local keys = { - "CGIT_CONFIG", - "CGIT_REPO_URL", "CGIT_REPO_NAME", "CGIT_REPO_PATH", - "CGIT_REPO_OWNER", "CGIT_REPO_GROUP", "CGIT_REPO_DEFBRANCH", - "CGIT_REPO_SECTION", "CGIT_REPO_CLONE_URL", - - "GIT_REPO", "GIT_CONFIG_NOSYSTEM", - "GIT_ATTR_NOSYSTEM", - "GIT_DIR", "GIT_CONFIG_NOSYSTEM", "GIT_ATTR_NOSYSTEM", - - "QUERY_STRING" - } - - -- print "!!!" - -- html ("!!!") - -- print ("

body

") - io.stderr:write(os.time(os.date("!*t"))) - io.stderr:write("\n") - io.stderr:write(arg); - for _, attr in pairs(keys) do - local l = os.getenv(attr) - -- print("") - io.stderr:write(attr) - io.stderr:write(" = " ) - if l == nil then - io.stderr:write("nil"); - else - io.stderr:write(l) - end - io.stderr:write("\n") - end - -- print ("
KeyValue
" )
-		---print (attr)
-		-- print ("
") - -- print (l) - -- print("
") -end - -- Sets HTTP cookie headers based on post and sets up redirection. --- TODO this tries to authenticate on the root page (good), but fails to set --- the cookie. I think it gets stuck in the redirect filter (bad). --- TODO invalid login also kinda breaks the page... Not found should return the --- user to the login page with an error messsage displaed. function authenticate_post() - printenv("Authenticate Post\n=================\n"); - local password = users[post["username"]] + local hash = users[post["username"]] local redirect = validate_value("redirect", post["redirect"]) if redirect == nil then @@ -95,8 +82,7 @@ function authenticate_post() redirect_to(redirect) - -- Lua hashes strings, so these comparisons are time invariant. - if password == nil or password ~= post["password"] then + if hash == nil or hash ~= unistd.crypt(post["password"], hash) then set_cookie("cgitauth", "") else -- One week expiration time @@ -111,22 +97,21 @@ end -- Returns 1 if the cookie is valid and 0 if it is not. function authenticate_cookie() - printenv("Authenticate Cookie\n===================\n"); -- Everyone has access to the index page. - if os.getenv("CGIT_REPO_NAME") == nil then + -- printenv(os.getenv("CGIT_REPO_NAME")); + if cgit["repo"] == "" then return 1 end + ispublic = public_repos[cgit["repo"]] -- accepted_users = protected_repos[cgit["repo"]] - if public_repos[cgit["repo"]] then - -- We return as valid if the repo is not protected. + if ispublic == true then + -- We return as valid if the repo is public return 1 end - local username = validate_value("username", get_cookie(http["cookie"], "cgitauth")) - -- if username == nil or not accepted_users[username:lower()] then if username == nil then return 0 else @@ -136,11 +121,9 @@ end -- Prints the html for the login form. function body() - printenv("Body\n====\n"); - - html("

New login form!

"); - html("

But still don't contact me to gain access.

"); html("

Authentication Required

") + -- html("HTML = ") + -- html(tostring(cgit["repo"] == "")) html("
") @@ -237,6 +220,13 @@ 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 -- -- @@ -244,7 +234,38 @@ end -- -- -local crypto = require("crypto") +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) @@ -253,7 +274,7 @@ function validate_value(expected_field, cookie) local field = "" local expiration = 0 local salt = "" - local hmac = "" + local chmac = "" if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then return nil @@ -272,19 +293,19 @@ function validate_value(expected_field, cookie) elseif i == 3 then salt = component elseif i == 4 then - hmac = component + chmac = component else break end i = i + 1 end - if hmac == nil or hmac:len() == 0 then + if chmac == nil or chmac:len() == 0 then return nil end -- Lua hashes strings, so these comparisons are time invariant. - if hmac ~= crypto.hmac.digest("sha1", field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt, secret) then + if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then return nil end @@ -305,11 +326,11 @@ function secure_value(field, value, expiration) end local authstr = "" - local salt = crypto.hex(crypto.rand.bytes(16)) + local salt = tohex(rand.bytes(16)) value = url_encode(value) field = url_encode(field) authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt - authstr = authstr .. "|" .. crypto.hmac.digest("sha1", authstr, secret) + authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) return authstr end diff --git a/hugo-highlighting.sh b/hugo-highlighting.sh new file mode 100755 index 0000000..603b8ab --- /dev/null +++ b/hugo-highlighting.sh @@ -0,0 +1,138 @@ +#!/bin/bash +# This script can be used to implement syntax highlighting in the cgit +# tree-view by refering to this file with the source-filter or repo.source- +# filter options in cgitrc. +# +# This script requires a shell supporting the ${var##pattern} syntax. +# It is supported by at least dash and bash, however busybox environments +# might have to use an external call to sed instead. +# +# Note: the highlight command (http://www.andre-simon.de/) uses css for syntax +# 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/ +# +# table.blob .num { color:#2928ff; } +# table.blob .esc { color:#ff00ff; } +# table.blob .str { color:#ff0000; } +# table.blob .dstr { color:#818100; } +# table.blob .slc { color:#838183; font-style:italic; } +# table.blob .com { color:#838183; font-style:italic; } +# table.blob .dir { color:#008200; } +# table.blob .sym { color:#000000; } +# table.blob .kwa { color:#000000; font-weight:bold; } +# table.blob .kwb { color:#830000; } +# table.blob .kwc { color:#000000; font-weight:bold; } +# table.blob .kwd { color:#010181; } +# +# +# Style definition file generated by highlight 2.6.14, http://www.andre-simon.de/ +# +# body.hl { background-color:#ffffff; } +# pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:'Courier New';} +# .hl.num { color:#2928ff; } +# .hl.esc { color:#ff00ff; } +# .hl.str { color:#ff0000; } +# .hl.dstr { color:#818100; } +# .hl.slc { color:#838183; font-style:italic; } +# .hl.com { color:#838183; font-style:italic; } +# .hl.dir { color:#008200; } +# .hl.sym { color:#000000; } +# .hl.line { color:#555555; } +# .hl.mark { background-color:#ffffbb;} +# .hl.kwa { color:#000000; font-weight:bold; } +# .hl.kwb { color:#830000; } +# .hl.kwc { color:#000000; font-weight:bold; } +# .hl.kwd { color:#010181; } +# +# +# Style definition file generated by highlight 3.8, http://www.andre-simon.de/ +# +# body.hl { background-color:#e0eaee; } +# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New';} +# .hl.num { color:#b07e00; } +# .hl.esc { color:#ff00ff; } +# .hl.str { color:#bf0303; } +# .hl.pps { color:#818100; } +# .hl.slc { color:#838183; font-style:italic; } +# .hl.com { color:#838183; font-style:italic; } +# .hl.ppc { color:#008200; } +# .hl.opt { color:#000000; } +# .hl.lin { color:#555555; } +# .hl.kwa { color:#000000; font-weight:bold; } +# .hl.kwb { color:#0057ae; } +# .hl.kwc { color:#000000; font-weight:bold; } +# .hl.kwd { color:#010181; } +# +# +# Style definition file generated by highlight 3.13, http://www.andre-simon.de/ +# +# body.hl { background-color:#e0eaee; } +# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New',monospace;} +# .hl.num { color:#b07e00; } +# .hl.esc { color:#ff00ff; } +# .hl.str { color:#bf0303; } +# .hl.pps { color:#818100; } +# .hl.slc { color:#838183; font-style:italic; } +# .hl.com { color:#838183; font-style:italic; } +# .hl.ppc { color:#008200; } +# .hl.opt { color:#000000; } +# .hl.ipl { color:#0057ae; } +# .hl.lin { color:#555555; } +# .hl.kwa { color:#000000; font-weight:bold; } +# .hl.kwb { color:#0057ae; } +# .hl.kwc { color:#000000; font-weight:bold; } +# .hl.kwd { color:#010181; } +# +# +# The following environment variables can be used to retrieve the configuration +# of the repository for which this script is called: +# CGIT_REPO_URL ( = repo.url setting ) +# CGIT_REPO_NAME ( = repo.name setting ) +# CGIT_REPO_PATH ( = repo.path setting ) +# CGIT_REPO_OWNER ( = repo.owner setting ) +# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting ) +# CGIT_REPO_SECTION ( = section setting ) +# CGIT_REPO_CLONE_URL ( = repo.clone-url setting ) +# + +# store filename and extension in local vars +BASENAME="$1" +EXTENSION="${BASENAME##*.}" + +[ "${BASENAME}" = "${EXTENSION}" ] && EXTENSION=txt +[ -z "${EXTENSION}" ] && EXTENSION=txt + +# map Makefile and Makefile.* to .mk +[ "${BASENAME%%.*}" = "Makefile" ] && EXTENSION=mk + +# highlight versions 2 and 3 have different commandline options. Specifically, +# the -X option that is used for version 2 is replaced by the -O xhtml option +# for version 3. +# +# Version 2 can be found (for example) on EPEL 5, while version 3 can be +# found (for example) on EPEL 6. +# +# This is for version 2 +#exec highlight --force -f -I -X -S "$EXTENSION" 2>/dev/null + +# env + +extension=${REQUEST_URI: -3} + +case $extension in + org) + temp=$(mktemp) + cat - > $temp.org + emacs $temp.org \ + --quick \ + --batch \ + --funcall org-html-export-to-html \ + --kill + tail -n+10 $temp.html + exit 0 + ;; +esac + +exec highlight --force -f -I -O xhtml -S "$EXTENSION" # 2>/dev/null diff --git a/hugo-pre.sh b/hugo-pre.sh new file mode 100755 index 0000000..cd303ec --- /dev/null +++ b/hugo-pre.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +name=$1 + +extension=${name: -3} + +case $extension in + .md) pandoc -f gfm -t html ;; + *) + cat <<- EOF +
$(cat -)
+ EOF + ;; +esac + +prel_head="$(grep -Eo 'h=([-A-Za-z0-9.~_+]|%[A-Fa-f0-9]{2})*' <<< "$REQUEST_URI")" +if [ $? -eq 0 ]; then + head=$(cut -c 3- <<< "$prel_head") +else + head=$CGIT_REPO_DEFBRANCH +fi + +echo "
" +echo "
"
+cloc --git "$head" --quiet --md | pandoc -f gfm -t html
+echo "
" -- cgit v1.2.3