Add end-to-end encryption check for conference

This commit is contained in:
Benoit Martins 2026-03-24 14:41:15 +01:00
parent b84bd1faf3
commit 127e12b384
5 changed files with 75 additions and 103 deletions

View file

@ -1,7 +1,7 @@
import Foundation
public enum AppGitInfo {
public static let branch = "feature/address_selector"
public static let commit = "dcfa42329"
public static let branch = "master"
public static let commit = "b84bd1faf"
public static let tag = "6.1.0-alpha"
}

View file

@ -131,7 +131,6 @@
"call_history_deleted_toast" = "History has been deleted";
"call_not_encrypted" = "Call is not encrypted";
"call_outgoing" = "Outgoing call";
"call_srtp_point_to_point_encrypted" = "Point-to-point encrypted by SRTP";
"call_state_connected" = "Active";
"call_state_paused" = "Paused";
"call_state_paused_by_remote" = "Paused by remote";
@ -148,7 +147,12 @@
"call_transfer_in_progress_toast" = "Call is being transferred";
"call_transfer_successful_toast" = "Call has been successfully transferred";
"call_waiting_for_encryption_info" = "Waiting for encryption…";
"call_conference_end_to_end_encrypted" = "End-to-end encrypted";
"call_zrtp_point_to_point_encrypted" = "Point-to-point encrypted by ZRTP";
"call_srtp_point_to_point_encrypted" = "Point-to-point encrypted by SRTP";
"call_zrtp_end_to_end_encrypted" = "End-to-end encrypted by ZRTP";
"call_zrtp_sas_validation_required" = "Validation required";
"call_zrtp_sas_validation_skip" = "Skip";
"calls_count_label" = "%@ calls";

View file

@ -131,7 +131,6 @@
"call_history_deleted_toast" = "Historique supprimé";
"call_not_encrypted" = "Appel non chiffré";
"call_outgoing" = "Appel sortant";
"call_srtp_point_to_point_encrypted" = "Appel chiffré de point à point";
"call_state_connected" = "Actif";
"call_state_paused" = "En pause";
"call_state_paused_by_remote" = "Mis en pause par le correspondant";
@ -148,7 +147,12 @@
"call_transfer_in_progress_toast" = "Transfert en cours";
"call_transfer_successful_toast" = "Appel transféré";
"call_waiting_for_encryption_info" = "En attente du chiffrement…";
"call_conference_end_to_end_encrypted" = "Conférence chiffrée de bout en bout";
"call_zrtp_point_to_point_encrypted" = "Appel chiffré de point à point";
"call_srtp_point_to_point_encrypted" = "Appel chiffré de point à point";
"call_zrtp_end_to_end_encrypted" = "Appel chiffré de bout en bout";
"call_zrtp_sas_validation_required" = "Vérification nécessaire";
"call_zrtp_sas_validation_skip" = "Passer";
"calls_count_label" = "%@ appels";

View file

