-- cgit email-filter that puts a Libravatar icon next to an author name. Enable -- it with the email-filter or repo.email-filter setting and the lua: prefix, -- so it runs in cgit's embedded interpreter with no per-request process. The -- companion email-gravatar.lua is the same filter pointed at Gravatar instead. -- -- email-filter=lua:/path/to/email-libravatar.lua -- -- Runs on Lua 5.1, 5.2, 5.3, 5.4 and LuaJIT. Lua 5.5 is not supported, because -- luaossl has no 5.5 build. -- -- The one dependency is luaossl, the OpenSSL binding that provides -- openssl.digest, from . The reliable -- cross-platform install is LuaRocks, matched to the Lua version cgit is built -- against, and it needs the OpenSSL development headers present. -- -- # Debian and Ubuntu -- sudo apt install luarocks libssl-dev -- sudo luarocks --lua-version 5.1 install luaossl -- -- # Fedora -- sudo dnf install luarocks openssl-devel -- sudo luarocks --lua-version 5.1 install luaossl -- -- # macOS with Homebrew -- brew install luarocks openssl -- 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. 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. 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. local buffer = "" local avatar_hash = nil local function hash_hex(input) local raw = digest.new("md5"):final(input) local hex = "" for i = 1, #raw do hex = hex .. string.format("%.2x", string.byte(raw, i)) end return hex end -- cgit can hand over the address still wrapped in angle brackets, and the -- service hashes the trimmed lowercase form, so an address that skipped this -- would hash to something the service has never heard of. A missing or empty -- address becomes nil, which is how the caller knows to draw no icon. local function normalize_email(email) if email == nil then return nil end local inner = email:match("<(.*)>") if inner ~= nil then email = inner end email = (email:gsub("^%s*(.-)%s*$", "%1")):lower() if email == "" then return nil end return email end function filter_open(email, page) buffer = "" local address = normalize_email(email) if address == nil then avatar_hash = nil else avatar_hash = hash_hex(address) end end function filter_write(text) buffer = buffer .. text end -- A log page can carry one icon per commit, so the attributes let the -- browser defer the fetches for icons still off screen and keep decoding -- off the critical path. function filter_close() if avatar_hash == nil then html(buffer) else html("" .. alt_text ..
			" " .. buffer) end return 0 end