clean group util

This commit is contained in:
Ryan ZHAO 2021-01-22 10:33:19 +11:00
parent 6fa2c308b5
commit d4781e64a3
15 changed files with 64 additions and 60 deletions

View File

@ -122,19 +122,20 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
return new Reader(cursor);
}
public String getOrCreateGroupForMembers(List<Address> members, boolean mms, List<Address> admins) {
// This function always creates a mms group
public String getOrCreateGroupForMembers(List<Address> members, List<Address> admins) {
Collections.sort(members);
Collections.sort(admins);
Cursor cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {GROUP_ID},
MEMBERS + " = ? AND " + MMS + " = ?",
new String[] {Address.Companion.toSerializedList(members, ','), mms ? "1" : "0"},
new String[] {Address.Companion.toSerializedList(members, ','), "1"},
null, null, null);
try {
if (cursor != null && cursor.moveToNext()) {
return cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
} else {
String groupId = GroupUtil.INSTANCE.getEncodedGroupID(allocateGroupId());
String groupId = GroupUtil.getEncodedMMSGroupID(allocateGroupId());
create(groupId, null, members, null, null, admins);
return groupId;
}

View File

@ -221,7 +221,7 @@ public class SmsMigrator {
memberAddresses.add(recipient.getAddress());
}
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, true, null);
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, null);
Recipient ourGroupRecipient = Recipient.from(context, Address.Companion.fromSerialized(ourGroupId), true);
long ourThreadId = threadDatabase.getOrCreateThreadIdFor(ourGroupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);

View File

@ -322,12 +322,12 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: SignalServiceProtos.GroupContext.Type, type1: SignalServiceGroup.Type, name: String, members: Collection<String>, admins: Collection<String>) {
val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
.setType(type0)
.setName(name)
.addAllMembers(members)
.addAllAdmins(admins)
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray()), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, System.currentTimeMillis(), "", Optional.of(group), 0, true)
val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), "")
val smsDB = DatabaseFactory.getSmsDatabase(context)
@ -337,7 +337,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String, members: Collection<String>, admins: Collection<String>, threadID: Long) {
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
.setType(type)
.setName(name)
.addAllMembers(members)

View File

@ -52,12 +52,11 @@ public class GroupManager {
@NonNull Set<Recipient> members,
@Nullable Bitmap avatar,
@Nullable String name,
boolean mms,
@NonNull Set<Recipient> admins)
{
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
String id = GroupUtil.getEncodedGroupID(database.allocateGroupId());
return createGroup(id, context, members, avatar, name, mms, admins);
String id = GroupUtil.getEncodedClosedGroupID(database.allocateGroupId()); // TODO: The group id is double encoded here 1
return createGroup(id, context, members, avatar, name, admins);
}
public static @NonNull GroupActionResult createGroup(@NonNull String id,
@ -65,12 +64,11 @@ public class GroupManager {
@NonNull Set<Recipient> members,
@Nullable Bitmap avatar,
@Nullable String name,
boolean mms,
@NonNull Set<Recipient> admins)
{
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
final String groupId = GroupUtil.getEncodedGroupID(id.getBytes());
final String groupId = GroupUtil.getEncodedClosedGroupID(id.getBytes()); // TODO: The group id is double encoded here 2
final Recipient groupRecipient = Recipient.from(context, Address.Companion.fromSerialized(groupId), false);
final Set<Address> memberAddresses = getMemberAddresses(members);
final Set<Address> adminAddresses = getMemberAddresses(admins);
@ -81,15 +79,9 @@ public class GroupManager {
memberAddresses.add(Address.Companion.fromSerialized(masterPublicKey));
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses));
if (!mms) {
groupDatabase.updateProfilePicture(groupId, avatarBytes);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses);
} else {
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(
groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
return new GroupActionResult(groupRecipient, threadId);
}
groupDatabase.updateProfilePicture(groupId, avatarBytes);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
return sendGroupUpdate(context, groupId, memberAddresses, name, avatarBytes, adminAddresses);
}
public static @NonNull GroupActionResult createOpenGroup(@NonNull String id,
@ -190,7 +182,7 @@ public class GroupManager {
}
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupId.getBytes())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupId)))
.setType(GroupContext.Type.UPDATE)
.addAllMembers(numbers)
.addAllAdmins(adminNumbers);

View File

@ -248,7 +248,7 @@ public class MmsDownloadJob extends BaseJob {
}
if (members.size() > 2) {
group = Optional.of(Address.Companion.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true, new LinkedList<>())));
group = Optional.of(Address.Companion.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), new LinkedList<>())));
}
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, false);

