From 15f898ca8068419fc02364231bb2981cc54971cb Mon Sep 17 00:00:00 2001 From: Leonardo Arena Date: Thu, 12 Jun 2014 07:56:57 +0000 Subject: testing/aaudit: move to main --- main/aaudit/aaudit-server.lua | 399 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 main/aaudit/aaudit-server.lua (limited to 'main/aaudit/aaudit-server.lua') diff --git a/main/aaudit/aaudit-server.lua b/main/aaudit/aaudit-server.lua new file mode 100644 index 0000000000..89f2fc0219 --- /dev/null +++ b/main/aaudit/aaudit-server.lua @@ -0,0 +1,399 @@ +local M = {} + +local posix = require 'posix' +local json = require 'cjson' +local zlib = require 'zlib' +local aac = require 'aaudit.common' +local smtp = require 'socket.smtp' + +local HOME = os.getenv("HOME") + +M.serverconfig = aac.readconfig(("%s/aaudit-server.json"):format(HOME)) or {} + +local function merge_bool(a, b) return a or b end +local function merge_array(a, b) if b then for i=1,#b do a[#a+1] = b[i] end end return a end + +local function match_file(fn, match_list) + if not match_list then return false end + local i, m + for i, pattern in ipairs(match_list) do + if posix.fnmatch(pattern, fn) then return true end + end + return false +end + +local function sortedpairs(t) + local i, keys, k = 0, {} + for k in pairs(t) do keys[#keys+1] = k end + table.sort(keys) + return function() + i = i + 1 + if keys[i] then return keys[i], t[keys[i]] end + end +end + +local function checksum_header(block) + local sum = 256 + for i = 1,148 do sum = sum + block:byte(i) end + for i = 157,500 do sum = sum + block:byte(i) end + return sum +end + +local function nullterm(s) return s:match("^[^%z]*") end +local function octal_to_number(str) return tonumber(nullterm(str), 8) end + +local function read_header_block(block) + local header = { + name = nullterm(block:sub(1,100)), + mode = octal_to_number(block:sub(101,108)), + uid = octal_to_number(block:sub(109,116)), + gid = octal_to_number(block:sub(117,124)), + size = octal_to_number(block:sub(125,136)), + mtime = octal_to_number(block:sub(137,148)), + chksum = octal_to_number(block:sub(149,156)), + typeflag = block:sub(157,157), + linkname = nullterm(block:sub(158,257)), + magic = block:sub(258,263), + version = block:sub(264,265), + uname = nullterm(block:sub(266,297)), + gname = nullterm(block:sub(298,329)), + devmajor = octal_to_number(block:sub(330,337)), + devminor = octal_to_number(block:sub(338,345)), + prefix = nullterm(block:sub(346,500)), + } + if header.magic ~= "ustar " and header.magic ~= "ustar\0" then + return false, "Invalid header magic "..header.magic + end + if header.version ~= "00" and header.version ~= " \0" then + return false, "Unknown version "..header.version + end + if not checksum_header(block) == header.chksum then + return false, "Failed header checksum" + end + return header +end + +local function rfc822_address(id) + local identities = M.serverconfig.identities + if id == nil then id = "_default" end + if identities and identities[id] then id = identities[id] end + local name, email = id:match("^(.-) *(<.*>)$") + if not email then return ("<%s>"):format(id) end + return ("%s %s"):format(name, email) +end + +local function rfc822_email(rfc822) + return rfc822:match("(<.*>)$") + +end + +function M.sendemail(mail) + local to = {} + local m = { + headers = { + ["Content-Type"] = 'text/plain; charset=utf8', + ["X-RT-Command"] = mail.rtheader, + from = rfc822_address(mail.from), + subject = mail.subject, + }, + body = mail.message, + } + local rcpt = {} + for _, addr in ipairs(mail.to) do + local rfc822 = rfc822_address(addr) + table.insert(to, rfc822) + table.insert(rcpt, rfc822_email(rfc822)) + end + m.headers.to = table.concat(to, ", ") + return smtp.send{ + from = rfc822_email(m.headers.from), + rcpt = rcpt, + source = smtp.message(m) + } +end + +local rt_keywords = { + fix = true, + fixes = true, + close = true, + closes = true, + ref = false, + refs = false, + rt = false, +} + +local function sendcommitdiff(body, req, R, G) + if not body then return end + if not G.notify_emails then return end + + local mail = { + from = req.committer, + to = G.notify_emails, + subject = ("config change - %s (%s)"):format(R.description, R.address), + message = table.concat(body, '\n') + } + + -- Set Request Tracker headers if relevant + local rtqueue = M.serverconfig.rtqueue + if rtqueue then + for k,no in req.message:gmatch("(%a+) #(%d+)") do + local action = rt_keywords[k] + if action ~= nil then + mail.subject = ("[%s #%s] %s"):format(rtqueue, no, mail.subject) + if action == true then + mail.rtheader = "Status: resolved" + end + break + end + end + end + + -- Send email + return M.sendemail(mail) +end + +local function import_tar(TAR, GIT, req, G) + local branch_ref = "refs/heads/import" + local from_ref = "refs/heads/master" + local blocksize = 512 + local nextmark = 1 + local author_time = 0 + local all_files = {} + local long_name, long_link_name + local symlinkmode = tonumber('0120000', 8) + local rwmode = tonumber('0755', 8) + local romode = tonumber('0644', 8) + local wandmode = tonumber('0111', 8) + + while true do + local block = TAR:read(blocksize) + if not block then return false, "Premature end of archive" end + if not block:match("[^%z]") then break end + + local header, err = read_header_block(block) + if not header then return false, err end + + local file_data = TAR:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) + if header.typeflag == "L" then + long_name = nullterm(file_data) + elseif header.typeflag == "K" then + long_link_name = nullterm(file_data) + else + if long_name then + header.name = long_name + long_name = nil + end + if long_link_name then + header.linkname = long_link_name + long_link_name = nil + end + end + + if header.name == "etc/aaudit/aaudit.json" then + local success, res = pcall(json.decode, file_data) + if success and res.contact then + local contact = res.contact + G.notify_emails = merge_array(G.notify_emails, {contact}) + if req.local_change then + req.author = rfc822_address(res.contact) + end + end + end + + if header.typeflag:match("^[0-46]$") and + not match_file(header.name, G.no_track) then + GIT:write('blob\n', 'mark :', nextmark, '\n') + if header.typeflag == "2" then + GIT:write('data ', tostring(#header.linkname), '\n', header.linkname, '\n') + header.mode = symlinkmode + else + GIT:write('data ', tostring(header.size), '\n', file_data, '\n') + end + local fn = header.prefix..header.name + all_files[fn] = { mark=nextmark, mode=header.mode, uname=header.uname, gname=header.gname } + nextmark = nextmark + 1 + if header.mtime > author_time then author_time = header.mtime end + end + end + if G.track_filemode then + GIT:write('blob\n', 'mark :', nextmark, '\n', + 'data <