aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
diff options
context:
space:
mode:
authorAndreas Straub <andy@strb.org>2015-07-20 15:13:14 +0200
committerAndreas Straub <andy@strb.org>2015-07-20 15:13:14 +0200
commitaaa8fe8978ac0513a013a9c77efef663f32eda47 (patch)
tree16cc60f67a4fbded2eeeb7ba1001ebb1b1a004a5 /src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
parent9c91b9036aa57c610c26b4cdf52ee295eaa0dc95 (diff)
parent19a0ae42d667644ee3400c92c53ad0ad093c52fe (diff)
Merge branch 'CryptoNextBeta' into development
* CryptoNextBeta: (60 commits) Lock TrustKeys if no trusted keys are available Optimize imports Use MD style for key trust toggle switch Fix set/remove OnUpdateBlocklistListener Fix axolotl database migration Remove device list from EditAccount Add clear devices to overflow menu in EditAccount Ask for key trust when sending messages Encrypt files for HTTP upload in encrypted chats Refactor trust key ui and show in account details Send correct body for HTTP files Handle file transmission properly in axolotl Remove unneccessary code Fix trust status for outgoing messages Don't merge messages with different trust statuses Fix copying of axolotl keys to clipboard Add refresh icon to v21 theme Disable Axolotl option if not usable Show trust status of messages' originating session Add key trust toggle to ContactDetailsActivity ...
Diffstat (limited to 'src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java')
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java510
1 files changed, 494 insertions, 16 deletions
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index d11b02fa..71b4cba9 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -1,10 +1,32 @@
package eu.siacs.conversations.persistance;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteCantOpenDatabaseException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Base64;
+import android.util.Log;
+
+import org.whispersystems.libaxolotl.AxolotlAddress;
+import org.whispersystems.libaxolotl.IdentityKey;
+import org.whispersystems.libaxolotl.IdentityKeyPair;
+import org.whispersystems.libaxolotl.InvalidKeyException;
+import org.whispersystems.libaxolotl.state.PreKeyRecord;
+import org.whispersystems.libaxolotl.state.SessionRecord;
+import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
+
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
@@ -13,19 +35,12 @@ import eu.siacs.conversations.entities.Roster;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteCantOpenDatabaseException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
-
public class DatabaseBackend extends SQLiteOpenHelper {
private static DatabaseBackend instance = null;
private static final String DATABASE_NAME = "history";
- private static final int DATABASE_VERSION = 14;
+ private static final int DATABASE_VERSION = 15;
private static String CREATE_CONTATCS_STATEMENT = "create table "
+ Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, "
@@ -33,12 +48,66 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Contact.JID + " TEXT," + Contact.KEYS + " TEXT,"
+ Contact.PHOTOURI + " TEXT," + Contact.OPTIONS + " NUMBER,"
+ Contact.SYSTEMACCOUNT + " NUMBER, " + Contact.AVATAR + " TEXT, "
- + Contact.LAST_PRESENCE + " TEXT, " + Contact.LAST_TIME + " NUMBER, "
+ + Contact.LAST_PRESENCE + " TEXT, " + Contact.LAST_TIME + " NUMBER, "
+ Contact.GROUPS + " TEXT, FOREIGN KEY(" + Contact.ACCOUNT + ") REFERENCES "
+ Account.TABLENAME + "(" + Account.UUID
+ ") ON DELETE CASCADE, UNIQUE(" + Contact.ACCOUNT + ", "
+ Contact.JID + ") ON CONFLICT REPLACE);";
+ private static String CREATE_PREKEYS_STATEMENT = "CREATE TABLE "
+ + AxolotlService.SQLiteAxolotlStore.PREKEY_TABLENAME + "("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.ID + " INTEGER, "
+ + AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT
+ + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
+ + "UNIQUE( " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + ", "
+ + AxolotlService.SQLiteAxolotlStore.ID
+ + ") ON CONFLICT REPLACE"
+ +");";
+
+ private static String CREATE_SIGNED_PREKEYS_STATEMENT = "CREATE TABLE "
+ + AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME + "("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.ID + " INTEGER, "
+ + AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT
+ + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
+ + "UNIQUE( " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + ", "
+ + AxolotlService.SQLiteAxolotlStore.ID
+ + ") ON CONFLICT REPLACE"+
+ ");";
+
+ private static String CREATE_SESSIONS_STATEMENT = "CREATE TABLE "
+ + AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME + "("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " INTEGER, "
+ + AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT
+ + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
+ + "UNIQUE( " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + ", "
+ + AxolotlService.SQLiteAxolotlStore.NAME + ", "
+ + AxolotlService.SQLiteAxolotlStore.DEVICE_ID
+ + ") ON CONFLICT REPLACE"
+ +");";
+
+ private static String CREATE_IDENTITIES_STATEMENT = "CREATE TABLE "
+ + AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME + "("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.OWN + " INTEGER, "
+ + AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " TEXT, "
+ + AxolotlService.SQLiteAxolotlStore.TRUSTED + " INTEGER, "
+ + AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
+ + AxolotlService.SQLiteAxolotlStore.ACCOUNT
+ + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
+ + "UNIQUE( " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + ", "
+ + AxolotlService.SQLiteAxolotlStore.NAME + ", "
+ + AxolotlService.SQLiteAxolotlStore.FINGERPRINT
+ + ") ON CONFLICT IGNORE"
+ +");";
+
private DatabaseBackend(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -69,12 +138,17 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Message.STATUS + " NUMBER," + Message.TYPE + " NUMBER, "
+ Message.RELATIVE_FILE_PATH + " TEXT, "
+ Message.SERVER_MSG_ID + " TEXT, "
+ + Message.FINGERPRINT + " TEXT, "
+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
+ Message.CONVERSATION + ") REFERENCES "
+ Conversation.TABLENAME + "(" + Conversation.UUID
+ ") ON DELETE CASCADE);");
db.execSQL(CREATE_CONTATCS_STATEMENT);
+ db.execSQL(CREATE_SESSIONS_STATEMENT);
+ db.execSQL(CREATE_PREKEYS_STATEMENT);
+ db.execSQL(CREATE_SIGNED_PREKEYS_STATEMENT);
+ db.execSQL(CREATE_IDENTITIES_STATEMENT);
}
@Override
@@ -109,12 +183,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN "
+ Conversation.ATTRIBUTES + " TEXT");
}
- if (oldVersion < 9 && newVersion >= 9) {
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
- + Contact.LAST_TIME + " NUMBER");
- db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
- + Contact.LAST_PRESENCE + " TEXT");
- }
+ if (oldVersion < 9 && newVersion >= 9) {
+ db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
+ + Contact.LAST_TIME + " NUMBER");
+ db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN "
+ + Contact.LAST_PRESENCE + " TEXT");
+ }
if (oldVersion < 10 && newVersion >= 10) {
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
+ Message.RELATIVE_FILE_PATH + " TEXT");
@@ -215,6 +289,11 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
cursor.close();
}
+ if (oldVersion < 15 && newVersion >= 15) {
+ recreateAxolotlDb(db);
+ db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
+ + Message.FINGERPRINT + " TEXT");
+ }
}
public static synchronized DatabaseBackend getInstance(Context context) {
@@ -311,7 +390,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
};
Cursor cursor = db.query(Conversation.TABLENAME, null,
Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID
- + " like ? OR "+Conversation.CONTACTJID+"=?)", selectionArgs, null, null, null);
+ + " like ? OR " + Conversation.CONTACTJID + "=?)", selectionArgs, null, null, null);
if (cursor.getCount() == 0)
return null;
cursor.moveToFirst();
@@ -481,4 +560,403 @@ public class DatabaseBackend extends SQLiteOpenHelper {
cursor.close();
return list;
}
+
+ private Cursor getCursorForSession(Account account, AxolotlAddress contact) {
+ final SQLiteDatabase db = this.getReadableDatabase();
+ String[] columns = null;
+ String[] selectionArgs = {account.getUuid(),
+ contact.getName(),
+ Integer.toString(contact.getDeviceId())};
+ Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME,
+ columns,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND "
+ + AxolotlService.SQLiteAxolotlStore.NAME + " = ? AND "
+ + AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " = ? ",
+ selectionArgs,
+ null, null, null);
+
+ return cursor;
+ }
+
+ public SessionRecord loadSession(Account account, AxolotlAddress contact) {
+ SessionRecord session = null;
+ Cursor cursor = getCursorForSession(account, contact);
+ if(cursor.getCount() != 0) {
+ cursor.moveToFirst();
+ try {
+ session = new SessionRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT));
+ } catch (IOException e) {
+ cursor.close();
+ throw new AssertionError(e);
+ }
+ }
+ cursor.close();
+ return session;
+ }
+
+ public List<Integer> getSubDeviceSessions(Account account, AxolotlAddress contact) {
+ List<Integer> devices = new ArrayList<>();
+ final SQLiteDatabase db = this.getReadableDatabase();
+ String[] columns = {AxolotlService.SQLiteAxolotlStore.DEVICE_ID};
+ String[] selectionArgs = {account.getUuid(),
+ contact.getName()};
+ Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME,
+ columns,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND "
+ + AxolotlService.SQLiteAxolotlStore.NAME + " = ?",
+ selectionArgs,
+ null, null, null);
+
+ while(cursor.moveToNext()) {
+ devices.add(cursor.getInt(
+ cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.DEVICE_ID)));
+ }
+
+ cursor.close();
+ return devices;
+ }
+
+ public boolean containsSession(Account account, AxolotlAddress contact) {
+ Cursor cursor = getCursorForSession(account, contact);
+ int count = cursor.getCount();
+ cursor.close();
+ return count != 0;
+ }
+
+ public void storeSession(Account account, AxolotlAddress contact, SessionRecord session) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(AxolotlService.SQLiteAxolotlStore.NAME, contact.getName());
+ values.put(AxolotlService.SQLiteAxolotlStore.DEVICE_ID, contact.getDeviceId());
+ values.put(AxolotlService.SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(),Base64.DEFAULT));
+ values.put(AxolotlService.SQLiteAxolotlStore.ACCOUNT, account.getUuid());
+ db.insert(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME, null, values);
+ }
+
+ public void deleteSession(Account account, AxolotlAddress contact) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] args = {account.getUuid(),
+ contact.getName(),
+ Integer.toString(contact.getDeviceId())};
+ db.delete(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND "
+ + AxolotlService.SQLiteAxolotlStore.NAME + " = ? AND "
+ + AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " = ? ",
+ args);
+ }
+
+ public void deleteAllSessions(Account account, AxolotlAddress contact) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] args = {account.getUuid(), contact.getName()};
+ db.delete(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + "=? AND "
+ + AxolotlService.SQLiteAxolotlStore.NAME + " = ?",
+ args);
+ }
+
+ private Cursor getCursorForPreKey(Account account, int preKeyId) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ String[] columns = {AxolotlService.SQLiteAxolotlStore.KEY};
+ String[] selectionArgs = {account.getUuid(), Integer.toString(preKeyId)};
+ Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.PREKEY_TABLENAME,
+ columns,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + "=? AND "
+ + AxolotlService.SQLiteAxolotlStore.ID + "=?",
+ selectionArgs,
+ null, null, null);
+
+ return cursor;
+ }
+
+ public PreKeyRecord loadPreKey(Account account, int preKeyId) {
+ PreKeyRecord record = null;
+ Cursor cursor = getCursorForPreKey(account, preKeyId);
+ if(cursor.getCount() != 0) {
+ cursor.moveToFirst();
+ try {
+ record = new PreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT));
+ } catch (IOException e ) {
+ throw new AssertionError(e);
+ }
+ }
+ cursor.close();
+ return record;
+ }
+
+ public boolean containsPreKey(Account account, int preKeyId) {
+ Cursor cursor = getCursorForPreKey(account, preKeyId);
+ int count = cursor.getCount();
+ cursor.close();
+ return count != 0;
+ }
+
+ public void storePreKey(Account account, PreKeyRecord record) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(AxolotlService.SQLiteAxolotlStore.ID, record.getId());
+ values.put(AxolotlService.SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(),Base64.DEFAULT));
+ values.put(AxolotlService.SQLiteAxolotlStore.ACCOUNT, account.getUuid());
+ db.insert(AxolotlService.SQLiteAxolotlStore.PREKEY_TABLENAME, null, values);
+ }
+
+ public void deletePreKey(Account account, int preKeyId) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] args = {account.getUuid(), Integer.toString(preKeyId)};
+ db.delete(AxolotlService.SQLiteAxolotlStore.PREKEY_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + "=? AND "
+ + AxolotlService.SQLiteAxolotlStore.ID + "=?",
+ args);
+ }
+
+ private Cursor getCursorForSignedPreKey(Account account, int signedPreKeyId) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ String[] columns = {AxolotlService.SQLiteAxolotlStore.KEY};
+ String[] selectionArgs = {account.getUuid(), Integer.toString(signedPreKeyId)};
+ Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ columns,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + "=? AND " + AxolotlService.SQLiteAxolotlStore.ID + "=?",
+ selectionArgs,
+ null, null, null);
+
+ return cursor;
+ }
+
+ public SignedPreKeyRecord loadSignedPreKey(Account account, int signedPreKeyId) {
+ SignedPreKeyRecord record = null;
+ Cursor cursor = getCursorForSignedPreKey(account, signedPreKeyId);
+ if(cursor.getCount() != 0) {
+ cursor.moveToFirst();
+ try {
+ record = new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT));
+ } catch (IOException e ) {
+ throw new AssertionError(e);
+ }
+ }
+ cursor.close();
+ return record;
+ }
+
+ public List<SignedPreKeyRecord> loadSignedPreKeys(Account account) {
+ List<SignedPreKeyRecord> prekeys = new ArrayList<>();
+ SQLiteDatabase db = this.getReadableDatabase();
+ String[] columns = {AxolotlService.SQLiteAxolotlStore.KEY};
+ String[] selectionArgs = {account.getUuid()};
+ Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ columns,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + "=?",
+ selectionArgs,
+ null, null, null);
+
+ while(cursor.moveToNext()) {
+ try {
+ prekeys.add(new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)), Base64.DEFAULT)));
+ } catch (IOException ignored) {
+ }
+ }
+ cursor.close();
+ return prekeys;
+ }
+
+ public boolean containsSignedPreKey(Account account, int signedPreKeyId) {
+ Cursor cursor = getCursorForPreKey(account, signedPreKeyId);
+ int count = cursor.getCount();
+ cursor.close();
+ return count != 0;
+ }
+
+ public void storeSignedPreKey(Account account, SignedPreKeyRecord record) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(AxolotlService.SQLiteAxolotlStore.ID, record.getId());
+ values.put(AxolotlService.SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(),Base64.DEFAULT));
+ values.put(AxolotlService.SQLiteAxolotlStore.ACCOUNT, account.getUuid());
+ db.insert(AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, null, values);
+ }
+
+ public void deleteSignedPreKey(Account account, int signedPreKeyId) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] args = {account.getUuid(), Integer.toString(signedPreKeyId)};
+ db.delete(AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + "=? AND "
+ + AxolotlService.SQLiteAxolotlStore.ID + "=?",
+ args);
+ }
+
+ private Cursor getIdentityKeyCursor(Account account, String name, boolean own) {
+ return getIdentityKeyCursor(account, name, own, null);
+ }
+
+ private Cursor getIdentityKeyCursor(Account account, String fingerprint) {
+ return getIdentityKeyCursor(account, null, null, fingerprint);
+ }
+
+ private Cursor getIdentityKeyCursor(Account account, String name, Boolean own, String fingerprint) {
+ final SQLiteDatabase db = this.getReadableDatabase();
+ String[] columns = {AxolotlService.SQLiteAxolotlStore.TRUSTED,
+ AxolotlService.SQLiteAxolotlStore.KEY};
+ ArrayList<String> selectionArgs = new ArrayList<>(4);
+ selectionArgs.add(account.getUuid());
+ String selectionString = AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?";
+ if (name != null){
+ selectionArgs.add(name);
+ selectionString += " AND " +AxolotlService.SQLiteAxolotlStore.NAME + " = ?";
+ }
+ if (fingerprint != null){
+ selectionArgs.add(fingerprint);
+ selectionString += " AND " +AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " = ?";
+ }
+ if (own != null){
+ selectionArgs.add(own?"1":"0");
+ selectionString += " AND " +AxolotlService.SQLiteAxolotlStore.OWN + " = ?";
+ }
+ Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ columns,
+ selectionString,
+ selectionArgs.toArray(new String[selectionArgs.size()]),
+ null, null, null);
+
+ return cursor;
+ }
+
+ public IdentityKeyPair loadOwnIdentityKeyPair(Account account, String name) {
+ IdentityKeyPair identityKeyPair = null;
+ Cursor cursor = getIdentityKeyCursor(account, name, true);
+ if(cursor.getCount() != 0) {
+ cursor.moveToFirst();
+ try {
+ identityKeyPair = new IdentityKeyPair(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT));
+ } catch (InvalidKeyException e) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Encountered invalid IdentityKey in database for account" + account.getJid().toBareJid() + ", address: " + name);
+ }
+ }
+ cursor.close();
+
+ return identityKeyPair;
+ }
+
+ public Set<IdentityKey> loadIdentityKeys(Account account, String name) {
+ return loadIdentityKeys(account, name, null);
+ }
+
+ public Set<IdentityKey> loadIdentityKeys(Account account, String name, AxolotlService.SQLiteAxolotlStore.Trust trust) {
+ Set<IdentityKey> identityKeys = new HashSet<>();
+ Cursor cursor = getIdentityKeyCursor(account, name, false);
+
+ while(cursor.moveToNext()) {
+ if ( trust != null &&
+ cursor.getInt(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.TRUSTED))
+ != trust.ordinal()) {
+ continue;
+ }
+ try {
+ identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.KEY)),Base64.DEFAULT),0));
+ } catch (InvalidKeyException e) {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Encountered invalid IdentityKey in database for account"+account.getJid().toBareJid()+", address: "+name);
+ }
+ }
+ cursor.close();
+
+ return identityKeys;
+ }
+
+ public long numTrustedKeys(Account account, String name) {
+ SQLiteDatabase db = getReadableDatabase();
+ String[] args = {
+ account.getUuid(),
+ name
+ };
+ return DatabaseUtils.queryNumEntries(db, AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?"
+ + " AND " + AxolotlService.SQLiteAxolotlStore.NAME + " = ?",
+ args
+ );
+ }
+
+ private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized) {
+ storeIdentityKey(account, name, own, fingerprint, base64Serialized, AxolotlService.SQLiteAxolotlStore.Trust.UNDECIDED);
+ }
+
+ private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized, AxolotlService.SQLiteAxolotlStore.Trust trusted) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(AxolotlService.SQLiteAxolotlStore.ACCOUNT, account.getUuid());
+ values.put(AxolotlService.SQLiteAxolotlStore.NAME, name);
+ values.put(AxolotlService.SQLiteAxolotlStore.OWN, own ? 1 : 0);
+ values.put(AxolotlService.SQLiteAxolotlStore.FINGERPRINT, fingerprint);
+ values.put(AxolotlService.SQLiteAxolotlStore.KEY, base64Serialized);
+ values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trusted.ordinal());
+ db.insert(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
+ }
+
+ public AxolotlService.SQLiteAxolotlStore.Trust isIdentityKeyTrusted(Account account, String fingerprint) {
+ Cursor cursor = getIdentityKeyCursor(account, fingerprint);
+ AxolotlService.SQLiteAxolotlStore.Trust trust = null;
+ if (cursor.getCount() > 0) {
+ cursor.moveToFirst();
+ int trustValue = cursor.getInt(cursor.getColumnIndex(AxolotlService.SQLiteAxolotlStore.TRUSTED));
+ trust = AxolotlService.SQLiteAxolotlStore.Trust.values()[trustValue];
+ }
+ cursor.close();
+ return trust;
+ }
+
+ public boolean setIdentityKeyTrust(Account account, String fingerprint, AxolotlService.SQLiteAxolotlStore.Trust trust) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] selectionArgs = {
+ account.getUuid(),
+ fingerprint
+ };
+ ContentValues values = new ContentValues();
+ values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trust.ordinal());
+ int rows = db.update(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, values,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND "
+ + AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " = ? ",
+ selectionArgs);
+ return rows == 1;
+ }
+
+ public void storeIdentityKey(Account account, String name, IdentityKey identityKey) {
+ storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
+ }
+
+ public void storeOwnIdentityKeyPair(Account account, String name, IdentityKeyPair identityKeyPair) {
+ storeIdentityKey(account, name, true, identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKeyPair.serialize(), Base64.DEFAULT), AxolotlService.SQLiteAxolotlStore.Trust.TRUSTED);
+ }
+
+ public void recreateAxolotlDb() {
+ recreateAxolotlDb(getWritableDatabase());
+ }
+
+ public void recreateAxolotlDb(SQLiteDatabase db) {
+ Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+">>> (RE)CREATING AXOLOTL DATABASE <<<");
+ db.execSQL("DROP TABLE IF EXISTS " + AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME);
+ db.execSQL(CREATE_SESSIONS_STATEMENT);
+ db.execSQL("DROP TABLE IF EXISTS " + AxolotlService.SQLiteAxolotlStore.PREKEY_TABLENAME);
+ db.execSQL(CREATE_PREKEYS_STATEMENT);
+ db.execSQL("DROP TABLE IF EXISTS " + AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME);
+ db.execSQL(CREATE_SIGNED_PREKEYS_STATEMENT);
+ db.execSQL("DROP TABLE IF EXISTS " + AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME);
+ db.execSQL(CREATE_IDENTITIES_STATEMENT);
+ }
+
+ public void wipeAxolotlDb(Account account) {
+ String accountName = account.getUuid();
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+">>> WIPING AXOLOTL DATABASE FOR ACCOUNT " + accountName + " <<<");
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[] deleteArgs= {
+ accountName
+ };
+ db.delete(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?",
+ deleteArgs);
+ db.delete(AxolotlService.SQLiteAxolotlStore.PREKEY_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?",
+ deleteArgs);
+ db.delete(AxolotlService.SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?",
+ deleteArgs);
+ db.delete(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME,
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ?",
+ deleteArgs);
+ }
}