core, ui: confirm before connecting a call answered without e2e encryption (#7647)

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
spaced4ndyandEvgeny Poberezkin authored and GitHub committed 2026-10-05 09:45:57 +01:00
1 parent b79223fe5c
commit 86671a1699
4 files changed
+86 -25

No files matched your search

@@ -3371,20 +3371,13 @@ object ChatController {
chatModel.callManager.reportNewIncomingCall(r.callInvitation.copy(remoteHostId = rhId))
}
is CR.CallOffer -> {
// TODO askConfirmation?
// TODO check encryption is compatible
withCall(r, r.contact) { call ->
chatModel.activeCall.value = call.copy(callState = CallState.OfferReceived, hasSharedKey = r.sharedKey != null)
val useRelay = appPrefs.webrtcPolicyRelay.get()
val iceServers = getIceServers()
chatModel.callCommand.add(WCallCommand.Offer(
offer = r.offer.rtcSession,
iceCandidates = r.offer.rtcIceCandidates,
media = r.callType.media,
aesKey = r.sharedKey,
iceServers = iceServers,
relay = useRelay
))
if (r.askConfirmation) {
showUnencryptedCallAlert(call) { processCallOffer(r) }
} else {
processCallOffer(r)
}
}
}
is CR.CallAnswer -> {
@@ -3640,6 +3633,39 @@ object ChatController {
}
}
private fun processCallOffer(r: CR.CallOffer) {
val useRelay = appPrefs.webrtcPolicyRelay.get()
val iceServers = getIceServers()
chatModel.callCommand.add(WCallCommand.Offer(
offer = r.offer.rtcSession,
iceCandidates = r.offer.rtcIceCandidates,
media = r.callType.media,
aesKey = r.sharedKey,
iceServers = iceServers,
relay = useRelay
))
}
private fun showUnencryptedCallAlert(call: Call, onContinue: () -> Unit) {
// the call may have ended, or a new one started with the same contact, while the alert was shown
fun offerPending(): Boolean {
val c = chatModel.activeCall.value
return c != null && c.remoteHostId == call.remoteHostId && c.contact.id == call.contact.id && c.callState == CallState.OfferReceived
}
val endCall = { if (offerPending()) withBGApi { chatModel.callManager.endCall(call) } }
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.call_not_encrypted_title),
text = generalGetString(MR.strings.call_not_encrypted_desc).format(call.contact.displayName),
confirmText = generalGetString(MR.strings.call_service_notification_end_call),
onConfirm = { endCall() },
dismissText = generalGetString(MR.strings.continue_to_next_step),
onDismiss = { if (offerPending()) onContinue() },
onDismissRequest = { endCall() },
destructive = true,
parseHtml = false
)
}
suspend fun leaveGroup(rh: Long?, groupId: Long) {
val groupInfo = apiLeaveGroup(rh, groupId)
if (groupInfo != null) {
@@ -1415,6 +1415,8 @@
<string name="status_no_e2e_encryption">no e2e encryption</string>
<string name="status_contact_has_e2e_encryption">contact has e2e encryption</string>
<string name="status_contact_has_no_e2e_encryption">contact has no e2e encryption</string>
<string name="call_not_encrypted_title">Call is not encrypted</string>
<string name="call_not_encrypted_desc">%s accepted the call without end-to-end encryption.</string>
<string name="call_connection_peer_to_peer">peer-to-peer</string>
<string name="call_connection_via_relay">via relay</string>
<string name="icon_descr_hang_up">Hang up</string>