Change ZRTP SAS UI

This commit is contained in:
Benoit Martins 2024-06-27 11:50:43 +02:00
parent 8875e2ba54
commit 4b46322264
13 changed files with 900 additions and 191 deletions

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "lock-key.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M128,112a28,28,0,0,0-8,54.83V184a8,8,0,0,0,16,0V166.83A28,28,0,0,0,128,112Zm0,40a12,12,0,1,1,12-12A12,12,0,0,1,128,152Zm80-72H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Z"></path></svg>

After

Width:  |  Height:  |  Size: 417 B

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "security.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="S&#195;&#169;curit&#195;&#169;">
<path id="Vector" d="M23 2.52647V9.2355C23 19.4652 14.3123 22.8591 12.5729 23.4356C12.2014 23.5614 11.7986 23.5614 11.4271 23.4356C9.68542 22.8591 1 19.4652 1 9.2355V2.52647C1 2.04205 1.19315 1.57747 1.53697 1.23493C1.88079 0.892387 2.3471 0.699951 2.83333 0.699951H21.1667C21.6529 0.699951 22.1192 0.892387 22.463 1.23493C22.8068 1.57747 23 2.04205 23 2.52647Z" fill="#364860"/>
<path id="Vector_2" d="M20.3333 1.59998H3.66667C3.22464 1.59998 2.80072 1.77557 2.48816 2.08813C2.17559 2.40069 2 2.82461 2 3.26664V9.38852C2 18.7229 9.89792 21.8198 11.4792 22.3458C11.8169 22.4607 12.1831 22.4607 12.5208 22.3458C14.1042 21.8198 22 18.7229 22 9.38852V3.26664C22 2.82461 21.8244 2.40069 21.5118 2.08813C21.1993 1.77557 20.7754 1.59998 20.3333 1.59998ZM16.7563 8.85623L10.9229 14.6896C10.8455 14.767 10.7536 14.8285 10.6525 14.8704C10.5513 14.9124 10.4428 14.934 10.3333 14.934C10.2238 14.934 10.1154 14.9124 10.0142 14.8704C9.91305 14.8285 9.82114 14.767 9.74375 14.6896L7.24375 12.1896C7.08738 12.0332 6.99954 11.8211 6.99954 11.6C6.99954 11.3788 7.08738 11.1668 7.24375 11.0104C7.40012 10.854 7.6122 10.7662 7.83333 10.7662C8.05447 10.7662 8.26655 10.854 8.42292 11.0104L10.3333 12.9208L15.5771 7.67706C15.6545 7.59963 15.7464 7.53822 15.8476 7.49631C15.9487 7.45441 16.0572 7.43285 16.1667 7.43285C16.2762 7.43285 16.3846 7.45441 16.4857 7.49631C16.5869 7.53822 16.6788 7.59963 16.7563 7.67706C16.8337 7.75448 16.8951 7.8464 16.937 7.94756C16.9789 8.04872 17.0005 8.15715 17.0005 8.26664C17.0005 8.37614 16.9789 8.48456 16.937 8.58572C16.8951 8.68688 16.8337 8.7788 16.7563 8.85623Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "shield-warning.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M120,136V96a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm8,48a12,12,0,1,0-12-12A12,12,0,0,0,128,184ZM224,56v56c0,52.72-25.52,84.67-46.93,102.19-23.06,18.86-46,25.27-47,25.53a8,8,0,0,1-4.2,0c-1-.26-23.91-6.67-47-25.53C57.52,196.67,32,164.72,32,112V56A16,16,0,0,1,48,40H208A16,16,0,0,1,224,56Zm-16,0L48,56l0,56c0,37.3,13.82,67.51,41.07,89.81A128.25,128.25,0,0,0,128,223.62a129.3,129.3,0,0,0,39.41-22.2C194.34,179.16,208,149.07,208,112Z"></path></svg>

After

Width:  |  Height:  |  Size: 546 B

View file

