Match desktop session handling

This commit is contained in:
nielsandriesse
2020-07-16 09:44:00 +10:00
parent dbdb4ec855
commit 4beaf88fbe
6 changed files with 81 additions and 32 deletions

View File

@@ -70,11 +70,25 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
private val publicChatID = "public_chat_id"
private val userCount = "user_count"
@JvmStatic val createUserCountCacheCommand = "CREATE TABLE $userCountCache ($publicChatID STRING PRIMARY KEY, $userCount INTEGER DEFAULT 0);"
// Session request timestamp cache
// Session request sent timestamp cache
private val sessionRequestSentTimestampCache = "session_request_sent_timestamp_cache"
private val sessionRequestSentPublicKey = "public_key"
private val sessionRequestSentTimestamp = "timestamp"
@JvmStatic val createSessionRequestSentTimestampCacheCommand = "CREATE TABLE $sessionRequestSentTimestampCache ($sessionRequestSentPublicKey STRING PRIMARY KEY, $sessionRequestSentTimestamp INTEGER DEFAULT 0);"
// Session request processed timestamp cache
private val sessionRequestProcessedTimestampCache = "session_request_processed_timestamp_cache"
private val sessionRequestProcessedPublicKey = "public_key"
private val sessionRequestProcessedTimestamp = "timestamp"
@JvmStatic val createSessionRequestProcessedTimestampCacheCommand = "CREATE TABLE $sessionRequestProcessedTimestampCache ($sessionRequestProcessedPublicKey STRING PRIMARY KEY, $sessionRequestProcessedTimestamp INTEGER DEFAULT 0);"
// region Deprecated
private val sessionRequestTimestampCache = "session_request_timestamp_cache"
private val sessionRequestPublicKey = "public_key"
private val timestamp = "timestamp"
@JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($sessionRequestPublicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);"
// endregion
}
override fun getSnodePool(): Set<Snode> {
@@ -323,17 +337,30 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
database.insertOrUpdate(userCountCache, row, "$publicChatID = ?", wrap(index))
}
override fun getSessionRequestTimestamp(publicKey: String): Long? {
override fun getSessionRequestSentTimestamp(publicKey: String): Long? {
val database = databaseHelper.readableDatabase
return database.get(sessionRequestTimestampCache, "$LokiAPIDatabase.publicKey = ?", wrap(publicKey)) { cursor ->
cursor.getInt(LokiAPIDatabase.timestamp)
return database.get(sessionRequestSentTimestampCache, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey)) { cursor ->
cursor.getInt(LokiAPIDatabase.sessionRequestSentTimestamp)
}?.toLong()
}
override fun setSessionRequestTimestamp(publicKey: String, timestamp: Long) {
override fun setSessionRequestSentTimestamp(publicKey: String, timestamp: Long) {
val database = databaseHelper.writableDatabase
val row = wrap(mapOf(LokiAPIDatabase.sessionRequestPublicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString()))
database.insertOrUpdate(sessionRequestTimestampCache, row, "${LokiAPIDatabase.sessionRequestPublicKey} = ?", wrap(publicKey))
val row = wrap(mapOf(LokiAPIDatabase.sessionRequestSentPublicKey to publicKey, LokiAPIDatabase.sessionRequestSentTimestamp to timestamp.toString()))
database.insertOrUpdate(sessionRequestSentTimestampCache, row, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey))
}
override fun getSessionRequestProcessedTimestamp(publicKey: String): Long? {
val database = databaseHelper.readableDatabase
return database.get(sessionRequestProcessedTimestampCache, "${LokiAPIDatabase.sessionRequestProcessedPublicKey} = ?", wrap(publicKey)) { cursor ->
cursor.getInt(LokiAPIDatabase.sessionRequestProcessedTimestamp)
}?.toLong()
}
override fun setSessionRequestProcessedTimestamp(publicKey: String, timestamp: Long) {
val database = databaseHelper.writableDatabase
val row = wrap(mapOf(LokiAPIDatabase.sessionRequestProcessedPublicKey to publicKey, LokiAPIDatabase.sessionRequestProcessedTimestamp to timestamp.toString()))
database.insertOrUpdate(sessionRequestProcessedTimestampCache, row, "${LokiAPIDatabase.sessionRequestProcessedPublicKey} = ?", wrap(publicKey))
}
}

View File

