From 2aa179585f220236f187de449eb581cd8b604250 Mon Sep 17 00:00:00 2001 From: Anton Chekulaev Date: Mon, 14 Dec 2020 12:16:30 +1100 Subject: [PATCH] Identity functionality and data structure are completely removed. --- .../identity/UntrustedSendDialog.java | 66 ----- .../identity/UnverifiedBannerView.java | 97 ------- .../identity/UnverifiedSendDialog.java | 67 ----- .../conversation/ConversationActivity.java | 178 +----------- .../conversation/ConversationUpdateItem.java | 8 - .../storage/SignalProtocolStoreImpl.java | 27 +- .../storage/TextSecureIdentityKeyStore.java | 151 ----------- .../securesms/database/DatabaseFactory.java | 6 - .../securesms/database/IdentityDatabase.java | 243 ----------------- .../database/helpers/ClassicOpenHelper.java | 2 - .../database/helpers/SQLCipherOpenHelper.java | 38 ++- .../database/identity/IdentityRecordList.java | 115 -------- .../SignalCommunicationModule.java | 2 - .../migration/WorkManagerFactoryMappings.java | 2 - .../securesms/jobs/JobManagerFactories.java | 1 - .../securesms/jobs/PushDecryptJob.java | 9 - .../securesms/jobs/RetrieveProfileJob.java | 255 ------------------ .../RecoveryPhraseRestoreActivity.kt | 4 - .../loki/activities/RegisterActivity.kt | 4 - .../securesms/util/IdentityUtil.java | 252 ----------------- .../main/res/layout/conversation_activity.xml | 7 - ...sation_activity_unverified_banner_stub.xml | 6 - .../api/SignalServiceMessageReceiver.java | 4 +- .../loki/utilities/DownloadUtilities.kt | 2 + 24 files changed, 45 insertions(+), 1501 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/identity/UntrustedSendDialog.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedBannerView.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedSendDialog.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/IdentityDatabase.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java delete mode 100644 app/src/main/res/layout/conversation_activity_unverified_banner_stub.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/identity/UntrustedSendDialog.java b/app/src/main/java/org/thoughtcrime/securesms/components/identity/UntrustedSendDialog.java deleted file mode 100644 index 1e5660d785..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/identity/UntrustedSendDialog.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.thoughtcrime.securesms.components.identity; - - -import android.content.Context; -import android.content.DialogInterface; -import android.os.AsyncTask; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; - -import network.loki.messenger.R; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; - -import java.util.List; - -import static org.session.libsignal.libsignal.SessionCipher.SESSION_LOCK; - -public class UntrustedSendDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener { - - private final List untrustedRecords; - private final ResendListener resendListener; - - public UntrustedSendDialog(@NonNull Context context, - @NonNull String message, - @NonNull List untrustedRecords, - @NonNull ResendListener resendListener) - { - super(context); - this.untrustedRecords = untrustedRecords; - this.resendListener = resendListener; - - setTitle(R.string.UntrustedSendDialog_send_message); - setIconAttribute(R.attr.dialog_alert_icon); - setMessage(message); - setPositiveButton(R.string.UntrustedSendDialog_send, this); - setNegativeButton(android.R.string.cancel, null); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - final IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(getContext()); - - new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - synchronized (SESSION_LOCK) { - for (IdentityRecord identityRecord : untrustedRecords) { - identityDatabase.setApproval(identityRecord.getAddress(), true); - } - } - - return null; - } - - @Override - protected void onPostExecute(Void result) { - resendListener.onResendMessage(); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - public interface ResendListener { - public void onResendMessage(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedBannerView.java b/app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedBannerView.java deleted file mode 100644 index f06cd2c6bd..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedBannerView.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.thoughtcrime.securesms.components.identity; - - -import android.content.Context; -import android.os.Build; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import android.util.AttributeSet; -import org.thoughtcrime.securesms.logging.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import network.loki.messenger.R; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; -import org.thoughtcrime.securesms.util.ViewUtil; - -import java.util.List; - -public class UnverifiedBannerView extends LinearLayout { - - private static final String TAG = UnverifiedBannerView.class.getSimpleName(); - - private View container; - private TextView text; - private ImageView closeButton; - - public UnverifiedBannerView(Context context) { - super(context); - initialize(); - } - - public UnverifiedBannerView(Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - initialize(); - } - - @RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) - public UnverifiedBannerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - initialize(); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public UnverifiedBannerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - initialize(); - } - - private void initialize() { - LayoutInflater.from(getContext()).inflate(R.layout.unverified_banner_view, this, true); - this.container = ViewUtil.findById(this, R.id.container); - this.text = ViewUtil.findById(this, R.id.unverified_text); - this.closeButton = ViewUtil.findById(this, R.id.cancel); - } - - public void display(@NonNull final String text, - @NonNull final List unverifiedIdentities, - @NonNull final ClickListener clickListener, - @NonNull final DismissListener dismissListener) - { - this.text.setText(text); - setVisibility(View.VISIBLE); - - this.container.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - Log.i(TAG, "onClick()"); - clickListener.onClicked(unverifiedIdentities); - } - }); - - this.closeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - hide(); - dismissListener.onDismissed(unverifiedIdentities); - } - }); - } - - public void hide() { - setVisibility(View.GONE); - } - - public interface DismissListener { - public void onDismissed(List unverifiedIdentities); - } - - public interface ClickListener { - public void onClicked(List unverifiedIdentities); - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedSendDialog.java b/app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedSendDialog.java deleted file mode 100644 index 1d9ec45ad2..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/identity/UnverifiedSendDialog.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.thoughtcrime.securesms.components.identity; - -import android.content.Context; -import android.content.DialogInterface; -import android.os.AsyncTask; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; - -import network.loki.messenger.R; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; - -import java.util.List; - -import static org.session.libsignal.libsignal.SessionCipher.SESSION_LOCK; - -public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener { - - private final List untrustedRecords; - private final ResendListener resendListener; - - public UnverifiedSendDialog(@NonNull Context context, - @NonNull String message, - @NonNull List untrustedRecords, - @NonNull ResendListener resendListener) - { - super(context); - this.untrustedRecords = untrustedRecords; - this.resendListener = resendListener; - - setTitle(R.string.UnverifiedSendDialog_send_message); - setIconAttribute(R.attr.dialog_alert_icon); - setMessage(message); - setPositiveButton(R.string.UnverifiedSendDialog_send, this); - setNegativeButton(android.R.string.cancel, null); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - final IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(getContext()); - - new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - synchronized (SESSION_LOCK) { - for (IdentityRecord identityRecord : untrustedRecords) { - identityDatabase.setVerified(identityRecord.getAddress(), - identityRecord.getIdentityKey(), - IdentityDatabase.VerifiedStatus.DEFAULT); - } - } - - return null; - } - - @Override - protected void onPostExecute(Void result) { - resendListener.onResendMessage(); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - - public interface ResendListener { - public void onResendMessage(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index d57ec11897..c75d46fec7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -112,29 +112,21 @@ import org.thoughtcrime.securesms.components.TooltipPopup; import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider; import org.thoughtcrime.securesms.components.emoji.EmojiStrings; import org.thoughtcrime.securesms.components.emoji.MediaKeyboard; -import org.thoughtcrime.securesms.components.identity.UntrustedSendDialog; -import org.thoughtcrime.securesms.components.identity.UnverifiedBannerView; -import org.thoughtcrime.securesms.components.identity.UnverifiedSendDialog; import org.thoughtcrime.securesms.components.location.SignalPlace; import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData; import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.contactshare.ContactUtil; import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher; -import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable; import org.thoughtcrime.securesms.crypto.SecurityEvent; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DraftDatabase; import org.thoughtcrime.securesms.database.DraftDatabase.Draft; import org.thoughtcrime.securesms.database.DraftDatabase.Drafts; -import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; -import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MmsSmsColumns.Types; import org.thoughtcrime.securesms.database.ThreadDatabase; -import org.thoughtcrime.securesms.database.identity.IdentityRecordList; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.database.model.StickerRecord; @@ -200,7 +192,6 @@ import org.thoughtcrime.securesms.stickers.StickerSearchRepository; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.ExpirationUtil; -import org.thoughtcrime.securesms.util.IdentityUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.PushCharacterCalculator; import org.thoughtcrime.securesms.util.ServiceUtil; @@ -218,7 +209,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Set; @@ -229,7 +219,6 @@ import java.util.concurrent.atomic.AtomicInteger; import kotlin.Unit; import network.loki.messenger.R; -import static org.session.libsignal.libsignal.SessionCipher.SESSION_LOCK; import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; /** @@ -290,7 +279,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private Button unblockButton; private Button makeDefaultSmsButton; private InputAwareLayout container; - private Stub unverifiedBannerView; private Stub groupShareProfileView; private TypingStatusTextWatcher typingTextWatcher; private MentionTextWatcher mentionTextWatcher; @@ -327,8 +315,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private int collapsedKeyboardHeight = Integer.MAX_VALUE; private int keyboardHeight = 0; - private final IdentityRecordList identityRecords = new IdentityRecordList(); - // Message status bar private ArrayList broadcastReceivers = new ArrayList<>(); private String messageStatus = null; @@ -505,7 +491,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity EventBus.getDefault().register(this); initializeEnabledCheck(); initializeMmsEnabledCheck(); - initializeIdentityRecords(); composeText.setTransport(); updateTitleTextView(recipient); @@ -513,7 +498,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateSubtitleTextView(); updateInputUI(recipient); setGroupShareProfileReminder(recipient); - calculateCharactersRemaining(); ApplicationContext.getInstance(this).messageNotifier.setVisibleThread(threadId); markThreadAsRead(); @@ -1178,52 +1162,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } - private void handleUnverifiedRecipients() { - List unverifiedRecipients = identityRecords.getUnverifiedRecipients(this); - List unverifiedRecords = identityRecords.getUnverifiedRecords(); - String message = IdentityUtil.getUnverifiedSendDialogDescription(this, unverifiedRecipients); - - if (message == null) return; - - //noinspection CodeBlock2Expr - new UnverifiedSendDialog(this, message, unverifiedRecords, () -> { - initializeIdentityRecords().addListener(new ListenableFuture.Listener() { - @Override - public void onSuccess(Boolean result) { - sendMessage(); - } - - @Override - public void onFailure(ExecutionException e) { - throw new AssertionError(e); - } - }); - }).show(); - } - - private void handleUntrustedRecipients() { - List untrustedRecipients = identityRecords.getUntrustedRecipients(this); - List untrustedRecords = identityRecords.getUntrustedRecords(); - String untrustedMessage = IdentityUtil.getUntrustedSendDialogDescription(this, untrustedRecipients); - - if (untrustedMessage == null) return; - - //noinspection CodeBlock2Expr - new UntrustedSendDialog(this, untrustedMessage, untrustedRecords, () -> { - initializeIdentityRecords().addListener(new ListenableFuture.Listener() { - @Override - public void onSuccess(Boolean result) { - sendMessage(); - } - - @Override - public void onFailure(ExecutionException e) { - throw new AssertionError(e); - } - }); - }).show(); - } - private void handleSecurityChange(boolean isSecureText, boolean isDefaultSms) { Log.i(TAG, "handleSecurityChange(" + isSecureText + ", " + isDefaultSms + ")"); if (isSecurityInitialized && isSecureText == true && isDefaultSms == this.isDefaultSms) { @@ -1249,7 +1187,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } */ - calculateCharactersRemaining(); supportInvalidateOptionsMenu(); updateInputUI(recipient); } @@ -1429,63 +1366,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - private ListenableFuture initializeIdentityRecords() { - final SettableFuture future = new SettableFuture<>(); - - new AsyncTask>() { - @Override - protected @NonNull Pair doInBackground(Recipient... params) { - IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this); - IdentityRecordList identityRecordList = new IdentityRecordList(); - List recipients = new LinkedList<>(); - - if (params[0].isGroupRecipient()) { - recipients.addAll(DatabaseFactory.getGroupDatabase(ConversationActivity.this) - .getGroupMembers(params[0].getAddress().toGroupString(), false)); - } else { - recipients.add(params[0]); - } - - for (Recipient recipient : recipients) { - Log.i(TAG, "Loading identity for: " + recipient.getAddress()); - identityRecordList.add(identityDatabase.getIdentity(recipient.getAddress())); - } - - String message = null; - - if (identityRecordList.isUnverified()) { - message = IdentityUtil.getUnverifiedBannerDescription(ConversationActivity.this, identityRecordList.getUnverifiedRecipients(ConversationActivity.this)); - } - - return new Pair<>(identityRecordList, message); - } - - @Override - protected void onPostExecute(@NonNull Pair result) { - Log.i(TAG, "Got identity records: " + result.first.isUnverified()); - identityRecords.replaceWith(result.first); - - //TODO Remove it. -// if (result.second != null) { -// Log.d(TAG, "Replacing banner..."); -// unverifiedBannerView.get().display(result.second, result.first.getUnverifiedRecords(), -// new UnverifiedClickedListener(), -// new UnverifiedDismissedListener()); -// } else if (unverifiedBannerView.resolved()) { -// Log.d(TAG, "Clearing banner..."); -// unverifiedBannerView.get().hide(); -// } - -// titleView.setVerified(isSecureText && identityRecords.isVerified()); - - future.set(true); - } - - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient); - - return future; - } - private void initializeViews() { profilePictureView = findViewById(R.id.profilePictureView); titleTextView = findViewById(R.id.titleTextView); @@ -1498,7 +1378,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity unblockButton = ViewUtil.findById(this, R.id.unblock_button); makeDefaultSmsButton = ViewUtil.findById(this, R.id.make_default_sms_button); container = ViewUtil.findById(this, R.id.layout_container); - unverifiedBannerView = ViewUtil.findStubById(this, R.id.unverified_banner_stub); groupShareProfileView = ViewUtil.findStubById(this, R.id.group_share_profile_view_stub); quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle); inlineAttachmentToggle = ViewUtil.findById(this, R.id.inline_attachment_container); @@ -1700,11 +1579,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity }); } - @Subscribe(threadMode = ThreadMode.MAIN) - public void onIdentityRecordUpdate(final IdentityRecord event) { - initializeIdentityRecords(); - } - @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onStickerPackInstalled(final StickerPackInstallEvent event) { if (!TextSecurePreferences.hasSeenStickerIntroTooltip(this)) return; @@ -1731,7 +1605,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity @Override public void onReceive(Context context, Intent intent) { initializeSecurity(true, isDefaultSms); - calculateCharactersRemaining(); } }; @@ -1931,25 +1804,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } - private void calculateCharactersRemaining() { - /* - String messageBody = composeText.getTextTrimmed(); - TransportOption transportOption = sendButton.getSelectedTransport(); - CharacterState characterState = transportOption.calculateCharacters(messageBody); - - if (characterState.charactersRemaining <= 15 || characterState.messagesSpent > 1) { - charactersLeft.setText(String.format(dynamicLanguage.getCurrentLocale(), - "%d/%d (%d)", - characterState.charactersRemaining, - characterState.maxTotalMessageSize, - characterState.messagesSpent)); - charactersLeft.setVisibility(View.VISIBLE); - } else { - charactersLeft.setVisibility(View.GONE); - } - */ - } - private void initializeMediaKeyboardProviders(@NonNull MediaKeyboard mediaKeyboard, boolean stickersAvailable) { boolean isSystemEmojiPreferred = TextSecurePreferences.isSystemEmojiPreferred(this); @@ -2127,9 +1981,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages needsSplit; - if (identityRecords.isUnverified()) { - handleUnverifiedRecipients(); - } else if (isMediaMessage) { + if (isMediaMessage) { sendMediaMessage(expiresIn, subscriptionId, initiating); } else { sendTextMessage(expiresIn, subscriptionId, initiating); @@ -2552,7 +2404,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity @Override public void afterTextChanged(Editable s) { - calculateCharactersRemaining(); if (composeText.getTextTrimmed().length() == 0 || beforeLength == 0) { composeText.postDelayed(ConversationActivity.this::updateToggleButtonState, 50); @@ -2719,33 +2570,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity updateLinkPreviewState(); } - private class UnverifiedDismissedListener implements UnverifiedBannerView.DismissListener { - @Override - public void onDismissed(final List unverifiedIdentities) { - final IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this); - - new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - synchronized (SESSION_LOCK) { - for (IdentityRecord identityRecord : unverifiedIdentities) { - identityDatabase.setVerified(identityRecord.getAddress(), - identityRecord.getIdentityKey(), - VerifiedStatus.DEFAULT); - } - } - - return null; - } - - @Override - protected void onPostExecute(Void result) { - initializeIdentityRecords(); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - } - private class QuoteRestorationTask extends AsyncTask { private final String serialized; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index d17d8528df..a882c25341 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.conversation; import android.content.Context; -import android.content.Intent; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -16,11 +15,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.thoughtcrime.securesms.BindableConversationItem; -import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable; -import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; import org.thoughtcrime.securesms.database.model.MessageRecord; -import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; @@ -28,14 +23,11 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.ExpirationUtil; import org.thoughtcrime.securesms.util.GroupUtil; -import org.thoughtcrime.securesms.util.IdentityUtil; import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.session.libsignal.libsignal.util.guava.Optional; import java.util.Locale; import java.util.Set; -import java.util.concurrent.ExecutionException; import network.loki.messenger.R; diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java index d9c1251053..031e665a56 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/SignalProtocolStoreImpl.java @@ -21,63 +21,68 @@ public class SignalProtocolStoreImpl implements SignalProtocolStore { // private final PreKeyStore preKeyStore; // private final SignedPreKeyStore signedPreKeyStore; - private final IdentityKeyStore identityKeyStore; +// private final IdentityKeyStore identityKeyStore; private final SessionStore sessionStore; public SignalProtocolStoreImpl(Context context) { // this.preKeyStore = new TextSecurePreKeyStore(context); // this.signedPreKeyStore = new TextSecurePreKeyStore(context); - this.identityKeyStore = new TextSecureIdentityKeyStore(context); +// this.identityKeyStore = new TextSecureIdentityKeyStore(context); this.sessionStore = new TextSecureSessionStore(context); } @Override public IdentityKeyPair getIdentityKeyPair() { - return identityKeyStore.getIdentityKeyPair(); +// return identityKeyStore.getIdentityKeyPair(); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public int getLocalRegistrationId() { - return identityKeyStore.getLocalRegistrationId(); +// return identityKeyStore.getLocalRegistrationId(); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) { - return identityKeyStore.saveIdentity(address, identityKey); +// return identityKeyStore.saveIdentity(address, identityKey); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) { - return identityKeyStore.isTrustedIdentity(address, identityKey, direction); +// return identityKeyStore.isTrustedIdentity(address, identityKey, direction); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public IdentityKey getIdentity(SignalProtocolAddress address) { - return identityKeyStore.getIdentity(address); +// return identityKeyStore.getIdentity(address); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public PreKeyRecord loadPreKey(int preKeyId) throws InvalidKeyIdException { - throw new UnsupportedOperationException("This method will be removed with refactor."); // return preKeyStore.loadPreKey(preKeyId); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public void storePreKey(int preKeyId, PreKeyRecord record) { - throw new UnsupportedOperationException("This method will be removed with refactor."); // preKeyStore.storePreKey(preKeyId, record); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public boolean containsPreKey(int preKeyId) { - throw new UnsupportedOperationException("This method will be removed with refactor."); // return preKeyStore.containsPreKey(preKeyId); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override public void removePreKey(int preKeyId) { - throw new UnsupportedOperationException("This method will be removed with refactor."); // preKeyStore.removePreKey(preKeyId); + throw new UnsupportedOperationException("This method will be removed with refactor."); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java deleted file mode 100644 index 2b391898c0..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureIdentityKeyStore.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.thoughtcrime.securesms.crypto.storage; - -import android.content.Context; -import org.thoughtcrime.securesms.logging.Log; - -import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; -import org.thoughtcrime.securesms.crypto.SessionUtil; -import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; -import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.util.IdentityUtil; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.session.libsignal.libsignal.IdentityKey; -import org.session.libsignal.libsignal.IdentityKeyPair; -import org.session.libsignal.libsignal.SignalProtocolAddress; -import org.session.libsignal.libsignal.state.IdentityKeyStore; -import org.session.libsignal.libsignal.util.guava.Optional; - -import java.util.concurrent.TimeUnit; - -public class TextSecureIdentityKeyStore implements IdentityKeyStore { - - private static final int TIMESTAMP_THRESHOLD_SECONDS = 5; - - private static final String TAG = TextSecureIdentityKeyStore.class.getSimpleName(); - private static final Object LOCK = new Object(); - - private final Context context; - - public TextSecureIdentityKeyStore(Context context) { - this.context = context; - } - - @Override - public IdentityKeyPair getIdentityKeyPair() { - return IdentityKeyUtil.getIdentityKeyPair(context); - } - - @Override - public int getLocalRegistrationId() { - return TextSecurePreferences.getLocalRegistrationId(context); - } - - public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) { - synchronized (LOCK) { - IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context); - Address signalAddress = Address.fromSerialized(address.getName()); - Optional identityRecord = identityDatabase.getIdentity(signalAddress); - - if (!identityRecord.isPresent()) { - Log.i(TAG, "Saving new identity..."); - identityDatabase.saveIdentity(signalAddress, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval); - return false; - } - - if (!identityRecord.get().getIdentityKey().equals(identityKey)) { - Log.i(TAG, "Replacing existing identity..."); - VerifiedStatus verifiedStatus; - - if (identityRecord.get().getVerifiedStatus() == VerifiedStatus.VERIFIED || - identityRecord.get().getVerifiedStatus() == VerifiedStatus.UNVERIFIED) - { - verifiedStatus = VerifiedStatus.UNVERIFIED; - } else { - verifiedStatus = VerifiedStatus.DEFAULT; - } - - identityDatabase.saveIdentity(signalAddress, identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval); - IdentityUtil.markIdentityUpdate(context, Recipient.from(context, signalAddress, true)); - SessionUtil.archiveSiblingSessions(context, address); - return true; - } - - if (isNonBlockingApprovalRequired(identityRecord.get())) { - Log.i(TAG, "Setting approval status..."); - identityDatabase.setApproval(signalAddress, nonBlockingApproval); - return false; - } - - return false; - } - } - - @Override - public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey) { - return saveIdentity(address, identityKey, false); - } - - @Override - public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) { - synchronized (LOCK) { - IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context); - String ourNumber = TextSecurePreferences.getLocalNumber(context); - Address theirAddress = Address.fromSerialized(address.getName()); - - if (ourNumber.equals(address.getName()) || Address.fromSerialized(ourNumber).equals(theirAddress)) { - return identityKey.equals(IdentityKeyUtil.getIdentityKey(context)); - } - - switch (direction) { - case SENDING: return isTrustedForSending(identityKey, identityDatabase.getIdentity(theirAddress)); - case RECEIVING: return true; - default: throw new AssertionError("Unknown direction: " + direction); - } - } - } - - @Override - public IdentityKey getIdentity(SignalProtocolAddress address) { - Optional record = DatabaseFactory.getIdentityDatabase(context).getIdentity(Address.fromSerialized(address.getName())); - - if (record.isPresent()) { - return record.get().getIdentityKey(); - } else { - return null; - } - } - - private boolean isTrustedForSending(IdentityKey identityKey, Optional identityRecord) { - if (!identityRecord.isPresent()) { - Log.w(TAG, "Nothing here, returning true..."); - return true; - } - - if (!identityKey.equals(identityRecord.get().getIdentityKey())) { - Log.w(TAG, "Identity keys don't match..."); - return false; - } - - if (identityRecord.get().getVerifiedStatus() == VerifiedStatus.UNVERIFIED) { - Log.w(TAG, "Needs unverified approval!"); - return false; - } - - if (isNonBlockingApprovalRequired(identityRecord.get())) { - Log.w(TAG, "Needs non-blocking approval!"); - return false; - } - - return true; - } - - private boolean isNonBlockingApprovalRequired(IdentityRecord identityRecord) { - return !identityRecord.isFirstUse() && - System.currentTimeMillis() - identityRecord.getTimestamp() < TimeUnit.SECONDS.toMillis(TIMESTAMP_THRESHOLD_SECONDS) && - !identityRecord.isApprovedNonBlocking(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java index a90b8e286d..f02e1d9c05 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -51,7 +51,6 @@ public class DatabaseFactory { private final MediaDatabase media; private final ThreadDatabase thread; private final MmsSmsDatabase mmsSmsDatabase; - private final IdentityDatabase identityDatabase; private final DraftDatabase draftDatabase; private final PushDatabase pushDatabase; private final GroupDatabase groupDatabase; @@ -107,10 +106,6 @@ public class DatabaseFactory { return getInstance(context).media; } - public static IdentityDatabase getIdentityDatabase(Context context) { - return getInstance(context).identityDatabase; - } - public static DraftDatabase getDraftDatabase(Context context) { return getInstance(context).draftDatabase; } @@ -211,7 +206,6 @@ public class DatabaseFactory { this.media = new MediaDatabase(context, databaseHelper); this.thread = new ThreadDatabase(context, databaseHelper); this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper); - this.identityDatabase = new IdentityDatabase(context, databaseHelper); this.draftDatabase = new DraftDatabase(context, databaseHelper); this.pushDatabase = new PushDatabase(context, databaseHelper); this.groupDatabase = new GroupDatabase(context, databaseHelper); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/IdentityDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/IdentityDatabase.java deleted file mode 100644 index 8f33a11464..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/IdentityDatabase.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2011 Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.thoughtcrime.securesms.database; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import net.sqlcipher.database.SQLiteDatabase; - -import org.greenrobot.eventbus.EventBus; -import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; -import org.thoughtcrime.securesms.util.Base64; -import org.session.libsignal.libsignal.IdentityKey; -import org.session.libsignal.libsignal.InvalidKeyException; -import org.session.libsignal.libsignal.util.guava.Optional; - -import java.io.IOException; - -public class IdentityDatabase extends Database { - - @SuppressWarnings("unused") - private static final String TAG = IdentityDatabase.class.getSimpleName(); - - private static final String TABLE_NAME = "identities"; - private static final String ID = "_id"; - private static final String ADDRESS = "address"; - private static final String IDENTITY_KEY = "key"; - private static final String TIMESTAMP = "timestamp"; - private static final String FIRST_USE = "first_use"; - private static final String NONBLOCKING_APPROVAL = "nonblocking_approval"; - private static final String VERIFIED = "verified"; - - public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + - " (" + ID + " INTEGER PRIMARY KEY, " + - ADDRESS + " TEXT UNIQUE, " + - IDENTITY_KEY + " TEXT, " + - FIRST_USE + " INTEGER DEFAULT 0, " + - TIMESTAMP + " INTEGER DEFAULT 0, " + - VERIFIED + " INTEGER DEFAULT 0, " + - NONBLOCKING_APPROVAL + " INTEGER DEFAULT 0);"; - - public enum VerifiedStatus { - DEFAULT, VERIFIED, UNVERIFIED; - - public int toInt() { - if (this == DEFAULT) return 0; - else if (this == VERIFIED) return 1; - else if (this == UNVERIFIED) return 2; - else throw new AssertionError(); - } - - public static VerifiedStatus forState(int state) { - if (state == 0) return DEFAULT; - else if (state == 1) return VERIFIED; - else if (state == 2) return UNVERIFIED; - else throw new AssertionError("No such state: " + state); - } - } - - IdentityDatabase(Context context, SQLCipherOpenHelper databaseHelper) { - super(context, databaseHelper); - } - - public Cursor getIdentities() { - SQLiteDatabase database = databaseHelper.getReadableDatabase(); - return database.query(TABLE_NAME, null, null, null, null, null, null); - } - - public @Nullable IdentityReader readerFor(@Nullable Cursor cursor) { - if (cursor == null) return null; - return new IdentityReader(cursor); - } - - public Optional getIdentity(Address address) { - SQLiteDatabase database = databaseHelper.getReadableDatabase(); - Cursor cursor = null; - - try { - cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?", - new String[] {address.serialize()}, null, null, null); - - if (cursor != null && cursor.moveToFirst()) { - return Optional.of(getIdentityRecord(cursor)); - } - } catch (InvalidKeyException | IOException e) { - throw new AssertionError(e); - } finally { - if (cursor != null) cursor.close(); - } - - return Optional.absent(); - } - - public void saveIdentity(Address address, IdentityKey identityKey, VerifiedStatus verifiedStatus, - boolean firstUse, long timestamp, boolean nonBlockingApproval) - { - SQLiteDatabase database = databaseHelper.getWritableDatabase(); - String identityKeyString = Base64.encodeBytes(identityKey.serialize()); - - ContentValues contentValues = new ContentValues(); - contentValues.put(ADDRESS, address.serialize()); - contentValues.put(IDENTITY_KEY, identityKeyString); - contentValues.put(TIMESTAMP, timestamp); - contentValues.put(VERIFIED, verifiedStatus.toInt()); - contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval ? 1 : 0); - contentValues.put(FIRST_USE, firstUse ? 1 : 0); - - database.replace(TABLE_NAME, null, contentValues); - - EventBus.getDefault().post(new IdentityRecord(address, identityKey, verifiedStatus, - firstUse, timestamp, nonBlockingApproval)); - } - - public void setApproval(Address address, boolean nonBlockingApproval) { - SQLiteDatabase database = databaseHelper.getWritableDatabase(); - - ContentValues contentValues = new ContentValues(2); - contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval); - - database.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[] {address.serialize()}); - } - - public void setVerified(Address address, IdentityKey identityKey, VerifiedStatus verifiedStatus) { - SQLiteDatabase database = databaseHelper.getWritableDatabase(); - - ContentValues contentValues = new ContentValues(1); - contentValues.put(VERIFIED, verifiedStatus.toInt()); - - int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ? AND " + IDENTITY_KEY + " = ?", - new String[] {address.serialize(), Base64.encodeBytes(identityKey.serialize())}); - - if (updated > 0) { - Optional record = getIdentity(address); - if (record.isPresent()) EventBus.getDefault().post(record.get()); - } - } - - private IdentityRecord getIdentityRecord(@NonNull Cursor cursor) throws IOException, InvalidKeyException { - String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)); - String serializedIdentity = cursor.getString(cursor.getColumnIndexOrThrow(IDENTITY_KEY)); - long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)); - int verifiedStatus = cursor.getInt(cursor.getColumnIndexOrThrow(VERIFIED)); - boolean nonblockingApproval = cursor.getInt(cursor.getColumnIndexOrThrow(NONBLOCKING_APPROVAL)) == 1; - boolean firstUse = cursor.getInt(cursor.getColumnIndexOrThrow(FIRST_USE)) == 1; - IdentityKey identity = new IdentityKey(Base64.decode(serializedIdentity), 0); - - return new IdentityRecord(Address.fromSerialized(address), identity, VerifiedStatus.forState(verifiedStatus), firstUse, timestamp, nonblockingApproval); - } - - public static class IdentityRecord { - - private final Address address; - private final IdentityKey identitykey; - private final VerifiedStatus verifiedStatus; - private final boolean firstUse; - private final long timestamp; - private final boolean nonblockingApproval; - - private IdentityRecord(Address address, - IdentityKey identitykey, VerifiedStatus verifiedStatus, - boolean firstUse, long timestamp, boolean nonblockingApproval) - { - this.address = address; - this.identitykey = identitykey; - this.verifiedStatus = verifiedStatus; - this.firstUse = firstUse; - this.timestamp = timestamp; - this.nonblockingApproval = nonblockingApproval; - } - - public Address getAddress() { - return address; - } - - public IdentityKey getIdentityKey() { - return identitykey; - } - - public long getTimestamp() { - return timestamp; - } - - public VerifiedStatus getVerifiedStatus() { - return verifiedStatus; - } - - public boolean isApprovedNonBlocking() { - return nonblockingApproval; - } - - public boolean isFirstUse() { - return firstUse; - } - - @Override - public @NonNull String toString() { - return "{address: " + address + ", identityKey: " + identitykey + ", verifiedStatus: " + verifiedStatus + ", firstUse: " + firstUse + "}"; - } - - } - - public class IdentityReader { - private final Cursor cursor; - - IdentityReader(@NonNull Cursor cursor) { - this.cursor = cursor; - } - - public @Nullable IdentityRecord getNext() { - if (cursor.moveToNext()) { - try { - return getIdentityRecord(cursor); - } catch (IOException | InvalidKeyException e) { - throw new AssertionError(e); - } - } - - return null; - } - - public void close() { - cursor.close(); - } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java index 4b6182fd80..1ad2418169 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/ClassicOpenHelper.java @@ -23,7 +23,6 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.DraftDatabase; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupReceiptDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.PushDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase; @@ -120,7 +119,6 @@ public class ClassicOpenHelper extends SQLiteOpenHelper { db.execSQL(MmsDatabase.CREATE_TABLE); db.execSQL(AttachmentDatabase.CREATE_TABLE); db.execSQL(ThreadDatabase.CREATE_TABLE); - db.execSQL(IdentityDatabase.CREATE_TABLE); db.execSQL(DraftDatabase.CREATE_TABLE); db.execSQL(PushDatabase.CREATE_TABLE); db.execSQL(GroupDatabase.CREATE_TABLE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index bf8a31b0b4..19facfe0e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -22,7 +22,6 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.DraftDatabase; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupReceiptDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.database.JobDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.OneTimePreKeyDatabase; @@ -91,9 +90,12 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int lokiV16 = 37; private static final int lokiV17 = 38; private static final int lokiV18_CLEAR_BG_POLL_JOBS = 39; - private static final int lokiV19_OLD_CODE_CLEANUP = 40; //TODO Change back to 40 when the refactoring is over. + //TODO Merge all "refactor" migrations to one before pushing to the main repo. + private static final int lokiV19_REFACTOR0 = 40; + private static final int lokiV19_REFACTOR1 = 41; - private static final int DATABASE_VERSION = lokiV19_OLD_CODE_CLEANUP; // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes + // Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes + private static final int DATABASE_VERSION = lokiV19_REFACTOR1; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -124,7 +126,6 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL(MmsDatabase.CREATE_TABLE); db.execSQL(AttachmentDatabase.CREATE_TABLE); db.execSQL(ThreadDatabase.CREATE_TABLE); - db.execSQL(IdentityDatabase.CREATE_TABLE); db.execSQL(DraftDatabase.CREATE_TABLE); db.execSQL(PushDatabase.CREATE_TABLE); db.execSQL(GroupDatabase.CREATE_TABLE); @@ -637,16 +638,14 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { db.execSQL("DELETE FROM constraint_spec WHERE factory_key = 'BackgroundPollJob'"); } - if (oldVersion < lokiV19_OLD_CODE_CLEANUP) { - // Many classes were removed. We need to update D structure and data to match the code changes. - - String[] deletedJobKeys = { - "ServiceOutageDetectionJob", - }; - for (String jobKey : deletedJobKeys) { - db.execSQL("DELETE FROM job_spec WHERE factory_key = ?", new String[]{jobKey}); - db.execSQL("DELETE FROM constraint_spec WHERE factory_key = ?", new String[]{jobKey}); - } + // Many classes were removed. We need to update DB structure and data to match the code changes. + //TODO Merge "refactor" changes in one migration. + if (oldVersion < lokiV19_REFACTOR0) { + deleteJobRecords(db, "ServiceOutageDetectionJob"); + } + if (oldVersion < lokiV19_REFACTOR1) { + db.execSQL("DROP TABLE identities"); + deleteJobRecords(db, "RetrieveProfileJob"); } db.setTransactionSuccessful(); @@ -691,4 +690,15 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { return false; } + + /** + * Cleans up all the records related to the job keys specified. + * This method should be called once the Signal job class is deleted from the project. + */ + private static void deleteJobRecords(SQLiteDatabase db, String... jobKeys) { + for (String jobKey : jobKeys) { + db.execSQL("DELETE FROM job_spec WHERE factory_key = ?", new String[]{jobKey}); + db.execSQL("DELETE FROM constraint_spec WHERE factory_key = ?", new String[]{jobKey}); + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java b/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java deleted file mode 100644 index a0e38502c1..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.thoughtcrime.securesms.database.identity; - - -import android.content.Context; - -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; -import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.session.libsignal.libsignal.util.guava.Optional; - -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class IdentityRecordList { - - private static final String TAG = IdentityRecordList.class.getSimpleName(); - - private final List identityRecords = new LinkedList<>(); - - public void add(Optional identityRecord) { - if (identityRecord.isPresent()) { - identityRecords.add(identityRecord.get()); - } - } - - public void replaceWith(IdentityRecordList identityRecordList) { - identityRecords.clear(); - identityRecords.addAll(identityRecordList.identityRecords); - } - - public boolean isVerified() { - for (IdentityRecord identityRecord : identityRecords) { - if (identityRecord.getVerifiedStatus() != VerifiedStatus.VERIFIED) { - return false; - } - } - - return identityRecords.size() > 0; - } - - public boolean isUnverified() { - for (IdentityRecord identityRecord : identityRecords) { - if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) { - return true; - } - } - - return false; - } - - public boolean isUntrusted() { - for (IdentityRecord identityRecord : identityRecords) { - if (isUntrusted(identityRecord)) { - return true; - } - } - - return false; - } - - public List getUntrustedRecords() { - List results = new LinkedList<>(); - - for (IdentityRecord identityRecord : identityRecords) { - if (isUntrusted(identityRecord)) { - results.add(identityRecord); - } - } - - return results; - } - - public List getUntrustedRecipients(Context context) { - List untrusted = new LinkedList<>(); - - for (IdentityRecord identityRecord : identityRecords) { - if (isUntrusted(identityRecord)) { - untrusted.add(Recipient.from(context, identityRecord.getAddress(), false)); - } - } - - return untrusted; - } - - public List getUnverifiedRecords() { - List results = new LinkedList<>(); - - for (IdentityRecord identityRecord : identityRecords) { - if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) { - results.add(identityRecord); - } - } - - return results; - } - - public List getUnverifiedRecipients(Context context) { - List unverified = new LinkedList<>(); - - for (IdentityRecord identityRecord : identityRecords) { - if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) { - unverified.add(Recipient.from(context, identityRecord.getAddress(), false)); - } - } - - return unverified; - } - - private boolean isUntrusted(IdentityRecord identityRecord) { - return !identityRecord.isApprovedNonBlocking() && - System.currentTimeMillis() - identityRecord.getTimestamp() < TimeUnit.SECONDS.toMillis(5); - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java index bc20a89a76..127b0f390a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.jobs.RefreshAttributesJob; import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob; import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob; import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob; -import org.thoughtcrime.securesms.jobs.RetrieveProfileJob; import org.thoughtcrime.securesms.jobs.RotateCertificateJob; import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob; import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob; @@ -60,7 +59,6 @@ import network.loki.messenger.BuildConfig; RequestGroupInfoJob.class, PushGroupUpdateJob.class, AvatarDownloadJob.class, - RetrieveProfileJob.class, RetrieveProfileAvatarJob.class, SendReadReceiptJob.class, AppProtectionPreferenceFragment.class, diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migration/WorkManagerFactoryMappings.java b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migration/WorkManagerFactoryMappings.java index 8d1a780c65..6594b4210b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migration/WorkManagerFactoryMappings.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobmanager/migration/WorkManagerFactoryMappings.java @@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.jobs.RefreshAttributesJob; import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob; import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob; import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob; -import org.thoughtcrime.securesms.jobs.RetrieveProfileJob; import org.thoughtcrime.securesms.jobs.RotateCertificateJob; import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob; import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob; @@ -64,7 +63,6 @@ public class WorkManagerFactoryMappings { put(RefreshUnidentifiedDeliveryAbilityJob.class.getName(), RefreshUnidentifiedDeliveryAbilityJob.KEY); put(RequestGroupInfoJob.class.getName(), RequestGroupInfoJob.KEY); put(RetrieveProfileAvatarJob.class.getName(), RetrieveProfileAvatarJob.KEY); - put(RetrieveProfileJob.class.getName(), RetrieveProfileJob.KEY); put(RotateCertificateJob.class.getName(), RotateCertificateJob.KEY); put(RotateProfileKeyJob.class.getName(), RotateProfileKeyJob.KEY); put(SendDeliveryReceiptJob.class.getName(), SendDeliveryReceiptJob.KEY); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index 93c2ae5be5..ae90710cb1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -48,7 +48,6 @@ public final class JobManagerFactories { put(RefreshUnidentifiedDeliveryAbilityJob.KEY, new RefreshUnidentifiedDeliveryAbilityJob.Factory()); put(RequestGroupInfoJob.KEY, new RequestGroupInfoJob.Factory()); put(RetrieveProfileAvatarJob.KEY, new RetrieveProfileAvatarJob.Factory(application)); - put(RetrieveProfileJob.KEY, new RetrieveProfileJob.Factory(application)); put(RotateCertificateJob.KEY, new RotateCertificateJob.Factory()); put(RotateProfileKeyJob.KEY, new RotateProfileKeyJob.Factory()); put(SendDeliveryReceiptJob.KEY, new SendDeliveryReceiptJob.Factory()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 8ea8535205..486b05df87 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -5,7 +5,6 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.text.TextUtils; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -92,7 +91,6 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.stickers.StickerLocator; import org.thoughtcrime.securesms.util.GroupUtil; 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.session.libsignal.libsignal.InvalidMessageException; @@ -107,10 +105,7 @@ import org.session.libsignal.service.api.messages.SignalServiceEnvelope; import org.session.libsignal.service.api.messages.SignalServiceGroup; import org.session.libsignal.service.api.messages.SignalServiceReceiptMessage; import org.session.libsignal.service.api.messages.SignalServiceTypingMessage; -import org.session.libsignal.service.api.messages.multidevice.ReadMessage; -import org.session.libsignal.service.api.messages.multidevice.RequestMessage; import org.session.libsignal.service.api.messages.multidevice.SentTranscriptMessage; -import org.session.libsignal.service.api.messages.multidevice.SignalServiceSyncMessage; import org.session.libsignal.service.api.messages.multidevice.StickerPackOperationMessage; import org.session.libsignal.service.api.messages.multidevice.VerifiedMessage; import org.session.libsignal.service.api.messages.shared.SharedContact; @@ -479,10 +474,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } } - private void handleSynchronizeVerifiedMessage(@NonNull VerifiedMessage verifiedMessage) { - IdentityUtil.processVerifiedMessage(context, verifiedMessage); - } - private void handleSynchronizeStickerPackOperation(@NonNull List stickerPackOperations) { JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java deleted file mode 100644 index 3ab2c79750..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileJob.java +++ /dev/null @@ -1,255 +0,0 @@ -package org.thoughtcrime.securesms.jobs; - - -import android.app.Application; -import androidx.annotation.NonNull; -import android.text.TextUtils; - -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.database.RecipientDatabase; -import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode; -import org.thoughtcrime.securesms.dependencies.InjectableType; -import org.thoughtcrime.securesms.jobmanager.Data; -import org.thoughtcrime.securesms.jobmanager.Job; -import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint; -import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.service.IncomingMessageObserver; -import org.thoughtcrime.securesms.util.Base64; -import org.thoughtcrime.securesms.util.IdentityUtil; -import org.thoughtcrime.securesms.util.Util; -import org.session.libsignal.libsignal.IdentityKey; -import org.session.libsignal.libsignal.InvalidKeyException; -import org.session.libsignal.libsignal.util.guava.Optional; -import org.session.libsignal.service.api.SignalServiceMessagePipe; -import org.session.libsignal.service.api.SignalServiceMessageReceiver; -import org.session.libsignal.service.api.crypto.InvalidCiphertextException; -import org.session.libsignal.service.api.crypto.ProfileCipher; -import org.session.libsignal.service.api.crypto.UnidentifiedAccess; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; -import org.session.libsignal.service.api.profiles.SignalServiceProfile; -import org.session.libsignal.service.api.push.SignalServiceAddress; -import org.session.libsignal.service.api.push.exceptions.NonSuccessfulResponseCodeException; -import org.session.libsignal.service.api.util.InvalidNumberException; - -import java.io.IOException; -import java.util.List; - -import javax.inject.Inject; - -public class RetrieveProfileJob extends BaseJob implements InjectableType { - - public static final String KEY = "RetrieveProfileJob"; - - private static final String TAG = RetrieveProfileJob.class.getSimpleName(); - - private static final String KEY_ADDRESS = "address"; - - @Inject SignalServiceMessageReceiver receiver; - - private Recipient recipient; - - public RetrieveProfileJob(@NonNull Recipient recipient) { - this(new Job.Parameters.Builder() - .addConstraint(NetworkConstraint.KEY) - .setMaxAttempts(3) - .build(), - recipient); - } - - private RetrieveProfileJob(@NonNull Job.Parameters parameters, @NonNull Recipient recipient) { - super(parameters); - this.recipient = recipient; - } - - @Override - public @NonNull Data serialize() { - return new Data.Builder().putString(KEY_ADDRESS, recipient.getAddress().serialize()).build(); - } - - @Override - public @NonNull String getFactoryKey() { - return KEY; - } - - @Override - public void onRun() throws IOException, InvalidKeyException { - // Loki - Do nothing - /* - try { - if (recipient.isGroupRecipient()) handleGroupRecipient(recipient); - else handleIndividualRecipient(recipient); - } catch (InvalidNumberException e) { - Log.w(TAG, e); - } - */ - } - - @Override - public boolean onShouldRetry(@NonNull Exception e) { - return false; - } - - @Override - public void onCanceled() {} - - private void handleIndividualRecipient(Recipient recipient) - throws IOException, InvalidKeyException, InvalidNumberException - { - String number = recipient.getAddress().toPhoneString(); - Optional unidentifiedAccess = getUnidentifiedAccess(recipient); - - SignalServiceProfile profile; - - try { - profile = retrieveProfile(number, unidentifiedAccess); - } catch (NonSuccessfulResponseCodeException e) { - if (unidentifiedAccess.isPresent()) { - profile = retrieveProfile(number, Optional.absent()); - } else { - throw e; - } - } - - setIdentityKey(recipient, profile.getIdentityKey()); - setProfileName(recipient, profile.getName()); - setProfileAvatar(recipient, profile.getAvatar()); - setUnidentifiedAccessMode(recipient, profile.getUnidentifiedAccess(), profile.isUnrestrictedUnidentifiedAccess()); - } - - private void handleGroupRecipient(Recipient group) - throws IOException, InvalidKeyException, InvalidNumberException - { - List recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(group.getAddress().toGroupString(), false); - - for (Recipient recipient : recipients) { - handleIndividualRecipient(recipient); - } - } - - private SignalServiceProfile retrieveProfile(@NonNull String number, Optional unidentifiedAccess) - throws IOException - { - SignalServiceMessagePipe authPipe = IncomingMessageObserver.getPipe(); - SignalServiceMessagePipe unidentifiedPipe = IncomingMessageObserver.getUnidentifiedPipe(); - SignalServiceMessagePipe pipe = unidentifiedPipe != null && unidentifiedAccess.isPresent() ? unidentifiedPipe - : authPipe; - - if (pipe != null) { - try { - return pipe.getProfile(new SignalServiceAddress(number), unidentifiedAccess); - } catch (IOException e) { - Log.w(TAG, e); - } - } - - return receiver.retrieveProfile(new SignalServiceAddress(number), unidentifiedAccess); - } - - private void setIdentityKey(Recipient recipient, String identityKeyValue) { - try { - if (TextUtils.isEmpty(identityKeyValue)) { - Log.w(TAG, "Identity key is missing on profile!"); - return; - } - - IdentityKey identityKey = new IdentityKey(Base64.decode(identityKeyValue), 0); - - if (!DatabaseFactory.getIdentityDatabase(context) - .getIdentity(recipient.getAddress()) - .isPresent()) - { - Log.w(TAG, "Still first use..."); - return; - } - - IdentityUtil.saveIdentity(context, recipient.getAddress().toPhoneString(), identityKey); - } catch (InvalidKeyException | IOException e) { - Log.w(TAG, e); - } - } - - private void setUnidentifiedAccessMode(Recipient recipient, String unidentifiedAccessVerifier, boolean unrestrictedUnidentifiedAccess) { - RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context); - byte[] profileKey = recipient.getProfileKey(); - - if (unrestrictedUnidentifiedAccess && unidentifiedAccessVerifier != null) { - Log.i(TAG, "Marking recipient UD status as unrestricted."); - recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED); - } else if (profileKey == null || unidentifiedAccessVerifier == null) { - Log.i(TAG, "Marking recipient UD status as disabled."); - recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED); - } else { - ProfileCipher profileCipher = new ProfileCipher(profileKey); - boolean verifiedUnidentifiedAccess; - - try { - verifiedUnidentifiedAccess = profileCipher.verifyUnidentifiedAccess(Base64.decode(unidentifiedAccessVerifier)); - } catch (IOException e) { - Log.w(TAG, e); - verifiedUnidentifiedAccess = false; - } - - UnidentifiedAccessMode mode = verifiedUnidentifiedAccess ? UnidentifiedAccessMode.ENABLED : UnidentifiedAccessMode.DISABLED; - Log.i(TAG, "Marking recipient UD status as " + mode.name() + " after verification."); - recipientDatabase.setUnidentifiedAccessMode(recipient, mode); - } - } - - private void setProfileName(Recipient recipient, String profileName) { - try { - byte[] profileKey = recipient.getProfileKey(); - if (profileKey == null) return; - - String plaintextProfileName = null; - - if (profileName != null) { - ProfileCipher profileCipher = new ProfileCipher(profileKey); - plaintextProfileName = new String(profileCipher.decryptName(Base64.decode(profileName))); - } - - if (!Util.equals(plaintextProfileName, recipient.getProfileName())) { - DatabaseFactory.getRecipientDatabase(context).setProfileName(recipient, plaintextProfileName); - } - } catch (InvalidCiphertextException | IOException e) { - Log.w(TAG, e); - } - } - - private void setProfileAvatar(Recipient recipient, String profileAvatar) { - if (recipient.getProfileKey() == null) return; - - if (!Util.equals(profileAvatar, recipient.getProfileAvatar())) { - ApplicationContext.getInstance(context) - .getJobManager() - .add(new RetrieveProfileAvatarJob(recipient, profileAvatar)); - } - } - - private Optional getUnidentifiedAccess(@NonNull Recipient recipient) { - Optional unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient); - - if (unidentifiedAccess.isPresent()) { - return unidentifiedAccess.get().getTargetUnidentifiedAccess(); - } - - return Optional.absent(); - } - - public static final class Factory implements Job.Factory { - - private final Application application; - - public Factory(Application application) { - this.application = application; - } - - @Override - public @NonNull RetrieveProfileJob create(@NonNull Parameters parameters, @NonNull Data data) { - return new RetrieveProfileJob(parameters, Recipient.from(application, Address.fromSerialized(data.getString(KEY_ADDRESS)), true)); - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt index 4a13c7618c..0d4acd6ec3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RecoveryPhraseRestoreActivity.kt @@ -17,7 +17,6 @@ import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.database.IdentityDatabase import org.thoughtcrime.securesms.loki.utilities.KeyPairUtilities import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities import org.thoughtcrime.securesms.loki.utilities.push @@ -72,9 +71,6 @@ class RecoveryPhraseRestoreActivity : BaseActionBarActivity() { val userHexEncodedPublicKey = x25519KeyPair.hexEncodedPublicKey val registrationID = KeyHelper.generateRegistrationId(false) TextSecurePreferences.setLocalRegistrationId(this, registrationID) - DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(userHexEncodedPublicKey), - IdentityKeyUtil.getIdentityKeyPair(this).publicKey, IdentityDatabase.VerifiedStatus.VERIFIED, - true, System.currentTimeMillis(), true) TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey) TextSecurePreferences.setRestorationTime(this, System.currentTimeMillis()) TextSecurePreferences.setHasViewedSeed(this, true) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt index 336efb58e3..2a7c761198 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/RegisterActivity.kt @@ -22,7 +22,6 @@ import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory -import org.thoughtcrime.securesms.database.IdentityDatabase import org.thoughtcrime.securesms.loki.utilities.KeyPairUtilities import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo @@ -109,9 +108,6 @@ class RegisterActivity : BaseActionBarActivity() { val userHexEncodedPublicKey = x25519KeyPair!!.hexEncodedPublicKey val registrationID = KeyHelper.generateRegistrationId(false) TextSecurePreferences.setLocalRegistrationId(this, registrationID) - DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(userHexEncodedPublicKey), - IdentityKeyUtil.getIdentityKeyPair(this).publicKey, IdentityDatabase.VerifiedStatus.VERIFIED, - true, System.currentTimeMillis(), true) TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey) TextSecurePreferences.setRestorationTime(this, 0) TextSecurePreferences.setHasViewedSeed(this, false) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java deleted file mode 100644 index 3cf58160ed..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/util/IdentityUtil.java +++ /dev/null @@ -1,252 +0,0 @@ -package org.thoughtcrime.securesms.util; - -import android.content.Context; -import android.os.AsyncTask; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; - -import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore; -import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore; -import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.database.GroupDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase; -import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; -import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult; -import org.thoughtcrime.securesms.database.SmsDatabase; -import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.sms.IncomingIdentityDefaultMessage; -import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage; -import org.thoughtcrime.securesms.sms.IncomingIdentityVerifiedMessage; -import org.thoughtcrime.securesms.sms.IncomingTextMessage; -import org.thoughtcrime.securesms.sms.OutgoingIdentityDefaultMessage; -import org.thoughtcrime.securesms.sms.OutgoingIdentityVerifiedMessage; -import org.thoughtcrime.securesms.sms.OutgoingTextMessage; -import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; -import org.thoughtcrime.securesms.util.concurrent.SettableFuture; -import org.session.libsignal.libsignal.IdentityKey; -import org.session.libsignal.libsignal.SignalProtocolAddress; -import org.session.libsignal.libsignal.state.IdentityKeyStore; -import org.session.libsignal.libsignal.state.SessionRecord; -import org.session.libsignal.libsignal.state.SessionStore; -import org.session.libsignal.libsignal.util.guava.Optional; -import org.session.libsignal.service.api.messages.SignalServiceGroup; -import org.session.libsignal.service.api.messages.multidevice.VerifiedMessage; - -import java.util.List; - -import network.loki.messenger.R; - -import static org.session.libsignal.libsignal.SessionCipher.SESSION_LOCK; - -public class IdentityUtil { - - private static final String TAG = IdentityUtil.class.getSimpleName(); - - public static ListenableFuture> getRemoteIdentityKey(final Context context, final Recipient recipient) { - final SettableFuture> future = new SettableFuture<>(); - - new AsyncTask>() { - @Override - protected Optional doInBackground(Recipient... recipient) { - return DatabaseFactory.getIdentityDatabase(context) - .getIdentity(recipient[0].getAddress()); - } - - @Override - protected void onPostExecute(Optional result) { - future.set(result); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient); - - return future; - } - - public static void markIdentityVerified(Context context, Recipient recipient, boolean verified, boolean remote) - { - long time = System.currentTimeMillis(); - SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); - GroupDatabase.Reader reader = groupDatabase.getGroups(); - - GroupDatabase.GroupRecord groupRecord; - - while ((groupRecord = reader.getNext()) != null) { - if (groupRecord.isRSSFeed() || groupRecord.isOpenGroup()) { continue; } - if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive() && !groupRecord.isMms()) { - SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId(), SignalServiceGroup.GroupType.SIGNAL); - - if (remote) { - IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0, false); - - if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming); - else incoming = new IncomingIdentityDefaultMessage(incoming); - - smsDatabase.insertMessageInbox(incoming); - } else { - Recipient groupRecipient = Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(group.getGroupId(), false)), true); - long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(groupRecipient); - OutgoingTextMessage outgoing ; - - if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient); - else outgoing = new OutgoingIdentityDefaultMessage(recipient); - - DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoing, false, time, null); - } - } - } - - if (remote) { - IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.absent(), 0, false); - - if (verified) incoming = new IncomingIdentityVerifiedMessage(incoming); - else incoming = new IncomingIdentityDefaultMessage(incoming); - - smsDatabase.insertMessageInbox(incoming); - } else { - OutgoingTextMessage outgoing; - - if (verified) outgoing = new OutgoingIdentityVerifiedMessage(recipient); - else outgoing = new OutgoingIdentityDefaultMessage(recipient); - - long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient); - - Log.i(TAG, "Inserting verified outbox..."); - DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoing, false, time, null); - } - } - - public static void markIdentityUpdate(Context context, Recipient recipient) { - long time = System.currentTimeMillis(); - SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); - GroupDatabase.Reader reader = groupDatabase.getGroups(); - - GroupDatabase.GroupRecord groupRecord; - - while ((groupRecord = reader.getNext()) != null) { - if (groupRecord.isRSSFeed() || groupRecord.isOpenGroup()) { continue; } - if (groupRecord.getMembers().contains(recipient.getAddress()) && groupRecord.isActive()) { - SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId(), SignalServiceGroup.GroupType.SIGNAL); - IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.of(group), 0, false); - IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming); - - smsDatabase.insertMessageInbox(groupUpdate); - } - } - - IncomingTextMessage incoming = new IncomingTextMessage(recipient.getAddress(), 1, time, null, Optional.absent(), 0, false); - IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming); - Optional insertResult = smsDatabase.insertMessageInbox(individualUpdate); - - if (insertResult.isPresent()) { - ApplicationContext.getInstance(context).messageNotifier.updateNotification(context, insertResult.get().getThreadId()); - } - } - - public static void saveIdentity(Context context, String number, IdentityKey identityKey) { - synchronized (SESSION_LOCK) { - IdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(context); - SessionStore sessionStore = new TextSecureSessionStore(context); - SignalProtocolAddress address = new SignalProtocolAddress(number, 1); - - if (identityKeyStore.saveIdentity(address, identityKey)) { - if (sessionStore.containsSession(address)) { - SessionRecord sessionRecord = sessionStore.loadSession(address); - sessionRecord.archiveCurrentState(); - - sessionStore.storeSession(address, sessionRecord); - } - } - } - } - - public static void processVerifiedMessage(Context context, VerifiedMessage verifiedMessage) { - synchronized (SESSION_LOCK) { - IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context); - Recipient recipient = Recipient.from(context, Address.fromExternal(context, verifiedMessage.getDestination()), true); - Optional identityRecord = identityDatabase.getIdentity(recipient.getAddress()); - - if (!identityRecord.isPresent() && verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT) { - Log.w(TAG, "No existing record for default status"); - return; - } - - if (verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.DEFAULT && - identityRecord.isPresent() && - identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey()) && - identityRecord.get().getVerifiedStatus() != IdentityDatabase.VerifiedStatus.DEFAULT) - { - identityDatabase.setVerified(recipient.getAddress(), identityRecord.get().getIdentityKey(), IdentityDatabase.VerifiedStatus.DEFAULT); - markIdentityVerified(context, recipient, false, true); - } - - if (verifiedMessage.getVerified() == VerifiedMessage.VerifiedState.VERIFIED && - (!identityRecord.isPresent() || - (identityRecord.isPresent() && !identityRecord.get().getIdentityKey().equals(verifiedMessage.getIdentityKey())) || - (identityRecord.isPresent() && identityRecord.get().getVerifiedStatus() != IdentityDatabase.VerifiedStatus.VERIFIED))) - { - saveIdentity(context, verifiedMessage.getDestination(), verifiedMessage.getIdentityKey()); - identityDatabase.setVerified(recipient.getAddress(), verifiedMessage.getIdentityKey(), IdentityDatabase.VerifiedStatus.VERIFIED); - markIdentityVerified(context, recipient, true, true); - } - } - } - - - public static @Nullable String getUnverifiedBannerDescription(@NonNull Context context, - @NonNull List unverified) - { - return getPluralizedIdentityDescription(context, unverified, - R.string.IdentityUtil_unverified_banner_one, - R.string.IdentityUtil_unverified_banner_two, - R.string.IdentityUtil_unverified_banner_many); - } - - public static @Nullable String getUnverifiedSendDialogDescription(@NonNull Context context, - @NonNull List unverified) - { - return getPluralizedIdentityDescription(context, unverified, - R.string.IdentityUtil_unverified_dialog_one, - R.string.IdentityUtil_unverified_dialog_two, - R.string.IdentityUtil_unverified_dialog_many); - } - - public static @Nullable String getUntrustedSendDialogDescription(@NonNull Context context, - @NonNull List untrusted) - { - return getPluralizedIdentityDescription(context, untrusted, - R.string.IdentityUtil_untrusted_dialog_one, - R.string.IdentityUtil_untrusted_dialog_two, - R.string.IdentityUtil_untrusted_dialog_many); - } - - private static @Nullable String getPluralizedIdentityDescription(@NonNull Context context, - @NonNull List recipients, - @StringRes int resourceOne, - @StringRes int resourceTwo, - @StringRes int resourceMany) - { - if (recipients.isEmpty()) return null; - - if (recipients.size() == 1) { - String name = recipients.get(0).toShortString(); - return context.getString(resourceOne, name); - } else { - String firstName = recipients.get(0).toShortString(); - String secondName = recipients.get(1).toShortString(); - - if (recipients.size() == 2) { - return context.getString(resourceTwo, firstName, secondName); - } else { - int othersCount = recipients.size() - 2; - String nMore = context.getResources().getQuantityString(R.plurals.identity_others, othersCount, othersCount); - - return context.getString(resourceMany, firstName, secondName, nMore); - } - } - } -} diff --git a/app/src/main/res/layout/conversation_activity.xml b/app/src/main/res/layout/conversation_activity.xml index f42cdfd391..a16d43c215 100644 --- a/app/src/main/res/layout/conversation_activity.xml +++ b/app/src/main/res/layout/conversation_activity.xml @@ -146,13 +146,6 @@ android:inflatedId="@+id/group_share_profile_view" android:layout="@layout/conversation_activity_group_share_profile_stub" /> - - - diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageReceiver.java b/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageReceiver.java index 7e23798e89..7277be5a09 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageReceiver.java +++ b/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageReceiver.java @@ -117,7 +117,7 @@ public class SignalServiceMessageReceiver { public InputStream retrieveProfileAvatar(String path, File destination, byte[] profileKey, int maxSizeBytes) throws IOException { - DownloadUtilities.INSTANCE.downloadFile(destination, path, maxSizeBytes, null); + DownloadUtilities.downloadFile(destination, path, maxSizeBytes, null); return new ProfileCipherInputStream(new FileInputStream(destination), profileKey); } @@ -138,7 +138,7 @@ public class SignalServiceMessageReceiver { { // Loki - Fetch attachment if (pointer.getUrl().isEmpty()) throw new InvalidMessageException("Missing attachment URL."); - DownloadUtilities.INSTANCE.downloadFile(destination, pointer.getUrl(), maxSizeBytes, listener); + DownloadUtilities.downloadFile(destination, pointer.getUrl(), maxSizeBytes, listener); // Loki - Assume we're retrieving an attachment for an open group server if the digest is not set if (!pointer.getDigest().isPresent()) { return new FileInputStream(destination); } diff --git a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/DownloadUtilities.kt b/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/DownloadUtilities.kt index fe7471f099..24088e1229 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/DownloadUtilities.kt +++ b/libsignal/src/main/java/org/session/libsignal/service/loki/utilities/DownloadUtilities.kt @@ -16,6 +16,7 @@ object DownloadUtilities { /** * Blocks the calling thread. */ + @JvmStatic fun downloadFile(destination: File, url: String, maxSize: Int, listener: SignalServiceAttachment.ProgressListener?) { val outputStream = FileOutputStream(destination) // Throws var remainingAttempts = 4 @@ -36,6 +37,7 @@ object DownloadUtilities { /** * Blocks the calling thread. */ + @JvmStatic fun downloadFile(outputStream: OutputStream, url: String, maxSize: Int, listener: SignalServiceAttachment.ProgressListener?) { // We need to throw a PushNetworkException or NonSuccessfulResponseCodeException // because the underlying Signal logic requires these to work correctly