Identity functionality and data structure are completely removed.

This commit is contained in:
Anton Chekulaev 2020-12-14 12:16:30 +11:00
parent 5046d1dce6
commit 2aa179585f
24 changed files with 45 additions and 1501 deletions

View File

@ -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<IdentityRecord> untrustedRecords;
private final ResendListener resendListener;
public UntrustedSendDialog(@NonNull Context context,
@NonNull String message,
@NonNull List<IdentityRecord> 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<Void, Void, Void>() {
@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();
}
}

View File

@ -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<IdentityRecord> 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<IdentityRecord> unverifiedIdentities);
}
public interface ClickListener {
public void onClicked(List<IdentityRecord> unverifiedIdentities);
}
}

View File

@ -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<IdentityRecord> untrustedRecords;
private final ResendListener resendListener;
public UnverifiedSendDialog(@NonNull Context context,
@NonNull String message,
@NonNull List<IdentityRecord> 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<Void, Void, Void>() {
@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();
}
}

View File

@ -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> unverifiedBannerView;
private Stub<GroupShareProfileView> 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<BroadcastReceiver> 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<Recipient> unverifiedRecipients = identityRecords.getUnverifiedRecipients(this);
List<IdentityRecord> 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<Boolean>() {
@Override
public void onSuccess(Boolean result) {
sendMessage();
}
@Override
public void onFailure(ExecutionException e) {
throw new AssertionError(e);
}
});
}).show();
}
private void handleUntrustedRecipients() {
List<Recipient> untrustedRecipients = identityRecords.getUntrustedRecipients(this);
List<IdentityRecord> 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<Boolean>() {
@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<Boolean> initializeIdentityRecords() {
final SettableFuture<Boolean> future = new SettableFuture<>();
new AsyncTask<Recipient, Void, Pair<IdentityRecordList, String>>() {
@Override
protected @NonNull Pair<IdentityRecordList, String> doInBackground(Recipient... params) {
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this);
IdentityRecordList identityRecordList = new IdentityRecordList();
List<Recipient> 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<IdentityRecordList, String> 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<IdentityRecord> unverifiedIdentities) {
final IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(ConversationActivity.this);
new AsyncTask<Void, Void, Void>() {
@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<Void, Void, MessageRecord> {
private final String serialized;

View File

@ -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;

View File

@ -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

View File

@ -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> 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<IdentityRecord> 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> 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();
}
}

View File

@ -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);

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<IdentityRecord> 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<IdentityRecord> 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();
}
}
}

View File

@ -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);

View File

@ -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});
}
}
}

View File

@ -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<IdentityRecord> identityRecords = new LinkedList<>();
public void add(Optional<IdentityRecord> 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<IdentityRecord> getUntrustedRecords() {
List<IdentityRecord> results = new LinkedList<>();
for (IdentityRecord identityRecord : identityRecords) {
if (isUntrusted(identityRecord)) {
results.add(identityRecord);
}
}
return results;
}
public List<Recipient> getUntrustedRecipients(Context context) {
List<Recipient> untrusted = new LinkedList<>();
for (IdentityRecord identityRecord : identityRecords) {
if (isUntrusted(identityRecord)) {
untrusted.add(Recipient.from(context, identityRecord.getAddress(), false));
}
}
return untrusted;
}
public List<IdentityRecord> getUnverifiedRecords() {
List<IdentityRecord> results = new LinkedList<>();
for (IdentityRecord identityRecord : identityRecords) {
if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) {
results.add(identityRecord);
}
}
return results;
}
public List<Recipient> getUnverifiedRecipients(Context context) {
List<Recipient> 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);
}
}

View File

@ -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,

View File

@ -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);

View File

@ -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());

View File

@ -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<StickerPackOperationMessage> stickerPackOperations) {
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();

View File

@ -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> 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<Recipient> recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(group.getAddress().toGroupString(), false);
for (Recipient recipient : recipients) {
handleIndividualRecipient(recipient);
}
}
private SignalServiceProfile retrieveProfile(@NonNull String number, Optional<UnidentifiedAccess> 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<UnidentifiedAccess> getUnidentifiedAccess(@NonNull Recipient recipient) {
Optional<UnidentifiedAccessPair> unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient);
if (unidentifiedAccess.isPresent()) {
return unidentifiedAccess.get().getTargetUnidentifiedAccess();
}
return Optional.absent();
}
public static final class Factory implements Job.Factory<RetrieveProfileJob> {
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));
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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<Optional<IdentityRecord>> getRemoteIdentityKey(final Context context, final Recipient recipient) {
final SettableFuture<Optional<IdentityRecord>> future = new SettableFuture<>();
new AsyncTask<Recipient, Void, Optional<IdentityRecord>>() {
@Override
protected Optional<IdentityRecord> doInBackground(Recipient... recipient) {
return DatabaseFactory.getIdentityDatabase(context)
.getIdentity(recipient[0].getAddress());
}
@Override
protected void onPostExecute(Optional<IdentityRecord> 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> 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> 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<Recipient> 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<Recipient> 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<Recipient> 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<Recipient> 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);
}
}
}
}

View File

@ -146,13 +146,6 @@
android:inflatedId="@+id/group_share_profile_view"
android:layout="@layout/conversation_activity_group_share_profile_stub" />
<ViewStub
android:id="@+id/unverified_banner_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/unverified_banner"
android:layout="@layout/conversation_activity_unverified_banner_stub" />
<FrameLayout
android:id="@+id/fragment_content"
android:layout_width="match_parent"

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.components.identity.UnverifiedBannerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/unverified_banner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@ -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); }

View File

@ -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