aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs/conversations/utils')
-rw-r--r--src/main/java/eu/siacs/conversations/utils/CryptoHelper.java100
-rw-r--r--src/main/java/eu/siacs/conversations/utils/DNSHelper.java14
-rw-r--r--src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java2
-rw-r--r--src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java25
-rw-r--r--src/main/java/eu/siacs/conversations/utils/UIHelper.java38
-rw-r--r--src/main/java/eu/siacs/conversations/utils/XmppUri.java79
6 files changed, 146 insertions, 112 deletions
diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
index 47595c6e..b4a6e65c 100644
--- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java
@@ -1,20 +1,14 @@
package eu.siacs.conversations.utils;
-import java.math.BigInteger;
-import java.nio.charset.Charset;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-
-import eu.siacs.conversations.entities.Account;
-import android.util.Base64;
+import java.text.Normalizer;
public class CryptoHelper {
public static final String FILETRANSFER = "?FILETRANSFERv1:";
final protected static char[] hexArray = "0123456789abcdef".toCharArray();
final protected static char[] vowels = "aeiou".toCharArray();
- final protected static char[] consonants = "bcdfghjklmnpqrstvwxyz"
- .toCharArray();
+ final protected static char[] consonants = "bcdfghjklmnpqrstvwxyz".toCharArray();
+ final public static byte[] ONE = new byte[] { 0, 0, 0, 1 };
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
@@ -36,64 +30,17 @@ public class CryptoHelper {
return array;
}
- public static String saslPlain(String username, String password) {
- String sasl = '\u0000' + username + '\u0000' + password;
- return Base64.encodeToString(sasl.getBytes(Charset.defaultCharset()),
- Base64.NO_WRAP);
+ public static String hexToString(final String hexString) {
+ return new String(hexToBytes(hexString));
}
- private static byte[] concatenateByteArrays(byte[] a, byte[] b) {
+ public static byte[] concatenateByteArrays(byte[] a, byte[] b) {
byte[] result = new byte[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
- public static String saslDigestMd5(Account account, String challenge,
- SecureRandom random) {
- try {
- String[] challengeParts = new String(Base64.decode(challenge,
- Base64.DEFAULT)).split(",");
- String nonce = "";
- for (int i = 0; i < challengeParts.length; ++i) {
- String[] parts = challengeParts[i].split("=");
- if (parts[0].equals("nonce")) {
- nonce = parts[1].replace("\"", "");
- } else if (parts[0].equals("rspauth")) {
- return null;
- }
- }
- String digestUri = "xmpp/" + account.getServer();
- String nonceCount = "00000001";
- String x = account.getUsername() + ":" + account.getServer() + ":"
- + account.getPassword();
- MessageDigest md = MessageDigest.getInstance("MD5");
- byte[] y = md.digest(x.getBytes(Charset.defaultCharset()));
- String cNonce = new BigInteger(100, random).toString(32);
- byte[] a1 = concatenateByteArrays(y,
- (":" + nonce + ":" + cNonce).getBytes(Charset
- .defaultCharset()));
- String a2 = "AUTHENTICATE:" + digestUri;
- String ha1 = bytesToHex(md.digest(a1));
- String ha2 = bytesToHex(md.digest(a2.getBytes(Charset
- .defaultCharset())));
- String kd = ha1 + ":" + nonce + ":" + nonceCount + ":" + cNonce
- + ":auth:" + ha2;
- String response = bytesToHex(md.digest(kd.getBytes(Charset
- .defaultCharset())));
- String saslString = "username=\"" + account.getUsername()
- + "\",realm=\"" + account.getServer() + "\",nonce=\""
- + nonce + "\",cnonce=\"" + cNonce + "\",nc=" + nonceCount
- + ",qop=auth,digest-uri=\"" + digestUri + "\",response="
- + response + ",charset=utf-8";
- return Base64.encodeToString(
- saslString.getBytes(Charset.defaultCharset()),
- Base64.NO_WRAP);
- } catch (NoSuchAlgorithmException e) {
- return null;
- }
- }
-
public static String randomMucName(SecureRandom random) {
return randomWord(3, random) + "." + randomWord(7, random);
}
@@ -109,4 +56,39 @@ public class CryptoHelper {
}
return builder.toString();
}
+
+ /**
+ * Escapes usernames or passwords for SASL.
+ */
+ public static String saslEscape(final String s) {
+ final StringBuilder sb = new StringBuilder((int) (s.length() * 1.1));
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ switch (c) {
+ case ',':
+ sb.append("=2C");
+ break;
+ case '=':
+ sb.append("=3D");
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String saslPrep(final String s) {
+ return saslEscape(Normalizer.normalize(s, Normalizer.Form.NFKC));
+ }
+
+ public static String prettifyFingerprint(String fingerprint) {
+ StringBuilder builder = new StringBuilder(fingerprint);
+ builder.insert(8, " ");
+ builder.insert(17, " ");
+ builder.insert(26, " ");
+ builder.insert(35, " ");
+ return builder.toString();
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
index f101e883..8c1a8dea 100644
--- a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java
@@ -11,6 +11,7 @@ import de.measite.minidns.record.AAAA;
import de.measite.minidns.record.Data;
import de.measite.minidns.util.NameUtil;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.xmpp.jid.Jid;
import java.io.IOException;
import java.net.InetAddress;
@@ -26,7 +27,8 @@ import android.util.Log;
public class DNSHelper {
protected static Client client = new Client();
- public static Bundle getSRVRecord(String host) throws IOException {
+ public static Bundle getSRVRecord(final Jid jid) throws IOException {
+ final String host = jid.getDomainpart();
String dns[] = client.findDNS();
if (dns != null) {
@@ -62,9 +64,9 @@ public class DNSHelper {
// a random order respecting the weight, and dump that priority by
// priority
- TreeMap<Integer, ArrayList<SRV>> priorities = new TreeMap<Integer, ArrayList<SRV>>();
- TreeMap<String, ArrayList<String>> ips4 = new TreeMap<String, ArrayList<String>>();
- TreeMap<String, ArrayList<String>> ips6 = new TreeMap<String, ArrayList<String>>();
+ TreeMap<Integer, ArrayList<SRV>> priorities = new TreeMap<>();
+ TreeMap<String, ArrayList<String>> ips4 = new TreeMap<>();
+ TreeMap<String, ArrayList<String>> ips6 = new TreeMap<>();
for (Record[] rrset : new Record[][] { message.getAnswers(),
message.getAdditionalResourceRecords() }) {
@@ -97,7 +99,7 @@ public class DNSHelper {
}
Random rnd = new Random();
- ArrayList<SRV> result = new ArrayList<SRV>(
+ ArrayList<SRV> result = new ArrayList<>(
priorities.size() * 2 + 1);
for (ArrayList<SRV> s : priorities.values()) {
@@ -136,7 +138,7 @@ public class DNSHelper {
bundle.putString("error", "nosrv");
return bundle;
}
- ArrayList<Bundle> values = new ArrayList<Bundle>();
+ ArrayList<Bundle> values = new ArrayList<>();
for (SRV srv : result) {
Bundle namePort = new Bundle();
namePort.putString("name", srv.getName());
diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java
index 88fa18ff..0ad57fe2 100644
--- a/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java
+++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java
@@ -31,6 +31,8 @@ public class ExceptionHandler implements UncaughtExceptionHandler {
OutputStream os = context.openFileOutput("stacktrace.txt",
Context.MODE_PRIVATE);
os.write(stacktrace.getBytes());
+ os.flush();
+ os.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
index b5fc88bd..6f3152ca 100644
--- a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java
@@ -13,6 +13,9 @@ import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -87,12 +90,15 @@ public class ExceptionHelper {
public void onClick(DialogInterface dialog, int which) {
Log.d(Config.LOGTAG, "using account="
- + finalAccount.getJid()
+ + finalAccount.getJid().toBareJid()
+ " to send in stack trace");
- Conversation conversation = service
- .findOrCreateConversation(finalAccount,
- "bugs@siacs.eu", false);
- Message message = new Message(conversation, report
+ Conversation conversation = null;
+ try {
+ conversation = service.findOrCreateConversation(finalAccount,
+ Jid.fromString("bugs@siacs.eu"), false);
+ } catch (final InvalidJidException ignored) {
+ }
+ Message message = new Message(conversation, report
.toString(), Message.ENCRYPTION_NONE);
service.sendMessage(message);
}
@@ -103,15 +109,12 @@ public class ExceptionHelper {
@Override
public void onClick(DialogInterface dialog, int which) {
preferences.edit().putBoolean("never_send", true)
- .commit();
+ .apply();
}
});
builder.create().show();
- } catch (FileNotFoundException e) {
- return;
- } catch (IOException e) {
- return;
- }
+ } catch (final IOException ignored) {
+ }
}
}
diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
index 5141c83c..c4832d60 100644
--- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
@@ -110,7 +110,7 @@ public class UIHelper {
List<Account> accounts) {
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
- List<Account> accountsWproblems = new ArrayList<Account>();
+ List<Account> accountsWproblems = new ArrayList<>();
for (Account account : accounts) {
if (account.hasErrorStatus()) {
accountsWproblems.add(account);
@@ -124,7 +124,7 @@ public class UIHelper {
} else if (accountsWproblems.size() == 1) {
mBuilder.setContentTitle(context
.getString(R.string.problem_connecting_to_account));
- mBuilder.setContentText(accountsWproblems.get(0).getJid());
+ mBuilder.setContentText(accountsWproblems.get(0).getJid().toBareJid().toString());
} else {
mBuilder.setContentTitle(context
.getString(R.string.problem_connecting_to_accounts));
@@ -148,40 +148,6 @@ public class UIHelper {
mNotificationManager.notify(1111, notification);
}
- @SuppressLint("InflateParams")
- public static AlertDialog getVerifyFingerprintDialog(
- final ConversationActivity activity,
- final Conversation conversation, final View msg) {
- final Contact contact = conversation.getContact();
- final Account account = conversation.getAccount();
-
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- builder.setTitle("Verify fingerprint");
- LayoutInflater inflater = activity.getLayoutInflater();
- View view = inflater.inflate(R.layout.dialog_verify_otr, null);
- TextView jid = (TextView) view.findViewById(R.id.verify_otr_jid);
- TextView fingerprint = (TextView) view
- .findViewById(R.id.verify_otr_fingerprint);
- TextView yourprint = (TextView) view
- .findViewById(R.id.verify_otr_yourprint);
-
- jid.setText(contact.getJid());
- fingerprint.setText(conversation.getOtrFingerprint());
- yourprint.setText(account.getOtrFingerprint());
- builder.setNegativeButton("Cancel", null);
- builder.setPositiveButton("Verify", new OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- contact.addOtrFingerprint(conversation.getOtrFingerprint());
- msg.setVisibility(View.GONE);
- activity.xmppConnectionService.syncRosterToDisk(account);
- }
- });
- builder.setView(view);
- return builder.create();
- }
-
private final static class EmoticonPattern {
Pattern pattern;
String replacement;
diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java
new file mode 100644
index 00000000..09abd049
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java
@@ -0,0 +1,79 @@
+package eu.siacs.conversations.utils;
+
+import android.net.Uri;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+import eu.siacs.conversations.utils.CryptoHelper;
+import eu.siacs.conversations.xmpp.jid.InvalidJidException;
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public class XmppUri {
+
+ private String jid;
+ private boolean muc;
+ private String fingerprint;
+
+ public XmppUri(String uri) {
+ try {
+ parse(Uri.parse(uri));
+ } catch (IllegalArgumentException e) {
+ jid = null;
+ }
+ }
+
+ public XmppUri(Uri uri) {
+ parse(uri);
+ }
+
+ protected void parse(Uri uri) {
+ String scheme = uri.getScheme();
+ if ("xmpp".equals(scheme)) {
+ // sample: xmpp:jid@foo.com
+ muc = "join".equalsIgnoreCase(uri.getQuery());
+ if (uri.getAuthority() != null) {
+ jid = uri.getAuthority();
+ } else {
+ jid = uri.getSchemeSpecificPart().split("\\?")[0];
+ }
+ fingerprint = parseFingerprint(uri.getQuery());
+ } else if ("imto".equals(scheme)) {
+ // sample: imto://xmpp/jid@foo.com
+ try {
+ jid = URLDecoder.decode(uri.getEncodedPath(), "UTF-8").split("/")[1];
+ } catch (final UnsupportedEncodingException ignored) {
+ }
+ }
+ }
+
+ protected String parseFingerprint(String query) {
+ if (query == null) {
+ return null;
+ } else {
+ final String NEEDLE = "otr-fingerprint=";
+ int index = query.indexOf(NEEDLE);
+ if (index >= 0 && query.length() >= (NEEDLE.length() + index + 40)) {
+ return CryptoHelper.prettifyFingerprint(query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40));
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public Jid getJid() {
+ try {
+ return Jid.fromString(this.jid);
+ } catch (InvalidJidException e) {
+ return null;
+ }
+ }
+
+ public String getFingerprint() {
+ return this.fingerprint;
+ }
+
+ public boolean isMuc() {
+ return this.muc;
+ }
+}