View File

@ -1082,7 +1082,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (typingMessage.getGroupId().isPresent()) {
// Typing messages should only apply to closed groups, thus we use `getEncodedId`
Address groupAddress = Address.Companion.fromSerialized(GroupUtil.getEncodedGroupID(typingMessage.getGroupId().get()));
Address groupAddress = Address.Companion.fromSerialized(GroupUtil.getEncodedClosedGroupID(typingMessage.getGroupId().get()));
Recipient groupRecipient = Recipient.from(context, groupAddress, false);
threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(groupRecipient);
@ -1267,7 +1267,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
private Recipient getMessageDestination(SignalServiceContent content, SignalServiceDataMessage message) {
if (message.getGroupInfo().isPresent()) {
return Recipient.from(context, Address.Companion.fromExternal(context, GroupUtil.getEncodedGroupID(message.getGroupInfo().get().getGroupId())), false);
return Recipient.from(context, Address.Companion.fromExternal(context, GroupUtil.getEncodedClosedGroupID(message.getGroupInfo().get().getGroupId())), false);
} else {
return Recipient.from(context, Address.Companion.fromExternal(context, content.getSender()), false);
}

View File

@ -262,7 +262,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
GroupContext groupContext = groupMessage.getGroupContext();
SignalServiceAttachment avatar = attachmentPointers.isEmpty() ? null : attachmentPointers.get(0);
SignalServiceGroup.Type type = groupMessage.isGroupQuit() ? SignalServiceGroup.Type.QUIT : SignalServiceGroup.Type.UPDATE;
SignalServiceGroup group = new SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupId.getBytes()), groupType, groupContext.getName(), groupContext.getMembersList(), avatar, groupContext.getAdminsList());
SignalServiceGroup group = new SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupId), groupType, groupContext.getName(), groupContext.getMembersList(), avatar, groupContext.getAdminsList());
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
.withTimestamp(message.getSentTimeMillis())
.withExpiration(message.getRecipient().getExpireMessages())
@ -271,7 +271,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
return messageSender.sendMessage(messageId, addresses, unidentifiedAccess, groupDataMessage);
} else {
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedGroupIDAsData(groupId.getBytes()), groupType);
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedGroupIDAsData(groupId), groupType);
SignalServiceDataMessage groupMessage = SignalServiceDataMessage.newBuilder()
.withTimestamp(message.getSentTimeMillis())
.asGroupMessage(group)

View File

