mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 02:25:19 +00:00
Match desktop session handling
This commit is contained in:
parent
dbdb4ec855
commit
4beaf88fbe
@ -594,13 +594,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||||||
SignalProtocolAddress address = new SignalProtocolAddress(publicKey, SignalServiceAddress.DEFAULT_DEVICE_ID);
|
SignalProtocolAddress address = new SignalProtocolAddress(publicKey, SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||||
boolean hasSession = new TextSecureSessionStore(this).containsSession(address);
|
boolean hasSession = new TextSecureSessionStore(this).containsSession(address);
|
||||||
if (hasSession) { return; }
|
if (hasSession) { return; }
|
||||||
// Check that we didn't already send or process a session request
|
// Check that we didn't already send a session request
|
||||||
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
|
||||||
boolean hasSentOrProcessedSessionRequest = (apiDB.getSessionRequestTimestamp(publicKey) != null);
|
boolean hasSentSessionRequest = (apiDB.getSessionRequestSentTimestamp(publicKey) != null);
|
||||||
if (hasSentOrProcessedSessionRequest) { return; }
|
if (hasSentSessionRequest) { return; }
|
||||||
// Send the session request
|
// Send the session request
|
||||||
DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestTimestamp(publicKey, new Date().getTime());
|
long timestamp = new Date().getTime();
|
||||||
PushSessionRequestMessageSendJob job = new PushSessionRequestMessageSendJob(publicKey);
|
DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestSentTimestamp(publicKey, timestamp);
|
||||||
|
PushSessionRequestMessageSendJob job = new PushSessionRequestMessageSendJob(publicKey, timestamp);
|
||||||
jobManager.add(job);
|
jobManager.add(job);
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
@ -83,8 +83,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int lokiV7 = 28;
|
private static final int lokiV7 = 28;
|
||||||
private static final int lokiV8 = 29;
|
private static final int lokiV8 = 29;
|
||||||
private static final int lokiV9 = 30;
|
private static final int lokiV9 = 30;
|
||||||
|
private static final int lokiV10 = 31;
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = lokiV9; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
private static final int DATABASE_VERSION = lokiV10; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
|
||||||
private static final String DATABASE_NAME = "signal.db";
|
private static final String DATABASE_NAME = "signal.db";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -143,6 +144,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiAPIDatabase.getCreateDeviceLinkCacheCommand());
|
db.execSQL(LokiAPIDatabase.getCreateDeviceLinkCacheCommand());
|
||||||
db.execSQL(LokiAPIDatabase.getCreateUserCountCacheCommand());
|
db.execSQL(LokiAPIDatabase.getCreateUserCountCacheCommand());
|
||||||
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand());
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampCacheCommand());
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampCacheCommand());
|
||||||
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand());
|
||||||
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
|
db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand());
|
||||||
@ -589,6 +592,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.execSQL(LokiAPIDatabase.getCreateOnionRequestPathCacheCommand());
|
db.execSQL(LokiAPIDatabase.getCreateOnionRequestPathCacheCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < lokiV10) {
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampCacheCommand());
|
||||||
|
db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampCacheCommand());
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -70,11 +70,25 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
private val publicChatID = "public_chat_id"
|
private val publicChatID = "public_chat_id"
|
||||||
private val userCount = "user_count"
|
private val userCount = "user_count"
|
||||||
@JvmStatic val createUserCountCacheCommand = "CREATE TABLE $userCountCache ($publicChatID STRING PRIMARY KEY, $userCount INTEGER DEFAULT 0);"
|
@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 sessionRequestTimestampCache = "session_request_timestamp_cache"
|
||||||
private val sessionRequestPublicKey = "public_key"
|
private val sessionRequestPublicKey = "public_key"
|
||||||
private val timestamp = "timestamp"
|
private val timestamp = "timestamp"
|
||||||
@JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($sessionRequestPublicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);"
|
@JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($sessionRequestPublicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);"
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSnodePool(): Set<Snode> {
|
override fun getSnodePool(): Set<Snode> {
|
||||||
@ -323,17 +337,30 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
|
|||||||
database.insertOrUpdate(userCountCache, row, "$publicChatID = ?", wrap(index))
|
database.insertOrUpdate(userCountCache, row, "$publicChatID = ?", wrap(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSessionRequestTimestamp(publicKey: String): Long? {
|
override fun getSessionRequestSentTimestamp(publicKey: String): Long? {
|
||||||
val database = databaseHelper.readableDatabase
|
val database = databaseHelper.readableDatabase
|
||||||
return database.get(sessionRequestTimestampCache, "$LokiAPIDatabase.publicKey = ?", wrap(publicKey)) { cursor ->
|
return database.get(sessionRequestSentTimestampCache, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey)) { cursor ->
|
||||||
cursor.getInt(LokiAPIDatabase.timestamp)
|
cursor.getInt(LokiAPIDatabase.sessionRequestSentTimestamp)
|
||||||
}?.toLong()
|
}?.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSessionRequestTimestamp(publicKey: String, timestamp: Long) {
|
override fun setSessionRequestSentTimestamp(publicKey: String, timestamp: Long) {
|
||||||
val database = databaseHelper.writableDatabase
|
val database = databaseHelper.writableDatabase
|
||||||
val row = wrap(mapOf(LokiAPIDatabase.sessionRequestPublicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString()))
|
val row = wrap(mapOf(LokiAPIDatabase.sessionRequestSentPublicKey to publicKey, LokiAPIDatabase.sessionRequestSentTimestamp to timestamp.toString()))
|
||||||
database.insertOrUpdate(sessionRequestTimestampCache, row, "${LokiAPIDatabase.sessionRequestPublicKey} = ?", wrap(publicKey))
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ object MultiDeviceProtocol {
|
|||||||
TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterPublicKey)
|
TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterPublicKey)
|
||||||
TextSecurePreferences.setMultiDevice(context, true)
|
TextSecurePreferences.setMultiDevice(context, true)
|
||||||
FileServerAPI.shared.addDeviceLink(deviceLink)
|
FileServerAPI.shared.addDeviceLink(deviceLink)
|
||||||
org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.duplicate_handleProfileKey(context, content)
|
org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.handleProfileKeyUpdate(context, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
@ -19,22 +19,23 @@ import java.security.SecureRandom
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
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 {
|
companion object {
|
||||||
const val KEY = "PushSessionRequestMessageSendJob"
|
const val KEY = "PushSessionRequestMessageSendJob"
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(publicKey: String) : this(Parameters.Builder()
|
constructor(publicKey: String, timestamp: Long) : this(Parameters.Builder()
|
||||||
.addConstraint(NetworkConstraint.KEY)
|
.addConstraint(NetworkConstraint.KEY)
|
||||||
.setQueue(KEY)
|
.setQueue(KEY)
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||||
.setMaxAttempts(1)
|
.setMaxAttempts(1)
|
||||||
.build(),
|
.build(),
|
||||||
publicKey)
|
publicKey,
|
||||||
|
timestamp)
|
||||||
|
|
||||||
override fun serialize(): Data {
|
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 }
|
override fun getFactoryKey(): String { return KEY }
|
||||||
@ -83,14 +84,21 @@ class PushSessionRequestMessageSendJob private constructor(parameters: Parameter
|
|||||||
return false
|
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> {
|
class Factory : Job.Factory<PushSessionRequestMessageSendJob> {
|
||||||
|
|
||||||
override fun create(parameters: Parameters, data: Data): PushSessionRequestMessageSendJob {
|
override fun create(parameters: Parameters, data: Data): PushSessionRequestMessageSendJob {
|
||||||
try {
|
try {
|
||||||
val publicKey = data.getString("publicKey")
|
val publicKey = data.getString("publicKey")
|
||||||
return PushSessionRequestMessageSendJob(parameters, publicKey)
|
val timestamp = data.getLong("timestamp")
|
||||||
|
return PushSessionRequestMessageSendJob(parameters, publicKey, timestamp)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
throw AssertionError(e)
|
throw AssertionError(e)
|
||||||
}
|
}
|
||||||
|
@ -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
|
@JvmStatic
|
||||||
fun handlePreKeyBundleMessageIfNeeded(context: Context, content: SignalServiceContent) {
|
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 preKeyBundleMessage = content.preKeyBundleMessage.orNull() ?: return
|
||||||
val registrationID = TextSecurePreferences.getLocalRegistrationId(context) // TODO: It seems wrong to use the local registration ID for this?
|
val publicKey = content.sender
|
||||||
val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context)
|
if (recipient(context, publicKey).isGroupRecipient) { return } // Should never occur
|
||||||
Log.d("Loki", "Received a pre key bundle from: $publicKey.")
|
Log.d("Loki", "Received a pre key bundle from: $publicKey.")
|
||||||
val sessionRequestTimestamp = DatabaseFactory.getLokiAPIDatabase(context).getSessionRequestTimestamp(content.sender)
|
if (!shouldProcessSessionRequest(context, publicKey, content.timestamp)) {
|
||||||
if (sessionRequestTimestamp != null && content.timestamp < sessionRequestTimestamp) {
|
Log.d("Loki", "Ignoring session request from: $publicKey.")
|
||||||
// We sent or processed a session request after this one was sent
|
|
||||||
Log.d("Loki", "Ignoring session request from: ${content.sender}.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val registrationID = TextSecurePreferences.getLocalRegistrationId(context)
|
||||||
|
val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context)
|
||||||
val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID)
|
val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID)
|
||||||
lokiPreKeyBundleDatabase.setPreKeyBundle(content.sender, preKeyBundle)
|
lokiPreKeyBundleDatabase.setPreKeyBundle(publicKey, preKeyBundle)
|
||||||
DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestTimestamp(content.sender, Date().time)
|
DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestProcessedTimestamp(publicKey, Date().time)
|
||||||
val job = PushNullMessageSendJob(content.sender)
|
val job = PushNullMessageSendJob(publicKey)
|
||||||
ApplicationContext.getInstance(context).jobManager.add(job)
|
ApplicationContext.getInstance(context).jobManager.add(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user