aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIngo Bauersachs <ingo@jitsi.org>2016-05-15 20:33:26 +0200
committerIngo Bauersachs <ingo@jitsi.org>2016-05-17 21:41:16 +0200
commit6fa91bd6cb35dcdc89e32bb9e155f4d01ff1e5b4 (patch)
treeada7fb3a751be5e0ef4995ef836c675583a4e7ef /src
parente575cdb49da6ca61c0f51e0e68f04be6f5b087e0 (diff)
downloadjitsi-6fa91bd6cb35dcdc89e32bb9e155f4d01ff1e5b4.zip
jitsi-6fa91bd6cb35dcdc89e32bb9e155f4d01ff1e5b4.tar.gz
jitsi-6fa91bd6cb35dcdc89e32bb9e155f4d01ff1e5b4.tar.bz2
Validate protocol addresses before creating a contact
Instead of simply failing after clicking OK when adding a contact, validate the address/ID supplied by the user, show an error and attempt to correct it.
Diffstat (limited to 'src')
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java23
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java87
-rw-r--r--src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java89
-rw-r--r--src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java13
-rw-r--r--src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java17
6 files changed, 234 insertions, 4 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java
index 856ae5b..f92fbbe 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/AddContactDialog.java
@@ -21,10 +21,13 @@ import java.awt.*;
import java.awt.Container;
import java.awt.event.*;
import java.util.*;
+import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
+import org.jitsi.util.*;
+
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.contactlist.addgroup.*;
import net.java.sip.communicator.impl.gui.utils.*;
@@ -499,6 +502,26 @@ public class AddContactDialog
final String contactAddress = contactAddressField.getText().trim();
final String displayName = displayNameField.getText();
+ List<String> validationResult = new ArrayList<>(2);
+ if (!protocolProvider.validateContactAddress(contactAddress,
+ validationResult))
+ {
+ new ErrorDialog(GuiActivator.getUIService().getMainFrame(),
+ GuiActivator.getResources()
+ .getI18NString("service.gui.ADD_CONTACT_ERROR_TITLE"),
+ validationResult.get(0), ErrorDialog.WARNING).showDialog();
+ if (validationResult.size() >= 2)
+ {
+ contactAddressField.setText(validationResult.get(1));
+ if (StringUtils.isNullOrEmpty(displayName, true))
+ {
+ displayNameField.setText(contactAddress);
+ }
+ }
+
+ return;
+ }
+
if (!protocolProvider.isRegistered())
{
new ErrorDialog(
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index 425b70a..888c0aa 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -2040,6 +2040,93 @@ public class ProtocolProviderServiceJabberImpl
}
/**
+ * Validates the node part of a JID and returns an error message if
+ * applicable and a suggested correction.
+ *
+ * @param contactId the contact identifier to validate
+ * @param result Must be supplied as an empty a list. Implementors add
+ * items:
+ * <ol>
+ * <li>is the error message if applicable
+ * <li>a suggested correction. Index 1 is optional and can only
+ * be present if there was a validation failure.
+ * </ol>
+ * @return true if the contact id is valid, false otherwise
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ if (result == null)
+ {
+ throw new IllegalArgumentException("result must be an empty list");
+ }
+
+ result.clear();
+ try
+ {
+ contactId = contactId.trim();
+ if (contactId.length() == 0)
+ {
+ result.add(JabberActivator.getResources().getI18NString(
+ "impl.protocol.jabber.INVALID_ADDRESS", new String[]
+ { contactId }));
+ // no suggestion for an empty id
+ return false;
+ }
+
+ String user = contactId;
+ String remainder = "";
+ int at = contactId.indexOf('@');
+ if (at > -1)
+ {
+ user = contactId.substring(0, at);
+ remainder = contactId.substring(at);
+ }
+
+ // <conforming-char> ::= #x21 | [#x23-#x25] | [#x28-#x2E] |
+ // [#x30-#x39] | #x3B | #x3D | #x3F |
+ // [#x41-#x7E] | [#x80-#xD7FF] |
+ // [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+ boolean valid = true;
+ String suggestion = "";
+ for (char c : user.toCharArray())
+ {
+ if (!(c == 0x21 || (c >= 0x23 && c <= 0x25)
+ || (c >= 0x28 && c <= 0x2e) || (c >= 0x30 && c <= 0x39)
+ || c == 0x3b || c == 0x3d || c == 0x3f
+ || (c >= 0x41 && c <= 0x7e) || (c >= 0x80 && c <= 0xd7ff)
+ || (c >= 0xe000 && c <= 0xfffd)))
+ {
+ valid = false;
+ }
+ else
+ {
+ suggestion += c;
+ }
+ }
+
+ if (!valid)
+ {
+ result.add(JabberActivator.getResources().getI18NString(
+ "impl.protocol.jabber.INVALID_ADDRESS", new String[]
+ { contactId }));
+ result.add(suggestion + remainder);
+ return false;
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ result.add(JabberActivator.getResources().getI18NString(
+ "impl.protocol.jabber.INVALID_ADDRESS", new String[]
+ { contactId }));
+ }
+
+ return false;
+ }
+
+ /**
* Returns the <tt>XMPPConnection</tt>opened by this provider
* @return a reference to the <tt>XMPPConnection</tt> last opened by this
* provider.
diff --git a/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java b/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java
index bcff799..a7b6e5e 100644
--- a/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/mock/MockProvider.java
@@ -294,6 +294,15 @@ public class MockProvider
}
/**
+ * Always true.
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ return true;
+ }
+
+ /**
* Mock implementation of the corresponding ProtocolProviderService method.
* We have no icon corresponding to this protocol provider.
*/
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
index d0460fb..a978de8 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
@@ -246,6 +246,72 @@ public class ProtocolProviderServiceSipImpl
}
/**
+ * Validates the contact identifier and returns an error message if
+ * applicable and a suggested correction
+ *
+ * @param contactId the contact identifier to validate
+ * @param result Must be supplied as an empty a list. Implementors add
+ * items:
+ * <ol>
+ * <li>is the error message if applicable
+ * <li>a suggested correction. Index 1 is optional and can only
+ * be present if there was a validation failure.
+ * </ol>
+ * @return true if the contact id is valid, false otherwise
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ if (result == null)
+ {
+ throw new IllegalArgumentException("result must be an empty list");
+ }
+
+ result.clear();
+ try
+ {
+ Address address = parseAddressString(contactId);
+ if (address.toString().equals(contactId))
+ {
+ return true;
+ }
+ else if (((SipUri) address.getURI()).getUser().equals(contactId))
+ {
+ return true;
+ }
+ else
+ {
+ result.add(SipActivator.getResources().getI18NString(
+ "impl.protocol.sip.INVALID_ADDRESS", new String[]
+ { contactId }));
+ result.add(((SipUri) address.getURI()).getUser());
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.error("Validating SIP address failed for " + contactId, ex);
+ result.add(SipActivator.getResources()
+ .getI18NString("impl.protocol.sip.INVALID_ADDRESS", new String[]
+ { contactId }));
+
+ String user = contactId;
+ String remainder = "";
+ int at = contactId.indexOf('@');
+ if (at > -1)
+ {
+ user = contactId.substring(0, at);
+ remainder = contactId.substring(at);
+ }
+
+ // replace invalid characters in user part with hex encoding
+ String banned = "([^a-z0-9-_.!~*'()&=+$,;?/])+";
+ result.add(user.replaceAll(banned, "") + remainder);
+ }
+
+ return false;
+ }
+
+ /**
* Indicates whether or not this provider must registered
* when placing outgoing calls.
*
@@ -2390,21 +2456,36 @@ public class ProtocolProviderServiceSipImpl
//we don't know how to handle the "tel:" and "callto:" schemes ... or
// rather we handle them same as sip so replace:
if(uriStr.toLowerCase().startsWith("tel:"))
- uriStr = "sip:" + uriStr.substring("tel:".length());
+ uriStr = uriStr.substring("tel:".length());
else if(uriStr.toLowerCase().startsWith("callto:"))
- uriStr = "sip:" + uriStr.substring("callto:".length());
+ uriStr = uriStr.substring("callto:".length());
+ else if(uriStr.toLowerCase().startsWith("sips:"))
+ uriStr = uriStr.substring("sips:".length());
+
+ String user = uriStr;
+ String remainder = "";
+ int at = uriStr.indexOf('@');
+ if (at > -1)
+ {
+ user = uriStr.substring(0, at);
+ remainder = uriStr.substring(at);
+ }
+
+ //replace invalid characters in user part with hex encoding
+ String banned = "([^a-z0-9-_.!~*'()&=+$,;?/])+";
+ user = user.replaceAll(banned, "") + remainder;
//Handle default domain name (i.e. transform 1234 -> 1234@sip.com)
//assuming that if no domain name is specified then it should be the
//same as ours.
- if (uriStr.indexOf('@') == -1)
+ if (at == -1)
{
//if we have a registrar, then we could append its domain name as
//default
SipRegistrarConnection src = sipRegistrarConnection;
if(src != null && !src.isRegistrarless() )
{
- uriStr = uriStr + "@"
+ uriStr = user + "@"
+ ((SipURI)src.getAddressOfRecord().getURI()).getHost();
}
diff --git a/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java b/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java
index 9a78eec..897b74b 100644
--- a/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java
+++ b/src/net/java/sip/communicator/service/protocol/AbstractProtocolProviderService.java
@@ -245,6 +245,19 @@ public abstract class AbstractProtocolProviderService
}
/**
+ * Default implementation that always returns true.
+ *
+ * @param contactId ignored.
+ * @param result ignored
+ * @return true
+ */
+ @Override
+ public boolean validateContactAddress(String contactId, List<String> result)
+ {
+ return true;
+ }
+
+ /**
* Returns an array containing all operation sets supported by the current
* implementation. When querying this method users must be prepared to
* receive any subset of the OperationSet-s defined by this service. They
diff --git a/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java b/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java
index 15c5b8d..ffc356c 100644
--- a/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java
+++ b/src/net/java/sip/communicator/service/protocol/ProtocolProviderService.java
@@ -218,6 +218,23 @@ public interface ProtocolProviderService
public AccountID getAccountID();
/**
+ * Validates the given protocol specific contact identifier and returns an
+ * error message if applicable and a suggested correction.
+ *
+ * @param contactId the contact identifier to validate
+ * @param result Must be supplied as an empty a list. Implementors add
+ * items:
+ * <ol>
+ * <li>is the error message if applicable
+ * <li>a suggested correction. Index 1 is optional and can only
+ * be present if there was a validation failure.
+ * </ol>
+ * @return true if the contact id is valid, false otherwise
+ */
+ public boolean validateContactAddress(String contactId,
+ List<String> result);
+
+ /**
* Indicate if the signaling transport of this protocol instance uses a
* secure (e.g. via TLS) connection.
*