From 5120565a032754cb927d72c5133676a5fe933944 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 15 Jul 2020 11:45:49 +1000 Subject: [PATCH 01/18] Fix inverted flag --- src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt b/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt index 8ae4cb0314..cb40362f40 100644 --- a/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt @@ -29,7 +29,7 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() { override fun onAlarm(context: Context, scheduledTime: Long): Long { if (scheduledTime != 0L) { - if (TextSecurePreferences.isUsingFCM(context)) { + if (!TextSecurePreferences.isUsingFCM(context)) { val userPublicKey = TextSecurePreferences.getLocalNumber(context) val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context) try { From 21554441f322fa45541241866f7b47125863be3e Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 15 Jul 2020 12:24:43 +1000 Subject: [PATCH 02/18] Make things compile --- .../securesms/ApplicationContext.java | 33 +++++----- .../securesms/CreateProfileActivity.java | 8 +-- .../securesms/components/QuoteView.java | 4 +- .../conversation/ConversationActivity.java | 11 ++-- .../conversation/ConversationFragment.java | 12 ++-- .../conversation/ConversationItem.java | 8 +-- .../database/helpers/SQLCipherOpenHelper.java | 4 +- .../SignalCommunicationModule.java | 1 - .../securesms/jobs/AttachmentUploadJob.java | 1 - .../securesms/jobs/PushDecryptJob.java | 34 +++++----- .../securesms/jobs/PushMediaSendJob.java | 1 - .../securesms/jobs/PushReceivedJob.java | 2 +- .../securesms/jobs/PushTextSendJob.java | 2 - .../securesms/loki/activities/HomeActivity.kt | 9 +-- .../loki/activities/LandingActivity.kt | 6 +- .../loki/activities/LinkedDevicesActivity.kt | 16 ++--- .../loki/activities/SettingsActivity.kt | 6 +- .../loki/api/BackgroundPollWorker.kt | 2 +- .../loki/api/LokiPublicChatManager.kt | 14 ++-- .../loki/api/LokiPublicChatPoller.kt | 50 +++++++-------- .../loki/database/LokiAPIDatabase.kt | 60 ++++++++--------- .../loki/database/LokiMessageDatabase.kt | 36 +++++------ .../loki/database/LokiPreKeyBundleDatabase.kt | 36 +++++------ .../loki/database/LokiPreKeyRecordDatabase.kt | 24 +++---- .../loki/database/LokiThreadDatabase.kt | 64 +++++++++---------- .../loki/database/LokiUserDatabase.kt | 36 +++++------ .../dialogs/LinkDeviceMasterModeDialog.kt | 14 ++-- .../loki/dialogs/LinkDeviceSlaveModeDialog.kt | 2 +- .../loki/protocol/ClosedGroupsProtocol.kt | 8 +-- .../loki/protocol/FriendRequestProtocol.kt | 4 +- .../LokiSessionResetImplementation.kt | 24 +++---- .../protocol/MultiDeviceOpenGroupUpdateJob.kt | 4 +- .../loki/protocol/MultiDeviceProtocol.kt | 26 ++++---- .../protocol/PushEphemeralMessageSendJob.kt | 5 +- .../loki/protocol/PushNullMessageSendJob.kt | 2 +- .../protocol/SessionManagementProtocol.kt | 4 +- .../loki/protocol/SyncMessagesProtocol.kt | 4 +- .../loki/shelved/LokiRSSFeedPoller.kt | 2 +- .../loki/utilities/ContactUtilities.kt | 2 +- .../loki/utilities/OpenGroupUtilities.kt | 8 +-- .../loki/views/MentionCandidateView.kt | 6 +- .../securesms/mms/PushMediaConstraints.java | 12 ++-- .../push/MessageSenderEventListener.java | 16 ----- 43 files changed, 290 insertions(+), 333 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index c83193444d..cb4c969603 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -102,12 +102,11 @@ import org.whispersystems.signalservice.loki.api.Poller; import org.whispersystems.signalservice.loki.api.PushNotificationAcknowledgement; import org.whispersystems.signalservice.loki.api.SnodeAPI; import org.whispersystems.signalservice.loki.api.SwarmAPI; -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI; +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI; import org.whispersystems.signalservice.loki.api.shelved.p2p.LokiP2PAPI; import org.whispersystems.signalservice.loki.api.shelved.p2p.LokiP2PAPIDelegate; import org.whispersystems.signalservice.loki.database.LokiAPIDatabaseProtocol; -import org.whispersystems.signalservice.loki.protocol.friendrequests.FriendRequestProtocol; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol; import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink; @@ -156,7 +155,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc public MessageNotifier messageNotifier = null; public Poller lokiPoller = null; public LokiPublicChatManager lokiPublicChatManager = null; - private LokiPublicChatAPI lokiPublicChatAPI = null; + private PublicChatAPI publicChatAPI = null; public Broadcaster broadcaster = null; public SignalCommunicationModule communicationModule; @@ -189,7 +188,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc if (userPublicKey != null) { SwarmAPI.Companion.configureIfNeeded(apiDB); SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster); - FriendRequestProtocol.Companion.configureIfNeeded(apiDB, userPublicKey); MentionsManager.Companion.configureIfNeeded(userPublicKey, threadDB, userDB); SessionMetaProtocol.Companion.configureIfNeeded(apiDB, userPublicKey); SyncMessagesProtocol.Companion.configureIfNeeded(apiDB, userPublicKey); @@ -201,7 +199,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc if (setUpStorageAPIIfNeeded()) { if (userPublicKey != null) { Set deviceLinks = DatabaseFactory.getLokiAPIDatabase(this).getDeviceLinks(userPublicKey); - LokiFileServerAPI.shared.setDeviceLinks(deviceLinks); + FileServerAPI.shared.setDeviceLinks(deviceLinks); } } resubmitProfilePictureIfNeeded(); @@ -284,15 +282,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc } // Loki - public @Nullable LokiPublicChatAPI getLokiPublicChatAPI() { - if (lokiPublicChatAPI != null || !IdentityKeyUtil.hasIdentityKey(this)) { return lokiPublicChatAPI; } + public @Nullable PublicChatAPI getPublicChatAPI() { + if (publicChatAPI != null || !IdentityKeyUtil.hasIdentityKey(this)) { return publicChatAPI; } String userPublicKey = TextSecurePreferences.getLocalNumber(this); - if (userPublicKey== null) { return lokiPublicChatAPI; } + if (userPublicKey== null) { return publicChatAPI; } byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this); - lokiPublicChatAPI = new LokiPublicChatAPI(userPublicKey, userPrivateKey, apiDB, userDB); - return lokiPublicChatAPI; + publicChatAPI = new PublicChatAPI(userPublicKey, userPrivateKey, apiDB, userDB); + return publicChatAPI; } private void initializeSecurityProvider() { @@ -446,8 +444,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc super.attachBaseContext(DynamicLanguageContextWrapper.updateContext(base, TextSecurePreferences.getLanguage(base))); } - private static class ProviderInitializationException extends RuntimeException { - } + private static class ProviderInitializationException extends RuntimeException { } // region Loki public boolean setUpStorageAPIIfNeeded() { @@ -456,7 +453,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc boolean isDebugMode = BuildConfig.DEBUG; byte[] userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(this).getPrivateKey().serialize(); LokiAPIDatabaseProtocol apiDB = DatabaseFactory.getLokiAPIDatabase(this); - LokiFileServerAPI.Companion.configure(isDebugMode, userPublicKey, userPrivateKey, apiDB); + FileServerAPI.Companion.configure(userPublicKey, userPrivateKey, apiDB); return true; } @@ -534,7 +531,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc try { File profilePicture = AvatarHelper.getAvatarFile(this, Address.fromSerialized(userPublicKey)); StreamDetails stream = new StreamDetails(new FileInputStream(profilePicture), "image/jpeg", profilePicture.length()); - LokiFileServerAPI.shared.uploadProfilePicture(LokiFileServerAPI.shared.getServer(), profileKey, stream, () -> { + FileServerAPI.shared.uploadProfilePicture(FileServerAPI.shared.getServer(), profileKey, stream, () -> { TextSecurePreferences.setLastProfilePictureUpload(this, new Date().getTime()); TextSecurePreferences.setProfileAvatarId(this, new SecureRandom().nextInt()); ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey); @@ -548,9 +545,9 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc public void updateOpenGroupProfilePicturesIfNeeded() { AsyncTask.execute(() -> { - LokiPublicChatAPI publicChatAPI = null; + PublicChatAPI publicChatAPI = null; try { - publicChatAPI = getLokiPublicChatAPI(); + publicChatAPI = getPublicChatAPI(); } catch (Exception e) { // Do nothing } @@ -590,7 +587,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc } @Override - public void sendSessionRequest(@NotNull String publicKey) { + public void sendSessionRequestIfNeeded(@NotNull String publicKey) { // It's never necessary to establish a session with self String userPublicKey = TextSecurePreferences.getLocalNumber(this); if (publicKey.equals(userPublicKey)) { return; } diff --git a/src/org/thoughtcrime/securesms/CreateProfileActivity.java b/src/org/thoughtcrime/securesms/CreateProfileActivity.java index 62eb077481..e41694bae8 100644 --- a/src/org/thoughtcrime/securesms/CreateProfileActivity.java +++ b/src/org/thoughtcrime/securesms/CreateProfileActivity.java @@ -58,8 +58,8 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.crypto.ProfileCipher; import org.whispersystems.signalservice.api.util.StreamDetails; import org.whispersystems.signalservice.loki.api.LokiDotNetAPI; -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI; +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI; import java.io.ByteArrayInputStream; import java.io.File; @@ -386,7 +386,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje Context context = CreateProfileActivity.this; TextSecurePreferences.setProfileName(context, name); - LokiPublicChatAPI publicChatAPI = ApplicationContext.getInstance(context).getLokiPublicChatAPI(); + PublicChatAPI publicChatAPI = ApplicationContext.getInstance(context).getPublicChatAPI(); if (publicChatAPI != null) { Set servers = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChatServers(); for (String server : servers) { @@ -409,7 +409,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje // Loki - Upload the profile photo here if (avatar != null) { Log.d("Loki", "Start uploading profile photo"); - LokiFileServerAPI storageAPI = LokiFileServerAPI.shared; + FileServerAPI storageAPI = FileServerAPI.shared; LokiDotNetAPI.UploadResult result = storageAPI.uploadProfilePicture(storageAPI.getServer(), profileKey, avatar, () -> { TextSecurePreferences.setLastProfilePictureUpload(CreateProfileActivity.this, new Date().getTime()); return Unit.INSTANCE; diff --git a/src/org/thoughtcrime/securesms/components/QuoteView.java b/src/org/thoughtcrime/securesms/components/QuoteView.java index 93e06f6dd7..43c9e8bf7c 100644 --- a/src/org/thoughtcrime/securesms/components/QuoteView.java +++ b/src/org/thoughtcrime/securesms/components/QuoteView.java @@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat; import java.util.List; @@ -197,7 +197,7 @@ public class QuoteView extends FrameLayout implements RecipientModifiedListener long threadID = DatabaseFactory.getThreadDatabase(getContext()).getThreadIdFor(conversationRecipient); String senderHexEncodedPublicKey = author.getAddress().serialize(); - LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadID); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadID); if (senderHexEncodedPublicKey.equalsIgnoreCase(TextSecurePreferences.getLocalNumber(getContext()))) { quoteeDisplayName = TextSecurePreferences.getProfileName(getContext()); } else if (publicChat != null) { diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index a18509f92b..ab0983abd5 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -187,7 +187,6 @@ import org.thoughtcrime.securesms.mms.StickerSlide; import org.thoughtcrime.securesms.mms.TextSlide; import org.thoughtcrime.securesms.mms.VideoSlide; import org.thoughtcrime.securesms.notifications.MarkReadReceiver; -import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.profiles.GroupShareProfileView; @@ -227,7 +226,7 @@ import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.util.guava.Optional; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat; import org.whispersystems.signalservice.loki.protocol.mentions.Mention; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol; @@ -465,9 +464,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(threadId, this); - LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId); if (publicChat != null) { - ApplicationContext.getInstance(this).getLokiPublicChatAPI().getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success( displayName -> { + ApplicationContext.getInstance(this).getPublicChatAPI().getChannelInfo(publicChat.getChannel(), publicChat.getServer()).success(displayName -> { updateSubtitleTextView(); return Unit.INSTANCE; }); @@ -2172,7 +2171,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity try { int startIndex = result.indexOf("@" + mention.getDisplayName()); int endIndex = startIndex + mention.getDisplayName().length() + 1; // + 1 to include the @ - result = result.substring(0, startIndex) + "@" + mention.getHexEncodedPublicKey() + result.substring(endIndex); + result = result.substring(0, startIndex) + "@" + mention.getPublicKey() + result.substring(endIndex); } catch (Exception exception) { Log.d("Loki", "Couldn't process mention due to error: " + exception.toString() + "."); } @@ -3107,7 +3106,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity muteIndicatorImageView.setVisibility(View.VISIBLE); subtitleTextView.setText("Muted until " + DateUtils.getFormattedDateTime(recipient.mutedUntil, "EEE, MMM d, yyyy HH:mm", Locale.getDefault())); } else if (recipient.isGroupRecipient() && recipient.getName() != null && !recipient.getName().equals("Session Updates") && !recipient.getName().equals("Loki News")) { - LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId); if (publicChat != null) { Integer userCount = DatabaseFactory.getLokiAPIDatabase(this).getUserCount(publicChat.getChannel(), publicChat.getServer()); if (userCount == null) { userCount = 0; } diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 52a5d8ff2e..2a40d8dedb 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -101,8 +101,8 @@ import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; import org.whispersystems.libsignal.util.guava.Optional; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI; import java.io.IOException; import java.io.InputStream; @@ -399,7 +399,7 @@ public class ConversationFragment extends Fragment boolean isGroupChat = recipient.isGroupRecipient(); if (isGroupChat) { - LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId); boolean isPublicChat = (publicChat != null); int selectedMessageCount = messageRecords.size(); boolean areAllSentByUser = true; @@ -409,7 +409,7 @@ public class ConversationFragment extends Fragment menu.findItem(R.id.menu_context_copy_public_key).setVisible(isPublicChat && selectedMessageCount == 1 && !areAllSentByUser); menu.findItem(R.id.menu_context_reply).setVisible(selectedMessageCount == 1); String userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(getContext()); - boolean userCanModerate = isPublicChat && LokiPublicChatAPI.Companion.isUserModerator(userHexEncodedPublicKey, publicChat.getChannel(), publicChat.getServer()); + boolean userCanModerate = isPublicChat && PublicChatAPI.Companion.isUserModerator(userHexEncodedPublicKey, publicChat.getChannel(), publicChat.getServer()); boolean isDeleteOptionVisible = !isPublicChat || (areAllSentByUser || userCanModerate); menu.findItem(R.id.menu_context_delete_message).setVisible(isDeleteOptionVisible); } else { @@ -502,7 +502,7 @@ public class ConversationFragment extends Fragment builder.setMessage(getActivity().getResources().getQuantityString(R.plurals.ConversationFragment_this_will_permanently_delete_all_n_selected_messages, messagesCount, messagesCount)); builder.setCancelable(true); - LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(getContext()).getPublicChat(threadId); builder.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { @Override @@ -518,7 +518,7 @@ public class ConversationFragment extends Fragment ArrayList ignoredMessages = new ArrayList<>(); ArrayList failedMessages = new ArrayList<>(); boolean isSentByUser = true; - LokiPublicChatAPI publicChatAPI = ApplicationContext.getInstance(getContext()).getLokiPublicChatAPI(); + PublicChatAPI publicChatAPI = ApplicationContext.getInstance(getContext()).getPublicChatAPI(); for (MessageRecord messageRecord : messageRecords) { isSentByUser = isSentByUser && messageRecord.isOutgoing(); Long serverID = DatabaseFactory.getLokiMessageDatabase(getContext()).getServerID(messageRecord.id); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index 3d8d9c4ff4..b1c8f359a0 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -112,8 +112,8 @@ import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.util.guava.Optional; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI; import java.util.Collections; import java.util.HashSet; @@ -1001,9 +1001,9 @@ public class ConversationItem extends LinearLayout profilePictureView.setVisibility(VISIBLE); int visibility = View.GONE; - LokiPublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(messageRecord.getThreadId()); + PublicChat publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(messageRecord.getThreadId()); if (publicChat != null) { - boolean isModerator = LokiPublicChatAPI.Companion.isUserModerator(current.getRecipient().getAddress().toString(), publicChat.getChannel(), publicChat.getServer()); + boolean isModerator = PublicChatAPI.Companion.isUserModerator(current.getRecipient().getAddress().toString(), publicChat.getChannel(), publicChat.getServer()); visibility = isModerator ? View.VISIBLE : View.GONE; } diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index e55644c8ff..945cd0249b 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -45,7 +45,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat; +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat; import java.io.File; @@ -545,7 +545,7 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { try (Cursor lokiPublicChatCursor = db.rawQuery("SELECT public_chat FROM loki_public_chat_database", null)) { while (lokiPublicChatCursor != null && lokiPublicChatCursor.moveToNext()) { String chatString = lokiPublicChatCursor.getString(0); - LokiPublicChat publicChat = LokiPublicChat.fromJSON(chatString); + PublicChat publicChat = PublicChat.fromJSON(chatString); if (publicChat != null) { byte[] groupId = publicChat.getId().getBytes(); String oldId = GroupUtil.getEncodedId(groupId, false); diff --git a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java index b74af10069..a06ebe5eba 100644 --- a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java +++ b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java @@ -152,7 +152,6 @@ public class SignalCommunicationModule { Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()), Optional.of(new MessageSenderEventListener(context)), TextSecurePreferences.getLocalNumber(context), - TextSecurePreferences.getMasterHexEncodedPublicKey(context), DatabaseFactory.getLokiAPIDatabase(context), DatabaseFactory.getLokiThreadDatabase(context), DatabaseFactory.getLokiMessageDatabase(context), diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java index 16d1b09b85..1e14336f3c 100644 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java @@ -27,7 +27,6 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI; import java.io.IOException; import java.io.InputStream; diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index ef43989c11..1f1e39db7c 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -73,7 +73,6 @@ import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol; import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob; -import org.thoughtcrime.securesms.loki.protocol.PushNullMessageSendJob; import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol; import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol; @@ -103,7 +102,7 @@ import org.thoughtcrime.securesms.util.Hex; import org.thoughtcrime.securesms.util.IdentityUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.libsignal.loki.LokiSessionResetProtocol; +import org.whispersystems.libsignal.loki.SessionResetProtocol; import org.whispersystems.libsignal.state.SignalProtocolStore; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; @@ -128,7 +127,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOper import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage; import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI; import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus; @@ -263,11 +262,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType { private void handleMessage(@NonNull SignalServiceEnvelope envelope, @NonNull Optional smsMessageId, boolean isPushNotification) { try { - GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); - SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context); - LokiSessionResetProtocol lokiSessionResetProtocol = new LokiSessionResetImplementation(context); - SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context)); - LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, lokiSessionResetProtocol, UnidentifiedAccessUtil.getCertificateValidator()); + GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); + SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context); + SessionResetProtocol sessionResetProtocol = new LokiSessionResetImplementation(context); + SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context)); + LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, sessionResetProtocol, UnidentifiedAccessUtil.getCertificateValidator()); SignalServiceContent content = cipher.decrypt(envelope); @@ -298,12 +297,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType { boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent() || message.getSticker().isPresent(); // Loki - Handle unlinking request if needed - if (message.isUnlinkingRequest()) { + if (message.isDeviceUnlinkingRequest()) { MultiDeviceProtocol.handleUnlinkingRequestIfNeeded(context, content); } else { - // Loki - Don't process session restoration requests any further - if (message.isSessionRestorationRequest()) { return; } - // Loki - Handle friend request acceptance if needed FriendRequestProtocol.handleFriendRequestAcceptanceIfNeeded(context, content.getSender(), content); @@ -371,11 +367,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // Loki - This is needed for compatibility with refactored desktop clients // ======== - if (content.isFriendRequest()) { - ApplicationContext.getInstance(context).getJobManager().add(new PushNullMessageSendJob(content.getSender())); - } else { - Log.w(TAG, "Got unrecognized message..."); - } +// if (content.isFriendRequest()) { +// ApplicationContext.getInstance(context).getJobManager().add(new PushNullMessageSendJob(content.getSender())); +// } else { +// Log.w(TAG, "Got unrecognized message..."); +// } Recipient recipient = recipient(context, content.getSender()); long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient); LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(context); @@ -1432,7 +1428,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } else { try { // TODO: Burn this with fire when we can - PromiseUtilities.timeout(LokiFileServerAPI.shared.getDeviceLinks(publicKey, false), 6000).get(); + PromiseUtilities.timeout(FileServerAPI.shared.getDeviceLinks(publicKey, false), 6000).get(); String masterPublicKey = org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.shared.getMasterDevice(publicKey); if (masterPublicKey == null) { masterPublicKey = publicKey; @@ -1464,7 +1460,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } else { try { // TODO: Burn this with fire when we can - PromiseUtilities.timeout(LokiFileServerAPI.shared.getDeviceLinks(publicKey, false), 6000).get(); + PromiseUtilities.timeout(FileServerAPI.shared.getDeviceLinks(publicKey, false), 6000).get(); String masterPublicKey = org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.shared.getMasterDevice(publicKey); if (masterPublicKey == null) { masterPublicKey = publicKey; diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index d36fd517a5..682054b856 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -291,7 +291,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { .withPreviews(previews) .asExpirationUpdate(message.isExpirationUpdate()) .withPreKeyBundle(preKeyBundle) - .asFriendRequest(isLokiPreKeyBundleMessage) .build(); if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) { diff --git a/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java b/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java index c93ee94cd0..7b96e5593c 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java @@ -36,7 +36,7 @@ public abstract class PushReceivedJob extends BaseJob { if (envelope.isReceipt()) { handleReceipt(envelope); - } else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender() || envelope.isFriendRequest()) { + } else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender()) { handleMessage(envelope, isPushNotification); } else { Log.w(TAG, "Received envelope of unknown type: " + envelope.getType()); diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 74f33f457f..c2c019a3d6 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase; -import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; @@ -229,7 +228,6 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { .withExpiration((int)(message.getExpiresIn() / 1000)) .withProfileKey(profileKey.orNull()) .asEndSessionMessage(message.isEndSession()) - .asFriendRequest(isLokiPreKeyBundleMessage) .withPreKeyBundle(preKeyBundle) .build(); diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index 2921dc1108..a906f26337 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -40,10 +40,8 @@ import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegat import org.thoughtcrime.securesms.loki.views.SeedReminderViewDelegate import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideRequests -import org.thoughtcrime.securesms.notifications.MessageNotifier import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI -import org.whispersystems.signalservice.loki.protocol.friendrequests.FriendRequestProtocol +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol @@ -160,7 +158,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe val userPublicKey = TextSecurePreferences.getLocalNumber(this) val sessionResetImpl = LokiSessionResetImplementation(this) if (userPublicKey != null) { - FriendRequestProtocol.configureIfNeeded(apiDB, userPublicKey) MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB) SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey) SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey) @@ -175,7 +172,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe }.map { it.recipient.address.toPhoneString() }.toSet() - LokiFileServerAPI.shared.getDeviceLinks(publicKeys) + FileServerAPI.shared.getDeviceLinks(publicKeys) // TODO: Temporary hack to unbork existing clients val allContacts = DatabaseFactory.getRecipientDatabase(this).allAddresses.map { MultiDeviceProtocol.shared.getMasterDevice(it.serialize()) ?: it.serialize() @@ -311,7 +308,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe val apiDatabase = DatabaseFactory.getLokiAPIDatabase(activity) apiDatabase.removeLastMessageServerID(publicChat.channel, publicChat.server) apiDatabase.removeLastDeletionServerID(publicChat.channel, publicChat.server) - ApplicationContext.getInstance(activity).lokiPublicChatAPI!!.leave(publicChat.channel, publicChat.server) + ApplicationContext.getInstance(activity).publicChatAPI!!.leave(publicChat.channel, publicChat.server) } threadDatabase.deleteConversation(threadID) ApplicationContext.getInstance(activity).messageNotifier.updateNotification(activity) diff --git a/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt index b3109cc1d4..6ddb1f0a2c 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt @@ -27,7 +27,6 @@ import org.whispersystems.curve25519.Curve25519 import org.whispersystems.libsignal.ecc.Curve import org.whispersystems.libsignal.ecc.ECKeyPair import org.whispersystems.libsignal.util.KeyHelper -import org.whispersystems.signalservice.loki.protocol.friendrequests.FriendRequestProtocol import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink @@ -111,7 +110,6 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega val userDB = DatabaseFactory.getLokiUserDatabase(this) val userPublicKey = TextSecurePreferences.getLocalNumber(this) val sessionResetImpl = LokiSessionResetImplementation(this) - FriendRequestProtocol.configureIfNeeded(apiDB, userPublicKey) MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB) SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey) org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB) @@ -124,13 +122,13 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega linkDeviceDialog.show(supportFragmentManager, "Link Device Dialog") AsyncTask.execute { retryIfNeeded(8) { - MultiDeviceProtocol.sendDeviceLinkMessage(this@LandingActivity, deviceLink.masterHexEncodedPublicKey, deviceLink) + MultiDeviceProtocol.sendDeviceLinkMessage(this@LandingActivity, deviceLink.masterPublicKey, deviceLink) } } } override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) { - TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterHexEncodedPublicKey) + TextSecurePreferences.setMasterHexEncodedPublicKey(this, deviceLink.masterPublicKey) val intent = Intent(this, HomeActivity::class.java) show(intent) finish() diff --git a/src/org/thoughtcrime/securesms/loki/activities/LinkedDevicesActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/LinkedDevicesActivity.kt index f36bee9179..041e8a8efa 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/LinkedDevicesActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/LinkedDevicesActivity.kt @@ -26,7 +26,7 @@ import org.thoughtcrime.securesms.loki.utilities.recipient import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import java.util.* import kotlin.concurrent.schedule @@ -126,30 +126,30 @@ class LinkedDevicesActivity : PassphraseRequiredActionBarActivity, LoaderManager val userPublicKey = TextSecurePreferences.getLocalNumber(this) val apiDB = DatabaseFactory.getLokiAPIDatabase(this) val deviceLinks = apiDB.getDeviceLinks(userPublicKey) - val deviceLink = deviceLinks.find { it.masterHexEncodedPublicKey == userPublicKey && it.slaveHexEncodedPublicKey == slaveDevicePublicKey } + val deviceLink = deviceLinks.find { it.masterPublicKey == userPublicKey && it.slavePublicKey == slaveDevicePublicKey } if (deviceLink == null) { return Toast.makeText(this, R.string.activity_linked_devices_unlinking_failed_message, Toast.LENGTH_LONG).show() } - LokiFileServerAPI.shared.setDeviceLinks(setOf()).successUi { + FileServerAPI.shared.setDeviceLinks(setOf()).successUi { DatabaseFactory.getLokiAPIDatabase(this).clearDeviceLinks(userPublicKey) deviceLinks.forEach { deviceLink -> // We don't use PushEphemeralMessageJob because want these messages to send before the pre key and // session associated with the slave device have been deleted val unlinkingRequest = SignalServiceDataMessage.newBuilder() .withTimestamp(System.currentTimeMillis()) - .asUnlinkingRequest(true) + .asDeviceUnlinkingRequest(true) val messageSender = ApplicationContext.getInstance(this@LinkedDevicesActivity).communicationModule.provideSignalMessageSender() - val address = SignalServiceAddress(deviceLink.slaveHexEncodedPublicKey) + val address = SignalServiceAddress(deviceLink.slavePublicKey) try { - val udAccess = UnidentifiedAccessUtil.getAccessFor(this@LinkedDevicesActivity, recipient(this@LinkedDevicesActivity, deviceLink.slaveHexEncodedPublicKey)) + val udAccess = UnidentifiedAccessUtil.getAccessFor(this@LinkedDevicesActivity, recipient(this@LinkedDevicesActivity, deviceLink.slavePublicKey)) messageSender.sendMessage(0, address, udAccess, unlinkingRequest.build()) // The message ID doesn't matter } catch (e: Exception) { Log.d("Loki", "Failed to send unlinking request due to error: $e.") throw e } - DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey) + DatabaseFactory.getLokiPreKeyBundleDatabase(this).removePreKeyBundle(deviceLink.slavePublicKey) val sessionStore = TextSecureSessionStore(this@LinkedDevicesActivity) - sessionStore.deleteAllSessions(deviceLink.slaveHexEncodedPublicKey) + sessionStore.deleteAllSessions(deviceLink.slavePublicKey) } LoaderManager.getInstance(this).restartLoader(0, null, this) Toast.makeText(this, R.string.activity_linked_devices_unlinking_successful_message, Toast.LENGTH_LONG).show() diff --git a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt index 91cf61b401..72482a1691 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt @@ -42,7 +42,7 @@ import org.thoughtcrime.securesms.util.BitmapUtil import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.crypto.ProfileCipher import org.whispersystems.signalservice.api.util.StreamDetails -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import java.io.ByteArrayInputStream import java.io.File import java.security.SecureRandom @@ -151,7 +151,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { val promises = mutableListOf>() val displayName = displayNameToBeUploaded if (displayName != null) { - val publicChatAPI = ApplicationContext.getInstance(this).lokiPublicChatAPI + val publicChatAPI = ApplicationContext.getInstance(this).publicChatAPI if (publicChatAPI != null) { val servers = DatabaseFactory.getLokiThreadDatabase(this).getAllPublicChatServers() promises.addAll(servers.map { publicChatAPI.setDisplayName(displayName, it) }) @@ -162,7 +162,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { val encodedProfileKey = ProfileKeyUtil.generateEncodedProfileKey(this) val profileKey = ProfileKeyUtil.getProfileKeyFromEncodedString(encodedProfileKey) if (isUpdatingProfilePicture && profilePicture != null) { - val storageAPI = LokiFileServerAPI.shared + val storageAPI = FileServerAPI.shared val deferred = deferred() AsyncTask.execute { val stream = StreamDetails(ByteArrayInputStream(profilePicture), "image/jpeg", profilePicture.size.toLong()) diff --git a/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt b/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt index cb40362f40..f4808e4563 100644 --- a/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt @@ -15,7 +15,7 @@ import java.util.concurrent.TimeUnit class BackgroundPollWorker : PersistentAlarmManagerListener() { companion object { - private val pollInterval = TimeUnit.MINUTES.toMillis(15) + private val pollInterval = TimeUnit.MINUTES.toMillis(30) @JvmStatic fun schedule(context: Context) { diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt index ae2e1fb2fc..09f661ac9b 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt @@ -12,10 +12,10 @@ import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat class LokiPublicChatManager(private val context: Context) { - private var chats = mutableMapOf() + private var chats = mutableMapOf() private val pollers = mutableMapOf() private val observers = mutableMapOf() private var isPolling = false @@ -55,8 +55,8 @@ class LokiPublicChatManager(private val context: Context) { isPolling = false } - public fun addChat(server: String, channel: Long): Promise { - val groupChatAPI = ApplicationContext.getInstance(context).lokiPublicChatAPI ?: return Promise.ofFail(IllegalStateException("LokiPublicChatAPI is not set!")) + public fun addChat(server: String, channel: Long): Promise { + val groupChatAPI = ApplicationContext.getInstance(context).publicChatAPI ?: return Promise.ofFail(IllegalStateException("LokiPublicChatAPI is not set!")) return groupChatAPI.getAuthToken(server).bind { groupChatAPI.getChannelInfo(channel, server) }.map { @@ -64,8 +64,8 @@ class LokiPublicChatManager(private val context: Context) { } } - public fun addChat(server: String, channel: Long, name: String): LokiPublicChat { - val chat = LokiPublicChat(channel, server, name, true) + public fun addChat(server: String, channel: Long, name: String): PublicChat { + val chat = PublicChat(channel, server, name, true) var threadID = GroupManager.getOpenGroupThreadID(chat.id, context) // Create the group if we don't have one if (threadID < 0) { @@ -76,7 +76,7 @@ class LokiPublicChatManager(private val context: Context) { // Set our name on the server val displayName = TextSecurePreferences.getProfileName(context) if (!TextUtils.isEmpty(displayName)) { - ApplicationContext.getInstance(context).lokiPublicChatAPI?.setDisplayName(displayName, server) + ApplicationContext.getInstance(context).publicChatAPI?.setDisplayName(displayName, server) } // Start polling Util.runOnMain{ startPollersIfNeeded() } diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt index bc521e86ba..411859178d 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt @@ -22,16 +22,16 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatMessage +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatMessage import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import java.security.MessageDigest import java.util.* -class LokiPublicChatPoller(private val context: Context, private val group: LokiPublicChat) { +class LokiPublicChatPoller(private val context: Context, private val group: PublicChat) { private val handler = Handler() private var hasStarted = false public var isCaughtUp = false @@ -40,12 +40,12 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki private val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) private var displayNameUpdatees = setOf() - private val api: LokiPublicChatAPI + private val api: PublicChatAPI get() = { val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context) val lokiUserDatabase = DatabaseFactory.getLokiUserDatabase(context) - LokiPublicChatAPI(userHexEncodedPublicKey, userPrivateKey, lokiAPIDatabase, lokiUserDatabase) + PublicChatAPI(userHexEncodedPublicKey, userPrivateKey, lokiAPIDatabase, lokiUserDatabase) }() // endregion @@ -112,16 +112,16 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki // endregion // region Polling - private fun getDataMessage(message: LokiPublicChatMessage): SignalServiceDataMessage { + private fun getDataMessage(message: PublicChatMessage): SignalServiceDataMessage { val id = group.id.toByteArray() val serviceGroup = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, SignalServiceGroup.GroupType.PUBLIC_CHAT, null, null, null, null) val quote = if (message.quote != null) { - SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteeHexEncodedPublicKey), message.quote!!.quotedMessageBody, listOf()) + SignalServiceDataMessage.Quote(message.quote!!.quotedMessageTimestamp, SignalServiceAddress(message.quote!!.quoteePublicKey), message.quote!!.quotedMessageBody, listOf()) } else { null } val attachments = message.attachments.mapNotNull { attachment -> - if (attachment.kind != LokiPublicChatMessage.Attachment.Kind.Attachment) { return@mapNotNull null } + if (attachment.kind != PublicChatMessage.Attachment.Kind.Attachment) { return@mapNotNull null } SignalServiceAttachmentPointer( attachment.serverID, attachment.contentType, @@ -135,7 +135,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki Optional.fromNullable(attachment.caption), attachment.url) } - val linkPreview = message.attachments.firstOrNull { it.kind == LokiPublicChatMessage.Attachment.Kind.LinkPreview } + val linkPreview = message.attachments.firstOrNull { it.kind == PublicChatMessage.Attachment.Kind.LinkPreview } val signalLinkPreviews = mutableListOf() if (linkPreview != null) { val attachment = SignalServiceAttachmentPointer( @@ -157,16 +157,16 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } fun pollForNewMessages() { - fun processIncomingMessage(message: LokiPublicChatMessage) { + fun processIncomingMessage(message: PublicChatMessage) { // If the sender of the current message is not a slave device, set the display name in the database - val masterHexEncodedPublicKey = MultiDeviceProtocol.shared.getMasterDevice(message.hexEncodedPublicKey) + val masterHexEncodedPublicKey = MultiDeviceProtocol.shared.getMasterDevice(message.publicKey) if (masterHexEncodedPublicKey == null) { - val senderDisplayName = "${message.displayName} (...${message.hexEncodedPublicKey.takeLast(8)})" - DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.hexEncodedPublicKey, senderDisplayName) + val senderDisplayName = "${message.displayName} (...${message.publicKey.takeLast(8)})" + DatabaseFactory.getLokiUserDatabase(context).setServerDisplayName(group.id, message.publicKey, senderDisplayName) } - val senderHexEncodedPublicKey = masterHexEncodedPublicKey ?: message.hexEncodedPublicKey + val senderHexEncodedPublicKey = masterHexEncodedPublicKey ?: message.publicKey val serviceDataMessage = getDataMessage(message) - val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false, false, false, false) + val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false, false, false) if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) { PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } else { @@ -191,7 +191,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki } } } - fun processOutgoingMessage(message: LokiPublicChatMessage) { + fun processOutgoingMessage(message: PublicChatMessage) { val messageServerID = message.serverID ?: return val isDuplicate = DatabaseFactory.getLokiMessageDatabase(context).getMessageID(messageServerID) != null if (isDuplicate) { return } @@ -206,7 +206,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki PushDecryptJob(context).handleSynchronizeSentTextMessage(transcript) } // If we got a message from our master device then make sure our mapping stays in sync - val recipient = Recipient.from(context, Address.fromSerialized(message.hexEncodedPublicKey), false) + val recipient = Recipient.from(context, Address.fromSerialized(message.publicKey), false) if (recipient.isUserMasterDevice && message.profilePicture != null) { val profileKey = message.profilePicture!!.profileKey val url = message.profilePicture!!.url @@ -222,15 +222,15 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki var uniqueDevices = setOf() val userPrivateKey = IdentityKeyUtil.getIdentityKeyPair(context).privateKey.serialize() val apiDB = DatabaseFactory.getLokiAPIDatabase(context) - LokiFileServerAPI.configure(false, userHexEncodedPublicKey, userPrivateKey, apiDB) + FileServerAPI.configure(userHexEncodedPublicKey, userPrivateKey, apiDB) // Kovenant propagates a context to chained promises, so LokiPublicChatAPI.sharedContext should be used for all of the below - api.getMessages(group.channel, group.server).bind(LokiPublicChatAPI.sharedContext) { messages -> + api.getMessages(group.channel, group.server).bind(PublicChatAPI.sharedContext) { messages -> if (messages.isNotEmpty()) { // We need to fetch the device mapping for any devices we don't have - uniqueDevices = messages.map { it.hexEncodedPublicKey }.toSet() - val devicesToUpdate = uniqueDevices.filter { !userDevices.contains(it) && LokiFileServerAPI.shared.hasDeviceLinkCacheExpired(hexEncodedPublicKey = it) } + uniqueDevices = messages.map { it.publicKey }.toSet() + val devicesToUpdate = uniqueDevices.filter { !userDevices.contains(it) && FileServerAPI.shared.hasDeviceLinkCacheExpired(publicKey = it) } if (devicesToUpdate.isNotEmpty()) { - return@bind LokiFileServerAPI.shared.getDeviceLinks(devicesToUpdate.toSet()).then { messages } + return@bind FileServerAPI.shared.getDeviceLinks(devicesToUpdate.toSet()).then { messages } } } Promise.of(messages) @@ -244,7 +244,7 @@ class LokiPublicChatPoller(private val context: Context, private val group: Loki }.successBackground { messages -> // Process messages in the background messages.forEach { message -> - if (userDevices.contains(message.hexEncodedPublicKey)) { + if (userDevices.contains(message.publicKey)) { processOutgoingMessage(message) } else { processIncomingMessage(message) diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt index ca55870188..a3cbef083d 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt @@ -29,9 +29,9 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( @JvmStatic val createOnionRequestPathCacheCommand = "CREATE TABLE $onionRequestPathCache ($indexPath TEXT PRIMARY KEY, $snode TEXT);" // Swarm cache private val swarmCache = "loki_api_swarm_cache" - private val hexEncodedPublicKey = "hex_encoded_public_key" + private val swarmPublicKey = "hex_encoded_public_key" private val swarm = "swarm" - @JvmStatic val createSwarmCacheCommand = "CREATE TABLE $swarmCache ($hexEncodedPublicKey TEXT PRIMARY KEY, $swarm TEXT);" + @JvmStatic val createSwarmCacheCommand = "CREATE TABLE $swarmCache ($swarmPublicKey TEXT PRIMARY KEY, $swarm TEXT);" // Last message hash value cache private val lastMessageHashValueCache = "loki_api_last_message_hash_value_cache" private val target = "target" @@ -59,12 +59,12 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( @JvmStatic val createLastDeletionServerIDCacheCommand = "CREATE TABLE $lastDeletionServerIDCache ($lastDeletionServerIDCacheIndex STRING PRIMARY KEY, $lastDeletionServerID INTEGER DEFAULT 0);" // Device link cache private val deviceLinkCache = "loki_pairing_authorisation_cache" - private val masterHexEncodedPublicKey = "primary_device" - private val slaveHexEncodedPublicKey = "secondary_device" + private val masterPublicKey = "primary_device" + private val slavePublicKey = "secondary_device" private val requestSignature = "request_signature" private val authorizationSignature = "grant_signature" - @JvmStatic val createDeviceLinkCacheCommand = "CREATE TABLE $deviceLinkCache ($masterHexEncodedPublicKey TEXT, $slaveHexEncodedPublicKey TEXT, " + - "$requestSignature TEXT NULLABLE DEFAULT NULL, $authorizationSignature TEXT NULLABLE DEFAULT NULL, PRIMARY KEY ($masterHexEncodedPublicKey, $slaveHexEncodedPublicKey));" + @JvmStatic val createDeviceLinkCacheCommand = "CREATE TABLE $deviceLinkCache ($masterPublicKey TEXT, $slavePublicKey TEXT, " + + "$requestSignature TEXT NULLABLE DEFAULT NULL, $authorizationSignature TEXT NULLABLE DEFAULT NULL, PRIMARY KEY ($masterPublicKey, $slavePublicKey));" // User count cache private val userCountCache = "loki_user_count_cache" private val publicChatID = "public_chat_id" @@ -72,9 +72,9 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( @JvmStatic val createUserCountCacheCommand = "CREATE TABLE $userCountCache ($publicChatID STRING PRIMARY KEY, $userCount INTEGER DEFAULT 0);" // Session request timestamp cache private val sessionRequestTimestampCache = "session_request_timestamp_cache" - private val publicKey = "public_key" + private val sessionRequestPublicKey = "public_key" private val timestamp = "timestamp" - @JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($publicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" + @JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($sessionRequestPublicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" } override fun getSnodePool(): Set { @@ -161,9 +161,9 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( set("1-1", path1[1]); set("1-2", path1[2]) } - override fun getSwarm(hexEncodedPublicKey: String): Set? { + override fun getSwarm(publicKey: String): Set? { val database = databaseHelper.readableDatabase - return database.get(swarmCache, "${Companion.hexEncodedPublicKey} = ?", wrap(hexEncodedPublicKey)) { cursor -> + return database.get(swarmCache, "${Companion.swarmPublicKey} = ?", wrap(publicKey)) { cursor -> val swarmAsString = cursor.getString(cursor.getColumnIndexOrThrow(swarm)) swarmAsString.split(", ").mapNotNull { targetAsString -> val components = targetAsString.split("-") @@ -176,7 +176,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( }?.toSet() } - override fun setSwarm(hexEncodedPublicKey: String, newValue: Set) { + override fun setSwarm(publicKey: String, newValue: Set) { val database = databaseHelper.writableDatabase val swarmAsString = newValue.joinToString(", ") { target -> var string = "${target.address}-${target.port}" @@ -186,21 +186,21 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( } string } - val row = wrap(mapOf(Companion.hexEncodedPublicKey to hexEncodedPublicKey, swarm to swarmAsString)) - database.insertOrUpdate(swarmCache, row, "${Companion.hexEncodedPublicKey} = ?", wrap(hexEncodedPublicKey)) + val row = wrap(mapOf(Companion.swarmPublicKey to publicKey, swarm to swarmAsString)) + database.insertOrUpdate(swarmCache, row, "${Companion.swarmPublicKey} = ?", wrap(publicKey)) } - override fun getLastMessageHashValue(target: Snode): String? { + override fun getLastMessageHashValue(snode: Snode): String? { val database = databaseHelper.readableDatabase - return database.get(lastMessageHashValueCache, "${Companion.target} = ?", wrap(target.address)) { cursor -> + return database.get(lastMessageHashValueCache, "${Companion.target} = ?", wrap(snode.address)) { cursor -> cursor.getString(cursor.getColumnIndexOrThrow(lastMessageHashValue)) } } - override fun setLastMessageHashValue(target: Snode, newValue: String) { + override fun setLastMessageHashValue(snode: Snode, newValue: String) { val database = databaseHelper.writableDatabase - val row = wrap(mapOf(Companion.target to target.address, lastMessageHashValue to newValue)) - database.insertOrUpdate(lastMessageHashValueCache, row, "${Companion.target} = ?", wrap(target.address)) + val row = wrap(mapOf(Companion.target to snode.address, lastMessageHashValue to newValue)) + database.insertOrUpdate(lastMessageHashValueCache, row, "${Companion.target} = ?", wrap(snode.address)) } override fun getReceivedMessageHashValues(): Set? { @@ -277,35 +277,35 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( database.delete(lastDeletionServerIDCache,"$lastDeletionServerIDCacheIndex = ?", wrap(index)) } - override fun getDeviceLinks(hexEncodedPublicKey: String): Set { + override fun getDeviceLinks(publicKey: String): Set { val database = databaseHelper.readableDatabase - return database.getAll(deviceLinkCache, "$masterHexEncodedPublicKey = ? OR $slaveHexEncodedPublicKey = ?", arrayOf( hexEncodedPublicKey, hexEncodedPublicKey )) { cursor -> - val masterHexEncodedPublicKey = cursor.getString(masterHexEncodedPublicKey) - val slaveHexEncodedPublicKey = cursor.getString(slaveHexEncodedPublicKey) + return database.getAll(deviceLinkCache, "$masterPublicKey = ? OR $slavePublicKey = ?", arrayOf( publicKey, publicKey )) { cursor -> + val masterHexEncodedPublicKey = cursor.getString(masterPublicKey) + val slaveHexEncodedPublicKey = cursor.getString(slavePublicKey) val requestSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(requestSignature))) null else cursor.getBase64EncodedData(requestSignature) val authorizationSignature: ByteArray? = if (cursor.isNull(cursor.getColumnIndexOrThrow(authorizationSignature))) null else cursor.getBase64EncodedData(authorizationSignature) DeviceLink(masterHexEncodedPublicKey, slaveHexEncodedPublicKey, requestSignature, authorizationSignature) }.toSet() } - override fun clearDeviceLinks(hexEncodedPublicKey: String) { + override fun clearDeviceLinks(publicKey: String) { val database = databaseHelper.writableDatabase - database.delete(deviceLinkCache, "$masterHexEncodedPublicKey = ? OR $slaveHexEncodedPublicKey = ?", arrayOf( hexEncodedPublicKey, hexEncodedPublicKey )) + database.delete(deviceLinkCache, "$masterPublicKey = ? OR $slavePublicKey = ?", arrayOf( publicKey, publicKey )) } override fun addDeviceLink(deviceLink: DeviceLink) { val database = databaseHelper.writableDatabase val values = ContentValues() - values.put(masterHexEncodedPublicKey, deviceLink.masterHexEncodedPublicKey) - values.put(slaveHexEncodedPublicKey, deviceLink.slaveHexEncodedPublicKey) + values.put(masterPublicKey, deviceLink.masterPublicKey) + values.put(slavePublicKey, deviceLink.slavePublicKey) if (deviceLink.requestSignature != null) { values.put(requestSignature, Base64.encodeBytes(deviceLink.requestSignature)) } if (deviceLink.authorizationSignature != null) { values.put(authorizationSignature, Base64.encodeBytes(deviceLink.authorizationSignature)) } - database.insertOrUpdate(deviceLinkCache, values, "$masterHexEncodedPublicKey = ? AND $slaveHexEncodedPublicKey = ?", arrayOf( deviceLink.masterHexEncodedPublicKey, deviceLink.slaveHexEncodedPublicKey )) + database.insertOrUpdate(deviceLinkCache, values, "$masterPublicKey = ? AND $slavePublicKey = ?", arrayOf( deviceLink.masterPublicKey, deviceLink.slavePublicKey )) } override fun removeDeviceLink(deviceLink: DeviceLink) { val database = databaseHelper.writableDatabase - database.delete(deviceLinkCache, "$masterHexEncodedPublicKey = ? OR $slaveHexEncodedPublicKey = ?", arrayOf( deviceLink.masterHexEncodedPublicKey, deviceLink.slaveHexEncodedPublicKey )) + database.delete(deviceLinkCache, "$masterPublicKey = ? OR $slavePublicKey = ?", arrayOf( deviceLink.masterPublicKey, deviceLink.slavePublicKey )) } fun getUserCount(group: Long, server: String): Int? { @@ -332,8 +332,8 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( override fun setSessionRequestTimestamp(publicKey: String, timestamp: Long) { val database = databaseHelper.writableDatabase - val row = wrap(mapOf(LokiAPIDatabase.publicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString())) - database.insertOrUpdate(sessionRequestTimestampCache, row, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) + val row = wrap(mapOf(LokiAPIDatabase.sessionRequestPublicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString())) + database.insertOrUpdate(sessionRequestTimestampCache, row, "${LokiAPIDatabase.sessionRequestPublicKey} = ?", wrap(publicKey)) } } diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt index 81adc0be03..816614f66d 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt @@ -16,34 +16,34 @@ import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol { companion object { - private val messageFriendRequestTableName = "loki_message_friend_request_database" - private val messageThreadMappingTableName = "loki_message_thread_mapping_database" - private val errorMessageTableName = "loki_error_message_database" + private val messageFriendRequestTable = "loki_message_friend_request_database" + private val messageThreadMappingTable = "loki_message_thread_mapping_database" + private val errorMessageTable = "loki_error_message_database" private val messageID = "message_id" private val serverID = "server_id" private val friendRequestStatus = "friend_request_status" private val threadID = "thread_id" private val errorMessage = "error_message" - @JvmStatic val createMessageFriendRequestTableCommand = "CREATE TABLE $messageFriendRequestTableName ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" - @JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTableName ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);" - @JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTableName ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);" + @JvmStatic val createMessageFriendRequestTableCommand = "CREATE TABLE $messageFriendRequestTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" + @JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTable ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);" + @JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTable ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);" } - override fun getQuoteServerID(quoteID: Long, quoteeHexEncodedPublicKey: String): Long? { - val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, Address.fromSerialized(quoteeHexEncodedPublicKey)) + override fun getQuoteServerID(quoteID: Long, quoteePublicKey: String): Long? { + val message = DatabaseFactory.getMmsSmsDatabase(context).getMessageFor(quoteID, Address.fromSerialized(quoteePublicKey)) return if (message != null) getServerID(message.getId()) else null } fun getServerID(messageID: Long): Long? { val database = databaseHelper.readableDatabase - return database.get(messageFriendRequestTableName, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> + return database.get(messageFriendRequestTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> cursor.getInt(serverID) }?.toLong() } fun getMessageID(serverID: Long): Long? { val database = databaseHelper.readableDatabase - return database.get(messageFriendRequestTableName, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor -> + return database.get(messageFriendRequestTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor -> cursor.getInt(messageID) }?.toLong() } @@ -53,12 +53,12 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab val contentValues = ContentValues(2) contentValues.put(Companion.messageID, messageID) contentValues.put(Companion.serverID, serverID) - database.insertOrUpdate(messageFriendRequestTableName, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) + database.insertOrUpdate(messageFriendRequestTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) } fun getOriginalThreadID(messageID: Long): Long { val database = databaseHelper.readableDatabase - return database.get(messageThreadMappingTableName, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> + return database.get(messageThreadMappingTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> cursor.getInt(threadID) }?.toLong() ?: -1L } @@ -68,12 +68,12 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab val contentValues = ContentValues(2) contentValues.put(Companion.messageID, messageID) contentValues.put(Companion.threadID, threadID) - database.insertOrUpdate(messageThreadMappingTableName, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) + database.insertOrUpdate(messageThreadMappingTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) } fun getFriendRequestStatus(messageID: Long): LokiMessageFriendRequestStatus { val database = databaseHelper.readableDatabase - val result = database.get(messageFriendRequestTableName, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> + val result = database.get(messageFriendRequestTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> cursor.getInt(friendRequestStatus) } return if (result != null) { @@ -83,12 +83,12 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab } } - override fun setFriendRequestStatus(messageID: Long, friendRequestStatus: LokiMessageFriendRequestStatus) { + fun setFriendRequestStatus(messageID: Long, friendRequestStatus: LokiMessageFriendRequestStatus) { val database = databaseHelper.writableDatabase val contentValues = ContentValues(2) contentValues.put(Companion.messageID, messageID) contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue) - database.insertOrUpdate(messageFriendRequestTableName, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) + database.insertOrUpdate(messageFriendRequestTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) val threadID = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID) notifyConversationListeners(threadID) } @@ -99,7 +99,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab fun getErrorMessage(messageID: Long): String? { val database = databaseHelper.readableDatabase - return database.get(errorMessageTableName, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> + return database.get(errorMessageTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> cursor.getString(errorMessage) } } @@ -109,6 +109,6 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab val contentValues = ContentValues(2) contentValues.put(Companion.messageID, messageID) contentValues.put(Companion.errorMessage, errorMessage) - database.insertOrUpdate(errorMessageTableName, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) + database.insertOrUpdate(errorMessageTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyBundleDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyBundleDatabase.kt index 7fcb034f85..6e89f77a40 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyBundleDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyBundleDatabase.kt @@ -26,8 +26,8 @@ import org.whispersystems.signalservice.loki.database.LokiPreKeyBundleDatabasePr class LokiPreKeyBundleDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiPreKeyBundleDatabaseProtocol { companion object { - private val tableName = "loki_pre_key_bundle_database" - private val hexEncodedPublicKey = "public_key" + private val table = "loki_pre_key_bundle_database" + private val publicKey = "public_key" private val preKeyID = "pre_key_id" private val preKeyPublic = "pre_key_public" private val signedPreKeyID = "signed_pre_key_id" @@ -36,16 +36,16 @@ class LokiPreKeyBundleDatabase(context: Context, helper: SQLCipherOpenHelper) : private val identityKey = "identity_key" private val deviceID = "device_id" private val registrationID = "registration_id" - @JvmStatic val createTableCommand = "CREATE TABLE $tableName (" + "$hexEncodedPublicKey TEXT PRIMARY KEY," + "$preKeyID INTEGER," + + @JvmStatic val createTableCommand = "CREATE TABLE $table (" + "$publicKey TEXT PRIMARY KEY," + "$preKeyID INTEGER," + "$preKeyPublic TEXT NOT NULL," + "$signedPreKeyID INTEGER," + "$signedPreKeyPublic TEXT NOT NULL," + "$signedPreKeySignature TEXT," + "$identityKey TEXT NOT NULL," + "$deviceID INTEGER," + "$registrationID INTEGER" + ");" } - fun generatePreKeyBundle(hexEncodedPublicKey: String): PreKeyBundle? { + fun generatePreKeyBundle(publicKey: String): PreKeyBundle? { var failureCount = 0 while (failureCount < 3) { try { - val preKey = generatePreKeyBundle(hexEncodedPublicKey, failureCount > 0) ?: return null + val preKey = generatePreKeyBundle(publicKey, failureCount > 0) ?: return null // Verify the bundle is correct if (!Curve.verifySignature(preKey.identityKey.publicKey, preKey.signedPreKey.serialize(), preKey.signedPreKeySignature)) { throw InvalidKeyException() @@ -55,19 +55,19 @@ class LokiPreKeyBundleDatabase(context: Context, helper: SQLCipherOpenHelper) : failureCount += 1 } } - Log.w("Loki", "Failed to generate a valid pre key bundle for: $hexEncodedPublicKey.") + Log.w("Loki", "Failed to generate a valid pre key bundle for: $publicKey.") return null } - private fun generatePreKeyBundle(hexEncodedPublicKey: String, forceClean: Boolean): PreKeyBundle? { - if (hexEncodedPublicKey.isEmpty()) return null + private fun generatePreKeyBundle(publicKey: String, forceClean: Boolean): PreKeyBundle? { + if (publicKey.isEmpty()) return null var registrationID = TextSecurePreferences.getLocalRegistrationId(context) if (registrationID == 0) { registrationID = KeyHelper.generateRegistrationId(false) TextSecurePreferences.setLocalRegistrationId(context, registrationID) } val deviceID = SignalServiceAddress.DEFAULT_DEVICE_ID - val preKeyRecord = DatabaseFactory.getLokiPreKeyRecordDatabase(context).getOrCreatePreKeyRecord(hexEncodedPublicKey) + val preKeyRecord = DatabaseFactory.getLokiPreKeyRecordDatabase(context).getOrCreatePreKeyRecord(publicKey) val identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context) if (!forceClean && TextSecurePreferences.isSignedPreKeyRegistered(context)) { Log.d("Loki", "A signed pre key has already been registered.") @@ -80,9 +80,9 @@ class LokiPreKeyBundleDatabase(context: Context, helper: SQLCipherOpenHelper) : return PreKeyBundle(registrationID, deviceID, preKeyRecord.id, preKeyRecord.keyPair.publicKey, activeSignedPreKey.id, activeSignedPreKey.keyPair.publicKey, activeSignedPreKey.signature, identityKeyPair.publicKey) } - override fun getPreKeyBundle(hexEncodedPublicKey: String): PreKeyBundle? { + override fun getPreKeyBundle(publicKey: String): PreKeyBundle? { val database = databaseHelper.readableDatabase - return database.get(tableName, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) { cursor -> + return database.get(table, "${Companion.publicKey} = ?", arrayOf( publicKey )) { cursor -> val registrationID = cursor.getInt(registrationID) val deviceID = cursor.getInt(deviceID) val preKeyID = cursor.getInt(preKeyID) @@ -95,7 +95,7 @@ class LokiPreKeyBundleDatabase(context: Context, helper: SQLCipherOpenHelper) : } } - fun setPreKeyBundle(hexEncodedPublicKey: String, preKeyBundle: PreKeyBundle) { + fun setPreKeyBundle(publicKey: String, preKeyBundle: PreKeyBundle) { val database = databaseHelper.writableDatabase val values = ContentValues(9) values.put(registrationID, preKeyBundle.registrationId) @@ -106,20 +106,20 @@ class LokiPreKeyBundleDatabase(context: Context, helper: SQLCipherOpenHelper) : values.put(signedPreKeyPublic, Base64.encodeBytes(preKeyBundle.signedPreKey.serialize())) values.put(signedPreKeySignature, Base64.encodeBytes(preKeyBundle.signedPreKeySignature)) values.put(identityKey, Base64.encodeBytes(preKeyBundle.identityKey.serialize())) - values.put(Companion.hexEncodedPublicKey, hexEncodedPublicKey) - database.insertOrUpdate(tableName, values, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) + values.put(Companion.publicKey, publicKey) + database.insertOrUpdate(table, values, "${Companion.publicKey} = ?", arrayOf( publicKey )) } - override fun removePreKeyBundle(hexEncodedPublicKey: String) { + override fun removePreKeyBundle(publicKey: String) { val database = databaseHelper.writableDatabase - database.delete(tableName, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) + database.delete(table, "${Companion.publicKey} = ?", arrayOf( publicKey )) } - fun hasPreKeyBundle(hexEncodedPublicKey: String): Boolean { + fun hasPreKeyBundle(publicKey: String): Boolean { val database = databaseHelper.readableDatabase var cursor: Cursor? = null return try { - cursor = database.query(tableName, null, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey ), null, null, null) + cursor = database.query(table, null, "${Companion.publicKey} = ?", arrayOf( publicKey ), null, null, null) cursor != null && cursor.count > 0 } catch (e: Exception) { false diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyRecordDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyRecordDatabase.kt index 934368c085..ab92ee50d4 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyRecordDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiPreKeyRecordDatabase.kt @@ -14,38 +14,38 @@ import org.whispersystems.signalservice.loki.database.LokiPreKeyRecordDatabasePr class LokiPreKeyRecordDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiPreKeyRecordDatabaseProtocol { companion object { - private val tableName = "loki_pre_key_record_database" - private val hexEncodedPublicKey = "public_key" + private val table = "loki_pre_key_record_database" + private val publicKey = "public_key" private val preKeyID = "pre_key_id" - @JvmStatic val createTableCommand = "CREATE TABLE $tableName ($hexEncodedPublicKey TEXT PRIMARY KEY, $preKeyID INTEGER);" + @JvmStatic val createTableCommand = "CREATE TABLE $table ($publicKey TEXT PRIMARY KEY, $preKeyID INTEGER);" } - fun hasPreKey(hexEncodedPublicKey: String): Boolean { + fun hasPreKey(publicKey: String): Boolean { val database = databaseHelper.readableDatabase - return database.get(tableName, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) { it.count > 0 } ?: false + return database.get(table, "${Companion.publicKey} = ?", arrayOf( publicKey )) { it.count > 0 } ?: false } - override fun getPreKeyRecord(hexEncodedPublicKey: String): PreKeyRecord? { + override fun getPreKeyRecord(publicKey: String): PreKeyRecord? { val database = databaseHelper.readableDatabase - return database.get(tableName, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) { cursor -> + return database.get(table, "${Companion.publicKey} = ?", arrayOf( publicKey )) { cursor -> val preKeyID = cursor.getInt(preKeyID) PreKeyUtil.loadPreKey(context, preKeyID) } } - fun getOrCreatePreKeyRecord(hexEncodedPublicKey: String): PreKeyRecord { - return getPreKeyRecord(hexEncodedPublicKey) ?: generateAndStorePreKeyRecord(hexEncodedPublicKey) + fun getOrCreatePreKeyRecord(publicKey: String): PreKeyRecord { + return getPreKeyRecord(publicKey) ?: generateAndStorePreKeyRecord(publicKey) } - private fun generateAndStorePreKeyRecord(hexEncodedPublicKey: String): PreKeyRecord { + private fun generateAndStorePreKeyRecord(publicKey: String): PreKeyRecord { val records = PreKeyUtil.generatePreKeyRecords(context, 1) PreKeyUtil.storePreKeyRecords(context, records) val record = records.first() val database = databaseHelper.writableDatabase val values = ContentValues(2) - values.put(Companion.hexEncodedPublicKey, hexEncodedPublicKey) + values.put(Companion.publicKey, publicKey) values.put(preKeyID, record.id) - database.insertOrUpdate(tableName, values, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) + database.insertOrUpdate(table, values, "${Companion.publicKey} = ?", arrayOf( publicKey )) return record } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt index a2e47425e2..4df60e594d 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt @@ -11,9 +11,9 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.loki.utilities.* import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.libsignal.loki.LokiSessionResetStatus +import org.whispersystems.libsignal.loki.SessionResetStatus import org.whispersystems.signalservice.internal.util.JsonUtil -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat import org.whispersystems.signalservice.loki.database.LokiThreadDatabaseProtocol import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation @@ -22,16 +22,16 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa var delegate: LokiThreadDatabaseDelegate? = null companion object { - private val friendRequestTableName = "loki_thread_friend_request_database" - private val sessionResetTableName = "loki_thread_session_reset_database" - val publicChatTableName = "loki_public_chat_database" + private val friendRequestTable = "loki_thread_friend_request_database" + private val sessionResetTable = "loki_thread_session_reset_database" + val publicChatTable = "loki_public_chat_database" val threadID = "thread_id" private val friendRequestStatus = "friend_request_status" private val sessionResetStatus = "session_reset_status" val publicChat = "public_chat" - @JvmStatic val createFriendRequestTableCommand = "CREATE TABLE $friendRequestTableName ($threadID INTEGER PRIMARY KEY, $friendRequestStatus INTEGER DEFAULT 0);" - @JvmStatic val createSessionResetTableCommand = "CREATE TABLE $sessionResetTableName ($threadID INTEGER PRIMARY KEY, $sessionResetStatus INTEGER DEFAULT 0);" - @JvmStatic val createPublicChatTableCommand = "CREATE TABLE $publicChatTableName ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);" + @JvmStatic val createFriendRequestTableCommand = "CREATE TABLE $friendRequestTable ($threadID INTEGER PRIMARY KEY, $friendRequestStatus INTEGER DEFAULT 0);" + @JvmStatic val createSessionResetTableCommand = "CREATE TABLE $sessionResetTable ($threadID INTEGER PRIMARY KEY, $sessionResetStatus INTEGER DEFAULT 0);" + @JvmStatic val createPublicChatTableCommand = "CREATE TABLE $publicChatTable ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);" } override fun getThreadID(hexEncodedPublicKey: String): Long { @@ -49,7 +49,7 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID) if (recipient != null && recipient.isGroupRecipient) { return LokiThreadFriendRequestStatus.FRIENDS; } val database = databaseHelper.readableDatabase - val result = database.get(friendRequestTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> + val result = database.get(friendRequestTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> cursor.getInt(friendRequestStatus) } return if (result != null) { @@ -59,59 +59,53 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa } } - override fun setFriendRequestStatus(threadID: Long, friendRequestStatus: LokiThreadFriendRequestStatus) { + fun setFriendRequestStatus(threadID: Long, friendRequestStatus: LokiThreadFriendRequestStatus) { if (threadID < 0) { return } Log.d("Loki", "Setting FR status for thread with ID $threadID to $friendRequestStatus.") val database = databaseHelper.writableDatabase val contentValues = ContentValues(2) contentValues.put(Companion.threadID, threadID) contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue) - database.insertOrUpdate(friendRequestTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) + database.insertOrUpdate(friendRequestTable, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) notifyConversationListListeners() notifyConversationListeners(threadID) delegate?.handleThreadFriendRequestStatusChanged(threadID) } - fun hasPendingFriendRequest(threadID: Long): Boolean { - val friendRequestStatus = getFriendRequestStatus(threadID) - return friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT - || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED - } - - fun getSessionResetStatus(hexEncodedPublicKey: String): LokiSessionResetStatus { + fun getSessionResetStatus(hexEncodedPublicKey: String): SessionResetStatus { val threadID = getThreadID(hexEncodedPublicKey) val database = databaseHelper.readableDatabase - val result = database.get(sessionResetTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> + val result = database.get(sessionResetTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> cursor.getInt(sessionResetStatus) } return if (result != null) { - LokiSessionResetStatus.values().first { it.rawValue == result } + SessionResetStatus.values().first { it.rawValue == result } } else { - LokiSessionResetStatus.NONE + SessionResetStatus.NONE } } - fun setSessionResetStatus(hexEncodedPublicKey: String, sessionResetStatus: LokiSessionResetStatus) { + fun setSessionResetStatus(hexEncodedPublicKey: String, sessionResetStatus: SessionResetStatus) { val threadID = getThreadID(hexEncodedPublicKey) val database = databaseHelper.writableDatabase val contentValues = ContentValues(2) contentValues.put(Companion.threadID, threadID) contentValues.put(Companion.sessionResetStatus, sessionResetStatus.rawValue) - database.insertOrUpdate(sessionResetTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) + database.insertOrUpdate(sessionResetTable, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) notifyConversationListListeners() notifyConversationListeners(threadID) } - fun getAllPublicChats(): Map { + fun getAllPublicChats(): Map { val database = databaseHelper.readableDatabase var cursor: Cursor? = null - val result = mutableMapOf() + val result = mutableMapOf() try { - cursor = database.rawQuery("select * from $publicChatTableName", null) + cursor = database.rawQuery("select * from $publicChatTable", null) while (cursor != null && cursor.moveToNext()) { val threadID = cursor.getLong(threadID) val string = cursor.getString(publicChat) - val publicChat = LokiPublicChat.fromJSON(string) + val publicChat = PublicChat.fromJSON(string) if (publicChat != null) { result[threadID] = publicChat } } } catch (e: Exception) { @@ -126,31 +120,31 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa return getAllPublicChats().values.fold(setOf()) { set, chat -> set.plus(chat.server) } } - override fun getPublicChat(threadID: Long): LokiPublicChat? { + override fun getPublicChat(threadID: Long): PublicChat? { if (threadID < 0) { return null } val database = databaseHelper.readableDatabase - return database.get(publicChatTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> + return database.get(publicChatTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> val publicChatAsJSON = cursor.getString(publicChat) - LokiPublicChat.fromJSON(publicChatAsJSON) + PublicChat.fromJSON(publicChatAsJSON) } } - override fun setPublicChat(publicChat: LokiPublicChat, threadID: Long) { + override fun setPublicChat(publicChat: PublicChat, threadID: Long) { if (threadID < 0) { return } val database = databaseHelper.writableDatabase val contentValues = ContentValues(2) contentValues.put(Companion.threadID, threadID) contentValues.put(Companion.publicChat, JsonUtil.toJson(publicChat.toJSON())) - database.insertOrUpdate(publicChatTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) + database.insertOrUpdate(publicChatTable, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) } override fun removePublicChat(threadID: Long) { - databaseHelper.writableDatabase.delete(publicChatTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) + databaseHelper.writableDatabase.delete(publicChatTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) } - fun addSessionRestoreDevice(threadID: Long, hexEncodedPublicKey: String) { + fun addSessionRestoreDevice(threadID: Long, publicKey: String) { val devices = getSessionRestoreDevices(threadID).toMutableSet() - if (devices.add(hexEncodedPublicKey)) { + if (devices.add(publicKey)) { TextSecurePreferences.setStringPreference(context, "session_restore_devices_$threadID", devices.joinToString(",")) delegate?.handleSessionRestoreDevicesChanged(threadID) } diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt index 0e307499e2..236ffb6fe3 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiUserDatabase.kt @@ -20,60 +20,60 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database private val displayName = "display_name" // Display name cache private val displayNameTable = "loki_user_display_name_database" - private val hexEncodedPublicKey = "hex_encoded_public_key" - @JvmStatic val createDisplayNameTableCommand = "CREATE TABLE $displayNameTable ($hexEncodedPublicKey TEXT PRIMARY KEY, $displayName TEXT);" + private val publicKey = "hex_encoded_public_key" + @JvmStatic val createDisplayNameTableCommand = "CREATE TABLE $displayNameTable ($publicKey TEXT PRIMARY KEY, $displayName TEXT);" // Server display name cache private val serverDisplayNameTable = "loki_user_server_display_name_database" private val serverID = "server_id" - @JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($hexEncodedPublicKey TEXT, $serverID TEXT, $displayName TEXT, PRIMARY KEY ($hexEncodedPublicKey, $serverID));" + @JvmStatic val createServerDisplayNameTableCommand = "CREATE TABLE $serverDisplayNameTable ($publicKey TEXT, $serverID TEXT, $displayName TEXT, PRIMARY KEY ($publicKey, $serverID));" } - override fun getDisplayName(hexEncodedPublicKey: String): String? { - if (hexEncodedPublicKey == TextSecurePreferences.getLocalNumber(context)) { + override fun getDisplayName(publicKey: String): String? { + if (publicKey == TextSecurePreferences.getLocalNumber(context)) { return TextSecurePreferences.getProfileName(context) } else { val database = databaseHelper.readableDatabase - return database.get(displayNameTable, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) { cursor -> + return database.get(displayNameTable, "${Companion.publicKey} = ?", arrayOf( publicKey )) { cursor -> cursor.getString(cursor.getColumnIndexOrThrow(displayName)) } } } - fun setDisplayName(hexEncodedPublicKey: String, displayName: String) { + fun setDisplayName(publicKey: String, displayName: String) { val database = databaseHelper.writableDatabase val row = ContentValues(2) - row.put(Companion.hexEncodedPublicKey, hexEncodedPublicKey) + row.put(Companion.publicKey, publicKey) row.put(Companion.displayName, displayName) - database.insertOrUpdate(displayNameTable, row, "${Companion.hexEncodedPublicKey} = ?", arrayOf( hexEncodedPublicKey )) - Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners() + database.insertOrUpdate(displayNameTable, row, "${Companion.publicKey} = ?", arrayOf( publicKey )) + Recipient.from(context, Address.fromSerialized(publicKey), false).notifyListeners() } - override fun getServerDisplayName(serverID: String, hexEncodedPublicKey: String): String? { + override fun getServerDisplayName(serverID: String, publicKey: String): String? { val database = databaseHelper.readableDatabase - return database.get(serverDisplayNameTable, "${Companion.hexEncodedPublicKey} = ? AND ${Companion.serverID} = ?", arrayOf( hexEncodedPublicKey, serverID )) { cursor -> + return database.get(serverDisplayNameTable, "${Companion.publicKey} = ? AND ${Companion.serverID} = ?", arrayOf( publicKey, serverID )) { cursor -> cursor.getString(cursor.getColumnIndexOrThrow(displayName)) } } - fun setServerDisplayName(serverID: String, hexEncodedPublicKey: String, displayName: String) { + fun setServerDisplayName(serverID: String, publicKey: String, displayName: String) { val database = databaseHelper.writableDatabase val values = ContentValues(3) values.put(Companion.serverID, serverID) - values.put(Companion.hexEncodedPublicKey, hexEncodedPublicKey) + values.put(Companion.publicKey, publicKey) values.put(Companion.displayName, displayName) try { database.insertWithOnConflict(serverDisplayNameTable, null, values, SQLiteDatabase.CONFLICT_REPLACE) - Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners() + Recipient.from(context, Address.fromSerialized(publicKey), false).notifyListeners() } catch (e: Exception) { Log.d("Loki", "Couldn't save server display name due to exception: $e.") } } - override fun getProfilePictureURL(hexEncodedPublicKey: String): String? { - return if (hexEncodedPublicKey == TextSecurePreferences.getLocalNumber(context)) { + override fun getProfilePictureURL(publicKey: String): String? { + return if (publicKey == TextSecurePreferences.getLocalNumber(context)) { TextSecurePreferences.getProfilePictureURL(context) } else { - Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).resolve().profileAvatar + Recipient.from(context, Address.fromSerialized(publicKey), false).resolve().profileAvatar } } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceMasterModeDialog.kt b/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceMasterModeDialog.kt index 019160b674..dc40272543 100644 --- a/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceMasterModeDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceMasterModeDialog.kt @@ -22,7 +22,7 @@ import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.loki.api.SnodeAPI -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import org.whispersystems.signalservice.loki.crypto.MnemonicCodec import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLinkingSession @@ -52,7 +52,7 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene } override fun requestUserAuthorization(deviceLink: DeviceLink) { - if (deviceLink.type != DeviceLink.Type.REQUEST || deviceLink.masterHexEncodedPublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.deviceLink != null) { return } + if (deviceLink.type != DeviceLink.Type.REQUEST || deviceLink.masterPublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.deviceLink != null) { return } Util.runOnMain { this.deviceLink = deviceLink contentView.qrCodeImageView.visibility = View.GONE @@ -62,7 +62,7 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene contentView.titleTextView.text = resources.getString(R.string.dialog_link_device_master_mode_title_2) contentView.explanationTextView.text = resources.getString(R.string.dialog_link_device_master_mode_explanation_2) contentView.mnemonicTextView.visibility = View.VISIBLE - contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), deviceLink.slaveHexEncodedPublicKey) + contentView.mnemonicTextView.text = MnemonicUtilities.getFirst3Words(MnemonicCodec(languageFileDirectory), deviceLink.slavePublicKey) contentView.authorizeButton.visibility = View.VISIBLE } } @@ -84,7 +84,7 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene contentView.cancelButton.visibility = View.GONE contentView.authorizeButton.visibility = View.GONE } - LokiFileServerAPI.shared.addDeviceLink(deviceLink).bind(SnodeAPI.sharedContext) { + FileServerAPI.shared.addDeviceLink(deviceLink).bind(SnodeAPI.sharedContext) { MultiDeviceProtocol.signAndSendDeviceLinkMessage(context!!, deviceLink) }.success { TextSecurePreferences.setMultiDevice(context!!, true) @@ -92,8 +92,8 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene delegate?.onDeviceLinkRequestAuthorized() dismiss() }.fail { - LokiFileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem - DatabaseFactory.getLokiPreKeyBundleDatabase(context!!).removePreKeyBundle(deviceLink.slaveHexEncodedPublicKey) + FileServerAPI.shared.removeDeviceLink(deviceLink) // If this fails we have a problem + DatabaseFactory.getLokiPreKeyBundleDatabase(context!!).removePreKeyBundle(deviceLink.slavePublicKey) }.failUi { delegate?.onDeviceLinkAuthorizationFailed() dismiss() @@ -104,7 +104,7 @@ class LinkDeviceMasterModeDialog : DialogFragment(), DeviceLinkingSessionListene DeviceLinkingSession.shared.stopListeningForLinkingRequests() DeviceLinkingSession.shared.removeListener(this) if (deviceLink != null) { - DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(deviceLink!!.slaveHexEncodedPublicKey) + DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(deviceLink!!.slavePublicKey) } dismiss() delegate?.onDeviceLinkCanceled() diff --git a/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceSlaveModeDialog.kt b/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceSlaveModeDialog.kt index 744cdaa29a..6f99502ccc 100644 --- a/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceSlaveModeDialog.kt +++ b/src/org/thoughtcrime/securesms/loki/dialogs/LinkDeviceSlaveModeDialog.kt @@ -41,7 +41,7 @@ class LinkDeviceSlaveModeDialog : DialogFragment(), DeviceLinkingSessionListener } override fun onDeviceLinkRequestAuthorized(deviceLink: DeviceLink) { - if (deviceLink.type != DeviceLink.Type.AUTHORIZATION || deviceLink.slaveHexEncodedPublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.deviceLink != null) { return } + if (deviceLink.type != DeviceLink.Type.AUTHORIZATION || deviceLink.slavePublicKey != TextSecurePreferences.getLocalNumber(context!!) || this.deviceLink != null) { return } Util.runOnMain { this.deviceLink = deviceLink DeviceLinkingSession.shared.stopListeningForLinkingRequests() diff --git a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt index 40311e35cf..cbcbfb3b71 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocol.kt @@ -18,7 +18,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.loki.api.SnodeAPI -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol import java.util.* @@ -32,7 +32,7 @@ object ClosedGroupsProtocol { if (!conversation.address.isClosedGroup || groupID == null) { return false } // A closed group's members should never include slave devices val senderPublicKey = content.sender - LokiFileServerAPI.shared.getDeviceLinks(senderPublicKey).timeout(6000).get() + FileServerAPI.shared.getDeviceLinks(senderPublicKey).timeout(6000).get() val senderMasterPublicKey = MultiDeviceProtocol.shared.getMasterDevice(senderPublicKey) val publicKeyToCheckFor = senderMasterPublicKey ?: senderPublicKey val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupID, true) @@ -57,7 +57,7 @@ object ClosedGroupsProtocol { } else { // A closed group's members should never include slave devices val members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupID, false) - return LokiFileServerAPI.shared.getDeviceLinks(members.map { it.address.serialize() }.toSet()).map { + return FileServerAPI.shared.getDeviceLinks(members.map { it.address.serialize() }.toSet()).map { val result = members.flatMap { member -> MultiDeviceProtocol.shared.getAllLinkedDevices(member.address.serialize()).map { Address.fromSerialized(it) } }.toMutableSet() @@ -106,7 +106,7 @@ object ClosedGroupsProtocol { allDevices.remove(userPublicKey) } for (device in allDevices) { - ApplicationContext.getInstance(context).sendSessionRequest(device) + ApplicationContext.getInstance(context).sendSessionRequestIfNeeded(device) } } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt index 50d95cf379..a0e164cfc1 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt @@ -140,7 +140,6 @@ object FriendRequestProtocol { fun handleFriendRequestAcceptanceIfNeeded(context: Context, publicKey: String, content: SignalServiceContent) { // If we get an envelope that isn't a friend request, then we can infer that we had to use // Signal cipher decryption and thus that we have a session with the other person. - if (content.isFriendRequest) { return } val recipient = recipient(context, publicKey) // Friend requests don't apply to groups if (recipient.isGroupRecipient) { return } @@ -200,7 +199,6 @@ object FriendRequestProtocol { @JvmStatic fun handleFriendRequestMessageIfNeeded(context: Context, publicKey: String, content: SignalServiceContent) { - if (!content.isFriendRequest) { return } val recipient = recipient(context, publicKey) // Friend requests don't apply to groups if (recipient.isGroupRecipient) { return } @@ -241,7 +239,7 @@ object FriendRequestProtocol { @JvmStatic fun isFriendRequestFromBeforeRestoration(context: Context, content: SignalServiceContent): Boolean { - return content.isFriendRequest && content.timestamp < TextSecurePreferences.getRestorationTime(context) + return content.timestamp < TextSecurePreferences.getRestorationTime(context) } @JvmStatic diff --git a/src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt b/src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt index 067a25b27c..7804a1479b 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt @@ -3,30 +3,30 @@ package org.thoughtcrime.securesms.loki.protocol import android.content.Context import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.DatabaseFactory -import org.whispersystems.libsignal.loki.LokiSessionResetProtocol -import org.whispersystems.libsignal.loki.LokiSessionResetStatus +import org.whispersystems.libsignal.loki.SessionResetProtocol +import org.whispersystems.libsignal.loki.SessionResetStatus import org.whispersystems.libsignal.protocol.PreKeySignalMessage -class LokiSessionResetImplementation(private val context: Context) : LokiSessionResetProtocol { +class LokiSessionResetImplementation(private val context: Context) : SessionResetProtocol { - override fun getSessionResetStatus(hexEncodedPublicKey: String): LokiSessionResetStatus { - return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(hexEncodedPublicKey) + override fun getSessionResetStatus(publicKey: String): SessionResetStatus { + return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(publicKey) } - override fun setSessionResetStatus(hexEncodedPublicKey: String, sessionResetStatus: LokiSessionResetStatus) { - return DatabaseFactory.getLokiThreadDatabase(context).setSessionResetStatus(hexEncodedPublicKey, sessionResetStatus) + override fun setSessionResetStatus(publicKey: String, sessionResetStatus: SessionResetStatus) { + return DatabaseFactory.getLokiThreadDatabase(context).setSessionResetStatus(publicKey, sessionResetStatus) } - override fun onNewSessionAdopted(hexEncodedPublicKey: String, oldSessionResetStatus: LokiSessionResetStatus) { - if (oldSessionResetStatus == LokiSessionResetStatus.IN_PROGRESS) { - val ephemeralMessage = EphemeralMessage.create(hexEncodedPublicKey) + override fun onNewSessionAdopted(publicKey: String, oldSessionResetStatus: SessionResetStatus) { + if (oldSessionResetStatus == SessionResetStatus.IN_PROGRESS) { + val ephemeralMessage = EphemeralMessage.create(publicKey) ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) } // TODO: Show session reset succeed message } - override fun validatePreKeySignalMessage(sender: String, message: PreKeySignalMessage) { - val preKeyRecord = DatabaseFactory.getLokiPreKeyRecordDatabase(context).getPreKeyRecord(sender) ?: return + override fun validatePreKeySignalMessage(publicKey: String, message: PreKeySignalMessage) { + val preKeyRecord = DatabaseFactory.getLokiPreKeyRecordDatabase(context).getPreKeyRecord(publicKey) ?: return // TODO: Checking that the pre key record isn't null is causing issues when it shouldn't check(preKeyRecord.id == (message.preKeyId ?: -1)) { "Received a background message from an unknown source." } } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt index 2c6ed90ff0..ff8a8eb0a6 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt @@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.logging.Log import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.SignalServiceMessageSender import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -43,7 +43,7 @@ class MultiDeviceOpenGroupUpdateJob private constructor(parameters: Parameters) return } // Gather open groups - val openGroups = mutableListOf() + val openGroups = mutableListOf() DatabaseFactory.getGroupDatabase(context).groups.use { reader -> while (true) { val record = reader.next ?: return@use diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index 4486d76795..34d7dab213 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.push.SignalServiceAddress -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLinkingSession @@ -80,7 +80,7 @@ object MultiDeviceProtocol { } } val publicKey = recipient.address.serialize() - LokiFileServerAPI.shared.getDeviceLinks(publicKey).success { + FileServerAPI.shared.getDeviceLinks(publicKey).success { val devices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey) val jobs = devices.map { sendMessagePushToDevice(context, recipient(context, it), messageID, messageType, isEndSession) } @Suppress("UNCHECKED_CAST") @@ -105,7 +105,7 @@ object MultiDeviceProtocol { // A request should include a pre key bundle. An authorization should be a normal message. if (deviceLink.type == DeviceLink.Type.REQUEST) { val preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.number) - message.asFriendRequest(true).withPreKeyBundle(preKeyBundle) + message.withPreKeyBundle(preKeyBundle) } else { // Include the user's profile key so that the slave device can get the user's profile picture message.withProfileKey(ProfileKeyUtil.getProfileKey(context)) @@ -135,7 +135,7 @@ object MultiDeviceProtocol { return Promise.ofFail(Exception("Failed to sign device link.")) } return retryIfNeeded(8) { - sendDeviceLinkMessage(context, deviceLink.slaveHexEncodedPublicKey, signedDeviceLink) + sendDeviceLinkMessage(context, deviceLink.slavePublicKey, signedDeviceLink) } } @@ -144,7 +144,7 @@ object MultiDeviceProtocol { val userPublicKey = TextSecurePreferences.getLocalNumber(context) if (deviceLink.type == DeviceLink.Type.REQUEST) { handleDeviceLinkRequestMessage(context, deviceLink, content) - } else if (deviceLink.slaveHexEncodedPublicKey == userPublicKey) { + } else if (deviceLink.slavePublicKey == userPublicKey) { handleDeviceLinkAuthorizedMessage(context, deviceLink, content) } } @@ -158,10 +158,10 @@ object MultiDeviceProtocol { } else if (isRequest && TextSecurePreferences.getMasterHexEncodedPublicKey(context) != null) { Log.d("Loki", "Ignoring unexpected device link message (the device is a slave device).") return false - } else if (isRequest && deviceLink.masterHexEncodedPublicKey != userPublicKey) { + } else if (isRequest && deviceLink.masterPublicKey != userPublicKey) { Log.d("Loki", "Ignoring device linking message addressed to another user.") return false - } else if (isRequest && deviceLink.slaveHexEncodedPublicKey == userPublicKey) { + } else if (isRequest && deviceLink.slavePublicKey == userPublicKey) { Log.d("Loki", "Ignoring device linking request message from self.") return false } @@ -193,9 +193,9 @@ object MultiDeviceProtocol { val userPublicKey = TextSecurePreferences.getLocalNumber(context) DatabaseFactory.getLokiAPIDatabase(context).clearDeviceLinks(userPublicKey) DatabaseFactory.getLokiAPIDatabase(context).addDeviceLink(deviceLink) - TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterHexEncodedPublicKey) + TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterPublicKey) TextSecurePreferences.setMultiDevice(context, true) - LokiFileServerAPI.shared.addDeviceLink(deviceLink) + FileServerAPI.shared.addDeviceLink(deviceLink) org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content) org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.duplicate_handleProfileKey(context, content) } @@ -210,19 +210,19 @@ object MultiDeviceProtocol { // Ignore the request if we don't know about the device link in question val masterDeviceLinks = DatabaseFactory.getLokiAPIDatabase(context).getDeviceLinks(masterDevicePublicKey) if (masterDeviceLinks.none { - it.masterHexEncodedPublicKey == masterDevicePublicKey && it.slaveHexEncodedPublicKey == userPublicKey + it.masterPublicKey == masterDevicePublicKey && it.slavePublicKey == userPublicKey }) { return } - LokiFileServerAPI.shared.getDeviceLinks(userPublicKey, true).success { slaveDeviceLinks -> + FileServerAPI.shared.getDeviceLinks(userPublicKey, true).success { slaveDeviceLinks -> // Check that the device link IS present on the file server. // Note that the device link as seen from the master device's perspective has been deleted at this point, but the // device link as seen from the slave perspective hasn't. if (slaveDeviceLinks.any { - it.masterHexEncodedPublicKey == masterDevicePublicKey && it.slaveHexEncodedPublicKey == userPublicKey + it.masterPublicKey == masterDevicePublicKey && it.slavePublicKey == userPublicKey }) { for (slaveDeviceLink in slaveDeviceLinks) { // In theory there should only be one - LokiFileServerAPI.shared.removeDeviceLink(slaveDeviceLink) // Attempt to clean up on the file server + FileServerAPI.shared.removeDeviceLink(slaveDeviceLink) // Attempt to clean up on the file server } TextSecurePreferences.setWasUnlinked(context, true) ApplicationContext.getInstance(context).clearData() diff --git a/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt index 565d25f670..7c28f9fa90 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt @@ -44,12 +44,11 @@ class PushEphemeralMessageSendJob private constructor(parameters: Parameters, pr // Attach a pre key bundle if needed if (message.get("friendRequest", false)) { val bundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(recipient) - dataMessage.withPreKeyBundle(bundle).asFriendRequest(true) + dataMessage.withPreKeyBundle(bundle) } // Set flags if needed (these are mutually exclusive) when { - message.get("unpairingRequest", false) -> dataMessage.asUnlinkingRequest(true) - message.get("sessionRestore", false) -> dataMessage.asSessionRestorationRequest(true) + message.get("unpairingRequest", false) -> dataMessage.asDeviceUnlinkingRequest(true) message.get("sessionRequest", false) -> dataMessage.asSessionRequest(true) } // Send the message diff --git a/src/org/thoughtcrime/securesms/loki/protocol/PushNullMessageSendJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/PushNullMessageSendJob.kt index a0e745b626..90b8ef0e00 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/PushNullMessageSendJob.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/PushNullMessageSendJob.kt @@ -56,7 +56,7 @@ class PushNullMessageSendJob private constructor(parameters: Parameters, private try { messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess, Date().time, serializedContentMessage, false, ttl, false, - false, false, false, false) + false, false, false) } catch (e: Exception) { Log.d("Loki", "Failed to send null message to: $publicKey due to error: $e.") throw e diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt index be4663ba4e..28b651f2c3 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt @@ -13,7 +13,7 @@ import org.thoughtcrime.securesms.loki.utilities.recipient import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.sms.OutgoingTextMessage import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.libsignal.loki.LokiSessionResetStatus +import org.whispersystems.libsignal.loki.SessionResetStatus import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol import java.util.* @@ -93,7 +93,7 @@ object SessionManagementProtocol { val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) Log.d("Loki", "Received a session reset request from: ${content.sender}; archiving the session.") sessionStore.archiveAllSessions(content.sender) - lokiThreadDB.setSessionResetStatus(content.sender, LokiSessionResetStatus.REQUEST_RECEIVED) + lokiThreadDB.setSessionResetStatus(content.sender, SessionResetStatus.REQUEST_RECEIVED) Log.d("Loki", "Sending an ephemeral message back to: ${content.sender}.") val ephemeralMessage = EphemeralMessage.create(content.sender) ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index db0a8a85d7..10f43aed36 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -22,7 +22,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceGroup import org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsInputStream import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus @@ -151,7 +151,7 @@ object SyncMessagesProtocol { } @JvmStatic - fun handleOpenGroupSyncMessage(context: Context, content: SignalServiceContent, openGroups: List) { + fun handleOpenGroupSyncMessage(context: Context, content: SignalServiceContent, openGroups: List) { val userPublicKey = TextSecurePreferences.getLocalNumber(context) val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey) if (!allUserDevices.contains(content.sender)) { return } diff --git a/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt b/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt index de10a226fe..4846412ae7 100644 --- a/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt @@ -66,7 +66,7 @@ class LokiRSSFeedPoller(private val context: Context, private val feed: LokiRSSF val id = feed.id.toByteArray() val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, SignalServiceGroup.GroupType.RSS_FEED, null, null, null, null) val x2 = SignalServiceDataMessage(timestamp, x1, null, body) - val x3 = SignalServiceContent(x2, "Loki", SignalServiceAddress.DEFAULT_DEVICE_ID, timestamp, false, false, false, false) + val x3 = SignalServiceContent(x2, "Loki", SignalServiceAddress.DEFAULT_DEVICE_ID, timestamp, false, false, false) PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.absent()) } }.fail { exception -> diff --git a/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt index b6a9dad67b..9ab84e53fb 100644 --- a/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt @@ -47,7 +47,7 @@ object ContactUtilities { var isSlave = false if (!recipient.isGroupRecipient) { val deviceLinks = lokiAPIDatabase.getDeviceLinks(publicKey) - isSlave = deviceLinks.find { it.slaveHexEncodedPublicKey == publicKey } != null + isSlave = deviceLinks.find { it.slavePublicKey == publicKey } != null } result.add(Contact(recipient, isFriend, isSlave, isUserDevice)) } diff --git a/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt index ea4a9f02ba..d9d572f093 100644 --- a/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt @@ -8,20 +8,20 @@ import org.thoughtcrime.securesms.crypto.ProfileKeyUtil import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat +import org.whispersystems.signalservice.loki.api.opengroups.PublicChat object OpenGroupUtilities { - @JvmStatic fun addGroup(context: Context, url: String, channel: Long): Promise { + @JvmStatic fun addGroup(context: Context, url: String, channel: Long): Promise { // Check for an existing group - val groupID = LokiPublicChat.getId(channel, url) + val groupID = PublicChat.getId(channel, url) val threadID = GroupManager.getOpenGroupThreadID(groupID, context) val openGroup = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID) if (openGroup != null) { return Promise.of(openGroup) } // Add the new group val application = ApplicationContext.getInstance(context) val displayName = TextSecurePreferences.getProfileName(context) - val lokiPublicChatAPI = application.lokiPublicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.") + val lokiPublicChatAPI = application.publicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.") return application.lokiPublicChatManager.addChat(url, channel).then { group -> DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url) DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url) diff --git a/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt b/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt index cba87e5bee..4b1392aeb8 100644 --- a/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt +++ b/src/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.thoughtcrime.securesms.mms.GlideRequests -import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChatAPI +import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI import org.whispersystems.signalservice.loki.protocol.mentions.Mention class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { @@ -31,13 +31,13 @@ class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: private fun update() { displayNameTextView.text = mentionCandidate.displayName - profilePictureView.hexEncodedPublicKey = mentionCandidate.hexEncodedPublicKey + profilePictureView.hexEncodedPublicKey = mentionCandidate.publicKey profilePictureView.additionalHexEncodedPublicKey = null profilePictureView.isRSSFeed = false profilePictureView.glide = glide!! profilePictureView.update() if (publicChatServer != null && publicChatChannel != null) { - val isUserModerator = LokiPublicChatAPI.isUserModerator(mentionCandidate.hexEncodedPublicKey, publicChatChannel!!, publicChatServer!!) + val isUserModerator = PublicChatAPI.isUserModerator(mentionCandidate.publicKey, publicChatChannel!!, publicChatServer!!) moderatorIconImageView.visibility = if (isUserModerator) View.VISIBLE else View.GONE } else { moderatorIconImageView.visibility = View.GONE diff --git a/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java b/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java index 27f7ddd87f..a592c3be86 100644 --- a/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java +++ b/src/org/thoughtcrime/securesms/mms/PushMediaConstraints.java @@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.mms; import android.content.Context; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.signalservice.loki.api.fileserver.LokiFileServerAPI; +import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI; public class PushMediaConstraints extends MediaConstraints { @@ -22,26 +22,26 @@ public class PushMediaConstraints extends MediaConstraints { @Override public int getImageMaxSize(Context context) { - return LokiFileServerAPI.Companion.getMaxFileSize(); + return FileServerAPI.Companion.getMaxFileSize(); } @Override public int getGifMaxSize(Context context) { - return LokiFileServerAPI.Companion.getMaxFileSize(); + return FileServerAPI.Companion.getMaxFileSize(); } @Override public int getVideoMaxSize(Context context) { - return LokiFileServerAPI.Companion.getMaxFileSize(); + return FileServerAPI.Companion.getMaxFileSize(); } @Override public int getAudioMaxSize(Context context) { - return LokiFileServerAPI.Companion.getMaxFileSize(); + return FileServerAPI.Companion.getMaxFileSize(); } @Override public int getDocumentMaxSize(Context context) { - return LokiFileServerAPI.Companion.getMaxFileSize(); + return FileServerAPI.Companion.getMaxFileSize(); } } diff --git a/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java b/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java index d27752fac3..4e1d198a15 100644 --- a/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java +++ b/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.push; import android.content.Context; import org.thoughtcrime.securesms.crypto.SecurityEvent; -import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.push.SignalServiceAddress; @@ -18,19 +17,4 @@ public class MessageSenderEventListener implements SignalServiceMessageSender.Ev public void onSecurityEvent(SignalServiceAddress textSecureAddress) { SecurityEvent.broadcastSecurityUpdateEvent(context); } - - @Override - public void onFriendRequestSending(long messageID, long threadID) { - FriendRequestProtocol.setFriendRequestStatusToSendingIfNeeded(context, messageID, threadID); - } - - @Override - public void onFriendRequestSent(long messageID, long threadID) { - FriendRequestProtocol.setFriendRequestStatusToSentIfNeeded(context, messageID, threadID); - } - - @Override - public void onFriendRequestSendingFailed(long messageID, long threadID) { - FriendRequestProtocol.setFriendRequestStatusToFailedIfNeeded(context, messageID, threadID); - } } From 455471b20ec05c4ade34f917deacf8d4bfc84c8f Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 15 Jul 2020 14:26:20 +1000 Subject: [PATCH 03/18] Remove the concept of friend requests --- res/layout/conversation_item_received.xml | 277 ++++++++------- res/layout/conversation_item_sent.xml | 239 +++++++------ res/values-pl/strings.xml | 1 + res/values-ru/strings.xml | 1 + res/values/strings.xml | 1 - .../securesms/ApplicationContext.java | 16 +- .../securesms/GroupCreateActivity.java | 2 +- .../securesms/InviteActivity.java | 2 +- .../components/TypingStatusSender.java | 2 +- .../conversation/ConversationActivity.java | 87 +---- .../conversation/ConversationAdapter.java | 9 +- .../conversation/ConversationFragment.java | 3 - .../conversation/ConversationItem.java | 21 +- .../securesms/database/SmsDatabase.java | 7 +- .../database/helpers/SQLCipherOpenHelper.java | 3 +- .../database/model/SmsMessageRecord.java | 23 +- .../SignalCommunicationModule.java | 4 +- .../jobs/MultiDeviceContactUpdateJob.java | 1 - .../securesms/jobs/PushDecryptJob.java | 42 +-- .../securesms/jobs/PushMediaSendJob.java | 58 +--- .../securesms/jobs/PushTextSendJob.java | 51 +-- .../activities/CreateClosedGroupLoader.kt | 3 +- .../securesms/loki/activities/HomeActivity.kt | 42 +-- .../loki/activities/LandingActivity.kt | 4 +- .../loki/activities/SettingsActivity.kt | 2 +- .../loki/api/BackgroundPollWorker.kt | 2 +- ...licChatManager.kt => PublicChatManager.kt} | 10 +- ...ublicChatPoller.kt => PublicChatPoller.kt} | 10 +- .../loki/database/LokiMessageDatabase.kt | 37 +- .../loki/database/LokiThreadDatabase.kt | 31 -- .../database/LokiThreadDatabaseDelegate.kt | 1 - .../fragments/ContactSelectionListLoader.kt | 12 +- .../loki/protocol/EphemeralMessage.kt | 5 +- .../loki/protocol/FriendRequestProtocol.kt | 316 ------------------ .../loki/protocol/MultiDeviceProtocol.kt | 38 +-- .../protocol/SessionManagementProtocol.kt | 4 +- .../loki/protocol/SessionMetaProtocol.kt | 21 +- ...ation.kt => SessionResetImplementation.kt} | 2 +- .../loki/protocol/SyncMessagesProtocol.kt | 46 +-- .../loki/utilities/ContactUtilities.kt | 10 +- .../loki/utilities/NotificationUtilities.kt | 8 +- .../loki/utilities/OpenGroupUtilities.kt | 2 +- .../securesms/loki/views/ConversationView.kt | 10 +- .../securesms/loki/views/FriendRequestView.kt | 190 ----------- .../loki/views/MentionCandidateView.kt | 4 +- .../loki/views/ProfilePictureView.kt | 22 +- .../securesms/loki/views/UserView.kt | 12 +- .../securesms/mms/OutgoingMediaMessage.java | 1 - .../notifications/DefaultMessageNotifier.java | 2 +- .../notifications/MarkReadReceiver.java | 2 +- .../OptimizedMessageNotifier.java | 26 +- .../securesms/sms/MessageSender.java | 11 - .../securesms/sms/OutgoingTextMessage.java | 1 - 53 files changed, 405 insertions(+), 1332 deletions(-) rename src/org/thoughtcrime/securesms/loki/api/{LokiPublicChatManager.kt => PublicChatManager.kt} (93%) rename src/org/thoughtcrime/securesms/loki/api/{LokiPublicChatPoller.kt => PublicChatPoller.kt} (94%) delete mode 100644 src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt rename src/org/thoughtcrime/securesms/loki/protocol/{LokiSessionResetImplementation.kt => SessionResetImplementation.kt} (94%) delete mode 100644 src/org/thoughtcrime/securesms/loki/views/FriendRequestView.kt diff --git a/res/layout/conversation_item_received.xml b/res/layout/conversation_item_received.xml index 999f79089c..fa22c50cb7 100644 --- a/res/layout/conversation_item_received.xml +++ b/res/layout/conversation_item_received.xml @@ -45,174 +45,159 @@ + android:clipChildren="false" + android:background="@color/white" + tools:backgroundTint="@color/conversation_blue"> + android:layout_marginStart="@dimen/message_bubble_horizontal_padding" + android:layout_marginBottom="@dimen/medium_spacing" + android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" + android:orientation="horizontal" + android:visibility="gone" + tools:visibility="visible"> - - - - - - - - - - - - - - - - - - - - - - - - - + android:maxLines="1" + android:ellipsize="end" + tools:visibility="visible" + tools:text="+14152222222"/> - + android:paddingStart="4sp" + android:paddingEnd="4sp" + style="@style/Signal.Text.Preview" + android:fontFamily="sans-serif-regular" + android:textColor="?conversation_item_received_text_primary_color" + android:textStyle="italic" + android:maxLines="1" + android:ellipsize="end" + tools:text="~Clement Duval"/> - + + + + + + + + + android:layout="@layout/conversation_item_received_link_preview" /> + + + + + + + + + + diff --git a/res/layout/conversation_item_sent.xml b/res/layout/conversation_item_sent.xml index c89e2b8a5d..87f39bbca6 100644 --- a/res/layout/conversation_item_sent.xml +++ b/res/layout/conversation_item_sent.xml @@ -23,150 +23,135 @@ android:clipChildren="false"> + android:clipChildren="false" + android:background="@color/white" + tools:backgroundTint="@color/core_grey_05"> - + android:layout_marginStart="@dimen/large_spacing" + android:layout_marginBottom="@dimen/medium_spacing" + android:layout_marginEnd="@dimen/large_spacing" + android:visibility="gone" + app:message_type="outgoing" + app:quote_colorPrimary="@color/text" + app:quote_colorSecondary="@color/text" + tools:visibility="visible"/> - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + Łączność Grupy zamknięte Otwórz grupy + diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index b604866aa1..1cd7a756ef 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -1358,6 +1358,7 @@ + Продолжить Копировать Неверная ссылка diff --git a/res/values/strings.xml b/res/values/strings.xml index 10f2ca0e38..d92843d0a8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1655,7 +1655,6 @@ - Continue Copy Invalid URL diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index cb4c969603..bdd2ae5c47 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -61,13 +61,13 @@ import org.thoughtcrime.securesms.logging.PersistentLogger; import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger; import org.thoughtcrime.securesms.loki.activities.HomeActivity; import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker; -import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager; +import org.thoughtcrime.securesms.loki.api.PublicChatManager; import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager; import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage; -import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation; +import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation; import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob; import org.thoughtcrime.securesms.loki.utilities.Broadcaster; import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier; @@ -154,7 +154,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // Loki public MessageNotifier messageNotifier = null; public Poller lokiPoller = null; - public LokiPublicChatManager lokiPublicChatManager = null; + public PublicChatManager publicChatManager = null; private PublicChatAPI publicChatAPI = null; public Broadcaster broadcaster = null; public SignalCommunicationModule communicationModule; @@ -184,7 +184,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(this); LokiUserDatabase userDB = DatabaseFactory.getLokiUserDatabase(this); String userPublicKey = TextSecurePreferences.getLocalNumber(this); - LokiSessionResetImplementation sessionResetImpl = new LokiSessionResetImplementation(this); + SessionResetImplementation sessionResetImpl = new SessionResetImplementation(this); if (userPublicKey != null) { SwarmAPI.Companion.configureIfNeeded(apiDB); SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster); @@ -203,7 +203,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc } } resubmitProfilePictureIfNeeded(); - lokiPublicChatManager = new LokiPublicChatManager(this); + publicChatManager = new PublicChatManager(this); updateOpenGroupProfilePicturesIfNeeded(); registerForFCMIfNeeded(false); // ======== @@ -229,8 +229,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // Loki if (lokiPoller != null) { lokiPoller.setCaughtUp(false); } startPollingIfNeeded(); - lokiPublicChatManager.markAllAsNotCaughtUp(); - lokiPublicChatManager.startPollersIfNeeded(); + publicChatManager.markAllAsNotCaughtUp(); + publicChatManager.startPollersIfNeeded(); } @Override @@ -241,7 +241,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc messageNotifier.setVisibleThread(-1); // Loki if (lokiPoller != null) { lokiPoller.stopIfNeeded(); } - if (lokiPublicChatManager != null) { lokiPublicChatManager.stopPollers(); } + if (publicChatManager != null) { publicChatManager.stopPollers(); } } @Override diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index ede18c5061..5763292046 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -322,7 +322,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity @Override public void onClick(View v) { Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class); - intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS); + intent.putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_CONTACTS); startActivityForResult(intent, PICK_CONTACT); } } diff --git a/src/org/thoughtcrime/securesms/InviteActivity.java b/src/org/thoughtcrime/securesms/InviteActivity.java index 4fbb2bd052..cf4bd2fdd8 100644 --- a/src/org/thoughtcrime/securesms/InviteActivity.java +++ b/src/org/thoughtcrime/securesms/InviteActivity.java @@ -53,7 +53,7 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState, boolean ready) { - getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_FRIENDS); + getIntent().putExtra(ContactSelectionListFragment.DISPLAY_MODE, DisplayMode.FLAG_CONTACTS); getIntent().putExtra(ContactSelectionListFragment.MULTI_SELECT, true); getIntent().putExtra(ContactSelectionListFragment.REFRESHABLE, false); diff --git a/src/org/thoughtcrime/securesms/components/TypingStatusSender.java b/src/org/thoughtcrime/securesms/components/TypingStatusSender.java index dc510073fc..0cd6e33663 100644 --- a/src/org/thoughtcrime/securesms/components/TypingStatusSender.java +++ b/src/org/thoughtcrime/securesms/components/TypingStatusSender.java @@ -84,7 +84,7 @@ public class TypingStatusSender { ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); Recipient recipient = threadDatabase.getRecipientForThreadId(threadId); // Loki - Check whether we want to send a typing indicator to this user - if (!SessionMetaProtocol.shouldSendTypingIndicator(recipient, context)) { return; } + if (recipient != null && !SessionMetaProtocol.shouldSendTypingIndicator(recipient.getAddress())) { return; } // Loki - Take into account multi device Set linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.getAddress().serialize()); for (String device : linkedDevices) { diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index ab0983abd5..72e29bb344 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -68,7 +68,6 @@ import android.view.View.OnFocusChangeListener; import android.view.View.OnKeyListener; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; @@ -81,7 +80,6 @@ import com.annimon.stream.Stream; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import org.jetbrains.annotations.NotNull; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.ExpirationDialog; import org.thoughtcrime.securesms.GroupCreateActivity; @@ -159,10 +157,8 @@ import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabaseDelegate; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol; -import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol; import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities; -import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate; import org.thoughtcrime.securesms.loki.views.MentionCandidateSelectionView; import org.thoughtcrime.securesms.loki.views.SessionRestoreBannerView; import org.thoughtcrime.securesms.mediasend.Media; @@ -231,7 +227,6 @@ import org.whispersystems.signalservice.loki.protocol.mentions.Mention; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol; import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol; -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus; import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation; import java.io.IOException; @@ -272,8 +267,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity ComposeText.CursorPositionChangedListener, ConversationSearchBottomBar.EventListener, StickerKeyboardProvider.StickerEventListener, - LokiThreadDatabaseDelegate, - FriendRequestViewDelegate + LokiThreadDatabaseDelegate { private static final String TAG = ConversationActivity.class.getSimpleName(); @@ -355,14 +349,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity // Message status bar private ArrayList broadcastReceivers = new ArrayList<>(); - private String messageStatus = null; + private String messageStatus = null; // Mentions - private View mentionCandidateSelectionViewContainer; + private View mentionCandidateSelectionViewContainer; private MentionCandidateSelectionView mentionCandidateSelectionView; - private int currentMentionStartIndex = -1; - private ArrayList mentions = new ArrayList<>(); - private String oldText = ""; + private int currentMentionStartIndex = -1; + private ArrayList mentions = new ArrayList<>(); + private String oldText = ""; // Restoration protected SessionRestoreBannerView sessionRestoreBannerView; @@ -386,7 +380,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity getWindow().getDecorView().setBackgroundColor(color); fragment = initFragment(R.id.fragment_content, new ConversationFragment(), dynamicLanguage.getCurrentLocale()); - fragment.friendRequestViewDelegate = this; registerMessageStatusObserver("calculatingPoW"); registerMessageStatusObserver("contactingNetwork"); @@ -554,8 +547,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this); - updateInputPanel(); - updateSessionRestoreBanner(); Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0))); @@ -2252,26 +2243,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateLinkPreviewState(); } - @Override - public void handleThreadFriendRequestStatusChanged(long threadID) { - if (recipient.isGroupRecipient()) { return; } - boolean isUpdateNeeded = false; - if (threadID == this.threadId) { - isUpdateNeeded = true; - } else { - String thisThreadPublicKey = recipient.getAddress().serialize(); - Set thisThreadAssociatedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(thisThreadPublicKey); - Recipient changedThreadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID); - String changedThreadPublicKey = changedThreadRecipient.getAddress().serialize(); - for (String device : thisThreadAssociatedDevices) { - if (device.equals(changedThreadPublicKey)) { isUpdateNeeded = true; } - } - } - if (isUpdateNeeded) { - updateInputPanel(); - } - } - @Override public void handleSessionRestoreDevicesChanged(long threadID) { if (threadID == this.threadId) { @@ -2279,21 +2250,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } - private void updateInputPanel() { - boolean shouldInputPanelBeEnabled = FriendRequestProtocol.shouldInputPanelBeEnabled(this, recipient); - Util.runOnMain(() -> { - updateToggleButtonState(); - String hint = shouldInputPanelBeEnabled ? "Message" : "Pending session request"; - inputPanel.setHint(hint); - inputPanel.setEnabled(shouldInputPanelBeEnabled); - if (shouldInputPanelBeEnabled && inputPanel.getVisibility() == View.VISIBLE) { - inputPanel.composeText.requestFocus(); - InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); - inputMethodManager.showSoftInput(inputPanel.composeText, 0); - } - }); - } - private void sendMessage() { if (inputPanel.isRecordingInLockedMode()) { inputPanel.releaseRecordingLock(); @@ -2395,11 +2351,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity outgoingMessage = outgoingMessageCandidate; } - // Loki - Send a friend request if we're not yet friends with the user in question - LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId); - outgoingMessage.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS - && !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()); // Needed for stageOutgoingMessage(...) - if (clearComposeBox) { inputPanel.clearQuote(); attachmentManager.clear(glideRequests, false); @@ -2448,11 +2399,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity message = new OutgoingTextMessage(recipient, messageBody, expiresIn, subscriptionId); } - // Loki - Send a friend request if we're not yet friends with the user in question - LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId); - message.isFriendRequest = !isGroupConversation() && friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS - && !SessionMetaProtocol.shared.isNoteToSelf(recipient.getAddress().serialize()); // Needed for stageOutgoingMessage(...) - silentlySetComposeText(""); final long id = fragment.stageOutgoingMessage(message); @@ -2482,13 +2428,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } private void updateToggleButtonState() { - if (!FriendRequestProtocol.shouldAttachmentButtonBeEnabled(this, recipient)) { - buttonToggle.display(sendButton); - quickAttachmentToggle.hide(); - inlineAttachmentToggle.hide(); - return; - } - if (inputPanel.isRecordingInLockedMode()) { buttonToggle.display(sendButton); quickAttachmentToggle.show(); @@ -3192,19 +3131,5 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateSubtitleTextView(); updateMessageStatusProgressBar(); } - - @Override - public void acceptFriendRequest(@NotNull MessageRecord friendRequest) { - if (recipient.isGroupRecipient()) { return; } - FriendRequestProtocol.acceptFriendRequest(this, recipient); - updateInputPanel(); - } - - @Override - public void rejectFriendRequest(@NotNull MessageRecord friendRequest) { - if (recipient.isGroupRecipient()) { return; } - FriendRequestProtocol.rejectFriendRequest(this, recipient); - updateInputPanel(); - } // endregion } diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationAdapter.java b/src/org/thoughtcrime/securesms/conversation/ConversationAdapter.java index 9940097011..a26197a8b0 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationAdapter.java @@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; @@ -108,8 +107,6 @@ public class ConversationAdapter private MessageRecord recordToPulseHighlight; private String searchQuery; - public FriendRequestViewDelegate friendRequestViewDelegate; // Loki - protected static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(final @NonNull V itemView) { super(itemView); @@ -202,11 +199,7 @@ public class ConversationAdapter MessageRecord previousRecord = adapterPosition < getItemCount() - 1 && !isFooterPosition(adapterPosition + 1) ? getRecordForPositionOrThrow(adapterPosition + 1) : null; MessageRecord nextRecord = adapterPosition > 0 && !isHeaderPosition(adapterPosition - 1) ? getRecordForPositionOrThrow(adapterPosition - 1) : null; - BindableConversationItem conversationItem = viewHolder.getView(); - if (conversationItem instanceof ConversationItem) { - ((ConversationItem)conversationItem).friendRequestViewDelegate = this.friendRequestViewDelegate; - } - conversationItem.bind(messageRecord, + viewHolder.getView().bind(messageRecord, Optional.fromNullable(previousRecord), Optional.fromNullable(nextRecord), glideRequests, diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 2a40d8dedb..abc28fd82c 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -79,7 +79,6 @@ import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate; import org.thoughtcrime.securesms.longmessage.LongMessageActivity; import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mms.GlideApp; @@ -151,7 +150,6 @@ public class ConversationFragment extends Fragment private View composeDivider; private View scrollToBottomButton; private TextView scrollDateHeader; - public FriendRequestViewDelegate friendRequestViewDelegate; // Loki @Override public void onCreate(Bundle icicle) { @@ -706,7 +704,6 @@ public class ConversationFragment extends Fragment if (adapter == null) { return; } - adapter.friendRequestViewDelegate = this.friendRequestViewDelegate; if (cursor.getCount() >= PARTIAL_CONVERSATION_LIMIT && loader.hasLimit()) { adapter.setFooterView(topLoadMoreView); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index b1c8f359a0..541e6ac900 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -86,10 +86,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase; import org.thoughtcrime.securesms.loki.utilities.MentionUtilities; -import org.thoughtcrime.securesms.loki.views.FriendRequestView; -import org.thoughtcrime.securesms.loki.views.FriendRequestViewDelegate; import org.thoughtcrime.securesms.loki.views.ProfilePictureView; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.ImageSlide; @@ -158,7 +155,6 @@ public class ConversationItem extends LinearLayout private ViewGroup contactPhotoHolder; private AlertView alertView; private ViewGroup container; - private FriendRequestView friendRequestView; private @NonNull Set batchSelected = new HashSet<>(); private Recipient conversationRecipient; @@ -182,8 +178,6 @@ public class ConversationItem extends LinearLayout private final Context context; - public FriendRequestViewDelegate friendRequestViewDelegate; // Loki - public ConversationItem(Context context) { this(context, null); } @@ -223,7 +217,6 @@ public class ConversationItem extends LinearLayout this.groupSenderHolder = findViewById(R.id.group_sender_holder); this.quoteView = findViewById(R.id.quote_view); this.container = findViewById(R.id.container); - this.friendRequestView = findViewById(R.id.friend_request_view); setOnClickListener(new ClickListener(null)); @@ -269,7 +262,6 @@ public class ConversationItem extends LinearLayout setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setFooter(messageRecord, nextMessageRecord, locale, groupThread); - setFriendRequestView(messageRecord); adjustMarginsIfNeeded(messageRecord); } @@ -807,8 +799,8 @@ public class ConversationItem extends LinearLayout layoutParams.setMarginStart((groupThread && !isRSSFeed) ? groupThreadMargin : defaultMargin); bodyBubble.setLayoutParams(layoutParams); if (profilePictureView == null) return; - profilePictureView.setHexEncodedPublicKey(recipient.getAddress().toString()); - profilePictureView.setAdditionalHexEncodedPublicKey(null); + profilePictureView.setPublicKey(recipient.getAddress().toString()); + profilePictureView.setAdditionalPublicKey(null); profilePictureView.setRSSFeed(false); profilePictureView.setGlide(glideRequests); profilePictureView.update(); @@ -920,11 +912,6 @@ public class ConversationItem extends LinearLayout } } - private void setFriendRequestView(@NonNull MessageRecord record) { - friendRequestView.setDelegate(friendRequestViewDelegate); - friendRequestView.update(record); - } - private ConversationItemFooter getActiveFooter(@NonNull MessageRecord messageRecord) { if (hasSticker(messageRecord)) { return stickerFooter; @@ -1067,10 +1054,8 @@ public class ConversationItem extends LinearLayout int spacingBottom = spacingTop; boolean isOutgoingStack = current.isOutgoing() && previous.orNull() != null && previous.get().isOutgoing(); - LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); - boolean isPreviousMessageFriendRequest = previous.orNull() != null && lokiMessageDatabase.isFriendRequest(previous.get().id); - if (isOutgoingStack && isPreviousMessageFriendRequest) { + if (isOutgoingStack) { spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default); } diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 0c2200688c..5b99737b18 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -885,7 +885,7 @@ public class SmsDatabase extends MessagingDatabase { 0, message.isSecureMessage() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(), threadId, 0, new LinkedList(), message.getSubscriptionId(), message.getExpiresIn(), - System.currentTimeMillis(), 0, false, message.isFriendRequest); + System.currentTimeMillis(), 0, false); } } @@ -934,15 +934,12 @@ public class SmsDatabase extends MessagingDatabase { List mismatches = getMismatches(mismatchDocument); Recipient recipient = Recipient.from(context, address, true); - // Loki - Check to see if this message was a friend request - boolean isFriendRequest = DatabaseFactory.getLokiMessageDatabase(context).isFriendRequest(messageId); - return new SmsMessageRecord(messageId, body, recipient, recipient, addressDeviceId, dateSent, dateReceived, deliveryReceiptCount, type, threadId, status, mismatches, subscriptionId, - expiresIn, expireStarted, readReceiptCount, unidentified, isFriendRequest); + expiresIn, expireStarted, readReceiptCount, unidentified); } private List getMismatches(String document) { diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index 945cd0249b..a2482a5b17 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -145,10 +145,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand()); db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand()); db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand()); - db.execSQL(LokiMessageDatabase.getCreateMessageFriendRequestTableCommand()); + db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand()); db.execSQL(LokiMessageDatabase.getCreateMessageToThreadMappingTableCommand()); db.execSQL(LokiMessageDatabase.getCreateErrorMessageTableCommand()); - db.execSQL(LokiThreadDatabase.getCreateFriendRequestTableCommand()); db.execSQL(LokiThreadDatabase.getCreateSessionResetTableCommand()); db.execSQL(LokiThreadDatabase.getCreatePublicChatTableCommand()); db.execSQL(LokiUserDatabase.getCreateDisplayNameTableCommand()); diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java index 52c9700ebe..056dbacb45 100644 --- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java @@ -39,23 +39,6 @@ import network.loki.messenger.R; */ public class SmsMessageRecord extends MessageRecord { - // Loki - private final boolean isFriendRequest; - - public SmsMessageRecord(long id, - String body, Recipient recipient, - Recipient individualRecipient, - int recipientDeviceId, - long dateSent, long dateReceived, - int deliveryReceiptCount, - long type, long threadId, - int status, List mismatches, - int subscriptionId, long expiresIn, long expireStarted, - int readReceiptCount, boolean unidentified) - { - this(id, body, recipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, deliveryReceiptCount, type, threadId, status, mismatches, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, false); - } - public SmsMessageRecord(long id, String body, Recipient recipient, Recipient individualRecipient, @@ -65,22 +48,18 @@ public class SmsMessageRecord extends MessageRecord { long type, long threadId, int status, List mismatches, int subscriptionId, long expiresIn, long expireStarted, - int readReceiptCount, boolean unidentified, boolean isFriendRequest) + int readReceiptCount, boolean unidentified) { super(id, body, recipient, individualRecipient, recipientDeviceId, dateSent, dateReceived, threadId, status, deliveryReceiptCount, type, mismatches, new LinkedList<>(), subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified); - this.isFriendRequest = isFriendRequest; } public long getType() { return type; } - // Loki - public boolean isFriendRequest() { return isFriendRequest; } - @Override public SpannableString getDisplayBody(@NonNull Context context) { Recipient recipient = getRecipient(); diff --git a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java index a06ebe5eba..79a875c817 100644 --- a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java +++ b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java @@ -45,7 +45,7 @@ import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob; import org.thoughtcrime.securesms.jobs.TypingSendJob; import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation; +import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob; import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment; import org.thoughtcrime.securesms.push.MessageSenderEventListener; @@ -156,7 +156,7 @@ public class SignalCommunicationModule { DatabaseFactory.getLokiThreadDatabase(context), DatabaseFactory.getLokiMessageDatabase(context), DatabaseFactory.getLokiPreKeyBundleDatabase(context), - new LokiSessionResetImplementation(context), + new SessionResetImplementation(context), DatabaseFactory.getLokiUserDatabase(context), ((ApplicationContext)context.getApplicationContext()).broadcaster); } else { diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java index 2c18845211..4cd977c0d4 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -139,7 +139,6 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy Optional identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address); Optional verifiedMessage = getVerifiedMessage(recipient, identityRecord); - // Loki - Only sync contacts we are friends with if (SyncMessagesProtocol.shouldSyncContact(context, address)) { out.write(new DeviceContact(address.toPhoneString(), Optional.fromNullable(recipient.getName()), diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 1f1e39db7c..31c0ab7710 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -66,15 +66,11 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.loki.activities.HomeActivity; import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase; -import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol; -import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage; -import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol; -import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; -import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob; import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol; +import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation; import org.thoughtcrime.securesms.loki.protocol.SyncMessagesProtocol; import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities; import org.thoughtcrime.securesms.loki.utilities.PromiseUtilities; @@ -130,7 +126,6 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI; import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus; import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation; import java.security.MessageDigest; @@ -145,8 +140,6 @@ import javax.inject.Inject; import network.loki.messenger.R; -import static org.thoughtcrime.securesms.loki.utilities.RecipientUtilitiesKt.recipient; - public class PushDecryptJob extends BaseJob implements InjectableType { public static final String KEY = "PushDecryptJob"; @@ -225,9 +218,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } @Override - public void onCanceled() { - - } + public void onCanceled() { } public void processMessage(@NonNull SignalServiceEnvelope envelope, boolean isPushNotification) { synchronized (PushReceivedJob.RECEIVE_LOCK) { @@ -264,18 +255,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType { try { GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context); - SessionResetProtocol sessionResetProtocol = new LokiSessionResetImplementation(context); + SessionResetProtocol sessionResetProtocol = new SessionResetImplementation(context); SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context)); LokiServiceCipher cipher = new LokiServiceCipher(localAddress, axolotlStore, sessionResetProtocol, UnidentifiedAccessUtil.getCertificateValidator()); SignalServiceContent content = cipher.decrypt(envelope); - // Loki - Ignore any friend requests from before restoration - if (FriendRequestProtocol.isFriendRequestFromBeforeRestoration(context, content)) { - Log.d("Loki", "Ignoring friend request from before restoration."); - return; - } - if (shouldIgnore(content)) { Log.i(TAG, "Ignoring message."); return; @@ -300,8 +285,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { if (message.isDeviceUnlinkingRequest()) { MultiDeviceProtocol.handleUnlinkingRequestIfNeeded(context, content); } else { - // Loki - Handle friend request acceptance if needed - FriendRequestProtocol.handleFriendRequestAcceptanceIfNeeded(context, content.getSender(), content); if (message.isEndSession()) { handleEndSessionMessage(content, smsMessageId); @@ -311,14 +294,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { handleExpirationUpdate(content, message, smsMessageId); } else if (isMediaMessage) { handleMediaMessage(content, message, smsMessageId, Optional.absent()); - - // Loki - Handle friend request message if needed - FriendRequestProtocol.handleFriendRequestMessageIfNeeded(context, content.getSender(), content); } else if (message.getBody().isPresent()) { handleTextMessage(content, message, smsMessageId, Optional.absent()); - - // Loki - Handle friend request message if needed - FriendRequestProtocol.handleFriendRequestMessageIfNeeded(context, content.getSender(), content); } if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get()))) { @@ -364,7 +341,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } else if (content.getTypingMessage().isPresent()) { handleTypingMessage(content, content.getTypingMessage().get()); } else if (content.getNullMessage().isPresent()) { - // Loki - This is needed for compatibility with refactored desktop clients // ======== // if (content.isFriendRequest()) { @@ -372,18 +348,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // } else { // Log.w(TAG, "Got unrecognized message..."); // } - Recipient recipient = recipient(context, content.getSender()); - long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient); - LokiThreadDatabase threadDB = DatabaseFactory.getLokiThreadDatabase(context); - LokiThreadFriendRequestStatus threadFriendRequestStatus = threadDB.getFriendRequestStatus(threadID); - if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.NONE || threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) { - threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED); - } else if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) { - threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS); - EphemeralMessage ephemeralMessage = EphemeralMessage.create(content.getSender()); - ApplicationContext.getInstance(context).getJobManager().add(new PushEphemeralMessageSendJob(ephemeralMessage)); - SyncMessagesProtocol.syncContact(context, Address.fromSerialized(content.getSender())); - } // ======== } diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 682054b856..3a70c4fc18 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import com.annimon.stream.Stream; @@ -31,7 +30,6 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.libsignal.state.PreKeyBundle; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; @@ -64,46 +62,34 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id"; private static final String KEY_MESSAGE_ID = "message_id"; private static final String KEY_DESTINATION = "destination"; - private static final String KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE = "is_friend_request"; - private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message"; @Inject SignalServiceMessageSender messageSender; - private long messageId; // The message ID - private long templateMessageId; // The message ID of the message to template this send job from - - // Loki - Multi device - private Address destination; // Used to check whether this is another device we're sending to - private boolean isLokiPreKeyBundleMessage; // Whether this is a friend request / session request / device link message - private String customFriendRequestMessage; // If this isn't set then we use the message body + private long messageId; + private long templateMessageId; + private Address destination; public PushMediaSendJob(long messageId, Address destination) { this(messageId, messageId, destination); } public PushMediaSendJob(long templateMessageId, long messageId, Address destination) { - this(templateMessageId, messageId, destination, false, null); + this(constructParameters(destination), templateMessageId, messageId, destination); } - public PushMediaSendJob(long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) { - this(constructParameters(destination), templateMessageId, messageId, destination, isLokiPreKeyBundleMessage, customFriendRequestMessage); - } - - private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) { + private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination) { super(parameters); this.templateMessageId = templateMessageId; this.messageId = messageId; this.destination = destination; - this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage; - this.customFriendRequestMessage = customFriendRequestMessage; } public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination) { - enqueue(context, jobManager, messageId, messageId, destination, false, null); + enqueue(context, jobManager, messageId, messageId, destination); } - public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination, Boolean isFriendRequest, @Nullable String customFriendRequestMessage) { - enqueue(context, jobManager, Collections.singletonList(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage))); + public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination) { + enqueue(context, jobManager, Collections.singletonList(new PushMediaSendJob(templateMessageId, messageId, destination))); } @WorkerThread @@ -144,14 +130,10 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { @Override public @NonNull Data serialize() { - Data.Builder builder = new Data.Builder() - .putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId) - .putLong(KEY_MESSAGE_ID, messageId) - .putString(KEY_DESTINATION, destination.serialize()) - .putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage); - - if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); } - return builder.build(); + return new Data.Builder() + .putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId) + .putLong(KEY_MESSAGE_ID, messageId) + .putString(KEY_DESTINATION, destination.serialize()).build(); } @Override @@ -270,17 +252,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { List sharedContacts = getSharedContactsFor(message); List previews = getPreviewsFor(message); - // Loki - Include a pre key bundle if needed - PreKeyBundle preKeyBundle; - if (isLokiPreKeyBundleMessage) { - preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber()); - } else { - preKeyBundle = null; - } - - String body = (isLokiPreKeyBundleMessage && customFriendRequestMessage != null) ? customFriendRequestMessage : message.getBody(); SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder() - .withBody(body) + .withBody(message.getBody()) .withAttachments(serviceAttachments) .withTimestamp(message.getSentTimeMillis()) .withExpiration((int)(message.getExpiresIn() / 1000)) @@ -290,7 +263,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { .withSharedContacts(sharedContacts) .withPreviews(previews) .asExpirationUpdate(message.isExpirationUpdate()) - .withPreKeyBundle(preKeyBundle) .build(); if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) { @@ -326,9 +298,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID); long messageID = data.getLong(KEY_MESSAGE_ID); Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION)); - boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE); - String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null; - return new PushMediaSendJob(parameters, templateMessageID, messageID, destination, isLokiPreKeyBundleMessage, customFRMessage); + return new PushMediaSendJob(parameters, templateMessageID, messageID, destination); } } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index c2c019a3d6..3854760a24 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.libsignal.state.PreKeyBundle; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; @@ -47,50 +46,34 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { private static final String KEY_TEMPLATE_MESSAGE_ID = "template_message_id"; private static final String KEY_MESSAGE_ID = "message_id"; private static final String KEY_DESTINATION = "destination"; - private static final String KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE = "is_friend_request"; - private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message"; @Inject SignalServiceMessageSender messageSender; - private long messageId; // The message ID - private long templateMessageId; // The message ID of the message to template this send job from - - // Loki - Multi device - private Address destination; // Used to check whether this is another device we're sending to - private boolean isLokiPreKeyBundleMessage; // Whether this is a friend request / session request / device link message - private String customFriendRequestMessage; // If this isn't set then we use the message body + private long messageId; + private long templateMessageId; + private Address destination; public PushTextSendJob(long messageId, Address destination) { this(messageId, messageId, destination); } public PushTextSendJob(long templateMessageId, long messageId, Address destination) { - this(templateMessageId, messageId, destination, false, null); + this(constructParameters(destination), templateMessageId, messageId, destination); } - public PushTextSendJob(long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) { - this(constructParameters(destination), templateMessageId, messageId, destination, isLokiPreKeyBundleMessage, customFriendRequestMessage); - } - - private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isLokiPreKeyBundleMessage, String customFriendRequestMessage) { + private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination) { super(parameters); this.templateMessageId = templateMessageId; this.messageId = messageId; this.destination = destination; - this.isLokiPreKeyBundleMessage = isLokiPreKeyBundleMessage; - this.customFriendRequestMessage = customFriendRequestMessage; } @Override public @NonNull Data serialize() { - Data.Builder builder = new Data.Builder() - .putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId) - .putLong(KEY_MESSAGE_ID, messageId) - .putString(KEY_DESTINATION, destination.serialize()) - .putBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE, isLokiPreKeyBundleMessage); - - if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); } - return builder.build(); + return new Data.Builder() + .putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId) + .putLong(KEY_MESSAGE_ID, messageId) + .putString(KEY_DESTINATION, destination.serialize()).build(); } @Override @@ -213,22 +196,12 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { log(TAG, "Have access key to use: " + unidentifiedAccess.isPresent()); - // Loki - Include a pre key bundle if needed - PreKeyBundle preKeyBundle; - if (isLokiPreKeyBundleMessage || message.isEndSession()) { - preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber()); - } else { - preKeyBundle = null; - } - - String body = (isLokiPreKeyBundleMessage && customFriendRequestMessage != null) ? customFriendRequestMessage : message.getBody(); SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder() .withTimestamp(message.getDateSent()) - .withBody(body) + .withBody(message.getBody()) .withExpiration((int)(message.getExpiresIn() / 1000)) .withProfileKey(profileKey.orNull()) .asEndSessionMessage(message.isEndSession()) - .withPreKeyBundle(preKeyBundle) .build(); if (SessionMetaProtocol.shared.isNoteToSelf(address.getNumber())) { @@ -261,9 +234,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { long templateMessageID = data.getLong(KEY_TEMPLATE_MESSAGE_ID); long messageID = data.getLong(KEY_MESSAGE_ID); Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION)); - boolean isLokiPreKeyBundleMessage = data.getBoolean(KEY_IS_LOKI_PRE_KEY_BUNDLE_MESSAGE); - String customFRMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null; - return new PushTextSendJob(parameters, templateMessageID, messageID, destination, isLokiPreKeyBundleMessage, customFRMessage); + return new PushTextSendJob(parameters, templateMessageID, messageID, destination); } } } diff --git a/src/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupLoader.kt b/src/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupLoader.kt index 59422993e1..b2999ea6b0 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupLoader.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupLoader.kt @@ -8,9 +8,8 @@ class CreateClosedGroupLoader(context: Context) : AsyncLoader>(cont override fun loadInBackground(): List { val contacts = ContactUtilities.getAllContacts(context) - // Only show the master devices of the users we are friends with return contacts.filter { contact -> - !contact.recipient.isGroupRecipient && contact.isFriend && !contact.isOurDevice && !contact.isSlave + !contact.recipient.isGroupRecipient && !contact.isOurDevice && !contact.isSlave }.map { it.recipient.address.toPhoneString() } diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index a906f26337..3279d14db0 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.database.model.ThreadRecord import org.thoughtcrime.securesms.loki.dialogs.PNModeBottomSheet import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol -import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation +import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation import org.thoughtcrime.securesms.loki.utilities.* import org.thoughtcrime.securesms.loki.views.ConversationView import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetViewDelegate @@ -47,18 +47,16 @@ import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import kotlin.math.abs class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate { private lateinit var glide: GlideRequests - private val hexEncodedPublicKey: String + private val publicKey: String get() { - val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this) - val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this) - return masterHexEncodedPublicKey ?: userHexEncodedPublicKey + val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this) + val userPublicKey = TextSecurePreferences.getLocalNumber(this) + return masterPublicKey ?: userPublicKey } // region Lifecycle @@ -94,7 +92,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe glide = GlideApp.with(this) // Set up toolbar buttons profileButton.glide = glide - profileButton.hexEncodedPublicKey = hexEncodedPublicKey + profileButton.publicKey = publicKey profileButton.update() profileButton.setOnClickListener { openSettings() } pathStatusViewContainer.setOnClickListener { showPath() } @@ -156,45 +154,23 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe val threadDB = DatabaseFactory.getLokiThreadDatabase(this) val userDB = DatabaseFactory.getLokiUserDatabase(this) val userPublicKey = TextSecurePreferences.getLocalNumber(this) - val sessionResetImpl = LokiSessionResetImplementation(this) + val sessionResetImpl = SessionResetImplementation(this) if (userPublicKey != null) { MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB) SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey) SyncMessagesProtocol.configureIfNeeded(apiDB, userPublicKey) - application.lokiPublicChatManager.startPollersIfNeeded() + application.publicChatManager.startPollersIfNeeded() } SessionManagementProtocol.configureIfNeeded(sessionResetImpl, threadDB, application) MultiDeviceProtocol.configureIfNeeded(apiDB) IP2Country.configureIfNeeded(this) // Preload device links to make message sending quicker val publicKeys = ContactUtilities.getAllContacts(this).filter { contact -> - !contact.recipient.isGroupRecipient && contact.isFriend && !contact.isOurDevice && !contact.isSlave + !contact.recipient.isGroupRecipient && !contact.isOurDevice && !contact.isSlave }.map { it.recipient.address.toPhoneString() }.toSet() FileServerAPI.shared.getDeviceLinks(publicKeys) - // TODO: Temporary hack to unbork existing clients - val allContacts = DatabaseFactory.getRecipientDatabase(this).allAddresses.map { - MultiDeviceProtocol.shared.getMasterDevice(it.serialize()) ?: it.serialize() - }.toSet() - val lokiMessageDB = DatabaseFactory.getLokiMessageDatabase(this) - for (contact in allContacts) { - val slaveDeviceHasPendingFR = MultiDeviceProtocol.shared.getSlaveDevices(contact).any { - val slaveDeviceThreadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(recipient(this, it)) - DatabaseFactory.getLokiThreadDatabase(this).getFriendRequestStatus(slaveDeviceThreadID) == LokiThreadFriendRequestStatus.REQUEST_RECEIVED - } - val masterDeviceThreadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(recipient(this, contact)) - val masterDeviceHasNoPendingFR = (DatabaseFactory.getLokiThreadDatabase(this).getFriendRequestStatus(masterDeviceThreadID) == LokiThreadFriendRequestStatus.NONE) - if (slaveDeviceHasPendingFR && masterDeviceHasNoPendingFR) { - val lastMessageID = org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol.getLastMessageID(this, masterDeviceThreadID) - if (lastMessageID != null) { - val lastMessageFRStatus = lokiMessageDB.getFriendRequestStatus(lastMessageID) - if (lastMessageFRStatus != LokiMessageFriendRequestStatus.REQUEST_PENDING) { - lokiMessageDB.setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_PENDING) - } - } - } - } } override fun onResume() { diff --git a/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt index 6ddb1f0a2c..d0de9698bf 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/LandingActivity.kt @@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.database.IdentityDatabase import org.thoughtcrime.securesms.logging.Log import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialog import org.thoughtcrime.securesms.loki.dialogs.LinkDeviceSlaveModeDialogDelegate -import org.thoughtcrime.securesms.loki.protocol.LokiSessionResetImplementation +import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo @@ -109,7 +109,7 @@ class LandingActivity : BaseActionBarActivity(), LinkDeviceSlaveModeDialogDelega val threadDB = DatabaseFactory.getLokiThreadDatabase(this) val userDB = DatabaseFactory.getLokiUserDatabase(this) val userPublicKey = TextSecurePreferences.getLocalNumber(this) - val sessionResetImpl = LokiSessionResetImplementation(this) + val sessionResetImpl = SessionResetImplementation(this) MentionsManager.configureIfNeeded(userPublicKey, threadDB, userDB) SessionMetaProtocol.configureIfNeeded(apiDB, userPublicKey) org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol.configureIfNeeded(apiDB) diff --git a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt index 72482a1691..0cb7b3e45b 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/SettingsActivity.kt @@ -73,7 +73,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() { showQRCodeButton.setOnClickListener { showQRCode() } glide = GlideApp.with(this) profilePictureView.glide = glide - profilePictureView.hexEncodedPublicKey = hexEncodedPublicKey + profilePictureView.publicKey = hexEncodedPublicKey profilePictureView.isLarge = true profilePictureView.update() profilePictureView.setOnClickListener { showEditProfilePictureUI() } diff --git a/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt b/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt index f4808e4563..1d96295f73 100644 --- a/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt +++ b/src/org/thoughtcrime/securesms/loki/api/BackgroundPollWorker.kt @@ -47,7 +47,7 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() { } val openGroups = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats().map { it.value } for (openGroup in openGroups) { - val poller = LokiPublicChatPoller(context, openGroup) + val poller = PublicChatPoller(context, openGroup) poller.stop() poller.pollForNewMessages() } diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt b/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt similarity index 93% rename from src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt rename to src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt index 09f661ac9b..8095731318 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt @@ -14,9 +14,9 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.loki.api.opengroups.PublicChat -class LokiPublicChatManager(private val context: Context) { +class PublicChatManager(private val context: Context) { private var chats = mutableMapOf() - private val pollers = mutableMapOf() + private val pollers = mutableMapOf() private val observers = mutableMapOf() private var isPolling = false @@ -24,7 +24,7 @@ class LokiPublicChatManager(private val context: Context) { var areAllCaughtUp = true refreshChatsAndPollers() for ((threadID, chat) in chats) { - val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat) + val poller = pollers[threadID] ?: PublicChatPoller(context, chat) areAllCaughtUp = areAllCaughtUp && poller.isCaughtUp } return areAllCaughtUp @@ -33,7 +33,7 @@ class LokiPublicChatManager(private val context: Context) { public fun markAllAsNotCaughtUp() { refreshChatsAndPollers() for ((threadID, chat) in chats) { - val poller = pollers[threadID] ?: LokiPublicChatPoller(context, chat) + val poller = pollers[threadID] ?: PublicChatPoller(context, chat) poller.isCaughtUp = false } } @@ -42,7 +42,7 @@ class LokiPublicChatManager(private val context: Context) { refreshChatsAndPollers() for ((threadId, chat) in chats) { - val poller = pollers[threadId] ?: LokiPublicChatPoller(context, chat) + val poller = pollers[threadId] ?: PublicChatPoller(context, chat) poller.startIfNeeded() listenToThreadDeletion(threadId) if (!pollers.containsKey(threadId)) { pollers[threadId] = poller } diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt similarity index 94% rename from src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt rename to src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt index 411859178d..f3473ff413 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt @@ -27,11 +27,10 @@ import org.whispersystems.signalservice.loki.api.opengroups.PublicChat import org.whispersystems.signalservice.loki.api.opengroups.PublicChatAPI import org.whispersystems.signalservice.loki.api.opengroups.PublicChatMessage import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import java.security.MessageDigest import java.util.* -class LokiPublicChatPoller(private val context: Context, private val group: PublicChat) { +class PublicChatPoller(private val context: Context, private val group: PublicChat) { private val handler = Handler() private var hasStarted = false public var isCaughtUp = false @@ -182,13 +181,6 @@ class LokiPublicChatPoller(private val context: Context, private val group: Publ database.setProfileKey(senderAsRecipient, profileKey) ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, url)) } - } else if (senderAsRecipient.profileAvatar.orEmpty().isNotEmpty()) { - // Clear the profile picture if we had a profile picture before and we're not friends with the person - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(senderAsRecipient) - val friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) - if (friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) { - ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(senderAsRecipient, "")) - } } } fun processOutgoingMessage(message: PublicChatMessage) { diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt index 816614f66d..675fbf3ce7 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiMessageDatabase.kt @@ -11,12 +11,11 @@ import org.thoughtcrime.securesms.loki.utilities.getInt import org.thoughtcrime.securesms.loki.utilities.getString import org.thoughtcrime.securesms.loki.utilities.insertOrUpdate import org.whispersystems.signalservice.loki.database.LokiMessageDatabaseProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiMessageDatabaseProtocol { companion object { - private val messageFriendRequestTable = "loki_message_friend_request_database" + private val messageIDTable = "loki_message_friend_request_database" private val messageThreadMappingTable = "loki_message_thread_mapping_database" private val errorMessageTable = "loki_error_message_database" private val messageID = "message_id" @@ -24,7 +23,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab private val friendRequestStatus = "friend_request_status" private val threadID = "thread_id" private val errorMessage = "error_message" - @JvmStatic val createMessageFriendRequestTableCommand = "CREATE TABLE $messageFriendRequestTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" + @JvmStatic val createMessageIDTableCommand = "CREATE TABLE $messageIDTable ($messageID INTEGER PRIMARY KEY, $serverID INTEGER DEFAULT 0, $friendRequestStatus INTEGER DEFAULT 0);" @JvmStatic val createMessageToThreadMappingTableCommand = "CREATE TABLE IF NOT EXISTS $messageThreadMappingTable ($messageID INTEGER PRIMARY KEY, $threadID INTEGER);" @JvmStatic val createErrorMessageTableCommand = "CREATE TABLE IF NOT EXISTS $errorMessageTable ($messageID INTEGER PRIMARY KEY, $errorMessage STRING);" } @@ -36,14 +35,14 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab fun getServerID(messageID: Long): Long? { val database = databaseHelper.readableDatabase - return database.get(messageFriendRequestTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> + return database.get(messageIDTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> cursor.getInt(serverID) }?.toLong() } fun getMessageID(serverID: Long): Long? { val database = databaseHelper.readableDatabase - return database.get(messageFriendRequestTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor -> + return database.get(messageIDTable, "${Companion.serverID} = ?", arrayOf( serverID.toString() )) { cursor -> cursor.getInt(messageID) }?.toLong() } @@ -53,7 +52,7 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab val contentValues = ContentValues(2) contentValues.put(Companion.messageID, messageID) contentValues.put(Companion.serverID, serverID) - database.insertOrUpdate(messageFriendRequestTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) + database.insertOrUpdate(messageIDTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) } fun getOriginalThreadID(messageID: Long): Long { @@ -71,32 +70,6 @@ class LokiMessageDatabase(context: Context, helper: SQLCipherOpenHelper) : Datab database.insertOrUpdate(messageThreadMappingTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) } - fun getFriendRequestStatus(messageID: Long): LokiMessageFriendRequestStatus { - val database = databaseHelper.readableDatabase - val result = database.get(messageFriendRequestTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> - cursor.getInt(friendRequestStatus) - } - return if (result != null) { - LokiMessageFriendRequestStatus.values().first { it.rawValue == result } - } else { - LokiMessageFriendRequestStatus.NONE - } - } - - fun setFriendRequestStatus(messageID: Long, friendRequestStatus: LokiMessageFriendRequestStatus) { - val database = databaseHelper.writableDatabase - val contentValues = ContentValues(2) - contentValues.put(Companion.messageID, messageID) - contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue) - database.insertOrUpdate(messageFriendRequestTable, contentValues, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) - val threadID = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID) - notifyConversationListeners(threadID) - } - - fun isFriendRequest(messageID: Long): Boolean { - return getFriendRequestStatus(messageID) != LokiMessageFriendRequestStatus.NONE - } - fun getErrorMessage(messageID: Long): String? { val database = databaseHelper.readableDatabase return database.get(errorMessageTable, "${Companion.messageID} = ?", arrayOf( messageID.toString() )) { cursor -> diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt index 4df60e594d..5a4697b00c 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabase.kt @@ -15,21 +15,18 @@ import org.whispersystems.libsignal.loki.SessionResetStatus import org.whispersystems.signalservice.internal.util.JsonUtil import org.whispersystems.signalservice.loki.api.opengroups.PublicChat import org.whispersystems.signalservice.loki.database.LokiThreadDatabaseProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol { var delegate: LokiThreadDatabaseDelegate? = null companion object { - private val friendRequestTable = "loki_thread_friend_request_database" private val sessionResetTable = "loki_thread_session_reset_database" val publicChatTable = "loki_public_chat_database" val threadID = "thread_id" private val friendRequestStatus = "friend_request_status" private val sessionResetStatus = "session_reset_status" val publicChat = "public_chat" - @JvmStatic val createFriendRequestTableCommand = "CREATE TABLE $friendRequestTable ($threadID INTEGER PRIMARY KEY, $friendRequestStatus INTEGER DEFAULT 0);" @JvmStatic val createSessionResetTableCommand = "CREATE TABLE $sessionResetTable ($threadID INTEGER PRIMARY KEY, $sessionResetStatus INTEGER DEFAULT 0);" @JvmStatic val createPublicChatTableCommand = "CREATE TABLE $publicChatTable ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);" } @@ -44,34 +41,6 @@ class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Databa return DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID) } - fun getFriendRequestStatus(threadID: Long): LokiThreadFriendRequestStatus { - if (threadID < 0) { return LokiThreadFriendRequestStatus.NONE } - val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID) - if (recipient != null && recipient.isGroupRecipient) { return LokiThreadFriendRequestStatus.FRIENDS; } - val database = databaseHelper.readableDatabase - val result = database.get(friendRequestTable, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor -> - cursor.getInt(friendRequestStatus) - } - return if (result != null) { - LokiThreadFriendRequestStatus.values().first { it.rawValue == result } - } else { - LokiThreadFriendRequestStatus.NONE - } - } - - fun setFriendRequestStatus(threadID: Long, friendRequestStatus: LokiThreadFriendRequestStatus) { - if (threadID < 0) { return } - Log.d("Loki", "Setting FR status for thread with ID $threadID to $friendRequestStatus.") - val database = databaseHelper.writableDatabase - val contentValues = ContentValues(2) - contentValues.put(Companion.threadID, threadID) - contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue) - database.insertOrUpdate(friendRequestTable, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) - notifyConversationListListeners() - notifyConversationListeners(threadID) - delegate?.handleThreadFriendRequestStatusChanged(threadID) - } - fun getSessionResetStatus(hexEncodedPublicKey: String): SessionResetStatus { val threadID = getThreadID(hexEncodedPublicKey) val database = databaseHelper.readableDatabase diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabaseDelegate.kt b/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabaseDelegate.kt index ed64bc5929..a27ea6409e 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabaseDelegate.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiThreadDatabaseDelegate.kt @@ -2,6 +2,5 @@ package org.thoughtcrime.securesms.loki.database interface LokiThreadDatabaseDelegate { - fun handleThreadFriendRequestStatusChanged(threadID: Long) fun handleSessionRestoreDevicesChanged(threadID: Long) } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/fragments/ContactSelectionListLoader.kt b/src/org/thoughtcrime/securesms/loki/fragments/ContactSelectionListLoader.kt index bd04316726..4bfacb84a0 100644 --- a/src/org/thoughtcrime/securesms/loki/fragments/ContactSelectionListLoader.kt +++ b/src/org/thoughtcrime/securesms/loki/fragments/ContactSelectionListLoader.kt @@ -15,10 +15,10 @@ sealed class ContactSelectionListItem { class ContactSelectionListLoader(context: Context, val mode: Int, val filter: String?) : AsyncLoader>(context) { object DisplayMode { - const val FLAG_FRIENDS = 1 + const val FLAG_CONTACTS = 1 const val FLAG_CLOSED_GROUPS = 1 shl 1 const val FLAG_OPEN_GROUPS = 1 shl 2 - const val FLAG_ALL = FLAG_FRIENDS or FLAG_CLOSED_GROUPS or FLAG_OPEN_GROUPS + const val FLAG_ALL = FLAG_CONTACTS or FLAG_CLOSED_GROUPS or FLAG_OPEN_GROUPS } private fun isFlagSet(flag: Int): Boolean { @@ -39,15 +39,15 @@ class ContactSelectionListLoader(context: Context, val mode: Int, val filter: St if (isFlagSet(DisplayMode.FLAG_OPEN_GROUPS)) { list.addAll(getOpenGroups(contacts)) } - if (isFlagSet(DisplayMode.FLAG_FRIENDS)) { - list.addAll(getFriends(contacts)) + if (isFlagSet(DisplayMode.FLAG_CONTACTS)) { + list.addAll(getContacts(contacts)) } return list } - private fun getFriends(contacts: List): List { + private fun getContacts(contacts: List): List { return getItems(contacts, context.getString(R.string.fragment_contact_selection_contacts_title)) { - !it.recipient.isGroupRecipient && it.isFriend && !it.isOurDevice && !it.isSlave + !it.recipient.isGroupRecipient && !it.isOurDevice && !it.isSlave } } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt b/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt index ca46684223..1b04e9d037 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt @@ -10,10 +10,7 @@ class EphemeralMessage private constructor(val data: Map<*, *>) { fun create(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey )) @JvmStatic - fun createUnlinkingRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "unpairingRequest" to true )) - - @JvmStatic - fun createSessionRestorationRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRestore" to true )) + fun createDeviceUnlinkingRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "unpairingRequest" to true )) @JvmStatic fun createSessionRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRequest" to true )) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt deleted file mode 100644 index a0e164cfc1..0000000000 --- a/src/org/thoughtcrime/securesms/loki/protocol/FriendRequestProtocol.kt +++ /dev/null @@ -1,316 +0,0 @@ -package org.thoughtcrime.securesms.loki.protocol - -import android.content.Context -import android.util.Log -import org.thoughtcrime.securesms.ApplicationContext -import org.thoughtcrime.securesms.database.Address -import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.loki.utilities.recipient -import org.thoughtcrime.securesms.mms.OutgoingMediaMessage -import org.thoughtcrime.securesms.recipients.Recipient -import org.thoughtcrime.securesms.sms.MessageSender -import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage -import org.thoughtcrime.securesms.sms.OutgoingTextMessage -import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.whispersystems.signalservice.api.messages.SignalServiceContent -import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol -import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus - -object FriendRequestProtocol { - - @JvmStatic - fun acceptFriendRequest(context: Context, recipient: Recipient) { - if (recipient.isGroupRecipient) { return; } - val userPublicKey = TextSecurePreferences.getLocalNumber(context) - val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey) - // Accept all outstanding friend requests associated with this user and try to establish sessions with the - // subset of their devices that haven't sent a friend request. - val allContactDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize()) - val threadDB = DatabaseFactory.getThreadDatabase(context) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - for (device in allContactDevices) { - val deviceAsRecipient = recipient(context, device) - val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient) - val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID) - if (deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) { - lokiThreadDB.setFriendRequestStatus(deviceThreadID, LokiThreadFriendRequestStatus.FRIENDS) - val lastMessageID = getLastMessageID(context, deviceThreadID) - if (lastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED) - } - DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient(context, device), true) - val ephemeralMessage = EphemeralMessage.create(device) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) - // Sync contact if needed - if (allUserDevices.contains(device)) { return } - val deviceToSync = MultiDeviceProtocol.shared.getMasterDevice(device) ?: device - SyncMessagesProtocol.syncContact(context, Address.fromSerialized(deviceToSync)) - } else if (deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) { - // Do nothing - } else if (!allUserDevices.contains(device) - && (deviceFRStatus == LokiThreadFriendRequestStatus.NONE || deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED)) { - sendAutoGeneratedFriendRequest(context, device) - } - } - } - - @JvmStatic - fun rejectFriendRequest(context: Context, recipient: Recipient) { - if (recipient.isGroupRecipient) { return; } - val linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize()) - val threadDB = DatabaseFactory.getThreadDatabase(context) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - for (device in linkedDevices) { - val deviceAsRecipient = recipient(context, device) - val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient) - val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID) - // We only want to decline incoming requests - if (deviceFRStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) { - // Delete the pre key bundle for the given contact. This ensures that if we send a - // new message after this, it restarts the friend request process from scratch. - DatabaseFactory.getLokiPreKeyBundleDatabase(context).removePreKeyBundle(device) - lokiThreadDB.setFriendRequestStatus(deviceThreadID, LokiThreadFriendRequestStatus.NONE) - val lastMessageID = getLastMessageID(context, deviceThreadID) - if (lastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_REJECTED) - } - } - } - } - - @JvmStatic - fun shouldInputPanelBeEnabled(context: Context, recipient: Recipient): Boolean { - // Friend requests have nothing to do with groups, so if this is a group thread the input panel should be enabled - if (recipient.isGroupRecipient) { return true } - // If this is a note to self the input panel should be enabled - if (SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize())) { return true } - // Gather friend request statuses - val linkedDeviceFRStatuses = mutableSetOf() - val linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize()) - val threadDB = DatabaseFactory.getThreadDatabase(context) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - for (device in linkedDevices) { - val deviceAsRecipient = recipient(context, device) - val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient) - val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID) - linkedDeviceFRStatuses.add(deviceFRStatus) - } - // If the user is friends with any of the other user's devices the input panel should be enabled - if (linkedDeviceFRStatuses.contains(LokiThreadFriendRequestStatus.FRIENDS)) { return true } - // If no friend request has been sent the input panel should be enabled - if (linkedDeviceFRStatuses.all { it == LokiThreadFriendRequestStatus.NONE || it == LokiThreadFriendRequestStatus.REQUEST_EXPIRED }) { return true } - // There must be a pending friend request - return false - } - - @JvmStatic - fun shouldAttachmentButtonBeEnabled(context: Context, recipient: Recipient): Boolean { - // Friend requests have nothing to do with groups, so if this is a group thread the attachment button should be enabled - if (recipient.isGroupRecipient) { return true } - // If this is a note to self the attachment button should be enabled - if (SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize())) { return true } - // Gather friend request statuses - val linkedDeviceFRStatuses = mutableSetOf() - val linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(recipient.address.serialize()) - val threadDB = DatabaseFactory.getThreadDatabase(context) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - for (device in linkedDevices) { - val deviceAsRecipient = recipient(context, device) - val deviceThreadID = threadDB.getThreadIdFor(deviceAsRecipient) - val deviceFRStatus = lokiThreadDB.getFriendRequestStatus(deviceThreadID) - linkedDeviceFRStatuses.add(deviceFRStatus) - } - // If the user is friends with any of the other user's devices the attachment button should be enabled - if (linkedDeviceFRStatuses.contains(LokiThreadFriendRequestStatus.FRIENDS)) { return true } - // Otherwise don't allow attachments - return false - } - - @JvmStatic - fun getLastMessageID(context: Context, threadID: Long): Long? { - val db = DatabaseFactory.getSmsDatabase(context) - val messageCount = db.getMessageCountForThread(threadID) - if (messageCount == 0) { return null } - return db.getIDForMessageAtIndex(threadID, messageCount - 1) - } - - @JvmStatic - fun handleFriendRequestAcceptanceIfNeeded(context: Context, publicKey: String, content: SignalServiceContent) { - // If we get an envelope that isn't a friend request, then we can infer that we had to use - // Signal cipher decryption and thus that we have a session with the other person. - val recipient = recipient(context, publicKey) - // Friend requests don't apply to groups - if (recipient.isGroupRecipient) { return } - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID) - // Guard against invalid state transitions - if (threadFRStatus != LokiThreadFriendRequestStatus.REQUEST_SENDING && threadFRStatus != LokiThreadFriendRequestStatus.REQUEST_SENT - && threadFRStatus != LokiThreadFriendRequestStatus.REQUEST_RECEIVED) { return } - Log.d("Loki", "Received a friend request accepted message from $publicKey.") - lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS) - val lastMessageID = getLastMessageID(context, threadID) - if (lastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED) - } - DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true) - // Send a contact sync message if needed - val userPublicKey = TextSecurePreferences.getLocalNumber(context) - val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey) - if (allUserDevices.contains(publicKey)) { return } - val deviceToSync = MultiDeviceProtocol.shared.getMasterDevice(publicKey) ?: publicKey - SyncMessagesProtocol.syncContact(context, Address.fromSerialized(deviceToSync)) - } - - private fun canFriendRequestBeAutoAccepted(context: Context, publicKey: String): Boolean { - val recipient = recipient(context, publicKey) - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID) - if (threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) { - // This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his - // mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request - // and send a friend request accepted message back to Bob. We don't check that sending the - // friend request accepted message succeeds. Even if it doesn't, the thread's current friend - // request status will be set to FRIENDS for Alice making it possible for Alice to send messages - // to Bob. When Bob receives a message, his thread's friend request status will then be set to - // FRIENDS. If we do check for a successful send before updating Alice's thread's friend request - // status to FRIENDS, we can end up in a deadlock where both users' threads' friend request statuses - // are SENT. - return true - } - // Auto-accept any friend requests from the user's own linked devices - val userPublicKey = TextSecurePreferences.getLocalNumber(context) - val allUserDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey) - if (allUserDevices.contains(publicKey)) { return true } - // Auto-accept if the user is friends with any of the sender's linked devices. - val allSenderDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey) - if (allSenderDevices.any { device -> - val deviceAsRecipient = recipient(context, publicKey) - val deviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(deviceAsRecipient) - lokiThreadDB.getFriendRequestStatus(deviceThreadID) == LokiThreadFriendRequestStatus.FRIENDS - }) { - return true - } - return false - } - - @JvmStatic - fun handleFriendRequestMessageIfNeeded(context: Context, publicKey: String, content: SignalServiceContent) { - val recipient = recipient(context, publicKey) - // Friend requests don't apply to groups - if (recipient.isGroupRecipient) { return } - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID) - if (canFriendRequestBeAutoAccepted(context, publicKey)) { - Log.d("Loki", "Auto-accepting friend request from $publicKey.") - lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS) - val lastMessageID = getLastMessageID(context, threadID) - if (lastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED) - } - DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true) - val ephemeralMessage = EphemeralMessage.create(publicKey) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) - } else if (threadFRStatus != LokiThreadFriendRequestStatus.FRIENDS) { - Log.d("Loki", "Handling friend request from $publicKey.") - // Checking that the sender of the message isn't already a friend is necessary because otherwise - // the following situation can occur: Alice and Bob are friends. Bob loses his database and his - // friend request status is reset to NONE. Bob now sends Alice a friend request. Alice's thread's - // friend request status is reset to RECEIVED - lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED) - val masterPublicKey = MultiDeviceProtocol.shared.getMasterDevice(publicKey) ?: publicKey - val masterThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient(context, masterPublicKey)) - val masterThreadLastMessageID = getLastMessageID(context, masterThreadID) // Messages get routed into the master thread - if (masterThreadLastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(masterThreadLastMessageID, LokiMessageFriendRequestStatus.REQUEST_PENDING) - } else { - // Device link fetching could fail, in which case the message could get routed into the slave thread - val slaveThreadLastMessageID = getLastMessageID(context, threadID) - if (slaveThreadLastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(slaveThreadLastMessageID, LokiMessageFriendRequestStatus.REQUEST_PENDING) - } - } - } - } - - @JvmStatic - fun isFriendRequestFromBeforeRestoration(context: Context, content: SignalServiceContent): Boolean { - return content.timestamp < TextSecurePreferences.getRestorationTime(context) - } - - @JvmStatic - fun shouldUpdateFriendRequestStatusFromOutgoingTextMessage(context: Context, message: OutgoingTextMessage): Boolean { - // The order of these checks matters - if (message.recipient.isGroupRecipient) { return false } - if (message.recipient.address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false } - // TODO: Return true if the message is a device linking request - // TODO: Return false if the message is a session request - return message.isFriendRequest - } - - @JvmStatic - fun shouldUpdateFriendRequestStatusFromOutgoingMediaMessage(context: Context, message: OutgoingMediaMessage): Boolean { - // The order of these checks matters - if (message.recipient.isGroupRecipient) { return false } - if (message.recipient.address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false } - // TODO: Return true if the message is a device linking request - // TODO: Return false if the message is a session request - return message.isFriendRequest - } - - @JvmStatic - fun setFriendRequestStatusToSendingIfNeeded(context: Context, messageID: Long, threadID: Long) { - val messageDB = DatabaseFactory.getLokiMessageDatabase(context) - val messageFRStatus = messageDB.getFriendRequestStatus(messageID) - if (messageFRStatus == LokiMessageFriendRequestStatus.NONE || messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_EXPIRED) { - messageDB.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING) - } - val threadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = threadDB.getFriendRequestStatus(threadID) - if (threadFRStatus == LokiThreadFriendRequestStatus.NONE || threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) { - threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_SENDING) - } - } - - @JvmStatic - fun setFriendRequestStatusToSentIfNeeded(context: Context, messageID: Long, threadID: Long) { - val messageDB = DatabaseFactory.getLokiMessageDatabase(context) - val messageFRStatus = messageDB.getFriendRequestStatus(messageID) - if (messageFRStatus == LokiMessageFriendRequestStatus.NONE || messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_EXPIRED - || messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_SENDING) { - messageDB.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING) - } - val threadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = threadDB.getFriendRequestStatus(threadID) - if (threadFRStatus == LokiThreadFriendRequestStatus.NONE || threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED - || threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING) { - threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_SENT) - } - } - - @JvmStatic - fun setFriendRequestStatusToFailedIfNeeded(context: Context, messageID: Long, threadID: Long) { - val messageDB = DatabaseFactory.getLokiMessageDatabase(context) - val messageFRStatus = messageDB.getFriendRequestStatus(messageID) - if (messageFRStatus == LokiMessageFriendRequestStatus.REQUEST_SENDING) { - messageDB.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_FAILED) - } - val threadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = threadDB.getFriendRequestStatus(threadID) - if (threadFRStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING) { - threadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.NONE) - } - } - - fun sendAutoGeneratedFriendRequest(context: Context, publicKey: String) { - val recipient = recipient(context, publicKey) - val message = OutgoingEncryptedMessage(recipient, "Please accept to enable messages to be synced across devices", 0) - message.isFriendRequest = true - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - MessageSender.send(context, message, threadID, false, null) - } -} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index 34d7dab213..d62331f6c0 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -23,7 +23,6 @@ import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLinkingSession import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.retryIfNeeded object MultiDeviceProtocol { @@ -40,36 +39,6 @@ object MultiDeviceProtocol { sendMessagePush(context, recipient, messageID, MessageType.Media, false) } - private fun sendMessagePushToDevice(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean): PushSendJob { - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - val threadFRStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) - val isNoteToSelf = SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize()) - val isContactFriend = (threadFRStatus == LokiThreadFriendRequestStatus.FRIENDS || isNoteToSelf) // In the note to self case the device linking request was the FR - val isFRMessage = !isContactFriend - val hasVisibleContent = when (messageType) { - MessageType.Text -> DatabaseFactory.getSmsDatabase(context).getMessage(messageID).body.isNotBlank() - MessageType.Media -> { - val outgoingMediaMessage = DatabaseFactory.getMmsDatabase(context).getOutgoingMessage(messageID) - outgoingMediaMessage.body.isNotBlank() || outgoingMediaMessage.attachments.isNotEmpty() - } - } - val shouldSendAutoGeneratedFR = !isContactFriend && !isFRMessage - && !isNoteToSelf && !recipient.address.isGroup // Group threads work through session requests - && hasVisibleContent && !isEndSession - if (!shouldSendAutoGeneratedFR) { - when (messageType) { - MessageType.Text -> return PushTextSendJob(messageID, messageID, recipient.address, isFRMessage, null) - MessageType.Media -> return PushMediaSendJob(messageID, messageID, recipient.address, isFRMessage, null) - } - } else { - val autoGeneratedFRMessage = "Please accept to enable messages to be synced across devices" - when (messageType) { - MessageType.Text -> return PushTextSendJob(messageID, messageID, recipient.address, true, autoGeneratedFRMessage) - MessageType.Media -> return PushMediaSendJob(messageID, messageID, recipient.address, true, autoGeneratedFRMessage) - } - } - } - private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean) { val jobManager = ApplicationContext.getInstance(context).jobManager val isMultiDeviceRequired = !recipient.address.isOpenGroup @@ -82,7 +51,12 @@ object MultiDeviceProtocol { val publicKey = recipient.address.serialize() FileServerAPI.shared.getDeviceLinks(publicKey).success { val devices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey) - val jobs = devices.map { sendMessagePushToDevice(context, recipient(context, it), messageID, messageType, isEndSession) } + val jobs = devices.map { + when (messageType) { + MessageType.Text -> PushTextSendJob(messageID, messageID, recipient(context, it).address) as PushSendJob + MessageType.Media -> PushMediaSendJob(messageID, messageID, recipient(context, it).address) as PushSendJob + } + } @Suppress("UNCHECKED_CAST") when (messageType) { MessageType.Text -> jobManager.startChain(jobs).enqueue() diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt index 28b651f2c3..94533af303 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt @@ -27,8 +27,8 @@ object SessionManagementProtocol { val smsDB = DatabaseFactory.getSmsDatabase(context) val devices = lokiThreadDB.getSessionRestoreDevices(threadID) for (device in devices) { - val sessionRestorationRequest = EphemeralMessage.createSessionRestorationRequest(recipient.address.serialize()) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRestorationRequest)) + val sessionRequest = EphemeralMessage.createSessionRequest(recipient.address.serialize()) + ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRequest)) } val infoMessage = OutgoingTextMessage(recipient, "", 0, 0) val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt index 6c2b73ffb1..538312f801 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt @@ -11,7 +11,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import java.security.MessageDigest object SessionMetaProtocol { @@ -75,31 +74,23 @@ object SessionMetaProtocol { * Should be invoked for the recipient's master device. */ @JvmStatic - fun canUserReplyToNotification(recipient: Recipient, context: Context): Boolean { - val isGroup = recipient.isGroupRecipient - if (isGroup) { return !recipient.address.isRSSFeed } - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS + fun canUserReplyToNotification(recipient: Recipient): Boolean { + return !recipient.address.isRSSFeed } /** * Should be invoked for the recipient's master device. */ @JvmStatic - fun shouldSendReadReceipt(address: Address, context: Context): Boolean { - if (address.isGroup) { return false } - val recipient = Recipient.from(context, address,false) - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS + fun shouldSendReadReceipt(address: Address): Boolean { + return !address.isGroup } /** * Should be invoked for the recipient's master device. */ @JvmStatic - fun shouldSendTypingIndicator(recipient: Recipient?, context: Context): Boolean { - if (recipient == null || recipient.isGroupRecipient) { return false } - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - return DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS + fun shouldSendTypingIndicator(address: Address): Boolean { + return !address.isGroup } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt similarity index 94% rename from src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt rename to src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt index 7804a1479b..bb12235aa5 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/LokiSessionResetImplementation.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt @@ -7,7 +7,7 @@ import org.whispersystems.libsignal.loki.SessionResetProtocol import org.whispersystems.libsignal.loki.SessionResetStatus import org.whispersystems.libsignal.protocol.PreKeySignalMessage -class LokiSessionResetImplementation(private val context: Context) : SessionResetProtocol { +class SessionResetImplementation(private val context: Context) : SessionResetProtocol { override fun getSessionResetStatus(publicKey: String): SessionResetStatus { return DatabaseFactory.getLokiThreadDatabase(context).getSessionResetStatus(publicKey) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index 10f43aed36..fbd4b8ee83 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -24,8 +24,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsI import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream import org.whispersystems.signalservice.loki.api.opengroups.PublicChat import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation import java.util.* @@ -67,9 +65,7 @@ object SyncMessagesProtocol { if (!PublicKeyValidation.isValid(address.serialize())) { return false } if (address.serialize() == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false } if (address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false } - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false)) - val isFriend = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS - return isFriend + return true } @JvmStatic @@ -99,29 +95,9 @@ object SyncMessagesProtocol { for (contactPublicKey in contactPublicKeys) { if (contactPublicKey == userPublicKey || !PublicKeyValidation.isValid(contactPublicKey)) { return } val recipient = recipient(context, contactPublicKey) - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient) - val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context) - val threadFRStatus = lokiThreadDB.getFriendRequestStatus(threadID) - when (threadFRStatus) { - LokiThreadFriendRequestStatus.NONE, LokiThreadFriendRequestStatus.REQUEST_EXPIRED -> { - val contactLinkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(contactPublicKey) - for (device in contactLinkedDevices) { - FriendRequestProtocol.sendAutoGeneratedFriendRequest(context, device) - } - } - LokiThreadFriendRequestStatus.REQUEST_RECEIVED -> { - FriendRequestProtocol.acceptFriendRequest(context, recipient(context, contactPublicKey)) // Takes into account multi device internally - lokiThreadDB.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS) - val lastMessageID = FriendRequestProtocol.getLastMessageID(context, threadID) - if (lastMessageID != null) { - DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED) - } - DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient(context, contactPublicKey), true) - } - else -> { - // Do nothing - } - } + val applicationContext = context.applicationContext as ApplicationContext + applicationContext.sendSessionRequestIfNeeded(contactPublicKey) + // TODO: Make the thread visible } } @@ -136,13 +112,13 @@ object SyncMessagesProtocol { val closedGroups = closedGroupsInputStream.readAll() for (closedGroup in closedGroups) { val signalServiceGroup = SignalServiceGroup( - SignalServiceGroup.Type.UPDATE, - closedGroup.id, - SignalServiceGroup.GroupType.SIGNAL, - closedGroup.name.orNull(), - closedGroup.members, - closedGroup.avatar.orNull(), - closedGroup.admins + SignalServiceGroup.Type.UPDATE, + closedGroup.id, + SignalServiceGroup.GroupType.SIGNAL, + closedGroup.name.orNull(), + closedGroup.members, + closedGroup.avatar.orNull(), + closedGroup.admins ) val signalServiceDataMessage = SignalServiceDataMessage(content.timestamp, signalServiceGroup, null, null) // This establishes sessions internally diff --git a/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt index 9ab84e53fb..67e4f3475b 100644 --- a/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/utilities/ContactUtilities.kt @@ -5,11 +5,9 @@ import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol -import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus data class Contact( val recipient: Recipient, - val isFriend: Boolean, val isSlave: Boolean, val isOurDevice: Boolean ) { @@ -31,10 +29,9 @@ object ContactUtilities { @JvmStatic fun getAllContacts(context: Context): Set { val threadDatabase = DatabaseFactory.getThreadDatabase(context) - val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) - val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) + val userPublicKey = TextSecurePreferences.getLocalNumber(context) val lokiAPIDatabase = DatabaseFactory.getLokiAPIDatabase(context) - val userDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userHexEncodedPublicKey) + val userDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey) val cursor = threadDatabase.conversationList val result = mutableSetOf() threadDatabase.readerFor(cursor).use { reader -> @@ -43,13 +40,12 @@ object ContactUtilities { val recipient = thread.recipient val publicKey = recipient.address.serialize() val isUserDevice = userDevices.contains(publicKey) - val isFriend = lokiThreadDatabase.getFriendRequestStatus(thread.threadId) == LokiThreadFriendRequestStatus.FRIENDS var isSlave = false if (!recipient.isGroupRecipient) { val deviceLinks = lokiAPIDatabase.getDeviceLinks(publicKey) isSlave = deviceLinks.find { it.slavePublicKey == publicKey } != null } - result.add(Contact(recipient, isFriend, isSlave, isUserDevice)) + result.add(Contact(recipient, isSlave, isUserDevice)) } } return result diff --git a/src/org/thoughtcrime/securesms/loki/utilities/NotificationUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/NotificationUtilities.kt index 013f18fa7b..69a00115ec 100644 --- a/src/org/thoughtcrime/securesms/loki/utilities/NotificationUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/utilities/NotificationUtilities.kt @@ -8,11 +8,11 @@ import org.thoughtcrime.securesms.recipients.Recipient fun getOpenGroupDisplayName(recipient: Recipient, threadRecipient: Recipient, context: Context): String { val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(threadRecipient) val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID) - val hexEncodedPublicKey = recipient.address.toString() + val publicKey = recipient.address.toString() val displayName = if (publicChat != null) { - DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, hexEncodedPublicKey) + DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, publicKey) } else { - DatabaseFactory.getLokiUserDatabase(context).getDisplayName(hexEncodedPublicKey) + DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey) } - return displayName ?: hexEncodedPublicKey + return displayName ?: publicKey } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt index d9d572f093..c2abd36dd5 100644 --- a/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/utilities/OpenGroupUtilities.kt @@ -22,7 +22,7 @@ object OpenGroupUtilities { val application = ApplicationContext.getInstance(context) val displayName = TextSecurePreferences.getProfileName(context) val lokiPublicChatAPI = application.publicChatAPI ?: throw Error("LokiPublicChatAPI is not initialized.") - return application.lokiPublicChatManager.addChat(url, channel).then { group -> + return application.publicChatManager.addChat(url, channel).then { group -> DatabaseFactory.getLokiAPIDatabase(context).removeLastMessageServerID(channel, url) DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(channel, url) lokiPublicChatAPI.getMessages(channel, url) diff --git a/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt b/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt index 375cd23a16..26b9762622 100644 --- a/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt @@ -50,18 +50,18 @@ class ConversationView : LinearLayout { unreadMessagesIndicatorView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE if (thread.recipient.isGroupRecipient) { if ("Session Public Chat" == thread.recipient.name) { - profilePictureView.hexEncodedPublicKey = "" + profilePictureView.publicKey = "" profilePictureView.isRSSFeed = true } else { val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toList() ?: listOf() val randomUsers = users.sorted() // Sort to provide a level of stability - profilePictureView.hexEncodedPublicKey = randomUsers.getOrNull(0) ?: "" - profilePictureView.additionalHexEncodedPublicKey = randomUsers.getOrNull(1) ?: "" + profilePictureView.publicKey = randomUsers.getOrNull(0) ?: "" + profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: "" profilePictureView.isRSSFeed = thread.recipient.name == "Loki News" || thread.recipient.name == "Session Updates" } } else { - profilePictureView.hexEncodedPublicKey = thread.recipient.address.toString() - profilePictureView.additionalHexEncodedPublicKey = null + profilePictureView.publicKey = thread.recipient.address.toString() + profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false } profilePictureView.glide = glide diff --git a/src/org/thoughtcrime/securesms/loki/views/FriendRequestView.kt b/src/org/thoughtcrime/securesms/loki/views/FriendRequestView.kt deleted file mode 100644 index ea6556088d..0000000000 --- a/src/org/thoughtcrime/securesms/loki/views/FriendRequestView.kt +++ /dev/null @@ -1,190 +0,0 @@ -package org.thoughtcrime.securesms.loki.views - -import android.content.Context -import android.os.Build -import android.util.AttributeSet -import android.util.TypedValue -import android.view.Gravity -import android.view.View -import android.widget.Button -import android.widget.LinearLayout -import android.widget.ProgressBar -import android.widget.TextView -import com.github.ybq.android.spinkit.style.DoubleBounce -import network.loki.messenger.R -import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord -import org.thoughtcrime.securesms.database.model.MessageRecord -import org.thoughtcrime.securesms.loki.utilities.getColorWithID -import org.thoughtcrime.securesms.loki.utilities.toPx -import org.whispersystems.signalservice.loki.protocol.todo.LokiMessageFriendRequestStatus - -class FriendRequestView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { - private var isUISetUp = false - private var message: MessageRecord? = null - var delegate: FriendRequestViewDelegate? = null - - // region Components - private val topSpacer by lazy { - val result = View(context) - result.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(12, resources)) - result - } - - private val label by lazy { - val result = TextView(context) - result.setTextColor(resources.getColorWithID(R.color.text, context.theme)) - result.textAlignment = TextView.TEXT_ALIGNMENT_CENTER - result.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.small_font_size)) - result - } - - private val buttonLinearLayout by lazy { - val result = LinearLayout(context) - result.orientation = HORIZONTAL - result.setPadding(0, resources.getDimension(R.dimen.medium_spacing).toInt(), 0, 0) - result - } - - private val loaderContainer by lazy { - val result = LinearLayout(context) - val layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(50, resources)) - result.layoutParams = layoutParams - result.gravity = Gravity.CENTER - result - } - // endregion - - // region Initialization - constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) - constructor(context: Context) : this(context, null) - // endregion - - // region Updating - fun update(message: MessageRecord) { - this.message = message - setUpUIIfNeeded() - updateUI() - } - - private fun setUpUIIfNeeded() { - if (isUISetUp) { return } - isUISetUp = true - orientation = VERTICAL - setPadding(toPx(48, resources), 0, toPx(48, resources), 0) - addView(topSpacer) - addView(label) - if (!message!!.isOutgoing) { - val loader = ProgressBar(context) - loader.isIndeterminate = true - loader.indeterminateDrawable = DoubleBounce() - val loaderLayoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(24, resources)) - loader.layoutParams = loaderLayoutParams - loaderContainer.addView(loader) - addView(loaderContainer) - fun button(): Button { - val result = Button(context) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - result.elevation = 0f - result.stateListAnimator = null - } - result.setTextColor(resources.getColorWithID(R.color.text, context.theme)) - result.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.small_font_size)) - result.isAllCaps = false - result.setPadding(0, 0, 0, 0) - val buttonLayoutParams = LayoutParams(0, resources.getDimension(R.dimen.small_button_height).toInt()) - buttonLayoutParams.weight = 1f - result.layoutParams = buttonLayoutParams - return result - } - val rejectButton = button() - rejectButton.text = resources.getString(R.string.view_friend_request_reject_button_title) - rejectButton.setBackgroundResource(R.drawable.unimportant_dialog_button_background) - rejectButton.setOnClickListener { reject() } - buttonLinearLayout.addView(rejectButton) - val acceptButton = button() - acceptButton.text = resources.getString(R.string.view_friend_request_accept_button_title) - acceptButton.setBackgroundResource(R.drawable.prominent_dialog_button_background) - val acceptButtonLayoutParams = acceptButton.layoutParams as LayoutParams - acceptButtonLayoutParams.setMargins(resources.getDimension(R.dimen.medium_spacing).toInt(), 0, 0, 0) - acceptButton.layoutParams = acceptButtonLayoutParams - acceptButton.setOnClickListener { accept() } - buttonLinearLayout.addView(acceptButton) - buttonLinearLayout.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, toPx(50, resources)) - addView(buttonLinearLayout) - } - } - - private fun updateUI() { - val message = message - val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) - val contactID = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(message!!.threadId)!!.address.toString() - val contactDisplayName = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(contactID) ?: contactID - val friendRequestStatus = lokiMessageDatabase.getFriendRequestStatus(message.id) - if (message is MediaMmsMessageRecord) { - visibility = View.GONE - return - } - if (!message.isOutgoing) { - visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.NONE) View.GONE else View.VISIBLE - buttonLinearLayout.visibility = if (friendRequestStatus != LokiMessageFriendRequestStatus.REQUEST_PENDING) View.GONE else View.VISIBLE - loaderContainer.visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.REQUEST_SENDING) View.VISIBLE else View.GONE - val formatID = when (friendRequestStatus) { - LokiMessageFriendRequestStatus.NONE, LokiMessageFriendRequestStatus.REQUEST_SENDING, LokiMessageFriendRequestStatus.REQUEST_FAILED -> return - LokiMessageFriendRequestStatus.REQUEST_PENDING -> R.string.view_friend_request_incoming_pending_message - LokiMessageFriendRequestStatus.REQUEST_ACCEPTED -> R.string.view_friend_request_incoming_accepted_message - LokiMessageFriendRequestStatus.REQUEST_REJECTED -> R.string.view_friend_request_incoming_declined_message - LokiMessageFriendRequestStatus.REQUEST_EXPIRED -> R.string.view_friend_request_incoming_expired_message - } - label.text = resources.getString(formatID, contactDisplayName) - } else { - visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.NONE) View.GONE else View.VISIBLE - buttonLinearLayout.visibility = View.GONE - loaderContainer.visibility = View.GONE - val formatID = when (friendRequestStatus) { - LokiMessageFriendRequestStatus.NONE -> return - LokiMessageFriendRequestStatus.REQUEST_SENDING, LokiMessageFriendRequestStatus.REQUEST_FAILED -> null - LokiMessageFriendRequestStatus.REQUEST_PENDING, LokiMessageFriendRequestStatus.REQUEST_REJECTED -> R.string.view_friend_request_outgoing_pending_message - LokiMessageFriendRequestStatus.REQUEST_ACCEPTED -> R.string.view_friend_request_outgoing_accepted_message - LokiMessageFriendRequestStatus.REQUEST_EXPIRED -> R.string.view_friend_request_outgoing_expired_message - } - if (formatID != null) { - label.text = resources.getString(formatID, contactDisplayName) - } - label.visibility = if (formatID != null) View.VISIBLE else View.GONE - topSpacer.visibility = label.visibility - } - } - // endregion - - // region Interaction - private fun accept() { - val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) - lokiMessageDatabase.setFriendRequestStatus(message!!.id, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED) - updateUI() - delegate?.acceptFriendRequest(message!!) - } - - private fun reject() { - val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) - lokiMessageDatabase.setFriendRequestStatus(message!!.id, LokiMessageFriendRequestStatus.REQUEST_REJECTED) - updateUI() - delegate?.rejectFriendRequest(message!!) - } - // endregion -} - -// region Delegate -interface FriendRequestViewDelegate { - /** - * Implementations of this method should update the thread's friend request status - * and send a friend request accepted message. - */ - fun acceptFriendRequest(friendRequest: MessageRecord) - /** - * Implementations of this method should update the thread's friend request status - * and remove the pre keys associated with the contact. - */ - fun rejectFriendRequest(friendRequest: MessageRecord) -} -// endregion \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt b/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt index 4b1392aeb8..6208150b54 100644 --- a/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/MentionCandidateView.kt @@ -31,8 +31,8 @@ class MentionCandidateView(context: Context, attrs: AttributeSet?, defStyleAttr: private fun update() { displayNameTextView.text = mentionCandidate.displayName - profilePictureView.hexEncodedPublicKey = mentionCandidate.publicKey - profilePictureView.additionalHexEncodedPublicKey = null + profilePictureView.publicKey = mentionCandidate.publicKey + profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false profilePictureView.glide = glide!! profilePictureView.update() diff --git a/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt b/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt index 0e566d6b91..1250be7514 100644 --- a/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt @@ -21,8 +21,8 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences class ProfilePictureView : RelativeLayout { lateinit var glide: GlideRequests - var hexEncodedPublicKey: String? = null - var additionalHexEncodedPublicKey: String? = null + var publicKey: String? = null + var additionalPublicKey: String? = null var isRSSFeed = false var isLarge = false @@ -52,11 +52,11 @@ class ProfilePictureView : RelativeLayout { // region Updating fun update() { - val hexEncodedPublicKey = hexEncodedPublicKey ?: return - val additionalHexEncodedPublicKey = additionalHexEncodedPublicKey - doubleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey != null && !isRSSFeed) View.VISIBLE else View.INVISIBLE - singleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey == null && !isRSSFeed && !isLarge) View.VISIBLE else View.INVISIBLE - largeSingleModeImageViewContainer.visibility = if (additionalHexEncodedPublicKey == null && !isRSSFeed && isLarge) View.VISIBLE else View.INVISIBLE + val publicKey = publicKey ?: return + val additionalPublicKey = additionalPublicKey + doubleModeImageViewContainer.visibility = if (additionalPublicKey != null && !isRSSFeed) View.VISIBLE else View.INVISIBLE + singleModeImageViewContainer.visibility = if (additionalPublicKey == null && !isRSSFeed && !isLarge) View.VISIBLE else View.INVISIBLE + largeSingleModeImageViewContainer.visibility = if (additionalPublicKey == null && !isRSSFeed && isLarge) View.VISIBLE else View.INVISIBLE rssImageView.visibility = if (isRSSFeed) View.VISIBLE else View.INVISIBLE fun setProfilePictureIfNeeded(imageView: ImageView, hexEncodedPublicKey: String, @DimenRes sizeID: Int) { glide.clear(imageView) @@ -76,10 +76,10 @@ class ProfilePictureView : RelativeLayout { imageView.setImageDrawable(null) } } - setProfilePictureIfNeeded(doubleModeImageView1, hexEncodedPublicKey, R.dimen.small_profile_picture_size) - setProfilePictureIfNeeded(doubleModeImageView2, additionalHexEncodedPublicKey ?: "", R.dimen.small_profile_picture_size) - setProfilePictureIfNeeded(singleModeImageView, hexEncodedPublicKey, R.dimen.medium_profile_picture_size) - setProfilePictureIfNeeded(largeSingleModeImageView, hexEncodedPublicKey, R.dimen.large_profile_picture_size) + setProfilePictureIfNeeded(doubleModeImageView1, publicKey, R.dimen.small_profile_picture_size) + setProfilePictureIfNeeded(doubleModeImageView2, additionalPublicKey ?: "", R.dimen.small_profile_picture_size) + setProfilePictureIfNeeded(singleModeImageView, publicKey, R.dimen.medium_profile_picture_size) + setProfilePictureIfNeeded(largeSingleModeImageView, publicKey, R.dimen.large_profile_picture_size) } // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/views/UserView.kt b/src/org/thoughtcrime/securesms/loki/views/UserView.kt index 16ffc77db4..3dd15e318c 100644 --- a/src/org/thoughtcrime/securesms/loki/views/UserView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/UserView.kt @@ -48,20 +48,20 @@ class UserView : LinearLayout { val address = user.address.serialize() if (user.isGroupRecipient) { if ("Session Public Chat" == user.name || user.address.isRSSFeed) { - profilePictureView.hexEncodedPublicKey = "" - profilePictureView.additionalHexEncodedPublicKey = null + profilePictureView.publicKey = "" + profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = true } else { val threadID = GroupManager.getThreadIDFromGroupID(address, context) val users = MentionsManager.shared.userPublicKeyCache[threadID]?.toList() ?: listOf() val randomUsers = users.sorted() // Sort to provide a level of stability - profilePictureView.hexEncodedPublicKey = randomUsers.getOrNull(0) ?: "" - profilePictureView.additionalHexEncodedPublicKey = randomUsers.getOrNull(1) ?: "" + profilePictureView.publicKey = randomUsers.getOrNull(0) ?: "" + profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: "" profilePictureView.isRSSFeed = false } } else { - profilePictureView.hexEncodedPublicKey = address - profilePictureView.additionalHexEncodedPublicKey = null + profilePictureView.publicKey = address + profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = false } profilePictureView.glide = glide diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java index de1f2c9240..091c2e81fc 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java @@ -23,7 +23,6 @@ public class OutgoingMediaMessage { private final int distributionType; private final int subscriptionId; private final long expiresIn; - public boolean isFriendRequest = false; private final QuoteModel outgoingQuote; private final List networkFailures = new LinkedList<>(); diff --git a/src/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index c5b789eff6..660e1a4ecd 100644 --- a/src/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -325,7 +325,7 @@ public class DefaultMessageNotifier implements MessageNotifier { ReplyMethod replyMethod = ReplyMethod.forRecipient(context, recipient); - boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient, context); + boolean canReply = SessionMetaProtocol.canUserReplyToNotification(recipient); PendingIntent quickReplyIntent = canReply ? notificationState.getQuickReplyIntent(context, recipient) : null; PendingIntent remoteReplyIntent = canReply ? notificationState.getRemoteReplyIntent(context, recipient, replyMethod) : null; diff --git a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java index 6e5c32bf0f..9c3cbccfce 100644 --- a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java +++ b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java @@ -93,7 +93,7 @@ public class MarkReadReceiver extends BroadcastReceiver { for (Address address : addressMap.keySet()) { List timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList(); // Loki - Check whether we want to send a read receipt to this user - if (!SessionMetaProtocol.shouldSendReadReceipt(address, context)) { continue; } + if (!SessionMetaProtocol.shouldSendReadReceipt(address)) { continue; } // Loki - Take into account multi device Set linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(address.serialize()); for (String device : linkedDevices) { diff --git a/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java index 12ae011499..a74c0415dc 100644 --- a/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java @@ -7,7 +7,7 @@ import androidx.annotation.MainThread; import androidx.annotation.NonNull; import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.loki.api.LokiPublicChatManager; +import org.thoughtcrime.securesms.loki.api.PublicChatManager; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Debouncer; import org.whispersystems.signalservice.loki.api.Poller; @@ -41,14 +41,14 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@NonNull Context context) { Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; - LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager; + PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp(); } - if (lokiPublicChatManager != null) { - isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp(); + if (publicChatManager != null) { + isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp(); } if (isCaughtUp) { @@ -61,14 +61,14 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@NonNull Context context, long threadId) { Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; - LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager; + PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp(); } - if (lokiPublicChatManager != null) { - isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp(); + if (publicChatManager != null) { + isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp(); } if (isCaughtUp) { @@ -81,14 +81,14 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@NonNull Context context, long threadId, boolean signal) { Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; - LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager; + PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp(); } - if (lokiPublicChatManager != null) { - isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp(); + if (publicChatManager != null) { + isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp(); } if (isCaughtUp) { @@ -101,14 +101,14 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount) { Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; - LokiPublicChatManager lokiPublicChatManager = ApplicationContext.getInstance(context).lokiPublicChatManager; + PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { isCaughtUp = isCaughtUp && lokiPoller.isCaughtUp(); } - if (lokiPublicChatManager != null) { - isCaughtUp = isCaughtUp && lokiPublicChatManager.areAllCaughtUp(); + if (publicChatManager != null) { + isCaughtUp = isCaughtUp && publicChatManager.areAllCaughtUp(); } if (isCaughtUp) { diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 35f48d702c..0ef6d29eeb 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -38,7 +38,6 @@ import org.thoughtcrime.securesms.jobs.MmsSendJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.protocol.FriendRequestProtocol; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -76,11 +75,6 @@ public class MessageSender { long messageId = database.insertMessageOutbox(allocatedThreadId, message, forceSms, System.currentTimeMillis(), insertListener); - // Loki - Set the message's friend request status as soon as it hits the database - if (FriendRequestProtocol.shouldUpdateFriendRequestStatusFromOutgoingTextMessage(context, message)) { - FriendRequestProtocol.setFriendRequestStatusToSendingIfNeeded(context, messageId, allocatedThreadId); - } - sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.isEndSession()); return allocatedThreadId; @@ -107,11 +101,6 @@ public class MessageSender { Recipient recipient = message.getRecipient(); long messageId = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); - // Loki - Set the message's friend request status as soon as it hits the database - if (FriendRequestProtocol.shouldUpdateFriendRequestStatusFromOutgoingMediaMessage(context, message)) { - FriendRequestProtocol.setFriendRequestStatusToSendingIfNeeded(context, messageId, allocatedThreadId); - } - sendMediaMessage(context, recipient, forceSms, messageId, message.getExpiresIn()); return allocatedThreadId; } catch (MmsException e) { diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java index 387fec8fa1..e74cb8ff99 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java @@ -9,7 +9,6 @@ public class OutgoingTextMessage { private final String message; private final int subscriptionId; private final long expiresIn; - public boolean isFriendRequest = false; public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) { this(recipient, message, 0, subscriptionId); From 06f547dc88c8f04c2eac6106586f3ffee48192b3 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 15 Jul 2020 15:14:37 +1000 Subject: [PATCH 04/18] Implement the new protocol --- .../securesms/ApplicationContext.java | 9 +- .../conversation/ConversationActivity.java | 8 ++ .../securesms/jobs/JobManagerFactories.java | 4 +- .../securesms/jobs/PushDecryptJob.java | 24 ++--- .../securesms/jobs/PushTextSendJob.java | 7 ++ .../loki/api/LokiPushNotificationManager.kt | 4 +- .../securesms/loki/api/PublicChatPoller.kt | 2 +- .../loki/protocol/EphemeralMessage.kt | 31 ------ .../protocol/MultiDeviceOpenGroupUpdateJob.kt | 2 +- .../loki/protocol/MultiDeviceProtocol.kt | 10 +- .../protocol/PushEphemeralMessageSendJob.kt | 84 ---------------- .../PushSessionRequestMessageSendJob.kt | 99 +++++++++++++++++++ .../protocol/SessionManagementProtocol.kt | 43 +++----- .../protocol/SessionResetImplementation.kt | 4 +- .../loki/protocol/SyncMessagesProtocol.kt | 2 - .../loki/shelved/LokiRSSFeedPoller.kt | 2 +- .../loki/utilities/MentionUtilities.kt | 12 +-- .../securesms/sms/MessageSender.java | 12 +-- 18 files changed, 168 insertions(+), 191 deletions(-) delete mode 100644 src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt delete mode 100644 src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt create mode 100644 src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index bdd2ae5c47..614019ced9 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -61,14 +61,13 @@ import org.thoughtcrime.securesms.logging.PersistentLogger; import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger; import org.thoughtcrime.securesms.loki.activities.HomeActivity; import org.thoughtcrime.securesms.loki.api.BackgroundPollWorker; -import org.thoughtcrime.securesms.loki.api.PublicChatManager; import org.thoughtcrime.securesms.loki.api.LokiPushNotificationManager; +import org.thoughtcrime.securesms.loki.api.PublicChatManager; import org.thoughtcrime.securesms.loki.database.LokiAPIDatabase; import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase; import org.thoughtcrime.securesms.loki.database.LokiUserDatabase; -import org.thoughtcrime.securesms.loki.protocol.EphemeralMessage; +import org.thoughtcrime.securesms.loki.protocol.PushSessionRequestMessageSendJob; import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation; -import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob; import org.thoughtcrime.securesms.loki.utilities.Broadcaster; import org.thoughtcrime.securesms.notifications.DefaultMessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier; @@ -601,8 +600,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc if (hasSentOrProcessedSessionRequest) { return; } // Send the session request DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestTimestamp(publicKey, new Date().getTime()); - EphemeralMessage sessionRequest = EphemeralMessage.createSessionRequest(publicKey); - jobManager.add(new PushEphemeralMessageSendJob(sessionRequest)); + PushSessionRequestMessageSendJob job = new PushSessionRequestMessageSendJob(publicKey); + jobManager.add(job); } // endregion } diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 72e29bb344..b7e74b8d1b 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -2359,6 +2359,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity final long id = fragment.stageOutgoingMessage(outgoingMessage); + if (!recipient.isGroupRecipient()) { + ApplicationContext.getInstance(this).sendSessionRequestIfNeeded(recipient.getAddress().serialize()); + } + new AsyncTask() { @Override protected Long doInBackground(Void... param) { @@ -2402,6 +2406,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity silentlySetComposeText(""); final long id = fragment.stageOutgoingMessage(message); + if (!recipient.isGroupRecipient()) { + ApplicationContext.getInstance(this).sendSessionRequestIfNeeded(recipient.getAddress().serialize()); + } + new AsyncTask() { @Override protected Long doInBackground(OutgoingTextMessage... messages) { diff --git a/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index c1c869e920..be5aef3962 100644 --- a/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/src/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -14,8 +14,8 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint; import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceOpenGroupUpdateJob; -import org.thoughtcrime.securesms.loki.protocol.PushEphemeralMessageSendJob; import org.thoughtcrime.securesms.loki.protocol.PushNullMessageSendJob; +import org.thoughtcrime.securesms.loki.protocol.PushSessionRequestMessageSendJob; import java.util.Arrays; import java.util.HashMap; @@ -72,7 +72,7 @@ public final class JobManagerFactories { put(TrimThreadJob.KEY, new TrimThreadJob.Factory()); put(TypingSendJob.KEY, new TypingSendJob.Factory()); put(UpdateApkJob.KEY, new UpdateApkJob.Factory()); - put(PushEphemeralMessageSendJob.KEY, new PushEphemeralMessageSendJob.Factory()); + put(PushSessionRequestMessageSendJob.KEY, new PushSessionRequestMessageSendJob.Factory()); put(MultiDeviceOpenGroupUpdateJob.KEY, new MultiDeviceOpenGroupUpdateJob.Factory()); }}; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 31c0ab7710..8d75a599b5 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -68,6 +68,7 @@ import org.thoughtcrime.securesms.loki.activities.HomeActivity; import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; +import org.thoughtcrime.securesms.loki.protocol.PushNullMessageSendJob; import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation; @@ -266,13 +267,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { return; } - // Loki - Handle pre key bundle message if needed SessionManagementProtocol.handlePreKeyBundleMessageIfNeeded(context, content); - // Loki - Handle session request if needed - if (SessionManagementProtocol.handleSessionRequestIfNeeded(context, content)) { return; } // Don't process the message any further - - // Loki - Handle profile update if needed SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content); if (content.getDeviceLink().isPresent()) { @@ -281,7 +277,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { SignalServiceDataMessage message = content.getDataMessage().get(); boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent() || message.getSticker().isPresent(); - // Loki - Handle unlinking request if needed if (message.isDeviceUnlinkingRequest()) { MultiDeviceProtocol.handleUnlinkingRequestIfNeeded(context, content); } else { @@ -341,14 +336,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } else if (content.getTypingMessage().isPresent()) { handleTypingMessage(content, content.getTypingMessage().get()); } else if (content.getNullMessage().isPresent()) { - // Loki - This is needed for compatibility with refactored desktop clients - // ======== -// if (content.isFriendRequest()) { -// ApplicationContext.getInstance(context).getJobManager().add(new PushNullMessageSendJob(content.getSender())); -// } else { -// Log.w(TAG, "Got unrecognized message..."); -// } - // ======== + if (content.preKeyBundleMessage.isPresent()) { + ApplicationContext.getInstance(context).getJobManager().add(new PushNullMessageSendJob(content.getSender())); + } else { + Log.w(TAG, "Got unrecognized message..."); + } } resetRecipientToPush(Recipient.from(context, Address.fromSerialized(content.getSender()), false)); @@ -645,11 +637,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType { DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true); } - // Loki - Handle profile key update if needed handleProfileKey(content, message.getMessage()); } - // Loki - Update profile if needed SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content); if (threadId != null) { @@ -754,7 +744,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); database.beginTransaction(); - // Loki - Ignore message if it has no body and no attachments + // Ignore message if it has no body and no attachments if (mediaMessage.getBody().isEmpty() && mediaMessage.getAttachments().isEmpty() && mediaMessage.getLinkPreviews().isEmpty()) { return; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 3854760a24..6e28d4163c 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libsignal.state.PreKeyBundle; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; @@ -196,11 +197,17 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { log(TAG, "Have access key to use: " + unidentifiedAccess.isPresent()); + PreKeyBundle preKeyBundle = null; + if (message.isEndSession()) { + preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(destination.serialize()); + } + SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder() .withTimestamp(message.getDateSent()) .withBody(message.getBody()) .withExpiration((int)(message.getExpiresIn() / 1000)) .withProfileKey(profileKey.orNull()) + .withPreKeyBundle(preKeyBundle) .asEndSessionMessage(message.isEndSession()) .build(); diff --git a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt index a51ed929bb..39a9c46078 100644 --- a/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/LokiPushNotificationManager.kt @@ -47,11 +47,11 @@ object LokiPushNotificationManager { } @JvmStatic - fun register(token: String, hexEncodedPublicKey: String, context: Context?, force: Boolean) { + fun register(token: String, publicKey: String, context: Context?, force: Boolean) { val oldToken = TextSecurePreferences.getFCMToken(context) val lastUploadDate = TextSecurePreferences.getLastFCMUploadTime(context) if (!force && token == oldToken && System.currentTimeMillis() - lastUploadDate < tokenExpirationInterval) { return } - val parameters = mapOf( "token" to token, "pubKey" to hexEncodedPublicKey ) + val parameters = mapOf( "token" to token, "pubKey" to publicKey ) val url = "$server/register" val body = RequestBody.create(MediaType.get("application/json"), JsonUtil.toJson(parameters)) val request = Request.Builder().url(url).post(body).build() diff --git a/src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt b/src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt index f3473ff413..c89fad387c 100644 --- a/src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/api/PublicChatPoller.kt @@ -165,7 +165,7 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh } val senderHexEncodedPublicKey = masterHexEncodedPublicKey ?: message.publicKey val serviceDataMessage = getDataMessage(message) - val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false, false, false) + val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false, false) if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) { PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) } else { diff --git a/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt b/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt deleted file mode 100644 index 1b04e9d037..0000000000 --- a/src/org/thoughtcrime/securesms/loki/protocol/EphemeralMessage.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.thoughtcrime.securesms.loki.protocol - -import org.whispersystems.signalservice.internal.util.JsonUtil - -class EphemeralMessage private constructor(val data: Map<*, *>) { - - companion object { - - @JvmStatic - fun create(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey )) - - @JvmStatic - fun createDeviceUnlinkingRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "unpairingRequest" to true )) - - @JvmStatic - fun createSessionRequest(publicKey: String) = EphemeralMessage(mapOf( "recipient" to publicKey, "friendRequest" to true, "sessionRequest" to true )) - - internal fun parse(serialized: String): EphemeralMessage { - val data = JsonUtil.fromJson(serialized, Map::class.java) ?: throw IllegalArgumentException("Couldn't parse string to JSON") - return EphemeralMessage(data) - } - } - - fun get(key: String, defaultValue: T): T { - return data[key] as? T ?: defaultValue - } - - fun serialize(): String { - return JsonUtil.toJson(data) - } -} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt index ff8a8eb0a6..70de694044 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceOpenGroupUpdateJob.kt @@ -27,7 +27,7 @@ class MultiDeviceOpenGroupUpdateJob private constructor(parameters: Parameters) constructor() : this(Parameters.Builder() .addConstraint(NetworkConstraint.KEY) - .setQueue("MultiDeviceOpenGroupUpdateJob") + .setQueue(KEY) .setLifespan(TimeUnit.DAYS.toMillis(1)) .setMaxAttempts(Parameters.UNLIMITED) .build()) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index d62331f6c0..e1b1ada7a2 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -30,16 +30,16 @@ object MultiDeviceProtocol { enum class MessageType { Text, Media } @JvmStatic - fun sendTextPush(context: Context, recipient: Recipient, messageID: Long, isEndSession: Boolean) { - sendMessagePush(context, recipient, messageID, MessageType.Text, isEndSession) + fun sendTextPush(context: Context, recipient: Recipient, messageID: Long) { + sendMessagePush(context, recipient, messageID, MessageType.Text) } @JvmStatic fun sendMediaPush(context: Context, recipient: Recipient, messageID: Long) { - sendMessagePush(context, recipient, messageID, MessageType.Media, false) + sendMessagePush(context, recipient, messageID, MessageType.Media) } - private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean) { + private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType) { val jobManager = ApplicationContext.getInstance(context).jobManager val isMultiDeviceRequired = !recipient.address.isOpenGroup if (!isMultiDeviceRequired) { @@ -162,6 +162,8 @@ object MultiDeviceProtocol { } val isValid = isValidDeviceLinkMessage(context, deviceLink) if (!isValid) { return } + // The line below isn't actually necessary because this is called after PushDecryptJob + // calls handlePreKeyBundleMessageIfNeeded, but it also doesn't hurt. SessionManagementProtocol.handlePreKeyBundleMessageIfNeeded(context, content) linkingSession.processLinkingAuthorization(deviceLink) val userPublicKey = TextSecurePreferences.getLocalNumber(context) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt deleted file mode 100644 index 7c28f9fa90..0000000000 --- a/src/org/thoughtcrime/securesms/loki/protocol/PushEphemeralMessageSendJob.kt +++ /dev/null @@ -1,84 +0,0 @@ -package org.thoughtcrime.securesms.loki.protocol - -import org.thoughtcrime.securesms.ApplicationContext -import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil -import org.thoughtcrime.securesms.database.Address -import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.jobmanager.Data -import org.thoughtcrime.securesms.jobmanager.Job -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint -import org.thoughtcrime.securesms.jobs.BaseJob -import org.thoughtcrime.securesms.logging.Log -import org.thoughtcrime.securesms.recipients.Recipient -import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage -import org.whispersystems.signalservice.api.push.SignalServiceAddress -import java.io.IOException -import java.util.concurrent.TimeUnit - -class PushEphemeralMessageSendJob private constructor(parameters: Parameters, private val message: EphemeralMessage) : BaseJob(parameters) { - - companion object { - private const val KEY_MESSAGE = "message" - const val KEY = "PushBackgroundMessageSendJob" - } - - constructor(message: EphemeralMessage) : this(Parameters.Builder() - .addConstraint(NetworkConstraint.KEY) - .setQueue(KEY) - .setLifespan(TimeUnit.DAYS.toMillis(1)) - .setMaxAttempts(1) - .build(), - message) - - override fun serialize(): Data { - return Data.Builder() - .putString(KEY_MESSAGE, message.serialize()) - .build() - } - - override fun getFactoryKey(): String { return KEY } - - public override fun onRun() { - val recipient = message.get("recipient", null) ?: throw IllegalStateException() - val dataMessage = SignalServiceDataMessage.newBuilder().withTimestamp(System.currentTimeMillis()) - // Attach a pre key bundle if needed - if (message.get("friendRequest", false)) { - val bundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(recipient) - dataMessage.withPreKeyBundle(bundle) - } - // Set flags if needed (these are mutually exclusive) - when { - message.get("unpairingRequest", false) -> dataMessage.asDeviceUnlinkingRequest(true) - message.get("sessionRequest", false) -> dataMessage.asSessionRequest(true) - } - // Send the message - val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender() - val address = SignalServiceAddress(recipient) - try { - val udAccess = UnidentifiedAccessUtil.getAccessFor(context, Recipient.from(context, Address.fromSerialized(recipient), false)) - messageSender.sendMessage(0, address, udAccess, dataMessage.build()) // The message ID doesn't matter - } catch (e: Exception) { - Log.d("Loki", "Failed to send background message to: $recipient due to error: $e.") - throw e - } - } - - public override fun onShouldRetry(e: Exception): Boolean { - // Disable since we have our own retrying - return false - } - - override fun onCanceled() { } - - class Factory : Job.Factory { - - override fun create(parameters: Parameters, data: Data): PushEphemeralMessageSendJob { - try { - val messageJSON = data.getString(KEY_MESSAGE) - return PushEphemeralMessageSendJob(parameters, EphemeralMessage.parse(messageJSON)) - } catch (e: IOException) { - throw AssertionError(e) - } - } - } -} diff --git a/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt new file mode 100644 index 0000000000..b55e30aa65 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt @@ -0,0 +1,99 @@ +package org.thoughtcrime.securesms.loki.protocol + +import com.google.protobuf.ByteString +import org.thoughtcrime.securesms.ApplicationContext +import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil +import org.thoughtcrime.securesms.database.Address +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.jobmanager.Data +import org.thoughtcrime.securesms.jobmanager.Job +import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint +import org.thoughtcrime.securesms.jobs.BaseJob +import org.thoughtcrime.securesms.logging.Log +import org.thoughtcrime.securesms.recipients.Recipient +import org.whispersystems.signalservice.api.push.SignalServiceAddress +import org.whispersystems.signalservice.internal.push.SignalServiceProtos +import org.whispersystems.signalservice.loki.protocol.meta.TTLUtilities +import java.io.IOException +import java.security.SecureRandom +import java.util.* +import java.util.concurrent.TimeUnit + +class PushSessionRequestMessageSendJob private constructor(parameters: Parameters, private val publicKey: String) : BaseJob(parameters) { + + companion object { + const val KEY = "PushSessionRequestMessageSendJob" + } + + constructor(publicKey: String) : this(Parameters.Builder() + .addConstraint(NetworkConstraint.KEY) + .setQueue(KEY) + .setLifespan(TimeUnit.DAYS.toMillis(1)) + .setMaxAttempts(1) + .build(), + publicKey) + + override fun serialize(): Data { + return Data.Builder().putString("publicKey", publicKey).build() + } + + override fun getFactoryKey(): String { return KEY } + + public override fun onRun() { + // Prepare + val contentMessage = SignalServiceProtos.Content.newBuilder() + // Attach the pre key bundle message + val preKeyBundleMessage = SignalServiceProtos.PreKeyBundleMessage.newBuilder() + val preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(publicKey) ?: return + preKeyBundleMessage.identityKey = ByteString.copyFrom(preKeyBundle.identityKey.serialize()) + preKeyBundleMessage.deviceId = preKeyBundle.deviceId + preKeyBundleMessage.preKeyId = preKeyBundle.preKeyId + preKeyBundleMessage.signedKeyId = preKeyBundle.signedPreKeyId + preKeyBundleMessage.preKey = ByteString.copyFrom(preKeyBundle.preKey.serialize()) + preKeyBundleMessage.signedKey = ByteString.copyFrom(preKeyBundle.signedPreKey.serialize()) + preKeyBundleMessage.signature = ByteString.copyFrom(preKeyBundle.signedPreKeySignature) + contentMessage.preKeyBundleMessage = preKeyBundleMessage.build() + // Attach the null message + val nullMessage = SignalServiceProtos.NullMessage.newBuilder() + val sr = SecureRandom() + val paddingSize = sr.nextInt(512) + val padding = ByteArray(paddingSize) + sr.nextBytes(padding) + nullMessage.padding = ByteString.copyFrom(padding) + contentMessage.nullMessage = nullMessage.build() + // Send the result + val serializedContentMessage = contentMessage.build().toByteArray() + val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender() + val address = SignalServiceAddress(publicKey) + val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false) + val udAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient) + val ttl = TTLUtilities.getTTL(TTLUtilities.MessageType.SessionRequest) + try { + messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess, + Date().time, serializedContentMessage, false, ttl, false, + true, false, false) + } catch (e: Exception) { + Log.d("Loki", "Failed to send session request to: $publicKey due to error: $e.") + throw e + } + } + + public override fun onShouldRetry(e: Exception): Boolean { + // Disable since we have our own retrying + return false + } + + override fun onCanceled() { } + + class Factory : Job.Factory { + + override fun create(parameters: Parameters, data: Data): PushSessionRequestMessageSendJob { + try { + val publicKey = data.getString("publicKey") + return PushSessionRequestMessageSendJob(parameters, publicKey) + } catch (e: IOException) { + throw AssertionError(e) + } + } + } +} diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt index 94533af303..bf24cc5d10 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt @@ -11,6 +11,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.jobs.CleanPreKeysJob import org.thoughtcrime.securesms.loki.utilities.recipient import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.sms.MessageSender +import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage import org.thoughtcrime.securesms.sms.OutgoingTextMessage import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.libsignal.loki.SessionResetStatus @@ -27,8 +29,8 @@ object SessionManagementProtocol { val smsDB = DatabaseFactory.getSmsDatabase(context) val devices = lokiThreadDB.getSessionRestoreDevices(threadID) for (device in devices) { - val sessionRequest = EphemeralMessage.createSessionRequest(recipient.address.serialize()) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(sessionRequest)) + val endSessionMessage = OutgoingEndSessionMessage(OutgoingTextMessage(recipient, "TERMINATE", 0, -1)) + MessageSender.send(context, endSessionMessage, threadID, false, null) } val infoMessage = OutgoingTextMessage(recipient, "", 0, 0) val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null) @@ -53,37 +55,24 @@ object SessionManagementProtocol { @JvmStatic fun handlePreKeyBundleMessageIfNeeded(context: Context, content: SignalServiceContent) { - val recipient = recipient(context, content.sender) - if (recipient.isGroupRecipient) { return } - val preKeyBundleMessage = content.lokiServiceMessage.orNull()?.preKeyBundleMessage ?: return + val publicKey = content.sender + val recipient = recipient(context, publicKey) + if (recipient.isGroupRecipient) { return } // Should never occur + val preKeyBundleMessage = content.preKeyBundleMessage.orNull() ?: return val registrationID = TextSecurePreferences.getLocalRegistrationId(context) // TODO: It seems wrong to use the local registration ID for this? val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context) - Log.d("Loki", "Received a pre key bundle from: " + content.sender.toString() + ".") - if (content.dataMessage.isPresent && content.dataMessage.get().isSessionRequest) { - val sessionRequestTimestamp = DatabaseFactory.getLokiAPIDatabase(context).getSessionRequestTimestamp(content.sender) - if (sessionRequestTimestamp != null && content.timestamp < sessionRequestTimestamp) { - // We sent or processed a session request after this one was sent - Log.d("Loki", "Ignoring session request from: ${content.sender}.") - return - } - } - val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID) - lokiPreKeyBundleDatabase.setPreKeyBundle(content.sender, preKeyBundle) - } - - @JvmStatic - fun handleSessionRequestIfNeeded(context: Context, content: SignalServiceContent): Boolean { - if (!content.dataMessage.isPresent || !content.dataMessage.get().isSessionRequest) { return false } + Log.d("Loki", "Received a pre key bundle from: $publicKey.") val sessionRequestTimestamp = DatabaseFactory.getLokiAPIDatabase(context).getSessionRequestTimestamp(content.sender) if (sessionRequestTimestamp != null && content.timestamp < sessionRequestTimestamp) { // We sent or processed a session request after this one was sent Log.d("Loki", "Ignoring session request from: ${content.sender}.") - return false + return } + val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID) + lokiPreKeyBundleDatabase.setPreKeyBundle(content.sender, preKeyBundle) DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestTimestamp(content.sender, Date().time) - val ephemeralMessage = EphemeralMessage.create(content.sender) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) - return true + val job = PushNullMessageSendJob(content.sender) + ApplicationContext.getInstance(context).jobManager.add(job) } @JvmStatic @@ -95,8 +84,8 @@ object SessionManagementProtocol { sessionStore.archiveAllSessions(content.sender) lokiThreadDB.setSessionResetStatus(content.sender, SessionResetStatus.REQUEST_RECEIVED) Log.d("Loki", "Sending an ephemeral message back to: ${content.sender}.") - val ephemeralMessage = EphemeralMessage.create(content.sender) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) + val job = PushNullMessageSendJob(content.sender) + ApplicationContext.getInstance(context).jobManager.add(job) SecurityEvent.broadcastSecurityUpdateEvent(context) } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt index bb12235aa5..4c34d64b64 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionResetImplementation.kt @@ -19,8 +19,8 @@ class SessionResetImplementation(private val context: Context) : SessionResetPro override fun onNewSessionAdopted(publicKey: String, oldSessionResetStatus: SessionResetStatus) { if (oldSessionResetStatus == SessionResetStatus.IN_PROGRESS) { - val ephemeralMessage = EphemeralMessage.create(publicKey) - ApplicationContext.getInstance(context).jobManager.add(PushEphemeralMessageSendJob(ephemeralMessage)) + val job = PushNullMessageSendJob(publicKey) + ApplicationContext.getInstance(context).jobManager.add(job) } // TODO: Show session reset succeed message } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index fbd4b8ee83..16ec6aa8de 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -94,10 +94,8 @@ object SyncMessagesProtocol { val contactPublicKeys = contactsInputStream.readAll().map { it.number } for (contactPublicKey in contactPublicKeys) { if (contactPublicKey == userPublicKey || !PublicKeyValidation.isValid(contactPublicKey)) { return } - val recipient = recipient(context, contactPublicKey) val applicationContext = context.applicationContext as ApplicationContext applicationContext.sendSessionRequestIfNeeded(contactPublicKey) - // TODO: Make the thread visible } } diff --git a/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt b/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt index 4846412ae7..2e93f96039 100644 --- a/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt +++ b/src/org/thoughtcrime/securesms/loki/shelved/LokiRSSFeedPoller.kt @@ -66,7 +66,7 @@ class LokiRSSFeedPoller(private val context: Context, private val feed: LokiRSSF val id = feed.id.toByteArray() val x1 = SignalServiceGroup(SignalServiceGroup.Type.UPDATE, id, SignalServiceGroup.GroupType.RSS_FEED, null, null, null, null) val x2 = SignalServiceDataMessage(timestamp, x1, null, body) - val x3 = SignalServiceContent(x2, "Loki", SignalServiceAddress.DEFAULT_DEVICE_ID, timestamp, false, false, false) + val x3 = SignalServiceContent(x2, "Loki", SignalServiceAddress.DEFAULT_DEVICE_ID, timestamp, false, false) PushDecryptJob(context).handleTextMessage(x3, x2, Optional.absent(), Optional.absent()) } }.fail { exception -> diff --git a/src/org/thoughtcrime/securesms/loki/utilities/MentionUtilities.kt b/src/org/thoughtcrime/securesms/loki/utilities/MentionUtilities.kt index af5b80d868..203e74a478 100644 --- a/src/org/thoughtcrime/securesms/loki/utilities/MentionUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/utilities/MentionUtilities.kt @@ -28,22 +28,22 @@ object MentionUtilities { val mentions = mutableListOf, String>>() var startIndex = 0 val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID) - val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) + val userPublicKey = TextSecurePreferences.getLocalNumber(context) if (matcher.find(startIndex)) { while (true) { - val hexEncodedPublicKey = text.subSequence(matcher.start() + 1, matcher.end()).toString() // +1 to get rid of the @ - val userDisplayName: String? = if (hexEncodedPublicKey.toLowerCase() == userHexEncodedPublicKey.toLowerCase()) { + val publicKey = text.subSequence(matcher.start() + 1, matcher.end()).toString() // +1 to get rid of the @ + val userDisplayName: String? = if (publicKey.toLowerCase() == userPublicKey.toLowerCase()) { TextSecurePreferences.getProfileName(context) } else if (publicChat != null) { - DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, hexEncodedPublicKey) + DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChat.id, publicKey) } else { - DatabaseFactory.getLokiUserDatabase(context).getDisplayName(hexEncodedPublicKey) + DatabaseFactory.getLokiUserDatabase(context).getDisplayName(publicKey) } if (userDisplayName != null) { text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length) val endIndex = matcher.start() + 1 + userDisplayName.length startIndex = endIndex - mentions.add(Tuple2(Range.create(matcher.start(), endIndex), hexEncodedPublicKey)) + mentions.add(Tuple2(Range.create(matcher.start(), endIndex), publicKey)) } else { startIndex = matcher.end() } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 0ef6d29eeb..c34721c213 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -75,7 +75,7 @@ public class MessageSender { long messageId = database.insertMessageOutbox(allocatedThreadId, message, forceSms, System.currentTimeMillis(), insertListener); - sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.isEndSession()); + sendTextMessage(context, recipient, forceSms, keyExchange, messageId); return allocatedThreadId; } @@ -124,7 +124,7 @@ public class MessageSender { if (messageRecord.isMms()) { sendMediaMessage(context, recipient, forceSms, messageId, expiresIn); } else { - sendTextMessage(context, recipient, forceSms, keyExchange, messageId, messageRecord.isEndSession()); + sendTextMessage(context, recipient, forceSms, keyExchange, messageId); } } @@ -141,17 +141,17 @@ public class MessageSender { private static void sendTextMessage(Context context, Recipient recipient, boolean forceSms, boolean keyExchange, - long messageId, boolean isEndSession) + long messageId) { if (isLocalSelfSend(context, recipient, forceSms)) { sendLocalTextSelf(context, messageId); } else { - sendTextPush(context, recipient, messageId, isEndSession); + sendTextPush(context, recipient, messageId); } } - private static void sendTextPush(Context context, Recipient recipient, long messageId, boolean isEndSession) { - MultiDeviceProtocol.sendTextPush(context, recipient, messageId, isEndSession); + private static void sendTextPush(Context context, Recipient recipient, long messageId) { + MultiDeviceProtocol.sendTextPush(context, recipient, messageId); } private static void sendMediaPush(Context context, Recipient recipient, long messageId) { From dbdb4ec85594607beeef1f963b441bc44c91e8ca Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 08:55:29 +1000 Subject: [PATCH 05/18] Clean --- .../securesms/ApplicationContext.java | 18 ++--- .../securesms/jobs/PushDecryptJob.java | 81 +++++++------------ .../securesms/jobs/PushReceivedJob.java | 2 +- .../loki/protocol/MultiDeviceProtocol.kt | 4 - .../loki/protocol/SessionMetaProtocol.kt | 15 ++-- .../OptimizedMessageNotifier.java | 8 +- 6 files changed, 49 insertions(+), 79 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 614019ced9..4771324407 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -152,7 +152,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // Loki public MessageNotifier messageNotifier = null; - public Poller lokiPoller = null; + public Poller poller = null; public PublicChatManager publicChatManager = null; private PublicChatAPI publicChatAPI = null; public Broadcaster broadcaster = null; @@ -226,7 +226,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc executePendingContactSync(); KeyCachingService.onAppForegrounded(this); // Loki - if (lokiPoller != null) { lokiPoller.setCaughtUp(false); } + if (poller != null) { poller.setCaughtUp(false); } startPollingIfNeeded(); publicChatManager.markAllAsNotCaughtUp(); publicChatManager.startPollersIfNeeded(); @@ -239,7 +239,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc KeyCachingService.onAppBackgrounded(this); messageNotifier.setVisibleThread(-1); // Loki - if (lokiPoller != null) { lokiPoller.stopIfNeeded(); } + if (poller != null) { poller.stopIfNeeded(); } if (publicChatManager != null) { publicChatManager.stopPollers(); } } @@ -491,16 +491,16 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc private void setUpPollingIfNeeded() { String userPublicKey = TextSecurePreferences.getLocalNumber(this); if (userPublicKey == null) return; - if (lokiPoller != null) { + if (poller != null) { SnodeAPI.shared.setUserPublicKey(userPublicKey); - lokiPoller.setUserPublicKey(userPublicKey); + poller.setUserPublicKey(userPublicKey); return; } LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); Context context = this; SwarmAPI.Companion.configureIfNeeded(apiDB); SnodeAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster); - lokiPoller = new Poller(userPublicKey, apiDB, protos -> { + poller = new Poller(userPublicKey, apiDB, protos -> { for (SignalServiceProtos.Envelope proto : protos) { new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto), false); } @@ -510,12 +510,12 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc public void startPollingIfNeeded() { setUpPollingIfNeeded(); - if (lokiPoller != null) { lokiPoller.startIfNeeded(); } + if (poller != null) { poller.startIfNeeded(); } } public void stopPolling() { - if (lokiPoller == null) { return; } - lokiPoller.stopIfNeeded(); + if (poller == null) { return; } + poller.stopIfNeeded(); } private void resubmitProfilePictureIfNeeded() { diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 8d75a599b5..4ceb4009f8 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -48,7 +48,6 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.PushDatabase; -import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.StickerDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase; @@ -68,7 +67,6 @@ import org.thoughtcrime.securesms.loki.activities.HomeActivity; import org.thoughtcrime.securesms.loki.database.LokiMessageDatabase; import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol; import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol; -import org.thoughtcrime.securesms.loki.protocol.PushNullMessageSendJob; import org.thoughtcrime.securesms.loki.protocol.SessionManagementProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol; import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation; @@ -129,7 +127,6 @@ import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation; -import java.security.MessageDigest; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; @@ -298,7 +295,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } if (message.getProfileKey().isPresent() && message.getProfileKey().get().length == 32) { - handleProfileKey(content, message); + SessionMetaProtocol.handleProfileKeyUpdate(context, content); } if (content.isNeedsReceipt()) { @@ -335,12 +332,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { else if (message.isDeliveryReceipt()) handleDeliveryReceipt(content, message); } else if (content.getTypingMessage().isPresent()) { handleTypingMessage(content, content.getTypingMessage().get()); - } else if (content.getNullMessage().isPresent()) { - if (content.preKeyBundleMessage.isPresent()) { - ApplicationContext.getInstance(context).getJobManager().add(new PushNullMessageSendJob(content.getSender())); - } else { - Log.w(TAG, "Got unrecognized message..."); - } + } else { + Log.w(TAG, "Got unrecognized message..."); } resetRecipientToPush(Recipient.from(context, Address.fromSerialized(content.getSender()), false)); @@ -637,7 +630,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true); } - handleProfileKey(content, message.getMessage()); + SessionMetaProtocol.handleProfileKeyUpdate(context, content); } SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content); @@ -781,20 +774,28 @@ public class PushDecryptJob extends BaseJob implements InjectableType { messageNotifier.updateNotification(context, insertResult.get().getThreadId()); } - // Loki - Store message open group server ID if needed - if (insertResult.isPresent() && messageServerIDOrNull.isPresent()) { - long messageID = insertResult.get().getMessageId(); - long messageServerID = messageServerIDOrNull.get(); - LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); - lokiMessageDatabase.setServerID(messageID, messageServerID); - } - - // Loki - Update mapping of message ID to original thread ID if (insertResult.isPresent()) { - ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); - LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); - long originalThreadId = threadDatabase.getThreadIdFor(originalRecipient); - lokiMessageDatabase.setOriginalThreadID(insertResult.get().getMessageId(), originalThreadId); + InsertResult result = insertResult.get(); + + // Loki - Cache the user hex encoded public key (for mentions) + MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(result.getThreadId(), context); + MentionsManager.shared.cache(content.getSender(), result.getThreadId()); + + // Loki - Store message open group server ID if needed + if (messageServerIDOrNull.isPresent()) { + long messageID = result.getMessageId(); + long messageServerID = messageServerIDOrNull.get(); + LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); + lokiMessageDatabase.setServerID(messageID, messageServerID); + } + + // Loki - Update mapping of message ID to original thread ID + if (result.getMessageId() > -1) { + ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); + LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); + long originalThreadId = threadDatabase.getThreadIdFor(originalRecipient); + lokiMessageDatabase.setOriginalThreadID(result.getMessageId(), originalThreadId); + } } } @@ -958,17 +959,17 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // Loki - Cache the user hex encoded public key (for mentions) MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(result.getThreadId(), context); - MentionsManager.shared.cache(textMessage.getSender().serialize(), result.getThreadId()); + MentionsManager.shared.cache(content.getSender(), result.getThreadId()); - // Loki - Store message server ID - if (insertResult.isPresent() && messageServerIDOrNull.isPresent()) { - long messageID = insertResult.get().getMessageId(); + // Loki - Store message open group server ID if needed + if (messageServerIDOrNull.isPresent()) { + long messageID = result.getMessageId(); long messageServerID = messageServerIDOrNull.get(); LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); lokiMessageDatabase.setServerID(messageID, messageServerID); } - // Loki - Update mapping of message to original thread ID + // Loki - Update mapping of message ID to original thread ID if (result.getMessageId() > -1) { ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); @@ -1127,28 +1128,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // } } - private void handleProfileKey(@NonNull SignalServiceContent content, - @NonNull SignalServiceDataMessage message) - { - if (!message.getProfileKey().isPresent()) { return; } - - /* - If we get a profile key then we don't need to map it to the primary device. - For now a profile key is mapped one-to-one to avoid secondary devices setting the incorrect avatar for a primary device. - */ - RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context); - Recipient recipient = Recipient.from(context, Address.fromSerialized(content.getSender()), false); - - if (recipient.getProfileKey() == null || !MessageDigest.isEqual(recipient.getProfileKey(), message.getProfileKey().get())) { - database.setProfileKey(recipient, message.getProfileKey().get()); - database.setUnidentifiedAccessMode(recipient, RecipientDatabase.UnidentifiedAccessMode.UNKNOWN); - String url = content.senderProfilePictureURL.or(""); - ApplicationContext.getInstance(context).getJobManager().add(new RetrieveProfileAvatarJob(recipient, url)); - - SessionMetaProtocol.handleProfileKeyUpdateIfNeeded(context, content); - } - } - private void handleNeedsDeliveryReceipt(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { diff --git a/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java b/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java index 7b96e5593c..63fc0f65d5 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushReceivedJob.java @@ -36,7 +36,7 @@ public abstract class PushReceivedJob extends BaseJob { if (envelope.isReceipt()) { handleReceipt(envelope); - } else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender()) { + } else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender() || envelope.isFallbackMessage()) { handleMessage(envelope, isPushNotification); } else { Log.w(TAG, "Received envelope of unknown type: " + envelope.getType()); diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index e1b1ada7a2..e2b6c0f5f5 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -162,9 +162,6 @@ object MultiDeviceProtocol { } val isValid = isValidDeviceLinkMessage(context, deviceLink) if (!isValid) { return } - // The line below isn't actually necessary because this is called after PushDecryptJob - // calls handlePreKeyBundleMessageIfNeeded, but it also doesn't hurt. - SessionManagementProtocol.handlePreKeyBundleMessageIfNeeded(context, content) linkingSession.processLinkingAuthorization(deviceLink) val userPublicKey = TextSecurePreferences.getLocalNumber(context) DatabaseFactory.getLokiAPIDatabase(context).clearDeviceLinks(userPublicKey) @@ -172,7 +169,6 @@ object MultiDeviceProtocol { TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterPublicKey) TextSecurePreferences.setMultiDevice(context, true) FileServerAPI.shared.addDeviceLink(deviceLink) - org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.handleProfileUpdateIfNeeded(context, content) org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.duplicate_handleProfileKey(context, content) } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt index 538312f801..8d6184c073 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionMetaProtocol.kt @@ -47,9 +47,8 @@ object SessionMetaProtocol { } } - // FIXME: Basically a duplicate of PushDecryptJob's handleProfileKey @JvmStatic - fun duplicate_handleProfileKey(context: Context, content: SignalServiceContent) { + fun handleProfileKeyUpdate(context: Context, content: SignalServiceContent) { val message = content.dataMessage.get() if (!message.profileKey.isPresent) { return } val database = DatabaseFactory.getRecipientDatabase(context) @@ -59,17 +58,13 @@ object SessionMetaProtocol { database.setUnidentifiedAccessMode(recipient, RecipientDatabase.UnidentifiedAccessMode.UNKNOWN) val url = content.senderProfilePictureURL.or("") ApplicationContext.getInstance(context).jobManager.add(RetrieveProfileAvatarJob(recipient, url)) - handleProfileKeyUpdateIfNeeded(context, content) + val userMasterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context) + if (userMasterPublicKey == content.sender) { + ApplicationContext.getInstance(context).updateOpenGroupProfilePicturesIfNeeded() + } } } - @JvmStatic - fun handleProfileKeyUpdateIfNeeded(context: Context, content: SignalServiceContent) { - val userMasterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context) - if (userMasterPublicKey != content.sender) { return } - ApplicationContext.getInstance(context).updateOpenGroupProfilePicturesIfNeeded() - } - /** * Should be invoked for the recipient's master device. */ diff --git a/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java index a74c0415dc..ee2601e3ff 100644 --- a/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/OptimizedMessageNotifier.java @@ -40,7 +40,7 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@NonNull Context context) { - Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; + Poller lokiPoller = ApplicationContext.getInstance(context).poller; PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { @@ -60,7 +60,7 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@NonNull Context context, long threadId) { - Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; + Poller lokiPoller = ApplicationContext.getInstance(context).poller; PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { @@ -80,7 +80,7 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@NonNull Context context, long threadId, boolean signal) { - Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; + Poller lokiPoller = ApplicationContext.getInstance(context).poller; PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { @@ -100,7 +100,7 @@ public class OptimizedMessageNotifier implements MessageNotifier { @Override public void updateNotification(@android.support.annotation.NonNull Context context, boolean signal, int reminderCount) { - Poller lokiPoller = ApplicationContext.getInstance(context).lokiPoller; + Poller lokiPoller = ApplicationContext.getInstance(context).poller; PublicChatManager publicChatManager = ApplicationContext.getInstance(context).publicChatManager; boolean isCaughtUp = true; if (lokiPoller != null) { From 4beaf88fbe1107541ff2fb2ab67c126186c40111 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 09:44:00 +1000 Subject: [PATCH 06/18] Match desktop session handling --- .../securesms/ApplicationContext.java | 11 ++--- .../database/helpers/SQLCipherOpenHelper.java | 10 ++++- .../loki/database/LokiAPIDatabase.kt | 41 +++++++++++++++---- .../loki/protocol/MultiDeviceProtocol.kt | 2 +- .../PushSessionRequestMessageSendJob.kt | 20 ++++++--- .../protocol/SessionManagementProtocol.kt | 29 +++++++------ 6 files changed, 81 insertions(+), 32 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 4771324407..51950ccff7 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -594,13 +594,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc SignalProtocolAddress address = new SignalProtocolAddress(publicKey, SignalServiceAddress.DEFAULT_DEVICE_ID); boolean hasSession = new TextSecureSessionStore(this).containsSession(address); if (hasSession) { return; } - // Check that we didn't already send or process a session request + // Check that we didn't already send a session request LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); - boolean hasSentOrProcessedSessionRequest = (apiDB.getSessionRequestTimestamp(publicKey) != null); - if (hasSentOrProcessedSessionRequest) { return; } + boolean hasSentSessionRequest = (apiDB.getSessionRequestSentTimestamp(publicKey) != null); + if (hasSentSessionRequest) { return; } // Send the session request - DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestTimestamp(publicKey, new Date().getTime()); - PushSessionRequestMessageSendJob job = new PushSessionRequestMessageSendJob(publicKey); + long timestamp = new Date().getTime(); + DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestSentTimestamp(publicKey, timestamp); + PushSessionRequestMessageSendJob job = new PushSessionRequestMessageSendJob(publicKey, timestamp); jobManager.add(job); } // endregion diff --git a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index a2482a5b17..86b4f9cd2d 100644 --- a/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/src/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -83,8 +83,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int lokiV7 = 28; private static final int lokiV8 = 29; private static final int lokiV9 = 30; + private static final int lokiV10 = 31; - private static final int DATABASE_VERSION = lokiV9; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes + private static final int DATABASE_VERSION = lokiV10; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -143,6 +144,8 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateDeviceLinkCacheCommand()); db.execSQL(LokiAPIDatabase.getCreateUserCountCacheCommand()); db.execSQL(LokiAPIDatabase.getCreateSessionRequestTimestampCacheCommand()); + db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampCacheCommand()); + db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampCacheCommand()); db.execSQL(LokiPreKeyBundleDatabase.getCreateTableCommand()); db.execSQL(LokiPreKeyRecordDatabase.getCreateTableCommand()); db.execSQL(LokiMessageDatabase.getCreateMessageIDTableCommand()); @@ -589,6 +592,11 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(LokiAPIDatabase.getCreateOnionRequestPathCacheCommand()); } + if (oldVersion < lokiV10) { + db.execSQL(LokiAPIDatabase.getCreateSessionRequestSentTimestampCacheCommand()); + db.execSQL(LokiAPIDatabase.getCreateSessionRequestProcessedTimestampCacheCommand()); + } + db.setTransactionSuccessful(); } finally { db.endTransaction(); diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt index a3cbef083d..e203be2b29 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt @@ -70,11 +70,25 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( private val publicChatID = "public_chat_id" private val userCount = "user_count" @JvmStatic val createUserCountCacheCommand = "CREATE TABLE $userCountCache ($publicChatID STRING PRIMARY KEY, $userCount INTEGER DEFAULT 0);" - // Session request timestamp cache + // Session request sent timestamp cache + private val sessionRequestSentTimestampCache = "session_request_sent_timestamp_cache" + private val sessionRequestSentPublicKey = "public_key" + private val sessionRequestSentTimestamp = "timestamp" + @JvmStatic val createSessionRequestSentTimestampCacheCommand = "CREATE TABLE $sessionRequestSentTimestampCache ($sessionRequestSentPublicKey STRING PRIMARY KEY, $sessionRequestSentTimestamp INTEGER DEFAULT 0);" + // Session request processed timestamp cache + private val sessionRequestProcessedTimestampCache = "session_request_processed_timestamp_cache" + private val sessionRequestProcessedPublicKey = "public_key" + private val sessionRequestProcessedTimestamp = "timestamp" + @JvmStatic val createSessionRequestProcessedTimestampCacheCommand = "CREATE TABLE $sessionRequestProcessedTimestampCache ($sessionRequestProcessedPublicKey STRING PRIMARY KEY, $sessionRequestProcessedTimestamp INTEGER DEFAULT 0);" + + + + // region Deprecated private val sessionRequestTimestampCache = "session_request_timestamp_cache" private val sessionRequestPublicKey = "public_key" private val timestamp = "timestamp" @JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($sessionRequestPublicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" + // endregion } override fun getSnodePool(): Set { @@ -323,17 +337,30 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( database.insertOrUpdate(userCountCache, row, "$publicChatID = ?", wrap(index)) } - override fun getSessionRequestTimestamp(publicKey: String): Long? { + override fun getSessionRequestSentTimestamp(publicKey: String): Long? { val database = databaseHelper.readableDatabase - return database.get(sessionRequestTimestampCache, "$LokiAPIDatabase.publicKey = ?", wrap(publicKey)) { cursor -> - cursor.getInt(LokiAPIDatabase.timestamp) + return database.get(sessionRequestSentTimestampCache, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey)) { cursor -> + cursor.getInt(LokiAPIDatabase.sessionRequestSentTimestamp) }?.toLong() } - override fun setSessionRequestTimestamp(publicKey: String, timestamp: Long) { + override fun setSessionRequestSentTimestamp(publicKey: String, timestamp: Long) { val database = databaseHelper.writableDatabase - val row = wrap(mapOf(LokiAPIDatabase.sessionRequestPublicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString())) - database.insertOrUpdate(sessionRequestTimestampCache, row, "${LokiAPIDatabase.sessionRequestPublicKey} = ?", wrap(publicKey)) + val row = wrap(mapOf(LokiAPIDatabase.sessionRequestSentPublicKey to publicKey, LokiAPIDatabase.sessionRequestSentTimestamp to timestamp.toString())) + database.insertOrUpdate(sessionRequestSentTimestampCache, row, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey)) + } + + override fun getSessionRequestProcessedTimestamp(publicKey: String): Long? { + val database = databaseHelper.readableDatabase + return database.get(sessionRequestProcessedTimestampCache, "${LokiAPIDatabase.sessionRequestProcessedPublicKey} = ?", wrap(publicKey)) { cursor -> + cursor.getInt(LokiAPIDatabase.sessionRequestProcessedTimestamp) + }?.toLong() + } + + override fun setSessionRequestProcessedTimestamp(publicKey: String, timestamp: Long) { + val database = databaseHelper.writableDatabase + val row = wrap(mapOf(LokiAPIDatabase.sessionRequestProcessedPublicKey to publicKey, LokiAPIDatabase.sessionRequestProcessedTimestamp to timestamp.toString())) + database.insertOrUpdate(sessionRequestProcessedTimestampCache, row, "${LokiAPIDatabase.sessionRequestProcessedPublicKey} = ?", wrap(publicKey)) } } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index e2b6c0f5f5..771e6821b1 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -169,7 +169,7 @@ object MultiDeviceProtocol { TextSecurePreferences.setMasterHexEncodedPublicKey(context, deviceLink.masterPublicKey) TextSecurePreferences.setMultiDevice(context, true) FileServerAPI.shared.addDeviceLink(deviceLink) - org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.duplicate_handleProfileKey(context, content) + org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol.handleProfileKeyUpdate(context, content) } @JvmStatic diff --git a/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt b/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt index b55e30aa65..f530468235 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/PushSessionRequestMessageSendJob.kt @@ -19,22 +19,23 @@ import java.security.SecureRandom import java.util.* import java.util.concurrent.TimeUnit -class PushSessionRequestMessageSendJob private constructor(parameters: Parameters, private val publicKey: String) : BaseJob(parameters) { +class PushSessionRequestMessageSendJob private constructor(parameters: Parameters, private val publicKey: String, private val timestamp: Long) : BaseJob(parameters) { companion object { const val KEY = "PushSessionRequestMessageSendJob" } - constructor(publicKey: String) : this(Parameters.Builder() + constructor(publicKey: String, timestamp: Long) : this(Parameters.Builder() .addConstraint(NetworkConstraint.KEY) .setQueue(KEY) .setLifespan(TimeUnit.DAYS.toMillis(1)) .setMaxAttempts(1) .build(), - publicKey) + publicKey, + timestamp) override fun serialize(): Data { - return Data.Builder().putString("publicKey", publicKey).build() + return Data.Builder().putString("publicKey", publicKey).putLong("timestamp", timestamp).build() } override fun getFactoryKey(): String { return KEY } @@ -83,14 +84,21 @@ class PushSessionRequestMessageSendJob private constructor(parameters: Parameter return false } - override fun onCanceled() { } + override fun onCanceled() { + // Update the DB on fail if this is still the most recently sent session request (should always be true) + val apiDB = DatabaseFactory.getLokiAPIDatabase(context) + if (apiDB.getSessionRequestSentTimestamp(publicKey) == timestamp) { + apiDB.setSessionRequestSentTimestamp(publicKey, 0) + } + } class Factory : Job.Factory { override fun create(parameters: Parameters, data: Data): PushSessionRequestMessageSendJob { try { val publicKey = data.getString("publicKey") - return PushSessionRequestMessageSendJob(parameters, publicKey) + val timestamp = data.getLong("timestamp") + return PushSessionRequestMessageSendJob(parameters, publicKey, timestamp) } catch (e: IOException) { throw AssertionError(e) } diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt index bf24cc5d10..c442e060a7 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SessionManagementProtocol.kt @@ -53,25 +53,30 @@ object SessionManagementProtocol { } } + @JvmStatic + fun shouldProcessSessionRequest(context: Context, publicKey: String, timestamp: Long): Boolean { + val apiDB = DatabaseFactory.getLokiAPIDatabase(context) + val sentTimestamp = apiDB.getSessionRequestSentTimestamp(publicKey) ?: 0 + val processedTimestamp = apiDB.getSessionRequestProcessedTimestamp(publicKey) ?: 0 + return timestamp > sentTimestamp && timestamp > processedTimestamp + } + @JvmStatic fun handlePreKeyBundleMessageIfNeeded(context: Context, content: SignalServiceContent) { - val publicKey = content.sender - val recipient = recipient(context, publicKey) - if (recipient.isGroupRecipient) { return } // Should never occur val preKeyBundleMessage = content.preKeyBundleMessage.orNull() ?: return - val registrationID = TextSecurePreferences.getLocalRegistrationId(context) // TODO: It seems wrong to use the local registration ID for this? - val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context) + val publicKey = content.sender + if (recipient(context, publicKey).isGroupRecipient) { return } // Should never occur Log.d("Loki", "Received a pre key bundle from: $publicKey.") - val sessionRequestTimestamp = DatabaseFactory.getLokiAPIDatabase(context).getSessionRequestTimestamp(content.sender) - if (sessionRequestTimestamp != null && content.timestamp < sessionRequestTimestamp) { - // We sent or processed a session request after this one was sent - Log.d("Loki", "Ignoring session request from: ${content.sender}.") + if (!shouldProcessSessionRequest(context, publicKey, content.timestamp)) { + Log.d("Loki", "Ignoring session request from: $publicKey.") return } + val registrationID = TextSecurePreferences.getLocalRegistrationId(context) + val lokiPreKeyBundleDatabase = DatabaseFactory.getLokiPreKeyBundleDatabase(context) val preKeyBundle = preKeyBundleMessage.getPreKeyBundle(registrationID) - lokiPreKeyBundleDatabase.setPreKeyBundle(content.sender, preKeyBundle) - DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestTimestamp(content.sender, Date().time) - val job = PushNullMessageSendJob(content.sender) + lokiPreKeyBundleDatabase.setPreKeyBundle(publicKey, preKeyBundle) + DatabaseFactory.getLokiAPIDatabase(context).setSessionRequestProcessedTimestamp(publicKey, Date().time) + val job = PushNullMessageSendJob(publicKey) ApplicationContext.getInstance(context).jobManager.add(job) } From 3df78a00c5c354996b2a7e5e0d66a107979cfc5b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 09:46:10 +1000 Subject: [PATCH 07/18] Clean --- .../loki/database/LokiAPIDatabase.kt | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt b/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt index e203be2b29..da2356bcc2 100644 --- a/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt +++ b/src/org/thoughtcrime/securesms/loki/database/LokiAPIDatabase.kt @@ -17,6 +17,9 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( private val userPublicKey get() = TextSecurePreferences.getLocalNumber(context) companion object { + // Shared + private val publicKey = "public_key" + private val timestamp = "timestamp" // Snode pool cache private val snodePoolCache = "loki_snode_pool_cache" private val dummyKey = "dummy_key" @@ -72,22 +75,16 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( @JvmStatic val createUserCountCacheCommand = "CREATE TABLE $userCountCache ($publicChatID STRING PRIMARY KEY, $userCount INTEGER DEFAULT 0);" // Session request sent timestamp cache private val sessionRequestSentTimestampCache = "session_request_sent_timestamp_cache" - private val sessionRequestSentPublicKey = "public_key" - private val sessionRequestSentTimestamp = "timestamp" - @JvmStatic val createSessionRequestSentTimestampCacheCommand = "CREATE TABLE $sessionRequestSentTimestampCache ($sessionRequestSentPublicKey STRING PRIMARY KEY, $sessionRequestSentTimestamp INTEGER DEFAULT 0);" + @JvmStatic val createSessionRequestSentTimestampCacheCommand = "CREATE TABLE $sessionRequestSentTimestampCache ($publicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" // Session request processed timestamp cache private val sessionRequestProcessedTimestampCache = "session_request_processed_timestamp_cache" - private val sessionRequestProcessedPublicKey = "public_key" - private val sessionRequestProcessedTimestamp = "timestamp" - @JvmStatic val createSessionRequestProcessedTimestampCacheCommand = "CREATE TABLE $sessionRequestProcessedTimestampCache ($sessionRequestProcessedPublicKey STRING PRIMARY KEY, $sessionRequestProcessedTimestamp INTEGER DEFAULT 0);" + @JvmStatic val createSessionRequestProcessedTimestampCacheCommand = "CREATE TABLE $sessionRequestProcessedTimestampCache ($publicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" // region Deprecated private val sessionRequestTimestampCache = "session_request_timestamp_cache" - private val sessionRequestPublicKey = "public_key" - private val timestamp = "timestamp" - @JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($sessionRequestPublicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" + @JvmStatic val createSessionRequestTimestampCacheCommand = "CREATE TABLE $sessionRequestTimestampCache ($publicKey STRING PRIMARY KEY, $timestamp INTEGER DEFAULT 0);" // endregion } @@ -339,28 +336,28 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database( override fun getSessionRequestSentTimestamp(publicKey: String): Long? { val database = databaseHelper.readableDatabase - return database.get(sessionRequestSentTimestampCache, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey)) { cursor -> - cursor.getInt(LokiAPIDatabase.sessionRequestSentTimestamp) + return database.get(sessionRequestSentTimestampCache, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) { cursor -> + cursor.getInt(LokiAPIDatabase.timestamp) }?.toLong() } override fun setSessionRequestSentTimestamp(publicKey: String, timestamp: Long) { val database = databaseHelper.writableDatabase - val row = wrap(mapOf(LokiAPIDatabase.sessionRequestSentPublicKey to publicKey, LokiAPIDatabase.sessionRequestSentTimestamp to timestamp.toString())) - database.insertOrUpdate(sessionRequestSentTimestampCache, row, "${LokiAPIDatabase.sessionRequestSentPublicKey} = ?", wrap(publicKey)) + val row = wrap(mapOf(LokiAPIDatabase.publicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString())) + database.insertOrUpdate(sessionRequestSentTimestampCache, row, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) } override fun getSessionRequestProcessedTimestamp(publicKey: String): Long? { val database = databaseHelper.readableDatabase - return database.get(sessionRequestProcessedTimestampCache, "${LokiAPIDatabase.sessionRequestProcessedPublicKey} = ?", wrap(publicKey)) { cursor -> - cursor.getInt(LokiAPIDatabase.sessionRequestProcessedTimestamp) + return database.get(sessionRequestProcessedTimestampCache, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) { cursor -> + cursor.getInt(LokiAPIDatabase.timestamp) }?.toLong() } override fun setSessionRequestProcessedTimestamp(publicKey: String, timestamp: Long) { val database = databaseHelper.writableDatabase - val row = wrap(mapOf(LokiAPIDatabase.sessionRequestProcessedPublicKey to publicKey, LokiAPIDatabase.sessionRequestProcessedTimestamp to timestamp.toString())) - database.insertOrUpdate(sessionRequestProcessedTimestampCache, row, "${LokiAPIDatabase.sessionRequestProcessedPublicKey} = ?", wrap(publicKey)) + val row = wrap(mapOf(LokiAPIDatabase.publicKey to publicKey, LokiAPIDatabase.timestamp to timestamp.toString())) + database.insertOrUpdate(sessionRequestProcessedTimestampCache, row, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) } } From af5a37c601315a9bafb4358a1f6c15308f565a50 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 10:14:25 +1000 Subject: [PATCH 08/18] Debug --- res/layout/conversation_item_received.xml | 280 +++++++++--------- res/layout/conversation_item_sent.xml | 245 +++++++-------- .../conversation/ConversationActivity.java | 2 + .../conversation/ConversationItem.java | 6 - 4 files changed, 274 insertions(+), 259 deletions(-) diff --git a/res/layout/conversation_item_received.xml b/res/layout/conversation_item_received.xml index fa22c50cb7..5b7d503cdf 100644 --- a/res/layout/conversation_item_received.xml +++ b/res/layout/conversation_item_received.xml @@ -45,160 +45,169 @@ + android:clipChildren="false"> + android:layout_marginEnd="@dimen/massive_spacing" + android:layout_marginStart="12dp" + android:paddingTop="@dimen/medium_spacing" + android:paddingBottom="@dimen/medium_spacing" + android:orientation="vertical" + android:clipToPadding="false" + android:clipChildren="false" + android:background="@color/white" + tools:backgroundTint="@color/conversation_blue"> - + + + + + + + + + + + + + + + + + + + + + + + + + app:footer_text_color="?conversation_item_received_text_secondary_color" + app:footer_icon_color="?conversation_item_received_text_secondary_color"/> - + android:layout_marginTop="6dp" + android:layout_marginStart="@dimen/message_bubble_horizontal_padding" + android:layout_marginEnd="@dimen/message_bubble_horizontal_padding" + android:clipChildren="false" + android:clipToPadding="false" + android:visibility="gone" + app:footer_text_color="?conversation_sticker_footer_text_color" + app:footer_icon_color="?conversation_sticker_footer_icon_color"/> - - - - - - - - - - - - - - - - - - - - - + + \ No newline at end of file diff --git a/res/layout/conversation_item_sent.xml b/res/layout/conversation_item_sent.xml index 87f39bbca6..60f032ea8a 100644 --- a/res/layout/conversation_item_sent.xml +++ b/res/layout/conversation_item_sent.xml @@ -23,134 +23,143 @@ android:clipChildren="false"> + android:clipChildren="false"> - - - - - - - - - - - - - - - - - - - - - - - - - + android:background="@color/white" + tools:backgroundTint="@color/core_grey_05"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -166,4 +175,4 @@ - + \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index b7e74b8d1b..d9300166c8 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -547,6 +547,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity DatabaseFactory.getLokiThreadDatabase(this).setDelegate(this); + inputPanel.setHint("Message"); + updateSessionRestoreBanner(); Log.i(TAG, "onResume() Finished: " + (System.currentTimeMillis() - getIntent().getLongExtra(TIMING_EXTRA, 0))); diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java index 541e6ac900..fb56fbca52 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -1053,12 +1053,6 @@ public class ConversationItem extends LinearLayout int spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_collapse); int spacingBottom = spacingTop; - boolean isOutgoingStack = current.isOutgoing() && previous.orNull() != null && previous.get().isOutgoing(); - - if (isOutgoingStack) { - spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default); - } - if (isStartOfMessageCluster(current, previous, isGroupThread)) { spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default); } From c388d318737a5e862409c92627b332336058191d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 11:20:39 +1000 Subject: [PATCH 09/18] Implement blocking --- res/layout/view_conversation.xml | 2 +- res/menu/conversation_block.xml | 8 ++++ res/menu/conversation_unblock.xml | 8 ++++ .../conversation/ConversationActivity.java | 48 ++++++++++++++----- .../securesms/loki/views/ConversationView.kt | 19 ++++++-- 5 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 res/menu/conversation_block.xml create mode 100644 res/menu/conversation_unblock.xml diff --git a/res/layout/view_conversation.xml b/res/layout/view_conversation.xml index fffeb392e0..43a82160ba 100644 --- a/res/layout/view_conversation.xml +++ b/res/layout/view_conversation.xml @@ -8,7 +8,7 @@ android:gravity="center_vertical"> diff --git a/res/menu/conversation_block.xml b/res/menu/conversation_block.xml new file mode 100644 index 0000000000..14dfea3546 --- /dev/null +++ b/res/menu/conversation_block.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/menu/conversation_unblock.xml b/res/menu/conversation_unblock.xml new file mode 100644 index 0000000000..354401a817 --- /dev/null +++ b/res/menu/conversation_unblock.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index d9300166c8..f09264505d 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -753,10 +753,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } if (isSingleConversation()) { - /* - if (isSecureText) inflater.inflate(R.menu.conversation_callable_secure, menu); - else inflater.inflate(R.menu.conversation_callable_insecure, menu); - */ + if (recipient.isBlocked()) { + inflater.inflate(R.menu.conversation_unblock, menu); + } else { + inflater.inflate(R.menu.conversation_block, menu); + } } else if (isGroupConversation() && !isOpenGroupOrRSSFeed) { inflater.inflate(R.menu.conversation_group_options, menu); @@ -860,8 +861,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { - case R.id.menu_call_secure: handleDial(getRecipient(), true); return true; - case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true; + case R.id.menu_call_secure: handleDial(getRecipient(), true); return true; + case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true; + case R.id.menu_unblock: handleUnblock(); return true; + case R.id.menu_block: handleBlock(); return true; case R.id.menu_view_media: handleViewMedia(); return true; case R.id.menu_add_shortcut: handleAddShortcut(); return true; case R.id.menu_search: handleSearch(); return true; @@ -986,12 +989,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity int titleRes = R.string.ConversationActivity_unblock_this_contact_question; int bodyRes = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact; - if (recipient.isGroupRecipient()) { - titleRes = R.string.ConversationActivity_unblock_this_group_question; - bodyRes = R.string.ConversationActivity_unblock_this_group_description; - } - - //noinspection CodeBlock2Expr new AlertDialog.Builder(this) .setTitle(titleRes) .setMessage(bodyRes) @@ -1070,6 +1067,33 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity builder.show(); } + private void handleBlock() { + int titleRes = R.string.RecipientPreferenceActivity_block_this_contact_question; + int bodyRes = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact; + + new AlertDialog.Builder(this) + .setTitle(titleRes) + .setMessage(bodyRes) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.RecipientPreferenceActivity_block, (dialog, which) -> { + new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + DatabaseFactory.getRecipientDatabase(ConversationActivity.this) + .setBlocked(recipient, true); + + ApplicationContext.getInstance(ConversationActivity.this) + .getJobManager() + .add(new MultiDeviceBlockedUpdateJob()); + + Util.runOnMain(() -> finish()); + + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + }).show(); + } + private void handleViewMedia() { Intent intent = new Intent(this, MediaOverviewActivity.class); intent.putExtra(MediaOverviewActivity.ADDRESS_EXTRA, recipient.getAddress()); diff --git a/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt b/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt index 26b9762622..f859faa85e 100644 --- a/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/ConversationView.kt @@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.loki.utilities.MentionManagerUtilities.populat import org.thoughtcrime.securesms.loki.utilities.MentionUtilities.highlightMentions import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.util.DateUtils +import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager import java.util.* @@ -46,14 +47,26 @@ class ConversationView : LinearLayout { // region Updating fun bind(thread: ThreadRecord, isTyping: Boolean, glide: GlideRequests) { this.thread = thread - populateUserPublicKeyCacheIfNeeded(thread.threadId, context) // FIXME: This is a terrible place to do this - unreadMessagesIndicatorView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE + populateUserPublicKeyCacheIfNeeded(thread.threadId, context) // FIXME: This is a bad place to do this + if (thread.recipient.isBlocked) { + accentView.setBackgroundResource(R.color.destructive) + accentView.visibility = View.VISIBLE + } else { + accentView.setBackgroundResource(R.color.accent) + accentView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE + } if (thread.recipient.isGroupRecipient) { if ("Session Public Chat" == thread.recipient.name) { profilePictureView.publicKey = "" + profilePictureView.additionalPublicKey = null profilePictureView.isRSSFeed = true } else { - val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toList() ?: listOf() + val users = MentionsManager.shared.userPublicKeyCache[thread.threadId]?.toMutableList() ?: mutableListOf() + users.remove(TextSecurePreferences.getLocalNumber(context)) + val masterPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context) + if (masterPublicKey != null) { + users.remove(masterPublicKey) + } val randomUsers = users.sorted() // Sort to provide a level of stability profilePictureView.publicKey = randomUsers.getOrNull(0) ?: "" profilePictureView.additionalPublicKey = randomUsers.getOrNull(1) ?: "" From 56c2cd3ca9b1bf6feb62f7bbcee7213c1da97387 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 11:58:11 +1000 Subject: [PATCH 10/18] Replace swipe to delete by a bottom sheet --- .../fragment_conversation_bottom_sheet.xml | 28 +++ .../securesms/loki/activities/HomeActivity.kt | 197 +++++++++--------- .../dialogs/ConversationOptionsBottomSheet.kt | 36 ++++ 3 files changed, 165 insertions(+), 96 deletions(-) create mode 100644 res/layout/fragment_conversation_bottom_sheet.xml create mode 100644 src/org/thoughtcrime/securesms/loki/dialogs/ConversationOptionsBottomSheet.kt diff --git a/res/layout/fragment_conversation_bottom_sheet.xml b/res/layout/fragment_conversation_bottom_sheet.xml new file mode 100644 index 0000000000..2727ec8a3b --- /dev/null +++ b/res/layout/fragment_conversation_bottom_sheet.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index 3279d14db0..a3721f0a3d 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -1,21 +1,15 @@ package org.thoughtcrime.securesms.loki.activities -import android.annotation.SuppressLint import android.app.AlertDialog import android.arch.lifecycle.Observer import android.content.Intent import android.database.Cursor -import android.graphics.BitmapFactory -import android.graphics.Canvas -import android.graphics.Paint import android.os.AsyncTask import android.os.Bundle import android.os.Handler import android.support.v4.app.LoaderManager import android.support.v4.content.Loader import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.support.v7.widget.helper.ItemTouchHelper import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan @@ -31,6 +25,8 @@ import org.thoughtcrime.securesms.conversation.ConversationActivity import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.database.model.ThreadRecord +import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob +import org.thoughtcrime.securesms.loki.dialogs.ConversationOptionsBottomSheet import org.thoughtcrime.securesms.loki.dialogs.PNModeBottomSheet import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol import org.thoughtcrime.securesms.loki.protocol.SessionResetImplementation @@ -41,13 +37,13 @@ import org.thoughtcrime.securesms.loki.views.SeedReminderViewDelegate import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.loki.api.fileserver.FileServerAPI import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesProtocol -import kotlin.math.abs class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate { private lateinit var glide: GlideRequests @@ -116,7 +112,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe homeAdapter.conversationClickListener = this recyclerView.adapter = homeAdapter recyclerView.layoutManager = LinearLayoutManager(this) - ItemTouchHelper(SwipeCallback(this)).attachToRecyclerView(recyclerView) // Set up empty state view createNewPrivateChatButton.setOnClickListener { createNewPrivateChat() } // This is a workaround for the fact that CursorRecyclerViewAdapter doesn't actually auto-update (even though it says it will) @@ -224,7 +219,104 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe } override fun onLongConversationClick(view: ConversationView) { - // Do nothing + val thread = view.thread ?: return + val bottomSheet = ConversationOptionsBottomSheet() + bottomSheet.recipient = thread.recipient + bottomSheet.onBlockOrUnblockTapped = { + bottomSheet.dismiss() + if (thread.recipient.isBlocked) { + unblockConversation(thread) + } else { + blockConversation(thread) + } + } + bottomSheet.onDeleteTapped = { + bottomSheet.dismiss() + deleteConversation(thread) + } + bottomSheet.show(supportFragmentManager, bottomSheet.tag) + } + + private fun blockConversation(thread: ThreadRecord) { + AlertDialog.Builder(this) + .setTitle(R.string.RecipientPreferenceActivity_block_this_contact_question) + .setMessage(R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.RecipientPreferenceActivity_block) { dialog, _ -> + Thread { + DatabaseFactory.getRecipientDatabase(this).setBlocked(thread.recipient, true) + ApplicationContext.getInstance(this).jobManager.add(MultiDeviceBlockedUpdateJob()) + Util.runOnMain { + recyclerView.adapter!!.notifyDataSetChanged() + dialog.dismiss() + } + }.start() + }.show() + } + + private fun unblockConversation(thread: ThreadRecord) { + AlertDialog.Builder(this) + .setTitle(R.string.RecipientPreferenceActivity_unblock_this_contact_question) + .setMessage(R.string.RecipientPreferenceActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.RecipientPreferenceActivity_unblock) { dialog, _ -> + Thread { + DatabaseFactory.getRecipientDatabase(this).setBlocked(thread.recipient, false) + ApplicationContext.getInstance(this).jobManager.add(MultiDeviceBlockedUpdateJob()) + Util.runOnMain { + recyclerView.adapter!!.notifyDataSetChanged() + dialog.dismiss() + } + }.start() + }.show() + } + + private fun deleteConversation(thread: ThreadRecord) { + val threadID = thread.threadId + val recipient = thread.recipient + val threadDB = DatabaseFactory.getThreadDatabase(this) + val deleteThread = object : Runnable { + + override fun run() { + AsyncTask.execute { + val publicChat = DatabaseFactory.getLokiThreadDatabase(this@HomeActivity).getPublicChat(threadID) + if (publicChat != null) { + val apiDB = DatabaseFactory.getLokiAPIDatabase(this@HomeActivity) + apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server) + apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server) + ApplicationContext.getInstance(this@HomeActivity).publicChatAPI!!.leave(publicChat.channel, publicChat.server) + } + threadDB.deleteConversation(threadID) + ApplicationContext.getInstance(this@HomeActivity).messageNotifier.updateNotification(this@HomeActivity) + } + } + } + val dialogMessage = if (recipient.isGroupRecipient) R.string.activity_home_leave_group_dialog_message else R.string.activity_home_delete_conversation_dialog_message + val dialog = AlertDialog.Builder(this) + dialog.setMessage(dialogMessage) + dialog.setPositiveButton(R.string.yes) { _, _ -> + val isClosedGroup = recipient.address.isClosedGroup + // Send a leave group message if this is an active closed group + if (isClosedGroup && DatabaseFactory.getGroupDatabase(this).isActive(recipient.address.toGroupString())) { + if (!ClosedGroupsProtocol.leaveGroup(this, recipient)) { + Toast.makeText(this, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show() + return@setPositiveButton + } + } + // Archive the conversation and then delete it after 10 seconds (the case where the + // app was closed before the conversation could be deleted is handled in onCreate) + threadDB.archiveConversation(threadID) + val delay = if (isClosedGroup) 10000L else 1000L + val handler = Handler() + handler.postDelayed(deleteThread, delay) + // Notify the user + val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message + Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show() + } + dialog.setNegativeButton(R.string.no) { _, _ -> + // Do nothing + } + dialog.create().show() } private fun openConversation(thread: ThreadRecord) { @@ -262,92 +354,5 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe val intent = Intent(this, JoinPublicChatActivity::class.java) show(intent) } - - private class SwipeCallback(val activity: HomeActivity) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { - - override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { - return false - } - - @SuppressLint("StaticFieldLeak") - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - viewHolder as HomeAdapter.ViewHolder - val threadID = viewHolder.view.thread!!.threadId - val recipient = viewHolder.view.thread!!.recipient - val threadDatabase = DatabaseFactory.getThreadDatabase(activity) - val deleteThread = object : Runnable { - - override fun run() { - AsyncTask.execute { - val publicChat = DatabaseFactory.getLokiThreadDatabase(activity).getPublicChat(threadID) - if (publicChat != null) { - val apiDatabase = DatabaseFactory.getLokiAPIDatabase(activity) - apiDatabase.removeLastMessageServerID(publicChat.channel, publicChat.server) - apiDatabase.removeLastDeletionServerID(publicChat.channel, publicChat.server) - ApplicationContext.getInstance(activity).publicChatAPI!!.leave(publicChat.channel, publicChat.server) - } - threadDatabase.deleteConversation(threadID) - ApplicationContext.getInstance(activity).messageNotifier.updateNotification(activity) - } - } - } - val dialogMessage = if (recipient.isGroupRecipient) R.string.activity_home_leave_group_dialog_message else R.string.activity_home_delete_conversation_dialog_message - val dialog = AlertDialog.Builder(activity) - dialog.setMessage(dialogMessage) - dialog.setPositiveButton(R.string.yes) { _, _ -> - val isClosedGroup = recipient.address.isClosedGroup - // Send a leave group message if this is an active closed group - if (isClosedGroup && DatabaseFactory.getGroupDatabase(activity).isActive(recipient.address.toGroupString())) { - if (!ClosedGroupsProtocol.leaveGroup(activity, recipient)) { - Toast.makeText(activity, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show() - clearView(activity.recyclerView, viewHolder) - return@setPositiveButton - } - } - // Archive the conversation and then delete it after 10 seconds (the case where the - // app was closed before the conversation could be deleted is handled in onCreate) - threadDatabase.archiveConversation(threadID) - val delay = if (isClosedGroup) 10000L else 1000L - val handler = Handler() - handler.postDelayed(deleteThread, delay) - // Notify the user - val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message - Toast.makeText(activity, toastMessage, Toast.LENGTH_LONG).show() - } - dialog.setNegativeButton(R.string.no) { _, _ -> - clearView(activity.recyclerView, viewHolder) - } - dialog.create().show() - } - - override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dx: Float, dy: Float, actionState: Int, isCurrentlyActive: Boolean) { - if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE && dx < 0) { - val itemView = viewHolder.itemView - animate(viewHolder, dx) - val backgroundPaint = Paint() - backgroundPaint.color = activity.resources.getColorWithID(R.color.destructive, activity.theme) - c.drawRect(itemView.right.toFloat() - abs(dx), itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat(), backgroundPaint) - val icon = BitmapFactory.decodeResource(activity.resources, R.drawable.ic_trash_filled_32) - val iconPaint = Paint() - val left = itemView.right.toFloat() - abs(dx) + activity.resources.getDimension(R.dimen.medium_spacing) - val top = itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - icon.height) / 2 - c.drawBitmap(icon, left, top, iconPaint) - } else { - super.onChildDraw(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive) - } - } - - private fun animate(viewHolder: RecyclerView.ViewHolder, dx: Float) { - val alpha = 1.0f - abs(dx) / viewHolder.itemView.width.toFloat() - viewHolder.itemView.alpha = alpha - viewHolder.itemView.translationX = dx - } - - override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { - super.clearView(recyclerView, viewHolder) - viewHolder.itemView.alpha = 1.0f - viewHolder.itemView.translationX = 0.0f - } - } // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/dialogs/ConversationOptionsBottomSheet.kt b/src/org/thoughtcrime/securesms/loki/dialogs/ConversationOptionsBottomSheet.kt new file mode 100644 index 0000000000..498cb1f0e9 --- /dev/null +++ b/src/org/thoughtcrime/securesms/loki/dialogs/ConversationOptionsBottomSheet.kt @@ -0,0 +1,36 @@ +package org.thoughtcrime.securesms.loki.dialogs + +import android.os.Bundle +import android.support.design.widget.BottomSheetDialogFragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.fragment_conversation_bottom_sheet.* +import kotlinx.android.synthetic.main.fragment_device_list_bottom_sheet.* +import network.loki.messenger.R +import org.thoughtcrime.securesms.recipients.Recipient + +public class ConversationOptionsBottomSheet : BottomSheetDialogFragment() { + lateinit var recipient: Recipient + var onBlockOrUnblockTapped: (() -> Unit)? = null + var onDeleteTapped: (() -> Unit)? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_conversation_bottom_sheet, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + if (!recipient.isGroupRecipient && !recipient.isLocalNumber) { + val textID = if (recipient.isBlocked) R.string.RecipientPreferenceActivity_unblock else R.string.RecipientPreferenceActivity_block + blockOrUnblockTextView.setText(textID) + val iconID = if (recipient.isBlocked) R.drawable.ic_check_white_24dp else R.drawable.ic_block_white_24dp + val icon = context!!.resources.getDrawable(iconID, context!!.theme) + blockOrUnblockTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null) + blockOrUnblockTextView.setOnClickListener { onBlockOrUnblockTapped?.invoke() } + } else { + blockOrUnblockTextView.visibility = View.GONE + } + deleteTextView.setOnClickListener { onDeleteTapped?.invoke() } + } +} \ No newline at end of file From 662d9c7c637cd9f8a7ed41791b87c1d7990e2caa Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 12:49:37 +1000 Subject: [PATCH 11/18] Sync blocked contacts across devices --- .../securesms/database/RecipientDatabase.java | 5 ++-- .../securesms/jobs/PushDecryptJob.java | 1 + .../securesms/loki/activities/HomeActivity.kt | 22 ++++++++++++++++ .../loki/protocol/SyncMessagesProtocol.kt | 25 +++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java index 28c9611d6a..8553b2b73c 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -27,15 +27,14 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; public class RecipientDatabase extends Database { private static final String TAG = RecipientDatabase.class.getSimpleName(); - static final String TABLE_NAME = "recipient_preferences"; + static final String TABLE_NAME = "recipient_preferences"; private static final String ID = "_id"; - static final String ADDRESS = "recipient_ids"; + public static final String ADDRESS = "recipient_ids"; private static final String BLOCK = "block"; private static final String NOTIFICATION = "notification"; private static final String VIBRATE = "vibrate"; diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 4ceb4009f8..770c9d0ea9 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -315,6 +315,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { else if (syncMessage.getContacts().isPresent()) SyncMessagesProtocol.handleContactSyncMessage(context, content, syncMessage.getContacts().get()); else if (syncMessage.getGroups().isPresent()) SyncMessagesProtocol.handleClosedGroupSyncMessage(context, content, syncMessage.getGroups().get()); else if (syncMessage.getOpenGroups().isPresent()) SyncMessagesProtocol.handleOpenGroupSyncMessage(context, content, syncMessage.getOpenGroups().get()); + else if (syncMessage.getBlockedList().isPresent()) SyncMessagesProtocol.handleBlockedContactsSyncMessage(context, content, syncMessage.getBlockedList().get()); else Log.w(TAG, "Contains no known sync types..."); } else if (content.getCallMessage().isPresent()) { Log.i(TAG, "Got call message..."); diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index a3721f0a3d..cb9cae4fa4 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -2,13 +2,17 @@ package org.thoughtcrime.securesms.loki.activities import android.app.AlertDialog import android.arch.lifecycle.Observer +import android.content.BroadcastReceiver +import android.content.Context import android.content.Intent +import android.content.IntentFilter import android.database.Cursor import android.os.AsyncTask import android.os.Bundle import android.os.Handler import android.support.v4.app.LoaderManager import android.support.v4.content.Loader +import android.support.v4.content.LocalBroadcastManager import android.support.v7.widget.LinearLayoutManager import android.text.Spannable import android.text.SpannableString @@ -47,6 +51,7 @@ import org.whispersystems.signalservice.loki.protocol.syncmessages.SyncMessagesP class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate { private lateinit var glide: GlideRequests + private var broadcastReceiver: BroadcastReceiver? = null private val publicKey: String get() { @@ -166,6 +171,15 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe it.recipient.address.toPhoneString() }.toSet() FileServerAPI.shared.getDeviceLinks(publicKeys) + // Observe blocked contacts changed events + val broadcastReceiver = object : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent) { + recyclerView.adapter!!.notifyDataSetChanged() + } + } + this.broadcastReceiver = broadcastReceiver + LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged")) } override fun onResume() { @@ -198,6 +212,14 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe createNewPrivateChat() } } + + override fun onDestroy() { + val broadcastReceiver = this.broadcastReceiver + if (broadcastReceiver != null) { + LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver) + } + super.onDestroy() + } // endregion // region Updating diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index 16ec6aa8de..26b5bab8b2 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData import org.thoughtcrime.securesms.contacts.ContactAccessor.NumberData import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.database.RecipientDatabase import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.groups.GroupMessageProcessor import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob @@ -19,6 +20,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachment import org.whispersystems.signalservice.api.messages.SignalServiceContent import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage import org.whispersystems.signalservice.api.messages.SignalServiceGroup +import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage import org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsInputStream import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream @@ -138,4 +140,27 @@ object SyncMessagesProtocol { OpenGroupUtilities.addGroup(context, url, channel) } } + + @JvmStatic + fun handleBlockedContactsSyncMessage(context: Context, content: SignalServiceContent, blockedContacts: BlockedListMessage) { + val recipientDB = DatabaseFactory.getRecipientDatabase(context) + val cursor = recipientDB.blocked + val blockedPublicKeys = blockedContacts.numbers.toSet() + val publicKeysToUnblock = mutableSetOf() + fun addToUnblockListIfNeeded() { + val publicKey = cursor.getString(cursor.getColumnIndex(RecipientDatabase.ADDRESS)) ?: return + if (blockedPublicKeys.contains(publicKey)) { return } + publicKeysToUnblock.add(publicKey) + } + while (cursor.moveToNext()) { + addToUnblockListIfNeeded() + } + publicKeysToUnblock.forEach { + recipientDB.setBlocked(recipient(context, it), false) + } + blockedPublicKeys.forEach { + recipientDB.setBlocked(recipient(context, it), true) + } + ApplicationContext.getInstance(context).broadcaster.broadcast("blockedContactsChanged") + } } \ No newline at end of file From 5344d6aa64f03331904e58b299ac5dda54d30cd0 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 13:49:46 +1000 Subject: [PATCH 12/18] Handle syncing of blocked contacts --- .../securesms/loki/protocol/SyncMessagesProtocol.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index 26b5bab8b2..4254e60ada 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -93,11 +93,13 @@ object SyncMessagesProtocol { if (!allUserDevices.contains(content.sender)) { return } Log.d("Loki", "Received a contact sync message.") val contactsInputStream = DeviceContactsInputStream(message.contactsStream.asStream().inputStream) - val contactPublicKeys = contactsInputStream.readAll().map { it.number } - for (contactPublicKey in contactPublicKeys) { + val contacts = contactsInputStream.readAll() + for (contact in contacts) { + val contactPublicKey = contact.number if (contactPublicKey == userPublicKey || !PublicKeyValidation.isValid(contactPublicKey)) { return } val applicationContext = context.applicationContext as ApplicationContext applicationContext.sendSessionRequestIfNeeded(contactPublicKey) + DatabaseFactory.getRecipientDatabase(context).setBlocked(recipient(context, contactPublicKey), contact.isBlocked) } } From 0818b4c0e2cef86c33f77c79ab3961dcdffe55d7 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 14:15:36 +1000 Subject: [PATCH 13/18] Clean --- .../loki/protocol/SyncMessagesProtocol.kt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index 4254e60ada..4f34928f5e 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -52,8 +52,9 @@ object SyncMessagesProtocol { val allAddresses = ArrayList(DatabaseFactory.getRecipientDatabase(context).allAddresses) val result = mutableSetOf() for (address in allAddresses) { - if (!shouldSyncContact(context, address)) { continue } - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, address, false)) + if (!shouldSyncContact(context, address.serialize())) { continue } + val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(Recipient.from(context, address, false)) + if (threadID < 0) { continue } val displayName = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(address.serialize()) val contactData = ContactData(threadID, displayName) contactData.numbers.add(NumberData("TextSecure", address.serialize())) @@ -63,10 +64,11 @@ object SyncMessagesProtocol { } @JvmStatic - fun shouldSyncContact(context: Context, address: Address): Boolean { - if (!PublicKeyValidation.isValid(address.serialize())) { return false } - if (address.serialize() == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false } - if (address.serialize() == TextSecurePreferences.getLocalNumber(context)) { return false } + fun shouldSyncContact(context: Context, publicKey: String): Boolean { + if (!PublicKeyValidation.isValid(publicKey)) { return false } + if (publicKey == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) { return false } + if (publicKey == TextSecurePreferences.getLocalNumber(context)) { return false } + if (MultiDeviceProtocol.shared.getSlaveDevices(publicKey).contains(publicKey)) { return false } return true } @@ -100,6 +102,7 @@ object SyncMessagesProtocol { val applicationContext = context.applicationContext as ApplicationContext applicationContext.sendSessionRequestIfNeeded(contactPublicKey) DatabaseFactory.getRecipientDatabase(context).setBlocked(recipient(context, contactPublicKey), contact.isBlocked) + DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient(context, contactPublicKey)) // Creates the thread if needed } } @@ -122,9 +125,9 @@ object SyncMessagesProtocol { closedGroup.avatar.orNull(), closedGroup.admins ) - val signalServiceDataMessage = SignalServiceDataMessage(content.timestamp, signalServiceGroup, null, null) + val dataMessage = SignalServiceDataMessage(content.timestamp, signalServiceGroup, null, null) // This establishes sessions internally - GroupMessageProcessor.process(context, content, signalServiceDataMessage, false) + GroupMessageProcessor.process(context, content, dataMessage, false) } } From 8004313868db34237ab16a0415c8c6996b3ebc1a Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 16 Jul 2020 14:51:48 +1000 Subject: [PATCH 14/18] Debug --- .../securesms/jobs/MultiDeviceContactUpdateJob.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java index 4cd977c0d4..1a012b7270 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -122,7 +122,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy } if (address == null) generateFullContactUpdate(); - else if (SyncMessagesProtocol.shouldSyncContact(context, Address.fromSerialized(address))) generateSingleContactUpdate(Address.fromSerialized(address)); + else if (SyncMessagesProtocol.shouldSyncContact(context, address)) generateSingleContactUpdate(Address.fromSerialized(address)); } private void generateSingleContactUpdate(@NonNull Address address) @@ -139,7 +139,7 @@ public class MultiDeviceContactUpdateJob extends BaseJob implements InjectableTy Optional identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address); Optional verifiedMessage = getVerifiedMessage(recipient, identityRecord); - if (SyncMessagesProtocol.shouldSyncContact(context, address)) { + if (SyncMessagesProtocol.shouldSyncContact(context, address.serialize())) { out.write(new DeviceContact(address.toPhoneString(), Optional.fromNullable(recipient.getName()), getAvatar(recipient.getContactUri()), From 13b6bff206ce7c05416c01d7cf65945c0077a533 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 17 Jul 2020 08:49:24 +1000 Subject: [PATCH 15/18] Remove redundant line --- .../thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt index 4f34928f5e..6218575330 100644 --- a/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt +++ b/src/org/thoughtcrime/securesms/loki/protocol/SyncMessagesProtocol.kt @@ -102,7 +102,6 @@ object SyncMessagesProtocol { val applicationContext = context.applicationContext as ApplicationContext applicationContext.sendSessionRequestIfNeeded(contactPublicKey) DatabaseFactory.getRecipientDatabase(context).setBlocked(recipient(context, contactPublicKey), contact.isBlocked) - DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient(context, contactPublicKey)) // Creates the thread if needed } } From 1e892568afa29ff9c477ef1e39905338b4d84479 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 17 Jul 2020 09:05:37 +1000 Subject: [PATCH 16/18] Handle session request expiration --- .../securesms/ApplicationContext.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 51950ccff7..e1a079f16a 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -108,6 +108,7 @@ import org.whispersystems.signalservice.loki.api.shelved.p2p.LokiP2PAPIDelegate; import org.whispersystems.signalservice.loki.database.LokiAPIDatabaseProtocol; import org.whispersystems.signalservice.loki.protocol.mentions.MentionsManager; import org.whispersystems.signalservice.loki.protocol.meta.SessionMetaProtocol; +import org.whispersystems.signalservice.loki.protocol.meta.TTLUtilities; import org.whispersystems.signalservice.loki.protocol.multidevice.DeviceLink; import org.whispersystems.signalservice.loki.protocol.multidevice.MultiDeviceProtocol; import org.whispersystems.signalservice.loki.protocol.sessionmanagement.SessionManagementProtocol; @@ -585,6 +586,17 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc Runtime.getRuntime().exit(0); } + public boolean hasSentSessionRequestExpired(@NotNull String publicKey) { + LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); + Long timestamp = apiDB.getSessionRequestSentTimestamp(publicKey); + if (timestamp != null) { + long expiration = timestamp + TTLUtilities.getTTL(TTLUtilities.MessageType.SessionRequest); + return new Date().getTime() > expiration; + } else { + return false; + } + } + @Override public void sendSessionRequestIfNeeded(@NotNull String publicKey) { // It's never necessary to establish a session with self @@ -597,10 +609,14 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc // Check that we didn't already send a session request LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); boolean hasSentSessionRequest = (apiDB.getSessionRequestSentTimestamp(publicKey) != null); - if (hasSentSessionRequest) { return; } + boolean hasSentSessionRequestExpired = hasSentSessionRequestExpired(publicKey); + if (hasSentSessionRequestExpired) { + apiDB.setSessionRequestSentTimestamp(publicKey, 0); + } + if (hasSentSessionRequest && !hasSentSessionRequestExpired) { return; } // Send the session request long timestamp = new Date().getTime(); - DatabaseFactory.getLokiAPIDatabase(this).setSessionRequestSentTimestamp(publicKey, timestamp); + apiDB.setSessionRequestSentTimestamp(publicKey, timestamp); PushSessionRequestMessageSendJob job = new PushSessionRequestMessageSendJob(publicKey, timestamp); jobManager.add(job); } From 4d075679d3e58fffd289e85e2a77ea0f2261695b Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 17 Jul 2020 09:56:32 +1000 Subject: [PATCH 17/18] Integrate Persian translation --- res/values-fa/strings.xml | 212 +++++++++++++++++++++++++++++++++++++- 1 file changed, 211 insertions(+), 1 deletion(-) diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index def3986d3a..dd466c2613 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -1214,5 +1214,215 @@ Session قفل شده است یادآور: درباره ی ما - + + + + + + + ادامه + کپی 🀄 + URL نامعتبر است + در کلیپ بورد کپی شد + پیوند دستگاه امکان پذیر نیست. + بعد + اشتراک گذاری + شناسه نامعتبر جلسه + لغو + شناسه جلسه شما + + جلسه شما از اینجا شروع می شود... + شناسه جلسه را ایجاد کنید + جلسه خود را ادامه دهید + پیوند به یک حساب کاربری موجود + ارتباط دستگاه شما با موفقیت انجام نشد + + جلسه چیست؟ + این یک برنامه پیام رسانی غیرمتمرکز و رمزگذاری شده است + بنابراین اطلاعات شخصی یا ابرداده گفتگوی من جمع نمی شود؟ چگونه کار می کند؟ + استفاده از ترکیبی از فن آوری های رمزگذاری پیشرفته مسیریابی ناشناس و پایان به پایان. + دوستان اجازه نمی دهند تا دوستان از پیام رسان های مصالحه استفاده کنند. خواهش میکنم. + + سلام به شناسه جلسه خود + شناسه جلسه شما آدرس منحصر به فردی است که افراد می توانند از آنها برای تماس با شما در جلسه استفاده کنند. بدون ارتباط با هویت واقعی شما ، شناسه جلسه شما کاملاً ناشناس و خصوصی است. + در کلیپ بورد کپی شد + + حساب خود را بازیابی کنید + عبارت بازیابی را هنگام ثبت نام برای بازیابی حساب خود وارد کنید. + عبارت بازیابی خود را وارد کنید + + دستگاه پیوند + شناسه جلسه را وارد کنید + اسکن کد QR + به تنظیمات > دستگاه ها > پیوند دستگاه در دستگاه دیگر خود بروید و سپس کد QR را که برای شروع کار پیوند داده است ، اسکن کنید. + + دستگاه خود را پیوند دهید + به تنظیمات > دستگاه ها > پیوند دستگاه در دستگاه دیگر خود بروید و سپس شناسه جلسه خود را در اینجا وارد کنید تا فرایند پیوند آغاز شود. + شناسه جلسه خود را وارد کنید + + نام صفحه نمایش خود را انتخاب کنید + این نام شما هنگام استفاده از جلسه خواهد بود. این می تواند نام واقعی شما باشد ، نام مستعار یا هر چیز دیگری که دوست دارید. + نام نمایشگر را وارد کنید + لطفاً نام نمایشگر را انتخاب کنید + لطفاً یک نام نمایشگر را انتخاب کنید که فقط از نویسه های Az ، AZ ، 0-9 و _ تشکیل شده باشد + لطفاً نام نمایشگر کوتاه تری انتخاب کنید + + اعلانهای فشار + دو راه وجود دارد که جلسه می تواند اعلان های فشار را کنترل کند. حتما قبل از انتخاب توضیحات را با دقت بخوانید. + پیام ابری فایربیس + جلسه برای دریافت اعلان های فشار از سرویس پیام ابری فایربیس استفاده می کند. با اطمینان و بلافاصله از پیامهای جدید مطلع خواهید شد. استفاده از FCM بدان معنا است که آدرس IP و نشانه دستگاه شما در معرض گوگل قرار خواهد گرفت. اگر از اعلانهای فشار برای سایر برنامه ها استفاده می کنید ، این مورد در حال حاضر اینگونه خواهد بود. آدرس IP و نشانه دستگاه شما نیز در معرض Loki قرار خواهد گرفت ، اما پیام های شما هنوز هم از طریق رمزگذاری شده توسط اونیون و رمزگذاری نهایی به پایان می رسد ، بنابراین محتوای پیام های شما کاملاً خصوصی خواهد بود. + زمینه رای گیری + جلسه گاه به گاه پیام های جدید را در پس زمینه بررسی می کند. این محافظت کامل از ابرداده را تضمین می کند ، اما اعلان های پیام ممکن است به میزان قابل توجهی به تأخیر بیفتند. + توصیه شده + لطفا گزینه ای را انتخاب کنید + + شما هنوز هیچ تماسی ندارید + شروع جلسه + آیا مطمئن هستید که می خواهید این گروه را ترک کنید؟ + نمی توان گروه را ترک کرد + آیا مطمئن هستید که می خواهید این مکالمه را حذف کنید؟ + مکالمه حذف شد + + اعلانهای فشار + جلسه اکنون دو راه برای رسیدگی به اعلان های فشار دارد. حتما قبل از انتخاب توضیحات را با دقت بخوانید. + پیام ابری فایربیس + جلسه برای دریافت اعلان های فشار از سرویس پیام ابری فایربیس استفاده می کند. با اطمینان و بلافاصله از پیامهای جدید مطلع خواهید شد. استفاده از FCM بدان معنا است که آدرس IP و نشانه دستگاه شما در معرض گوگل قرار خواهد گرفت. اگر از اعلانهای فشار برای سایر برنامه ها استفاده می کنید ، این مورد در حال حاضر اینگونه خواهد بود. آدرس IP و نشانه دستگاه شما نیز در معرض Loki قرار خواهد گرفت ، اما پیام های شما هنوز هم از طریق رمزگذاری شده توسط پیاز و رمزگذاری نهایی به پایان می رسد ، بنابراین محتوای پیام های شما کاملاً خصوصی خواهد بود. + زمینه رای گیری + جلسه گاه به گاه پیام های جدید را در پس زمینه بررسی می کند. این محافظت کامل از ابرداده را تضمین می کند ، اما اعلان های پیام ممکن است به میزان قابل توجهی به تأخیر بیفتند. + توصیه شده + لطفا گزینه ای را انتخاب کنید + تایید + رد + + عبارت بازیابی شما + با عبارت بازیابی خود مطابقت داشته باشید + عبارت بازیابی شما کلید اصلی شناسه جلسه شما است - در صورت عدم دسترسی به دستگاه خود می توانید از آن برای بازگرداندن شناسه جلسه استفاده کنید. عبارت بازیابی خود را در مکانی امن ذخیره کنید و آن را به کسی ندهید. + نگه دارید تا فاش شود + + با ذخیره کردن عبارت بازیابی ، حساب خود را ایمن کنید + برای فاش کردن عبارت بازیابی ، بر روی کلمات redacted ضربه زده و نگه دارید ، سپس با خیال راحت آن را ذخیره کنید تا شناسه جلسه خود را ایمن نمایید. + حتماً عبارت بازیابی خود را در مکانی امن ذخیره کنید + + مسیر + جلسه IP شما را با گزاف گویی پیام های خود از طریق چندین گره سرویس در شبکه غیرمتمرکز جلسه مخفی می کند. اینها کشورهایی هستند که اتصال شما در حال حاضر از طریق آن فراخوانی می شوند: + شما + گره ورود + گره سرویس + مقصد + بیشتر بدانید + + جلسه جدید + شناسه جلسه را وارد کنید + اسکن کد QR + برای شروع جلسه ، کد QR کاربر را اسکن کنید. با ضربه زدن روی نماد کد QR در تنظیمات حساب ، کدهای QR را می توان یافت. + + شناسه گیرنده را وارد کنید + کاربران می توانند با وارد کردن به تنظیمات حساب خود و ضربه زدن به Share Share Session ID یا با به اشتراک گذاشتن کد QR خود ، شناسه جلسه خود را به اشتراک بگذارند. + + جلسه برای اسکن کدهای QR به دوربین دسترسی دارد + دسترسی به کمک دوربین + + گروه بسته شده جدید + نام گروه را وارد کنید + گروه های بسته تا 10 عضو را پشتیبانی می کنند و همان محافظت از حریم خصوصی را به عنوان جلسات یک به یک ارائه می دهند. + شما هنوز هیچ تماسی ندارید + شروع جلسه + لطفاً یک نام گروه وارد کنید + لطفاً نام گروه کوتاه تری وارد کنید + لطفا حداقل 2 عضو گروه را انتخاب کنید + یک گروه بسته نمی تواند بیش از 10 عضو داشته باشد + یکی از اعضای گروه شما دارای شناسه نامعتبر است + + به گروه باز بپیوندید + امکان پیوستن به گروه نیست + آدرس اینترنتی گروه را باز کنید + اسکن کد QR + کد QR گروه باز را که می خواهید بپیوندید اسکن کنید + + یک URL گروه باز وارد کنید + گروه های باز می توانند توسط هر کسی بپیوندند و محافظت کامل از حریم خصوصی ارائه نمی دهند + + تنظیمات + نام نمایشگر را وارد کنید + لطفاً نام نمایشگر را انتخاب کنید + لطفاً یک نام نمایشگر را انتخاب کنید که فقط از نویسه های Az ، AZ ، 0-9 و _ تشکیل شده باشد + لطفاً نام نمایشگر کوتاه تری انتخاب کنید + حریم خصوصی + اطلاعیه + چت + دستگاه ها + عبارت بازیابی + اطلاعات روشن + + اطلاعیه + سبک اطلاع رسانی + محتوای اطلاع رسانی + + حریم خصوصی + + چت + + دستگاه ها + دستگاه محدود شد + در حال حاضر مجاز به پیوند بیش از یک دستگاه نیست. + دستگاه را نمی توان ارتباط برقرار کرد. + دستگاه شما با موفقیت ارتباط برقرار نشد + پیوند دستگاه امکان پذیر نیست. + شما هنوز هیچ دستگاهی را پیوند نداده اید + پیوند یک دستگاه (بتا) + + استراتژی اعلان + از FCM استفاده کنید + با استفاده از پیام ابری فایربیس، اعلان های فشار قابل اطمینان تر امکان پذیر است ، اما نشانگر IP و دستگاه شما را در گوگل و لوکی قرار می دهد. + + در انتظار مجوز + پیوند دستگاه مجاز است + لطفاً بررسی کنید که کلمات زیر با کلمات نشان داده شده در دستگاه دیگر شما مطابقت دارند. + دستگاه شما با موفقیت پیوند خورده است + + منتظر دستگاه + درخواست پیوند دریافت شد + پیوند دستگاه مجاز + جلسه را در دستگاه دیگر خود دانلود کرده و روی پیوند به یک حساب موجود در پایین صفحه فرود ضربه بزنید. اگر در حال حاضر دارای یک حساب کاربری در دستگاه دیگر خود هستید ، ابتدا باید آن حساب را حذف کنید. + لطفاً بررسی کنید که کلمات زیر با کلمات نشان داده شده در دستگاه دیگر شما مطابقت دارند. + لطفاً منتظر بمانید تا پیوند دستگاه ایجاد شود. این ممکن است تا یک دقیقه طول بکشد. + اجازه دهید + + تغییر نام + دستگاه را جدا کنید + + یک نام وارد کنید + + عبارت بازیابی شما + این عبارت بازیابی شماست. با استفاده از آن ، می توانید شناسه جلسه خود را به دستگاه جدید بازیابی یا انتقال دهید. + + پاک کردن همه داده ها + این به طور دائم پیام ها، جلسات و مخاطبین شما را حذف می کند. + + کد QR + مشاهده کد QR من + اسکن کد QR + برای شروع مکالمه با آنها ، کد QR شخصی را اسکن کنید + + این کد QR شماست. سایر کاربران می توانند برای شروع جلسه با شما آن را اسکن کنند. + کد QR را به اشتراک بگذارید + + تایید کنید + کاهش می یابد + %1$s برای شما درخواست جلسه ارسال کرد + شما قبول کرده اید %1$s درخواست جلسه + شما کاهش داده اید %1$s درخواست جلسه + %1$s درخواست جلسه منقضی شده است + شما ارسال کرده اید %1$s درخواست جلسه + %1$s درخواست جلسه خود را پذیرفته اید + درخواست جلسه شما به %1$s منقضی شده است + + آیا می خواهید جلسه خود را با آن بازیابی کنید %s ؟ + رد + بازگرداندن + + مخاطبین + گروه های بسته + باز کردن گروه ها + From 12f70f188e6b8ce26348b5208f0bed9d3c5ada2a Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 17 Jul 2020 12:10:25 +1000 Subject: [PATCH 18/18] Make the app work with RTL languages --- res/layout-sw400dp/fragment_enter_public_key.xml | 2 +- res/layout/activity_settings.xml | 2 +- res/layout/conversation_input_panel.xml | 3 ++- res/layout/dialog_clear_all_data.xml | 2 +- res/layout/dialog_link_device_master_mode.xml | 2 +- res/layout/dialog_seed.xml | 2 +- res/layout/fragment_enter_public_key.xml | 2 +- res/layout/microphone_recorder_view.xml | 4 ++-- res/layout/view_conversation.xml | 12 ++++++------ res/values-fa/strings.xml | 2 +- res/values/styles.xml | 3 +++ .../securesms/loki/activities/PathActivity.kt | 2 ++ .../loki/views/NewConversationButtonSetView.kt | 2 ++ 13 files changed, 24 insertions(+), 16 deletions(-) diff --git a/res/layout-sw400dp/fragment_enter_public_key.xml b/res/layout-sw400dp/fragment_enter_public_key.xml index d2a9e7a290..88304992c9 100644 --- a/res/layout-sw400dp/fragment_enter_public_key.xml +++ b/res/layout-sw400dp/fragment_enter_public_key.xml @@ -73,7 +73,7 @@ android:layout_width="0dp" android:layout_height="@dimen/medium_button_height" android:layout_weight="1" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:text="@string/share" /> diff --git a/res/layout/activity_settings.xml b/res/layout/activity_settings.xml index 73a6fe5668..bff6499952 100644 --- a/res/layout/activity_settings.xml +++ b/res/layout/activity_settings.xml @@ -150,7 +150,7 @@ android:layout_width="0dp" android:layout_height="@dimen/medium_button_height" android:layout_weight="1" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:text="@string/share" /> diff --git a/res/layout/conversation_input_panel.xml b/res/layout/conversation_input_panel.xml index b2f64984b2..a6b7943ac3 100644 --- a/res/layout/conversation_input_panel.xml +++ b/res/layout/conversation_input_panel.xml @@ -96,6 +96,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:textAlignment="viewStart" android:layout_weight="1" android:textColorHint="#99FFFFFF" android:textSize="@dimen/small_font_size" @@ -137,7 +138,7 @@ android:id="@+id/recorder_view" android:layout_height="match_parent" android:layout_width="36dp" - android:layout_gravity="center_vertical" + android:layout_gravity="center" android:clipChildren="false" android:clipToPadding="false"> diff --git a/res/layout/dialog_clear_all_data.xml b/res/layout/dialog_clear_all_data.xml index 4f9077a939..86e9924fa9 100644 --- a/res/layout/dialog_clear_all_data.xml +++ b/res/layout/dialog_clear_all_data.xml @@ -49,7 +49,7 @@ android:layout_width="0dp" android:layout_height="@dimen/small_button_height" android:layout_weight="1" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:text="@string/delete" /> diff --git a/res/layout/dialog_link_device_master_mode.xml b/res/layout/dialog_link_device_master_mode.xml index 6236bba517..76113b3200 100644 --- a/res/layout/dialog_link_device_master_mode.xml +++ b/res/layout/dialog_link_device_master_mode.xml @@ -87,7 +87,7 @@ android:layout_width="0dp" android:layout_height="@dimen/small_button_height" android:layout_weight="1" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:text="@string/dialog_link_device_master_mode_authorize_button_title" android:visibility="gone" /> diff --git a/res/layout/dialog_seed.xml b/res/layout/dialog_seed.xml index de1069adeb..37b523ad98 100644 --- a/res/layout/dialog_seed.xml +++ b/res/layout/dialog_seed.xml @@ -60,7 +60,7 @@ android:layout_width="0dp" android:layout_height="@dimen/small_button_height" android:layout_weight="1" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:text="@string/copy" /> diff --git a/res/layout/fragment_enter_public_key.xml b/res/layout/fragment_enter_public_key.xml index 27be721c1f..63ae02d7f9 100644 --- a/res/layout/fragment_enter_public_key.xml +++ b/res/layout/fragment_enter_public_key.xml @@ -73,7 +73,7 @@ android:layout_width="0dp" android:layout_height="@dimen/medium_button_height" android:layout_weight="1" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:text="@string/share" /> diff --git a/res/layout/microphone_recorder_view.xml b/res/layout/microphone_recorder_view.xml index 6fed405950..e02cbc4c89 100644 --- a/res/layout/microphone_recorder_view.xml +++ b/res/layout/microphone_recorder_view.xml @@ -8,11 +8,11 @@ android:id="@+id/quick_audio_toggle" android:layout_width="24dp" android:layout_height="24dp" - android:layout_gravity="center_vertical" - android:layout_marginEnd="2dp" + android:layout_gravity="center" android:background="@null" android:contentDescription="@string/conversation_activity__quick_attachment_drawer_record_and_send_audio_description" android:scaleType="centerInside" + android:layout_marginEnd="4dp" android:tint="@color/text" app:srcCompat="@drawable/ic_microphone" /> diff --git a/res/layout/view_conversation.xml b/res/layout/view_conversation.xml index 43a82160ba..624d1b262b 100644 --- a/res/layout/view_conversation.xml +++ b/res/layout/view_conversation.xml @@ -18,14 +18,14 @@ android:layout_width="@dimen/medium_profile_picture_size" android:layout_height="@dimen/medium_profile_picture_size" android:layout_marginTop="@dimen/medium_spacing" - android:layout_marginLeft="@dimen/medium_spacing" + android:layout_marginStart="@dimen/medium_spacing" android:layout_marginBottom="@dimen/medium_spacing" /> + android:layout_marginEnd="4dp" /> + android:layout_marginStart="@dimen/medium_spacing" /> diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index dd466c2613..f478e99355 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -1221,7 +1221,7 @@ ادامه - کپی 🀄 + رونویسی کردن URL نامعتبر است در کلیپ بورد کپی شد پیوند دستگاه امکان پذیر نیست. diff --git a/res/values/styles.xml b/res/values/styles.xml index 35f4706d93..3355423f77 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -139,6 +139,7 @@ @dimen/large_font_size @color/text @font/space_mono_regular + viewStart @@ -162,6 +164,7 @@ @dimen/small_font_size @color/text @drawable/session_edit_text_cursor + viewStart 1 diff --git a/src/org/thoughtcrime/securesms/loki/activities/PathActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/PathActivity.kt index 929e5de266..1133865cad 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/PathActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/PathActivity.kt @@ -121,6 +121,7 @@ class PathActivity : PassphraseRequiredActionBarActivity() { titleTextView.setTextColor(resources.getColorWithID(R.color.text, theme)) titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.medium_font_size)) titleTextView.text = title + titleTextView.textAlignment = TextView.TEXT_ALIGNMENT_VIEW_START val titleContainer = LinearLayout(this) titleContainer.orientation = LinearLayout.VERTICAL titleContainer.addView(titleTextView) @@ -133,6 +134,7 @@ class PathActivity : PassphraseRequiredActionBarActivity() { subtitleTextView.setTextColor(resources.getColorWithID(R.color.text, theme)) subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.small_font_size)) subtitleTextView.text = subtitle + subtitleTextView.textAlignment = TextView.TEXT_ALIGNMENT_VIEW_START titleContainer.addView(subtitleTextView) } return mainContainer diff --git a/src/org/thoughtcrime/securesms/loki/views/NewConversationButtonSetView.kt b/src/org/thoughtcrime/securesms/loki/views/NewConversationButtonSetView.kt index 3f94883c6c..1b26e1d917 100644 --- a/src/org/thoughtcrime/securesms/loki/views/NewConversationButtonSetView.kt +++ b/src/org/thoughtcrime/securesms/loki/views/NewConversationButtonSetView.kt @@ -16,6 +16,7 @@ import android.os.Vibrator import android.support.annotation.ColorRes import android.support.annotation.DrawableRes import android.util.AttributeSet +import android.view.Gravity import android.view.MotionEvent import android.widget.ImageView import android.widget.RelativeLayout @@ -91,6 +92,7 @@ class NewConversationButtonSetView : RelativeLayout { addView(imageView) imageView.x = collapsedImageViewPosition.x imageView.y = collapsedImageViewPosition.y + gravity = Gravity.TOP or Gravity.LEFT // Intentionally not Gravity.START } fun expand() {