diff --git a/README.md b/README.md index 963ad21..0721263 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,11 @@ on top of ActivityPub implementations. - write test suite - create install instructions +## Testing + +``` +luarocks-5.1 install --local luaunit +luarocks-5.1 install --local lrexlib-PCRE2 +eval (luarocks-5.1 path --bin) +lua5.1 test.lua +``` diff --git a/ctx.lua b/ctx.lua new file mode 100644 index 0000000..98ddcc8 --- /dev/null +++ b/ctx.lua @@ -0,0 +1,48 @@ +function log(msg) + ngx.log(ngx.STDERR, tostring(msg)) +end + +local ctx = {} + +function ctx:setWantedScripts(graph) + self._wanted_scripts = graph +end + +function ctx:loadChain() + self.compiled_chain = {} + for module_name, module_config in pairs(self._wanted_scripts) do + local module = require(module_name) + local module_state = module.init(module_config) + -- TODO is it possible to make module_config readonly? + table.insert(self.compiled_chain, {module, module_config, module_state}) + end +end + +function ctx:onRequest() + local request_uri = ngx.var.uri + + -- find out which modules to call based on their regexes + local callbacks_to_call = {} + for _, filter in ipairs(self.compiled_chain) do + local module, module_config, state = unpack(filter) + + for callback_regex, callback_function in pairs(module.callbacks) do + local match, error = ngx.re.match(request_uri, callback_regex) + if match then + table.insert(callbacks_to_call, {callback_function, module_config, state}) + end + end + end + + for _,tuple in ipairs(callbacks_to_call) do + local callback_function, config, state = unpack(tuple) + local status_code, body = callback_function(config, state) + if status_code ~= nil then + ngx.status = status_code + ngx.say(body or "request denied") + ngx.exit(status_code) + end + end +end + +return ctx diff --git a/main.lua b/main.lua index ed7677f..13ee4f7 100644 --- a/main.lua +++ b/main.lua @@ -7,38 +7,13 @@ local CONFIG_PATH = ".;/etc/aproxy" -- -- local config = loadConfig() -function log(msg) - ngx.log(ngx.STDERR, tostring(msg)) +local ctx = require('ctx') + +ctx:setWantedScripts({ + ['scripts.webfinger_allowlist'] = {accounts = {"example@example.com"}} +}) +ctx:loadChain() + +return function() + ctx:onRequest() end - -local WANTED_SCRIPTS = { - 'scripts.webfinger_allowlist' -} - -local compiled_chain = {} - -for _, module_name in pairs(WANTED_SCRIPTS) do - log('load module', module_name) - mod = require(module_name) - log('load module', mod) - table.insert(compiled_chain, mod) -end - -local function onRequest() - log('AWOOOOGA') - - for _,mod in ipairs(compiled_chain) do - log(mod) - local mod_config = {accounts = {"a@a.com"}} - local result, body = mod.callback(mod_config) - log(result) - log(body) - if not result then - ngx.status = 400 - ngx.say(body or "request denied") - ngx.exit(400) - end - end -end - -return onRequest diff --git a/scripts/webfinger_allowlist.lua b/scripts/webfinger_allowlist.lua index c036494..4575e7e 100644 --- a/scripts/webfinger_allowlist.lua +++ b/scripts/webfinger_allowlist.lua @@ -1,19 +1,23 @@ -function webfingerCallback(cfg) +function webfingerInit(cfg) + local accounts_set = {} + for _, account in ipairs(cfg.accounts) do + accounts_set["acct:" .. account] = true + end + return accounts_set +end + +function webfingerCallback(cfg, accounts_set) local args, err = ngx.req.get_uri_args() if err == "truncated" then - return false, 'uri args too long' + return 400, 'uri args too long' end local resource = args['resource'] - if resource ~= nil then - for _, account in ipairs(cfg.accounts) do - if resource == account then - return true - end - end + if accounts_set[resource] then + return nil + else + return 404, "Couldn't find user" end - - return false end return { @@ -27,7 +31,7 @@ return { Useful for small instances. ]], apiVersion=1, - callback=webfingerCallback, + init=webfingerInit, callbacks = { ['/.well-known/webfinger'] = webfingerCallback }, diff --git a/test.lua b/test.lua new file mode 100644 index 0000000..63d3a08 --- /dev/null +++ b/test.lua @@ -0,0 +1,77 @@ +lu = require('luaunit') +local rex = require('rex_pcre2') + +function createNgx() + local ngx = { + status = nil + } + + local function mockedThing(self, property) + return function(value) + self['_'..property] = value + end + end + + ngx.say = mockedThing(ngx, "say") + ngx.exit = mockedThing(ngx, "exit") + + ngx.log = function (_, msg) + print(msg) + end + + -- only hold data here + ngx.var = {} + + -- request params api + ngx.req = {} + + ngx.req.get_uri_args = function () + return ngx._uri_args + end + + ngx.req.set_uri_args = function (val) + ngx._uri_args = val + end + + -- regex api + ngx.re = {} + ngx.re.match = rex.match + ngx.re.search = rex.find + + return ngx +end + +function resetNgx() + ngx = createNgx() +end +teardownNgx = resetNgx + +function setupFakeRequest(path, options) + ngx.var.uri = path + if options.params then + ngx.req.set_uri_args(options.params) + end +end + +local ctx = require('ctx') +function setupTest(module_require_path, config) + resetNgx() + local module = require(module_require_path) + state = module.init(config) + ctx.compiled_chain = { + {module, config, state} + } + return module +end + + +function onRequest() + ctx:setWantedScripts() + local ctx = require('ctx') + do + ctx:onRequest() + end +end + +require('tests.webfinger_allowlist') +os.exit(lu.LuaUnit.run()) diff --git a/tests/webfinger_allowlist.lua b/tests/webfinger_allowlist.lua new file mode 100644 index 0000000..7999f43 --- /dev/null +++ b/tests/webfinger_allowlist.lua @@ -0,0 +1,23 @@ +TestWebfinger = {} + +function TestWebfinger:setup() + self.mod = setupTest('scripts.webfinger_allowlist', {accounts = {'correct@example.org'}}) +end + +local WEBFINGER_PATH = '/.well-known/webfinger' + +function TestWebfinger:testCorrectAccount() + setupFakeRequest(WEBFINGER_PATH, { params = {resource = 'acct:correct@example.org'} }) + onRequest() + lu.assertIs(ngx.status, nil) +end + +function TestWebfinger:testWrongAccount() + setupFakeRequest(WEBFINGER_PATH, { params = {resource = 'acct:wrong@example.org'} }) + onRequest() + lu.assertIs(ngx.status, 404) +end + +function TestWebfinger:teardown() + teardownNgx() +end