@ -69,7 +69,7 @@ public class PushGroupUpdateJob extends BaseJob implements InjectableType {
@Override
public @NonNull Data serialize() {
return new Data.Builder().putString(KEY_SOURCE, source)
.putString(KEY_GROUP_ID, GroupUtil.getEncodedGroupID(groupId))
.putString(KEY_GROUP_ID, GroupUtil.getEncodedClosedGroupID(groupId))
.build();
}
@ -81,7 +81,7 @@ public class PushGroupUpdateJob extends BaseJob implements InjectableType {
@Override
public void onRun() throws IOException, UntrustedIdentityException {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
Optional<GroupRecord> record = groupDatabase.getGroup(GroupUtil.getEncodedGroupID(groupId));
Optional<GroupRecord> record = groupDatabase.getGroup(GroupUtil.getEncodedClosedGroupID(groupId));
SignalServiceAttachment avatar = null;
if (record == null) {
@ -115,7 +115,7 @@ public class PushGroupUpdateJob extends BaseJob implements InjectableType {
.withName(record.get().getTitle())
.build();
Address groupAddress = Address.Companion.fromSerialized(GroupUtil.getEncodedGroupID(groupId));
Address groupAddress = Address.Companion.fromSerialized(GroupUtil.getEncodedClosedGroupID(groupId));
Recipient groupRecipient = Recipient.from(context, groupAddress, false);
SignalServiceDataMessage message = SignalServiceDataMessage.newBuilder()
@ -145,7 +145,7 @@ public class PushGroupUpdateJob extends BaseJob implements InjectableType {
public @NonNull PushGroupUpdateJob create(@NonNull Parameters parameters, @NonNull org.thoughtcrime.securesms.jobmanager.Data data) {
return new PushGroupUpdateJob(parameters,
data.getString(KEY_SOURCE),
GroupUtil.getDecodedGroupIDAsData(data.getString(KEY_GROUP_ID).getBytes()));
GroupUtil.getDecodedGroupIDAsData(data.getString(KEY_GROUP_ID)));
}
}
}

View File

@ -60,7 +60,7 @@ public class RequestGroupInfoJob extends BaseJob implements InjectableType {
@Override
public @NonNull Data serialize() {
return new Data.Builder().putString(KEY_SOURCE, source)
.putString(KEY_GROUP_ID, GroupUtil.getEncodedGroupID(groupId))
.putString(KEY_GROUP_ID, GroupUtil.getEncodedClosedGroupID(groupId))
.build();
}
@ -101,7 +101,7 @@ public class RequestGroupInfoJob extends BaseJob implements InjectableType {
public @NonNull RequestGroupInfoJob create(@NonNull Parameters parameters, @NonNull Data data) {
return new RequestGroupInfoJob(parameters,
data.getString(KEY_SOURCE),
GroupUtil.getDecodedGroupIDAsData(data.getString(KEY_GROUP_ID).getBytes()));
GroupUtil.getDecodedGroupIDAsData(data.getString(KEY_GROUP_ID)));
}
}
}

View File

@ -90,7 +90,7 @@ public class TypingSendJob extends BaseJob implements InjectableType {
if (recipient.isGroupRecipient()) {
recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), false);
groupId = Optional.of(GroupUtil.getDecodedGroupIDAsData(recipient.getAddress().toGroupString().getBytes()));
groupId = Optional.of(GroupUtil.getDecodedGroupIDAsData(recipient.getAddress().toGroupString()));
}
List<SignalServiceAddress> addresses = Stream.of(recipients).map(r -> new SignalServiceAddress(r.getAddress().serialize())).toList();

View File

@ -170,7 +170,7 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM
override fun doInBackground(vararg params: Void?): Optional<GroupManager.GroupActionResult> {
val activity = activity.get() ?: return Optional.absent()
return Optional.of(GroupManager.createGroup(activity, members, profilePicture, name, false, admins))
return Optional.of(GroupManager.createGroup(activity, members, profilePicture, name, admins))
}
override fun onPostExecute(result: Optional<GroupManager.GroupActionResult>) {

View File

@ -549,12 +549,12 @@ object ClosedGroupsProtocol {
private fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: GroupContext.Type, type1: SignalServiceGroup.Type,
name: String, members: Collection<String>, admins: Collection<String>) {
val groupContextBuilder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
.setType(type0)
.setName(name)
.addAllMembers(members)
.addAllAdmins(admins)
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray()), GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, System.currentTimeMillis(), "", Optional.of(group), 0, true)
val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), "")
val smsDB = DatabaseFactory.getSmsDatabase(context)
@ -565,7 +565,7 @@ object ClosedGroupsProtocol {
members: Collection<String>, admins: Collection<String>, threadID: Long) {
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
val groupContextBuilder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
.setType(type)
.setName(name)
.addAllMembers(members)
@ -581,13 +581,13 @@ object ClosedGroupsProtocol {
@JvmStatic
@Throws(IOException::class)
public fun doubleEncodeGroupID(groupPublicKey: String): String {
return GroupUtil.getEncodedGroupID(GroupUtil.getEncodedGroupID(Hex.fromStringCondensed(groupPublicKey)).toByteArray())
return GroupUtil.getEncodedClosedGroupID(GroupUtil.getEncodedClosedGroupID(groupPublicKey))
}
@JvmStatic
@Throws(IOException::class)
public fun doubleDecodeGroupID(groupID: String): ByteArray {
return GroupUtil.getDecodedGroupIDAsData(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray()))
return GroupUtil.getDecodedGroupIDAsData(GroupUtil.getDecodedGroupID(groupID))
}
@WorkerThread
@ -600,7 +600,7 @@ object ClosedGroupsProtocol {
}
val decodedGroupId: ByteString
try {
decodedGroupId = ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(encodedGroupId.toByteArray()))
decodedGroupId = ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(encodedGroupId))
} catch (e: IOException) {
Log.w("Loki", "Failed to decode group ID.", e)
return null

View File

@ -375,12 +375,12 @@ object ClosedGroupsProtocolV2 {
private fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: SignalServiceProtos.GroupContext.Type, type1: SignalServiceGroup.Type,
name: String, members: Collection<String>, admins: Collection<String>) {
val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
.setType(type0)
.setName(name)
.addAllMembers(members)
.addAllAdmins(admins)
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray()), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList())
val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, System.currentTimeMillis(), "", Optional.of(group), 0, true)
val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), "")
val smsDB = DatabaseFactory.getSmsDatabase(context)
@ -391,7 +391,7 @@ object ClosedGroupsProtocolV2 {
members: Collection<String>, admins: Collection<String>, threadID: Long) {
val recipient = Recipient.from(context, Address.fromSerialized(groupID), false)
val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder()
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray())))
.setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID)))
.setType(type)
.setName(name)
.addAllMembers(members)
@ -407,12 +407,12 @@ object ClosedGroupsProtocolV2 {
@JvmStatic
@Throws(IOException::class)
public fun doubleEncodeGroupID(groupPublicKey: String): String {
return GroupUtil.getEncodedGroupID(GroupUtil.getEncodedGroupID(Hex.fromStringCondensed(groupPublicKey)).toByteArray())
return GroupUtil.getEncodedClosedGroupID(GroupUtil.getEncodedClosedGroupID(groupPublicKey))
}
@JvmStatic
@Throws(IOException::class)
public fun doubleDecodeGroupID(groupID: String): ByteArray {
return GroupUtil.getDecodedGroupIDAsData(GroupUtil.getDecodedGroupIDAsData(groupID.toByteArray()))
return GroupUtil.getDecodedGroupIDAsData(GroupUtil.getDecodedGroupID(groupID))
}
}

