webrtc: change server ports to 443, ios: allow configuring WebRTC ICE servers (#1077)

* webrtc: change server ports to 443

* pass stun/turn servers from user default

* ios: configure WebRTC ICE servers

* translations

* update servers

* translations
This commit is contained in:
Evgeny Poberezkin
2022-09-21 10:19:13 +01:00
committed by GitHub
parent edf217111f
commit 909a8aaf9c
14 changed files with 380 additions and 23 deletions
+9 -4
View File
@@ -24,8 +24,8 @@ var TransformOperation;
let activeCall;
const processCommand = (function () {
const defaultIceServers = [
{ urls: ["stun:stun.simplex.im:5349"] },
{ urls: ["turn:turn.simplex.im:5349"], username: "private", credential: "yleob6AVkiNI87hpR94Z" },
{ urls: ["stun:stun.simplex.im:443"] },
{ urls: ["turn:turn.simplex.im:443"], username: "private", credential: "yleob6AVkiNI87hpR94Z" },
];
function getCallConfig(encodedInsertableStreams, iceServers, relay) {
return {
@@ -495,6 +495,7 @@ function callCryptoFunction() {
const initialPlainTextRequired = {
key: 10,
delta: 3,
empty: 1,
};
const IV_LENGTH = 12;
function encryptFrame(key) {
@@ -505,7 +506,9 @@ function callCryptoFunction() {
const initial = data.subarray(0, n);
const plaintext = data.subarray(n, data.byteLength);
try {
const ciphertext = new Uint8Array(plaintext.length ? await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv.buffer }, key, plaintext) : 0);
const ciphertext = plaintext.length
? new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: iv.buffer }, key, plaintext))
: new Uint8Array(0);
frame.data = concatN(initial, ciphertext, iv).buffer;
controller.enqueue(frame);
}
@@ -523,7 +526,9 @@ function callCryptoFunction() {
const ciphertext = data.subarray(n, data.byteLength - IV_LENGTH);
const iv = data.subarray(data.byteLength - IV_LENGTH, data.byteLength);
try {
const plaintext = new Uint8Array(ciphertext.length ? await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext) : 0);
const plaintext = ciphertext.length
? new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext))
: new Uint8Array(0);
frame.data = concatN(initial, plaintext).buffer;
controller.enqueue(frame);
}
+10 -1
View File
@@ -899,8 +899,17 @@ func processReceivedMsg(_ res: ChatResponse) async {
call.peerMedia = callType.media
call.sharedKey = sharedKey
let useRelay = UserDefaults.standard.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
let iceServers = getIceServers()
logger.debug(".callOffer useRelay \(useRelay)")
m.callCommand = .offer(offer: offer.rtcSession, iceCandidates: offer.rtcIceCandidates, media: callType.media, aesKey: sharedKey, useWorker: true, relay: useRelay)
logger.debug(".callOffer iceServers \(String(describing: iceServers))")
m.callCommand = .offer(
offer: offer.rtcSession,
iceCandidates: offer.rtcIceCandidates,
media: callType.media, aesKey: sharedKey,
useWorker: true,
iceServers: iceServers,
relay: useRelay
)
}
case let .callAnswer(contact, answer):
withCall(contact) { call in
+10 -2
View File
@@ -47,8 +47,16 @@ class CallManager {
)
m.showCallView = true
let useRelay = UserDefaults.standard.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
logger.debug("answerIncomingCall useRelay \(useRelay)")
m.callCommand = .start(media: invitation.callType.media, aesKey: invitation.sharedKey, useWorker: true, relay: useRelay)
let iceServers = getIceServers()
logger.debug("answerIncomingCall useRelay: \(useRelay)")
logger.debug("answerIncomingCall iceServers: \(String(describing: iceServers))")
m.callCommand = .start(
media: invitation.callType.media,
aesKey: invitation.sharedKey,
useWorker: true,
iceServers: iceServers,
relay: useRelay
)
}
func endCall(callUUID: UUID, completed: @escaping (Bool) -> Void) {
+45
View File
@@ -394,3 +394,48 @@ struct RTCIceServer: Codable, Equatable {
var username: String? = nil
var credential: String? = nil
}
// the servers are expected in this format:
// stun:stun.simplex.im:443
// turn:private:yleob6AVkiNI87hpR94Z@turn.simplex.im:443
func parseRTCIceServer(_ str: String) -> RTCIceServer? {
var s = replaceScheme(str, "stun:")
s = replaceScheme(s, "turn:")
if let u: URL = URL(string: s),
let scheme = u.scheme,
let host = u.host,
let port = u.port,
u.path == "" && (scheme == "stun" || scheme == "turn") {
return RTCIceServer(
urls: ["\(scheme):\(host):\(port)"],
username: u.user,
credential: u.password
)
}
return nil
}
private func replaceScheme(_ s: String, _ scheme: String) -> String {
s.starts(with: scheme)
? s.replacingOccurrences(of: scheme, with: scheme + "//", options: .anchored, range: nil)
: s
}
func parseRTCIceServers(_ servers: [String]) -> [RTCIceServer]? {
var iceServers: [RTCIceServer] = []
for s in servers {
if let server = parseRTCIceServer(s) {
iceServers.append(server)
} else {
return nil
}
}
return iceServers.isEmpty ? nil : iceServers
}
func getIceServers() -> [RTCIceServer]? {
if let servers = UserDefaults.standard.stringArray(forKey: DEFAULT_WEBRTC_ICE_SERVERS) {
return parseRTCIceServers(servers)
}
return nil
}
@@ -16,6 +16,13 @@ struct CallSettings: View {
List {
Section {
Toggle("Connect via relay", isOn: $webrtcPolicyRelay)
NavigationLink {
RTCServers()
.navigationTitle("Your ICE servers")
} label: {
Text("WebRTC ICE servers")
}
} header: {
Text("Settings")
} footer: {
@@ -37,7 +37,7 @@ struct NetworkAndServers: View {
SMPServers()
.navigationTitle("Your SMP servers")
} label: {
settingsRow("server.rack") { Text("SMP servers") }
Text("SMP servers")
}
Picker("Use .onion hosts", selection: $onionHosts) {
@@ -49,14 +49,23 @@ struct NetworkAndServers: View {
AdvancedNetworkSettings()
.navigationTitle("Network settings")
} label: {
settingsRow("app.connected.to.app.below.fill") { Text("Advanced network settings") }
Text("Advanced network settings")
}
}
} header: {
Text("")
Text("Messages")
} footer: {
Text("Using .onion hosts requires compatible VPN provider.")
}
Section("Calls") {
NavigationLink {
RTCServers()
.navigationTitle("Your ICE servers")
} label: {
Text("WebRTC ICE servers")
}
}
}
}
.onAppear {
@@ -0,0 +1,154 @@
//
// RTCServers.swift
// SimpleX (iOS)
//
// Created by Evgeny on 20/09/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
private let howToUrl = URL(string: "https://github.com/simplex-chat/simplex-chat/blob/stable/docs/WEBRTC.md#configure-mobile-apps")!
struct RTCServers: View {
@State private var userRTCServers: [String] = []
@State private var isUserRTCServers = false
@State private var isUserRTCServersToggle = false
@State private var editRTCServers = true
@State private var userRTCServersStr = ""
@State private var showBadServersAlert = false
@State private var showResetServersAlert = false
@FocusState private var keyboardVisible: Bool
var body: some View {
List {
Section {
Toggle("Configure ICE servers", isOn: $isUserRTCServersToggle)
.onChange(of: isUserRTCServersToggle) { _ in
if (isUserRTCServersToggle) {
isUserRTCServers = true
} else if (userRTCServers.isEmpty) {
resetRTCServers()
} else {
showResetServersAlert = true
}
}
.alert(isPresented: $showResetServersAlert) {
Alert(
title: Text("Use SimpleX Chat servers?"),
message: Text("Saved WebRTC ICE servers will be removed"),
primaryButton: .destructive(Text("Confirm")) {
resetRTCServers()
}, secondaryButton: .cancel() {
withAnimation() {
isUserRTCServersToggle = true
}
}
)
}
} header: {
Text("")
} footer: {
if !isUserRTCServers {
Text("Using SimpleX Chat servers.")
}
}
if isUserRTCServers {
Section {
if editRTCServers {
TextEditor(text: $userRTCServersStr)
.focused($keyboardVisible)
.font(serversFont)
.disableAutocorrection(true)
.textInputAutocapitalization(.never)
.padding(.horizontal, -5)
.padding(.top, -8)
.frame(height: 160, alignment: .topLeading)
.frame(maxWidth: .infinity, alignment: .leading)
} else {
ScrollView {
Text(userRTCServersStr)
.font(serversFont)
.frame(minHeight: 0, alignment: .topLeading)
.textSelection(.enabled)
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(height: 160)
}
} header: {
Text("ICE servers (one per line)")
} footer: {
HStack(spacing: 20) {
if editRTCServers {
Button("Cancel") {
initialize()
}
Button("Save") {
saveUserRTCServers()
}
.alert(isPresented: $showBadServersAlert) {
Alert(title: Text("Error saving ICE servers"), message: Text("Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated."))
}
Spacer()
howToButton()
} else {
Button("Edit") {
editRTCServers = true
}
Spacer()
howToButton()
}
}
.font(.body)
}
}
}
.onAppear { initialize() }
}
private func initialize() {
userRTCServers = UserDefaults.standard.stringArray(forKey: DEFAULT_WEBRTC_ICE_SERVERS) ?? []
isUserRTCServers = !userRTCServers.isEmpty
isUserRTCServersToggle = isUserRTCServers
editRTCServers = !isUserRTCServers
userRTCServersStr = isUserRTCServers ? userRTCServers.joined(separator: "\n") : ""
}
private func resetRTCServers() {
isUserRTCServers = false
userRTCServers = []
UserDefaults.standard.removeObject(forKey: DEFAULT_WEBRTC_ICE_SERVERS)
}
private func saveUserRTCServers() {
let srvs = userRTCServersStr.components(separatedBy: "\n")
if srvs.count > 0 && Set(srvs).count == srvs.count && parseRTCIceServers(srvs) != nil {
userRTCServers = srvs
UserDefaults.standard.set(srvs, forKey: DEFAULT_WEBRTC_ICE_SERVERS)
editRTCServers = false
} else {
showBadServersAlert = true
}
}
func howToButton() -> some View {
Button {
DispatchQueue.main.async {
UIApplication.shared.open(howToUrl)
}
} label: {
HStack{
Text("How to")
Image(systemName: "arrow.up.right.circle")
}
}
}
}
struct RTCServers_Previews: PreviewProvider {
static var previews: some View {
RTCServers()
}
}
@@ -9,7 +9,7 @@
import SwiftUI
import SimpleXChat
private let serversFont = Font.custom("Menlo", size: 14)
let serversFont = Font.custom("Menlo", size: 14)
private let howToUrl = URL(string: "https://github.com/simplex-chat/simplexmq#using-smp-server-and-smp-agent")!
@@ -19,6 +19,7 @@ let DEFAULT_SHOW_LA_NOTICE = "showLocalAuthenticationNotice"
let DEFAULT_LA_NOTICE_SHOWN = "localAuthenticationNoticeShown"
let DEFAULT_PERFORM_LA = "performLocalAuthentication"
let DEFAULT_WEBRTC_POLICY_RELAY = "webrtcPolicyRelay"
let DEFAULT_WEBRTC_ICE_SERVERS = "webrtcICEServers"
let DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages"
let DEFAULT_PRIVACY_LINK_PREVIEWS = "privacyLinkPreviews"
let DEFAULT_EXPERIMENTAL_CALLS = "experimentalCalls"
@@ -193,7 +194,7 @@ struct SettingsView: View {
} label: {
settingsRow("terminal") { Text("Chat console") }
}
settingsRow("gear") {
settingsRow("chevron.left.forwardslash.chevron.right") {
Toggle("Developer tools", isOn: $developerTools)
}
ZStack(alignment: .leading) {
@@ -303,6 +303,11 @@
<target>Call already ended!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Calls" xml:space="preserve">
<source>Calls</source>
<target>Calls</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Can't invite contact!" xml:space="preserve">
<source>Can't invite contact!</source>
<target>Can't invite contact!</target>
@@ -403,6 +408,11 @@
<target>Colors</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure ICE servers" xml:space="preserve">
<source>Configure ICE servers</source>
<target>Configure ICE servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure SMP servers" xml:space="preserve">
<source>Configure SMP servers</source>
<target>Configure SMP servers</target>
@@ -961,6 +971,11 @@
<target>Error joining group</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving ICE servers" xml:space="preserve">
<source>Error saving ICE servers</source>
<target>Error saving ICE servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving SMP servers" xml:space="preserve">
<source>Error saving SMP servers</source>
<target>Error saving SMP servers</target>
@@ -1136,6 +1151,11 @@
<target>How to use markdown</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
<source>ICE servers (one per line)</source>
<target>ICE servers (one per line)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If the video fails to connect, flip the camera to resolve it." xml:space="preserve">
<source>If the video fails to connect, flip the camera to resolve it.</source>
<target>If the video fails to connect, flip the camera to resolve it.</target>
@@ -1363,6 +1383,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Make sure SMP server addresses are in correct format, line separated and are not duplicated.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." xml:space="preserve">
<source>Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated.</source>
<target>Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*" xml:space="preserve">
<source>Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*</source>
<target>Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*</target>
@@ -1398,6 +1423,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Message text</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages" xml:space="preserve">
<source>Messages</source>
<target>Messages</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive..." xml:space="preserve">
<source>Migrating database archive...</source>
<target>Migrating database archive...</target>
@@ -1858,6 +1888,11 @@ We will be adding server redundancy to prevent lost messages.</target>
<target>Saved SMP servers will be removed</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source>
<target>Saved WebRTC ICE servers will be removed</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code" xml:space="preserve">
<source>Scan QR code</source>
<target>Scan QR code</target>
@@ -2322,6 +2357,11 @@ To connect, please ask your contact to create another connection link and check
<target>Waiting for image</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="WebRTC ICE servers" xml:space="preserve">
<source>WebRTC ICE servers</source>
<target>WebRTC ICE servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Welcome %@!" xml:space="preserve">
<source>Welcome %@!</source>
<target>Welcome %@!</target>
@@ -2477,6 +2517,11 @@ To connect, please ask your contact to create another connection link and check
<target>You're using an incognito profile for this group - to prevent sharing your main profile inviting contacts is not allowed</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your ICE servers" xml:space="preserve">
<source>Your ICE servers</source>
<target>Your ICE servers</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your SMP servers" xml:space="preserve">
<source>Your SMP servers</source>
<target>Your SMP servers</target>
@@ -303,6 +303,11 @@
<target>Звонок уже завершен!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Calls" xml:space="preserve">
<source>Calls</source>
<target>Звонки</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Can't invite contact!" xml:space="preserve">
<source>Can't invite contact!</source>
<target>Нельзя пригласить контакт!</target>
@@ -403,6 +408,11 @@
<target>Цвета</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure ICE servers" xml:space="preserve">
<source>Configure ICE servers</source>
<target>Настройка ICE серверов</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Configure SMP servers" xml:space="preserve">
<source>Configure SMP servers</source>
<target>Настройка SMP серверов</target>
@@ -961,6 +971,11 @@
<target>Ошибка приглашения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving ICE servers" xml:space="preserve">
<source>Error saving ICE servers</source>
<target>Ошибка при сохранении ICE серверов</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error saving SMP servers" xml:space="preserve">
<source>Error saving SMP servers</source>
<target>Ошибка при сохранении SMP серверов</target>
@@ -1136,6 +1151,11 @@
<target>Как форматировать</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="ICE servers (one per line)" xml:space="preserve">
<source>ICE servers (one per line)</source>
<target>ICE серверы (один на строке)</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="If the video fails to connect, flip the camera to resolve it." xml:space="preserve">
<source>If the video fails to connect, flip the camera to resolve it.</source>
<target>Если видео не соединилось, переключите камеру.</target>
@@ -1363,6 +1383,11 @@ We will be adding server redundancy to prevent lost messages.</source>
<target>Пожалуйста, проверьте, что адреса SMP серверов имеют правильный формат, каждый адрес на отдельной строке и не повторяется.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." xml:space="preserve">
<source>Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated.</source>
<target>Пожалуйста, проверьте, что адреса WebRTC ICE серверов имеют правильный формат, каждый адрес на отдельной строке и не повторяется.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*" xml:space="preserve">
<source>Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*</source>
<target>Много пользователей спросили: *как SimpleX доставляет сообщения без идентификаторов пользователей?*</target>
@@ -1398,6 +1423,11 @@ We will be adding server redundancy to prevent lost messages.</source>
<target>Текст сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Messages" xml:space="preserve">
<source>Messages</source>
<target>Сообщения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Migrating database archive..." xml:space="preserve">
<source>Migrating database archive...</source>
<target>Данные чата перемещаются...</target>
@@ -1858,6 +1888,11 @@ We will be adding server redundancy to prevent lost messages.</source>
<target>Сохраненные SMP серверы будут удалены</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Saved WebRTC ICE servers will be removed" xml:space="preserve">
<source>Saved WebRTC ICE servers will be removed</source>
<target>Сохраненные WebRTC ICE серверы будут удалены</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Scan QR code" xml:space="preserve">
<source>Scan QR code</source>
<target>Сканировать QR код</target>
@@ -2322,6 +2357,11 @@ To connect, please ask your contact to create another connection link and check
<target>Ожидается прием изображения</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="WebRTC ICE servers" xml:space="preserve">
<source>WebRTC ICE servers</source>
<target>WebRTC ICE серверы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Welcome %@!" xml:space="preserve">
<source>Welcome %@!</source>
<target>Здравствуйте %@!</target>
@@ -2477,6 +2517,11 @@ To connect, please ask your contact to create another connection link and check
<target>Вы используете инкогнито профиль для этой группы - чтобы предотвратить раскрытие вашего основного профиля, приглашать контакты не разрешено</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your ICE servers" xml:space="preserve">
<source>Your ICE servers</source>
<target>Ваши ICE серверы</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Your SMP servers" xml:space="preserve">
<source>Your SMP servers</source>
<target>Ваши SMP серверы</target>
@@ -78,6 +78,7 @@
5CB0BA92282713FD00B3292C /* CreateProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA91282713FD00B3292C /* CreateProfile.swift */; };
5CB0BA962827143500B3292C /* MakeConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA952827143500B3292C /* MakeConnection.swift */; };
5CB0BA9A2827FD8800B3292C /* HowItWorks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB0BA992827FD8800B3292C /* HowItWorks.swift */; };
5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB2084E28DA4B4800D024EC /* RTCServers.swift */; };
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E42868AA7F001FD2EF /* SuspendChat.swift */; };
5CB346E72868D76D001FD2EF /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E62868D76D001FD2EF /* NotificationsView.swift */; };
5CB346E92869E8BA001FD2EF /* PushEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */; };
@@ -271,6 +272,7 @@
5CB0BA91282713FD00B3292C /* CreateProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateProfile.swift; sourceTree = "<group>"; };
5CB0BA952827143500B3292C /* MakeConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeConnection.swift; sourceTree = "<group>"; };
5CB0BA992827FD8800B3292C /* HowItWorks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HowItWorks.swift; sourceTree = "<group>"; };
5CB2084E28DA4B4800D024EC /* RTCServers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RTCServers.swift; sourceTree = "<group>"; };
5CB346E42868AA7F001FD2EF /* SuspendChat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuspendChat.swift; sourceTree = "<group>"; };
5CB346E62868D76D001FD2EF /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
5CB346E82869E8BA001FD2EF /* PushEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushEnvironment.swift; sourceTree = "<group>"; };
@@ -561,6 +563,7 @@
5CB924E027A867BA00ACCCDD /* UserProfile.swift */,
5C577F7C27C83AA10006112D /* MarkdownHelp.swift */,
640F50E227CF991C001E05C2 /* SMPServers.swift */,
5CB2084E28DA4B4800D024EC /* RTCServers.swift */,
5C3F1D592844B4DE00EC8A82 /* ExperimentalFeaturesView.swift */,
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */,
);
@@ -876,6 +879,7 @@
5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */,
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */,
5C4B3B0A285FB130003915F2 /* DatabaseView.swift in Sources */,
5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */,
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */,
5C7505A827B6D34800BE3227 /* ChatInfoToolbar.swift in Sources */,
+27
View File
@@ -218,6 +218,9 @@
/* call status */
"calling…" = "входящий звонок…";
/* No comment provided by engineer. */
"Calls" = "Звонки";
/* No comment provided by engineer. */
"Can't invite contact!" = "Нельзя пригласить контакт!";
@@ -284,6 +287,9 @@
/* No comment provided by engineer. */
"complete" = "соединение завершено";
/* No comment provided by engineer. */
"Configure ICE servers" = "Настройка ICE серверов";
/* No comment provided by engineer. */
"Configure SMP servers" = "Настройка SMP серверов";
@@ -683,6 +689,9 @@
/* No comment provided by engineer. */
"Error saving group profile" = "Ошибка при сохранении профиля группы";
/* No comment provided by engineer. */
"Error saving ICE servers" = "Ошибка при сохранении ICE серверов";
/* No comment provided by engineer. */
"Error saving SMP servers" = "Ошибка при сохранении SMP серверов";
@@ -791,6 +800,9 @@
/* No comment provided by engineer. */
"How to use markdown" = "Как форматировать";
/* No comment provided by engineer. */
"ICE servers (one per line)" = "ICE серверы (один на строке)";
/* No comment provided by engineer. */
"If the video fails to connect, flip the camera to resolve it." = "Если видео не соединилось, переключите камеру.";
@@ -956,6 +968,9 @@
/* No comment provided by engineer. */
"Make sure SMP server addresses are in correct format, line separated and are not duplicated." = "Пожалуйста, проверьте, что адреса SMP серверов имеют правильный формат, каждый адрес на отдельной строке и не повторяется.";
/* No comment provided by engineer. */
"Make sure WebRTC ICE server addresses are in correct format, line separated and are not duplicated." = "Пожалуйста, проверьте, что адреса WebRTC ICE серверов имеют правильный формат, каждый адрес на отдельной строке и не повторяется.";
/* No comment provided by engineer. */
"Many people asked: *if SimpleX has no user identifiers, how can it deliver messages?*" = "Много пользователей спросили: *как SimpleX доставляет сообщения без идентификаторов пользователей?*";
@@ -986,6 +1001,9 @@
/* No comment provided by engineer. */
"Message text" = "Текст сообщения";
/* No comment provided by engineer. */
"Messages" = "Сообщения";
/* No comment provided by engineer. */
"Migrating database archive..." = "Данные чата перемещаются...";
@@ -1292,6 +1310,9 @@
/* No comment provided by engineer. */
"Saved SMP servers will be removed" = "Сохраненные SMP серверы будут удалены";
/* No comment provided by engineer. */
"Saved WebRTC ICE servers will be removed" = "Сохраненные WebRTC ICE серверы будут удалены";
/* No comment provided by engineer. */
"Scan contact's QR code" = "Сосканировать QR код контакта";
@@ -1619,6 +1640,9 @@
/* No comment provided by engineer. */
"wants to connect to you!" = "хочет соединиться с вами!";
/* No comment provided by engineer. */
"WebRTC ICE servers" = "WebRTC ICE серверы";
/* No comment provided by engineer. */
"Welcome %@!" = "Здравствуйте %@!";
@@ -1766,6 +1790,9 @@
/* No comment provided by engineer. */
"Your current chat database will be DELETED and REPLACED with the imported one." = "Текущие данные вашего чата будет УДАЛЕНЫ и ЗАМЕНЕНЫ импортированными.";
/* No comment provided by engineer. */
"Your ICE servers" = "Ваши ICE серверы";
/* No comment provided by engineer. */
"Your privacy" = "Конфиденциальность";
+9 -11
View File
@@ -217,8 +217,8 @@ const processCommand = (function () {
}
const defaultIceServers: RTCIceServer[] = [
{urls: ["stun:stun.simplex.im:5349"]},
{urls: ["turn:turn.simplex.im:5349"], username: "private", credential: "yleob6AVkiNI87hpR94Z"},
{urls: ["stun:stun.simplex.im:443"]},
{urls: ["turn:turn.simplex.im:443"], username: "private", credential: "yleob6AVkiNI87hpR94Z"},
]
function getCallConfig(encodedInsertableStreams: boolean, iceServers?: RTCIceServer[], relay?: boolean): CallConfig {
@@ -703,16 +703,12 @@ interface CallCrypto {
decodeBase64url: (b64: Uint8Array) => Uint8Array | undefined
}
interface RTCEncodedVideoFrame {
type: "key" | "delta"
data: ArrayBuffer
}
// Cryptography function - it is loaded both in the main window and in worker context (if the worker is used)
function callCryptoFunction(): CallCrypto {
const initialPlainTextRequired = {
key: 10,
delta: 3,
empty: 1,
}
const IV_LENGTH = 12
@@ -725,9 +721,9 @@ function callCryptoFunction(): CallCrypto {
const initial = data.subarray(0, n)
const plaintext = data.subarray(n, data.byteLength)
try {
const ciphertext = new Uint8Array(
plaintext.length ? await crypto.subtle.encrypt({name: "AES-GCM", iv: iv.buffer}, key, plaintext) : 0
)
const ciphertext = plaintext.length
? new Uint8Array(await crypto.subtle.encrypt({name: "AES-GCM", iv: iv.buffer}, key, plaintext))
: new Uint8Array(0)
frame.data = concatN(initial, ciphertext, iv).buffer
controller.enqueue(frame)
} catch (e) {
@@ -745,7 +741,9 @@ function callCryptoFunction(): CallCrypto {
const ciphertext = data.subarray(n, data.byteLength - IV_LENGTH)
const iv = data.subarray(data.byteLength - IV_LENGTH, data.byteLength)
try {
const plaintext = new Uint8Array(ciphertext.length ? await crypto.subtle.decrypt({name: "AES-GCM", iv}, key, ciphertext) : 0)
const plaintext = ciphertext.length
? new Uint8Array(await crypto.subtle.decrypt({name: "AES-GCM", iv}, key, ciphertext))
: new Uint8Array(0)
frame.data = concatN(initial, plaintext).buffer
controller.enqueue(frame)
} catch (e) {