2020-05-11 16:19:26 +10:00
|
|
|
package org.thoughtcrime.securesms.loki.protocol
|
|
|
|
|
|
|
|
import android.content.Context
|
2020-05-13 10:24:20 +10:00
|
|
|
import org.thoughtcrime.securesms.ApplicationContext
|
2020-05-12 16:28:35 +10:00
|
|
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore
|
2020-05-11 16:19:26 +10:00
|
|
|
import org.thoughtcrime.securesms.database.Address
|
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
2020-05-13 12:29:31 +10:00
|
|
|
import org.thoughtcrime.securesms.loki.utilities.recipient
|
2020-05-11 16:19:26 +10:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient
|
|
|
|
import org.thoughtcrime.securesms.sms.MessageSender
|
|
|
|
import org.thoughtcrime.securesms.util.GroupUtil
|
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
2020-05-12 16:28:35 +10:00
|
|
|
import org.whispersystems.libsignal.SignalProtocolAddress
|
2020-05-13 12:29:31 +10:00
|
|
|
import org.whispersystems.signalservice.api.messages.SignalServiceContent
|
2020-05-12 16:28:35 +10:00
|
|
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup
|
|
|
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
2020-05-12 15:29:00 +10:00
|
|
|
import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol
|
2020-05-22 10:41:31 +10:00
|
|
|
import java.util.*
|
2020-05-11 16:19:26 +10:00
|
|
|
|
|
|
|
object ClosedGroupsProtocol {
|
|
|
|
|
2020-05-12 16:28:35 +10:00
|
|
|
@JvmStatic
|
2020-05-13 12:29:31 +10:00
|
|
|
fun shouldIgnoreContentMessage(context: Context, conversation: Recipient, groupID: String?, content: SignalServiceContent): Boolean {
|
|
|
|
if (!conversation.address.isClosedGroup || groupID == null) { return false }
|
2020-05-14 11:44:33 +10:00
|
|
|
// A closed group's members should never include slave devices
|
2020-05-13 12:29:31 +10:00
|
|
|
val senderPublicKey = content.sender
|
|
|
|
val senderMasterPublicKey = MultiDeviceProtocol.shared.getMasterDevice(senderPublicKey)
|
|
|
|
val publicKeyToCheckFor = senderMasterPublicKey ?: senderPublicKey
|
|
|
|
val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupID, true)
|
|
|
|
return !members.contains(recipient(context, publicKeyToCheckFor))
|
|
|
|
}
|
|
|
|
|
|
|
|
@JvmStatic
|
|
|
|
fun shouldIgnoreGroupCreatedMessage(context: Context, group: SignalServiceGroup): Boolean {
|
2020-05-12 16:28:35 +10:00
|
|
|
val members = group.members
|
2020-05-13 12:29:31 +10:00
|
|
|
val userMasterDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
|
|
|
return !members.isPresent || !members.get().contains(userMasterDevice)
|
2020-05-12 16:28:35 +10:00
|
|
|
}
|
|
|
|
|
2020-05-12 15:29:00 +10:00
|
|
|
@JvmStatic
|
|
|
|
fun getDestinations(groupID: String, context: Context): List<Address> {
|
|
|
|
if (GroupUtil.isRSSFeed(groupID)) { return listOf() }
|
|
|
|
if (GroupUtil.isOpenGroup(groupID)) {
|
|
|
|
val result = mutableListOf<Address>()
|
|
|
|
result.add(Address.fromSerialized(groupID))
|
|
|
|
return result
|
|
|
|
} else {
|
2020-05-13 12:29:31 +10:00
|
|
|
// A closed group's members should never include slave devices
|
2020-05-12 15:29:00 +10:00
|
|
|
val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupID, false)
|
2020-05-13 12:29:31 +10:00
|
|
|
val destinations = members.flatMap { member ->
|
2020-05-12 15:29:00 +10:00
|
|
|
MultiDeviceProtocol.shared.getAllLinkedDevices(member.address.serialize()).map { Address.fromSerialized(it) }
|
|
|
|
}.toMutableSet()
|
2020-05-13 12:29:31 +10:00
|
|
|
val userMasterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
|
|
|
if (userMasterPublicKey != null && destinations.contains(Address.fromSerialized(userMasterPublicKey))) {
|
|
|
|
destinations.remove(Address.fromSerialized(userMasterPublicKey))
|
2020-05-12 15:29:00 +10:00
|
|
|
}
|
|
|
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
2020-05-13 12:29:31 +10:00
|
|
|
if (userPublicKey != null && destinations.contains(Address.fromSerialized(userPublicKey))) {
|
|
|
|
destinations.remove(Address.fromSerialized(userPublicKey))
|
2020-05-12 15:29:00 +10:00
|
|
|
}
|
2020-05-13 12:29:31 +10:00
|
|
|
return destinations.toList()
|
2020-05-12 15:29:00 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@JvmStatic
|
2020-05-11 16:19:26 +10:00
|
|
|
fun leaveGroup(context: Context, recipient: Recipient): Boolean {
|
2020-05-11 16:54:31 +10:00
|
|
|
if (!recipient.address.isClosedGroup) { return true }
|
2020-05-11 16:19:26 +10:00
|
|
|
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
|
|
val message = GroupUtil.createGroupLeaveMessage(context, recipient)
|
|
|
|
if (threadID < 0 || !message.isPresent) { return false }
|
|
|
|
MessageSender.send(context, message.get(), threadID, false, null)
|
2020-05-13 12:29:31 +10:00
|
|
|
// Remove the master device from the group (a closed group's members should never include slave devices)
|
2020-05-11 16:54:31 +10:00
|
|
|
val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
2020-05-13 12:29:31 +10:00
|
|
|
val publicKeyToRemove = masterPublicKey ?: TextSecurePreferences.getLocalNumber(context)
|
2020-05-11 16:19:26 +10:00
|
|
|
val groupDatabase = DatabaseFactory.getGroupDatabase(context)
|
|
|
|
val groupID = recipient.address.toGroupString()
|
|
|
|
groupDatabase.setActive(groupID, false)
|
2020-05-13 12:29:31 +10:00
|
|
|
groupDatabase.remove(groupID, Address.fromSerialized(publicKeyToRemove))
|
2020-05-11 16:19:26 +10:00
|
|
|
return true
|
|
|
|
}
|
2020-05-12 16:28:35 +10:00
|
|
|
|
|
|
|
@JvmStatic
|
|
|
|
fun establishSessionsWithMembersIfNeeded(context: Context, members: List<String>) {
|
2020-05-13 12:29:31 +10:00
|
|
|
// A closed group's members should never include slave devices
|
2020-05-12 16:28:35 +10:00
|
|
|
val allDevices = members.flatMap { member ->
|
|
|
|
MultiDeviceProtocol.shared.getAllLinkedDevices(member)
|
|
|
|
}.toMutableSet()
|
2020-05-13 12:29:31 +10:00
|
|
|
val userMasterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context)
|
|
|
|
if (userMasterPublicKey != null && allDevices.contains(userMasterPublicKey)) {
|
|
|
|
allDevices.remove(userMasterPublicKey)
|
2020-05-12 16:28:35 +10:00
|
|
|
}
|
|
|
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
|
|
|
if (userPublicKey != null && allDevices.contains(userPublicKey)) {
|
|
|
|
allDevices.remove(userPublicKey)
|
|
|
|
}
|
|
|
|
for (device in allDevices) {
|
2020-05-13 12:29:31 +10:00
|
|
|
val deviceAsAddress = SignalProtocolAddress(device, SignalServiceAddress.DEFAULT_DEVICE_ID)
|
|
|
|
val hasSession = TextSecureSessionStore(context).containsSession(deviceAsAddress)
|
|
|
|
if (hasSession) { continue }
|
2020-05-22 10:41:31 +10:00
|
|
|
DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestTimestamp(device, Date().time)
|
2020-05-13 12:29:31 +10:00
|
|
|
val sessionRequest = EphemeralMessage.createSessionRequest(device)
|
|
|
|
ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRequest))
|
2020-05-12 16:28:35 +10:00
|
|
|
}
|
|
|
|
}
|
2020-05-11 16:19:26 +10:00
|
|
|
}
|