File

tools/openfire2prosody.lua @ 13126:d043834f15d2

mod_http: Use RFC 7239 Forwarded header to find original client IP Prefer over X-Forwarded-* since it has an actual specification. Main practical difference is that Forwarded may carry more properties than only the IP address since it is a structured header. Since we parse it into an array, it is easier to do the logical thing and iterate backwards trough proxies until an untrusted one is encountered. Compare the handling of X-Forwarded-For. The 'secure' field now accounts for the full chain of proxies, which must be secure all the way to be considered secure.
author Kim Alvefur <zash@zash.se>
date Sat, 03 Jun 2023 17:10:04 +0200
parent 5776:bd0ff8ae98a8
child 13142:879a6a33c21b
line wrap: on
line source

#!/usr/bin/env lua
-- Prosody IM
-- Copyright (C) 2008-2009 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--

package.path = package.path..";../?.lua";
package.cpath = package.cpath..";../?.so"; -- needed for util.pposix used in datamanager

local my_name = arg[0];
if my_name:match("[/\\]") then
	package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua");
	package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so");
end

-- ugly workaround for getting datamanager to work outside of prosody :(
prosody = { };
prosody.platform = "unknown";
if os.getenv("WINDIR") then
	prosody.platform = "windows";
elseif package.config:sub(1,1) == "/" then
	prosody.platform = "posix";
end

local parse_xml = require "util.xml".parse;

-----------------------------------------------------------------------

package.loaded["util.logger"] = {init = function() return function() end; end}
local dm = require "util.datamanager"
dm.set_data_path("data");

local arg = ...;
local help = "/? -? ? /h -h /help -help --help";
if not arg or help:find(arg, 1, true) then
	print([[Openfire importer for Prosody

  Usage: openfire2prosody.lua filename.xml hostname

]]);
	os.exit(1);
end

local host = select(2, ...) or "localhost";

local file = assert(io.open(arg));
local data = assert(file:read("*a"));
file:close();

local xml = assert(parse_xml(data));

assert(xml.name == "Openfire", "The input file is not an Openfire XML export");

local substatus_mapping = { ["0"] = "none", ["1"] = "to", ["2"] = "from", ["3"] = "both" };

for _,tag in ipairs(xml.tags) do
	if tag.name == "User" then
		local username, password, roster;

		for _,tag in ipairs(tag.tags) do
			if tag.name == "Username" then
				username = tag:get_text();
			elseif tag.name == "Password" then
				password = tag:get_text();
			elseif tag.name == "Roster" then
				roster = {};
				local pending = {};
				for _,tag in ipairs(tag.tags) do
					if tag.name == "Item" then
						local jid = assert(tag.attr.jid, "Roster item has no JID");
						if tag.attr.substatus ~= "-1" then
							local item = {};
							item.name = tag.attr.name;
							item.subscription = assert(substatus_mapping[tag.attr.substatus], "invalid substatus");
							item.ask = tag.attr.askstatus == "0" and "subscribe" or nil;

							local groups = {};
							for _,tag in ipairs(tag) do
								if tag.name == "Group" then
									groups[tag:get_text()] = true;
								end
							end
							item.groups = groups;
							roster[jid] = item;
						end
						if tag.attr.recvstatus == "1" then pending[jid] = true; end
					end
				end

				if next(pending) then
					roster[false] = { pending = pending };
				end
			end
		end

		assert(username and password, "No username or password");

		local ret, err = dm.store(username, host, "accounts", {password = password});
		print("["..(err or "success").."] stored account: "..username.."@"..host.." = "..password);

		if roster then
			local ret, err = dm.store(username, host, "roster", roster);
			print("["..(err or "success").."] stored roster: "..username.."@"..host.." = "..password);
		end
	end
end