mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 20:28:26 +00:00
fix: various fixes wrt open groups, config messages, job queueing
This commit is contained in:
parent
c3f7425ccd
commit
3654d1731c
@ -230,14 +230,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
if (closedGroupPoller != null) {
|
||||
closedGroupPoller.stopIfNeeded();
|
||||
}
|
||||
if (publicChatManager != null) {
|
||||
publicChatManager.stopPollers();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
stopKovenant(); // Loki
|
||||
if (publicChatManager != null) {
|
||||
publicChatManager.stopPollers();
|
||||
}
|
||||
super.onTerminate();
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||
import org.session.libsession.messaging.jobs.Job
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.signal.*
|
||||
import org.session.libsession.messaging.messages.signal.IncomingTextMessage
|
||||
import org.session.libsession.messaging.messages.visible.Attachment
|
||||
@ -30,7 +31,9 @@ import org.session.libsignal.libsignal.util.guava.Optional
|
||||
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
|
||||
import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase
|
||||
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol
|
||||
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
|
||||
@ -65,12 +68,27 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
return TextSecurePreferences.getProfilePictureURL(context)
|
||||
}
|
||||
|
||||
override fun setUserProfilePictureUrl(newProfilePicture: String) {
|
||||
val ourRecipient = Address.fromSerialized(getUserPublicKey()!!).let {
|
||||
Recipient.from(context, it, false)
|
||||
}
|
||||
TextSecurePreferences.setProfilePictureURL(context, newProfilePicture)
|
||||
RetrieveProfileAvatarJob(ourRecipient, newProfilePicture)
|
||||
ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(ourRecipient, newProfilePicture))
|
||||
}
|
||||
|
||||
override fun getProfileKeyForRecipient(recipientPublicKey: String): ByteArray? {
|
||||
val address = Address.fromSerialized(recipientPublicKey)
|
||||
val recipient = Recipient.from(context, address, false)
|
||||
return recipient.profileKey
|
||||
}
|
||||
|
||||
override fun setProfileKeyForRecipient(recipientPublicKey: String, profileKey: ByteArray) {
|
||||
val address = Address.fromSerialized(recipientPublicKey)
|
||||
val recipient = Recipient.from(context, address, false)
|
||||
DatabaseFactory.getRecipientDatabase(context).setProfileKey(recipient, profileKey)
|
||||
}
|
||||
|
||||
override fun getOrGenerateRegistrationID(): Int {
|
||||
var registrationID = TextSecurePreferences.getLocalRegistrationId(context)
|
||||
if (registrationID == 0) {
|
||||
@ -511,6 +529,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
return DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey)
|
||||
}
|
||||
|
||||
override fun setDisplayName(publicKey: String, newName: String) {
|
||||
DatabaseFactory.getLokiUserDatabase(context).setDisplayName(publicKey, newName)
|
||||
}
|
||||
|
||||
override fun getServerDisplayName(serverID: String, publicKey: String): String? {
|
||||
return DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(serverID, publicKey)
|
||||
}
|
||||
@ -524,6 +546,31 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
|
||||
return if (recipientSettings.isPresent) { recipientSettings.get() } else null
|
||||
}
|
||||
|
||||
override fun addContacts(contacts: List<ConfigurationMessage.Contact>) {
|
||||
val recipientDatabase = DatabaseFactory.getRecipientDatabase(context)
|
||||
val threadDatabase = DatabaseFactory.getThreadDatabase(context)
|
||||
for (contact in contacts) {
|
||||
val address = Address.fromSerialized(contact.publicKey)
|
||||
val recipient = Recipient.from(context, address, true)
|
||||
if (!contact.profilePicture.isNullOrEmpty()) {
|
||||
recipientDatabase.setProfileAvatar(recipient, contact.profilePicture)
|
||||
}
|
||||
if (contact.profileKey?.isNotEmpty() == true) {
|
||||
recipientDatabase.setProfileKey(recipient, contact.profileKey)
|
||||
}
|
||||
if (contact.name.isNotEmpty()) {
|
||||
recipientDatabase.setProfileName(recipient, contact.name)
|
||||
}
|
||||
recipientDatabase.setProfileSharing(recipient, true)
|
||||
recipientDatabase.setRegistered(recipient, Recipient.RegisteredState.REGISTERED)
|
||||
// create Thread if needed
|
||||
threadDatabase.getOrCreateThreadIdFor(recipient)
|
||||
}
|
||||
if (contacts.isNotEmpty()) {
|
||||
threadDatabase.notifyUpdatedFromConfig()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachmentDataUri(attachmentId: AttachmentId): Uri {
|
||||
return PartAuthority.getAttachmentDataUri(attachmentId)
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ package org.thoughtcrime.securesms.jobs;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.session.libsession.messaging.threads.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
import org.session.libsession.messaging.threads.recipients.Recipient;
|
||||
import org.session.libsignal.service.api.messages.SignalServiceEnvelope;
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
|
||||
public abstract class PushReceivedJob extends BaseJob {
|
||||
|
||||
|
@ -4,13 +4,13 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
import org.session.libsession.messaging.jobs.JobQueue
|
||||
import org.session.libsession.messaging.jobs.MessageReceiveJob
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.utilities.logging.Log
|
||||
import org.session.libsignal.service.api.messages.SignalServiceEnvelope
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.service.loki.api.MessageWrapper
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.utilities.logging.Log
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels
|
||||
|
||||
class PushNotificationService : FirebaseMessagingService() {
|
||||
|
||||
@ -27,8 +27,7 @@ class PushNotificationService : FirebaseMessagingService() {
|
||||
val data = base64EncodedData?.let { Base64.decode(it) }
|
||||
if (data != null) {
|
||||
try {
|
||||
val envelope = MessageWrapper.unwrap(data)
|
||||
PushContentReceiveJob(this).processEnvelope(SignalServiceEnvelope(envelope), true)
|
||||
JobQueue.shared.add(MessageReceiveJob(MessageWrapper.unwrap(data).toByteArray(),true))
|
||||
} catch (e: Exception) {
|
||||
Log.d("Loki", "Failed to unwrap data for message due to error: $e.")
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.net.Uri
|
||||
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||
import org.session.libsession.messaging.jobs.Job
|
||||
import org.session.libsession.messaging.jobs.MessageSendJob
|
||||
import org.session.libsession.messaging.messages.control.ConfigurationMessage
|
||||
import org.session.libsession.messaging.messages.visible.Attachment
|
||||
import org.session.libsession.messaging.messages.visible.VisibleMessage
|
||||
import org.session.libsession.messaging.opengroups.OpenGroup
|
||||
@ -30,8 +31,10 @@ interface StorageProtocol {
|
||||
fun getUserDisplayName(): String?
|
||||
fun getUserProfileKey(): ByteArray?
|
||||
fun getUserProfilePictureURL(): String?
|
||||
fun setUserProfilePictureUrl(newProfilePicture: String)
|
||||
|
||||
fun getProfileKeyForRecipient(recipientPublicKey: String): ByteArray?
|
||||
fun setProfileKeyForRecipient(recipientPublicKey: String, profileKey: ByteArray)
|
||||
|
||||
// Signal Protocol
|
||||
|
||||
@ -140,11 +143,13 @@ interface StorageProtocol {
|
||||
|
||||
// Loki User
|
||||
fun getDisplayName(publicKey: String): String?
|
||||
fun setDisplayName(publicKey: String, newName: String)
|
||||
fun getServerDisplayName(serverID: String, publicKey: String): String?
|
||||
fun getProfilePictureURL(publicKey: String): String?
|
||||
|
||||
// Recipient
|
||||
fun getRecipientSettings(address: Address): RecipientSettings?
|
||||
fun addContacts(contacts: List<ConfigurationMessage.Contact>)
|
||||
|
||||
// PartAuthority
|
||||
fun getAttachmentDataUri(attachmentId: AttachmentId): Uri
|
||||
|
@ -34,30 +34,26 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
|
||||
}
|
||||
|
||||
override fun execute() {
|
||||
val handleFailure: (java.lang.Exception) -> Unit = { exception ->
|
||||
if(exception is Error && exception == Error.NoAttachment) {
|
||||
MessagingConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
|
||||
this.handlePermanentFailure(exception)
|
||||
} else if (exception is DotNetAPI.Error && exception == DotNetAPI.Error.ParsingFailed) {
|
||||
// No need to retry if the response is invalid. Most likely this means we (incorrectly)
|
||||
// got a "Cannot GET ..." error from the file server.
|
||||
MessagingConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
|
||||
this.handlePermanentFailure(exception)
|
||||
} else {
|
||||
this.handleFailure(exception)
|
||||
}
|
||||
}
|
||||
try {
|
||||
val messageDataProvider = MessagingConfiguration.shared.messageDataProvider
|
||||
val attachment = messageDataProvider.getDatabaseAttachment(attachmentID) ?: return handleFailure(Error.NoAttachment)
|
||||
messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachmentID, this.databaseMessageID)
|
||||
val tempFile = createTempFile()
|
||||
val handleFailure: (java.lang.Exception) -> Unit = { exception ->
|
||||
tempFile.delete()
|
||||
if(exception is Error && exception == Error.NoAttachment) {
|
||||
MessagingConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
|
||||
this.handlePermanentFailure(exception)
|
||||
} else if (exception is DotNetAPI.Error && exception == DotNetAPI.Error.ParsingFailed) {
|
||||
// No need to retry if the response is invalid. Most likely this means we (incorrectly)
|
||||
// got a "Cannot GET ..." error from the file server.
|
||||
MessagingConfiguration.shared.messageDataProvider.setAttachmentState(AttachmentState.FAILED, attachmentID, databaseMessageID)
|
||||
this.handlePermanentFailure(exception)
|
||||
} else {
|
||||
this.handleFailure(exception)
|
||||
}
|
||||
}
|
||||
try {
|
||||
FileServerAPI.shared.downloadFile(tempFile, attachment.url, MAX_ATTACHMENT_SIZE, null)
|
||||
} catch (e: Exception) {
|
||||
return handleFailure(e)
|
||||
}
|
||||
|
||||
FileServerAPI.shared.downloadFile(tempFile, attachment.url, MAX_ATTACHMENT_SIZE, null)
|
||||
|
||||
// DECRYPTION
|
||||
|
||||
@ -70,7 +66,7 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
|
||||
tempFile.delete()
|
||||
handleSuccess()
|
||||
} catch (e: Exception) {
|
||||
handleFailure(e)
|
||||
return handleFailure(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,19 +16,17 @@ import kotlin.math.roundToLong
|
||||
class JobQueue : JobDelegate {
|
||||
private var hasResumedPendingJobs = false // Just for debugging
|
||||
|
||||
private val dispatcher = Executors.newCachedThreadPool().asCoroutineDispatcher()
|
||||
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
private val scope = GlobalScope + SupervisorJob()
|
||||
private val queue = Channel<Job>(UNLIMITED)
|
||||
|
||||
init {
|
||||
// process jobs
|
||||
scope.launch {
|
||||
scope.launch(dispatcher) {
|
||||
while (isActive) {
|
||||
queue.receive().let { job ->
|
||||
launch(dispatcher) {
|
||||
job.delegate = this@JobQueue
|
||||
job.execute()
|
||||
}
|
||||
job.delegate = this@JobQueue
|
||||
job.execute()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,7 +42,7 @@ class JobQueue : JobDelegate {
|
||||
queue.offer(job) // offer always called on unlimited capacity
|
||||
}
|
||||
|
||||
fun addWithoutExecuting(job: Job) {
|
||||
private fun addWithoutExecuting(job: Job) {
|
||||
job.id = System.currentTimeMillis().toString()
|
||||
MessagingConfiguration.shared.storage.persistJob(job)
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import org.session.libsession.messaging.threads.recipients.Recipient
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.SSKEnvironment
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.preferences.ProfileKeyUtil
|
||||
import org.session.libsignal.libsignal.ecc.DjbECPrivateKey
|
||||
import org.session.libsignal.libsignal.ecc.DjbECPublicKey
|
||||
import org.session.libsignal.libsignal.ecc.ECKeyPair
|
||||
@ -26,6 +27,7 @@ import org.session.libsignal.service.api.messages.SignalServiceGroup
|
||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||
import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
|
||||
import org.session.libsignal.service.loki.utilities.toHexString
|
||||
import org.session.libsignal.utilities.Base64
|
||||
import org.session.libsignal.utilities.logging.Log
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
@ -91,8 +93,11 @@ private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimer
|
||||
private fun MessageReceiver.handleConfigurationMessage(message: ConfigurationMessage) {
|
||||
val context = MessagingConfiguration.shared.context
|
||||
val storage = MessagingConfiguration.shared.storage
|
||||
if (TextSecurePreferences.getConfigurationMessageSynced(context)) return
|
||||
if (message.sender != storage.getUserPublicKey()) return
|
||||
if (TextSecurePreferences.getConfigurationMessageSynced(context) && !TextSecurePreferences.shouldUpdateProfile(context, message.sentTimestamp!!)) return
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
if (userPublicKey == null || message.sender != storage.getUserPublicKey()) return
|
||||
TextSecurePreferences.setConfigurationMessageSynced(context, true)
|
||||
TextSecurePreferences.setLastProfileUpdateTime(context, message.sentTimestamp!!)
|
||||
val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys()
|
||||
for (closeGroup in message.closedGroups) {
|
||||
if (allClosedGroupPublicKeys.contains(closeGroup.publicKey)) continue
|
||||
@ -103,8 +108,20 @@ private fun MessageReceiver.handleConfigurationMessage(message: ConfigurationMes
|
||||
if (allOpenGroups.contains(openGroup)) continue
|
||||
storage.addOpenGroup(openGroup, 1)
|
||||
}
|
||||
// TODO: in future handle the latest in config messages
|
||||
TextSecurePreferences.setConfigurationMessageSynced(context, true)
|
||||
if (message.displayName.isNotEmpty()) {
|
||||
TextSecurePreferences.setProfileName(context, message.displayName)
|
||||
storage.setDisplayName(userPublicKey, message.displayName)
|
||||
}
|
||||
if (message.profileKey.isNotEmpty()) {
|
||||
val profileKey = Base64.encodeBytes(message.profileKey)
|
||||
ProfileKeyUtil.setEncodedProfileKey(context, profileKey)
|
||||
storage.setProfileKeyForRecipient(userPublicKey, message.profileKey)
|
||||
// handle profile photo
|
||||
if (!message.profilePicture.isNullOrEmpty() && TextSecurePreferences.getProfilePictureURL(context) != message.profilePicture) {
|
||||
storage.setUserProfilePictureUrl(message.profilePicture!!)
|
||||
}
|
||||
}
|
||||
storage.addContacts(message.contacts)
|
||||
}
|
||||
|
||||
fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalServiceProtos.Content, openGroupID: String?) {
|
||||
@ -112,7 +129,7 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
|
||||
val context = MessagingConfiguration.shared.context
|
||||
// Update profile if needed
|
||||
val newProfile = message.profile
|
||||
if (newProfile != null) {
|
||||
if (newProfile != null && openGroupID.isNullOrEmpty()) {
|
||||
val profileManager = SSKEnvironment.shared.profileManager
|
||||
val recipient = Recipient.from(context, Address.fromSerialized(message.sender!!), false)
|
||||
val displayName = newProfile.displayName!!
|
||||
|
@ -83,10 +83,7 @@ class OpenGroupPoller(private val openGroup: OpenGroup, private val executorServ
|
||||
messages.forEach { message ->
|
||||
try {
|
||||
val senderPublicKey = message.senderPublicKey
|
||||
fun generateDisplayName(rawDisplayName: String): String {
|
||||
return "${rawDisplayName} (${senderPublicKey.takeLast(8)})"
|
||||
}
|
||||
val senderDisplayName = MessagingConfiguration.shared.storage.getOpenGroupDisplayName(senderPublicKey, openGroup.channel, openGroup.server) ?: generateDisplayName("Anonymous")
|
||||
val senderDisplayName = message.displayName
|
||||
val id = openGroup.id.toByteArray()
|
||||
// Main message
|
||||
val dataMessageProto = DataMessage.newBuilder()
|
||||
@ -145,7 +142,7 @@ class OpenGroupPoller(private val openGroup: OpenGroup, private val executorServ
|
||||
val messageServerID = message.serverID
|
||||
// Profile
|
||||
val profileProto = DataMessage.LokiProfile.newBuilder()
|
||||
profileProto.setDisplayName(message.displayName)
|
||||
profileProto.setDisplayName(senderDisplayName)
|
||||
val profilePicture = message.profilePicture
|
||||
if (profilePicture != null) {
|
||||
profileProto.setProfilePicture(profilePicture.url)
|
||||
|
Loading…
x
Reference in New Issue
Block a user