@ -204,9 +204,6 @@
},
"Appel" : {
},
"Appel chiffré de bout en bout" : {
},
"assistant_account_create" : {
"localizations" : {
@ -421,6 +418,278 @@
},
"Call transfer failed!" : {
},
"call_action_hang_up" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hang up"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Raccrocher"
}
}
}
},
"call_dialog_zrtp_security_alert_message" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "This call confidentiality may be compromise!"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "La confidentialité de votre appel peut être compromise !"
}
}
}
},
"call_dialog_zrtp_security_alert_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Security alert"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Alerte de sécurité"
}
}
}
},
"call_dialog_zrtp_security_alert_try_again" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Try again"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Réessayer"
}
}
}
},
"call_dialog_zrtp_validate_trust_letters_do_not_match" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nothing matches"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Aucune correspondance"
}
}
}
},
"call_dialog_zrtp_validate_trust_local_code_label" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Your code:"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Votre code :"
}
}
}
},
"call_dialog_zrtp_validate_trust_message" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "For your safety, we need to authenticate your correspondent device.Please exchange your codes:"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Pour garantir le chiffrement, nous avons besoin dauthentifier lappareil de votre correspondant.Veuillez échanger vos codes :"
}
}
}
},
"call_dialog_zrtp_validate_trust_remote_code_label" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Correspondent code:"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Code correspondant :"
}
}
}
},
"call_dialog_zrtp_validate_trust_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Validate the device"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Vérification de sécurité"
}
}
}
},
"call_dialog_zrtp_validate_trust_warning_message" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "For your safety, we need to re-authenticate your correspondent device.Please re-exchange your codes:"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Pour garantir le chiffrement, nous avons besoin de réauthentifier lappareil de votre correspondant.Veuillez ré-échanger vos codes :"
}
}
}
},
"call_not_encrypted" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Call is not encrypted"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Appel non chiffré"
}
}
}
},
"call_srtp_point_to_point_encrypted" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Point-to-point encrypted by SRTP"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Appel chiffré de point à point"
}
}
}
},
"call_waiting_for_encryption_info" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Waiting for encryption…"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "En attente du chiffrement…"
}
}
}
},
"call_zrtp_end_to_end_encrypted" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "End-to-end encrypted by ZRTP"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Appel chiffré de bout en bout"
}
}
}
},
"call_zrtp_sas_validation_required" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Validation required"
}
},
"fr" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Vérification nécessaire"
}
}
}
},
"call_zrtp_sas_validation_skip" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Skip"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Passer"
}
}
}
},
"Calls" : {
@ -889,21 +1158,9 @@
},
"Joining..." : {
},
"Key" : {
"extractionState" : "manual"
},
"Key 1" : {
"extractionState" : "manual"
},
"Key 2" : {
"extractionState" : "manual"
},
"Last name" : {
},
"Letters don't match!" : {
},
"Linphone" : {
@ -1101,9 +1358,6 @@
},
"Resuming" : {
},
"Say %@ and click on the letters given by your correspondent:" : {
},
"Say something..." : {
@ -1283,9 +1537,6 @@
},
"Username error" : {
},
"Validate the device" : {
},
"Vidéo" : {

View file

@ -225,7 +225,12 @@ extension ProviderDelegate: CXProviderDelegate {
DispatchQueue.main.async {
if UIApplication.shared.applicationState != .active {
TelecomManager.shared.backgroundContextCall = call
if call?.callLog != nil {
TelecomManager.shared.backgroundContextCameraIsEnabled = call?.params?.videoEnabled == true || call?.callLog?.wasConference() == true
} else {
TelecomManager.shared.backgroundContextCameraIsEnabled = call?.params?.videoEnabled == true
}
if #available(iOS 16.0, *) {
if call?.cameraEnabled == true {
call?.cameraEnabled = AVCaptureSession().isMultitaskingCameraAccessSupported

View file

@ -44,6 +44,7 @@ class TelecomManager: ObservableObject {
@Published var callInProgress: Bool = false
@Published var callDisplayed: Bool = true
@Published var callStarted: Bool = false
@Published var isNotVerifiedCounter: Int = 0
@Published var outgoingCallStarted: Bool = false
@Published var remoteConfVideo: Bool = false
@Published var isRecordingByRemote: Bool = false
@ -269,6 +270,7 @@ class TelecomManager: ObservableObject {
DispatchQueue.main.async {
self.outgoingCallStarted = true
self.callStarted = true
self.isNotVerifiedCounter = 0
if self.callInProgress == false {
withAnimation {
self.callInProgress = true
@ -316,6 +318,7 @@ class TelecomManager: ObservableObject {
DispatchQueue.main.async {
self.callStarted = true
self.isNotVerifiedCounter = 0
}
} catch {
Log.error("accept call failed \(error)")

View file

@ -177,10 +177,18 @@ struct CallView: View {
}
if callViewModel.zrtpPopupDisplayed == true {
ZRTPPopup(callViewModel: callViewModel)
if idiom != .pad
&& (orientation == .landscapeLeft
|| orientation == .landscapeRight
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height)
&& buttonSize != 45 {
ZRTPPopup(callViewModel: callViewModel, resizeView: 1.5)
.background(.black.opacity(0.65))
.onTapGesture {
callViewModel.zrtpPopupDisplayed = false
.frame(maxHeight: geo.size.height)
} else {
ZRTPPopup(callViewModel: callViewModel, resizeView: buttonSize == 45 ? 1.5 : 1)
.background(.black.opacity(0.65))
.frame(maxHeight: geo.size.height)
}
}
@ -281,15 +289,18 @@ struct CallView: View {
.frame(height: 40)
.zIndex(1)
if callViewModel.isMediaEncrypted {
if !telecomManager.outgoingCallStarted && telecomManager.callInProgress {
if callViewModel.isMediaEncrypted && callViewModel.isRemoteDeviceTrusted && callViewModel.isZrtp {
HStack {
Image("lock_simple")
Image("lock-key")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.blueInfo500)
.frame(width: 15, height: 15, alignment: .leading)
.padding(.leading, 50)
.padding(.top, 35)
Text("Appel chiffré de bout en bout")
Text("call_zrtp_end_to_end_encrypted")
.foregroundStyle(Color.blueInfo500)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
@ -301,6 +312,91 @@ struct CallView: View {
}
.frame(height: 40)
.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)
Text("call_srtp_point_to_point_encrypted")
.foregroundStyle(Color.blueInfo500)
.default_text_style_white(styleSize: 12)
.padding(.top, 35)
Spacer()
}
.onTapGesture {
mediaEncryptedSheet = true
}
.frame(height: 40)
.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: 40)
.zIndex(1)
} else if callViewModel.isNotEncrypted {
HStack {
Image("lock_simple")
.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: 40)
.zIndex(1)
} else {
HStack {
ProgressView()
.controlSize(.mini)
.progressViewStyle(CircularProgressViewStyle(tint: .white))
.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)
.padding(.top, 35)
Spacer()
}
.frame(height: 40)
.zIndex(1)
}
}
}
}

View file

@ -27,27 +27,116 @@ struct ZRTPPopup: View {
@ObservedObject var callViewModel: CallViewModel
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
@State private var orientation = UIDevice.current.orientation
var resizeView: CGFloat
var body: some View {
if callViewModel.isNotVerified {
alertZRTP
} else {
popupZRTP
}
}
var popupZRTP: some View {
GeometryReader { geometry in
VStack(alignment: .leading) {
Text("Validate the device")
.default_text_style_600(styleSize: 20)
Text("Say \(callViewModel.upperCaseAuthTokenToRead) and click on the letters given by your correspondent:")
.default_text_style(styleSize: 15)
.padding(.bottom, 20)
HStack(spacing: 25) {
ZStack(alignment: .top, content: {
HStack {
Spacer()
VStack {
Image("security")
.resizable()
.frame(width: 20, height: 20, alignment: .leading)
Text("call_dialog_zrtp_validate_trust_title")
.default_text_style_white_700(styleSize: 16 / resizeView)
}
.frame(maxWidth: .infinity)
Spacer()
}
.padding(.top, 15)
.padding(.bottom, 2)
HStack {
Spacer()
HStack {
Text("call_zrtp_sas_validation_skip")
.underline()
.tint(.white)
.default_text_style_white_600(styleSize: 16 / resizeView)
.foregroundStyle(.white)
}
.onTapGesture {
callViewModel.skipZrtpAuthentication()
callViewModel.zrtpPopupDisplayed = false
}
}
.padding(.top, 10 / resizeView)
.padding(.trailing, 15 / resizeView)
})
VStack(alignment: .center) {
VStack {
if idiom != .pad && (orientation == .landscapeLeft
|| orientation == .landscapeRight
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) {
HStack {
Text("call_dialog_zrtp_validate_trust_message")
.default_text_style(styleSize: 16 / resizeView)
.multilineTextAlignment(.center)
.padding(.bottom, 10 / resizeView)
VStack {
Text("call_dialog_zrtp_validate_trust_local_code_label")
.default_text_style(styleSize: 16 / resizeView)
.multilineTextAlignment(.center)
Text(!callViewModel.upperCaseAuthTokenToRead.isEmpty ? callViewModel.upperCaseAuthTokenToRead : "ZZ")
.default_text_style_700(styleSize: 22 / resizeView)
.padding(.bottom, 20 / resizeView)
}
}
} else {
Text(callViewModel.cacheMismatch ? "call_dialog_zrtp_validate_trust_warning_message" : "call_dialog_zrtp_validate_trust_message")
.default_text_style(styleSize: 16 / resizeView)
.multilineTextAlignment(.center)
.padding(.bottom, 10 / resizeView)
Text("call_dialog_zrtp_validate_trust_local_code_label")
.default_text_style(styleSize: 16 / resizeView)
.multilineTextAlignment(.center)
Text(!callViewModel.upperCaseAuthTokenToRead.isEmpty ? callViewModel.upperCaseAuthTokenToRead : "ZZ")
.default_text_style_800(styleSize: 22 / resizeView)
}
}
.padding(.bottom, 5)
VStack {
Text("call_dialog_zrtp_validate_trust_remote_code_label")
.default_text_style(styleSize: 16 / resizeView)
.multilineTextAlignment(.center)
.padding(.top, 15 / resizeView)
.padding(.bottom, 10 / resizeView)
if idiom != .pad && (orientation == .landscapeLeft
|| orientation == .landscapeRight
|| UIScreen.main.bounds.size.width > UIScreen.main.bounds.size.height) {
HStack(spacing: 30) {
HStack(alignment: .center) {
Text(callViewModel.letters1)
.default_text_style(styleSize: 30)
.frame(width: 60, height: 60)
.default_text_style(styleSize: 24 / resizeView)
.frame(width: 45 / resizeView, height: 45 / resizeView)
}
.padding(10)
.background(Color.grayMain2c200)
.cornerRadius(40)
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters1)
callViewModel.zrtpPopupDisplayed = false
@ -55,32 +144,27 @@ struct ZRTPPopup: View {
HStack(alignment: .center) {
Text(callViewModel.letters2)
.default_text_style(styleSize: 30)
.frame(width: 60, height: 60)
.default_text_style(styleSize: 24 / resizeView)
.frame(width: 45 / resizeView, height: 45 / resizeView)
}
.padding(10)
.background(Color.grayMain2c200)
.cornerRadius(40)
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters2)
callViewModel.zrtpPopupDisplayed = false
}
Spacer()
}
.padding(.bottom, 20)
HStack(spacing: 25) {
Spacer()
HStack(alignment: .center) {
Text(callViewModel.letters3)
.default_text_style(styleSize: 30)
.frame(width: 60, height: 60)
.default_text_style(styleSize: 24 / resizeView)
.frame(width: 45 / resizeView, height: 45 / resizeView)
}
.padding(10)
.background(Color.grayMain2c200)
.cornerRadius(40)
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters3)
callViewModel.zrtpPopupDisplayed = false
@ -88,62 +172,222 @@ struct ZRTPPopup: View {
HStack(alignment: .center) {
Text(callViewModel.letters4)
.default_text_style(styleSize: 30)
.frame(width: 60, height: 60)
.default_text_style(styleSize: 24 / resizeView)
.frame(width: 45 / resizeView, height: 45 / resizeView)
}
.padding(10)
.background(Color.grayMain2c200)
.cornerRadius(40)
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters4)
callViewModel.zrtpPopupDisplayed = false
}
Spacer()
}
.padding(.bottom, 20)
HStack {
Text("Skip")
.underline()
.tint(Color.grayMain2c600)
.default_text_style_600(styleSize: 15)
.foregroundStyle(Color.grayMain2c500)
.padding(.horizontal, 40 / resizeView)
.padding(.bottom, 20 / resizeView)
} else {
HStack(spacing: 30) {
HStack(alignment: .center) {
Text(callViewModel.letters1)
.default_text_style(styleSize: 34 / resizeView)
.frame(width: 60 / resizeView, height: 60 / resizeView)
}
.frame(maxWidth: .infinity)
.padding(.bottom, 30)
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.skipZrtpAuthentication()
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters1)
callViewModel.zrtpPopupDisplayed = false
}
HStack(alignment: .center) {
Text(callViewModel.letters2)
.default_text_style(styleSize: 34 / resizeView)
.frame(width: 60 / resizeView, height: 60 / resizeView)
}
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters2)
callViewModel.zrtpPopupDisplayed = false
}
}
.padding(.horizontal, 40 / resizeView)
.padding(.bottom, 20 / resizeView)
HStack(spacing: 30) {
HStack(alignment: .center) {
Text(callViewModel.letters3)
.default_text_style(styleSize: 34 / resizeView)
.frame(width: 60 / resizeView, height: 60 / resizeView)
}
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters3)
callViewModel.zrtpPopupDisplayed = false
}
HStack(alignment: .center) {
Text(callViewModel.letters4)
.default_text_style(styleSize: 34 / resizeView)
.frame(width: 60 / resizeView, height: 60 / resizeView)
}
.padding(10 / resizeView)
.background(.white)
.clipShape(Circle())
.shadow(color: .gray.opacity(0.4), radius: 4)
.onTapGesture {
callViewModel.updateZrtpSas(authTokenClicked: callViewModel.letters4)
callViewModel.zrtpPopupDisplayed = false
}
}
.padding(.horizontal, 40 / resizeView)
.padding(.bottom, 20 / resizeView)
}
}
.padding(.horizontal, 10 / resizeView)
.padding(.bottom, 10 / resizeView)
.cornerRadius(20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.inset(by: 0.5)
.stroke(Color.grayMain2c200, lineWidth: 1)
)
.padding(.bottom, 10 / resizeView)
Button(action: {
callViewModel.updateZrtpSas(authTokenClicked: "")
callViewModel.zrtpPopupDisplayed = false
}, label: {
Text("Letters don't match!")
.default_text_style_orange_600(styleSize: 20)
.frame(height: 35)
Text("call_dialog_zrtp_validate_trust_letters_do_not_match")
.foregroundStyle(Color.redDanger500)
.default_text_style_orange_600(styleSize: 20 / resizeView)
.frame(height: 35 / resizeView)
.frame(maxWidth: .infinity)
})
.padding(.horizontal, 20)
.padding(.vertical, 10)
.padding(.horizontal, 20 / resizeView)
.padding(.vertical, 10 / resizeView)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(Color.orangeMain500, lineWidth: 1)
.stroke(Color.redDanger500, lineWidth: 1)
)
.padding(.bottom)
}
.padding(.horizontal, 20)
.padding(.vertical, 20)
.padding(.top, 20 / resizeView)
.padding(.horizontal, 20 / resizeView)
.background(.white)
.cornerRadius(20)
.padding(.horizontal)
}
.background(callViewModel.cacheMismatch ? Color.orangeWarning600 : Color.blueInfo500)
.cornerRadius(20)
.padding(.horizontal, 2)
.frame(maxHeight: .infinity)
.shadow(color: Color.orangeMain500, radius: 0, x: 0, y: 2)
.frame(maxWidth: sharedMainViewModel.maxWidth)
.shadow(color: callViewModel.cacheMismatch ? Color.orangeWarning600 : Color.blueInfo500, radius: 0, x: 0, y: 2)
.frame(maxWidth: sharedMainViewModel.maxWidth * 1.2)
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
.onAppear {
callViewModel.remoteAuthenticationTokens()
}
}
}
var alertZRTP: some View {
GeometryReader { geometry in
VStack(alignment: .leading) {
ZStack(alignment: .top, content: {
HStack {
Spacer()
VStack {
Image("shield-warning")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 25, height: 25, alignment: .leading)
Text("call_dialog_zrtp_security_alert_title")
.default_text_style_white_700(styleSize: 16 / resizeView)
}
.frame(maxWidth: .infinity)
Spacer()
}
.padding(.top, 15)
.padding(.bottom, 2)
})
VStack(alignment: .center) {
VStack {
Text("call_dialog_zrtp_security_alert_message")
.default_text_style(styleSize: 16 / resizeView)
.multilineTextAlignment(.center)
.padding(.bottom, 10 / resizeView)
}
.padding(.bottom, 5)
if telecomManager.isNotVerifiedCounter <= 1 {
Button(action: {
callViewModel.isNotVerified = false
}, label: {
Text("call_dialog_zrtp_security_alert_try_again")
.foregroundStyle(Color.redDanger500)
.default_text_style_orange_600(styleSize: 20 / resizeView)
.frame(height: 35 / resizeView)
.frame(maxWidth: .infinity)
})
.padding(.horizontal, 20 / resizeView)
.padding(.vertical, 10 / resizeView)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(Color.redDanger500, lineWidth: 1)
)
.padding(.bottom)
}
Button(action: {
callViewModel.terminateCall()
}, label: {
HStack {
Image("phone-disconnect")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 20, height: 20)
Text("call_action_hang_up")
.default_text_style_white_600(styleSize: 20)
.frame(height: 35)
}
.frame(maxWidth: .infinity)
})
.padding(.horizontal, 20 / resizeView)
.padding(.vertical, 10 / resizeView)
.background(Color.redDanger500)
.cornerRadius(60)
.padding(.bottom)
}
.padding(.top, 20 / resizeView)
.padding(.horizontal, 20 / resizeView)
.background(.white)
.cornerRadius(20)
}
.background(Color.redDanger500)
.cornerRadius(20)
.padding(.horizontal, 2)
.frame(maxHeight: .infinity)
.shadow(color: Color.redDanger500, radius: 0, x: 0, y: 2)
.frame(maxWidth: sharedMainViewModel.maxWidth * 1.2)
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
.onAppear {
callViewModel.remoteAuthenticationTokens()
@ -153,5 +397,5 @@ struct ZRTPPopup: View {
}
#Preview {
ZRTPPopup(callViewModel: CallViewModel())
ZRTPPopup(callViewModel: CallViewModel(), resizeView: 1)
}

