mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-27 00:32:07 +01:00
1) SMACK-170 - Added JID escaping capabilities to SMACK.
2) Escaping form field values to prevent bad xml. git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@5363 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
parent
1df8baa6f7
commit
85781a7158
8 changed files with 83 additions and 35 deletions
|
@ -425,6 +425,7 @@ public class XMPPConnection {
|
||||||
}
|
}
|
||||||
// Do partial version of nameprep on the username.
|
// Do partial version of nameprep on the username.
|
||||||
username = username.toLowerCase().trim();
|
username = username.toLowerCase().trim();
|
||||||
|
username = StringUtils.escapeNode(username);
|
||||||
|
|
||||||
String response;
|
String response;
|
||||||
if (configuration.isSASLAuthenticationEnabled() &&
|
if (configuration.isSASLAuthenticationEnabled() &&
|
||||||
|
|
|
@ -112,7 +112,7 @@ public abstract class Packet {
|
||||||
* value has not been set.
|
* value has not been set.
|
||||||
*/
|
*/
|
||||||
public String getTo() {
|
public String getTo() {
|
||||||
return to;
|
return StringUtils.escapeJID(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,7 +134,7 @@ public abstract class Packet {
|
||||||
* valud has not been set.
|
* valud has not been set.
|
||||||
*/
|
*/
|
||||||
public String getFrom() {
|
public String getFrom() {
|
||||||
return from;
|
return StringUtils.escapeJID(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -198,7 +198,7 @@ public class RosterPacket extends IQ {
|
||||||
|
|
||||||
public String toXML() {
|
public String toXML() {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
buf.append("<item jid=\"").append(user).append("\"");
|
buf.append("<item jid=\"").append(StringUtils.escapeJID(user)).append("\"");
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
buf.append(" name=\"").append(StringUtils.escapeForXML(name)).append("\"");
|
buf.append(" name=\"").append(StringUtils.escapeForXML(name)).append("\"");
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class StringUtils {
|
||||||
if (XMPPAddress == null) {
|
if (XMPPAddress == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int atIndex = XMPPAddress.indexOf("@");
|
int atIndex = XMPPAddress.lastIndexOf("@");
|
||||||
if (atIndex <= 0) {
|
if (atIndex <= 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ public class StringUtils {
|
||||||
if (XMPPAddress == null) {
|
if (XMPPAddress == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int atIndex = XMPPAddress.indexOf("@");
|
int atIndex = XMPPAddress.lastIndexOf("@");
|
||||||
// If the String ends with '@', return the empty string.
|
// If the String ends with '@', return the empty string.
|
||||||
if (atIndex + 1 > XMPPAddress.length()) {
|
if (atIndex + 1 > XMPPAddress.length()) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -127,6 +127,8 @@ public class StringUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escapes the node portion of a JID according to "JID Escaping" (JEP-0106).
|
* Escapes the node portion of a JID according to "JID Escaping" (JEP-0106).
|
||||||
* Escaping replaces characters prohibited by node-prep with escape sequences,
|
* Escaping replaces characters prohibited by node-prep with escape sequences,
|
||||||
|
@ -166,15 +168,9 @@ public class StringUtils {
|
||||||
for (int i=0, n=node.length(); i<n; i++) {
|
for (int i=0, n=node.length(); i<n; i++) {
|
||||||
char c = node.charAt(i);
|
char c = node.charAt(i);
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"': buf.append("\\22"); break;
|
|
||||||
case '&': buf.append("\\26"); break;
|
|
||||||
case '\'': buf.append("\\27"); break;
|
|
||||||
case '/': buf.append("\\2f"); break;
|
|
||||||
case ':': buf.append("\\3a"); break;
|
|
||||||
case '<': buf.append("\\3c"); break;
|
|
||||||
case '>': buf.append("\\3e"); break;
|
|
||||||
case '@': buf.append("\\40"); break;
|
case '@': buf.append("\\40"); break;
|
||||||
case '\\': buf.append("\\5c"); break;
|
|
||||||
default: {
|
default: {
|
||||||
if (Character.isWhitespace(c)) {
|
if (Character.isWhitespace(c)) {
|
||||||
buf.append("\\20");
|
buf.append("\\20");
|
||||||
|
@ -188,6 +184,43 @@ public class StringUtils {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes a complete JID by examing the Node itself and escaping
|
||||||
|
* when neccessary.
|
||||||
|
* @param jid the users JID
|
||||||
|
* @return the escaped JID.
|
||||||
|
*/
|
||||||
|
public static String escapeJID(String jid){
|
||||||
|
if(jid == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
String node = parseName(jid);
|
||||||
|
String restOfJID = jid.substring(node.length());
|
||||||
|
builder.append(escapeNode(node));
|
||||||
|
builder.append(restOfJID);
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescapes a complete JID by examing the node itself and unescaping when necessary.
|
||||||
|
* @param jid the users jid.
|
||||||
|
* @return the unescaped JID.
|
||||||
|
*/
|
||||||
|
public static String unescapeJID(String jid){
|
||||||
|
if(jid == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
String node = parseName(jid);
|
||||||
|
String restOfJID = jid.substring(node.length());
|
||||||
|
builder.append(unescapeNode(node));
|
||||||
|
builder.append(restOfJID);
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Un-escapes the node portion of a JID according to "JID Escaping" (JEP-0106).<p>
|
* Un-escapes the node portion of a JID according to "JID Escaping" (JEP-0106).<p>
|
||||||
* Escaping replaces characters prohibited by node-prep with escape sequences,
|
* Escaping replaces characters prohibited by node-prep with escape sequences,
|
||||||
|
@ -308,7 +341,7 @@ public class StringUtils {
|
||||||
if (i > last) {
|
if (i > last) {
|
||||||
out.append(input, last, i - last);
|
out.append(input, last, i - last);
|
||||||
}
|
}
|
||||||
// Do nothing if the string is of the form ë (unicode value)
|
// Do nothing if the string is of the form ë (unicode value)
|
||||||
if (!(len > i + 5
|
if (!(len > i + 5
|
||||||
&& input[i + 1] == '#'
|
&& input[i + 1] == '#'
|
||||||
&& Character.isDigit(input[i + 2])
|
&& Character.isDigit(input[i + 2])
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
package org.jivesoftware.smackx;
|
package org.jivesoftware.smackx;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -288,7 +290,7 @@ public class FormField {
|
||||||
}
|
}
|
||||||
// Loop through all the values and append them to the string buffer
|
// Loop through all the values and append them to the string buffer
|
||||||
for (Iterator<String> i = getValues(); i.hasNext();) {
|
for (Iterator<String> i = getValues(); i.hasNext();) {
|
||||||
buf.append("<value>").append(i.next()).append("</value>");
|
buf.append("<value>").append(StringUtils.escapeForXML(i.next())).append("</value>");
|
||||||
}
|
}
|
||||||
// Loop through all the values and append them to the string buffer
|
// Loop through all the values and append them to the string buffer
|
||||||
for (Iterator i = getOptions(); i.hasNext();) {
|
for (Iterator i = getOptions(); i.hasNext();) {
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
package org.jivesoftware.smackx;
|
package org.jivesoftware.smackx;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,7 +102,7 @@ public class RemoteRosterEntry {
|
||||||
|
|
||||||
public String toXML() {
|
public String toXML() {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
buf.append("<item jid=\"").append(user).append("\"");
|
buf.append("<item jid=\"").append(StringUtils.escapeJID(user)).append("\"");
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
buf.append(" name=\"").append(name).append("\"");
|
buf.append(" name=\"").append(name).append("\"");
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
package org.jivesoftware.smackx.packet;
|
package org.jivesoftware.smackx.packet;
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.PacketExtension;
|
import org.jivesoftware.smack.packet.PacketExtension;
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents extended presence information about roles, affiliations, full JIDs,
|
* Represents extended presence information about roles, affiliations, full JIDs,
|
||||||
|
@ -130,7 +131,7 @@ public class MUCUser implements PacketExtension {
|
||||||
public Destroy getDestroy() {
|
public Destroy getDestroy() {
|
||||||
return destroy;
|
return destroy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the invitation for another user to a room. The sender of the invitation
|
* Sets the invitation for another user to a room. The sender of the invitation
|
||||||
* must be an occupant of the room. The invitation will be sent to the room which in turn
|
* must be an occupant of the room. The invitation will be sent to the room which in turn
|
||||||
|
@ -203,7 +204,7 @@ public class MUCUser implements PacketExtension {
|
||||||
private String reason;
|
private String reason;
|
||||||
private String from;
|
private String from;
|
||||||
private String to;
|
private String to;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bare JID of the inviter or, optionally, the room JID. (e.g.
|
* Returns the bare JID of the inviter or, optionally, the room JID. (e.g.
|
||||||
* 'crone1@shakespeare.lit/desktop').
|
* 'crone1@shakespeare.lit/desktop').
|
||||||
|
@ -288,7 +289,7 @@ public class MUCUser implements PacketExtension {
|
||||||
private String reason;
|
private String reason;
|
||||||
private String from;
|
private String from;
|
||||||
private String to;
|
private String to;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bare JID of the invitee that rejected the invitation. (e.g.
|
* Returns the bare JID of the invitee that rejected the invitation. (e.g.
|
||||||
* 'crone1@shakespeare.lit/desktop').
|
* 'crone1@shakespeare.lit/desktop').
|
||||||
|
@ -375,7 +376,7 @@ public class MUCUser implements PacketExtension {
|
||||||
private String jid;
|
private String jid;
|
||||||
private String nick;
|
private String nick;
|
||||||
private String role;
|
private String role;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new item child.
|
* Creates a new item child.
|
||||||
*
|
*
|
||||||
|
@ -386,7 +387,7 @@ public class MUCUser implements PacketExtension {
|
||||||
this.affiliation = affiliation;
|
this.affiliation = affiliation;
|
||||||
this.role = role;
|
this.role = role;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the actor (JID of an occupant in the room) that was kicked or banned.
|
* Returns the actor (JID of an occupant in the room) that was kicked or banned.
|
||||||
*
|
*
|
||||||
|
@ -496,7 +497,7 @@ public class MUCUser implements PacketExtension {
|
||||||
buf.append(" affiliation=\"").append(getAffiliation()).append("\"");
|
buf.append(" affiliation=\"").append(getAffiliation()).append("\"");
|
||||||
}
|
}
|
||||||
if (getJid() != null) {
|
if (getJid() != null) {
|
||||||
buf.append(" jid=\"").append(getJid()).append("\"");
|
buf.append(" jid=\"").append(StringUtils.escapeJID(getJid())).append("\"");
|
||||||
}
|
}
|
||||||
if (getNick() != null) {
|
if (getNick() != null) {
|
||||||
buf.append(" nick=\"").append(getNick()).append("\"");
|
buf.append(" nick=\"").append(getNick()).append("\"");
|
||||||
|
@ -513,7 +514,7 @@ public class MUCUser implements PacketExtension {
|
||||||
buf.append("<reason>").append(getReason()).append("</reason>");
|
buf.append("<reason>").append(getReason()).append("</reason>");
|
||||||
}
|
}
|
||||||
if (getActor() != null) {
|
if (getActor() != null) {
|
||||||
buf.append("<actor jid=\"").append(getActor()).append("\"/>");
|
buf.append("<actor jid=\"").append(StringUtils.escapeJID(getActor())).append("\"/>");
|
||||||
}
|
}
|
||||||
buf.append("</item>");
|
buf.append("</item>");
|
||||||
}
|
}
|
||||||
|
@ -528,7 +529,7 @@ public class MUCUser implements PacketExtension {
|
||||||
* @author Gaston Dombiak
|
* @author Gaston Dombiak
|
||||||
*/
|
*/
|
||||||
public static class Status {
|
public static class Status {
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of Status with the specified code.
|
* Creates a new instance of Status with the specified code.
|
||||||
|
@ -538,7 +539,7 @@ public class MUCUser implements PacketExtension {
|
||||||
public Status(String code) {
|
public Status(String code) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the code that uniquely identifies the reason of the error. The code
|
* Returns the code that uniquely identifies the reason of the error. The code
|
||||||
* assists in presenting notification messages.
|
* assists in presenting notification messages.
|
||||||
|
@ -566,8 +567,8 @@ public class MUCUser implements PacketExtension {
|
||||||
public static class Destroy {
|
public static class Destroy {
|
||||||
private String reason;
|
private String reason;
|
||||||
private String jid;
|
private String jid;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the JID of an alternate location since the current room is being destroyed.
|
* Returns the JID of an alternate location since the current room is being destroyed.
|
||||||
*
|
*
|
||||||
|
@ -608,7 +609,7 @@ public class MUCUser implements PacketExtension {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
buf.append("<destroy");
|
buf.append("<destroy");
|
||||||
if (getJid() != null) {
|
if (getJid() != null) {
|
||||||
buf.append(" jid=\"").append(getJid()).append("\"");
|
buf.append(" jid=\"").append(StringUtils.escapeJID(getJid())).append("\"");
|
||||||
}
|
}
|
||||||
if (getReason() == null) {
|
if (getReason() == null) {
|
||||||
buf.append("/>");
|
buf.append("/>");
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class UserSearchManager {
|
||||||
/**
|
/**
|
||||||
* Creates a new UserSearchManager.
|
* Creates a new UserSearchManager.
|
||||||
*
|
*
|
||||||
* @param con the XMPPConnection to use.
|
* @param con the XMPPConnection to use.
|
||||||
*/
|
*/
|
||||||
public UserSearchManager(XMPPConnection con) {
|
public UserSearchManager(XMPPConnection con) {
|
||||||
this.con = con;
|
this.con = con;
|
||||||
|
@ -71,7 +71,7 @@ public class UserSearchManager {
|
||||||
* Submits a search form to the server and returns the resulting information
|
* Submits a search form to the server and returns the resulting information
|
||||||
* in the form of <code>ReportedData</code>
|
* in the form of <code>ReportedData</code>
|
||||||
*
|
*
|
||||||
* @param searchForm the <code>Form</code> to submit for searching.
|
* @param searchForm the <code>Form</code> to submit for searching.
|
||||||
* @param searchService the name of the search service to use.
|
* @param searchService the name of the search service to use.
|
||||||
* @return the ReportedData returned by the server.
|
* @return the ReportedData returned by the server.
|
||||||
* @throws XMPPException thrown if a server error has occurred.
|
* @throws XMPPException thrown if a server error has occurred.
|
||||||
|
@ -88,18 +88,27 @@ public class UserSearchManager {
|
||||||
* @throws XMPPException thrown if a server error has occurred.
|
* @throws XMPPException thrown if a server error has occurred.
|
||||||
*/
|
*/
|
||||||
public Collection getSearchServices() throws XMPPException {
|
public Collection getSearchServices() throws XMPPException {
|
||||||
List searchServices = new ArrayList();
|
final List<String> searchServices = new ArrayList<String>();
|
||||||
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(con);
|
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(con);
|
||||||
DiscoverItems items = discoManager.discoverItems(con.getServiceName());
|
DiscoverItems items = discoManager.discoverItems(con.getServiceName());
|
||||||
for (Iterator it = items.getItems(); it.hasNext();) {
|
Iterator iter = items.getItems();
|
||||||
DiscoverItems.Item item = (DiscoverItems.Item) it.next();
|
while (iter.hasNext()) {
|
||||||
|
DiscoverItems.Item item = (DiscoverItems.Item) iter.next();
|
||||||
try {
|
try {
|
||||||
DiscoverInfo info = discoManager.discoverInfo(item.getEntityID());
|
DiscoverInfo info = null;
|
||||||
|
try {
|
||||||
|
info = discoManager.discoverInfo(item.getEntityID());
|
||||||
|
}
|
||||||
|
catch (XMPPException e) {
|
||||||
|
// Ignore Case
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (info.containsFeature("jabber:iq:search")) {
|
if (info.containsFeature("jabber:iq:search")) {
|
||||||
searchServices.add(item.getEntityID());
|
searchServices.add(item.getEntityID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (XMPPException e) {
|
catch (Exception e) {
|
||||||
// No info found.
|
// No info found.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue