kopia lustrzana https://github.com/ryukoposting/Signal-Android
226 wiersze
9.1 KiB
Kotlin
226 wiersze
9.1 KiB
Kotlin
package org.thoughtcrime.securesms.database
|
|
|
|
import com.google.protobuf.ByteString
|
|
import org.signal.storageservice.protos.groups.AccessControl
|
|
import org.signal.storageservice.protos.groups.GroupChange
|
|
import org.signal.storageservice.protos.groups.Member
|
|
import org.signal.storageservice.protos.groups.local.DecryptedGroup
|
|
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange
|
|
import org.signal.storageservice.protos.groups.local.DecryptedMember
|
|
import org.signal.storageservice.protos.groups.local.DecryptedPendingMember
|
|
import org.signal.storageservice.protos.groups.local.DecryptedRequestingMember
|
|
import org.signal.storageservice.protos.groups.local.DecryptedString
|
|
import org.signal.storageservice.protos.groups.local.DecryptedTimer
|
|
import org.signal.storageservice.protos.groups.local.EnabledState
|
|
import org.signal.zkgroup.groups.GroupMasterKey
|
|
import org.thoughtcrime.securesms.groups.GroupId
|
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
|
import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupHistoryEntry
|
|
import org.whispersystems.signalservice.api.groupsv2.GroupHistoryPage
|
|
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations
|
|
import org.whispersystems.signalservice.api.push.DistributionId
|
|
import org.whispersystems.signalservice.api.push.ServiceId
|
|
import java.util.Optional
|
|
|
|
fun DecryptedGroupChange.Builder.setNewDescription(description: String) {
|
|
newDescription = DecryptedString.newBuilder().setValue(description).build()
|
|
}
|
|
|
|
fun DecryptedGroupChange.Builder.setNewTitle(title: String) {
|
|
newTitle = DecryptedString.newBuilder().setValue(title).build()
|
|
}
|
|
|
|
class ChangeLog(private val revision: Int) {
|
|
var groupSnapshot: DecryptedGroup? = null
|
|
var groupChange: DecryptedGroupChange? = null
|
|
|
|
fun change(init: DecryptedGroupChange.Builder.() -> Unit) {
|
|
val builder = DecryptedGroupChange.newBuilder().setRevision(revision)
|
|
builder.init()
|
|
groupChange = builder.build()
|
|
}
|
|
|
|
fun fullSnapshot(
|
|
extendGroup: DecryptedGroup? = null,
|
|
title: String = extendGroup?.title ?: "",
|
|
avatar: String = extendGroup?.avatar ?: "",
|
|
description: String = extendGroup?.description ?: "",
|
|
accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl.getDefaultInstance(),
|
|
members: List<DecryptedMember> = extendGroup?.membersList ?: emptyList(),
|
|
pendingMembers: List<DecryptedPendingMember> = extendGroup?.pendingMembersList ?: emptyList(),
|
|
requestingMembers: List<DecryptedRequestingMember> = extendGroup?.requestingMembersList ?: emptyList(),
|
|
inviteLinkPassword: ByteArray = extendGroup?.inviteLinkPassword?.toByteArray() ?: ByteArray(0),
|
|
disappearingMessageTimer: DecryptedTimer = extendGroup?.disappearingMessagesTimer ?: DecryptedTimer.getDefaultInstance()
|
|
) {
|
|
groupSnapshot = decryptedGroup(revision, title, avatar, description, accessControl, members, pendingMembers, requestingMembers, inviteLinkPassword, disappearingMessageTimer)
|
|
}
|
|
}
|
|
|
|
class ChangeSet {
|
|
private val changeSet: MutableList<ChangeLog> = mutableListOf()
|
|
|
|
fun changeLog(revision: Int, init: ChangeLog.() -> Unit) {
|
|
val entry = ChangeLog(revision)
|
|
entry.init()
|
|
changeSet += entry
|
|
}
|
|
|
|
fun toApiResponse(): GroupHistoryPage {
|
|
return GroupHistoryPage(changeSet.map { DecryptedGroupHistoryEntry(Optional.ofNullable(it.groupSnapshot), Optional.ofNullable(it.groupChange)) }, GroupHistoryPage.PagingData.NONE)
|
|
}
|
|
}
|
|
|
|
class GroupChangeData(private val revision: Int, private val groupOperations: GroupsV2Operations.GroupOperations) {
|
|
private val groupChangeBuilder: GroupChange.Builder = GroupChange.newBuilder()
|
|
private val actionsBuilder: GroupChange.Actions.Builder = GroupChange.Actions.newBuilder()
|
|
var changeEpoch: Int = GroupsV2Operations.HIGHEST_KNOWN_EPOCH
|
|
|
|
val groupChange: GroupChange
|
|
get() {
|
|
return groupChangeBuilder
|
|
.setChangeEpoch(changeEpoch)
|
|
.setActions(actionsBuilder.setRevision(revision).build().toByteString())
|
|
.build()
|
|
}
|
|
|
|
fun source(serviceId: ServiceId) {
|
|
actionsBuilder.sourceUuid = groupOperations.encryptUuid(serviceId.uuid())
|
|
}
|
|
|
|
fun deleteMember(serviceId: ServiceId) {
|
|
actionsBuilder.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder().setDeletedUserId(groupOperations.encryptUuid(serviceId.uuid())))
|
|
}
|
|
|
|
fun modifyRole(serviceId: ServiceId, role: Member.Role) {
|
|
actionsBuilder.addModifyMemberRoles(GroupChange.Actions.ModifyMemberRoleAction.newBuilder().setUserId(groupOperations.encryptUuid(serviceId.uuid())).setRole(role))
|
|
}
|
|
}
|
|
|
|
class GroupStateTestData(private val masterKey: GroupMasterKey, private val groupOperations: GroupsV2Operations.GroupOperations? = null) {
|
|
|
|
var localState: DecryptedGroup? = null
|
|
var groupRecord: Optional<GroupDatabase.GroupRecord> = Optional.empty()
|
|
var serverState: DecryptedGroup? = null
|
|
var changeSet: ChangeSet? = null
|
|
var groupChange: GroupChange? = null
|
|
var includeFirst: Boolean = false
|
|
var requestedRevision: Int = 0
|
|
|
|
fun localState(
|
|
revision: Int = 0,
|
|
title: String = "",
|
|
avatar: String = "",
|
|
description: String = "",
|
|
accessControl: AccessControl = AccessControl.getDefaultInstance(),
|
|
members: List<DecryptedMember> = emptyList(),
|
|
pendingMembers: List<DecryptedPendingMember> = emptyList(),
|
|
requestingMembers: List<DecryptedRequestingMember> = emptyList(),
|
|
inviteLinkPassword: ByteArray = ByteArray(0),
|
|
disappearingMessageTimer: DecryptedTimer = DecryptedTimer.getDefaultInstance()
|
|
) {
|
|
localState = decryptedGroup(revision, title, avatar, description, accessControl, members, pendingMembers, requestingMembers, inviteLinkPassword, disappearingMessageTimer)
|
|
groupRecord = groupRecord(masterKey, localState!!)
|
|
}
|
|
|
|
fun serverState(
|
|
revision: Int,
|
|
extendGroup: DecryptedGroup? = null,
|
|
title: String = extendGroup?.title ?: "",
|
|
avatar: String = extendGroup?.avatar ?: "",
|
|
description: String = extendGroup?.description ?: "",
|
|
accessControl: AccessControl = extendGroup?.accessControl ?: AccessControl.getDefaultInstance(),
|
|
members: List<DecryptedMember> = extendGroup?.membersList ?: emptyList(),
|
|
pendingMembers: List<DecryptedPendingMember> = extendGroup?.pendingMembersList ?: emptyList(),
|
|
requestingMembers: List<DecryptedRequestingMember> = extendGroup?.requestingMembersList ?: emptyList(),
|
|
inviteLinkPassword: ByteArray = extendGroup?.inviteLinkPassword?.toByteArray() ?: ByteArray(0),
|
|
disappearingMessageTimer: DecryptedTimer = extendGroup?.disappearingMessagesTimer ?: DecryptedTimer.getDefaultInstance()
|
|
) {
|
|
serverState = decryptedGroup(revision, title, avatar, description, accessControl, members, pendingMembers, requestingMembers, inviteLinkPassword, disappearingMessageTimer)
|
|
}
|
|
|
|
fun changeSet(init: ChangeSet.() -> Unit) {
|
|
val changeSet = ChangeSet()
|
|
changeSet.init()
|
|
this.changeSet = changeSet
|
|
}
|
|
|
|
fun apiCallParameters(requestedRevision: Int, includeFirst: Boolean) {
|
|
this.requestedRevision = requestedRevision
|
|
this.includeFirst = includeFirst
|
|
}
|
|
|
|
fun groupChange(revision: Int, init: GroupChangeData.() -> Unit) {
|
|
val groupChangeData = GroupChangeData(revision, groupOperations!!)
|
|
groupChangeData.init()
|
|
this.groupChange = groupChangeData.groupChange
|
|
}
|
|
}
|
|
|
|
fun groupRecord(
|
|
masterKey: GroupMasterKey,
|
|
decryptedGroup: DecryptedGroup,
|
|
id: GroupId = GroupId.v2(masterKey),
|
|
recipientId: RecipientId = RecipientId.from(100),
|
|
members: String = "1",
|
|
unmigratedV1Members: String? = null,
|
|
avatarId: Long = 1,
|
|
avatarKey: ByteArray = ByteArray(0),
|
|
avatarContentType: String = "",
|
|
relay: String = "",
|
|
active: Boolean = true,
|
|
avatarDigest: ByteArray = ByteArray(0),
|
|
mms: Boolean = false,
|
|
distributionId: DistributionId? = null
|
|
): Optional<GroupDatabase.GroupRecord> {
|
|
return Optional.of(
|
|
GroupDatabase.GroupRecord(
|
|
id,
|
|
recipientId,
|
|
decryptedGroup.title,
|
|
members,
|
|
unmigratedV1Members,
|
|
avatarId,
|
|
avatarKey,
|
|
avatarContentType,
|
|
relay,
|
|
active,
|
|
avatarDigest,
|
|
mms,
|
|
masterKey.serialize(),
|
|
decryptedGroup.revision,
|
|
decryptedGroup.toByteArray(),
|
|
distributionId
|
|
)
|
|
)
|
|
}
|
|
|
|
fun decryptedGroup(
|
|
revision: Int = 0,
|
|
title: String = "",
|
|
avatar: String = "",
|
|
description: String = "",
|
|
accessControl: AccessControl = AccessControl.getDefaultInstance(),
|
|
members: List<DecryptedMember> = emptyList(),
|
|
pendingMembers: List<DecryptedPendingMember> = emptyList(),
|
|
requestingMembers: List<DecryptedRequestingMember> = emptyList(),
|
|
inviteLinkPassword: ByteArray = ByteArray(0),
|
|
disappearingMessageTimer: DecryptedTimer = DecryptedTimer.getDefaultInstance()
|
|
): DecryptedGroup {
|
|
|
|
val builder = DecryptedGroup.newBuilder()
|
|
.setAccessControl(accessControl)
|
|
.setAvatar(avatar)
|
|
.setAvatarBytes(ByteString.EMPTY)
|
|
.setDescription(description)
|
|
.setDisappearingMessagesTimer(disappearingMessageTimer)
|
|
.setInviteLinkPassword(ByteString.copyFrom(inviteLinkPassword))
|
|
.setIsAnnouncementGroup(EnabledState.DISABLED)
|
|
.setTitle(title)
|
|
.setRevision(revision)
|
|
.addAllMembers(members)
|
|
.addAllPendingMembers(pendingMembers)
|
|
.addAllRequestingMembers(requestingMembers)
|
|
|
|
return builder.build()
|
|
}
|