plugins/mod_component.lua
changeset 7877 de3c6fb74759
parent 7669 03aa330562ed
parent 7876 8d1ebb9a9b44
child 7890 93fd15b5ec1b
equal deleted inserted replaced
7873:a858066faac6 7877:de3c6fb74759
    31 
    31 
    32 function module.add_host(module)
    32 function module.add_host(module)
    33 	if module:get_host_type() ~= "component" then
    33 	if module:get_host_type() ~= "component" then
    34 		error("Don't load mod_component manually, it should be for a component, please see https://prosody.im/doc/components", 0);
    34 		error("Don't load mod_component manually, it should be for a component, please see https://prosody.im/doc/components", 0);
    35 	end
    35 	end
    36 	
    36 
    37 	local env = module.environment;
    37 	local env = module.environment;
    38 	env.connected = false;
    38 	env.connected = false;
    39 	env.session = false;
    39 	env.session = false;
    40 
    40 
    41 	local send;
    41 	local send;
    44 		env.connected = false;
    44 		env.connected = false;
    45 		env.session = false;
    45 		env.session = false;
    46 		send = nil;
    46 		send = nil;
    47 		session.on_destroy = nil;
    47 		session.on_destroy = nil;
    48 	end
    48 	end
    49 	
    49 
    50 	-- Handle authentication attempts by component
    50 	-- Handle authentication attempts by component
    51 	local function handle_component_auth(event)
    51 	local function handle_component_auth(event)
    52 		local session, stanza = event.origin, event.stanza;
    52 		local session, stanza = event.origin, event.stanza;
    53 		
    53 
    54 		if session.type ~= "component_unauthed" then return; end
    54 		if session.type ~= "component_unauthed" then return; end
    55 	
    55 
    56 		if (not session.host) or #stanza.tags > 0 then
    56 		if (not session.host) or #stanza.tags > 0 then
    57 			(session.log or log)("warn", "Invalid component handshake for host: %s", session.host);
    57 			(session.log or log)("warn", "Invalid component handshake for host: %s", session.host);
    58 			session:close("not-authorized");
    58 			session:close("not-authorized");
    59 			return true;
    59 			return true;
    60 		end
    60 		end
    61 		
    61 
    62 		local secret = module:get_option("component_secret");
    62 		local secret = module:get_option("component_secret");
    63 		if not secret then
    63 		if not secret then
    64 			(session.log or log)("warn", "Component attempted to identify as %s, but component_secret is not set", session.host);
    64 			(session.log or log)("warn", "Component attempted to identify as %s, but component_secret is not set", session.host);
    65 			session:close("not-authorized");
    65 			session:close("not-authorized");
    66 			return true;
    66 			return true;
    67 		end
    67 		end
    68 		
    68 
    69 		local supplied_token = t_concat(stanza);
    69 		local supplied_token = t_concat(stanza);
    70 		local calculated_token = sha1(session.streamid..secret, true);
    70 		local calculated_token = sha1(session.streamid..secret, true);
    71 		if supplied_token:lower() ~= calculated_token:lower() then
    71 		if supplied_token:lower() ~= calculated_token:lower() then
    72 			module:log("info", "Component authentication failed for %s", session.host);
    72 			module:log("info", "Component authentication failed for %s", session.host);
    73 			session:close{ condition = "not-authorized", text = "Given token does not match calculated token" };
    73 			session:close{ condition = "not-authorized", text = "Given token does not match calculated token" };
    74 			return true;
    74 			return true;
    75 		end
    75 		end
    76 		
    76 
    77 		if env.connected then
    77 		if env.connected then
    78 			local policy = module:get_option_string("component_conflict_resolve", "kick_new");
    78 			local policy = module:get_option_string("component_conflict_resolve", "kick_new");
    79 			if policy == "kick_old" then
    79 			if policy == "kick_old" then
    80 				env.session:close{ condition = "conflict", text = "Replaced by a new connection" };
    80 				env.session:close{ condition = "conflict", text = "Replaced by a new connection" };
    81 			else -- kick_new
    81 			else -- kick_new
    82 				module:log("error", "Second component attempted to connect, denying connection");
    82 				module:log("error", "Second component attempted to connect, denying connection");
    83 				session:close{ condition = "conflict", text = "Component already connected" };
    83 				session:close{ condition = "conflict", text = "Component already connected" };
    84 				return true;
    84 				return true;
    85 			end
    85 			end
    86 		end
    86 		end
    87 		
    87 
    88 		env.connected = true;
    88 		env.connected = true;
    89 		env.session = session;
    89 		env.session = session;
    90 		send = session.send;
    90 		send = session.send;
    91 		session.on_destroy = on_destroy;
    91 		session.on_destroy = on_destroy;
    92 		session.component_validate_from = module:get_option_boolean("validate_from_addresses", true);
    92 		session.component_validate_from = module:get_option_boolean("validate_from_addresses", true);
    93 		session.type = "component";
    93 		session.type = "component";
    94 		module:log("info", "External component successfully authenticated");
    94 		module:log("info", "External component successfully authenticated");
    95 		session.send(st.stanza("handshake"));
    95 		session.send(st.stanza("handshake"));
    96 		module:fire_event("component-authenticated", { session = session });
    96 		module:fire_event("component-authenticated", { session = session });
    97 	
    97 
    98 		return true;
    98 		return true;
    99 	end
    99 	end
   100 	module:hook("stanza/jabber:component:accept:handshake", handle_component_auth, -1);
   100 	module:hook("stanza/jabber:component:accept:handshake", handle_component_auth, -1);
   101 
   101 
   102 	-- Handle stanzas addressed to this component
   102 	-- Handle stanzas addressed to this component
   123 				event.origin.send(st.error_reply(stanza, "wait", "service-unavailable", "Component unavailable"));
   123 				event.origin.send(st.error_reply(stanza, "wait", "service-unavailable", "Component unavailable"));
   124 			end
   124 			end
   125 		end
   125 		end
   126 		return true;
   126 		return true;
   127 	end
   127 	end
   128 	
   128 
   129 	module:hook("iq/bare", handle_stanza, -1);
   129 	module:hook("iq/bare", handle_stanza, -1);
   130 	module:hook("message/bare", handle_stanza, -1);
   130 	module:hook("message/bare", handle_stanza, -1);
   131 	module:hook("presence/bare", handle_stanza, -1);
   131 	module:hook("presence/bare", handle_stanza, -1);
   132 	module:hook("iq/full", handle_stanza, -1);
   132 	module:hook("iq/full", handle_stanza, -1);
   133 	module:hook("message/full", handle_stanza, -1);
   133 	module:hook("message/full", handle_stanza, -1);
   280 	session.close = session_close;
   280 	session.close = session_close;
   281 
   281 
   282 	if opt_keepalives then
   282 	if opt_keepalives then
   283 		conn:setoption("keepalive", opt_keepalives);
   283 		conn:setoption("keepalive", opt_keepalives);
   284 	end
   284 	end
   285 	
   285 
   286 	session.log("info", "Incoming Jabber component connection");
   286 	session.log("info", "Incoming Jabber component connection");
   287 	
   287 
   288 	local stream = new_xmpp_stream(session, stream_callbacks);
   288 	local stream = new_xmpp_stream(session, stream_callbacks);
   289 	session.stream = stream;
   289 	session.stream = stream;
   290 	
   290 
   291 	session.notopen = true;
   291 	session.notopen = true;
   292 	
   292 
   293 	function session.reset_stream()
   293 	function session.reset_stream()
   294 		session.notopen = true;
   294 		session.notopen = true;
   295 		session.stream:reset();
   295 		session.stream:reset();
   296 	end
   296 	end
   297 
   297 
   299 		local ok, err = stream:feed(data);
   299 		local ok, err = stream:feed(data);
   300 		if ok then return; end
   300 		if ok then return; end
   301 		module:log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"));
   301 		module:log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"));
   302 		session:close("not-well-formed");
   302 		session:close("not-well-formed");
   303 	end
   303 	end
   304 	
   304 
   305 	session.dispatch_stanza = stream_callbacks.handlestanza;
   305 	session.dispatch_stanza = stream_callbacks.handlestanza;
   306 
   306 
   307 	sessions[conn] = session;
   307 	sessions[conn] = session;
   308 end
   308 end
   309 function listener.onincoming(conn, data)
   309 function listener.onincoming(conn, data)