diff --git a/app/src/main/java/org/thoughtcrime/securesms/AppContext.kt b/app/src/main/java/org/thoughtcrime/securesms/AppContext.kt new file mode 100644 index 0000000000..206e794605 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/AppContext.kt @@ -0,0 +1,20 @@ +package org.thoughtcrime.securesms + +import android.util.Log +import nl.komponents.kovenant.Kovenant +import nl.komponents.kovenant.jvm.asDispatcher +import org.session.libsignal.utilities.ThreadUtils +import java.util.concurrent.Executors + +object AppContext { + + fun configureKovenant() { + Kovenant.context { + callbackContext.dispatcher = Executors.newSingleThreadExecutor().asDispatcher() + workerContext.dispatcher = ThreadUtils.executorPool.asDispatcher() + multipleCompletion = { v1, v2 -> + Log.d("Loki", "Promise resolved more than once (first with $v1, then with $v2); ignoring $v2.") + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index e5b8b7fd5a..33e55e18d3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -49,7 +49,7 @@ import org.session.libsession.utilities.dynamiclanguage.DynamicLanguageContextWr import org.session.libsession.utilities.dynamiclanguage.LocaleParser; import org.session.libsession.utilities.preferences.ProfileKeyUtil; import org.session.libsignal.service.api.util.StreamDetails; -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol; +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol; import org.session.libsignal.utilities.logging.Log; import org.signal.aesgcmprovider.AesGcmProvider; import org.thoughtcrime.securesms.components.TypingStatusSender; @@ -93,7 +93,6 @@ import org.webrtc.voiceengine.WebRtcAudioUtils; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.security.SecureRandom; import java.security.Security; import java.util.Date; @@ -104,6 +103,7 @@ import dagger.ObjectGraph; import kotlin.Unit; import kotlinx.coroutines.Job; import network.loki.messenger.BuildConfig; +import nl.komponents.kovenant.Kovenant; import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant; import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant; @@ -164,6 +164,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc ProcessLifecycleOwner.get().getLifecycle().addObserver(this); // Loki // ======== + AppContext.INSTANCE.configureKovenant(); messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier()); broadcaster = new Broadcaster(this); threadNotificationHandler = new Handler(Looper.getMainLooper()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 80a6ffb5d8..56e44d6b25 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -95,7 +95,7 @@ import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.MediaTypes; import org.session.libsignal.libsignal.InvalidMessageException; import org.session.libsignal.libsignal.util.guava.Optional; -import org.session.libsignal.service.loki.utilities.mentions.Mention; +import org.session.libsignal.service.loki.Mention; import org.session.libsignal.service.loki.utilities.HexEncodingKt; import org.session.libsignal.service.loki.utilities.PublicKeyValidation; import org.thoughtcrime.securesms.ApplicationContext; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java index 790b215003..7f3d0cd97f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -25,10 +25,9 @@ import org.session.libsession.utilities.Util; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer; -import org.session.libsignal.service.loki.database.LokiOpenGroupDatabaseProtocol; +import org.session.libsignal.service.loki.LokiOpenGroupDatabaseProtocol; import java.io.Closeable; -import java.io.IOException; import java.security.SecureRandom; import java.util.Collections; import java.util.LinkedList; @@ -44,6 +43,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt static final String GROUP_ID = "group_id"; private static final String TITLE = "title"; private static final String MEMBERS = "members"; + private static final String ZOMBIE_MEMBERS = "zombie_members"; private static final String AVATAR = "avatar"; private static final String AVATAR_ID = "avatar_id"; private static final String AVATAR_KEY = "avatar_key"; @@ -64,6 +64,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt GROUP_ID + " TEXT, " + TITLE + " TEXT, " + MEMBERS + " TEXT, " + + ZOMBIE_MEMBERS + " TEXT, " + AVATAR + " BLOB, " + AVATAR_ID + " INTEGER, " + AVATAR_KEY + " BLOB, " + @@ -81,7 +82,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt }; private static final String[] GROUP_PROJECTION = { - GROUP_ID, TITLE, MEMBERS, AVATAR, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST, + GROUP_ID, TITLE, MEMBERS, ZOMBIE_MEMBERS, AVATAR, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST, TIMESTAMP, ACTIVE, MMS, AVATAR_URL, ADMINS }; @@ -162,7 +163,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt } public @NonNull List getGroupMembers(String groupId, boolean includeSelf) { - List
members = getCurrentMembers(groupId); + List
members = getCurrentMembers(groupId, false); List recipients = new LinkedList<>(); for (Address member : members) { @@ -177,6 +178,17 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt return recipients; } + public @NonNull List getGroupZombieMembers(String groupId) { + List
members = getCurrentZombieMembers(groupId); + List recipients = new LinkedList<>(); + + for (Address member : members) { + recipients.add(Recipient.from(context, member, false)); + } + + return recipients; + } + public long create(@NonNull String groupId, @Nullable String title, @NonNull List
members, @Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List
admins, @NonNull Long formationTimestamp) { @@ -300,6 +312,16 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt }); } + public void updateZombieMembers(String groupId, List
members) { + Collections.sort(members); + + ContentValues contents = new ContentValues(); + contents.put(ZOMBIE_MEMBERS, Address.toSerializedList(members, ',')); + contents.put(ACTIVE, 1); + databaseHelper.getWritableDatabase().update(TABLE_NAME, contents, GROUP_ID + " = ?", + new String[] {groupId}); + } + public void updateAdmins(String groupId, List
admins) { Collections.sort(admins); @@ -311,7 +333,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt } public void removeMember(String groupId, Address source) { - List
currentMembers = getCurrentMembers(groupId); + List
currentMembers = getCurrentMembers(groupId, false); currentMembers.remove(source); ContentValues contents = new ContentValues(); @@ -329,18 +351,22 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt }); } - private List
getCurrentMembers(String groupId) { + private List
getCurrentMembers(String groupId, boolean zombieMembers) { Cursor cursor = null; + String membersColumn = MEMBERS; + if (zombieMembers) membersColumn = ZOMBIE_MEMBERS; + try { - cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {MEMBERS}, + cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {membersColumn}, GROUP_ID + " = ?", new String[] {groupId}, null, null, null); if (cursor != null && cursor.moveToFirst()) { - String serializedMembers = cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)); - return Address.fromSerializedList(serializedMembers, ','); + String serializedMembers = cursor.getString(cursor.getColumnIndexOrThrow(membersColumn)); + if (serializedMembers != null && !serializedMembers.isEmpty()) + return Address.fromSerializedList(serializedMembers, ','); } return new LinkedList<>(); @@ -350,6 +376,10 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt } } + private List
getCurrentZombieMembers(String groupId) { + return getCurrentMembers(groupId, true); + } + public boolean isActive(String groupId) { Optional record = getGroup(groupId); return record.isPresent() && record.get().isActive(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index d3cb7a874c..eb3b43b224 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -391,6 +391,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, DatabaseFactory.getGroupDatabase(context).setActive(groupID, value) } + override fun getZombieMember(groupID: String): Set { + return DatabaseFactory.getGroupDatabase(context).getGroupZombieMembers(groupID).map { it.address.serialize() }.toHashSet() + } + override fun removeMember(groupID: String, member: Address) { DatabaseFactory.getGroupDatabase(context).removeMember(groupID, member) } @@ -399,6 +403,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, DatabaseFactory.getGroupDatabase(context).updateMembers(groupID, members) } + override fun updateZombieMembers(groupID: String, members: List
) { + DatabaseFactory.getGroupDatabase(context).updateZombieMembers(groupID, members) + } + override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) { val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 88d8c679f3..82a2044884 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -54,9 +54,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int lokiV20 = 41; private static final int lokiV21 = 42; private static final int lokiV22 = 43; + private static final int lokiV23 = 44; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes - private static final int DATABASE_VERSION = lokiV22; + private static final int DATABASE_VERSION = lokiV23; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -272,6 +273,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { "SendDeliveryReceiptJob"); } + if (oldVersion < lokiV23) { + db.execSQL("ALTER TABLE groups ADD COLUMN zombie_members TEXT"); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt index e969819d07..88c89f7319 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupActivity.kt @@ -37,8 +37,14 @@ import java.io.IOException class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { private val originalMembers = HashSet() + private val zombies = HashSet() private val members = HashSet() + private val allMembers: Set + get() { + return members + zombies + } private var hasNameChanged = false + private var isSelfAdmin = false private var isLoading = false set(newValue) { field = newValue; invalidateOptionsMenu() } @@ -54,7 +60,10 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { } private val memberListAdapter by lazy { - EditClosedGroupMembersAdapter(this, GlideApp.with(this), this::onMemberClick) + if (isSelfAdmin) + EditClosedGroupMembersAdapter(this, GlideApp.with(this), isSelfAdmin, this::onMemberClick) + else + EditClosedGroupMembersAdapter(this, GlideApp.with(this), isSelfAdmin) } private lateinit var mainContentContainer: LinearLayout @@ -81,7 +90,10 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { ThemeUtil.getThemedDrawableResId(this, R.attr.actionModeCloseDrawable)) groupID = intent.getStringExtra(groupIDKey)!! - originalName = DatabaseFactory.getGroupDatabase(this).getGroup(groupID).get().title + val groupInfo = DatabaseFactory.getGroupDatabase(this).getGroup(groupID).get() + originalName = groupInfo.title + isSelfAdmin = groupInfo.admins.any{ it.serialize() == TextSecurePreferences.getLocalNumber(this) } + name = originalName mainContentContainer = findViewById(R.id.mainContentContainer) @@ -116,31 +128,35 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { } } - LoaderManager.getInstance(this).initLoader(loaderID, null, object : LoaderManager.LoaderCallbacks> { + LoaderManager.getInstance(this).initLoader(loaderID, null, object : LoaderManager.LoaderCallbacks { - override fun onCreateLoader(id: Int, bundle: Bundle?): Loader> { + override fun onCreateLoader(id: Int, bundle: Bundle?): Loader { return EditClosedGroupLoader(this@EditClosedGroupActivity, groupID) } - override fun onLoadFinished(loader: Loader>, members: List) { + override fun onLoadFinished(loader: Loader, groupMembers: GroupMembers) { // We no longer need any subsequent loading events // (they will occur on every activity resume). LoaderManager.getInstance(this@EditClosedGroupActivity).destroyLoader(loaderID) + members.clear() + members.addAll(groupMembers.members.toHashSet()) + zombies.clear() + zombies.addAll(groupMembers.zombieMembers.toHashSet()) originalMembers.clear() - originalMembers.addAll(members.toHashSet()) - updateMembers(originalMembers) + originalMembers.addAll(members + zombies) + updateMembers() } - override fun onLoaderReset(loader: Loader>) { - updateMembers(setOf()) + override fun onLoaderReset(loader: Loader) { + updateMembers() } }) } override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_edit_closed_group, menu) - return members.isNotEmpty() && !isLoading + return allMembers.isNotEmpty() && !isLoading } // endregion @@ -153,8 +169,8 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { if (data == null || data.extras == null || !data.hasExtra(SelectContactsActivity.selectedContactsKey)) return val selectedContacts = data.extras!!.getStringArray(SelectContactsActivity.selectedContactsKey)!!.toSet() - val changedMembers = members + selectedContacts - updateMembers(changedMembers) + members.addAll(selectedContacts) + updateMembers() } } } @@ -173,17 +189,12 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { } } - private fun updateMembers(members: Set) { - this.members.clear() - this.members.addAll(members) - memberListAdapter.setMembers(members) + private fun updateMembers() { + memberListAdapter.setMembers(allMembers) + memberListAdapter.setZombieMembers(zombies) - val admins = DatabaseFactory.getGroupDatabase(this).getGroup(groupID).get().admins.map { it.toString() }.toMutableSet() - admins.remove(TextSecurePreferences.getLocalNumber(this)) - memberListAdapter.setLockedMembers(admins) - - mainContentContainer.visibility = if (members.isEmpty()) View.GONE else View.VISIBLE - emptyStateContainer.visibility = if (members.isEmpty()) View.VISIBLE else View.GONE + mainContentContainer.visibility = if (allMembers.isEmpty()) View.GONE else View.VISIBLE + emptyStateContainer.visibility = if (allMembers.isEmpty()) View.VISIBLE else View.GONE invalidateOptionsMenu() } @@ -200,8 +211,9 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { private fun onMemberClick(member: String) { val bottomSheet = ClosedGroupEditingOptionsBottomSheet() bottomSheet.onRemoveTapped = { - val changedMembers = members - member - updateMembers(changedMembers) + if (zombies.contains(member)) zombies.remove(member) + else members.remove(member) + updateMembers() bottomSheet.dismiss() } bottomSheet.show(supportFragmentManager, "GroupEditingOptionsBottomSheet") @@ -209,7 +221,7 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { private fun onAddMembersClick() { val intent = Intent(this@EditClosedGroupActivity, SelectContactsActivity::class.java) - intent.putExtra(SelectContactsActivity.usersToExcludeKey, members.toTypedArray()) + intent.putExtra(SelectContactsActivity.usersToExcludeKey, allMembers.toTypedArray()) intent.putExtra(SelectContactsActivity.emptyStateTextKey, "No contacts to add") startActivityForResult(intent, addUsersRequestCode) } @@ -229,7 +241,7 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { } private fun commitChanges() { - val hasMemberListChanges = (members != originalMembers) + val hasMemberListChanges = (allMembers != originalMembers) if (!hasNameChanged && !hasMemberListChanges) { return finish() @@ -237,15 +249,13 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { val name = if (hasNameChanged) this.name else originalName - val members = this.members.map { + val members = this.allMembers.map { Recipient.from(this, Address.fromSerialized(it), false) }.toSet() val originalMembers = this.originalMembers.map { Recipient.from(this, Address.fromSerialized(it), false) }.toSet() - val admins = members.toSet() //TODO For now, consider all the users to be admins. - var isClosedGroup: Boolean var groupPublicKey: String? try { @@ -303,4 +313,6 @@ class EditClosedGroupActivity : PassphraseRequiredActionBarActivity() { } } } + + class GroupMembers(val members: List, val zombieMembers: List) { } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupLoader.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupLoader.kt index 4f49501fc6..d2bb17a732 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupLoader.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupLoader.kt @@ -4,12 +4,19 @@ import android.content.Context import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.util.AsyncLoader -class EditClosedGroupLoader(context: Context, val groupID: String) : AsyncLoader>(context) { +class EditClosedGroupLoader(context: Context, val groupID: String) : AsyncLoader(context) { - override fun loadInBackground(): List { - val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupID, true) - return members.map { - it.address.toString() - } + override fun loadInBackground(): EditClosedGroupActivity.GroupMembers { + val groupDatabase = DatabaseFactory.getGroupDatabase(context) + val members = groupDatabase.getGroupMembers(groupID, true) + val zombieMembers = groupDatabase.getGroupZombieMembers(groupID) + return EditClosedGroupActivity.GroupMembers( + members.map { + it.address.toString() + }, + zombieMembers.map { + it.address.toString() + } + ) } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt index 3c07136f1a..7d5ed34086 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/EditClosedGroupMembersAdapter.kt @@ -7,15 +7,17 @@ import org.session.libsession.messaging.threads.Address import org.thoughtcrime.securesms.loki.views.UserView import org.thoughtcrime.securesms.mms.GlideRequests import org.session.libsession.messaging.threads.recipients.Recipient +import org.session.libsession.utilities.TextSecurePreferences class EditClosedGroupMembersAdapter( private val context: Context, private val glide: GlideRequests, + private val admin: Boolean, private val memberClickListener: ((String) -> Unit)? = null ) : RecyclerView.Adapter() { private val members = ArrayList() - private val lockedMembers = HashSet() + private val zombieMembers = ArrayList() fun setMembers(members: Collection) { this.members.clear() @@ -23,9 +25,9 @@ class EditClosedGroupMembersAdapter( notifyDataSetChanged() } - fun setLockedMembers(members: Collection) { - this.lockedMembers.clear() - this.lockedMembers.addAll(members) + fun setZombieMembers(members: Collection) { + this.zombieMembers.clear() + this.zombieMembers.addAll(members) notifyDataSetChanged() } @@ -39,15 +41,20 @@ class EditClosedGroupMembersAdapter( override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { val member = members[position] - val lockedMember = lockedMembers.contains(member) + val unlocked = admin && member != TextSecurePreferences.getLocalNumber(context) viewHolder.view.bind(Recipient.from( context, Address.fromSerialized(member), false), glide, - if (lockedMember) UserView.ActionIndicator.None else UserView.ActionIndicator.Menu) + if (unlocked) UserView.ActionIndicator.Menu else UserView.ActionIndicator.None) - if (!lockedMember) { + if (zombieMembers.contains(member)) + viewHolder.view.alpha = 0.5F + else + viewHolder.view.alpha = 1F + + if (unlocked) { viewHolder.view.setOnClickListener { this.memberClickListener?.invoke(member) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt index 6f3ef464bc..cc878e4beb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/LinkDeviceActivity.kt @@ -27,7 +27,7 @@ import kotlinx.coroutines.launch import network.loki.messenger.R import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.libsignal.util.KeyHelper -import org.session.libsignal.service.loki.crypto.MnemonicCodec +import org.session.libsignal.service.loki.MnemonicCodec import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.logging.Log diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt index 24d160f880..0ee7e0f574 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt @@ -15,7 +15,7 @@ import kotlinx.android.synthetic.main.activity_recovery_phrase_restore.* import network.loki.messenger.R import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.libsignal.util.KeyHelper -import org.session.libsignal.service.loki.crypto.MnemonicCodec +import org.session.libsignal.service.loki.MnemonicCodec import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey import org.session.libsignal.utilities.Hex import org.thoughtcrime.securesms.BaseActionBarActivity diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt index 2c79b4fc87..9ee8025335 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/SeedActivity.kt @@ -16,7 +16,7 @@ import org.session.libsession.utilities.IdentityKeyUtil import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities import org.thoughtcrime.securesms.loki.utilities.getColorWithID import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.service.loki.crypto.MnemonicCodec +import org.session.libsignal.service.loki.MnemonicCodec import org.session.libsignal.service.loki.utilities.hexEncodedPrivateKey class SeedActivity : BaseActionBarActivity() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt index 0501b0be36..a39cbb0aca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt @@ -9,11 +9,11 @@ import nl.komponents.kovenant.all import nl.komponents.kovenant.functional.map import org.session.libsession.messaging.jobs.MessageReceiveJob import org.session.libsession.messaging.open_groups.OpenGroup +import org.session.libsession.messaging.sending_receiving.pollers.ClosedGroupPoller import org.session.libsession.messaging.sending_receiving.pollers.OpenGroupPoller import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.logging.Log -import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.DatabaseFactory import java.io.IOException import java.util.concurrent.TimeUnit @@ -79,7 +79,7 @@ class BackgroundPollWorker(val context: Context, params: WorkerParameters) : Wor promises.addAll(privateChatsPromise.get()) // Closed groups - promises.addAll(ApplicationContext.getInstance(context).closedGroupPoller.pollOnce()) + promises.addAll(ClosedGroupPoller().pollOnce()) // Open Groups val openGroups = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { (_,chat)-> diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt index 58b9aeeec7..06da1f0676 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt @@ -8,7 +8,7 @@ import org.session.libsignal.libsignal.ecc.DjbECPrivateKey import org.session.libsignal.libsignal.ecc.DjbECPublicKey import org.session.libsignal.libsignal.ecc.ECKeyPair import org.session.libsignal.service.loki.Snode -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol import org.session.libsignal.service.loki.utilities.PublicKeyValidation import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.toHexString diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt index 66c1907405..1da93f7ec3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.loki.database import android.content.ContentValues import android.content.Context -import org.session.libsession.messaging.threads.Address import org.thoughtcrime.securesms.database.Database import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper @@ -10,7 +9,7 @@ import org.thoughtcrime.securesms.loki.utilities.get import org.thoughtcrime.securesms.loki.utilities.getInt import org.thoughtcrime.securesms.loki.utilities.getString import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate -import org.session.libsignal.service.loki.database.LokiMessageDatabaseProtocol +import org.session.libsignal.service.loki.LokiMessageDatabaseProtocol class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt index 05e5f666db..cea0f52d9f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt @@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.loki.utilities.get import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate import org.session.libsession.messaging.threads.recipients.Recipient import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol +import org.session.libsignal.service.loki.LokiUserDatabaseProtocol class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiUserDatabaseProtocol { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt index 12446cf57b..d327efe973 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/dialogs/SeedDialog.kt @@ -15,7 +15,7 @@ import kotlinx.android.synthetic.main.dialog_seed.view.* import network.loki.messenger.R import org.session.libsession.utilities.IdentityKeyUtil import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities -import org.session.libsignal.service.loki.crypto.MnemonicCodec +import org.session.libsignal.service.loki.MnemonicCodec import org.session.libsignal.service.loki.utilities.hexEncodedPrivateKey diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index 7b699c0780..f25833902e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -7,19 +7,8 @@ import org.session.libsession.messaging.messages.Destination import org.session.libsession.messaging.messages.control.ConfigurationMessage import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.messaging.threads.Address -import org.session.libsession.messaging.threads.recipients.Recipient import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsession.utilities.preferences.ProfileKeyUtil -import org.session.libsignal.service.internal.push.SignalServiceProtos -import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage -import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded -import org.session.libsignal.utilities.Base64 -import org.session.libsignal.utilities.Hex -import org.thoughtcrime.securesms.ApplicationContext -import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob import org.thoughtcrime.securesms.loki.utilities.ContactUtilities -import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities object MultiDeviceProtocol { @@ -51,80 +40,4 @@ object MultiDeviceProtocol { TextSecurePreferences.setLastConfigurationSyncTime(context, System.currentTimeMillis()) } - // TODO: remove this after we migrate to new message receiving pipeline - @JvmStatic - fun handleConfigurationMessage(context: Context, content: SignalServiceProtos.Content, senderPublicKey: String, timestamp: Long) { - synchronized(this) { - val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return - if (TextSecurePreferences.getConfigurationMessageSynced(context) && !TextSecurePreferences.shouldUpdateProfile(context, timestamp)) return - if (senderPublicKey != userPublicKey) return - TextSecurePreferences.setConfigurationMessageSynced(context, true) - TextSecurePreferences.setLastProfileUpdateTime(context, timestamp) - - val configurationMessage = ConfigurationMessage.fromProto(content) ?: return - - val storage = MessagingModuleConfiguration.shared.storage - val allClosedGroupPublicKeys = storage.getAllClosedGroupPublicKeys() - - val threadDatabase = DatabaseFactory.getThreadDatabase(context) - val recipientDatabase = DatabaseFactory.getRecipientDatabase(context) - - val ourRecipient = Recipient.from(context, Address.fromSerialized(userPublicKey),false) - - for (closedGroup in configurationMessage.closedGroups) { - if (allClosedGroupPublicKeys.contains(closedGroup.publicKey)) continue - - val closedGroupUpdate = DataMessage.ClosedGroupControlMessage.newBuilder() - closedGroupUpdate.type = DataMessage.ClosedGroupControlMessage.Type.NEW - closedGroupUpdate.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(closedGroup.publicKey)) - closedGroupUpdate.name = closedGroup.name - val encryptionKeyPair = SignalServiceProtos.KeyPair.newBuilder() - encryptionKeyPair.publicKey = ByteString.copyFrom(closedGroup.encryptionKeyPair!!.publicKey.serialize().removing05PrefixIfNeeded()) - encryptionKeyPair.privateKey = ByteString.copyFrom(closedGroup.encryptionKeyPair!!.privateKey.serialize()) - closedGroupUpdate.encryptionKeyPair = encryptionKeyPair.build() - closedGroupUpdate.addAllMembers(closedGroup.members.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) - closedGroupUpdate.addAllAdmins(closedGroup.admins.map { ByteString.copyFrom(Hex.fromStringCondensed(it)) }) - - ClosedGroupsProtocolV2.handleNewClosedGroup(context, closedGroupUpdate.build(), userPublicKey, timestamp) - } - val allOpenGroups = storage.getAllOpenGroups().map { it.value.server } - for (openGroup in configurationMessage.openGroups) { - if (allOpenGroups.contains(openGroup)) continue - OpenGroupUtilities.addGroup(context, openGroup, 1) - } - if (configurationMessage.displayName.isNotEmpty()) { - TextSecurePreferences.setProfileName(context, configurationMessage.displayName) - recipientDatabase.setProfileName(ourRecipient, configurationMessage.displayName) - } - if (configurationMessage.profileKey.isNotEmpty()) { - val profileKey = Base64.encodeBytes(configurationMessage.profileKey) - ProfileKeyUtil.setEncodedProfileKey(context, profileKey) - recipientDatabase.setProfileKey(ourRecipient, configurationMessage.profileKey) - if (!configurationMessage.profilePicture.isNullOrEmpty() && TextSecurePreferences.getProfilePictureURL(context) != configurationMessage.profilePicture) { - TextSecurePreferences.setProfilePictureURL(context, configurationMessage.profilePicture) - ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(ourRecipient, configurationMessage.profilePicture)) - } - } - for (contact in configurationMessage.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 (configurationMessage.contacts.isNotEmpty()) { - threadDatabase.notifyUpdatedFromConfig() - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/Broadcaster.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/Broadcaster.kt index 5156ff2572..dfc42c9340 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/Broadcaster.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/Broadcaster.kt @@ -3,8 +3,9 @@ package org.thoughtcrime.securesms.loki.utilities import android.content.Context import android.content.Intent import androidx.localbroadcastmanager.content.LocalBroadcastManager +import org.session.libsignal.service.loki.Broadcaster -class Broadcaster(private val context: Context) : org.session.libsignal.service.loki.utilities.Broadcaster { +class Broadcaster(private val context: Context) : Broadcaster { override fun broadcast(event: String) { val intent = Intent(event) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/MnemonicUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/MnemonicUtilities.kt index 27a2a78cfc..226bb1abfd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/MnemonicUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/MnemonicUtilities.kt @@ -1,10 +1,6 @@ package org.thoughtcrime.securesms.loki.utilities import android.content.Context -import org.session.libsignal.service.loki.crypto.MnemonicCodec -import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded -import java.io.File -import java.io.FileOutputStream object MnemonicUtilities { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateSelectionView.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateSelectionView.kt index ddda015d77..2da55501cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateSelectionView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateSelectionView.kt @@ -10,7 +10,7 @@ import android.widget.ListView import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.mms.GlideRequests -import org.session.libsignal.service.loki.utilities.mentions.Mention +import org.session.libsignal.service.loki.Mention class MentionCandidateSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) { private var mentionCandidates = listOf() diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt index f7af85ed13..f353402806 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt @@ -9,7 +9,7 @@ import android.widget.LinearLayout import kotlinx.android.synthetic.main.view_mention_candidate.view.* import network.loki.messenger.R import org.session.libsession.messaging.open_groups.OpenGroupAPI -import org.session.libsignal.service.loki.utilities.mentions.Mention +import org.session.libsignal.service.loki.Mention import org.thoughtcrime.securesms.mms.GlideRequests class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt index c731a354d2..acfa2470da 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt @@ -146,13 +146,13 @@ class ProfilePictureView : RelativeLayout { private fun setProfilePictureIfNeeded(imageView: ImageView, publicKey: String, displayName: String?, @DimenRes sizeResId: Int) { if (publicKey.isNotEmpty()) { val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false) - if (imagesCached.contains(recipient.profileAvatar.orEmpty())) return + if (imagesCached.contains(publicKey)) return val signalProfilePicture = recipient.contactPhoto if (signalProfilePicture != null && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "0" && (signalProfilePicture as? ProfileContactPhoto)?.avatarObject != "") { glide.clear(imageView) glide.load(signalProfilePicture).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC).circleCrop().into(imageView) - imagesCached.add(recipient.profileAvatar.orEmpty()) + imagesCached.add(publicKey) } else { val sizeInPX = resources.getDimensionPixelSize(sizeResId) glide.clear(imageView) @@ -162,7 +162,7 @@ class ProfilePictureView : RelativeLayout { publicKey, displayName )).diskCacheStrategy(DiskCacheStrategy.ALL).circleCrop().into(imageView) - imagesCached.add(recipient.profileAvatar.orEmpty()) + imagesCached.add(publicKey) } } else { imageView.setImageDrawable(null) diff --git a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt index b905d25cda..5bca1cee6b 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt @@ -108,8 +108,10 @@ interface StorageProtocol { fun createGroup(groupID: String, title: String?, members: List
, avatar: SignalServiceAttachmentPointer?, relay: String?, admins: List
, formationTimestamp: Long) fun isGroupActive(groupPublicKey: String): Boolean fun setActive(groupID: String, value: Boolean) + fun getZombieMember(groupID: String): Set fun removeMember(groupID: String, member: Address) fun updateMembers(groupID: String, members: List
) + fun updateZombieMembers(groupID: String, members: List
) // Closed Group fun getAllClosedGroupPublicKeys(): Set fun getAllActiveClosedGroupPublicKeys(): Set diff --git a/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerAPI.kt b/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerAPI.kt index 5e78caf6f0..b4a1861875 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerAPI.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/file_server/FileServerAPI.kt @@ -8,7 +8,7 @@ import org.session.libsession.snode.OnionRequestAPI import org.session.libsignal.utilities.logging.Log import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.JsonUtil -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol import org.session.libsignal.service.loki.utilities.* import java.net.URL diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt index ffdf459693..2d16b7b9b9 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt @@ -14,7 +14,7 @@ import org.session.libsignal.service.internal.crypto.PaddingInputStream import org.session.libsignal.service.internal.push.PushAttachmentData import org.session.libsignal.service.internal.push.http.AttachmentCipherOutputStreamFactory import org.session.libsignal.service.internal.util.Util -import org.session.libsignal.service.loki.utilities.PlaintextOutputStreamFactory +import org.session.libsignal.service.loki.PlaintextOutputStreamFactory import org.session.libsignal.utilities.logging.Log class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val message: Message, val messageSendJobID: String) : Job { diff --git a/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt b/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt index 715204825a..e421489b19 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/mentions/MentionsManager.kt @@ -1,9 +1,9 @@ package org.session.libsession.messaging.mentions import org.session.libsession.messaging.MessagingModuleConfiguration -import org.session.libsignal.service.loki.utilities.mentions.Mention +import org.session.libsignal.service.loki.Mention -import org.session.libsignal.service.loki.database.LokiUserDatabaseProtocol +import org.session.libsignal.service.loki.LokiUserDatabaseProtocol class MentionsManager(private val userPublicKey: String, private val userDatabase: LokiUserDatabaseProtocol) { var userPublicKeyCache = mutableMapOf>() // Thread ID to set of user hex encoded public keys diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt index 75af2abd6a..78275ca3b2 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ClosedGroupControlMessage.kt @@ -145,7 +145,7 @@ class ClosedGroupControlMessage() : ControlMessage() { } is Kind.EncryptionKeyPair -> { closedGroupControlMessage.type = DataMessage.ClosedGroupControlMessage.Type.ENCRYPTION_KEY_PAIR - closedGroupControlMessage.publicKey = kind.publicKey + closedGroupControlMessage.publicKey = kind.publicKey ?: ByteString.EMPTY closedGroupControlMessage.addAllWrappers(kind.wrappers.map { it.toProto() }) } is Kind.NameChange -> { diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPI.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPI.kt index bd70118abd..0aba366d9f 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPI.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroupAPI.kt @@ -21,7 +21,6 @@ import java.util.* object OpenGroupAPI: DotNetAPI() { private val moderators: HashMap>> = hashMapOf() // Server URL to (channel ID to set of moderator IDs) - val sharedContext = Kovenant.createContext() // region Settings private val fallbackBatchCount = 64 @@ -61,7 +60,7 @@ object OpenGroupAPI: DotNetAPI() { parameters["count"] = fallbackBatchCount parameters["include_deleted"] = 0 } - return execute(HTTPVerb.GET, server, "channels/$channel/messages", parameters = parameters).then(sharedContext) { json -> + return execute(HTTPVerb.GET, server, "channels/$channel/messages", parameters = parameters).then { json -> try { val data = json["data"] as List> val messages = data.mapNotNull { message -> @@ -166,7 +165,7 @@ object OpenGroupAPI: DotNetAPI() { } else { parameters["count"] = fallbackBatchCount } - return execute(HTTPVerb.GET, server, "loki/v1/channel/$channel/deletes", parameters = parameters).then(sharedContext) { json -> + return execute(HTTPVerb.GET, server, "loki/v1/channel/$channel/deletes", parameters = parameters).then { json -> try { val deletedMessageServerIDs = (json["data"] as List>).mapNotNull { deletion -> try { @@ -202,7 +201,7 @@ object OpenGroupAPI: DotNetAPI() { retryIfNeeded(maxRetryCount) { Log.d("Loki", "Sending message to open group with ID: $channel on server: $server.") val parameters = signedMessage.toJSON() - execute(HTTPVerb.POST, server, "channels/$channel/messages", parameters = parameters).then(sharedContext) { json -> + execute(HTTPVerb.POST, server, "channels/$channel/messages", parameters = parameters).then { json -> try { val data = json["data"] as Map<*, *> val serverID = (data["id"] as? Long) ?: (data["id"] as? Int)?.toLong() ?: (data["id"] as String).toLong() @@ -255,7 +254,7 @@ object OpenGroupAPI: DotNetAPI() { @JvmStatic fun getModerators(channel: Long, server: String): Promise, Exception> { - return execute(HTTPVerb.GET, server, "loki/v1/channel/$channel/get_moderators").then(sharedContext) { json -> + return execute(HTTPVerb.GET, server, "loki/v1/channel/$channel/get_moderators").then { json -> try { @Suppress("UNCHECKED_CAST") val moderators = json["moderators"] as? List val moderatorsAsSet = moderators.orEmpty().toSet() @@ -276,7 +275,7 @@ object OpenGroupAPI: DotNetAPI() { fun getChannelInfo(channel: Long, server: String): Promise { return retryIfNeeded(maxRetryCount) { val parameters = mapOf( "include_annotations" to 1 ) - execute(HTTPVerb.GET, server, "/channels/$channel", parameters = parameters).then(sharedContext) { json -> + execute(HTTPVerb.GET, server, "/channels/$channel", parameters = parameters).then { json -> try { val data = json["data"] as Map<*, *> val annotations = data["annotations"] as List> @@ -357,7 +356,7 @@ object OpenGroupAPI: DotNetAPI() { @JvmStatic fun getDisplayNames(publicKeys: Set, server: String): Promise, Exception> { - return getUserProfiles(publicKeys, server, false).map(sharedContext) { json -> + return getUserProfiles(publicKeys, server, false).map { json -> val mapping = mutableMapOf() for (user in json) { if (user["username"] != null) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt index 427bf4b832..a7c6dd97f7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroupHandler.kt @@ -169,15 +169,24 @@ fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List { diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index 47f99bcb54..34da1396b7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -111,7 +111,7 @@ private fun MessageReceiver.handleDataExtractionNotification(message: DataExtrac // Configuration message handling -private fun MessageReceiver.handleConfigurationMessage(message: ConfigurationMessage) { +private fun handleConfigurationMessage(message: ConfigurationMessage) { val context = MessagingModuleConfiguration.shared.context val storage = MessagingModuleConfiguration.shared.storage if (TextSecurePreferences.getConfigurationMessageSynced(context) && !TextSecurePreferences.shouldUpdateProfile(context, message.sentTimestamp!!)) return @@ -148,27 +148,25 @@ private fun MessageReceiver.handleConfigurationMessage(message: ConfigurationMes fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalServiceProtos.Content, openGroupID: String?) { val storage = MessagingModuleConfiguration.shared.storage val context = MessagingModuleConfiguration.shared.context + val userPublicKey = storage.getUserPublicKey() // Update profile if needed val newProfile = message.profile - if (newProfile != null) { + if (newProfile != null && openGroupID.isNullOrEmpty() && userPublicKey != message.sender) { val profileManager = SSKEnvironment.shared.profileManager val recipient = Recipient.from(context, Address.fromSerialized(message.sender!!), false) val displayName = newProfile.displayName!! - val userPublicKey = storage.getUserPublicKey() - if (openGroupID == null) { - if (userPublicKey == message.sender) { - // Update the user's local name if the message came from their master device - TextSecurePreferences.setProfileName(context, displayName) - } + if (displayName.isNotEmpty()) { profileManager.setDisplayName(context, recipient, displayName) } - if (recipient.profileKey == null || !MessageDigest.isEqual(recipient.profileKey, newProfile.profileKey)) { + if (newProfile.profileKey?.isNotEmpty() == true && !MessageDigest.isEqual(recipient.profileKey, newProfile.profileKey)) { profileManager.setProfileKey(context, recipient, newProfile.profileKey!!) profileManager.setUnidentifiedAccessMode(context, recipient, Recipient.UnidentifiedAccessMode.UNKNOWN) - val url = newProfile.profilePictureURL.orEmpty() - profileManager.setProfilePictureURL(context, recipient, url) - if (userPublicKey == message.sender) { - profileManager.updateOpenGroupProfilePicturesIfNeeded(context) + val newUrl = newProfile.profilePictureURL + if (!newUrl.isNullOrEmpty()) { + profileManager.setProfilePictureURL(context, recipient, newUrl) + if (userPublicKey == message.sender) { + profileManager.updateOpenGroupProfilePicturesIfNeeded(context) + } } } } @@ -286,7 +284,8 @@ private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGr val storage = MessagingModuleConfiguration.shared.storage val senderPublicKey = message.sender ?: return val kind = message.kind!! as? ClosedGroupControlMessage.Kind.EncryptionKeyPair ?: return - val groupPublicKey = kind.publicKey?.toByteArray()?.toHexString() ?: message.groupPublicKey ?: return + var groupPublicKey = kind.publicKey?.toByteArray()?.toHexString() + if (groupPublicKey.isNullOrEmpty()) groupPublicKey = message.groupPublicKey ?: return val userPublicKey = storage.getUserPublicKey()!! val userKeyPair = storage.getUserX25519KeyPair() // Unwrap the message @@ -300,7 +299,7 @@ private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGr return } if (!group.admins.map { it.toString() }.contains(senderPublicKey)) { - Log.d("Loki", "Ignoring closed group encryption key pair from non-member.") + Log.d("Loki", "Ignoring closed group encryption key pair from non-admin.") return } // Find our wrapper and decrypt it if possible @@ -381,6 +380,7 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo val updateMembers = kind.members.map { it.toByteArray().toHexString() } val newMembers = members + updateMembers storage.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) }) + // Notify the user if (userPublicKey == senderPublicKey) { // sender is a linked device @@ -403,6 +403,11 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo } } +/// Removes the given members from the group IF +/// • it wasn't the admin that was removed (that should happen through a `MEMBER_LEFT` message). +/// • the admin sent the message (only the admin can truly remove members). +/// If we're among the users that were removed, delete all encryption key pairs and the group public key, unsubscribe +/// from push notifications for this closed group, and remove the given members from the zombie list for this group. private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroupControlMessage) { val context = MessagingModuleConfiguration.shared.context val storage = MessagingModuleConfiguration.shared.storage @@ -416,7 +421,7 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup return } if (!group.isActive) { - Log.d("Loki", "Ignoring closed group info message for inactive group") + Log.d("Loki", "Ignoring closed group info message for inactive group.") return } val name = group.title @@ -427,6 +432,18 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup // Users that are part of this remove update val updateMembers = kind.members.map { it.toByteArray().toHexString() } + // Check that the admin wasn't removed + if (updateMembers.contains(admins.first())) { + Log.d("Loki", "Ignoring invalid closed group update.") + return + } + + // Check that the message was sent by the group admin + if (!admins.contains(senderPublicKey)) { + Log.d("Loki", "Ignoring invalid closed group update.") + return + } + if (!isValidGroupUpdate(group, message.sentTimestamp!!, senderPublicKey)) { return } // If admin leaves the group is disbanded val didAdminLeave = admins.any { it in updateMembers } @@ -443,25 +460,34 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup if (didAdminLeave || wasCurrentUserRemoved) { disableLocalGroupAndUnsubscribe(groupPublicKey, groupID, userPublicKey) } else { - val isCurrentUserAdmin = admins.contains(userPublicKey) storage.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) }) - if (isCurrentUserAdmin) { - MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, newMembers) - } } + // update zombie members + val zombies = storage.getZombieMember(groupID) + storage.updateZombieMembers(groupID, zombies.minus(updateMembers).map { Address.fromSerialized(it) }) + val type = if (senderLeft) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.MEMBER_REMOVED // Notify the user - if (userPublicKey == senderPublicKey) { - // sender is a linked device - val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, type, name, updateMembers, admins, threadID, message.sentTimestamp!!) - } else { - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, updateMembers, admins, message.sentTimestamp!!) + // we don't display zombie members in the notification as users have already been notified when those members left + val notificationMembers = updateMembers.minus(zombies) + if (notificationMembers.isNotEmpty()) { + // no notification to display when only zombies have been removed + if (userPublicKey == senderPublicKey) { + // sender is a linked device + val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) + storage.insertOutgoingInfoMessage(context, groupID, type, name, notificationMembers, admins, threadID, message.sentTimestamp!!) + } else { + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, notificationMembers, admins, message.sentTimestamp!!) + } } } +/// If a regular member left: +/// • Mark them as a zombie (to be removed by the admin later). +/// If the admin left: +/// • Unsubscribe from PNs, delete the group public key, etc. as the group will be disbanded. private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupControlMessage) { val context = MessagingModuleConfiguration.shared.context val storage = MessagingModuleConfiguration.shared.storage @@ -494,11 +520,10 @@ private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupCont // admin left the group of linked device left the group disableLocalGroupAndUnsubscribe(groupPublicKey, groupID, userPublicKey) } else { - val isCurrentUserAdmin = admins.contains(userPublicKey) storage.updateMembers(groupID, updatedMemberList.map { Address.fromSerialized(it) }) - if (isCurrentUserAdmin) { - MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, updatedMemberList) - } + // update zombie members + val zombies = storage.getZombieMember(groupID) + storage.updateZombieMembers(groupID, zombies.plus(senderPublicKey).map { Address.fromSerialized(it) }) } // Notify the user if (userLeft) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/DotNetAPI.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/DotNetAPI.kt index 562715a90a..1fac9ca922 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/DotNetAPI.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/DotNetAPI.kt @@ -23,7 +23,7 @@ import org.session.libsignal.service.internal.push.http.DigestingRequestBody import org.session.libsignal.service.internal.push.http.ProfileCipherOutputStreamFactory import org.session.libsignal.utilities.Hex import org.session.libsignal.utilities.JsonUtil -import org.session.libsignal.service.loki.api.utilities.HTTP +import org.session.libsignal.service.loki.HTTP import org.session.libsignal.service.loki.utilities.* import org.session.libsignal.utilities.* import org.session.libsignal.utilities.Base64 diff --git a/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt b/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt index 6a9bd70fdf..ba103ee42c 100644 --- a/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/OnionRequestAPI.kt @@ -12,12 +12,14 @@ import org.session.libsignal.utilities.logging.Log import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.* import org.session.libsignal.service.loki.Snode -import org.session.libsignal.service.loki.api.utilities.* +import org.session.libsignal.service.loki.* import org.session.libsession.utilities.AESGCM.EncryptionResult import org.session.libsignal.utilities.ThreadUtils import org.session.libsession.utilities.getBodyForOnionRequest import org.session.libsession.utilities.getHeadersForOnionRequest -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol +import org.session.libsignal.service.loki.Broadcaster +import org.session.libsignal.service.loki.HTTP +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol import org.session.libsignal.service.loki.utilities.* private typealias Path = List diff --git a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt index afb3050d99..b4209f6ff5 100644 --- a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt @@ -10,9 +10,9 @@ import org.session.libsession.messaging.utilities.MessageWrapper import org.session.libsession.snode.utilities.getRandomElement import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.loki.Snode -import org.session.libsignal.service.loki.api.utilities.HTTP -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol -import org.session.libsignal.service.loki.utilities.Broadcaster +import org.session.libsignal.service.loki.HTTP +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol +import org.session.libsignal.service.loki.Broadcaster import org.session.libsignal.service.loki.utilities.prettifiedDescription import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.retryIfNeeded diff --git a/libsession/src/main/java/org/session/libsession/snode/SnodeModule.kt b/libsession/src/main/java/org/session/libsession/snode/SnodeModule.kt index 95613ffda2..0d9381ab95 100644 --- a/libsession/src/main/java/org/session/libsession/snode/SnodeModule.kt +++ b/libsession/src/main/java/org/session/libsession/snode/SnodeModule.kt @@ -1,7 +1,7 @@ package org.session.libsession.snode -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol -import org.session.libsignal.service.loki.utilities.Broadcaster +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol +import org.session.libsignal.service.loki.Broadcaster class SnodeModule(val storage: LokiAPIDatabaseProtocol, val broadcaster: Broadcaster) { diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/crypto/SignalServiceCipher.java b/libsignal/src/main/java/org/session/libsignal/service/api/crypto/SignalServiceCipher.java index a8c2ca0bd9..5e425464ea 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/api/crypto/SignalServiceCipher.java +++ b/libsignal/src/main/java/org/session/libsignal/service/api/crypto/SignalServiceCipher.java @@ -22,7 +22,6 @@ import org.session.libsignal.service.api.messages.SignalServiceEnvelope; import org.session.libsignal.service.api.messages.SignalServiceGroup; import org.session.libsignal.service.api.messages.SignalServiceReceiptMessage; import org.session.libsignal.service.api.messages.SignalServiceTypingMessage; -import org.session.libsignal.service.api.messages.shared.SharedContact; import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsignal.service.internal.push.PushTransportDetails; import org.session.libsignal.service.internal.push.SignalServiceProtos; @@ -34,7 +33,7 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos.ReceiptMe import org.session.libsignal.service.internal.push.SignalServiceProtos.TypingMessage; import org.session.libsignal.service.loki.api.crypto.SessionProtocol; import org.session.libsignal.service.loki.api.crypto.SessionProtocolUtilities; -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol; +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol; import java.util.ArrayList; import java.util.LinkedList; diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/messages/shared/SharedContact.java b/libsignal/src/main/java/org/session/libsignal/service/api/messages/shared/SharedContact.java index 75ee56835d..6993eb8189 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/api/messages/shared/SharedContact.java +++ b/libsignal/src/main/java/org/session/libsignal/service/api/messages/shared/SharedContact.java @@ -1,6 +1,5 @@ package org.session.libsignal.service.api.messages.shared; - import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.messages.SignalServiceAttachment; diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Broadcaster.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Broadcaster.kt similarity index 66% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Broadcaster.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Broadcaster.kt index 17106c00b8..a251b89459 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Broadcaster.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/Broadcaster.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.utilities +package org.session.libsignal.service.loki interface Broadcaster { diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/api/utilities/HTTP.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/HTTP.kt similarity index 98% rename from libsignal/src/main/java/org/session/libsignal/service/loki/api/utilities/HTTP.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/HTTP.kt index 29d1cddb6e..11e7ed6154 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/api/utilities/HTTP.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/HTTP.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.api.utilities +package org.session.libsignal.service.loki import okhttp3.* import org.session.libsignal.utilities.logging.Log diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/HexEncoding.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/HexEncoding.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/HexEncoding.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/HexEncoding.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiAPIDatabaseProtocol.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiAPIDatabaseProtocol.kt similarity index 97% rename from libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiAPIDatabaseProtocol.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/LokiAPIDatabaseProtocol.kt index d564706ee8..a771b38ef9 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiAPIDatabaseProtocol.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiAPIDatabaseProtocol.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.database +package org.session.libsignal.service.loki import org.session.libsignal.libsignal.ecc.ECKeyPair import org.session.libsignal.service.loki.Snode diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiMessageDatabaseProtocol.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiMessageDatabaseProtocol.kt similarity index 76% rename from libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiMessageDatabaseProtocol.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/LokiMessageDatabaseProtocol.kt index 45f162de63..694d989af7 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiMessageDatabaseProtocol.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiMessageDatabaseProtocol.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.database +package org.session.libsignal.service.loki interface LokiMessageDatabaseProtocol { diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiOpenGroupDatabaseProtocol.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiOpenGroupDatabaseProtocol.kt similarity index 76% rename from libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiOpenGroupDatabaseProtocol.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/LokiOpenGroupDatabaseProtocol.kt index 5380c1a8fe..4c983e33fc 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiOpenGroupDatabaseProtocol.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiOpenGroupDatabaseProtocol.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.database +package org.session.libsignal.service.loki interface LokiOpenGroupDatabaseProtocol { diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiUserDatabaseProtocol.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiUserDatabaseProtocol.kt similarity index 81% rename from libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiUserDatabaseProtocol.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/LokiUserDatabaseProtocol.kt index 6879ee893a..b4428a4edf 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/database/LokiUserDatabaseProtocol.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/LokiUserDatabaseProtocol.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.database +package org.session.libsignal.service.loki interface LokiUserDatabaseProtocol { diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/mentions/Mention.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Mention.kt similarity index 52% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/mentions/Mention.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Mention.kt index 8d97c45268..0dd2165854 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/mentions/Mention.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/Mention.kt @@ -1,3 +1,3 @@ -package org.session.libsignal.service.loki.utilities.mentions +package org.session.libsignal.service.loki data class Mention(val publicKey: String, val displayName: String) diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/crypto/MnemonicCodec.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/MnemonicCodec.kt similarity index 97% rename from libsignal/src/main/java/org/session/libsignal/service/loki/crypto/MnemonicCodec.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/MnemonicCodec.kt index b3c15dd132..122354f33d 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/crypto/MnemonicCodec.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/MnemonicCodec.kt @@ -1,6 +1,5 @@ -package org.session.libsignal.service.loki.crypto +package org.session.libsignal.service.loki -import java.io.File import java.util.zip.CRC32 /** @@ -95,8 +94,10 @@ class MnemonicCodec(private val loadFileContents: (String) -> String) { var result = "" val n = truncatedWordSet.size.toLong() // Check preconditions - if (words.size < 12) { throw DecodingError.InputTooShort } - if (words.size % 3 == 0) { throw DecodingError.MissingLastWord } + if (words.size < 12) { throw DecodingError.InputTooShort + } + if (words.size % 3 == 0) { throw DecodingError.MissingLastWord + } // Get checksum word val checksumWord = words.removeAt(words.lastIndex) // Decode @@ -106,7 +107,8 @@ class MnemonicCodec(private val loadFileContents: (String) -> String) { val w2 = truncatedWordSet.indexOf(words[chunkStartIndex + 1].substring(0 until prefixLength)) val w3 = truncatedWordSet.indexOf(words[chunkStartIndex + 2].substring(0 until prefixLength)) val x = w1 + n * ((n - w1 + w2) % n) + n * n * ((n - w2 + w3) % n) - if (x % n != w1.toLong()) { throw DecodingError.Generic } + if (x % n != w1.toLong()) { throw DecodingError.Generic + } val string = "0000000" + x.toString(16) result += swap(string.substring(string.length - 8 until string.length)) } catch (e: Exception) { @@ -116,7 +118,8 @@ class MnemonicCodec(private val loadFileContents: (String) -> String) { // Verify checksum val checksumIndex = determineChecksumIndex(words, prefixLength) val expectedChecksumWord = words[checksumIndex] - if (expectedChecksumWord.substring(0 until prefixLength) != checksumWord.substring(0 until prefixLength)) { throw DecodingError.VerificationFailed } + if (expectedChecksumWord.substring(0 until prefixLength) != checksumWord.substring(0 until prefixLength)) { throw DecodingError.VerificationFailed + } // Return return result } diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/PlaintextOutputStreamFactory.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/PlaintextOutputStreamFactory.kt similarity index 92% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/PlaintextOutputStreamFactory.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/PlaintextOutputStreamFactory.kt index b913289b08..412f66458f 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/PlaintextOutputStreamFactory.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/PlaintextOutputStreamFactory.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.utilities +package org.session.libsignal.service.loki import org.session.libsignal.service.api.crypto.DigestingOutputStream import org.session.libsignal.service.internal.push.http.OutputStreamFactory diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/PrettifiedDescription.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/PrettifiedDescription.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/PrettifiedDescription.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/PrettifiedDescription.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Random.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Random.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Random.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Random.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Reflection.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Reflection.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Reflection.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Reflection.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Retrying.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Retrying.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Retrying.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Retrying.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/api/crypto/SessionProtocol.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/SessionProtocol.kt similarity index 97% rename from libsignal/src/main/java/org/session/libsignal/service/loki/api/crypto/SessionProtocol.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/SessionProtocol.kt index 3851919052..201ad4e85d 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/api/crypto/SessionProtocol.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/SessionProtocol.kt @@ -1,7 +1,7 @@ package org.session.libsignal.service.loki.api.crypto import org.session.libsignal.libsignal.ecc.ECKeyPair -import org.session.libsignal.service.loki.database.LokiAPIDatabaseProtocol +import org.session.libsignal.service.loki.LokiAPIDatabaseProtocol interface SessionProtocol { diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/api/SignalMessageInfo.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/SignalMessageInfo.kt similarity index 88% rename from libsignal/src/main/java/org/session/libsignal/service/loki/api/SignalMessageInfo.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/SignalMessageInfo.kt index 5b41d26a5f..f5e20f4168 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/api/SignalMessageInfo.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/SignalMessageInfo.kt @@ -1,4 +1,4 @@ -package org.session.libsignal.service.loki.api +package org.session.libsignal.service.loki import org.session.libsignal.service.internal.push.SignalServiceProtos diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Trimming.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Trimming.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Trimming.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Trimming.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Validation.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/Validation.kt similarity index 100% rename from libsignal/src/main/java/org/session/libsignal/service/loki/utilities/Validation.kt rename to libsignal/src/main/java/org/session/libsignal/service/loki/Validation.kt diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/api/utilities/OKHTTPUtilities.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/api/utilities/OKHTTPUtilities.kt deleted file mode 100644 index 442edc5549..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/api/utilities/OKHTTPUtilities.kt +++ /dev/null @@ -1,49 +0,0 @@ -package org.session.libsignal.service.loki.api.utilities - -import okhttp3.MultipartBody -import okhttp3.Request -import okio.Buffer -import org.session.libsignal.utilities.Base64 -import java.io.IOException -import java.util.* - -internal fun Request.getHeadersForOnionRequest(): Map { - val result = mutableMapOf() - val contentType = body()?.contentType() - if (contentType != null) { - result["content-type"] = contentType.toString() - } - val headers = headers() - for (name in headers.names()) { - val value = headers.get(name) - if (value != null) { - if (value.toLowerCase(Locale.US) == "true" || value.toLowerCase(Locale.US) == "false") { - result[name] = value.toBoolean() - } else if (value.toIntOrNull() != null) { - result[name] = value.toInt() - } else { - result[name] = value - } - } - } - return result -} - -internal fun Request.getBodyForOnionRequest(): Any? { - try { - val copyOfThis = newBuilder().build() - val buffer = Buffer() - val body = copyOfThis.body() ?: return null - body.writeTo(buffer) - val bodyAsData = buffer.readByteArray() - if (body is MultipartBody) { - val base64EncodedBody: String = Base64.encodeBytes(bodyAsData) - return mapOf( "fileUpload" to base64EncodedBody ) - } else { - val charset = body.contentType()?.charset() ?: Charsets.UTF_8 - return bodyAsData?.toString(charset) - } - } catch (e: IOException) { - return null - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/JsonUtil.java b/libsignal/src/main/java/org/session/libsignal/utilities/JsonUtil.java index b20a870d10..f5767a8da2 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/JsonUtil.java +++ b/libsignal/src/main/java/org/session/libsignal/utilities/JsonUtil.java @@ -58,7 +58,7 @@ public class JsonUtil { return objectMapper.writeValueAsString(object); } - public static String toJson(Object object) { + public static String toJson(Object object) { try { return objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { @@ -67,32 +67,11 @@ public class JsonUtil { } } - public static class IdentityKeySerializer extends JsonSerializer { - @Override - public void serialize(IdentityKey value, JsonGenerator gen, SerializerProvider serializers) - throws IOException - { - gen.writeString(Base64.encodeBytesWithoutPadding(value.serialize())); - } - } - - public static class IdentityKeyDeserializer extends JsonDeserializer { - @Override - public IdentityKey deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - try { - return new IdentityKey(Base64.decodeWithoutPadding(p.getValueAsString()), 0); - } catch (InvalidKeyException e) { - throw new IOException(e); - } - } - } - public static ObjectMapper getMapper() { return objectMapper; } public static class SaneJSONObject { - private final JSONObject delegate; public SaneJSONObject(JSONObject delegate) { diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/PromiseUtilities.kt b/libsignal/src/main/java/org/session/libsignal/utilities/PromiseUtilities.kt index 8fe7ce7355..530d432d57 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/PromiseUtilities.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/PromiseUtilities.kt @@ -1,25 +1,11 @@ @file:JvmName("PromiseUtilities") package org.session.libsignal.utilities -import nl.komponents.kovenant.Context -import nl.komponents.kovenant.Kovenant import nl.komponents.kovenant.Promise import nl.komponents.kovenant.deferred -import nl.komponents.kovenant.jvm.asDispatcher import org.session.libsignal.utilities.logging.Log -import java.util.concurrent.Executors import java.util.concurrent.TimeoutException -fun Kovenant.createContext(): Context { - return createContext { - callbackContext.dispatcher = Executors.newSingleThreadExecutor().asDispatcher() - workerContext.dispatcher = ThreadUtils.executorPool.asDispatcher() - multipleCompletion = { v1, v2 -> - Log.d("Loki", "Promise resolved more than once (first with $v1, then with $v2); ignoring $v2.") - } - } -} - fun Promise.get(defaultValue: V): V { return try { get() diff --git a/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt b/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt index 1ad277f345..9436a54832 100644 --- a/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt +++ b/libsignal/src/main/java/org/session/libsignal/utilities/ThreadUtils.kt @@ -3,7 +3,6 @@ package org.session.libsignal.utilities import java.util.concurrent.* object ThreadUtils { - val executorPool = Executors.newCachedThreadPool() @JvmStatic @@ -17,10 +16,8 @@ object ThreadUtils { @JvmStatic fun newDynamicSingleThreadedExecutor(): ExecutorService { - val executor = ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, - LinkedBlockingQueue()) + val executor = ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, LinkedBlockingQueue()) executor.allowCoreThreadTimeOut(true) return executor } - } \ No newline at end of file