View File

@ -14,7 +14,7 @@ class GroupRecord(
var admins: List<Address> = LinkedList<Address>()
fun getId(): ByteArray {
return try {
GroupUtil.getDecodedGroupIDAsData(encodedId.toByteArray())
GroupUtil.getDecodedGroupIDAsData(encodedId)
} catch (ioe: IOException) {
throw AssertionError(ioe)
}

View File

@ -5,6 +5,7 @@ import org.session.libsession.messaging.threads.Address.Companion.fromSerialized
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.messaging.threads.recipients.RecipientModifiedListener
import org.session.libsignal.libsignal.logging.Log
import org.session.libsignal.libsignal.util.Hex
import org.session.libsignal.service.api.messages.SignalServiceGroup
import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext
import java.io.IOException
@ -21,7 +22,12 @@ object GroupUtil {
}
fun getEncodedOpenGroupIDAsData(groupID: String): ByteArray {
return (OPEN_GROUP_PREFIX + groupID).toByteArray()
return Hex.fromStringCondensed(getEncodedOpenGroupID(groupID))
}
@JvmStatic
fun getEncodedClosedGroupID(groupID: ByteArray): String {
return getEncodedClosedGroupID(Hex.toStringCondensed(groupID))
}
fun getEncodedClosedGroupID(groupID: String): String {
@ -29,7 +35,12 @@ object GroupUtil {
}
fun getEncodedClosedGroupIDAsData(groupID: String): ByteArray {
return (CLOSED_GROUP_PREFIX + groupID).toByteArray()
return Hex.fromStringCondensed(getEncodedClosedGroupID(groupID))
}
@JvmStatic
fun getEncodedMMSGroupID(groupID: ByteArray): String {
return getEncodedMMSGroupID(Hex.toStringCondensed(groupID))
}
fun getEncodedMMSGroupID(groupID: String): String {
@ -41,31 +52,31 @@ object GroupUtil {
}
@JvmStatic
fun getEncodedId(group: SignalServiceGroup): String? {
fun getEncodedId(group: SignalServiceGroup): String {
val groupId = group.groupId
if (group.groupType == SignalServiceGroup.GroupType.PUBLIC_CHAT) {
return getEncodedOpenGroupID(groupId.toString())
}
return getEncodedGroupID(groupId)
return getEncodedClosedGroupID(Hex.toStringCondensed(groupId))
}
@JvmStatic
fun getEncodedGroupID(groupID: ByteArray): String {
return groupID.toString()
fun getDecodedGroupID(groupID: String): String {
if (groupID.split("!").count() > 1) {
return groupID.split("!")[1]
}
return groupID.split("!")[0]
}
@JvmStatic
fun getDecodedGroupID(groupID: ByteArray): String {
val encodedGroupID = groupID.toString()
if (encodedGroupID.split("!").count() > 1) {
return encodedGroupID.split("!")[1]
}
return encodedGroupID.split("!")[0]
val encodedGroupID = Hex.toStringCondensed(groupID)
return getDecodedGroupID(encodedGroupID)
}
@JvmStatic
fun getDecodedGroupIDAsData(groupID: ByteArray): ByteArray {
return getDecodedGroupID(groupID).toByteArray()
fun getDecodedGroupIDAsData(groupID: String): ByteArray {
return Hex.fromStringCondensed(getDecodedGroupID(groupID))
}
fun isEncodedGroup(groupId: String): Boolean {