diff --git a/res/values/strings.xml b/res/values/strings.xml index cf7c7cf0e..849768a2b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1155,6 +1155,9 @@ Disable Signal\'s built-in emoji support Video calling beta Support for next-generation video and voice calls when enabled by both parties. This feature is in beta. + Relay all calls through the Signal server to avoid revealing your IP address to your contact. Enabling will reduce call quality. + Always relay calls + diff --git a/res/xml/preferences_advanced.xml b/res/xml/preferences_advanced.xml index 6bd81a1ca..14ae8e11f 100644 --- a/res/xml/preferences_advanced.xml +++ b/res/xml/preferences_advanced.xml @@ -25,6 +25,12 @@ android:title="@string/preferences_advanced__video_calling_beta" android:summary="@string/preferences_advanced__enable_support_for_next_generation_video_and_voice_calls"/> + + diff --git a/res/xml/preferences_app_protection.xml b/res/xml/preferences_app_protection.xml index 91a392847..1cde21912 100644 --- a/res/xml/preferences_app_protection.xml +++ b/res/xml/preferences_app_protection.xml @@ -33,7 +33,7 @@ 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"/> - + diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java index 222b1e83b..098b9bc68 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java @@ -61,6 +61,23 @@ public class ContactAccessor { return instance; } + public boolean isSystemContact(Context context, String number) { + Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + String[] projection = new String[]{PhoneLookup.DISPLAY_NAME, PhoneLookup.LOOKUP_KEY, + PhoneLookup._ID, PhoneLookup.NUMBER}; + Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); + + try { + if (cursor != null && cursor.moveToFirst()) { + return true; + } + } finally { + if (cursor != null) cursor.close(); + } + + return false; + } + public Collection getContactsWithPush(Context context) { final ContentResolver resolver = context.getContentResolver(); final String[] inProjection = new String[]{PhoneLookup._ID, PhoneLookup.DISPLAY_NAME}; diff --git a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java index c204705e2..7afcd7f99 100644 --- a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -29,6 +29,7 @@ import org.thoughtcrime.redphone.util.AudioUtils; import org.thoughtcrime.redphone.util.UncaughtExceptionHandlerManager; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.WebRtcCallActivity; +import org.thoughtcrime.securesms.contacts.ContactAccessor; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory; @@ -40,6 +41,7 @@ import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.ServiceUtil; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.webrtc.CallNotificationManager; import org.thoughtcrime.securesms.webrtc.PeerConnectionFactoryOptions; @@ -279,7 +281,10 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo @Override public void onSuccessContinue(List result) { try { - WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result); + boolean isSystemContact = ContactAccessor.getInstance().isSystemContact(WebRtcCallService.this, recipient.getNumber()); + boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this); + + WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, !isSystemContact || isAlwaysTurn); WebRtcCallService.this.peerConnection.setRemoteDescription(new SessionDescription(SessionDescription.Type.OFFER, offer)); WebRtcCallService.this.lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING); @@ -330,7 +335,9 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo @Override public void onSuccessContinue(List result) { try { - WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result); + boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this); + + WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, isAlwaysTurn); WebRtcCallService.this.dataChannel = WebRtcCallService.this.peerConnection.createDataChannel(DATA_CHANNEL_NAME); WebRtcCallService.this.dataChannel.registerObserver(WebRtcCallService.this); diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 26c3092e8..da99e2100 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -99,6 +99,11 @@ public class TextSecurePreferences { public static final String SYSTEM_EMOJI_PREF = "pref_system_emoji"; private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device"; public static final String DIRECT_CAPTURE_CAMERA_ID = "pref_direct_capture_camera_id"; + private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only"; + + public static boolean isTurnOnly(Context context) { + return getBooleanPreference(context, ALWAYS_RELAY_CALLS_PREF, false); + } public static boolean isWebrtcCallingEnabled(Context context) { return getBooleanPreference(context, WEBRTC_CALLING_PREF, false); diff --git a/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java index 5fc66e8f0..8bf5741c9 100644 --- a/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java +++ b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java @@ -47,7 +47,8 @@ public class PeerConnectionWrapper { @NonNull PeerConnectionFactory factory, @NonNull PeerConnection.Observer observer, @NonNull VideoRenderer.Callbacks localRenderer, - @NonNull List turnServers) + @NonNull List turnServers, + boolean hideIp) { List iceServers = new LinkedList<>(); iceServers.add(STUN_SERVER); @@ -60,6 +61,10 @@ public class PeerConnectionWrapper { configuration.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE; configuration.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE; + if (hideIp) { + configuration.iceTransportsType = PeerConnection.IceTransportsType.RELAY; + } + constraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); audioConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));