From 5942e93a33add6aef92fd8f8031602dd53b352c3 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Wed, 16 Aug 2017 21:49:41 -0700 Subject: [PATCH] Share profile key when initiating a conversation // FREEBIE --- .../securesms/ConversationActivity.java | 24 +++++++++++++------ .../securesms/database/DatabaseFactory.java | 7 +++++- .../database/RecipientPreferenceDatabase.java | 24 +++++++++++++++---- .../securesms/groups/GroupManager.java | 1 + .../securesms/jobs/PushSendJob.java | 19 ++++++++------- 5 files changed, 55 insertions(+), 20 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index 9138b02614..5d19253073 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -1594,6 +1594,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms(); int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1); long expiresIn = recipient.getExpireMessages() * 1000; + boolean initiating = threadId == -1; Log.w(TAG, "isManual Selection: " + sendButton.isManualSelection()); Log.w(TAG, "forceSms: " + forceSms); @@ -1605,9 +1606,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } else if (!forceSms && identityRecords.isUntrusted()) { handleUntrustedRecipients(); } else if (attachmentManager.isAttachmentPresent() || recipient.isGroupRecipient() || recipient.getAddress().isEmail()) { - sendMediaMessage(forceSms, expiresIn, subscriptionId); + sendMediaMessage(forceSms, expiresIn, subscriptionId, initiating); } else { - sendTextMessage(forceSms, expiresIn, subscriptionId); + sendTextMessage(forceSms, expiresIn, subscriptionId, initiating); } } catch (RecipientFormattingException ex) { Toast.makeText(ConversationActivity.this, @@ -1621,13 +1622,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } } - private void sendMediaMessage(final boolean forceSms, final long expiresIn, final int subscriptionId) + private void sendMediaMessage(final boolean forceSms, final long expiresIn, final int subscriptionId, boolean initiating) throws InvalidMessageException { - sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), expiresIn, subscriptionId); + sendMediaMessage(forceSms, getMessage(), attachmentManager.buildSlideDeck(), expiresIn, subscriptionId, initiating); } - private ListenableFuture sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck, final long expiresIn, final int subscriptionId) + private ListenableFuture sendMediaMessage(final boolean forceSms, String body, SlideDeck slideDeck, final long expiresIn, final int subscriptionId, final boolean initiating) throws InvalidMessageException { final SettableFuture future = new SettableFuture<>(); @@ -1651,6 +1652,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity new AsyncTask() { @Override protected Long doInBackground(OutgoingMediaMessage... messages) { + if (initiating) { + DatabaseFactory.getRecipientPreferenceDatabase(context).setProfileSharing(recipient.getAddress(), true); + } + return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms, new SmsDatabase.InsertListener() { @Override public void onComplete() { @@ -1669,7 +1674,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity return future; } - private void sendTextMessage(final boolean forceSms, final long expiresIn, final int subscriptionId) + private void sendTextMessage(final boolean forceSms, final long expiresIn, final int subscriptionId, final boolean initiatingConversation) throws InvalidMessageException { final Context context = getApplicationContext(); @@ -1687,6 +1692,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity new AsyncTask() { @Override protected Long doInBackground(OutgoingTextMessage... messages) { + if (initiatingConversation) { + DatabaseFactory.getRecipientPreferenceDatabase(context).setProfileSharing(recipient.getAddress(), true); + } + return MessageSender.send(context, masterSecret, messages[0], threadId, forceSms, new SmsDatabase.InsertListener() { @Override public void onComplete() { @@ -1780,11 +1789,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms(); int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().or(-1); long expiresIn = recipient.getExpireMessages() * 1000; + boolean initiating = threadId == -1; AudioSlide audioSlide = new AudioSlide(ConversationActivity.this, result.first, result.second, MediaUtil.AUDIO_AAC, true); SlideDeck slideDeck = new SlideDeck(); slideDeck.addSlide(audioSlide); - sendMediaMessage(forceSms, "", slideDeck, expiresIn, subscriptionId).addListener(new AssertedSuccessListener() { + sendMediaMessage(forceSms, "", slideDeck, expiresIn, subscriptionId, initiating).addListener(new AssertedSuccessListener() { @Override public void onSuccess(Void nothing) { new AsyncTask() { diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index b7da217334..5cbe9e599b 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -104,7 +104,8 @@ public class DatabaseFactory { private static final int INTERNAL_DIRECTORY = 39; private static final int INTERNAL_SYSTEM_DISPLAY_NAME = 40; private static final int PROFILES = 41; - private static final int DATABASE_VERSION = 41; + private static final int PROFILE_SHARING_APPROVAL = 42; + private static final int DATABASE_VERSION = 42; private static final String DATABASE_NAME = "messages.db"; private static final Object lock = new Object(); @@ -1307,6 +1308,10 @@ public class DatabaseFactory { db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN signal_profile_avatar TEXT DEFAULT NULL"); } + if (oldVersion < PROFILE_SHARING_APPROVAL) { + db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN profile_sharing_approval INTEGER DEFAULT 0"); + } + db.setTransactionSuccessful(); db.endTransaction(); } diff --git a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java index 23371d0383..bc4bf9ca16 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java @@ -46,10 +46,11 @@ public class RecipientPreferenceDatabase extends Database { private static final String SYSTEM_DISPLAY_NAME = "system_display_name"; private static final String SIGNAL_PROFILE_NAME = "signal_profile_name"; private static final String SIGNAL_PROFILE_AVATAR = "signal_profile_avatar"; + private static final String PROFILE_SHARING = "profile_sharing_approval"; private static final String[] RECIPIENT_PROJECTION = new String[] { BLOCK, NOTIFICATION, VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, EXPIRE_MESSAGES, REGISTERED, - PROFILE_KEY, SYSTEM_DISPLAY_NAME, SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR + PROFILE_KEY, SYSTEM_DISPLAY_NAME, SIGNAL_PROFILE_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING }; static final List TYPED_RECIPIENT_PROJECTION = Stream.of(RECIPIENT_PROJECTION) @@ -90,7 +91,8 @@ public class RecipientPreferenceDatabase extends Database { SYSTEM_DISPLAY_NAME + " TEXT DEFAULT NULL, " + PROFILE_KEY + " TEXT DEFAULT NULL, " + SIGNAL_PROFILE_NAME + " TEXT DEFAULT NULL, " + - SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL);"; + SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " + + PROFILE_SHARING + " INTEGER DEFAULT 0);"; public RecipientPreferenceDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); @@ -143,6 +145,7 @@ public class RecipientPreferenceDatabase extends Database { String systemDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME)); String signalProfileName = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_NAME)); String signalProfileAvatar = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_AVATAR)); + boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1; MaterialColor color; byte[] profileKey = null; @@ -168,7 +171,7 @@ public class RecipientPreferenceDatabase extends Database { notificationUri, color, seenInviteReminder, defaultSubscriptionId, expireMessages, registered, profileKey, systemDisplayName, signalProfileName, - signalProfileAvatar)); + signalProfileAvatar, profileSharing)); } public BulkOperationsHandle resetAllDisplayNames() { @@ -259,6 +262,12 @@ public class RecipientPreferenceDatabase extends Database { updateOrInsert(address, contentValues); } + public void setProfileSharing(@NonNull Address address, boolean enabled) { + ContentValues contentValues = new ContentValues(1); + contentValues.put(PROFILE_SHARING, enabled ? 1 : 0); + updateOrInsert(address, contentValues); + } + public Set
getAllRecipients() { SQLiteDatabase db = databaseHelper.getReadableDatabase(); Set
results = new HashSet<>(); @@ -366,6 +375,7 @@ public class RecipientPreferenceDatabase extends Database { private final String systemDisplayName; private final String signalProfileName; private final String signalProfileAvatar; + private final boolean profileSharing; RecipientsPreferences(boolean blocked, long muteUntil, @NonNull VibrateState vibrateState, @@ -378,7 +388,8 @@ public class RecipientPreferenceDatabase extends Database { @Nullable byte[] profileKey, @Nullable String systemDisplayName, @Nullable String signalProfileName, - @Nullable String signalProfileAvatar) + @Nullable String signalProfileAvatar, + boolean profileSharing) { this.blocked = blocked; this.muteUntil = muteUntil; @@ -393,6 +404,7 @@ public class RecipientPreferenceDatabase extends Database { this.systemDisplayName = systemDisplayName; this.signalProfileName = signalProfileName; this.signalProfileAvatar = signalProfileAvatar; + this.profileSharing = profileSharing; } public @Nullable MaterialColor getColor() { @@ -446,6 +458,10 @@ public class RecipientPreferenceDatabase extends Database { public @Nullable String getProfileAvatar() { return signalProfileAvatar; } + + public boolean isProfileSharing() { + return profileSharing; + } } public static class BlockedReader { diff --git a/src/org/thoughtcrime/securesms/groups/GroupManager.java b/src/org/thoughtcrime/securesms/groups/GroupManager.java index af06662774..c42aeae0a7 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupManager.java +++ b/src/org/thoughtcrime/securesms/groups/GroupManager.java @@ -55,6 +55,7 @@ public class GroupManager { if (!mms) { groupDatabase.updateAvatar(groupId, avatarBytes); + DatabaseFactory.getRecipientPreferenceDatabase(context).setProfileSharing(Address.fromSerialized(groupId), true); return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes); } else { Recipient groupRecipient = RecipientFactory.getRecipientFor(context, Address.fromSerialized(groupId), true); diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index aa2523da76..12b87af299 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -70,18 +70,21 @@ public abstract class PushSendJob extends SendJob { Optional recipientsPreferences = DatabaseFactory.getRecipientPreferenceDatabase(context) .getRecipientsPreferences(address); - if (recipientsPreferences.isPresent() && !TextUtils.isEmpty(recipientsPreferences.get().getSystemDisplayName())) { - String profileKey = TextSecurePreferences.getProfileKey(context); + if (!recipientsPreferences.isPresent()) return Optional.absent(); - if (profileKey == null) { - profileKey = Util.getSecret(32); - TextSecurePreferences.setProfileKey(context, profileKey); - } + boolean isSystemContact = !TextUtils.isEmpty(recipientsPreferences.get().getSystemDisplayName()); + boolean isApproved = recipientsPreferences.get().isProfileSharing(); - return Optional.of(Base64.decode(profileKey)); + if (!isSystemContact & !isApproved) return Optional.absent(); + + String profileKey = TextSecurePreferences.getProfileKey(context); + + if (profileKey == null) { + profileKey = Util.getSecret(32); + TextSecurePreferences.setProfileKey(context, profileKey); } - return Optional.absent(); + return Optional.of(Base64.decode(profileKey)); } catch (IOException e) { throw new AssertionError(e); }