@@ -169,7 +169,7 @@ object MultiDeviceProtocol {
TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterPublicKey)
TextSecurePreferences.setMultiDevice(context, true)
FileServerAPI.shared.addDeviceLink(deviceLink)
org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.duplicate_handleProfileKey(context, content)
org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.handleProfileKeyUpdate(context, content)
}
@JvmStatic

View File

@@ -19,22 +19,23 @@ import java.security.SecureRandom
import java.util.*
import java.util.concurrent.TimeUnit
class PushSessionRequestMessageSendJob private constructor(parameters: Parameters, private val publicKey: String) : BaseJob(parameters) {
class PushSessionRequestMessageSendJob private constructor(parameters: Parameters, private val publicKey: String, private val timestamp: Long) : BaseJob(parameters) {
companion object {
const val KEY = "PushSessionRequestMessageSendJob"
}
constructor(publicKey: String) : this(Parameters.Builder()
constructor(publicKey: String, timestamp: Long) : this(Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.setQueue(KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(1)
.build(),
publicKey)
publicKey,
timestamp)
override fun serialize(): Data {
return Data.Builder().putString("publicKey", publicKey).build()
return Data.Builder().putString("publicKey", publicKey).putLong("timestamp", timestamp).build()
}
override fun getFactoryKey(): String { return KEY }
@@ -83,14 +84,21 @@ class PushSessionRequestMessageSendJob private constructor(parameters: Parameter
return false
}
override fun onCanceled() { }
override fun onCanceled() {
// Update the DB on fail if this is still the most recently sent session request (should always be true)
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
if (apiDB.getSessionRequestSentTimestamp(publicKey) == timestamp) {
apiDB.setSessionRequestSentTimestamp(publicKey, 0)
}
}
class Factory : Job.Factory<PushSessionRequestMessageSendJob> {
override fun create(parameters: Parameters, data: Data): PushSessionRequestMessageSendJob {
try {
val publicKey = data.getString("publicKey")
return PushSessionRequestMessageSendJob(parameters, publicKey)
val timestamp = data.getLong("timestamp")
return PushSessionRequestMessageSendJob(parameters, publicKey, timestamp)
} catch (e: IOException) {
throw AssertionError(e)
}

View File

@@ -53,25 +53,30 @@ object SessionManagementProtocol {
}
}
@JvmStatic
fun shouldProcessSessionRequest(context: Context, publicKey: String, timestamp: Long): Boolean {
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
val sentTimestamp = apiDB.getSessionRequestSentTimestamp(publicKey) ?: 0
val processedTimestamp = apiDB.getSessionRequestProcessedTimestamp(publicKey) ?: 0
return timestamp > sentTimestamp && timestamp > processedTimestamp
}
@JvmStatic
fun handlePreKeyBundleMessageIfNeeded(context: Context, content: SignalServiceContent) {
val publicKey = content.sender
val recipient = recipient(context, publicKey)
if (recipient.isGroupRecipient) { return } // Should never occur
val preKeyBundleMessage = content.preKeyBundleMessage.orNull() ?: return
val registrationID = TextSecurePreferences.getLocalRegistrationId(context) // TODO: It seems wrong to use the local registration ID for this?
val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context)
val publicKey = content.sender
if (recipient(context, publicKey).isGroupRecipient) { return } // Should never occur
Log.d("Loki", "Received a pre key bundle from: $publicKey.")
val sessionRequestTimestamp = DatabaseFactory.getLokiAPIDatabase(context).getSessionRequestTimestamp(content.sender)
if (sessionRequestTimestamp != null && content.timestamp < sessionRequestTimestamp) {
// We sent or processed a session request after this one was sent
Log.d("Loki", "Ignoring session request from: ${content.sender}.")
if (!shouldProcessSessionRequest(context, publicKey, content.timestamp)) {
Log.d("Loki", "Ignoring session request from: $publicKey.")
return
}
val registrationID = TextSecurePreferences.getLocalRegistrationId(context)
val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context)
val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID)
lokiPreKeyBundleDatabase.setPreKeyBundle(content.sender, preKeyBundle)
DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestTimestamp(content.sender, Date().time)
val job = PushNullMessageSendJob(content.sender)
lokiPreKeyBundleDatabase.setPreKeyBundle(publicKey, preKeyBundle)
DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestProcessedTimestamp(publicKey, Date().time)
val job = PushNullMessageSendJob(publicKey)
ApplicationContext.getInstance(context).jobManager.add(job)
}