detect irregular unicode in domain part
This commit is contained in:
parent
7ae3bdd3c6
commit
e2e5c04ef7
|
@ -38,7 +38,7 @@ import eu.siacs.conversations.entities.Contact;
|
||||||
import eu.siacs.conversations.entities.ListItem;
|
import eu.siacs.conversations.entities.ListItem;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
|
import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
|
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.UIHelper;
|
||||||
import eu.siacs.conversations.utils.XmppUri;
|
import eu.siacs.conversations.utils.XmppUri;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
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;
|
String account;
|
||||||
if (Config.DOMAIN_LOCK != null) {
|
if (Config.DOMAIN_LOCK != null) {
|
||||||
account = contact.getAccount().getJid().getLocal();
|
account = contact.getAccount().getJid().getLocal();
|
||||||
|
|
|
@ -10,16 +10,12 @@ import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.Account;
|
||||||
import eu.siacs.conversations.entities.Conversation;
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
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.utils.XmppUri;
|
||||||
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
|
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
|
||||||
import rocks.xmpp.addr.Jid;
|
import rocks.xmpp.addr.Jid;
|
||||||
|
@ -197,7 +193,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
|
||||||
hasForeignKeys = true;
|
hasForeignKeys = true;
|
||||||
KeysCardBinding keysCardBinding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.keys_card, binding.foreignKeys,false);
|
KeysCardBinding keysCardBinding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.keys_card, binding.foreignKeys,false);
|
||||||
final Jid jid = entry.getKey();
|
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)));
|
keysCardBinding.foreignKeysTitle.setOnClickListener(v -> switchToContactDetails(mAccount.getRoster().getContact(jid)));
|
||||||
final Map<String, Boolean> fingerprints = entry.getValue();
|
final Map<String, Boolean> fingerprints = entry.getValue();
|
||||||
for (final String fingerprint : fingerprints.keySet()) {
|
for (final String fingerprint : fingerprints.keySet()) {
|
||||||
|
|
|
@ -26,9 +26,8 @@ import eu.siacs.conversations.databinding.ContactBinding;
|
||||||
import eu.siacs.conversations.entities.ListItem;
|
import eu.siacs.conversations.entities.ListItem;
|
||||||
import eu.siacs.conversations.ui.SettingsActivity;
|
import eu.siacs.conversations.ui.SettingsActivity;
|
||||||
import eu.siacs.conversations.ui.XmppActivity;
|
import eu.siacs.conversations.ui.XmppActivity;
|
||||||
import eu.siacs.conversations.ui.util.Color;
|
|
||||||
import eu.siacs.conversations.utils.EmojiWrapper;
|
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 eu.siacs.conversations.utils.UIHelper;
|
||||||
import rocks.xmpp.addr.Jid;
|
import rocks.xmpp.addr.Jid;
|
||||||
|
|
||||||
|
@ -113,7 +112,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
|
||||||
final Jid jid = item.getJid();
|
final Jid jid = item.getJid();
|
||||||
if (jid != null) {
|
if (jid != null) {
|
||||||
viewHolder.jid.setVisibility(View.VISIBLE);
|
viewHolder.jid.setVisibility(View.VISIBLE);
|
||||||
viewHolder.jid.setText(IrregularUnicodeBlockDetector.style(activity, jid));
|
viewHolder.jid.setText(IrregularUnicodeDetector.style(activity, jid));
|
||||||
} else {
|
} else {
|
||||||
viewHolder.jid.setVisibility(View.GONE);
|
viewHolder.jid.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,10 @@ import eu.siacs.conversations.R;
|
||||||
import eu.siacs.conversations.ui.util.Color;
|
import eu.siacs.conversations.ui.util.Color;
|
||||||
import rocks.xmpp.addr.Jid;
|
import rocks.xmpp.addr.Jid;
|
||||||
|
|
||||||
public class IrregularUnicodeBlockDetector {
|
public class IrregularUnicodeDetector {
|
||||||
|
|
||||||
private static final Map<Character.UnicodeBlock, Character.UnicodeBlock> NORMALIZATION_MAP;
|
private static final Map<Character.UnicodeBlock, Character.UnicodeBlock> NORMALIZATION_MAP;
|
||||||
|
private static final LruCache<Jid, PatternTuple> CACHE = new LruCache<>(100);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Map<Character.UnicodeBlock, Character.UnicodeBlock> temp = new HashMap<>();
|
Map<Character.UnicodeBlock, Character.UnicodeBlock> temp = new HashMap<>();
|
||||||
|
@ -71,28 +72,32 @@ public class IrregularUnicodeBlockDetector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final LruCache<Jid, Pattern> CACHE = new LruCache<>(100);
|
|
||||||
|
|
||||||
public static Spannable style(Context context, Jid jid) {
|
public static Spannable style(Context context, Jid jid) {
|
||||||
return style(jid, Color.get(context, R.attr.color_warning));
|
return style(jid, Color.get(context, R.attr.color_warning));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Spannable style(Jid jid, @ColorInt int color) {
|
private static Spannable style(Jid jid, @ColorInt int color) {
|
||||||
|
PatternTuple patternTuple = find(jid);
|
||||||
SpannableStringBuilder builder = new SpannableStringBuilder();
|
SpannableStringBuilder builder = new SpannableStringBuilder();
|
||||||
if (jid.getLocal() != null) {
|
if (jid.getLocal() != null && patternTuple.local != null) {
|
||||||
SpannableString local = new SpannableString(jid.getLocal());
|
SpannableString local = new SpannableString(jid.getLocal());
|
||||||
Matcher matcher = find(jid).matcher(local);
|
colorize(local, patternTuple.local, color);
|
||||||
while (matcher.find()) {
|
|
||||||
if (matcher.start() < matcher.end()) {
|
|
||||||
local.setSpan(new ForegroundColorSpan(color), matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.append(local);
|
builder.append(local);
|
||||||
builder.append('@');
|
builder.append('@');
|
||||||
}
|
}
|
||||||
if (jid.getDomain() != null) {
|
if (jid.getDomain() != null) {
|
||||||
|
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());
|
builder.append(jid.getDomain());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (builder.length() != 0 && jid.getResource() != null) {
|
if (builder.length() != 0 && jid.getResource() != null) {
|
||||||
builder.append('/');
|
builder.append('/');
|
||||||
builder.append(jid.getResource());
|
builder.append(jid.getResource());
|
||||||
|
@ -100,12 +105,20 @@ public class IrregularUnicodeBlockDetector {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<Character.UnicodeBlock, List<String>> 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<Character.UnicodeBlock, List<String>> mapCompat(String word) {
|
||||||
Map<Character.UnicodeBlock, List<String>> map = new HashMap<>();
|
Map<Character.UnicodeBlock, List<String>> map = new HashMap<>();
|
||||||
String local = jid.getLocal();
|
final int length = word.length();
|
||||||
final int length = local.length();
|
|
||||||
for (int offset = 0; offset < 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));
|
Character.UnicodeBlock block = normalize(Character.UnicodeBlock.of(codePoint));
|
||||||
List<String> codePoints;
|
List<String> codePoints;
|
||||||
if (map.containsKey(block)) {
|
if (map.containsKey(block)) {
|
||||||
|
@ -121,12 +134,11 @@ public class IrregularUnicodeBlockDetector {
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.N)
|
@TargetApi(Build.VERSION_CODES.N)
|
||||||
private static Map<Character.UnicodeScript, List<String>> map(Jid jid) {
|
private static Map<Character.UnicodeScript, List<String>> map(String word) {
|
||||||
Map<Character.UnicodeScript, List<String>> map = new HashMap<>();
|
Map<Character.UnicodeScript, List<String>> map = new HashMap<>();
|
||||||
String local = jid.getLocal();
|
final int length = word.length();
|
||||||
final int length = local.length();
|
|
||||||
for (int offset = 0; offset < 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);
|
Character.UnicodeScript script = Character.UnicodeScript.of(codePoint);
|
||||||
if (script != Character.UnicodeScript.COMMON) {
|
if (script != Character.UnicodeScript.COMMON) {
|
||||||
List<String> codePoints;
|
List<String> codePoints;
|
||||||
|
@ -169,19 +181,24 @@ public class IrregularUnicodeBlockDetector {
|
||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Pattern find(Jid jid) {
|
private static Set<String> findIrregularCodePoints(String word) {
|
||||||
|
Set<String> 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) {
|
synchronized (CACHE) {
|
||||||
Pattern pattern = CACHE.get(jid);
|
PatternTuple pattern = CACHE.get(jid);
|
||||||
if (pattern != null) {
|
if (pattern != null) {
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
Set<String> codePoints;
|
;
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
pattern = PatternTuple.of(jid);
|
||||||
codePoints = eliminateFirstAndGetCodePointsCompat(mapCompat(jid));
|
|
||||||
} else {
|
|
||||||
codePoints = eliminateFirstAndGetCodePoints(map(jid));
|
|
||||||
}
|
|
||||||
pattern = create(codePoints);
|
|
||||||
CACHE.put(jid, pattern);
|
CACHE.put(jid, pattern);
|
||||||
return pattern;
|
return pattern;
|
||||||
}
|
}
|
||||||
|
@ -197,4 +214,37 @@ public class IrregularUnicodeBlockDetector {
|
||||||
}
|
}
|
||||||
return Pattern.compile(pattern.toString());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue