|
|
|
@ -25,6 +25,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup
|
|
|
|
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup.GroupType
|
|
|
|
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos
|
|
|
|
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext
|
|
|
|
|
import org.whispersystems.signalservice.loki.api.SnodeAPI
|
|
|
|
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupRatchet
|
|
|
|
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.ClosedGroupSenderKey
|
|
|
|
|
import org.whispersystems.signalservice.loki.protocol.closedgroups.SharedSenderKeysImplementation
|
|
|
|
@ -39,6 +40,12 @@ object ClosedGroupsProtocol {
|
|
|
|
|
val isSharedSenderKeysEnabled = true
|
|
|
|
|
val groupSizeLimit = 20
|
|
|
|
|
|
|
|
|
|
sealed class Error(val description: String) : Exception() {
|
|
|
|
|
object NoThread : Error("Couldn't find a thread associated with the given group public key")
|
|
|
|
|
object NoPrivateKey : Error("Couldn't find a private key associated with the given group public key.")
|
|
|
|
|
object InvalidUpdate : Error("Invalid group update.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public fun createClosedGroup(context: Context, name: String, members: Collection<String>): Promise<String, Exception> {
|
|
|
|
|
val deferred = deferred<String, Exception>()
|
|
|
|
|
Thread {
|
|
|
|
@ -98,10 +105,12 @@ object ClosedGroupsProtocol {
|
|
|
|
|
val name = group.title
|
|
|
|
|
val oldMembers = group.members.map { it.serialize() }.toSet()
|
|
|
|
|
val newMembers = oldMembers.minus(userPublicKey)
|
|
|
|
|
update(context, groupPublicKey, newMembers, name)
|
|
|
|
|
return update(context, groupPublicKey, newMembers, name).get()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public fun update(context: Context, groupPublicKey: String, members: Collection<String>, name: String) {
|
|
|
|
|
public fun update(context: Context, groupPublicKey: String, members: Collection<String>, name: String): Promise<Unit, Exception> {
|
|
|
|
|
val deferred = deferred<Unit, Exception>()
|
|
|
|
|
Thread {
|
|
|
|
|
val userPublicKey = TextSecurePreferences.getLocalNumber(context)
|
|
|
|
|
val sskDatabase = DatabaseFactory.getSSKDatabase(context)
|
|
|
|
|
val groupDB = DatabaseFactory.getGroupDatabase(context)
|
|
|
|
@ -109,7 +118,7 @@ object ClosedGroupsProtocol {
|
|
|
|
|
val group = groupDB.getGroup(groupID).orNull()
|
|
|
|
|
if (group == null) {
|
|
|
|
|
Log.d("Loki", "Can't update nonexistent closed group.")
|
|
|
|
|
return
|
|
|
|
|
return@Thread deferred.reject(Error.NoThread)
|
|
|
|
|
}
|
|
|
|
|
val oldMembers = group.members.map { it.serialize() }.toSet()
|
|
|
|
|
val newMembers = members.minus(oldMembers)
|
|
|
|
@ -119,7 +128,7 @@ object ClosedGroupsProtocol {
|
|
|
|
|
val groupPrivateKey = DatabaseFactory.getSSKDatabase(context).getClosedGroupPrivateKey(groupPublicKey)
|
|
|
|
|
if (groupPrivateKey == null) {
|
|
|
|
|
Log.d("Loki", "Couldn't get private key for closed group.")
|
|
|
|
|
return
|
|
|
|
|
return@Thread deferred.reject(Error.NoPrivateKey)
|
|
|
|
|
}
|
|
|
|
|
val wasAnyUserRemoved = members.toSet().intersect(oldMembers) != oldMembers.toSet()
|
|
|
|
|
val removedMembers = oldMembers.minus(members)
|
|
|
|
@ -128,7 +137,7 @@ object ClosedGroupsProtocol {
|
|
|
|
|
if (wasAnyUserRemoved) {
|
|
|
|
|
if (isUserLeaving && removedMembers.count() != 1) {
|
|
|
|
|
Log.d("Loki", "Can't remove self and others simultaneously.")
|
|
|
|
|
return
|
|
|
|
|
return@Thread deferred.reject(Error.InvalidUpdate)
|
|
|
|
|
}
|
|
|
|
|
// Establish sessions if needed
|
|
|
|
|
establishSessionsWithMembersIfNeeded(context, members)
|
|
|
|
@ -215,6 +224,9 @@ object ClosedGroupsProtocol {
|
|
|
|
|
val infoType = if (isUserLeaving) GroupContext.Type.QUIT else GroupContext.Type.UPDATE
|
|
|
|
|
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
|
|
|
|
|
insertOutgoingInfoMessage(context, groupID, infoType, name, members, admins, threadID)
|
|
|
|
|
deferred.resolve(Unit)
|
|
|
|
|
}.start()
|
|
|
|
|
return deferred.promise
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@JvmStatic
|
|
|
|
|