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.
sip-call-params
Ingo Bauersachs 10 years ago
parent e575cdb49d
commit 6fa91bd6cb

@ -902,6 +902,12 @@ impl.ldap.HOMEPHONE_FIELD_EXAMPLE=homePhone
impl.ldap.PHONE_PREFIX=Phone prefix
impl.ldap.PHONE_PREFIX_EXAMPLE=Ex.: 00
# SIP Protocol
impl.protocol.sip.INVALID_ADDRESS=''{0}'' is not a valid SIP address.
#Jabber Protocol
impl.protocol.jabber.INVALID_ADDRESS=''{0}'' is not a valid XMPP JID.
# Address book plugin
plugin.addrbook.ADDRESS_BOOKS=Address book
plugin.addrbook.ENABLE_MACOSX_ADDRESSBOOK=Enable MacOSX Address Book search

@ -21,10 +21,13 @@
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 void actionPerformed(ActionEvent e)
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(

@ -2039,6 +2039,93 @@ public AccountID getAccountID()
return accountID;
}
/**
* 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

@ -293,6 +293,15 @@ public AccountID getAccountID()
return accountID;
}
/**
* 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.

@ -245,6 +245,72 @@ public AccountID getAccountID()
return accountID;
}
/**
* 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 Address parseAddressString(String uriStr)
//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();
}

@ -244,6 +244,19 @@ public String getProtocolDisplayName()
return (displayName == null) ? getProtocolName() : displayName;
}
/**
* 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

@ -217,6 +217,23 @@ public void removeRegistrationStateChangeListener(
*/
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.

Loading…
Cancel
Save