Overhauled Message tagging

Messages are now tagged with the IdentityKey fingerprint of the
originating session. IdentityKeys have one of three trust states:
undecided (default), trusted, and untrusted/not yet trusted.
This commit is contained in:
Andreas Straub 2015-07-09 14:23:17 +02:00
parent 7f918542c8
commit d173913eba
5 changed files with 138 additions and 88 deletions

View file

@ -85,6 +85,7 @@ public class AxolotlService {
public static final String DEVICE_ID = "device_id"; public static final String DEVICE_ID = "device_id";
public static final String ID = "id"; public static final String ID = "id";
public static final String KEY = "key"; public static final String KEY = "key";
public static final String FINGERPRINT = "fingerprint";
public static final String NAME = "name"; public static final String NAME = "name";
public static final String TRUSTED = "trusted"; public static final String TRUSTED = "trusted";
public static final String OWN = "ownkey"; public static final String OWN = "ownkey";
@ -99,6 +100,23 @@ public class AxolotlService {
private final int localRegistrationId; private final int localRegistrationId;
private int currentPreKeyId = 0; private int currentPreKeyId = 0;
public enum Trust {
UNDECIDED, // 0
TRUSTED,
UNTRUSTED;
public String toString() {
switch(this){
case UNDECIDED:
return "Trust undecided";
case TRUSTED:
return "Trusted";
case UNTRUSTED:
default:
return "Untrusted";
}
}
};
private static IdentityKeyPair generateIdentityKeyPair() { private static IdentityKeyPair generateIdentityKeyPair() {
Log.i(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Generating axolotl IdentityKeyPair..."); Log.i(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Generating axolotl IdentityKeyPair...");
@ -242,11 +260,17 @@ public class AxolotlService {
*/ */
@Override @Override
public boolean isTrustedIdentity(String name, IdentityKey identityKey) { public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
//Set<IdentityKey> trustedKeys = mXmppConnectionService.databaseBackend.loadIdentityKeys(account, name);
//return trustedKeys.isEmpty() || trustedKeys.contains(identityKey);
return true; return true;
} }
public Trust getFingerprintTrust(String name, String fingerprint) {
return mXmppConnectionService.databaseBackend.isIdentityKeyTrusted(account, name, fingerprint);
}
public void setFingerprintTrust(String name, String fingerprint, Trust trust) {
mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, name, fingerprint, trust);
}
// -------------------------------------- // --------------------------------------
// SessionStore // SessionStore
// -------------------------------------- // --------------------------------------
@ -325,14 +349,6 @@ public class AxolotlService {
new AxolotlAddress(name, 0)); new AxolotlAddress(name, 0));
} }
public boolean isTrustedSession(AxolotlAddress address) {
return mXmppConnectionService.databaseBackend.isTrustedSession(this.account, address);
}
public void setTrustedSession(AxolotlAddress address, boolean trusted) {
mXmppConnectionService.databaseBackend.setTrustedSession(this.account, address, trusted);
}
// -------------------------------------- // --------------------------------------
// PreKeyStore // PreKeyStore
// -------------------------------------- // --------------------------------------
@ -453,27 +469,22 @@ public class AxolotlService {
public static class XmppAxolotlSession { public static class XmppAxolotlSession {
private final SessionCipher cipher; private final SessionCipher cipher;
private boolean isTrusted = false;
private Integer preKeyId = null; private Integer preKeyId = null;
private final SQLiteAxolotlStore sqLiteAxolotlStore; private final SQLiteAxolotlStore sqLiteAxolotlStore;
private final AxolotlAddress remoteAddress; private final AxolotlAddress remoteAddress;
private final Account account; private final Account account;
private String fingerprint = null;
public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress, String fingerprint) {
this(account, store, remoteAddress);
this.fingerprint = fingerprint;
}
public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress) { public XmppAxolotlSession(Account account, SQLiteAxolotlStore store, AxolotlAddress remoteAddress) {
this.cipher = new SessionCipher(store, remoteAddress); this.cipher = new SessionCipher(store, remoteAddress);
this.remoteAddress = remoteAddress; this.remoteAddress = remoteAddress;
this.sqLiteAxolotlStore = store; this.sqLiteAxolotlStore = store;
this.account = account; this.account = account;
this.isTrusted = sqLiteAxolotlStore.isTrustedSession(remoteAddress);
}
public void trust() {
sqLiteAxolotlStore.setTrustedSession(remoteAddress, true);
this.isTrusted = true;
}
public boolean isTrusted() {
return this.isTrusted;
} }
public Integer getPreKeyId() { public Integer getPreKeyId() {
@ -481,19 +492,30 @@ public class AxolotlService {
} }
public void resetPreKeyId() { public void resetPreKeyId() {
preKeyId = null; preKeyId = null;
} }
public String getFingerprint() {
return fingerprint;
}
public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) { public byte[] processReceiving(XmppAxolotlMessage.XmppAxolotlMessageHeader incomingHeader) {
byte[] plaintext = null; byte[] plaintext = null;
try { try {
try { try {
PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents()); PreKeyWhisperMessage message = new PreKeyWhisperMessage(incomingHeader.getContents());
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId()); Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"PreKeyWhisperMessage received, new session ID:" + message.getSignedPreKeyId() + "/" + message.getPreKeyId());
String fingerprint = message.getIdentityKey().getFingerprint().replaceAll("\\s", "");
if (this.fingerprint != null && !this.fingerprint.equals(fingerprint)) {
Log.e(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Had session with fingerprint "+ this.fingerprint+", received message with fingerprint "+fingerprint);
} else {
this.fingerprint = fingerprint;
plaintext = cipher.decrypt(message); plaintext = cipher.decrypt(message);
if (message.getPreKeyId().isPresent()) { if (message.getPreKeyId().isPresent()) {
preKeyId = message.getPreKeyId().get(); preKeyId = message.getPreKeyId().get();
} }
}
} catch (InvalidMessageException | InvalidVersionException e) { } catch (InvalidMessageException | InvalidVersionException e) {
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"WhisperMessage received"); Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"WhisperMessage received");
WhisperMessage message = new WhisperMessage(incomingHeader.getContents()); WhisperMessage message = new WhisperMessage(incomingHeader.getContents());
@ -582,7 +604,9 @@ public class AxolotlService {
List<Integer> deviceIDs = store.getSubDeviceSessions(address); List<Integer> deviceIDs = store.getSubDeviceSessions(address);
for (Integer deviceId : deviceIDs) { for (Integer deviceId : deviceIDs) {
AxolotlAddress axolotlAddress = new AxolotlAddress(address, deviceId); AxolotlAddress axolotlAddress = new AxolotlAddress(address, deviceId);
this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress)); Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building session for remote address: "+axolotlAddress.toString());
String fingerprint = store.loadSession(axolotlAddress).getSessionState().getRemoteIdentityKey().getFingerprint().replaceAll("\\s", "");
this.put(axolotlAddress, new XmppAxolotlSession(account, store, axolotlAddress, fingerprint));
} }
} }
} }
@ -619,18 +643,6 @@ public class AxolotlService {
return axolotlStore.getIdentityKeyPair().getPublicKey(); return axolotlStore.getIdentityKeyPair().getPublicKey();
} }
public void trustSession(AxolotlAddress counterpart) {
XmppAxolotlSession session = sessions.get(counterpart);
if (session != null) {
session.trust();
}
}
public boolean isTrustedSession(AxolotlAddress counterpart) {
XmppAxolotlSession session = sessions.get(counterpart);
return session != null && session.isTrusted();
}
private AxolotlAddress getAddressForJid(Jid jid) { private AxolotlAddress getAddressForJid(Jid jid) {
return new AxolotlAddress(jid.toString(), 0); return new AxolotlAddress(jid.toString(), 0);
} }
@ -808,11 +820,19 @@ public class AxolotlService {
} }
public boolean isContactAxolotlCapable(Contact contact) { public boolean isContactAxolotlCapable(Contact contact) {
Jid jid = contact.getJid().toBareJid(); Jid jid = contact.getJid().toBareJid();
AxolotlAddress address = new AxolotlAddress(jid.toString(), 0); AxolotlAddress address = new AxolotlAddress(jid.toString(), 0);
return sessions.hasAny(address) || return sessions.hasAny(address) ||
( deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty()); ( deviceIds.containsKey(jid) && !deviceIds.get(jid).isEmpty());
} }
public SQLiteAxolotlStore.Trust getFingerprintTrust(String name, String fingerprint) {
return axolotlStore.getFingerprintTrust(name, fingerprint);
}
public void setFingerprintTrust(String name, String fingerprint, SQLiteAxolotlStore.Trust trust) {
axolotlStore.setFingerprintTrust(name, fingerprint, trust);
}
private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address) { private void buildSessionFromPEP(final Conversation conversation, final AxolotlAddress address) {
Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building new sesstion for " + address.getDeviceId()); Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Building new sesstion for " + address.getDeviceId());
@ -851,7 +871,7 @@ public class AxolotlService {
try { try {
SessionBuilder builder = new SessionBuilder(axolotlStore, address); SessionBuilder builder = new SessionBuilder(axolotlStore, address);
builder.process(preKeyBundle); builder.process(preKeyBundle);
XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address); XmppAxolotlSession session = new XmppAxolotlSession(account, axolotlStore, address, bundle.getIdentityKey().getFingerprint().replaceAll("\\s", ""));
sessions.put(address, session); sessions.put(address, session);
fetchStatusMap.put(address, FetchStatus.SUCCESS); fetchStatusMap.put(address, FetchStatus.SUCCESS);
} catch (UntrustedIdentityException|InvalidKeyException e) { } catch (UntrustedIdentityException|InvalidKeyException e) {
@ -1003,7 +1023,7 @@ public class AxolotlService {
byte[] payloadKey = session.processReceiving(header); byte[] payloadKey = session.processReceiving(header);
if (payloadKey != null) { if (payloadKey != null) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got payload key from axolotl header. Decrypting message..."); Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Got payload key from axolotl header. Decrypting message...");
plaintextMessage = message.decrypt(session, payloadKey); plaintextMessage = message.decrypt(session, payloadKey, session.getFingerprint());
} }
Integer preKeyId = session.getPreKeyId(); Integer preKeyId = session.getPreKeyId();
if (preKeyId != null) { if (preKeyId != null) {

View file

@ -67,10 +67,12 @@ public class XmppAxolotlMessage {
public static class XmppAxolotlPlaintextMessage { public static class XmppAxolotlPlaintextMessage {
private final AxolotlService.XmppAxolotlSession session; private final AxolotlService.XmppAxolotlSession session;
private final String plaintext; private final String plaintext;
private final String fingerprint;
public XmppAxolotlPlaintextMessage(AxolotlService.XmppAxolotlSession session, String plaintext) { public XmppAxolotlPlaintextMessage(AxolotlService.XmppAxolotlSession session, String plaintext, String fingerprint) {
this.session = session; this.session = session;
this.plaintext = plaintext; this.plaintext = plaintext;
this.fingerprint = fingerprint;
} }
public String getPlaintext() { public String getPlaintext() {
@ -81,6 +83,9 @@ public class XmppAxolotlMessage {
return session; return session;
} }
public String getFingerprint() {
return fingerprint;
}
} }
public XmppAxolotlMessage(Jid from, Element axolotlMessage) { public XmppAxolotlMessage(Jid from, Element axolotlMessage) {
@ -167,7 +172,7 @@ public class XmppAxolotlMessage {
} }
public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key) { public XmppAxolotlPlaintextMessage decrypt(AxolotlService.XmppAxolotlSession session, byte[] key, String fingerprint) {
XmppAxolotlPlaintextMessage plaintextMessage = null; XmppAxolotlPlaintextMessage plaintextMessage = null;
try { try {
@ -178,7 +183,7 @@ public class XmppAxolotlMessage {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
String plaintext = new String(cipher.doFinal(ciphertext)); String plaintext = new String(cipher.doFinal(ciphertext));
plaintextMessage = new XmppAxolotlPlaintextMessage(session, plaintext); plaintextMessage = new XmppAxolotlPlaintextMessage(session, plaintext, fingerprint);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IllegalBlockSizeException | InvalidAlgorithmParameterException | IllegalBlockSizeException

View file

@ -54,6 +54,7 @@ public class Message extends AbstractEntity {
public static final String REMOTE_MSG_ID = "remoteMsgId"; public static final String REMOTE_MSG_ID = "remoteMsgId";
public static final String SERVER_MSG_ID = "serverMsgId"; public static final String SERVER_MSG_ID = "serverMsgId";
public static final String RELATIVE_FILE_PATH = "relativeFilePath"; public static final String RELATIVE_FILE_PATH = "relativeFilePath";
public static final String FINGERPRINT = "axolotl_fingerprint";
public static final String ME_COMMAND = "/me "; public static final String ME_COMMAND = "/me ";
@ -67,7 +68,6 @@ public class Message extends AbstractEntity {
protected int encryption; protected int encryption;
protected int status; protected int status;
protected int type; protected int type;
private AxolotlService.XmppAxolotlSession axolotlSession = null;
protected String relativeFilePath; protected String relativeFilePath;
protected boolean read = true; protected boolean read = true;
protected String remoteMsgId = null; protected String remoteMsgId = null;
@ -76,6 +76,7 @@ public class Message extends AbstractEntity {
protected Transferable transferable = null; protected Transferable transferable = null;
private Message mNextMessage = null; private Message mNextMessage = null;
private Message mPreviousMessage = null; private Message mPreviousMessage = null;
private String axolotlFingerprint = null;
private Message() { private Message() {
@ -97,6 +98,7 @@ public class Message extends AbstractEntity {
TYPE_TEXT, TYPE_TEXT,
null, null,
null, null,
null,
null); null);
this.conversation = conversation; this.conversation = conversation;
} }
@ -104,7 +106,7 @@ public class Message extends AbstractEntity {
private Message(final String uuid, final String conversationUUid, final Jid counterpart, private Message(final String uuid, final String conversationUUid, final Jid counterpart,
final Jid trueCounterpart, final String body, final long timeSent, final Jid trueCounterpart, final String body, final long timeSent,
final int encryption, final int status, final int type, final String remoteMsgId, final int encryption, final int status, final int type, final String remoteMsgId,
final String relativeFilePath, final String serverMsgId) { final String relativeFilePath, final String serverMsgId, final String fingerprint) {
this.uuid = uuid; this.uuid = uuid;
this.conversationUuid = conversationUUid; this.conversationUuid = conversationUUid;
this.counterpart = counterpart; this.counterpart = counterpart;
@ -117,6 +119,7 @@ public class Message extends AbstractEntity {
this.remoteMsgId = remoteMsgId; this.remoteMsgId = remoteMsgId;
this.relativeFilePath = relativeFilePath; this.relativeFilePath = relativeFilePath;
this.serverMsgId = serverMsgId; this.serverMsgId = serverMsgId;
this.axolotlFingerprint = fingerprint;
} }
public static Message fromCursor(Cursor cursor) { public static Message fromCursor(Cursor cursor) {
@ -153,7 +156,8 @@ public class Message extends AbstractEntity {
cursor.getInt(cursor.getColumnIndex(TYPE)), cursor.getInt(cursor.getColumnIndex(TYPE)),
cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)),
cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)), cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)),
cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID))); cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)),
cursor.getString(cursor.getColumnIndex(FINGERPRINT)));
} }
public static Message createStatusMessage(Conversation conversation, String body) { public static Message createStatusMessage(Conversation conversation, String body) {
@ -187,6 +191,7 @@ public class Message extends AbstractEntity {
values.put(REMOTE_MSG_ID, remoteMsgId); values.put(REMOTE_MSG_ID, remoteMsgId);
values.put(RELATIVE_FILE_PATH, relativeFilePath); values.put(RELATIVE_FILE_PATH, relativeFilePath);
values.put(SERVER_MSG_ID, serverMsgId); values.put(SERVER_MSG_ID, serverMsgId);
values.put(FINGERPRINT, axolotlFingerprint);
return values; return values;
} }
@ -667,11 +672,7 @@ public class Message extends AbstractEntity {
public int height = 0; public int height = 0;
} }
public boolean isTrusted() { public void setAxolotlFingerprint(String fingerprint) {
return this.axolotlSession != null && this.axolotlSession.isTrusted(); this.axolotlFingerprint = fingerprint;
}
public void setAxolotlSession(AxolotlService.XmppAxolotlSession session) {
this.axolotlSession = session;
} }
} }

View file

@ -106,7 +106,8 @@ public class MessageParser extends AbstractParser implements
XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage = service.processReceiving(xmppAxolotlMessage); XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintextMessage = service.processReceiving(xmppAxolotlMessage);
if(plaintextMessage != null) { if(plaintextMessage != null) {
finishedMessage = new Message(conversation, plaintextMessage.getPlaintext(), Message.ENCRYPTION_AXOLOTL, status); finishedMessage = new Message(conversation, plaintextMessage.getPlaintext(), Message.ENCRYPTION_AXOLOTL, status);
finishedMessage.setAxolotlSession(plaintextMessage.getSession()); finishedMessage.setAxolotlFingerprint(plaintextMessage.getFingerprint());
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(finishedMessage.getConversation().getAccount())+" Received Message with session fingerprint: "+plaintextMessage.getFingerprint());
} }
return finishedMessage; return finishedMessage;

View file

@ -82,7 +82,6 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
+ AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, " + AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, "
+ AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " INTEGER, " + AxolotlService.SQLiteAxolotlStore.DEVICE_ID + " INTEGER, "
+ AxolotlService.SQLiteAxolotlStore.TRUSTED + " INTEGER, "
+ AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + AxolotlService.SQLiteAxolotlStore.ACCOUNT
+ ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, "
@ -97,6 +96,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, " + AxolotlService.SQLiteAxolotlStore.ACCOUNT + " TEXT, "
+ AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, " + AxolotlService.SQLiteAxolotlStore.NAME + " TEXT, "
+ AxolotlService.SQLiteAxolotlStore.OWN + " INTEGER, " + AxolotlService.SQLiteAxolotlStore.OWN + " INTEGER, "
+ AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " TEXT PRIMARY KEY ON CONFLICT IGNORE, "
+ AxolotlService.SQLiteAxolotlStore.TRUSTED + " INTEGER, "
+ AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + AxolotlService.SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY("
+ AxolotlService.SQLiteAxolotlStore.ACCOUNT + AxolotlService.SQLiteAxolotlStore.ACCOUNT
+ ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE " + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE "
@ -132,6 +133,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Message.STATUS + " NUMBER," + Message.TYPE + " NUMBER, " + Message.STATUS + " NUMBER," + Message.TYPE + " NUMBER, "
+ Message.RELATIVE_FILE_PATH + " TEXT, " + Message.RELATIVE_FILE_PATH + " TEXT, "
+ Message.SERVER_MSG_ID + " TEXT, " + Message.SERVER_MSG_ID + " TEXT, "
+ Message.FINGERPRINT + " TEXT, "
+ Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY("
+ Message.CONVERSATION + ") REFERENCES " + Message.CONVERSATION + ") REFERENCES "
+ Conversation.TABLENAME + "(" + Conversation.UUID + Conversation.TABLENAME + "(" + Conversation.UUID
@ -284,6 +286,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
} }
if (oldVersion < 15 && newVersion >= 15) { if (oldVersion < 15 && newVersion >= 15) {
recreateAxolotlDb(); recreateAxolotlDb();
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "
+ Message.FINGERPRINT + " TEXT");
} }
} }
@ -645,28 +649,6 @@ public class DatabaseBackend extends SQLiteOpenHelper {
args); args);
} }
public boolean isTrustedSession(Account account, AxolotlAddress contact) {
boolean trusted = false;
Cursor cursor = getCursorForSession(account, contact);
if(cursor.getCount() != 0) {
cursor.moveToFirst();
trusted = cursor.getInt(cursor.getColumnIndex(
AxolotlService.SQLiteAxolotlStore.TRUSTED)) > 0;
}
cursor.close();
return trusted;
}
public void setTrustedSession(Account account, AxolotlAddress contact, boolean trusted) {
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.ACCOUNT, account.getUuid());
values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trusted?1:0);
db.insert(AxolotlService.SQLiteAxolotlStore.SESSION_TABLENAME, null, values);
}
private Cursor getCursorForPreKey(Account account, int preKeyId) { private Cursor getCursorForPreKey(Account account, int preKeyId) {
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {AxolotlService.SQLiteAxolotlStore.KEY}; String[] columns = {AxolotlService.SQLiteAxolotlStore.KEY};
@ -796,17 +778,28 @@ public class DatabaseBackend extends SQLiteOpenHelper {
} }
private Cursor getIdentityKeyCursor(Account account, String name, boolean own) { private Cursor getIdentityKeyCursor(Account account, String name, boolean own) {
return getIdentityKeyCursor(account, name, own, null);
}
private Cursor getIdentityKeyCursor(Account account, String name, boolean own, String fingerprint) {
final SQLiteDatabase db = this.getReadableDatabase(); final SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {AxolotlService.SQLiteAxolotlStore.KEY}; String[] columns = {AxolotlService.SQLiteAxolotlStore.TRUSTED,
String[] selectionArgs = {account.getUuid(), AxolotlService.SQLiteAxolotlStore.KEY};
name, ArrayList<String> selectionArgs = new ArrayList<>(4);
own?"1":"0"}; selectionArgs.add(account.getUuid());
selectionArgs.add(name);
selectionArgs.add(own?"1":"0");
String selectionString = AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND "
+ AxolotlService.SQLiteAxolotlStore.NAME + " = ? AND "
+ AxolotlService.SQLiteAxolotlStore.OWN + " = ? ";
if (fingerprint != null){
selectionArgs.add(fingerprint);
selectionString += "AND " +AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " = ? ";
}
Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, Cursor cursor = db.query(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME,
columns, columns,
AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? AND " selectionString,
+ AxolotlService.SQLiteAxolotlStore.NAME + " = ? AND " selectionArgs.toArray(new String[selectionArgs.size()]),
+ AxolotlService.SQLiteAxolotlStore.OWN + " = ? ",
selectionArgs,
null, null, null); null, null, null);
return cursor; return cursor;
@ -844,22 +837,52 @@ public class DatabaseBackend extends SQLiteOpenHelper {
return identityKeys; return identityKeys;
} }
private void storeIdentityKey(Account account, String name, boolean own, String base64Serialized) { private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized) {
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(AxolotlService.SQLiteAxolotlStore.ACCOUNT, account.getUuid()); values.put(AxolotlService.SQLiteAxolotlStore.ACCOUNT, account.getUuid());
values.put(AxolotlService.SQLiteAxolotlStore.NAME, name); values.put(AxolotlService.SQLiteAxolotlStore.NAME, name);
values.put(AxolotlService.SQLiteAxolotlStore.OWN, own ? 1 : 0); values.put(AxolotlService.SQLiteAxolotlStore.OWN, own ? 1 : 0);
values.put(AxolotlService.SQLiteAxolotlStore.FINGERPRINT, fingerprint);
values.put(AxolotlService.SQLiteAxolotlStore.KEY, base64Serialized); values.put(AxolotlService.SQLiteAxolotlStore.KEY, base64Serialized);
db.insert(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values); db.insert(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
} }
public AxolotlService.SQLiteAxolotlStore.Trust isIdentityKeyTrusted(Account account, String name, String fingerprint) {
Cursor cursor = getIdentityKeyCursor(account, name, false, 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 name, String fingerprint, AxolotlService.SQLiteAxolotlStore.Trust trust) {
SQLiteDatabase db = this.getWritableDatabase();
String[] selectionArgs = {
account.getUuid(),
name,
fingerprint
};
ContentValues values = new ContentValues();
values.put(AxolotlService.SQLiteAxolotlStore.TRUSTED, trust.ordinal());
int rows = db.update(AxolotlService.SQLiteAxolotlStore.IDENTITIES_TABLENAME, values,
AxolotlService.SQLiteAxolotlStore.ACCOUNT + " = ? "
+ AxolotlService.SQLiteAxolotlStore.NAME + " = ? "
+ AxolotlService.SQLiteAxolotlStore.FINGERPRINT + " = ? ",
selectionArgs);
return rows == 1;
}
public void storeIdentityKey(Account account, String name, IdentityKey identityKey) { public void storeIdentityKey(Account account, String name, IdentityKey identityKey) {
storeIdentityKey(account, name, false, Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT)); storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
} }
public void storeOwnIdentityKeyPair(Account account, String name, IdentityKeyPair identityKeyPair) { public void storeOwnIdentityKeyPair(Account account, String name, IdentityKeyPair identityKeyPair) {
storeIdentityKey(account, name, true, Base64.encodeToString(identityKeyPair.serialize(),Base64.DEFAULT)); storeIdentityKey(account, name, true, identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKeyPair.serialize(), Base64.DEFAULT));
} }
public void recreateAxolotlDb() { public void recreateAxolotlDb() {