From 40c52a31c90c8ab2bf21b880a9f535263dda4ac6 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Tue, 23 Aug 2022 16:48:57 -0400 Subject: [PATCH] Fix race condition when joining a group call. --- .../service/webrtc/GroupActionProcessor.java | 24 ++++++++++- .../service/webrtc/SignalCallManager.java | 41 ++++++++----------- .../service/webrtc/WebRtcActionProcessor.java | 7 +++- .../service/webrtc/WebRtcInteractor.java | 5 +++ 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java index 2964936282..7a4aca1db5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java @@ -125,8 +125,30 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { } @Override - protected @NonNull WebRtcServiceState handleGroupRequestMembershipProof(@NonNull WebRtcServiceState currentState, int groupCallHash, @NonNull byte[] groupMembershipToken) { + protected @NonNull WebRtcServiceState handleGroupRequestMembershipProof(@NonNull WebRtcServiceState currentState, int groupCallHashCode) { Log.i(tag, "handleGroupRequestMembershipProof():"); + Recipient recipient = currentState.getCallInfoState().getCallRecipient(); + if (!recipient.isPushV2Group()) { + Log.i(tag, "Request membership proof for non-group"); + return currentState; + } + + GroupCall currentGroupCall = currentState.getCallInfoState().getGroupCall(); + + if (currentGroupCall == null || currentGroupCall.hashCode() != groupCallHashCode) { + Log.i(tag, "Skipping group membership proof request, requested group call does not match current group call"); + return currentState; + } + + //noinspection OptionalGetWithoutIsPresent + webRtcInteractor.requestGroupMembershipProof(recipient.getGroupId().get().requireV2(), groupCallHashCode); + + return currentState; + } + + @Override + protected @NonNull WebRtcServiceState handleGroupMembershipProofResponse(@NonNull WebRtcServiceState currentState, int groupCallHash, @NonNull byte[] groupMembershipToken) { + Log.i(tag, "handleGroupMembershipProofResponse():"); GroupCall groupCall = currentState.getCallInfoState().getGroupCall(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java index 56542c5f3f..d66511de3e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/SignalCallManager.java @@ -388,6 +388,21 @@ private void processStateless(@NonNull Function1 { + try { + GroupExternalCredential credential = GroupManager.getGroupExternalCredential(context, groupId); + process((s, p) -> p.handleGroupMembershipProofResponse(s, groupCallHashCode, credential.getTokenBytes().toByteArray())); + } catch (IOException e) { + Log.w(TAG, "Unable to get group membership proof from service", e); + process((s, p) -> p.handleGroupCallEnded(s, groupCallHashCode, GroupCall.GroupCallEndReason.SFU_CLIENT_FAILED_TO_JOIN)); + } catch (VerificationFailedException e) { + Log.w(TAG, "Unable to verify group membership proof", e); + process((s, p) -> p.handleGroupCallEnded(s, groupCallHashCode, GroupCall.GroupCallEndReason.DEVICE_EXPLICITLY_DISCONNECTED)); + } + }); + } + public boolean startCallCardActivityIfPossible() { if (Build.VERSION.SDK_INT >= 29 && !ApplicationDependencies.getAppForegroundObserver().isForegrounded()) { return false; @@ -744,31 +759,7 @@ private void processStateless(@NonNull Function1 { - try { - GroupExternalCredential credential = GroupManager.getGroupExternalCredential(context, recipient.getGroupId().get().requireV2()); - process((s, p) -> p.handleGroupRequestMembershipProof(s, groupCall.hashCode(), credential.getTokenBytes().toByteArray())); - } catch (IOException e) { - Log.w(TAG, "Unable to get group membership proof from service", e); - onEnded(groupCall, GroupCall.GroupCallEndReason.SFU_CLIENT_FAILED_TO_JOIN); - } catch (VerificationFailedException e) { - Log.w(TAG, "Unable to verify group membership proof", e); - onEnded(groupCall, GroupCall.GroupCallEndReason.DEVICE_EXPLICITLY_DISCONNECTED); - } - }); + process((s, p) -> p.handleGroupRequestMembershipProof(s, groupCall.hashCode())); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java index 425266703a..18b4b64bcf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java @@ -726,11 +726,16 @@ public abstract class WebRtcActionProcessor { return currentState; } - protected @NonNull WebRtcServiceState handleGroupRequestMembershipProof(@NonNull WebRtcServiceState currentState, int groupCallHash, @NonNull byte[] groupMembershipToken) { + protected @NonNull WebRtcServiceState handleGroupRequestMembershipProof(@NonNull WebRtcServiceState currentState, int groupCallHashCode) { Log.i(tag, "handleGroupRequestMembershipProof not processed"); return currentState; } + protected @NonNull WebRtcServiceState handleGroupMembershipProofResponse(@NonNull WebRtcServiceState currentState, int groupCallHash, @NonNull byte[] groupMembershipToken) { + Log.i(tag, "handleGroupMembershipProofResponse not processed"); + return currentState; + } + protected @NonNull WebRtcServiceState handleGroupRequestUpdateMembers(@NonNull WebRtcServiceState currentState) { Log.i(tag, "handleGroupRequestUpdateMembers not processed"); return currentState; diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java index 02f9eb059e..8f4cb81c80 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcInteractor.java @@ -8,6 +8,7 @@ import androidx.annotation.Nullable; import org.signal.ringrtc.CallManager; import org.signal.ringrtc.GroupCall; +import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.ringrtc.CameraEventListener; @@ -182,4 +183,8 @@ public class WebRtcInteractor { public boolean addNewOutgoingCall(RecipientId recipientId, long callId, boolean isVideoCall) { return AndroidTelecomUtil.addOutgoingCall(recipientId, callId, isVideoCall); } + + public void requestGroupMembershipProof(GroupId.V2 groupId, int groupCallHashCode) { + signalCallManager.requestGroupMembershipToken(groupId, groupCallHashCode); + } }