mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Make fingerprint changes optionally non-blocking
Also complete the rename from "identity" to "safety numbers." // FREEBIE
This commit is contained in:
parent
852634b294
commit
848a25664b
@ -2,10 +2,11 @@ buildscript {
|
|||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url "https://repo1.maven.org/maven2"
|
url "https://repo1.maven.org/maven2"
|
||||||
|
jcenter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:1.2.3'
|
classpath 'com.android.tools.build:gradle:2.1.3'
|
||||||
classpath files('libs/gradle-witness.jar')
|
classpath files('libs/gradle-witness.jar')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +160,7 @@ dependencyVerification {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 22
|
compileSdkVersion 22
|
||||||
buildToolsVersion '22.0.1'
|
buildToolsVersion '23.0.2'
|
||||||
|
|
||||||
dexOptions {
|
dexOptions {
|
||||||
javaMaxHeapSize "4g"
|
javaMaxHeapSize "4g"
|
||||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
#Wed Jul 22 14:31:11 PDT 2015
|
#Sun Aug 28 20:14:40 PDT 2016
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
|
||||||
|
Binary file not shown.
BIN
res/drawable-hdpi/ic_security_white_24dp.png
Normal file
BIN
res/drawable-hdpi/ic_security_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 428 B |
BIN
res/drawable-mdpi/ic_security_white_24dp.png
Normal file
BIN
res/drawable-mdpi/ic_security_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 288 B |
BIN
res/drawable-xhdpi/ic_security_white_24dp.png
Normal file
BIN
res/drawable-xhdpi/ic_security_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 507 B |
BIN
res/drawable-xxhdpi/ic_security_white_24dp.png
Normal file
BIN
res/drawable-xxhdpi/ic_security_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 702 B |
BIN
res/drawable-xxxhdpi/ic_security_white_24dp.png
Normal file
BIN
res/drawable-xxxhdpi/ic_security_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 913 B |
@ -139,7 +139,8 @@
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableLayout>
|
</TableLayout>
|
||||||
|
|
||||||
<TextView android:layout_width="match_parent"
|
<TextView android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="25dp"
|
android:layout_marginTop="25dp"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
|
@ -75,12 +75,11 @@
|
|||||||
|
|
||||||
<!-- ConfirmIdentityDialog -->
|
<!-- ConfirmIdentityDialog -->
|
||||||
<string name="ConfirmIdentityDialog_the_signature_on_this_key_exchange_is_different">The
|
<string name="ConfirmIdentityDialog_the_signature_on_this_key_exchange_is_different">The
|
||||||
identifying key material for %1$s has changed. This could either mean that someone is trying to
|
safety numbers for %1$s have changed. This could either mean that someone is trying to
|
||||||
intercept your communication, or that %2$s simply re-installed Signal and now has a new
|
intercept your communication, or that %2$s simply re-installed Signal.
|
||||||
identity key.
|
|
||||||
</string>
|
</string>
|
||||||
<string name="ConfirmIdentityDialog_you_may_wish_to_verify_this_contact">You may wish to verify
|
<string name="ConfirmIdentityDialog_you_may_wish_to_verify_this_contact">You may wish to verify
|
||||||
this contact.
|
safety numbers for this contact.
|
||||||
</string>
|
</string>
|
||||||
<string name="ConfirmIdentityDialog_accept">Accept</string>
|
<string name="ConfirmIdentityDialog_accept">Accept</string>
|
||||||
|
|
||||||
@ -355,7 +354,7 @@
|
|||||||
|
|
||||||
<!-- MessageDetailsRecipient -->
|
<!-- MessageDetailsRecipient -->
|
||||||
<string name="MessageDetailsRecipient_failed_to_send">Failed to send</string>
|
<string name="MessageDetailsRecipient_failed_to_send">Failed to send</string>
|
||||||
<string name="MessageDetailsRecipient_new_identity">New identity</string>
|
<string name="MessageDetailsRecipient_new_safety_numbers">New safety numbers</string>
|
||||||
|
|
||||||
<!-- MmsDownloader -->
|
<!-- MmsDownloader -->
|
||||||
<string name="MmsDownloader_error_storing_mms">Error storing MMS!</string>
|
<string name="MmsDownloader_error_storing_mms">Error storing MMS!</string>
|
||||||
@ -536,8 +535,7 @@
|
|||||||
<string name="SmsMessageRecord_received_key_exchange_message_for_invalid_protocol_version">
|
<string name="SmsMessageRecord_received_key_exchange_message_for_invalid_protocol_version">
|
||||||
Received key exchange message for invalid protocol version.
|
Received key exchange message for invalid protocol version.
|
||||||
</string>
|
</string>
|
||||||
<string name="SmsMessageRecord_received_message_with_unknown_identity_key_tap_to_process">Received message with unknown identity key. Tap to process and display.</string>
|
<string name="SmsMessageRecord_received_message_with_new_safety_numbers_tap_to_process">Received message with new safety numbers. Tap to process and display.</string>
|
||||||
<string name="SmsMessageRecord_received_updated_but_unknown_identity_information">Received updated but unknown identity information. Tap to validate identity.</string>
|
|
||||||
<string name="SmsMessageRecord_secure_session_reset">You reset the secure session.</string>
|
<string name="SmsMessageRecord_secure_session_reset">You reset the secure session.</string>
|
||||||
<string name="SmsMessageRecord_secure_session_reset_s">%s reset the secure session.</string>
|
<string name="SmsMessageRecord_secure_session_reset_s">%s reset the secure session.</string>
|
||||||
<string name="SmsMessageRecord_duplicate_message">Duplicate message.</string>
|
<string name="SmsMessageRecord_duplicate_message">Duplicate message.</string>
|
||||||
@ -558,17 +556,6 @@
|
|||||||
<string name="VerifyIdentityActivity_you_re_attempting_to_verify_security_numbers_with">You\'re attempting to verify security numbers with %1$s, but scanned %2$s instead.</string>
|
<string name="VerifyIdentityActivity_you_re_attempting_to_verify_security_numbers_with">You\'re attempting to verify security numbers with %1$s, but scanned %2$s instead.</string>
|
||||||
<string name="VerifyIdentityActivity_the_scanned_qr_code_is_not_a_correctly_formatted_security_number">The scanned QR code is not a correctly formatted security number verification code. Please try scanning again.</string>
|
<string name="VerifyIdentityActivity_the_scanned_qr_code_is_not_a_correctly_formatted_security_number">The scanned QR code is not a correctly formatted security number verification code. Please try scanning again.</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- ViewIdentityActivity -->
|
|
||||||
<string name="ViewIdentityActivity_you_do_not_have_an_identity_key">You do not have an identity key.</string>
|
|
||||||
<string name="ViewIdentityActivity_scan_contacts_qr_code">Scan contact\'s QR code</string>
|
|
||||||
<string name="ViewIdentityActivity_display_your_qr_code">Display your QR code</string>
|
|
||||||
<string name="ViewIdentityActivity_warning_the_scanned_key_does_not_match_exclamation">WARNING, the scanned key DOES NOT match!</string>
|
|
||||||
<string name="ViewIdentityActivity_not_verified_exclamation">NOT verified!</string>
|
|
||||||
<string name="ViewIdentityActivity_the_scanned_key_matches_exclamation">The scanned key matches!</string>
|
|
||||||
<string name="ViewIdentityActivity_verified_exclamation">Verified!</string>
|
|
||||||
<string name="ViewIdentityActivity_your_identity_fingerprint">Your identity fingerprint</string>
|
|
||||||
|
|
||||||
<!-- KeyExchangeInitiator -->
|
<!-- KeyExchangeInitiator -->
|
||||||
<string name="KeyExchangeInitiator_initiate_despite_existing_request_question">Initiate despite existing request?</string>
|
<string name="KeyExchangeInitiator_initiate_despite_existing_request_question">Initiate despite existing request?</string>
|
||||||
<string name="KeyExchangeInitiator_send">Send</string>
|
<string name="KeyExchangeInitiator_send">Send</string>
|
||||||
@ -833,7 +820,7 @@
|
|||||||
<string name="recipient_preferences__block">Block</string>
|
<string name="recipient_preferences__block">Block</string>
|
||||||
<string name="recipient_preferences__color">Color</string>
|
<string name="recipient_preferences__color">Color</string>
|
||||||
<string name="recipient_preferences__color_for_this_contact">Color for this contact</string>
|
<string name="recipient_preferences__color_for_this_contact">Color for this contact</string>
|
||||||
<string name="recipient_preferences__verify_identity">Verify identity</string>
|
<string name="recipient_preferences__verify_safety_numbers">Verify safety numbers</string>
|
||||||
|
|
||||||
<!--- redphone_call_controls -->
|
<!--- redphone_call_controls -->
|
||||||
<string name="redphone_call_card__signal_call">Signal Call</string>
|
<string name="redphone_call_card__signal_call">Signal Call</string>
|
||||||
@ -930,7 +917,7 @@
|
|||||||
<string name="recipients_panel__add_member">Add member</string>
|
<string name="recipients_panel__add_member">Add member</string>
|
||||||
|
|
||||||
<!-- verify_display_fragment -->
|
<!-- verify_display_fragment -->
|
||||||
<string name="verify_display_fragment__scan_the_code_on_your_contact_s_phone_or_ask_them_to_scan_your_code_to_verify_that_your_messages_are_end_to_end_encrypted_you_can_alternately_compare_the_number_above">Scan the code on your contact\'s phone, or ask them to scan your code, to verify that your messages are end-to-end encrypted. You can alternately compare the number above.</string>
|
<string name="verify_display_fragment__scan_the_code_on_your_contact_s_phone_or_ask_them_to_scan_your_code_to_verify_that_your_messages_are_end_to_end_encrypted_you_can_alternately_compare_the_number_above">If you wish to verify the security of your end-to-end encryption with %s, compare the numbers above with the numbers on their device. Alternately, you can scan the code on their phone, or ask them to scan your code.</string>
|
||||||
<string name="verify_display_fragment__tap_to_scan">Tap to scan</string>
|
<string name="verify_display_fragment__tap_to_scan">Tap to scan</string>
|
||||||
|
|
||||||
<!-- message_details_header -->
|
<!-- message_details_header -->
|
||||||
@ -947,9 +934,8 @@
|
|||||||
<string name="AndroidManifest__enter_passphrase">Enter passphrase</string>
|
<string name="AndroidManifest__enter_passphrase">Enter passphrase</string>
|
||||||
<string name="AndroidManifest__select_contacts">Select contacts</string>
|
<string name="AndroidManifest__select_contacts">Select contacts</string>
|
||||||
<string name="AndroidManifest__signal_detected">Signal detected</string>
|
<string name="AndroidManifest__signal_detected">Signal detected</string>
|
||||||
<string name="AndroidManifest__public_identity_key">Public identity key</string>
|
|
||||||
<string name="AndroidManifest__change_passphrase">Change passphrase</string>
|
<string name="AndroidManifest__change_passphrase">Change passphrase</string>
|
||||||
<string name="AndroidManifest__verify_identity">Verify identity</string>
|
<string name="AndroidManifest__verify_safety_numbers">Verify safety numbers</string>
|
||||||
<string name="AndroidManifest__log_submit">Submit debug log</string>
|
<string name="AndroidManifest__log_submit">Submit debug log</string>
|
||||||
<string name="AndroidManifest__media_preview">Media preview</string>
|
<string name="AndroidManifest__media_preview">Media preview</string>
|
||||||
<string name="AndroidManifest__media_overview">All images</string>
|
<string name="AndroidManifest__media_overview">All images</string>
|
||||||
@ -961,7 +947,6 @@
|
|||||||
|
|
||||||
<!-- arrays.xml -->
|
<!-- arrays.xml -->
|
||||||
<string name="arrays__import_export">Import / export</string>
|
<string name="arrays__import_export">Import / export</string>
|
||||||
<string name="arrays__your_identity_key">Your identity key</string>
|
|
||||||
<string name="arrays__use_default">Use default</string>
|
<string name="arrays__use_default">Use default</string>
|
||||||
<string name="arrays__use_custom">Use custom</string>
|
<string name="arrays__use_custom">Use custom</string>
|
||||||
|
|
||||||
@ -1084,6 +1069,8 @@
|
|||||||
<string name="preferences__support_wifi_calling">\'WiFi Calling\' compatibility mode</string>
|
<string name="preferences__support_wifi_calling">\'WiFi Calling\' compatibility mode</string>
|
||||||
<string name="preferences__enable_if_your_device_supports_sms_mms_delivery_over_wifi">Enable if your device uses SMS/MMS delivery over WiFi (only enable when \'WiFi Calling\' is enabled on your device)</string>
|
<string name="preferences__enable_if_your_device_supports_sms_mms_delivery_over_wifi">Enable if your device uses SMS/MMS delivery over WiFi (only enable when \'WiFi Calling\' is enabled on your device)</string>
|
||||||
<string name="preferences_app_protection__blocked_contacts">Blocked contacts</string>
|
<string name="preferences_app_protection__blocked_contacts">Blocked contacts</string>
|
||||||
|
<string name="preferences_app_protection__safety_numbers_approval">Safety numbers approval</string>
|
||||||
|
<string name="preferences_app_protecting__require_approval_of_new_safety_numbers_when_they_change">Require approval of new safety numbers when they change</string>
|
||||||
<string name="preferences_notifications__display_in_notifications">Display in notifications</string>
|
<string name="preferences_notifications__display_in_notifications">Display in notifications</string>
|
||||||
<string name="preferences_chats__when_using_mobile_data">When using mobile data</string>
|
<string name="preferences_chats__when_using_mobile_data">When using mobile data</string>
|
||||||
<string name="preferences_chats__when_using_wifi">When using Wi-Fi</string>
|
<string name="preferences_chats__when_using_wifi">When using Wi-Fi</string>
|
||||||
@ -1156,8 +1143,6 @@
|
|||||||
<string name="conversation_list_fragment__fab_content_description">New conversation</string>
|
<string name="conversation_list_fragment__fab_content_description">New conversation</string>
|
||||||
|
|
||||||
<!-- conversation_secure_verified -->
|
<!-- conversation_secure_verified -->
|
||||||
<string name="conversation_secure_verified__menu_security">Security</string>
|
|
||||||
<string name="conversation_secure_verified__menu_verify_identity">Verify identity</string>
|
|
||||||
<string name="conversation_secure_verified__menu_reset_secure_session">Reset secure session</string>
|
<string name="conversation_secure_verified__menu_reset_secure_session">Reset secure session</string>
|
||||||
|
|
||||||
<!-- conversation_muted -->
|
<!-- conversation_muted -->
|
||||||
|
@ -28,6 +28,12 @@
|
|||||||
android:title="@string/preferences__screen_security"
|
android:title="@string/preferences__screen_security"
|
||||||
android:summary="@string/preferences__disable_screen_security_to_allow_screen_shots" />
|
android:summary="@string/preferences__disable_screen_security_to_allow_screen_shots" />
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="pref_blocking_identity_changes"
|
||||||
|
android:title="@string/preferences_app_protection__safety_numbers_approval"
|
||||||
|
android:summary="@string/preferences_app_protecting__require_approval_of_new_safety_numbers_when_they_change"/>
|
||||||
|
|
||||||
<Preference android:key="preference_category_blocked"
|
<Preference android:key="preference_category_blocked"
|
||||||
android:title="@string/preferences_app_protection__blocked_contacts" />
|
android:title="@string/preferences_app_protection__blocked_contacts" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
app:numColumns="5" />
|
app:numColumns="5" />
|
||||||
|
|
||||||
<Preference android:key="pref_key_recipient_identity"
|
<Preference android:key="pref_key_recipient_identity"
|
||||||
android:title="@string/recipient_preferences__verify_identity"
|
android:title="@string/recipient_preferences__verify_safety_numbers"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:enabled="false"/>
|
android:enabled="false"/>
|
||||||
|
|
||||||
|
@ -196,8 +196,8 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
|
|||||||
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
|
||||||
|
|
||||||
if (messageRecord.isGroupAction() || messageRecord.isCallLog() || messageRecord.isJoined() ||
|
if (messageRecord.isGroupAction() || messageRecord.isCallLog() || messageRecord.isJoined() ||
|
||||||
messageRecord.isExpirationTimerUpdate() || messageRecord.isEndSession())
|
messageRecord.isExpirationTimerUpdate() || messageRecord.isEndSessin() || messageRecord.isIdentityUpdate())
|
||||||
{
|
{
|
||||||
return MESSAGE_TYPE_UPDATE;
|
return MESSAGE_TYPE_UPDATE;
|
||||||
} else if (messageRecord.isOutgoing()) {
|
} else if (messageRecord.isOutgoing()) {
|
||||||
return MESSAGE_TYPE_OUTGOING;
|
return MESSAGE_TYPE_OUTGOING;
|
||||||
|
@ -181,7 +181,7 @@ public class ConversationFragment extends Fragment
|
|||||||
for (MessageRecord messageRecord : messageRecords) {
|
for (MessageRecord messageRecord : messageRecords) {
|
||||||
if (messageRecord.isGroupAction() || messageRecord.isCallLog() ||
|
if (messageRecord.isGroupAction() || messageRecord.isCallLog() ||
|
||||||
messageRecord.isJoined() || messageRecord.isExpirationTimerUpdate() ||
|
messageRecord.isJoined() || messageRecord.isExpirationTimerUpdate() ||
|
||||||
messageRecord.isEndSession())
|
messageRecord.isEndSession() || messageRecord.isIdentityUpdate())
|
||||||
{
|
{
|
||||||
actionMessage = true;
|
actionMessage = true;
|
||||||
break;
|
break;
|
||||||
|
@ -6,28 +6,39 @@ import android.graphics.Color;
|
|||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.PorterDuffColorFilter;
|
import android.graphics.PorterDuffColorFilter;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public class ConversationUpdateItem extends LinearLayout
|
public class ConversationUpdateItem extends LinearLayout
|
||||||
implements Recipients.RecipientsModifiedListener, Recipient.RecipientModifiedListener, BindableConversationItem, View.OnClickListener
|
implements Recipients.RecipientsModifiedListener, Recipient.RecipientModifiedListener, BindableConversationItem
|
||||||
{
|
{
|
||||||
private static final String TAG = ConversationUpdateItem.class.getSimpleName();
|
private static final String TAG = ConversationUpdateItem.class.getSimpleName();
|
||||||
|
|
||||||
|
private MasterSecret masterSecret;
|
||||||
|
private Set<MessageRecord> batchSelected;
|
||||||
|
|
||||||
private ImageView icon;
|
private ImageView icon;
|
||||||
private TextView body;
|
private TextView body;
|
||||||
private TextView date;
|
private TextView date;
|
||||||
@ -51,7 +62,7 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
this.body = (TextView)findViewById(R.id.conversation_update_body);
|
this.body = (TextView)findViewById(R.id.conversation_update_body);
|
||||||
this.date = (TextView)findViewById(R.id.conversation_update_date);
|
this.date = (TextView)findViewById(R.id.conversation_update_date);
|
||||||
|
|
||||||
setOnClickListener(this);
|
this.setOnClickListener(new InternalClickListener(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,13 +72,10 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
@NonNull Set<MessageRecord> batchSelected,
|
@NonNull Set<MessageRecord> batchSelected,
|
||||||
@NonNull Recipients conversationRecipients)
|
@NonNull Recipients conversationRecipients)
|
||||||
{
|
{
|
||||||
bind(messageRecord, locale);
|
this.masterSecret = masterSecret;
|
||||||
|
this.batchSelected = batchSelected;
|
||||||
|
|
||||||
if (batchSelected.contains(messageRecord)) {
|
bind(messageRecord, locale);
|
||||||
setSelected(true);
|
|
||||||
} else {
|
|
||||||
setSelected(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,7 +95,11 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
else if (messageRecord.isJoined()) setJoinedRecord(messageRecord);
|
else if (messageRecord.isJoined()) setJoinedRecord(messageRecord);
|
||||||
else if (messageRecord.isExpirationTimerUpdate()) setTimerRecord(messageRecord);
|
else if (messageRecord.isExpirationTimerUpdate()) setTimerRecord(messageRecord);
|
||||||
else if (messageRecord.isEndSession()) setEndSessionRecord(messageRecord);
|
else if (messageRecord.isEndSession()) setEndSessionRecord(messageRecord);
|
||||||
|
else if (messageRecord.isIdentityUpdate()) setIdentityRecord(messageRecord);
|
||||||
else throw new AssertionError("Neither group nor log nor joined.");
|
else throw new AssertionError("Neither group nor log nor joined.");
|
||||||
|
|
||||||
|
if (batchSelected.contains(messageRecord)) setSelected(true);
|
||||||
|
else setSelected(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCallRecord(MessageRecord messageRecord) {
|
private void setCallRecord(MessageRecord messageRecord) {
|
||||||
@ -113,6 +125,13 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
date.setVisibility(View.GONE);
|
date.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setIdentityRecord(final MessageRecord messageRecord) {
|
||||||
|
icon.setImageResource(R.drawable.ic_security_white_24dp);
|
||||||
|
icon.setColorFilter(new PorterDuffColorFilter(Color.parseColor("#757575"), PorterDuff.Mode.MULTIPLY));
|
||||||
|
body.setText(messageRecord.getDisplayBody());
|
||||||
|
date.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
private void setGroupRecord(MessageRecord messageRecord) {
|
private void setGroupRecord(MessageRecord messageRecord) {
|
||||||
icon.setImageResource(R.drawable.ic_group_grey600_24dp);
|
icon.setImageResource(R.drawable.ic_group_grey600_24dp);
|
||||||
icon.clearColorFilter();
|
icon.clearColorFilter();
|
||||||
@ -153,14 +172,8 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void setOnClickListener(View.OnClickListener l) {
|
||||||
if (messageRecord.isIdentityUpdate()) {
|
super.setOnClickListener(new InternalClickListener(l));
|
||||||
Intent intent = new Intent(getContext(), RecipientPreferenceActivity.class);
|
|
||||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENTS_EXTRA,
|
|
||||||
new long[] {messageRecord.getIndividualRecipient().getRecipientId()});
|
|
||||||
|
|
||||||
getContext().startActivity(intent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -169,4 +182,42 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
sender.removeListener(this);
|
sender.removeListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class InternalClickListener implements View.OnClickListener {
|
||||||
|
|
||||||
|
@Nullable private final View.OnClickListener parent;
|
||||||
|
|
||||||
|
public InternalClickListener(@Nullable View.OnClickListener parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (!messageRecord.isIdentityUpdate() || !batchSelected.isEmpty()) {
|
||||||
|
if (parent != null) parent.onClick(v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Recipient sender = ConversationUpdateItem.this.sender;
|
||||||
|
|
||||||
|
IdentityUtil.getRemoteIdentityKey(getContext(), masterSecret, sender).addListener(new ListenableFuture.Listener<Optional<IdentityKey>>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Optional<IdentityKey> result) {
|
||||||
|
if (result.isPresent()) {
|
||||||
|
Intent intent = new Intent(getContext(), VerifyIdentityActivity.class);
|
||||||
|
intent.putExtra(VerifyIdentityActivity.RECIPIENT_ID, sender.getRecipientId());
|
||||||
|
intent.putExtra(VerifyIdentityActivity.RECIPIENT_IDENTITY, new IdentityKeyParcelable(result.get()));
|
||||||
|
|
||||||
|
getContext().startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(ExecutionException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.VersionTracker;
|
import org.thoughtcrime.securesms.util.VersionTracker;
|
||||||
|
|
||||||
@ -68,6 +69,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
public static final int CONTACTS_ACCOUNT_VERSION = 136;
|
public static final int CONTACTS_ACCOUNT_VERSION = 136;
|
||||||
public static final int MEDIA_DOWNLOAD_CONTROLS_VERSION = 151;
|
public static final int MEDIA_DOWNLOAD_CONTROLS_VERSION = 151;
|
||||||
public static final int REDPHONE_SUPPORT_VERSION = 157;
|
public static final int REDPHONE_SUPPORT_VERSION = 157;
|
||||||
|
public static final int FINGERPRINTS_NON_BLOCKING_VESRION = 197;
|
||||||
|
|
||||||
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
||||||
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
||||||
@ -81,6 +83,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
add(MIGRATE_SESSION_PLAINTEXT);
|
add(MIGRATE_SESSION_PLAINTEXT);
|
||||||
add(MEDIA_DOWNLOAD_CONTROLS_VERSION);
|
add(MEDIA_DOWNLOAD_CONTROLS_VERSION);
|
||||||
add(REDPHONE_SUPPORT_VERSION);
|
add(REDPHONE_SUPPORT_VERSION);
|
||||||
|
add(FINGERPRINTS_NON_BLOCKING_VESRION);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
@ -231,6 +234,10 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
.add(new DirectoryRefreshJob(getApplicationContext()));
|
.add(new DirectoryRefreshJob(getApplicationContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params[0] < FINGERPRINTS_NON_BLOCKING_VESRION) {
|
||||||
|
TextSecurePreferences.setBlockingIdentityUpdates(getApplicationContext(), true);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||||||
resendButton.setVisibility(View.GONE);
|
resendButton.setVisibility(View.GONE);
|
||||||
conflictButton.setVisibility(View.VISIBLE);
|
conflictButton.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
errorText = getContext().getString(R.string.MessageDetailsRecipient_new_identity);
|
errorText = getContext().getString(R.string.MessageDetailsRecipient_new_safety_numbers);
|
||||||
conflictButton.setOnClickListener(new OnClickListener() {
|
conflictButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -31,7 +31,6 @@ import org.thoughtcrime.securesms.color.MaterialColors;
|
|||||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
|
||||||
@ -39,20 +38,15 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
|||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||||
import org.thoughtcrime.securesms.preferences.AdvancedRingtonePreference;
|
import org.thoughtcrime.securesms.preferences.AdvancedRingtonePreference;
|
||||||
import org.thoughtcrime.securesms.preferences.ColorPreference;
|
import org.thoughtcrime.securesms.preferences.ColorPreference;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
|
||||||
import org.whispersystems.libsignal.state.SessionRecord;
|
|
||||||
import org.whispersystems.libsignal.state.SessionStore;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
@ -296,7 +290,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
if (recipients.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
|
if (recipients.isBlocked()) blockPreference.setTitle(R.string.RecipientPreferenceActivity_unblock);
|
||||||
else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block);
|
else blockPreference.setTitle(R.string.RecipientPreferenceActivity_block);
|
||||||
|
|
||||||
getRemoteIdentityKey(getActivity(), masterSecret, recipients.getPrimaryRecipient()).addListener(new ListenableFuture.Listener<Optional<IdentityKey>>() {
|
IdentityUtil.getRemoteIdentityKey(getActivity(), masterSecret, recipients.getPrimaryRecipient()).addListener(new ListenableFuture.Listener<Optional<IdentityKey>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Optional<IdentityKey> result) {
|
public void onSuccess(Optional<IdentityKey> result) {
|
||||||
if (result.isPresent()) {
|
if (result.isPresent()) {
|
||||||
@ -325,36 +319,6 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFuture<Optional<IdentityKey>> getRemoteIdentityKey(final Context context,
|
|
||||||
final MasterSecret masterSecret,
|
|
||||||
final Recipient recipient)
|
|
||||||
{
|
|
||||||
final SettableFuture<Optional<IdentityKey>> future = new SettableFuture<>();
|
|
||||||
|
|
||||||
new AsyncTask<Recipient, Void, Optional<IdentityKey>>() {
|
|
||||||
@Override
|
|
||||||
protected Optional<IdentityKey> doInBackground(Recipient... recipient) {
|
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
|
|
||||||
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(recipient[0].getNumber(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
|
||||||
SessionRecord record = sessionStore.loadSession(axolotlAddress);
|
|
||||||
|
|
||||||
if (record == null) {
|
|
||||||
return Optional.absent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.fromNullable(record.getSessionState().getRemoteIdentityKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Optional<IdentityKey> result) {
|
|
||||||
future.set(result);
|
|
||||||
}
|
|
||||||
}.execute(recipient);
|
|
||||||
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener {
|
private class RingtoneChangeListener implements Preference.OnPreferenceChangeListener {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
|
@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.qr.ScanListener;
|
|||||||
import org.thoughtcrime.securesms.qr.ScanningThread;
|
import org.thoughtcrime.securesms.qr.ScanningThread;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
@ -93,7 +94,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle state, @NonNull MasterSecret masterSecret) {
|
protected void onCreate(Bundle state, @NonNull MasterSecret masterSecret) {
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_identity);
|
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_numbers);
|
||||||
|
|
||||||
Recipient recipient = RecipientFactory.getRecipientForId(this, getIntent().getLongExtra(RECIPIENT_ID, -1), true);
|
Recipient recipient = RecipientFactory.getRecipientForId(this, getIntent().getLongExtra(RECIPIENT_ID, -1), true);
|
||||||
|
|
||||||
@ -146,15 +147,16 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class VerifyDisplayFragment extends Fragment {
|
public static class VerifyDisplayFragment extends Fragment implements Recipients.RecipientsModifiedListener {
|
||||||
|
|
||||||
public static final String REMOTE_NUMBER = "remote_number";
|
public static final String REMOTE_NUMBER = "remote_number";
|
||||||
public static final String REMOTE_IDENTITY = "remote_identity";
|
public static final String REMOTE_IDENTITY = "remote_identity";
|
||||||
public static final String LOCAL_IDENTITY = "local_identity";
|
public static final String LOCAL_IDENTITY = "local_identity";
|
||||||
public static final String LOCAL_NUMBER = "local_number";
|
public static final String LOCAL_NUMBER = "local_number";
|
||||||
|
|
||||||
private String localNumber;
|
private Recipients recipient;
|
||||||
private String remoteNumber;
|
private String localNumber;
|
||||||
|
private String remoteNumber;
|
||||||
|
|
||||||
private IdentityKey localIdentity;
|
private IdentityKey localIdentity;
|
||||||
private IdentityKey remoteIdentity;
|
private IdentityKey remoteIdentity;
|
||||||
@ -164,6 +166,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private View container;
|
private View container;
|
||||||
private ImageView qrCode;
|
private ImageView qrCode;
|
||||||
private ImageView qrVerified;
|
private ImageView qrVerified;
|
||||||
|
private TextView description;
|
||||||
private View.OnClickListener clickListener;
|
private View.OnClickListener clickListener;
|
||||||
|
|
||||||
private TextView[] codes = new TextView[12];
|
private TextView[] codes = new TextView[12];
|
||||||
@ -172,21 +175,22 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle bundle) {
|
||||||
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_display_fragment);
|
this.container = ViewUtil.inflate(inflater, viewGroup, R.layout.verify_display_fragment);
|
||||||
this.qrCode = ViewUtil.findById(container, R.id.qr_code);
|
this.qrCode = ViewUtil.findById(container, R.id.qr_code);
|
||||||
this.qrVerified = ViewUtil.findById(container, R.id.qr_verified);
|
this.qrVerified = ViewUtil.findById(container, R.id.qr_verified);
|
||||||
this.codes[0] = ViewUtil.findById(container, R.id.code_first);
|
this.description = ViewUtil.findById(container, R.id.description);
|
||||||
this.codes[1] = ViewUtil.findById(container, R.id.code_second);
|
this.codes[0] = ViewUtil.findById(container, R.id.code_first);
|
||||||
this.codes[2] = ViewUtil.findById(container, R.id.code_third);
|
this.codes[1] = ViewUtil.findById(container, R.id.code_second);
|
||||||
this.codes[3] = ViewUtil.findById(container, R.id.code_fourth);
|
this.codes[2] = ViewUtil.findById(container, R.id.code_third);
|
||||||
this.codes[4] = ViewUtil.findById(container, R.id.code_fifth);
|
this.codes[3] = ViewUtil.findById(container, R.id.code_fourth);
|
||||||
this.codes[5] = ViewUtil.findById(container, R.id.code_sixth);
|
this.codes[4] = ViewUtil.findById(container, R.id.code_fifth);
|
||||||
this.codes[6] = ViewUtil.findById(container, R.id.code_seventh);
|
this.codes[5] = ViewUtil.findById(container, R.id.code_sixth);
|
||||||
this.codes[7] = ViewUtil.findById(container, R.id.code_eighth);
|
this.codes[6] = ViewUtil.findById(container, R.id.code_seventh);
|
||||||
this.codes[8] = ViewUtil.findById(container, R.id.code_ninth);
|
this.codes[7] = ViewUtil.findById(container, R.id.code_eighth);
|
||||||
this.codes[9] = ViewUtil.findById(container, R.id.code_tenth);
|
this.codes[8] = ViewUtil.findById(container, R.id.code_ninth);
|
||||||
this.codes[10] = ViewUtil.findById(container, R.id.code_eleventh);
|
this.codes[9] = ViewUtil.findById(container, R.id.code_tenth);
|
||||||
this.codes[11] = ViewUtil.findById(container, R.id.code_twelth);
|
this.codes[10] = ViewUtil.findById(container, R.id.code_eleventh);
|
||||||
|
this.codes[11] = ViewUtil.findById(container, R.id.code_twelth);
|
||||||
|
|
||||||
this.qrCode.setOnClickListener(clickListener);
|
this.qrCode.setOnClickListener(clickListener);
|
||||||
|
|
||||||
@ -200,9 +204,17 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
this.localNumber = getArguments().getString(LOCAL_NUMBER);
|
this.localNumber = getArguments().getString(LOCAL_NUMBER);
|
||||||
this.localIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(LOCAL_IDENTITY)).get();
|
this.localIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(LOCAL_IDENTITY)).get();
|
||||||
this.remoteNumber = getArguments().getString(REMOTE_NUMBER);
|
this.remoteNumber = getArguments().getString(REMOTE_NUMBER);
|
||||||
|
this.recipient = RecipientFactory.getRecipientsFromString(getActivity(), this.remoteNumber, true);
|
||||||
this.remoteIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(REMOTE_IDENTITY)).get();
|
this.remoteIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(REMOTE_IDENTITY)).get();
|
||||||
this.fingerprint = new NumericFingerprintGenerator(5200).createFor(localNumber, localIdentity,
|
this.fingerprint = new NumericFingerprintGenerator(5200).createFor(localNumber, localIdentity,
|
||||||
remoteNumber, remoteIdentity);
|
remoteNumber, remoteIdentity);
|
||||||
|
|
||||||
|
this.recipient.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onModified(Recipients recipients) {
|
||||||
|
setFingerprintViews(fingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -220,6 +232,12 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
recipient.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void setScannedFingerprint(String scanned) {
|
public void setScannedFingerprint(String scanned) {
|
||||||
try {
|
try {
|
||||||
if (fingerprint.getScannableFingerprint().compareTo(scanned.getBytes("ISO-8859-1"))) {
|
if (fingerprint.getScannableFingerprint().compareTo(scanned.getBytes("ISO-8859-1"))) {
|
||||||
@ -258,6 +276,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
Bitmap qrCodeBitmap = QrCode.create(qrCodeString);
|
Bitmap qrCodeBitmap = QrCode.create(qrCodeString);
|
||||||
|
|
||||||
qrCode.setImageBitmap(qrCodeBitmap);
|
qrCode.setImageBitmap(qrCodeBitmap);
|
||||||
|
description.setText(getActivity().getString(R.string.verify_display_fragment__scan_the_code_on_your_contact_s_phone_or_ask_them_to_scan_your_code_to_verify_that_your_messages_are_end_to_end_encrypted_you_can_alternately_compare_the_number_above, recipient.toShortString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap createVerifiedBitmap(int width, int height, @DrawableRes int id) {
|
private Bitmap createVerifiedBitmap(int width, int height, @DrawableRes int id) {
|
||||||
|
@ -2,8 +2,10 @@ package org.thoughtcrime.securesms.crypto.storage;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.jobs.IdentityUpdateJob;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
@ -36,8 +38,22 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
|
public boolean isTrustedIdentity(String name, IdentityKey identityKey) {
|
||||||
long recipientId = RecipientFactory.getRecipientsFromString(context, name, true).getPrimaryRecipient().getRecipientId();
|
long recipientId = RecipientFactory.getRecipientsFromString(context, name, true).getPrimaryRecipient().getRecipientId();
|
||||||
return DatabaseFactory.getIdentityDatabase(context)
|
boolean trusted = DatabaseFactory.getIdentityDatabase(context)
|
||||||
.isValidIdentity(recipientId, identityKey);
|
.isValidIdentity(recipientId, identityKey);
|
||||||
|
|
||||||
|
if (trusted) {
|
||||||
|
return true;
|
||||||
|
} else if (!TextSecurePreferences.isBlockingIdentityUpdates(context)) {
|
||||||
|
saveIdentity(name, identityKey);
|
||||||
|
|
||||||
|
ApplicationContext.getInstance(context)
|
||||||
|
.getJobManager()
|
||||||
|
.add(new IdentityUpdateJob(context, recipientId));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
type |= Types.END_SESSION_BIT;
|
type |= Types.END_SESSION_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT;
|
if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT;
|
||||||
|
if (message.isIdentityUpdate()) type |= Types.KEY_EXCHANGE_IDENTITY_UPDATE_BIT;
|
||||||
|
|
||||||
Recipients recipients;
|
Recipients recipients;
|
||||||
|
|
||||||
@ -508,8 +509,9 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
groupRecipients = RecipientFactory.getRecipientsFromString(context, message.getGroupId(), true);
|
groupRecipients = RecipientFactory.getRecipientsFromString(context, message.getGroupId(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean unread = org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
||||||
message.isSecureMessage() || message.isGroup() || message.isPreKeyBundle();
|
message.isSecureMessage() || message.isGroup() || message.isPreKeyBundle()) &&
|
||||||
|
!message.isIdentityUpdate();
|
||||||
|
|
||||||
long threadId;
|
long threadId;
|
||||||
|
|
||||||
@ -542,7 +544,10 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
if (!message.isIdentityUpdate()) {
|
||||||
|
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||||
|
}
|
||||||
|
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
jobManager.add(new TrimThreadJob(context, threadId));
|
jobManager.add(new TrimThreadJob(context, threadId));
|
||||||
|
|
||||||
|
@ -110,8 +110,10 @@ public abstract class MessageRecord extends DisplayRecord {
|
|||||||
return emphasisAdded(context.getString(R.string.MessageRecord_s_is_on_signal_say_hey, getIndividualRecipient().toShortString()));
|
return emphasisAdded(context.getString(R.string.MessageRecord_s_is_on_signal_say_hey, getIndividualRecipient().toShortString()));
|
||||||
} else if (isExpirationTimerUpdate()) {
|
} else if (isExpirationTimerUpdate()) {
|
||||||
String sender = isOutgoing() ? context.getString(R.string.MessageRecord_you) : getIndividualRecipient().toShortString();
|
String sender = isOutgoing() ? context.getString(R.string.MessageRecord_you) : getIndividualRecipient().toShortString();
|
||||||
String time = ExpirationUtil.getExpirationDisplayValue(context, (int)(getExpiresIn() / 1000));
|
String time = ExpirationUtil.getExpirationDisplayValue(context, (int) (getExpiresIn() / 1000));
|
||||||
return emphasisAdded(context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, sender, time));
|
return emphasisAdded(context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, sender, time));
|
||||||
|
} else if (isIdentityUpdate()) {
|
||||||
|
return emphasisAdded(String.format("Your safety numbers with %s have changed", getIndividualRecipient().toShortString()));
|
||||||
} else if (getBody().getBody().length() > MAX_DISPLAY_LENGTH) {
|
} else if (getBody().getBody().length() > MAX_DISPLAY_LENGTH) {
|
||||||
return new SpannableString(getBody().getBody().substring(0, MAX_DISPLAY_LENGTH));
|
return new SpannableString(getBody().getBody().substring(0, MAX_DISPLAY_LENGTH));
|
||||||
}
|
}
|
||||||
|
@ -75,9 +75,7 @@ public class SmsMessageRecord extends MessageRecord {
|
|||||||
} else if (MmsSmsColumns.Types.isLegacyType(type)) {
|
} else if (MmsSmsColumns.Types.isLegacyType(type)) {
|
||||||
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
|
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
|
||||||
} else if (isBundleKeyExchange()) {
|
} else if (isBundleKeyExchange()) {
|
||||||
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_unknown_identity_key_tap_to_process));
|
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_new_safety_numbers_tap_to_process));
|
||||||
} else if (isIdentityUpdate()) {
|
|
||||||
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_updated_but_unknown_identity_information));
|
|
||||||
} else if (isKeyExchange() && isOutgoing()) {
|
} else if (isKeyExchange() && isOutgoing()) {
|
||||||
return new SpannableString("");
|
return new SpannableString("");
|
||||||
} else if (isKeyExchange() && !isOutgoing()) {
|
} else if (isKeyExchange() && !isOutgoing()) {
|
||||||
|
@ -100,8 +100,10 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
} else if (SmsDatabase.Types.isJoinedType(type)) {
|
} else if (SmsDatabase.Types.isJoinedType(type)) {
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal_say_hey, getRecipients().getPrimaryRecipient().toShortString()));
|
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal_say_hey, getRecipients().getPrimaryRecipient().toShortString()));
|
||||||
} else if (SmsDatabase.Types.isExpirationTimerUpdate(type)) {
|
} else if (SmsDatabase.Types.isExpirationTimerUpdate(type)) {
|
||||||
String time = ExpirationUtil.getExpirationDisplayValue(context, (int)(getExpiresIn() / 1000));
|
String time = ExpirationUtil.getExpirationDisplayValue(context, (int) (getExpiresIn() / 1000));
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
|
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
|
||||||
|
} else if (SmsDatabase.Types.isIdentityUpdate(type)) {
|
||||||
|
return emphasisAdded(String.format("Your safety numbers with %s have changed", getRecipients().getPrimaryRecipient().toShortString()));
|
||||||
} else {
|
} else {
|
||||||
if (TextUtils.isEmpty(getBody().getBody())) {
|
if (TextUtils.isEmpty(getBody().getBody())) {
|
||||||
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
|
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
|
||||||
|
75
src/org/thoughtcrime/securesms/jobs/IdentityUpdateJob.java
Normal file
75
src/org/thoughtcrime/securesms/jobs/IdentityUpdateJob.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
|
||||||
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||||
|
|
||||||
|
public class IdentityUpdateJob extends MasterSecretJob {
|
||||||
|
|
||||||
|
private final long recipientId;
|
||||||
|
|
||||||
|
public IdentityUpdateJob(Context context, long recipientId) {
|
||||||
|
super(context, JobParameters.newBuilder()
|
||||||
|
.withGroupId(IdentityUpdateJob.class.getName())
|
||||||
|
.withPersistence()
|
||||||
|
.create());
|
||||||
|
this.recipientId = recipientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRun(MasterSecret masterSecret) throws Exception {
|
||||||
|
Recipient recipient = RecipientFactory.getRecipientForId(context, recipientId, true);
|
||||||
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, recipient, true);
|
||||||
|
String number = recipient.getNumber();
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||||
|
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||||
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
|
GroupDatabase.Reader reader = groupDatabase.getGroups();
|
||||||
|
|
||||||
|
GroupDatabase.GroupRecord groupRecord;
|
||||||
|
|
||||||
|
while ((groupRecord = reader.getNext()) != null) {
|
||||||
|
if (groupRecord.getMembers().contains(number)) {
|
||||||
|
SignalServiceGroup group = new SignalServiceGroup(groupRecord.getId());
|
||||||
|
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.of(group), 0);
|
||||||
|
IncomingIdentityUpdateMessage groupUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
|
|
||||||
|
smsDatabase.insertMessageInbox(groupUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (threadDatabase.getThreadIdIfExistsFor(recipients) != -1) {
|
||||||
|
IncomingTextMessage incoming = new IncomingTextMessage(number, 1, time, null, Optional.<SignalServiceGroup>absent(), 0);
|
||||||
|
IncomingIdentityUpdateMessage individualUpdate = new IncomingIdentityUpdateMessage(incoming);
|
||||||
|
smsDatabase.insertMessageInbox(individualUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onShouldRetryThrowable(Exception exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAdded() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCanceled() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.thoughtcrime.securesms.sms;
|
||||||
|
|
||||||
|
public class IncomingIdentityUpdateMessage extends IncomingTextMessage {
|
||||||
|
|
||||||
|
public IncomingIdentityUpdateMessage(IncomingTextMessage base) {
|
||||||
|
super(base, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIdentityUpdate() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -215,6 +215,10 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIdentityUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
|
51
src/org/thoughtcrime/securesms/util/IdentityUtil.java
Normal file
51
src/org/thoughtcrime/securesms/util/IdentityUtil.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package org.thoughtcrime.securesms.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
|
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||||
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
|
import org.whispersystems.libsignal.state.SessionRecord;
|
||||||
|
import org.whispersystems.libsignal.state.SessionStore;
|
||||||
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
|
public class IdentityUtil {
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
public static ListenableFuture<Optional<IdentityKey>> getRemoteIdentityKey(final Context context,
|
||||||
|
final MasterSecret masterSecret,
|
||||||
|
final Recipient recipient)
|
||||||
|
{
|
||||||
|
final SettableFuture<Optional<IdentityKey>> future = new SettableFuture<>();
|
||||||
|
|
||||||
|
new AsyncTask<Recipient, Void, Optional<IdentityKey>>() {
|
||||||
|
@Override
|
||||||
|
protected Optional<IdentityKey> doInBackground(Recipient... recipient) {
|
||||||
|
SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
|
||||||
|
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(recipient[0].getNumber(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||||
|
SessionRecord record = sessionStore.loadSession(axolotlAddress);
|
||||||
|
|
||||||
|
if (record == null) {
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.fromNullable(record.getSessionState().getRemoteIdentityKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Optional<IdentityKey> result) {
|
||||||
|
future.set(result);
|
||||||
|
}
|
||||||
|
}.execute(recipient);
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -73,6 +73,7 @@ public class TextSecurePreferences {
|
|||||||
private static final String SIGNALING_KEY_PREF = "pref_signaling_key";
|
private static final String SIGNALING_KEY_PREF = "pref_signaling_key";
|
||||||
private static final String DIRECTORY_FRESH_TIME_PREF = "pref_directory_refresh_time";
|
private static final String DIRECTORY_FRESH_TIME_PREF = "pref_directory_refresh_time";
|
||||||
private static final String IN_THREAD_NOTIFICATION_PREF = "pref_key_inthread_notifications";
|
private static final String IN_THREAD_NOTIFICATION_PREF = "pref_key_inthread_notifications";
|
||||||
|
private static final String BLOCKING_IDENTITY_CHANGES_PREF = "pref_blocking_identity_changes";
|
||||||
|
|
||||||
private static final String LOCAL_REGISTRATION_ID_PREF = "pref_local_registration_id";
|
private static final String LOCAL_REGISTRATION_ID_PREF = "pref_local_registration_id";
|
||||||
private static final String SIGNED_PREKEY_REGISTERED_PREF = "pref_signed_prekey_registered";
|
private static final String SIGNED_PREKEY_REGISTERED_PREF = "pref_signed_prekey_registered";
|
||||||
@ -113,6 +114,14 @@ public class TextSecurePreferences {
|
|||||||
return getBooleanPreference(context, MULTI_DEVICE_PROVISIONED_PREF, false);
|
return getBooleanPreference(context, MULTI_DEVICE_PROVISIONED_PREF, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isBlockingIdentityUpdates(Context context) {
|
||||||
|
return getBooleanPreference(context, BLOCKING_IDENTITY_CHANGES_PREF, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setBlockingIdentityUpdates(Context context, boolean value) {
|
||||||
|
setBooleanPreference(context, BLOCKING_IDENTITY_CHANGES_PREF, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
|
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
|
||||||
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
|
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user