diff options
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java')
-rw-r--r-- | src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java new file mode 100644 index 00000000..433f1f4f --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jid/JidUtil.java @@ -0,0 +1,145 @@ +package de.thedevstack.conversationsplus.xmpp.jid; + +import android.util.LruCache; + +import net.java.otr4j.session.SessionID; + +import java.net.IDN; + +import gnu.inet.encoding.Stringprep; +import gnu.inet.encoding.StringprepException; + +/** + */ +public class JidUtil { + private static LruCache<String,Jid> cache = new LruCache<>(1024); + + public static Jid fromSessionID(final SessionID id) throws InvalidJidException { + if (id.getUserID().isEmpty()) { + return fromString(id.getAccountID()); + } else { + return fromString(id.getAccountID()+"/"+id.getUserID()); + } + } + + public static Jid fromString(final String jid) throws InvalidJidException { + return fromString(jid, false); + } + + public static Jid fromString(final String jid, final boolean safe) throws InvalidJidException { + if (jid == null) throw new InvalidJidException(InvalidJidException.IS_NULL); + + Jid fromCache = JidUtil.cache.get(jid); + if (fromCache != null) { + return fromCache; + } + + // Hackish Android way to count the number of chars in a string... should work everywhere. + final int atCount = jid.length() - jid.replace("@", "").length(); + final int slashCount = jid.length() - jid.replace("/", "").length(); + + // Throw an error if there's anything obvious wrong with the JID... + if (jid.isEmpty() || jid.length() > 3071) { + throw new InvalidJidException(InvalidJidException.INVALID_LENGTH); + } + + // Go ahead and check if the localpart or resourcepart is empty. + if (jid.startsWith("@") || (jid.endsWith("@") && slashCount == 0) || jid.startsWith("/") || (jid.endsWith("/") && slashCount < 2)) { + throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER); + } + + String finaljid; + String localpart; + String domainpart; + String resourcepart; + + final int domainpartStart; + final int atLoc = jid.indexOf("@"); + final int slashLoc = jid.indexOf("/"); + // If there is no "@" in the JID (eg. "example.net" or "example.net/resource") + // or there are one or more "@" signs but they're all in the resourcepart (eg. "example.net/@/rp@"): + if (atCount == 0 || (atCount > 0 && slashLoc != -1 && atLoc > slashLoc)) { + localpart = ""; + finaljid = ""; + domainpartStart = 0; + } else { + final String lp = jid.substring(0, atLoc); + try { + localpart = safe ? lp : Stringprep.nodeprep(lp); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + if (localpart.isEmpty() || localpart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + domainpartStart = atLoc + 1; + finaljid = lp + "@"; + } + + final String dp; + if (slashCount > 0) { + final String rp = jid.substring(slashLoc + 1, jid.length()); + try { + resourcepart = safe ? rp : Stringprep.resourceprep(rp); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + if (resourcepart.isEmpty() || resourcepart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + try { + dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, slashLoc)), IDN.USE_STD3_ASCII_RULES); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + finaljid = finaljid + dp + "/" + rp; + } else { + resourcepart = ""; + try{ + dp = IDN.toUnicode(Stringprep.nameprep(jid.substring(domainpartStart, jid.length())), IDN.USE_STD3_ASCII_RULES); + } catch (final StringprepException e) { + throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); + } + finaljid = finaljid + dp; + } + + // Remove trailing "." before storing the domain part. + if (dp.endsWith(".")) { + try { + domainpart = IDN.toASCII(dp.substring(0, dp.length() - 1), IDN.USE_STD3_ASCII_RULES); + } catch (final IllegalArgumentException e) { + throw new InvalidJidException(e); + } + } else { + try { + domainpart = IDN.toASCII(dp, IDN.USE_STD3_ASCII_RULES); + } catch (final IllegalArgumentException e) { + throw new InvalidJidException(e); + } + } + + // TODO: Find a proper domain validation library; validate individual parts, separators, etc. + if (domainpart.isEmpty() || domainpart.length() > 1023) { + throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); + } + + Jid createdJid = new Jid(finaljid, localpart, domainpart, resourcepart); + + JidUtil.cache.put(jid, createdJid); + + return createdJid; + } + + public static Jid fromParts(final String localpart, final String domainpart, final String resourcepart) throws InvalidJidException { + String out; + if (localpart == null || localpart.isEmpty()) { + out = domainpart; + } else { + out = localpart + "@" + domainpart; + } + if (resourcepart != null && !resourcepart.isEmpty()) { + out = out + "/" + resourcepart; + } + return JidUtil.fromString(out, false); + } +} |