add new contact database api

This commit is contained in:
Ryan ZHAO 2021-05-07 16:31:46 +10:00
parent cbd6ae3bcb
commit a16e67d1fd
7 changed files with 138 additions and 8 deletions

View File

@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.database.SessionJobDatabase;
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
public class DatabaseFactory {
@ -63,6 +64,7 @@ public class DatabaseFactory {
private final LokiUserDatabase lokiUserDatabase;
private final LokiBackupFilesDatabase lokiBackupFilesDatabase;
private final SessionJobDatabase sessionJobDatabase;
private final SessionContactDatabase sessionContactDatabase;
// Refactor
private final Storage storage;
@ -157,6 +159,10 @@ public class DatabaseFactory {
public static SessionJobDatabase getSessionJobDatabase(Context context) {
return getInstance(context).sessionJobDatabase;
}
public static SessionContactDatabase getSessionContactDatabase(Context context) {
return getInstance(context).sessionContactDatabase;
}
// endregion
// region Refactor
@ -202,6 +208,7 @@ public class DatabaseFactory {
this.storage = new Storage(context, databaseHelper);
this.attachmentProvider = new DatabaseAttachmentProvider(context, databaseHelper);
this.sessionJobDatabase = new SessionJobDatabase(context, databaseHelper);
this.sessionContactDatabase = new SessionContactDatabase(context, databaseHelper);
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.net.Uri
import okhttp3.HttpUrl
import org.session.libsession.messaging.StorageProtocol
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.Job
import org.session.libsession.messaging.jobs.JobQueue
@ -624,6 +625,18 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
return DatabaseFactory.getLokiUserDatabase(context).getProfilePictureURL(publicKey)
}
override fun getContactWithSessionID(sessionID: String): Contact? {
return DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(sessionID)
}
override fun getAllContacts(): Set<Contact> {
return DatabaseFactory.getSessionContactDatabase(context).getAllContacts()
}
override fun setContact(contact: Contact) {
DatabaseFactory.getSessionContactDatabase(context).setContact(contact)
}
override fun getRecipientSettings(address: Address): Recipient.RecipientSettings? {
val recipientSettings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address)
return if (recipientSettings.isPresent) { recipientSettings.get() } else null

View File

@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.loki.database.LokiBackupFilesDatabase;
import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase;
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase;
import org.thoughtcrime.securesms.loki.database.LokiUserDatabase;
import org.thoughtcrime.securesms.loki.database.SessionContactDatabase;
import org.thoughtcrime.securesms.loki.database.SessionJobDatabase;
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsMigration;
@ -56,9 +57,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int lokiV22 = 43;
private static final int lokiV23 = 44;
private static final int lokiV24 = 45;
private static final int lokiV25 = 46;
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
private static final int DATABASE_VERSION = lokiV24;
private static final int DATABASE_VERSION = lokiV25;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@ -128,6 +130,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(SessionJobDatabase.getCreateSessionJobTableCommand());
db.execSQL(LokiMessageDatabase.getUpdateMessageIDTableForType());
db.execSQL(LokiMessageDatabase.getUpdateMessageMappingTable());
db.execSQL(SessionContactDatabase.getCreateSessionContactTableCommand());
executeStatements(db, SmsDatabase.CREATE_INDEXS);
executeStatements(db, MmsDatabase.CREATE_INDEXS);
@ -291,6 +294,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(LokiAPIDatabase.getCreateSwarmTableCommand());
}
if (oldVersion < lokiV25) {
db.execSQL(SessionContactDatabase.getCreateSessionContactTableCommand());
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();

View File

@ -0,0 +1,76 @@
package org.thoughtcrime.securesms.loki.database
import android.content.ContentValues
import android.content.Context
import net.sqlcipher.Cursor
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.Job
import org.session.libsignal.utilities.Base64
import org.thoughtcrime.securesms.database.Database
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.loki.utilities.*
class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper) {
companion object {
private const val sessionContactTable = "session_contact_database"
const val sessionID = "session_id"
const val name = "name"
const val nickname = "nickname"
const val profilePictureURL = "profile_picture_url"
const val profilePictureFileName = "profile_picture_file_name"
const val profilePictureEncryptionKey = "profile_picture_encryption_key"
const val threadID = "thread_id"
const val isTrusted = "is_trusted"
@JvmStatic val createSessionContactTableCommand =
"CREATE TABLE $sessionContactTable " +
"($sessionID STRING PRIMARY KEY, " +
"$name TEXT DEFAULT NULL, " +
"$nickname TEXT DEFAULT NULL, " +
"$profilePictureURL TEXT DEFAULT NULL, " +
"$profilePictureFileName TEXT DEFAULT NULL, " +
"$profilePictureEncryptionKey BLOB DEFAULT NULL, " +
"$threadID INTEGER DEFAULT -1, " +
"$isTrusted INTEGER DEFAULT 0);"
}
fun getContactWithSessionID(sessionID: String): Contact? {
val database = databaseHelper.readableDatabase
return database.get(sessionContactTable, "$sessionID = ?", arrayOf(sessionID)) { cursor ->
contactFromCursor(cursor)
}
}
fun getAllContacts(): Set<Contact> {
val database = databaseHelper.readableDatabase
return database.getAll(sessionContactTable, null, null) { cursor ->
contactFromCursor(cursor)
}.toSet()
}
fun setContact(contact: Contact) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(8)
contentValues.put(sessionID, contact.sessionID)
contentValues.put(name, contact.name)
contentValues.put(nickname, contact.nickname)
contentValues.put(profilePictureURL, contact.profilePictureURL)
contentValues.put(profilePictureFileName, contact.profilePictureFileName)
contentValues.put(profilePictureEncryptionKey, Base64.encodeBytes(contact.profilePictureEncryptionKey))
contentValues.put(threadID, threadID)
contentValues.put(isTrusted, if (contact.isTrusted) 1 else 0)
database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf(contact.sessionID))
}
private fun contactFromCursor(cursor: Cursor): Contact {
val sessionID = cursor.getString(sessionID)
val contact = Contact(sessionID)
contact.name = cursor.getString(name)
contact.nickname = cursor.getString(nickname)
contact.profilePictureURL = cursor.getString(profilePictureURL)
contact.profilePictureFileName = cursor.getString(profilePictureFileName)
contact.profilePictureEncryptionKey = Base64.decode(cursor.getString(profilePictureEncryptionKey))
contact.threadID = cursor.getInt(threadID)
contact.isTrusted = cursor.getInt(isTrusted) != 0
return contact
}
}

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.sskenvironment
import android.content.Context
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.SSKEnvironment
import org.thoughtcrime.securesms.ApplicationContext
@ -10,18 +11,31 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
class ProfileManager: SSKEnvironment.ProfileManagerProtocol {
override fun setDisplayName(context: Context, recipient: Recipient, displayName: String) {
val database = DatabaseFactory.getLokiUserDatabase(context)
val publicKey = recipient.address.serialize()
if (recipient.name == null) {
// Migrate the profile name in LokiUserDatabase to recipient
database.getDisplayName(publicKey)?.let { setProfileName(context, recipient, it) }
val sessionID = recipient.address.serialize()
database.setDisplayName(sessionID, displayName)
// New API
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
var contact = contactDatabase.getContactWithSessionID(sessionID)
if (contact == null) contact = Contact(sessionID)
if (contact.nickname != displayName) {
contact.nickname = displayName
contactDatabase.setContact(contact)
}
database.setDisplayName(publicKey, displayName)
}
override fun setProfileName(context: Context, recipient: Recipient, profileName: String) {
val database = DatabaseFactory.getRecipientDatabase(context)
database.setProfileName(recipient, profileName)
recipient.notifyListeners()
// New API
val sessionID = recipient.address.serialize()
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
var contact = contactDatabase.getContactWithSessionID(sessionID)
if (contact == null) contact = Contact(sessionID)
if (contact.name != profileName) {
contact.name = profileName
contactDatabase.setContact(contact)
}
}
override fun setProfilePictureURL(context: Context, recipient: Recipient, profilePictureURL: String) {
@ -31,6 +45,15 @@ class ProfileManager: SSKEnvironment.ProfileManagerProtocol {
override fun setProfileKey(context: Context, recipient: Recipient, profileKey: ByteArray) {
val database = DatabaseFactory.getRecipientDatabase(context)
database.setProfileKey(recipient, profileKey)
// New API
val sessionID = recipient.address.serialize()
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
var contact = contactDatabase.getContactWithSessionID(sessionID)
if (contact == null) contact = Contact(sessionID)
if (!contact.profilePictureEncryptionKey.contentEquals(profileKey)) {
contact.profilePictureEncryptionKey = profileKey
contactDatabase.setContact(contact)
}
}
override fun setUnidentifiedAccessMode(context: Context, recipient: Recipient, unidentifiedAccessMode: Recipient.UnidentifiedAccessMode) {

View File

@ -3,6 +3,7 @@ package org.session.libsession.messaging
import android.content.Context
import android.net.Uri
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
import org.session.libsession.messaging.jobs.Job
import org.session.libsession.messaging.jobs.MessageSendJob
@ -146,9 +147,12 @@ interface StorageProtocol {
fun getSessionRequestProcessedTimestamp(publicKey: String): Long?
fun setSessionRequestProcessedTimestamp(publicKey: String, newValue: Long)
// Loki User
// Session Contact (Loki User)
fun getDisplayName(publicKey: String): String?
fun getProfilePictureURL(publicKey: String): String?
fun getContactWithSessionID(sessionID: String): Contact?
fun getAllContacts(): Set<Contact>
fun setContact(contact: Contact)
// Recipient
fun getRecipientSettings(address: Address): RecipientSettings?

View File

@ -10,7 +10,7 @@ class Contact(val sessionID: String) {
// The key with which the profile picture is encrypted.
var profilePictureEncryptionKey: ByteArray? = null
// The ID of the thread associated with this contact.
var threadID: String? = null
var threadID: Int? = null
// This flag is used to determine whether we should auto-download files sent by this contact.
var isTrusted = false