@ -337,118 +337,78 @@ struct CallView: View {
.zIndex(1)
if !telecomManager.outgoingCallStarted && telecomManager.callInProgress {
if callViewModel.isMediaEncrypted && callViewModel.isRemoteDeviceTrusted && callViewModel.isZrtp {
HStack {
Image("lock-key")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.blueInfo500)
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
// Compute the image, text, and color before the HStack
let encryptionInfo: (image: String, textKey: LocalizedStringKey, color: Color) = {
if callViewModel.isMediaEncrypted && callViewModel.isRemoteDeviceTrusted && callViewModel.isZrtp {
// Encrypted call, ZRTP, device trusted
let key: LocalizedStringKey = {
if callViewModel.isConference {
if callViewModel.isEndToEndEncrypted {
return LocalizedStringKey("call_conference_end_to_end_encrypted")
} else if callViewModel.isZrtp {
return LocalizedStringKey("call_zrtp_point_to_point_encrypted")
} else {
return LocalizedStringKey("call_srtp_point_to_point_encrypted")
}
} else {
if callViewModel.isZrtp {
return LocalizedStringKey("call_zrtp_end_to_end_encrypted")
} else {
return LocalizedStringKey("call_srtp_point_to_point_encrypted")
}
}
}()
return ("lock-key", key, Color.blueInfo500)
Text(callViewModel.isConference ? "call_srtp_point_to_point_encrypted" : "call_zrtp_end_to_end_encrypted")
.foregroundStyle(Color.blueInfo500)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
} else if callViewModel.isMediaEncrypted && !callViewModel.isZrtp {
// Encrypted call, SRTP
return ("lock_simple", LocalizedStringKey("call_srtp_point_to_point_encrypted"), Color.blueInfo500)
Spacer()
}
.onTapGesture {
mediaEncryptedSheet = true
}
.frame(height: topBarHeight)
.padding(.leading, geometry.safeAreaInsets.leading)
.zIndex(1)
} else if callViewModel.isMediaEncrypted && !callViewModel.isZrtp {
HStack {
Image("lock_simple")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.blueInfo500)
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
} else if callViewModel.isMediaEncrypted && (!callViewModel.isRemoteDeviceTrusted && callViewModel.isZrtp) || callViewModel.cacheMismatch {
// ZRTP warning
return ("warning-circle", LocalizedStringKey("call_zrtp_sas_validation_required"), Color.orangeWarning600)
Text("call_srtp_point_to_point_encrypted")
.foregroundStyle(Color.blueInfo500)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
} else if callViewModel.isNotEncrypted {
// Not encrypted
return ("lock-simple-open", LocalizedStringKey("call_not_encrypted"), .white)
Spacer()
} else {
// Waiting for encryption info
return ("progress", LocalizedStringKey("call_waiting_for_encryption_info"), .white)
}
.onTapGesture {
mediaEncryptedSheet = true
}
.frame(height: topBarHeight)
.padding(.leading, geometry.safeAreaInsets.leading)
.zIndex(1)
} else if callViewModel.isMediaEncrypted && (!callViewModel.isRemoteDeviceTrusted && callViewModel.isZrtp) || callViewModel.cacheMismatch {
HStack {
Image("warning-circle")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.orangeWarning600)
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
Text("call_zrtp_sas_validation_required")
.foregroundStyle(Color.orangeWarning600)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
Spacer()
}
.onTapGesture {
mediaEncryptedSheet = true
}
.frame(height: topBarHeight)
.padding(.leading, geometry.safeAreaInsets.leading)
.zIndex(1)
} else if callViewModel.isNotEncrypted {
HStack {
Image("lock-simple-open")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
Text("call_not_encrypted")
.foregroundStyle(.white)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
Spacer()
}
.onTapGesture {
mediaEncryptedSheet = true
}
.frame(height: topBarHeight)
.padding(.leading, geometry.safeAreaInsets.leading)
.zIndex(1)
} else {
HStack {
}()
HStack {
if encryptionInfo.image == "progress" {
ProgressView()
.controlSize(.mini)
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.progressViewStyle(CircularProgressViewStyle(tint: encryptionInfo.color))
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
Text("call_waiting_for_encryption_info")
.foregroundStyle(.white)
.default_text_style_white(styleSize: 12)
} else {
Image(encryptionInfo.image)
.renderingMode(.template)
.resizable()
.foregroundStyle(encryptionInfo.color)
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
Spacer()
}
.frame(height: topBarHeight)
.padding(.leading, geometry.safeAreaInsets.leading)
.zIndex(1)
Text(encryptionInfo.textKey)
.foregroundStyle(encryptionInfo.color)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
Spacer()
}
.onTapGesture {
mediaEncryptedSheet = true
}
.frame(height: topBarHeight)
.padding(.leading, geometry.safeAreaInsets.leading)
.zIndex(1)
}
}
.frame(height: topBarHeight)

View file

@ -49,6 +49,7 @@ class CallViewModel: ObservableObject {
@Published var zrtpPopupDisplayed: Bool = false
@Published var upperCaseAuthTokenToRead = ""
@Published var upperCaseAuthTokenToListen = ""
@Published var isEndToEndEncrypted: Bool = false
@Published var isMediaEncrypted: Bool = false
@Published var isNotEncrypted: Bool = false
@Published var isZrtp: Bool = false
@ -259,6 +260,7 @@ class CallViewModel: ObservableObject {
}
var displayNameTmp = ""
var isEndToEndEncryptedTmp = false
var isOneOneCallTmp = false
if self.currentCall?.remoteAddress != nil {
@ -268,6 +270,7 @@ class CallViewModel: ObservableObject {
isOneOneCallTmp = true
} else {
displayNameTmp = confInfo?.subject ?? "Conference-focus"
isEndToEndEncryptedTmp = confInfo?.securityLevel == .EndToEnd || conf?.currentParams?.securityLevel == .EndToEnd
}
}
@ -376,6 +379,7 @@ class CallViewModel: ObservableObject {
self.videoDisplayed = videoDisplayedTmp
self.isOneOneCall = isOneOneCallTmp
self.isEndToEndEncrypted = isEndToEndEncryptedTmp
self.isMediaEncrypted = isMediaEncryptedTmp
self.isNotEncrypted = false
self.isZrtp = isZrtpTmp