1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-22 14:22:05 +01:00

Fix Carbon Listener setup

We can't always setup the carbons listener in the constructor of the
manager, as the our local XMPP address may not be available yet. So
setup the carbons listener on a connection listener *and* in the
constructor.
This commit is contained in:
Florian Schmaus 2017-02-01 10:59:44 +01:00
parent 872b254db5
commit 684d33b773

View file

@ -21,15 +21,15 @@ import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.ExceptionCallback;
import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.ExceptionCallback;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
@ -42,12 +42,13 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
import org.jivesoftware.smackx.carbons.packet.Carbon; import org.jivesoftware.smackx.carbons.packet.Carbon;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Direction; import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Direction;
import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Private; import org.jivesoftware.smackx.carbons.packet.CarbonExtension.Private;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.forward.packet.Forwarded; import org.jivesoftware.smackx.forward.packet.Forwarded;
import org.jxmpp.jid.EntityFullJid;
/** /**
* Manager for XEP-0280: Message Carbons. This class implements the manager for registering {@link CarbonExtension} * Manager for XEP-0280: Message Carbons. This class implements the manager for registering {@link CarbonExtension}
@ -92,28 +93,14 @@ public final class CarbonManager extends Manager {
private volatile boolean enabled_state = false; private volatile boolean enabled_state = false;
private final StanzaListener carbonsListener;
private CarbonManager(XMPPConnection connection) { private CarbonManager(XMPPConnection connection) {
super(connection); super(connection);
ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
sdm.addFeature(CarbonExtension.NAMESPACE); sdm.addFeature(CarbonExtension.NAMESPACE);
connection.addConnectionListener(new AbstractConnectionListener() {
@Override
public void connectionClosed() {
// Reset the state if the connection was cleanly closed. Note that this is not strictly necessary,
// because we also reset in authenticated() if the stream got not resumed, but for maximum correctness,
// also reset here.
enabled_state = false;
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
if (!resumed) {
// Non-resumed XMPP sessions always start with disabled carbons
enabled_state = false;
}
}
});
connection.addSyncStanzaListener(new StanzaListener() { carbonsListener = new StanzaListener() {
@Override @Override
public void processStanza(final Stanza stanza) throws NotConnectedException, InterruptedException { public void processStanza(final Stanza stanza) throws NotConnectedException, InterruptedException {
final Message wrappingMessage = (Message) stanza; final Message wrappingMessage = (Message) stanza;
@ -125,11 +112,45 @@ public final class CarbonManager extends Manager {
listener.onCarbonCopyReceived(direction, carbonCopy, wrappingMessage); listener.onCarbonCopyReceived(direction, carbonCopy, wrappingMessage);
} }
} }
// XEP-0280 § 11. Security Considerations "Any forwarded copies received by a Carbons-enabled client MUST be };
// from that user's bare JID; any copies that do not meet this requirement MUST be ignored." Otherwise, if
// those copies do not get ignored, malicious users may be able to impersonate other users. That is why the connection.addConnectionListener(new AbstractConnectionListener() {
// 'from' matcher is important here. @Override
}, new AndFilter(CARBON_EXTENSION_FILTER, FromMatchesFilter.createBare(connection.getUser()))); public void connectionClosed() {
// Reset the state if the connection was cleanly closed. Note that this is not strictly necessary,
// because we also reset in authenticated() if the stream got not resumed, but for maximum correctness,
// also reset here.
enabled_state = false;
boolean removed = connection().removeSyncStanzaListener(carbonsListener);
assert(removed);
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
if (!resumed) {
// Non-resumed XMPP sessions always start with disabled carbons
enabled_state = false;
}
addCarbonsListener(connection);
}
});
addCarbonsListener(connection);
}
private void addCarbonsListener(XMPPConnection connection) {
EntityFullJid localAddress = connection.getUser();
if (localAddress == null) {
// We where not connected yet and thus we don't know our XMPP address at the moment, which we need to match incoming
// carbons securely. Abort here. The ConnectionListener above will eventually setup the carbons listener.
return;
}
// XEP-0280 § 11. Security Considerations "Any forwarded copies received by a Carbons-enabled client MUST be
// from that user's bare JID; any copies that do not meet this requirement MUST be ignored." Otherwise, if
// those copies do not get ignored, malicious users may be able to impersonate other users. That is why the
// 'from' matcher is important here.
connection.addSyncStanzaListener(carbonsListener, new AndFilter(CARBON_EXTENSION_FILTER,
FromMatchesFilter.createBare(localAddress)));
} }
/** /**