View file

@ -42,8 +42,11 @@ class CallViewModel: ObservableObject {
@Published var upperCaseAuthTokenToRead = ""
@Published var upperCaseAuthTokenToListen = ""
@Published var isMediaEncrypted: Bool = false
@Published var isZrtpPq: Bool = false
@Published var isNotEncrypted: Bool = false
@Published var isZrtp: Bool = false
@Published var isRemoteDeviceTrusted: Bool = false
@Published var cacheMismatch: Bool = false
@Published var isNotVerified: Bool = false
@Published var selectedCall: Call?
@Published var isTransferInsteadCall: Bool = false
@Published var isOneOneCall: Bool = false
@ -125,14 +128,14 @@ class CallViewModel: ObservableObject {
}
var isMediaEncryptedTmp = false
var isZrtpPqTmp = false
var isZrtpTmp = false
if self.currentCall != nil && self.currentCall!.currentParams != nil {
if self.currentCall!.currentParams!.mediaEncryption == .ZRTP ||
self.currentCall!.currentParams!.mediaEncryption == .SRTP ||
self.currentCall!.currentParams!.mediaEncryption == .DTLS {
isMediaEncryptedTmp = true
isZrtpPqTmp = self.currentCall!.currentParams!.mediaEncryption == .ZRTP
isZrtpTmp = self.currentCall!.currentParams!.mediaEncryption == .ZRTP
}
}
@ -200,6 +203,9 @@ class CallViewModel: ObservableObject {
self.zrtpPopupDisplayed = false
self.upperCaseAuthTokenToRead = ""
self.upperCaseAuthTokenToListen = ""
self.isNotVerified = false
self.updateEncryption()
self.isConference = false
self.participantList = []
self.activeSpeakerParticipant = nil
@ -209,7 +215,9 @@ class CallViewModel: ObservableObject {
self.videoDisplayed = videoDisplayedTmp
self.isOneOneCall = isOneOneCallTmp
self.isMediaEncrypted = isMediaEncryptedTmp
self.isZrtpPq = isZrtpPqTmp
self.isNotEncrypted = false
self.isZrtp = isZrtpTmp
self.cacheMismatch = cacheMismatchFlag
self.getCallsList()
@ -228,22 +236,36 @@ class CallViewModel: ObservableObject {
})
self.callSuscriptions.insert(self.currentCall!.publisher?.onStatsUpdated?.postOnCoreQueue {(cbVal: (call: Call, stats: CallStats)) in
if self.currentCall != nil {
DispatchQueue.main.async {
if self.currentCall != nil {
self.callStatsModel.update(call: self.currentCall!, stats: cbVal.stats)
}
}
})
self.callSuscriptions.insert(
self.currentCall!.publisher?.onAuthenticationTokenVerified?.postOnCoreQueue {(call: Call, verified: Bool) in
Log.warn("[CallViewModel][ZRTPPopup] Notified that authentication token is \(verified ? "verified" : "not verified!")")
if verified {
self.updateEncryption()
if self.currentCall != nil {
self.callMediaEncryptionModel.update(call: self.currentCall!)
}
} else {
if self.telecomManager.isNotVerifiedCounter == 0 {
DispatchQueue.main.async {
self.isNotVerified = true
self.telecomManager.isNotVerifiedCounter += 1
}
self.showZrtpSasDialogIfPossible()
} else {
DispatchQueue.main.async {
self.isNotVerified = true
self.telecomManager.isNotVerifiedCounter += 1
self.zrtpPopupDisplayed = true
}
}
}
}
)
@ -641,6 +663,7 @@ class CallViewModel: ObservableObject {
telecomManager.callInProgress = true
telecomManager.callDisplayed = true
telecomManager.callStarted = true
telecomManager.isNotVerifiedCounter = 0
}
coreContext.doOnCoreQueue { core in
@ -881,6 +904,7 @@ class CallViewModel: ObservableObject {
coreContext.doOnCoreQueue { core in
if core.currentCall != nil {
let tokens = core.currentCall!.remoteAuthenticationTokens
if !tokens.isEmpty {
DispatchQueue.main.async {
self.letters1 = tokens[0]
self.letters2 = tokens[1]
@ -890,9 +914,10 @@ class CallViewModel: ObservableObject {
}
}
}
}
private func updateEncryption() {
coreContext.doOnCoreQueue { core in
coreContext.doOnCoreQueue { _ in
if self.currentCall != nil && self.currentCall!.currentParams != nil {
switch self.currentCall!.currentParams!.mediaEncryption {
case MediaEncryption.ZRTP:
@ -918,12 +943,14 @@ class CallViewModel: ObservableObject {
*/
// When Post Quantum is available, ZRTP is Post Quantum
let isZrtpPqTmp = Core.getPostQuantumAvailable
let isZrtpPQTmp = Core.getPostQuantumAvailable
DispatchQueue.main.async {
self.isRemoteDeviceTrusted = isRemoteDeviceTrustedTmp
self.isMediaEncrypted = true
self.isZrtpPq = isZrtpPqTmp
self.isZrtp = true
self.cacheMismatch = cacheMismatchFlag
self.isNotEncrypted = false
if isDeviceTrusted {
ToastViewModel.shared.toastMessage = "Info_call_securised"
@ -938,12 +965,18 @@ class CallViewModel: ObservableObject {
case MediaEncryption.SRTP, MediaEncryption.DTLS:
DispatchQueue.main.async {
self.isMediaEncrypted = true
self.isZrtpPq = false
self.isZrtp = false
self.isNotEncrypted = false
}
default:
case MediaEncryption.None:
DispatchQueue.main.async {
self.isMediaEncrypted = false
self.isZrtpPq = false
self.isZrtp = false
if self.currentCall!.state == .StreamsRunning {
self.isNotEncrypted = true
} else {
self.isNotEncrypted = false
}
}
}
}
@ -971,6 +1004,7 @@ class CallViewModel: ObservableObject {
let mySubstringSuffix = upperCaseAuthToken.suffix(2)
DispatchQueue.main.async {
switch self.currentCall!.dir {
case Call.Dir.Incoming:
self.upperCaseAuthTokenToRead = String(mySubstringPrefix)
@ -983,14 +1017,15 @@ class CallViewModel: ObservableObject {
self.zrtpPopupDisplayed = true
}
}
}
func transferClicked() {
coreContext.doOnCoreQueue { core in
var callToTransferTo = core.calls.last { call in
let callToTransferTo = core.calls.last { call in
call.state == Call.State.Paused && call.callLog?.callId != self.currentCall?.callLog?.callId
}
if (callToTransferTo == nil) {
if callToTransferTo == nil {
Log.error(
"[CallViewModel] Couldn't find a call in Paused state to transfer current call to"
)

View file

@ -35,6 +35,10 @@ extension Account {
}
static func == (lhs: Account, rhs: Account) -> Bool {
if lhs.params != nil && lhs.params?.identityAddress != nil && rhs.params != nil && rhs.params?.identityAddress != nil {
return lhs.params?.identityAddress?.asString() == rhs.params?.identityAddress?.asString()
} else {
return false
}
}
}