From e2e5c04ef7bbbe10598810a04a22dc928607cd0a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 8 Mar 2018 22:02:19 +0100 Subject: [PATCH] detect irregular unicode in domain part --- .../ui/ContactDetailsActivity.java | 4 +- .../conversations/ui/TrustKeysActivity.java | 8 +- .../ui/adapter/ListItemAdapter.java | 5 +- ...tor.java => IrregularUnicodeDetector.java} | 106 +++++++++++++----- 4 files changed, 84 insertions(+), 39 deletions(-) rename src/main/java/eu/siacs/conversations/utils/{IrregularUnicodeBlockDetector.java => IrregularUnicodeDetector.java} (69%) diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index f96574afa..5b5fa100f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -38,7 +38,7 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; -import eu.siacs.conversations.utils.IrregularUnicodeBlockDetector; +import eu.siacs.conversations.utils.IrregularUnicodeDetector; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xml.Namespace; @@ -384,7 +384,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp } } - binding.detailsContactjid.setText(IrregularUnicodeBlockDetector.style(this,contact.getJid())); + binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this,contact.getJid())); String account; if (Config.DOMAIN_LOCK != null) { account = contact.getAccount().getJid().getLocal(); diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index b37b7292b..77b8c7fef 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -10,16 +10,12 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; -import android.widget.Button; import android.widget.CompoundButton; -import android.widget.LinearLayout; -import android.widget.TextView; import android.widget.Toast; import org.whispersystems.libsignal.IdentityKey; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,7 +31,7 @@ import eu.siacs.conversations.databinding.KeysCardBinding; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.utils.CryptoHelper; -import eu.siacs.conversations.utils.IrregularUnicodeBlockDetector; +import eu.siacs.conversations.utils.IrregularUnicodeDetector; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import rocks.xmpp.addr.Jid; @@ -197,7 +193,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat hasForeignKeys = true; KeysCardBinding keysCardBinding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.keys_card, binding.foreignKeys,false); final Jid jid = entry.getKey(); - keysCardBinding.foreignKeysTitle.setText(IrregularUnicodeBlockDetector.style(this,jid)); + keysCardBinding.foreignKeysTitle.setText(IrregularUnicodeDetector.style(this,jid)); keysCardBinding.foreignKeysTitle.setOnClickListener(v -> switchToContactDetails(mAccount.getRoster().getContact(jid))); final Map fingerprints = entry.getValue(); for (final String fingerprint : fingerprints.keySet()) { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index b00cefbe9..4a9d3696a 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -26,9 +26,8 @@ import eu.siacs.conversations.databinding.ContactBinding; import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.ui.SettingsActivity; import eu.siacs.conversations.ui.XmppActivity; -import eu.siacs.conversations.ui.util.Color; import eu.siacs.conversations.utils.EmojiWrapper; -import eu.siacs.conversations.utils.IrregularUnicodeBlockDetector; +import eu.siacs.conversations.utils.IrregularUnicodeDetector; import eu.siacs.conversations.utils.UIHelper; import rocks.xmpp.addr.Jid; @@ -113,7 +112,7 @@ public class ListItemAdapter extends ArrayAdapter { final Jid jid = item.getJid(); if (jid != null) { viewHolder.jid.setVisibility(View.VISIBLE); - viewHolder.jid.setText(IrregularUnicodeBlockDetector.style(activity, jid)); + viewHolder.jid.setText(IrregularUnicodeDetector.style(activity, jid)); } else { viewHolder.jid.setVisibility(View.GONE); } diff --git a/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeBlockDetector.java b/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java similarity index 69% rename from src/main/java/eu/siacs/conversations/utils/IrregularUnicodeBlockDetector.java rename to src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java index a882896d3..5599358c9 100644 --- a/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeBlockDetector.java +++ b/src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java @@ -53,9 +53,10 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.ui.util.Color; import rocks.xmpp.addr.Jid; -public class IrregularUnicodeBlockDetector { +public class IrregularUnicodeDetector { private static final Map NORMALIZATION_MAP; + private static final LruCache CACHE = new LruCache<>(100); static { Map temp = new HashMap<>(); @@ -71,27 +72,31 @@ public class IrregularUnicodeBlockDetector { } } - private static final LruCache CACHE = new LruCache<>(100); - public static Spannable style(Context context, Jid jid) { return style(jid, Color.get(context, R.attr.color_warning)); } private static Spannable style(Jid jid, @ColorInt int color) { + PatternTuple patternTuple = find(jid); SpannableStringBuilder builder = new SpannableStringBuilder(); - if (jid.getLocal() != null) { + if (jid.getLocal() != null && patternTuple.local != null) { SpannableString local = new SpannableString(jid.getLocal()); - Matcher matcher = find(jid).matcher(local); - while (matcher.find()) { - if (matcher.start() < matcher.end()) { - local.setSpan(new ForegroundColorSpan(color), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } - } + colorize(local, patternTuple.local, color); builder.append(local); builder.append('@'); } if (jid.getDomain() != null) { - builder.append(jid.getDomain()); + int i = jid.getDomain().lastIndexOf('.'); + if (i != -1) { + String second = jid.getDomain().substring(0, i); + String top = jid.getDomain().substring(i, jid.getDomain().length()); + SpannableString secondSpannableString = new SpannableString(second); + colorize(secondSpannableString, patternTuple.domain, color); + builder.append(secondSpannableString); + builder.append(top); + } else { + builder.append(jid.getDomain()); + } } if (builder.length() != 0 && jid.getResource() != null) { builder.append('/'); @@ -100,12 +105,20 @@ public class IrregularUnicodeBlockDetector { return builder; } - private static Map> mapCompat(Jid jid) { + private static void colorize(SpannableString spannableString, Pattern pattern, @ColorInt int color) { + Matcher matcher = pattern.matcher(spannableString); + while (matcher.find()) { + if (matcher.start() < matcher.end()) { + spannableString.setSpan(new ForegroundColorSpan(color), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + + private static Map> mapCompat(String word) { Map> map = new HashMap<>(); - String local = jid.getLocal(); - final int length = local.length(); + final int length = word.length(); for (int offset = 0; offset < length; ) { - final int codePoint = local.codePointAt(offset); + final int codePoint = word.codePointAt(offset); Character.UnicodeBlock block = normalize(Character.UnicodeBlock.of(codePoint)); List codePoints; if (map.containsKey(block)) { @@ -121,12 +134,11 @@ public class IrregularUnicodeBlockDetector { } @TargetApi(Build.VERSION_CODES.N) - private static Map> map(Jid jid) { + private static Map> map(String word) { Map> map = new HashMap<>(); - String local = jid.getLocal(); - final int length = local.length(); + final int length = word.length(); for (int offset = 0; offset < length; ) { - final int codePoint = local.codePointAt(offset); + final int codePoint = word.codePointAt(offset); Character.UnicodeScript script = Character.UnicodeScript.of(codePoint); if (script != Character.UnicodeScript.COMMON) { List codePoints; @@ -169,19 +181,24 @@ public class IrregularUnicodeBlockDetector { return all; } - private static Pattern find(Jid jid) { + private static Set findIrregularCodePoints(String word) { + Set codePoints; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + codePoints = eliminateFirstAndGetCodePointsCompat(mapCompat(word)); + } else { + codePoints = eliminateFirstAndGetCodePoints(map(word)); + } + return codePoints; + } + + private static PatternTuple find(Jid jid) { synchronized (CACHE) { - Pattern pattern = CACHE.get(jid); + PatternTuple pattern = CACHE.get(jid); if (pattern != null) { return pattern; } - Set codePoints; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - codePoints = eliminateFirstAndGetCodePointsCompat(mapCompat(jid)); - } else { - codePoints = eliminateFirstAndGetCodePoints(map(jid)); - } - pattern = create(codePoints); + ; + pattern = PatternTuple.of(jid); CACHE.put(jid, pattern); return pattern; } @@ -197,4 +214,37 @@ public class IrregularUnicodeBlockDetector { } return Pattern.compile(pattern.toString()); } + + private static class PatternTuple { + private final Pattern local; + private final Pattern domain; + + private PatternTuple(Pattern local, Pattern domain) { + this.local = local; + this.domain = domain; + } + + private static PatternTuple of(Jid jid) { + final Pattern localPattern; + if (jid.getLocal() != null) { + localPattern = create(findIrregularCodePoints(jid.getLocal())); + } else { + localPattern = null; + } + String domain = jid.getDomain(); + final Pattern domainPattern; + if (domain != null) { + int i = domain.lastIndexOf('.'); + if (i != -1) { + String secondLevel = domain.substring(0, i); + domainPattern = create(findIrregularCodePoints(secondLevel)); + } else { + domainPattern = null; + } + } else { + domainPattern = null; + } + return new PatternTuple(localPattern, domainPattern); + } + } }