Commit 1fbab5fe authored by Christian Schudt's avatar Christian Schudt

Fix XEP-0012 logic.

If a query has no 'to' attribute it should be treated on behalf of the sender.
It should not be treated as if it were targeted to the server (and return the server uptime).

The former logic also threw an UserNotFoundException, if the user queried itself, because the user was not on his own roster.
 I've fixed that in the canProbePresence method.

 Fixes issue OF-982
parent 25d492d4
...@@ -98,7 +98,7 @@ public interface PresenceManager { ...@@ -98,7 +98,7 @@ public interface PresenceManager {
* Returns true if the the prober is allowed to see the presence of the probee. * Returns true if the the prober is allowed to see the presence of the probee.
* *
* @param prober the user that is trying to probe the presence of another user. * @param prober the user that is trying to probe the presence of another user.
* @param probee the username of the uset that is being probed. * @param probee the username of the user that is being probed.
* @return true if the the prober is allowed to see the presence of the probee. * @return true if the the prober is allowed to see the presence of the probee.
* @throws UserNotFoundException If the probee does not exist in the local server or the prober * @throws UserNotFoundException If the probee does not exist in the local server or the prober
* is not present in the roster of the probee. * is not present in the roster of the probee.
......
...@@ -22,8 +22,6 @@ import org.jivesoftware.openfire.PresenceManager; ...@@ -22,8 +22,6 @@ import org.jivesoftware.openfire.PresenceManager;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.disco.ServerFeaturesProvider; import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.User; import org.jivesoftware.openfire.user.User;
import org.jivesoftware.openfire.user.UserManager; import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
...@@ -43,28 +41,29 @@ import java.util.Iterator; ...@@ -43,28 +41,29 @@ import java.util.Iterator;
*/ */
public class IQLastActivityHandler extends IQHandler implements ServerFeaturesProvider { public class IQLastActivityHandler extends IQHandler implements ServerFeaturesProvider {
private IQHandlerInfo info; private static final String NAMESPACE = "jabber:iq:last";
private final IQHandlerInfo info;
private PresenceManager presenceManager; private PresenceManager presenceManager;
private RosterManager rosterManager;
public IQLastActivityHandler() { public IQLastActivityHandler() {
super("XMPP Last Activity Handler"); super("XMPP Last Activity Handler");
info = new IQHandlerInfo("query", "jabber:iq:last"); info = new IQHandlerInfo("query", NAMESPACE);
} }
@Override @Override
public IQ handleIQ(IQ packet) throws UnauthorizedException { public IQ handleIQ(IQ packet) throws UnauthorizedException {
IQ reply = IQ.createResultIQ(packet); IQ reply = IQ.createResultIQ(packet);
Element lastActivity = reply.setChildElement("query", "jabber:iq:last"); Element lastActivity = reply.setChildElement("query", NAMESPACE);
String sender = packet.getFrom().getNode(); String sender = packet.getFrom().getNode();
String username = packet.getTo() == null ? null : packet.getTo().getNode();
// Check if any of the usernames is null // Check if any of the usernames is null
if (sender == null) { if (sender == null) {
reply.setError(PacketError.Condition.forbidden); reply.setError(PacketError.Condition.forbidden);
return reply; return reply;
} }
if (username == null) {
if (packet.getTo() != null && packet.getTo().getNode() == null && XMPPServer.getInstance().isLocal(packet.getTo())) {
// http://xmpp.org/extensions/xep-0012.html#server // http://xmpp.org/extensions/xep-0012.html#server
// When the last activity query is sent to a server or component (i.e., to a JID of the form <domain.tld>), // When the last activity query is sent to a server or component (i.e., to a JID of the form <domain.tld>),
// the information contained in the IQ reply reflects the uptime of the JID sending the reply. // the information contained in the IQ reply reflects the uptime of the JID sending the reply.
...@@ -75,34 +74,36 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr ...@@ -75,34 +74,36 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
return reply; return reply;
} }
// If the 'to' attribute is null, treat the IQ on behalf of the account from which received the stanza
// in accordance with RFC 6120 § 10.3.3.
String username = packet.getTo() == null ? packet.getFrom().getNode() : packet.getTo().getNode();
try { try {
RosterItem item = rosterManager.getRoster(username).getRosterItem(packet.getFrom()); if (username != null) {
// Check that the user requesting this information is subscribed to the user's presence // Check that the user requesting this information is subscribed to the user's presence
if (item.getSubStatus() == RosterItem.SUB_FROM || if (presenceManager.canProbePresence(packet.getFrom(), username)) {
item.getSubStatus() == RosterItem.SUB_BOTH) { if (sessionManager.getSessions(username).isEmpty()) {
if (sessionManager.getSessions(username).isEmpty()) { User user = UserManager.getInstance().getUser(username);
User user = UserManager.getInstance().getUser(username); // The user is offline so answer the user's "last available time and the
// The user is offline so answer the user's "last available time and the // status message of the last unavailable presence received from the user"
// status message of the last unavailable presence received from the user" long lastActivityTime = presenceManager.getLastActivity(user);
long lastActivityTime = presenceManager.getLastActivity(user); if (lastActivityTime > -1) {
if (lastActivityTime > -1) { // Convert it to seconds
// Convert it to seconds lastActivityTime = lastActivityTime / 1000;
lastActivityTime = lastActivityTime / 1000; }
lastActivity.addAttribute("seconds", String.valueOf(lastActivityTime));
String lastStatus = presenceManager.getLastPresenceStatus(user);
if (lastStatus != null && lastStatus.length() > 0) {
lastActivity.setText(lastStatus);
}
} else {
// The user is online so answer seconds=0
lastActivity.addAttribute("seconds", "0");
} }
lastActivity.addAttribute("seconds", String.valueOf(lastActivityTime)); } else {
String lastStatus = presenceManager.getLastPresenceStatus(user); reply.setError(PacketError.Condition.forbidden);
if (lastStatus != null && lastStatus.length() > 0) {
lastActivity.setText(lastStatus);
}
}
else {
// The user is online so answer seconds=0
lastActivity.addAttribute("seconds", "0");
} }
} }
else {
reply.setError(PacketError.Condition.forbidden);
}
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
reply.setError(PacketError.Condition.forbidden); reply.setError(PacketError.Condition.forbidden);
...@@ -117,13 +118,12 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr ...@@ -117,13 +118,12 @@ public class IQLastActivityHandler extends IQHandler implements ServerFeaturesPr
@Override @Override
public Iterator<String> getFeatures() { public Iterator<String> getFeatures() {
return Collections.singleton("jabber:iq:last").iterator(); return Collections.singleton(NAMESPACE).iterator();
} }
@Override @Override
public void initialize(XMPPServer server) { public void initialize(XMPPServer server) {
super.initialize(server); super.initialize(server);
presenceManager = server.getPresenceManager(); presenceManager = server.getPresenceManager();
rosterManager = server.getRosterManager();
} }
} }
\ No newline at end of file
...@@ -337,6 +337,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager, ...@@ -337,6 +337,9 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager,
@Override @Override
public boolean canProbePresence(JID prober, String probee) throws UserNotFoundException { public boolean canProbePresence(JID prober, String probee) throws UserNotFoundException {
if (probee.equals(prober.getNode()) && XMPPServer.getInstance().isLocal(prober)) {
return true;
}
RosterItem item = rosterManager.getRoster(probee).getRosterItem(prober); RosterItem item = rosterManager.getRoster(probee).getRosterItem(prober);
return item.getSubStatus() == RosterItem.SUB_FROM return item.getSubStatus() == RosterItem.SUB_FROM
|| item.getSubStatus() == RosterItem.SUB_BOTH; || item.getSubStatus() == RosterItem.SUB_BOTH;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment