1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<#pragma once
#include "apactor.h"
#include "apbase.h"
#include "apobject.h"
#include "../types.h"
#include <QDateTime>
enum struct APActivityType {CREATE, ANNOUNCE, UNKNOWN};
struct APActivityFields {
QString by_actor;
QStringList to_actors;
QStringList cc_actors;
QString object_url; // maps to "id", represents the Activity, *not* the URL of the object it contains
QString published;
APObject* object; // will generally be a APPost or APReblog
StatusTypepre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */-- This script may be used with the auth-filter. Be sure to configure it as you wish.
--
-- Requirements:
-- luacrypto >= 0.3
-- <http://mkottman.github.io/luacrypto/>
--
--
--
-- 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 }
}
-- 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 = "secretpassword",
laurent = "s3cr3t",
bob = "ilikelua"
}
-- 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"
--
--
-- 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 password = users[post["username"]]
local redirect = validate_value(post["redirect"])
if redirect == nil then
not_found()
return 0
end
redirect_to(redirect)
-- 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
local username = secure_value(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(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(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
--
--
-- Cookie construction and validation helpers.
--
--
local crypto = require("crypto")
-- Returns value of cookie if cookie is valid. Otherwise returns nil.
function validate_value(cookie)
local i = 0
local value = ""
local expiration = 0
local salt = ""
local hmac = ""
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
value = component
elseif i == 1 then
expiration = tonumber(component)
if expiration == nil then
expiration = 0
end
elseif i == 2 then
salt = component
elseif i == 3 then
hmac = component
else
break
end
i = i + 1
end
if hmac == nil or hmac:len() == 0 then
return nil
end
-- Lua hashes strings, so these comparisons are time invariant.
if hmac ~= crypto.hmac.digest("sha1", value .. "|" .. tostring(expiration) .. "|" .. salt, secret) then
return nil
end
if expiration ~= 0 and expiration <= os.time() then
return nil
end
return url_decode(value)
end
function secure_value(value, expiration)
if value == nil or value:len() <= 0 then
return ""
end
local authstr = ""
local salt = crypto.hex(crypto.rand.bytes(16))
value = url_encode(value)
authstr = value .. "|" .. tostring(expiration) .. "|" .. salt
authstr = authstr .. "|" .. crypto.hmac.digest("sha1", authstr, secret)
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
|