Merge branch 'master' into ab/debug-subs
@@ -54,6 +54,7 @@ website/translations.json
|
||||
website/src/img/images/
|
||||
website/src/images/
|
||||
website/src/js/lottie.min.js
|
||||
website/src/privacy.md
|
||||
# Generated files
|
||||
website/package/generated*
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
---
|
||||
layout: layouts/privacy.html
|
||||
---
|
||||
|
||||
# SimpleX Chat Privacy Policy and Conditions of Use
|
||||
|
||||
SimpleX Chat is the first communication network based on a new protocol stack that builds on the same ideas of complete openness and decentralization as email and web, with the focus on providing security and privacy of communications, and without compromising on usability.
|
||||
|
||||
SimpleX Chat communication protocol is the first protocol that has no user profile IDs of any kind, not even random numbers, cryptographic keys or hashes that identify the users. SimpleX Chat apps allow their users to send messages and files via relay server infrastructure. Relay server owners and providers do not have any access to your messages, thanks to double-ratchet end-to-end encryption algorithm (also known as Signal algorithm - do not confuse with Signal protocols or platform) and additional encryption layers, and they also have no access to your profile and contacts - as they do not provide any user accounts.
|
||||
|
||||
Double ratchet algorithm has such important properties as [forward secrecy](./docs/GLOSSARY.md#forward-secrecy), sender [repudiation](./docs/GLOSSARY.md#) and break-in recovery (also known as [post-compromise security](./docs/GLOSSARY.md#post-compromise-security)).
|
||||
Double ratchet algorithm has such important properties as [forward secrecy](/docs/GLOSSARY.md#forward-secrecy), sender [repudiation](/docs/GLOSSARY.md#) and break-in recovery (also known as [post-compromise security](/docs/GLOSSARY.md#post-compromise-security)).
|
||||
|
||||
If you believe that any part of this document is not aligned with our mission or values, please raise it with us via [email](chat@simplex.chat) or [chat](https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23%2F%3Fv%3D1%26dh%3DMCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion).
|
||||
|
||||
## Privacy Policy
|
||||
|
||||
SimpleX Chat Ltd uses the best industry practices for security and encryption to provide client and server software for secure [end-to-end encrypted](./docs/GLOSSARY.md#end-to-end-encryption) messaging via private connections. This encryption cannot be compromised by the relays servers, even if they are modified or compromised, via [man-in-the-middle attack](./docs/GLOSSARY.md#man-in-the-middle-attack), unlike most other communication platforms, services and networks.
|
||||
SimpleX Chat Ltd uses the best industry practices for security and encryption to provide client and server software for secure [end-to-end encrypted](/docs/GLOSSARY.md#end-to-end-encryption) messaging via private connections. This encryption cannot be compromised by the relays servers, even if they are modified or compromised, via [man-in-the-middle attack](/docs/GLOSSARY.md#man-in-the-middle-attack), unlike most other communication platforms, services and networks.
|
||||
|
||||
SimpleX Chat software is built on top of SimpleX messaging and application protocols, based on a new message routing protocol allowing to establish private connections without having any kind of addresses or other identifiers assigned to its users - it does not use emails, phone numbers, usernames, identity keys or any other user profile identifiers to pass messages between the user applications.
|
||||
|
||||
@@ -20,7 +24,7 @@ While SimpleX Chat Ltd is not a communication service provider, and provide publ
|
||||
|
||||
We see users and data sovereignty, and device and provider portability as critically important properties for any communication system.
|
||||
|
||||
SimpleX Chat security assessment was done in October 2022 by [Trail of Bits](https://www.trailofbits.com/about), and most fixes were released in v4.2 – see [the announcement](./blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
|
||||
SimpleX Chat security assessment was done in October 2022 by [Trail of Bits](https://www.trailofbits.com/about), and most fixes were released in v4.2 – see [the announcement](/blog/20221108-simplex-chat-v4.2-security-audit-new-website.md).
|
||||
|
||||
### Your information
|
||||
|
||||
@@ -34,7 +38,7 @@ You can transfer the profile to another device by creating a backup of the app d
|
||||
|
||||
#### Messages and Files
|
||||
|
||||
SimpleX relay servers cannot decrypt or otherwise access the content or even the size of your messages and files you send or receive. Each message is padded to a fixed size of 16kb. Each file is sent in chunks of 64kb, 256kb, 1mb or 8mb via all or some of the configured file relay servers. Both messages and files are sent end-to-end encrypted, and the servers do not have technical means to compromise this encryption, because part of the [key exchange](./docs/GLOSSARY.md#key-exchange) happens out-of-band.
|
||||
SimpleX relay servers cannot decrypt or otherwise access the content or even the size of your messages and files you send or receive. Each message is padded to a fixed size of 16kb. Each file is sent in chunks of 64kb, 256kb, 1mb or 8mb via all or some of the configured file relay servers. Both messages and files are sent end-to-end encrypted, and the servers do not have technical means to compromise this encryption, because part of the [key exchange](/docs/GLOSSARY.md#key-exchange) happens out-of-band.
|
||||
|
||||
Your message history is stored only on your own device and the devices of your contacts. While the recipients' devices are offline, messaging relay servers temporarily store end-to-end encrypted messages – you can configure which relay servers are used to receive the messages from the new contacts, and you can manually change them for the existing contacts too.
|
||||
|
||||
@@ -82,7 +86,7 @@ Additional technical information can be stored on our servers, including randoml
|
||||
|
||||
#### SimpleX Directory
|
||||
|
||||
[SimpleX Directory](./docs/DIRECTORY.md) stores: your search requests, the messages and the members profiles in the registered groups. You can connect to SimpleX Directory via [this address](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).
|
||||
[SimpleX Directory](/docs/DIRECTORY.md) stores: your search requests, the messages and the members profiles in the registered groups. You can connect to SimpleX Directory via [this address](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FeXSPwqTkKyDO3px4fLf1wx3MvPdjdLW3%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAaiv6MkMH44L2TcYrt_CsX3ZvM11WgbMEUn0hkIKTOho%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion).
|
||||
|
||||
#### User Support
|
||||
|
||||
|
||||
@@ -234,6 +234,8 @@ You can use SimpleX with your own servers and still communicate with people usin
|
||||
|
||||
Recent and important updates:
|
||||
|
||||
[Apr 26, 2024. SimpleX network: legally binding transparency, v5.7 released with better calls and messages.](./blog/20240426-simplex-legally-binding-transparency-v5-7-better-user-experience.md)
|
||||
|
||||
[Mar 23, 2024. SimpleX network: real privacy and stable profits, non-profits for protocols, v5.6 released with quantum resistant e2e encryption and simple profile migration.](./blog/20240323-simplex-network-privacy-non-profit-v5-6-quantum-resistant-e2e-encryption-simple-migration.md)
|
||||
|
||||
[Mar 14, 2024. SimpleX Chat v5.6 beta: adding quantum resistance to Signal double ratchet algorithm.](./blog/20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md)
|
||||
@@ -412,13 +414,13 @@ We have never provided or have been requested access to our servers or any infor
|
||||
|
||||
We do not log IP addresses of the users and we do not perform any traffic correlation on our servers. If transport level security is critical you must use Tor or some other similar network to access messaging servers. We will be improving the client applications to reduce the opportunities for traffic correlation.
|
||||
|
||||
Please read more in [Terms & privacy policy](./PRIVACY.md).
|
||||
Please read more in [Privacy Policy](./PRIVACY.md).
|
||||
|
||||
## Security contact
|
||||
|
||||
To report a security vulnerability, please send us email to chat@simplex.chat. We will coordinate the fix and disclosure. Please do NOT report security vulnerabilities via GitHub issues.
|
||||
Please see our [Security Policy](./docs/SECURITY.md) on how to report security vulnerabilities to us. We will coordinate the fix and disclosure.
|
||||
|
||||
Please treat any findings of possible traffic correlation attacks allowing to correlate two different conversations to the same user, other than covered in [the threat model](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#threat-model), as security vulnerabilities, and follow this disclosure process.
|
||||
Please do NOT report security vulnerabilities via GitHub issues.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
|
||||
if playback {
|
||||
if AVAudioSession.sharedInstance().category != .playback {
|
||||
logger.log("AudioSession: playback")
|
||||
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: .duckOthers)
|
||||
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [.duckOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
|
||||
}
|
||||
} else {
|
||||
if AVAudioSession.sharedInstance().category != .soloAmbient {
|
||||
|
||||
@@ -110,8 +110,8 @@ struct ActiveCallView: View {
|
||||
call.callState = .invitationSent
|
||||
call.localCapabilities = capabilities
|
||||
}
|
||||
if call.supportsVideo {
|
||||
try? AVAudioSession.sharedInstance().setCategory(.playback, options: .defaultToSpeaker)
|
||||
if call.supportsVideo && !AVAudioSession.sharedInstance().hasExternalAudioDevice() {
|
||||
try? AVAudioSession.sharedInstance().setCategory(.playback, options: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
|
||||
}
|
||||
CallSoundsPlayer.shared.startConnectingCallSound()
|
||||
activeCallWaitDeliveryReceipt()
|
||||
@@ -139,7 +139,6 @@ struct ActiveCallView: View {
|
||||
await MainActor.run {
|
||||
call.callState = .negotiated
|
||||
CallSoundsPlayer.shared.stop()
|
||||
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient)
|
||||
}
|
||||
}
|
||||
case let .ice(iceCandidates):
|
||||
@@ -236,6 +235,7 @@ struct ActiveCallOverlay: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@ObservedObject var call: Call
|
||||
var client: WebRTCClient
|
||||
@ObservedObject private var deviceManager = CallAudioDeviceManager.shared
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
@@ -251,7 +251,16 @@ struct ActiveCallOverlay: View {
|
||||
HStack {
|
||||
toggleAudioButton()
|
||||
Spacer()
|
||||
Color.clear.frame(width: 40, height: 40)
|
||||
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
|
||||
toggleSpeakerButton()
|
||||
.frame(width: 40, height: 40)
|
||||
} else if call.hasMedia {
|
||||
AudioDevicePicker()
|
||||
.scaleEffect(2)
|
||||
.frame(maxWidth: 40, maxHeight: 40)
|
||||
} else {
|
||||
Color.clear.frame(width: 40, height: 40)
|
||||
}
|
||||
Spacer()
|
||||
endCallButton()
|
||||
Spacer()
|
||||
@@ -292,14 +301,33 @@ struct ActiveCallOverlay: View {
|
||||
toggleAudioButton()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
endCallButton()
|
||||
toggleSpeakerButton()
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
// Check if the only input is microphone. And in this case show toggle button,
|
||||
// If there are more inputs, it probably means something like bluetooth headphones are available
|
||||
// and in this case show iOS button for choosing different output.
|
||||
// There is no way to get available outputs, only inputs
|
||||
if deviceManager.availableInputs.allSatisfy({ $0.portType == .builtInMic }) {
|
||||
toggleSpeakerButton()
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
} else if call.hasMedia {
|
||||
AudioDevicePicker()
|
||||
.scaleEffect(2)
|
||||
.frame(maxWidth: 50, maxHeight: 40)
|
||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||
} else {
|
||||
Color.clear.frame(width: 50, height: 40)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 60)
|
||||
.padding(.horizontal, 48)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.onAppear {
|
||||
deviceManager.start()
|
||||
}
|
||||
.onDisappear {
|
||||
deviceManager.stop()
|
||||
}
|
||||
}
|
||||
|
||||
private func audioCallInfoView(_ call: Call) -> some View {
|
||||
@@ -377,12 +405,17 @@ struct ActiveCallOverlay: View {
|
||||
private func toggleSpeakerButton() -> some View {
|
||||
controlButton(call, call.speakerEnabled ? "speaker.wave.2.fill" : "speaker.wave.1.fill") {
|
||||
Task {
|
||||
client.setSpeakerEnabledAndConfigureSession(!call.speakerEnabled)
|
||||
let speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
|
||||
client.setSpeakerEnabledAndConfigureSession(!speakerEnabled)
|
||||
DispatchQueue.main.async {
|
||||
call.speakerEnabled = !call.speakerEnabled
|
||||
call.speakerEnabled = !speakerEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
deviceManager.call = call
|
||||
//call.speakerEnabled = AVAudioSession.sharedInstance().currentRoute.outputs.first?.portType == .builtInSpeaker
|
||||
}
|
||||
}
|
||||
|
||||
private func toggleVideoButton() -> some View {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// MPVolumeView.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Stanislav on 24.04.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
import AVKit
|
||||
|
||||
struct AudioDevicePicker: UIViewRepresentable {
|
||||
func makeUIView(context: Context) -> some UIView {
|
||||
let v = AVRoutePickerView(frame: .zero)
|
||||
v.activeTintColor = .white
|
||||
v.tintColor = .white
|
||||
return v
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: UIViewType, context: Context) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// CallAudioDeviceManager.swift
|
||||
// SimpleX (iOS)
|
||||
//
|
||||
// Created by Avently on 23.04.2024.
|
||||
// Copyright © 2024 SimpleX Chat. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
import AVKit
|
||||
import WebRTC
|
||||
|
||||
class CallAudioDeviceManager: ObservableObject {
|
||||
static let shared = CallAudioDeviceManager()
|
||||
let audioSession: AVAudioSession
|
||||
let nc = NotificationCenter.default
|
||||
|
||||
var call: Call?
|
||||
var timer: Timer? = nil
|
||||
|
||||
// Actually, only one output
|
||||
@Published var outputs: [AVAudioSessionPortDescription]
|
||||
@Published var currentDevice: AVAudioSessionPortDescription? = nil
|
||||
// All devices that can record audio (the ones that can play audio are not included)
|
||||
@Published var availableInputs: [AVAudioSessionPortDescription] = []
|
||||
|
||||
|
||||
init(_ audioSession: AVAudioSession? = nil) {
|
||||
self.audioSession = audioSession ?? RTCAudioSession.sharedInstance().session
|
||||
self.outputs = self.audioSession.currentRoute.outputs
|
||||
self.availableInputs = self.audioSession.availableInputs ?? []
|
||||
}
|
||||
|
||||
func reloadDevices() {
|
||||
outputs = audioSession.currentRoute.outputs
|
||||
currentDevice = audioSession.currentRoute.outputs.first
|
||||
availableInputs = audioSession.availableInputs ?? []
|
||||
call?.speakerEnabled = currentDevice?.portType == .builtInSpeaker
|
||||
|
||||
|
||||
// Workaround situation:
|
||||
// have bluetooth device connected, choosing speaker, disconnecting bluetooth device. In this case iOS will not post notification, so do it manually
|
||||
timer?.invalidate()
|
||||
if availableInputs.contains(where: { $0.portType != .builtInReceiver && $0.portType != .builtInSpeaker }) {
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { t in
|
||||
self.reloadDevices()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func audioCallback(notification: Notification) {
|
||||
reloadDevices()
|
||||
|
||||
logger.debug("Changes in devices, current audio devices: \(String(describing: self.availableInputs.map({ $0.portType.rawValue }))), output: \(String(describing: self.currentDevice?.portType.rawValue))")
|
||||
}
|
||||
|
||||
func start() {
|
||||
nc.addObserver(self, selector: #selector(audioCallback), name: AVAudioSession.routeChangeNotification, object: nil)
|
||||
}
|
||||
|
||||
func stop() {
|
||||
nc.removeObserver(self, name: AVAudioSession.routeChangeNotification, object: nil)
|
||||
timer?.invalidate()
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,23 @@ class CallController: NSObject, CXProviderDelegate, PKPushRegistryDelegate, Obse
|
||||
RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession)
|
||||
RTCAudioSession.sharedInstance().isAudioEnabled = true
|
||||
do {
|
||||
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: .mixWithOthers)
|
||||
let supportsVideo = ChatModel.shared.activeCall?.supportsVideo == true
|
||||
if supportsVideo {
|
||||
try audioSession.setCategory(.playAndRecord, mode: .videoChat, options: [.defaultToSpeaker, .mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
|
||||
} else {
|
||||
try audioSession.setCategory(.playAndRecord, mode: .voiceChat, options: [.mixWithOthers, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
|
||||
}
|
||||
// Without any delay sound is not playing from speaker or external device in incoming call
|
||||
Task {
|
||||
for i in 0 ... 3 {
|
||||
try? await Task.sleep(nanoseconds: UInt64(i) * 300_000000)
|
||||
if let preferred = audioSession.preferredInputDevice() {
|
||||
await MainActor.run { try? audioSession.setPreferredInput(preferred) }
|
||||
} else if supportsVideo {
|
||||
await MainActor.run { try? audioSession.overrideOutputAudioPort(.speaker) }
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.debug("audioSession category set")
|
||||
try audioSession.setActive(true)
|
||||
logger.debug("audioSession activated")
|
||||
|
||||
@@ -605,9 +605,23 @@ extension WebRTCClient {
|
||||
self.rtcAudioSession.unlockForConfiguration()
|
||||
}
|
||||
do {
|
||||
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue)
|
||||
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
|
||||
try self.rtcAudioSession.overrideOutputAudioPort(enabled ? .speaker : .none)
|
||||
let hasExternalAudioDevice = self.rtcAudioSession.session.hasExternalAudioDevice()
|
||||
if enabled {
|
||||
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.defaultToSpeaker, .allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
|
||||
try self.rtcAudioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)
|
||||
if hasExternalAudioDevice, let preferred = self.rtcAudioSession.session.preferredInputDevice() {
|
||||
try self.rtcAudioSession.setPreferredInput(preferred)
|
||||
} else {
|
||||
try self.rtcAudioSession.overrideOutputAudioPort(.speaker)
|
||||
}
|
||||
} else {
|
||||
try self.rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.allowBluetooth, .allowAirPlay, .allowBluetoothA2DP])
|
||||
try self.rtcAudioSession.setMode(AVAudioSession.Mode.voiceChat.rawValue)
|
||||
try self.rtcAudioSession.overrideOutputAudioPort(.none)
|
||||
}
|
||||
if hasExternalAudioDevice {
|
||||
logger.debug("WebRTCClient: configuring session with external device available, skip configuring speaker")
|
||||
}
|
||||
try self.rtcAudioSession.setActive(true)
|
||||
logger.debug("WebRTCClient: configuring session with speaker enabled \(enabled) success")
|
||||
} catch let error {
|
||||
@@ -658,6 +672,17 @@ extension WebRTCClient {
|
||||
}
|
||||
}
|
||||
|
||||
extension AVAudioSession {
|
||||
func hasExternalAudioDevice() -> Bool {
|
||||
availableInputs?.allSatisfy({ $0.portType == .builtInMic }) != true
|
||||
}
|
||||
|
||||
func preferredInputDevice() -> AVAudioSessionPortDescription? {
|
||||
// logger.debug("Preferred input device: \(String(describing: self.availableInputs?.filter({ $0.portType != .builtInMic })))")
|
||||
return availableInputs?.filter({ $0.portType != .builtInMic }).last
|
||||
}
|
||||
}
|
||||
|
||||
struct CustomRTCSessionDescription: Codable {
|
||||
public var type: RTCSdpType?
|
||||
public var sdp: String?
|
||||
|
||||
@@ -29,11 +29,6 @@
|
||||
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
|
||||
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
|
||||
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
|
||||
5C2217B62BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217B12BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV-ghc9.6.3.a */; };
|
||||
5C2217B72BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217B22BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV.a */; };
|
||||
5C2217B82BDA9B7000A8B0E7 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217B32BDA9B7000A8B0E7 /* libgmp.a */; };
|
||||
5C2217B92BDA9B7000A8B0E7 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217B42BDA9B7000A8B0E7 /* libgmpxx.a */; };
|
||||
5C2217BA2BDA9B7000A8B0E7 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C2217B52BDA9B7000A8B0E7 /* libffi.a */; };
|
||||
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
|
||||
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
|
||||
5C2E260F27A30FDC00F70299 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260E27A30FDC00F70299 /* ChatView.swift */; };
|
||||
@@ -73,6 +68,11 @@
|
||||
5C9329412929248A0090FFF9 /* ScanProtocolServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9329402929248A0090FFF9 /* ScanProtocolServer.swift */; };
|
||||
5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C971E1C27AEBEF600C8A3CE /* ChatInfoView.swift */; };
|
||||
5C971E2127AEBF8300C8A3CE /* ChatInfoImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C971E2027AEBF8300C8A3CE /* ChatInfoImage.swift */; };
|
||||
5C9731F72BDC0C4F000538F2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9731F22BDC0C4F000538F2 /* libffi.a */; };
|
||||
5C9731F82BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9731F32BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB.a */; };
|
||||
5C9731F92BDC0C4F000538F2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9731F42BDC0C4F000538F2 /* libgmpxx.a */; };
|
||||
5C9731FA2BDC0C4F000538F2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9731F52BDC0C4F000538F2 /* libgmp.a */; };
|
||||
5C9731FB2BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C9731F62BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB-ghc9.6.3.a */; };
|
||||
5C9A5BDB2871E05400A5B906 /* SetNotificationsMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9A5BDA2871E05400A5B906 /* SetNotificationsMode.swift */; };
|
||||
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9C2DA42894777E00CC63B1 /* GroupProfileView.swift */; };
|
||||
5C9C2DA7289957AE00CC63B1 /* AdvancedNetworkSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C9C2DA6289957AE00CC63B1 /* AdvancedNetworkSettings.swift */; };
|
||||
@@ -188,6 +188,8 @@
|
||||
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
|
||||
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */; };
|
||||
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */; };
|
||||
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */; };
|
||||
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */; };
|
||||
8CC956EE2BC0041000412A11 /* NetworkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CC956ED2BC0041000412A11 /* NetworkObserver.swift */; };
|
||||
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
|
||||
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
|
||||
@@ -279,11 +281,6 @@
|
||||
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
|
||||
5C13730C2815740A00F43030 /* DebugJSON.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = DebugJSON.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
|
||||
5C2217B12BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
5C2217B22BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV.a"; sourceTree = "<group>"; };
|
||||
5C2217B32BDA9B7000A8B0E7 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C2217B42BDA9B7000A8B0E7 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C2217B52BDA9B7000A8B0E7 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C245F3C2B501E98001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
5C245F3D2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = "tr.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
5C245F3E2B501F13001CC39F /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
@@ -349,6 +346,11 @@
|
||||
5C9329402929248A0090FFF9 /* ScanProtocolServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanProtocolServer.swift; sourceTree = "<group>"; };
|
||||
5C971E1C27AEBEF600C8A3CE /* ChatInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoView.swift; sourceTree = "<group>"; };
|
||||
5C971E2027AEBF8300C8A3CE /* ChatInfoImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInfoImage.swift; sourceTree = "<group>"; };
|
||||
5C9731F22BDC0C4F000538F2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C9731F32BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB.a"; sourceTree = "<group>"; };
|
||||
5C9731F42BDC0C4F000538F2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C9731F52BDC0C4F000538F2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C9731F62BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
5C9A5BDA2871E05400A5B906 /* SetNotificationsMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetNotificationsMode.swift; sourceTree = "<group>"; };
|
||||
5C9C2DA42894777E00CC63B1 /* GroupProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupProfileView.swift; sourceTree = "<group>"; };
|
||||
5C9C2DA6289957AE00CC63B1 /* AdvancedNetworkSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedNetworkSettings.swift; sourceTree = "<group>"; };
|
||||
@@ -483,6 +485,8 @@
|
||||
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
|
||||
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToDevice.swift; sourceTree = "<group>"; };
|
||||
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromDevice.swift; sourceTree = "<group>"; };
|
||||
8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioDevicePicker.swift; sourceTree = "<group>"; };
|
||||
8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallAudioDeviceManager.swift; sourceTree = "<group>"; };
|
||||
8CC956ED2BC0041000412A11 /* NetworkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkObserver.swift; sourceTree = "<group>"; };
|
||||
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
|
||||
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
@@ -525,13 +529,13 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5C2217B92BDA9B7000A8B0E7 /* libgmpxx.a in Frameworks */,
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
5C2217B82BDA9B7000A8B0E7 /* libgmp.a in Frameworks */,
|
||||
5C2217B62BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV-ghc9.6.3.a in Frameworks */,
|
||||
5C2217BA2BDA9B7000A8B0E7 /* libffi.a in Frameworks */,
|
||||
5C9731F92BDC0C4F000538F2 /* libgmpxx.a in Frameworks */,
|
||||
5C9731F82BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB.a in Frameworks */,
|
||||
5C9731F72BDC0C4F000538F2 /* libffi.a in Frameworks */,
|
||||
5C9731FA2BDC0C4F000538F2 /* libgmp.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
5C2217B72BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV.a in Frameworks */,
|
||||
5C9731FB2BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB-ghc9.6.3.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -549,6 +553,8 @@
|
||||
5C55A922283CEDE600C4E99E /* SoundPlayer.swift */,
|
||||
18415323A4082FC92887F906 /* WebRTCClient.swift */,
|
||||
18415B08031E8FB0F7FC27F9 /* CallViewRenderers.swift */,
|
||||
8CC4ED8F2BD7B8530078AEE8 /* CallAudioDeviceManager.swift */,
|
||||
8C81482B2BD91CD4002CBEC3 /* AudioDevicePicker.swift */,
|
||||
);
|
||||
path = Call;
|
||||
sourceTree = "<group>";
|
||||
@@ -595,11 +601,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C2217B52BDA9B7000A8B0E7 /* libffi.a */,
|
||||
5C2217B32BDA9B7000A8B0E7 /* libgmp.a */,
|
||||
5C2217B42BDA9B7000A8B0E7 /* libgmpxx.a */,
|
||||
5C2217B12BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV-ghc9.6.3.a */,
|
||||
5C2217B22BDA9B7000A8B0E7 /* libHSsimplex-chat-5.7.0.4-9w48ibH0KftLfWfQjuLznV.a */,
|
||||
5C9731F22BDC0C4F000538F2 /* libffi.a */,
|
||||
5C9731F52BDC0C4F000538F2 /* libgmp.a */,
|
||||
5C9731F42BDC0C4F000538F2 /* libgmpxx.a */,
|
||||
5C9731F62BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB-ghc9.6.3.a */,
|
||||
5C9731F32BDC0C4F000538F2 /* libHSsimplex-chat-5.7.0.5-KRbIOKUzDlJ3qPYhEOgsVB.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -1237,6 +1243,7 @@
|
||||
5CB346E52868AA7F001FD2EF /* SuspendChat.swift in Sources */,
|
||||
5C9C2DA52894777E00CC63B1 /* GroupProfileView.swift in Sources */,
|
||||
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */,
|
||||
8C81482C2BD91CD4002CBEC3 /* AudioDevicePicker.swift in Sources */,
|
||||
5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */,
|
||||
5C764E89279CBCB3000C6508 /* ChatModel.swift in Sources */,
|
||||
5C971E1D27AEBEF600C8A3CE /* ChatInfoView.swift in Sources */,
|
||||
@@ -1266,6 +1273,7 @@
|
||||
18415B0585EB5A9A0A7CA8CD /* PressedButtonStyle.swift in Sources */,
|
||||
1841560FD1CD447955474C1D /* UserProfilesView.swift in Sources */,
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */,
|
||||
8CC4ED902BD7B8530078AEE8 /* CallAudioDeviceManager.swift in Sources */,
|
||||
18415C6C56DBCEC2CBBD2F11 /* WebRTCClient.swift in Sources */,
|
||||
184152CEF68D2336FC2EBCB0 /* CallViewRenderers.swift in Sources */,
|
||||
5CB634AD29E46CF70066AD6B /* LocalAuthView.swift in Sources */,
|
||||
@@ -1544,7 +1552,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 212;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -1593,7 +1601,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 212;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -1679,7 +1687,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 212;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
@@ -1716,7 +1724,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 212;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
@@ -1753,7 +1761,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 212;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -1804,7 +1812,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 210;
|
||||
CURRENT_PROJECT_VERSION = 212;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
|
||||
@@ -689,6 +689,7 @@ fun WebRTCView(callCommand: SnapshotStateList<WCallCommand>, onResponse: (WVAPIM
|
||||
this.clearHistory()
|
||||
this.clearCache(true)
|
||||
this.addJavascriptInterface(WebRTCInterface(onResponse), "WebRTCInterface")
|
||||
this.setBackgroundColor(android.graphics.Color.BLACK)
|
||||
val webViewSettings = this.settings
|
||||
webViewSettings.allowFileAccess = true
|
||||
webViewSettings.allowContentAccess = true
|
||||
|
||||
@@ -26,11 +26,11 @@ android.enableJetifier=true
|
||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||
kotlin.jvm.target=11
|
||||
|
||||
android.version_name=5.7-beta.3
|
||||
android.version_code=199
|
||||
android.version_name=5.7
|
||||
android.version_code=200
|
||||
|
||||
desktop.version_name=5.7-beta.3
|
||||
desktop.version_code=40
|
||||
desktop.version_name=5.7
|
||||
desktop.version_code=41
|
||||
|
||||
kotlin.version=1.9.23
|
||||
gradle.plugin.version=8.2.0
|
||||
|
||||
@@ -1,13 +1,115 @@
|
||||
|
||||
---
|
||||
layout: layouts/article.html
|
||||
title: "SimpleX network: legally binding transparency, v5.7 released with better user experience for calls and messages"
|
||||
title: "SimpleX network: legally binding transparency, v5.7 released with better calls and messages"
|
||||
date: 2024-04-26
|
||||
preview: blog_previews/20240323.html
|
||||
draft: true
|
||||
previewBody: blog_previews/20240426.html
|
||||
image: images/20240426-profile.png
|
||||
imageBottom: true
|
||||
permalink: "/blog/20240426-simplex-legally-binding-transparency-v5-7-better-user-experience.html"
|
||||
---
|
||||
|
||||
# SimpleX network: legally binding transparency, v5.7 released with better user experience for calls and messages
|
||||
# SimpleX network: legally binding transparency, v5.7 released with better calls and messages
|
||||
|
||||
This is a permalink for the post
|
||||
What's new in v5.7:
|
||||
- [quantum resistant end-to-end encryption](#quantum-resistant-end-to-end-encryption) with all contacts.
|
||||
- [forward and save messages](#forward-and-save-messages) without revealing the source.
|
||||
- [in-call sounds and switching sound sources](#in-call-sounds-and-switching-sound-sources).
|
||||
- [better network connection management](#network-management).
|
||||
- [customizable profile images](#customizable-shape-of-profile-images)
|
||||
|
||||
Also, we added Lithuanian interface language to the Android and desktop apps, thanks to [our users and Weblate](https://github.com/simplex-chat/simplex-chat#help-translating-simplex-chat).
|
||||
|
||||
## Legally binding transparency
|
||||
|
||||
We are committed to open-source, privacy and security. Here are the recent changes we made:
|
||||
|
||||
- We now have a [Transparency Reports](https://simplex.chat/transparency/) page.
|
||||
- We updated our [Privacy Policy](https://github.com/simplex-chat/simplex-chat/blob/stable/PRIVACY.md) to remove undefined terms "impermissible" and "acceptable", which would allow us to remove anything we don't like, without any clarity on what that is. You can see the edits [here](https://github.com/simplex-chat/simplex-chat/pull/4076/files).
|
||||
- We published a new page with [Frequently Asked Questions](https://simplex.chat/faq/), thanks to the guidance from users.
|
||||
- We also have a new [Security Policy](https://simplex.chat/security/) – we welcome your feedback on it.
|
||||
|
||||
What do we mean by “legally binding transparency?”. It includes these principles:
|
||||
- Accountability: an empty promise or commitment to transparency that is not legally binding is just marketing, and can provide opportunities for the organizations to be misleading or not disclose important information that can affect their users privacy and security.
|
||||
- Consistency: often, there's a disconnect between marketing claims and legally binding policies. Our approach is to ensure that promises made in marketing materials or any external communications align with our legally binding documents, so that users can rely on our promises, and know exactly what to expect from us.
|
||||
|
||||
For example:
|
||||
- we use open-source code, and we made a legally binding commitment to use the published code in all released apps and deployed preset servers.
|
||||
- we use precise and technical language in the Privacy Policy defining what data and metadata can be accessed via the preset relays.
|
||||
|
||||
If you see any inconsistency between technical parameters of SimpleX Network and what is promised in our Privacy Policy please raise it with us.
|
||||
|
||||
## What's new in v5.7
|
||||
|
||||
This release focus is improving the app usability, and preparing the foundation for v5.8 that will provide an in-built protection of user IP addresses when connecting to unknown file and messaging servers, reducing the need to use Tor (which would still remain supported via SOCKS proxy, for additional privacy).
|
||||
|
||||
### Quantum resistant end-to-end encryption
|
||||
|
||||
<img src="./images/20240426-pq.png" width="288" class="float-right">
|
||||
|
||||
We [wrote before](./20240314-simplex-chat-v5-6-quantum-resistance-signal-double-ratchet-algorithm.md) about how quantum resistant encryption was added to SimpleX Chat and also about other properties of end-to-end encryption, possible attacks on its security and known mitigations.
|
||||
|
||||
Quantum resistant encryption will now be enabled by default in all direct chats. For the new conversations it will be enabled from the beginning, and for the existing conversations it will be agreed after you exchange several messages with your contacts - you will see a notice in the conversation when it happens.
|
||||
|
||||
You can still safely downgrade the app to an earlier version if needed, as v5.6 already supports quantum resistant encryption.
|
||||
|
||||
With the users who have an earlier version, the app will work using the conventional encryption, which is still very secure. It's important that we augmented the conventional encryption with post-quantum cryptographic algorithm rather than replaced it, using a hybrid construction as recommended by the cryptography experts.
|
||||
|
||||
The groups currently do not support quantum resistant encryption yet - we plan to add it in the future to small groups.
|
||||
|
||||
### Forward and save messages
|
||||
|
||||
You can now save received messages to private notes and forward them to your contacts and groups. This is both more convenient than copy-pasting the messages, and also more private - you can forward files and preserve a disappearing file in your private notes without saving them outside of the app.
|
||||
|
||||
You can see and navigate to the original source of the message via the message information, but the recipient of the message can only see that it was forwarded, but not from which conversation - in this way you can show that the message was quoted from another source without revealing the source ([Chatham House Rule](https://en.wikipedia.org/wiki/Chatham_House_rule)).
|
||||
|
||||
<img src="./images/20240426-forward1.png" width="288"> <img src="./images/20240426-forward2.png" width="288"> <img src="./images/20240426-forward3.png" width="288">
|
||||
|
||||
### In-call sounds and switching sound sources
|
||||
|
||||
This was the most frequent request of the users who use SimpleX Chat for audio and video calls - to add sound indication to the connection progress, as happens in all other apps. This release added these sounds and also vibration when call connects and disconnects.
|
||||
|
||||
You can also switch between bluetooth headphones, speakerphone and earpiece via the new button in the call.
|
||||
|
||||
### Network management
|
||||
|
||||
To reduce traffic and battery usage, this release made connection timeouts dependent on which network your device uses - timeouts will be larger when you are on mobile connection and smaller when on WiFi. It also makes connection attempts very infrequent when the device is not connected to network.
|
||||
|
||||
### Customizable shape of profile images
|
||||
|
||||
To customizable the interface, you can now change the shapes of profile images to anything from squares with sharp corners to circles, as before, via the Appearance menu in the app Settings. The default shape of profile images is changed to squares with rounded corners.
|
||||
|
||||
<img src="./images/20240426-profile1.png" width="288"> <img src="./images/20240426-profile2.png" width="288"> <img src="./images/20240426-profile3.png" width="288">
|
||||
|
||||
## SimpleX network
|
||||
|
||||
Some links to answer the most common questions:
|
||||
|
||||
[How can SimpleX deliver messages without user identifiers](./20220511-simplex-chat-v2-images-files.md#the-first-messaging-platform-without-user-identifiers).
|
||||
|
||||
[What are the risks to have identifiers assigned to the users](./20220711-simplex-chat-v3-released-ios-notifications-audio-video-calls-database-export-import-protocol-improvements.md#why-having-users-identifiers-is-bad-for-the-users).
|
||||
|
||||
[Technical details and limitations](https://github.com/simplex-chat/simplex-chat#privacy-technical-details-and-limitations).
|
||||
|
||||
[Frequently asked questions](../docs/FAQ.md).
|
||||
|
||||
Please also see our [website](https://simplex.chat).
|
||||
|
||||
## Help us with donations
|
||||
|
||||
Huge thank you to everybody who donates to SimpleX Chat!
|
||||
|
||||
We are planning a 3rd party security audit for the protocols and cryptography design in July 2024, and also the security audit for an implementation in December 2024/January 2025, and it would hugely help us if some part of this $50,000+ expense is covered with donations.
|
||||
|
||||
We are prioritizing users privacy and security - it would be impossible without your support.
|
||||
|
||||
Our pledge to our users is that SimpleX protocols are and will remain open, and in public domain, - so anybody can build the future implementations of the clients and the servers. We are building SimpleX network based on the same principles as email and web, but much more private and secure.
|
||||
|
||||
Your donations help us raise more funds – any amount, even the price of the cup of coffee, makes a big difference for us.
|
||||
|
||||
See [this section](https://github.com/simplex-chat/simplex-chat/tree/master#help-us-with-donations) for the ways to donate.
|
||||
|
||||
Thank you,
|
||||
|
||||
Evgeny
|
||||
|
||||
SimpleX Chat founder
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# Blog
|
||||
|
||||
Apr 26, 2024 [SimpleX network: legally binding transparency, v5.7 released with better calls and messages](./20240426-simplex-legally-binding-transparency-v5-7-better-user-experience.md)
|
||||
|
||||
We published Transparency Reports, Security Policy, and Frequently Asked Questions, and updated Privacy Policy.
|
||||
|
||||
We are committed to have full consistency between marketing promises and legally binding documents.
|
||||
|
||||
What's new in v5.7:
|
||||
- quantum resistant end-to-end encryption with all contacts.
|
||||
- forward and save messages without revealing the source.
|
||||
- in-call sounds and switching sound sources.
|
||||
- better network connection management.
|
||||
- customizable profile images
|
||||
|
||||
---
|
||||
|
||||
Apr 16. 2024 [The dangers of metadata in messengers](./20240416-dangers-of-metadata-in-messengers.md)
|
||||
|
||||
_By [Esra'a al Shafei](https://mastodon.social/@alshafei)_
|
||||
|
||||
|
After Width: | Height: | Size: 769 KiB |
|
After Width: | Height: | Size: 288 KiB |
|
After Width: | Height: | Size: 503 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 280 KiB |
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 168 KiB |
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Transparency Reports
|
||||
permalink: /transparency/index.html
|
||||
revision: 09.04.2024
|
||||
revision: 26.04.2024
|
||||
---
|
||||
|
||||
# Transparency Reports
|
||||
|
||||
**Updated**: Apr 9, 2024
|
||||
**Updated**: Apr 26, 2024
|
||||
|
||||
SimpleX Chat Ltd. is a company registered in the UK – it develops communication software enabling users to operate and communicate via SimpleX network, without user profile identifiers of any kind, and without having their data hosted by any network infrastructure operators.
|
||||
|
||||
@@ -17,8 +17,8 @@ This page will include any and all reports on requests for user data.
|
||||
Our objective is to consistently ensure that no user data and absolute minimum of the metadata required for the network to function is available for disclosure by any infrastructure operators, under any circumstances.
|
||||
|
||||
**Helpful resources**:
|
||||
- [Privacy policy](https://github.com/simplex-chat/simplex-chat/blob/stable/PRIVACY.md)
|
||||
- [Privacy and security: technical details and limitations](https://github.com/simplex-chat/simplex-chat?tab=readme-ov-file#privacy-and-security-technical-details-and-limitations)
|
||||
- [Privacy policy](../PRIVACY.md)
|
||||
- [Privacy and security: technical details and limitations](../README.md#privacy-and-security-technical-details-and-limitations)
|
||||
- Whitepaper:
|
||||
- [Trust in servers](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#trust-in-servers)
|
||||
- [Encryption Primitives Used](https://github.com/simplex-chat/simplexmq/blob/stable/protocol/overview-tjr.md#encryption-primitives-used)
|
||||
|
||||
@@ -8,9 +8,9 @@ u="$USER"
|
||||
tmp="$(mktemp -d -t)"
|
||||
folder="$tmp/simplex-chat"
|
||||
|
||||
nix_ver="nix-2.19.2"
|
||||
nix_ver="nix-2.22.0"
|
||||
nix_url="https://releases.nixos.org/nix/$nix_ver/install"
|
||||
nix_hash="435f0d7e11f7c7dffeeab0ec9cc55723f6d3c03352379d785633cf4ddb5caf90"
|
||||
nix_hash="4fed7db867186c01ce2a2077da4a6950ed16232efbf78d0cd19700cff80559f9"
|
||||
nix_config="sandbox = true
|
||||
max-jobs = auto
|
||||
experimental-features = nix-command flakes"
|
||||
@@ -43,12 +43,13 @@ nix_setup() {
|
||||
}
|
||||
|
||||
git_setup() {
|
||||
[ "$folder" != "." ] && {
|
||||
if [ "$folder" != "." ]; then
|
||||
git clone "$repo" "$folder"
|
||||
}
|
||||
fi
|
||||
|
||||
# Switch to nix-android branch
|
||||
git -C "$folder" checkout "$commit"
|
||||
if [ -z ${git_skip+x} ]; then
|
||||
git -C "$folder" checkout "$commit"
|
||||
fi
|
||||
}
|
||||
|
||||
checks() {
|
||||
@@ -100,14 +101,10 @@ build() {
|
||||
sed -i.bak 's/${extract_native_libs}/true/' "$folder/apps/multiplatform/android/src/main/AndroidManifest.xml"
|
||||
sed -i.bak 's/jniLibs.useLegacyPackaging =.*/jniLibs.useLegacyPackaging = true/' "$folder/apps/multiplatform/android/build.gradle.kts"
|
||||
sed -i.bak '/android {/a lint {abortOnError = false}' "$folder/apps/multiplatform/android/build.gradle.kts"
|
||||
sed -i.bak '/tasks/Q' "$folder/apps/multiplatform/android/build.gradle.kts"
|
||||
|
||||
for arch in $arches; do
|
||||
|
||||
tag_full="$(git tag --points-at HEAD | head -n1)"
|
||||
tag_version="${tag_full%%-*}"
|
||||
|
||||
if [ "$arch" = "armv7a" ] && [ -n "$tag_full" ] ; then
|
||||
git checkout "${tag_version}-armv7a"
|
||||
if [ "$arch" = "armv7a" ]; then
|
||||
android_simplex_lib="${folder}#hydraJobs.${arch}-android:lib:simplex-chat.x86_64-linux"
|
||||
android_support_lib="${folder}#hydraJobs.${arch}-android:lib:support.x86_64-linux"
|
||||
else
|
||||
@@ -150,10 +147,6 @@ build() {
|
||||
zipalign -p -f 4 "$tmp/$android_apk_output_final" "$PWD/$android_apk_output_final"
|
||||
|
||||
rm -rf "$libs_folder/$android_arch"
|
||||
|
||||
if [ "$arch" = "armv7a" ] && [ -n "$tag_full" ] ; then
|
||||
git checkout "${tag_full}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -161,15 +154,22 @@ final() {
|
||||
printf 'Simplex-chat was successfully compiled: %s/simplex-chat-*.apk\nDelete nix and gradle caches with "rm -rf /nix && rm $HOME/.nix* && $HOME/.gradle/caches" in case if no longer needed.\n' "$PWD"
|
||||
}
|
||||
|
||||
main() {
|
||||
while getopts ":s" opt; do
|
||||
pre() {
|
||||
while getopts ":sg" opt; do
|
||||
case $opt in
|
||||
s) folder="." ;;
|
||||
g) git_skip=1 ;;
|
||||
*) printf "Flag '-%s' doesn't exist.\n" "$OPTARG"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $(( $OPTIND - 1 ))
|
||||
commit="$1"; shift 1
|
||||
|
||||
commit="${1:-HEAD}"
|
||||
}
|
||||
|
||||
main() {
|
||||
pre "$@"
|
||||
git_setup
|
||||
checks
|
||||
build
|
||||
|
||||
@@ -394,6 +394,9 @@ module.exports = function (ty) {
|
||||
if (parsed.path.startsWith("../../blog")) {
|
||||
parsed.path = parsed.path.replace("../../blog", "/blog")
|
||||
}
|
||||
if (parsed.path.startsWith("../PRIVACY.md")) {
|
||||
parsed.path = parsed.path.replace("../PRIVACY.md", "/privacy")
|
||||
}
|
||||
parsed.path = parsed.path.replace(/\.md$/, ".html").toLowerCase()
|
||||
return uri.serialize(parsed)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"copyright-label": "© 2020-2023 SimpleX | Open-Source Project",
|
||||
"simplex-chat-protocol": "SimpleX Chat protocol",
|
||||
"terminal-cli": "Terminal CLI",
|
||||
"terms-and-privacy-policy": "Terms & Privacy Policy",
|
||||
"terms-and-privacy-policy": "Privacy Policy",
|
||||
"hero-header": "Privacy redefined",
|
||||
"hero-subheader": "The first messenger<br>without user IDs",
|
||||
"hero-p-1": "Other apps have user IDs: Signal, Matrix, Session, Briar, Jami, Cwtch, etc.<br> SimpleX does not, <strong>not even random numbers</strong>.<br> This radically improves your privacy.",
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<p><strong>Legally binding transparency</strong></p>
|
||||
|
||||
<ul class="mb-[12px]">
|
||||
<li>We published Transparency Reports, Security Policy, and Frequently Asked Questions, and updated Privacy Policy.</li>
|
||||
<li>We are committed to have full consistency between marketing promises and legally binding documents.</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>v5.7 is released:</strong></p>
|
||||
|
||||
<ul class="mb-[12px]">
|
||||
<li>quantum resistant end-to-end encryption with all contacts.</li>
|
||||
<li>forward and save messages without revealing the source.</li>
|
||||
<li>in-call sounds and switching sound sources.</li>
|
||||
<li>better network connection management.</li>
|
||||
<li>customizable profile images.</li>
|
||||
</ul>
|
||||
@@ -20,11 +20,9 @@
|
||||
{{ "simplex-chat-protocol" | i18n({}, lang ) | safe }}
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a>
|
||||
<a href="https://github.com/simplex-chat/simplex-chat/blob/stable/PRIVACY.md"
|
||||
target="_blank"
|
||||
<a href="/privacy"
|
||||
class="text-grey-black dark:text-white text-[14px] font-medium leading-[28px] tracking-[0.01em] mb-3 flex items-center gap-1">
|
||||
{{ "terms-and-privacy-policy" | i18n({}, lang ) | safe }}
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a>
|
||||
<a href="https://github.com/simplex-chat/simplex-chat#help-us-with-donations"
|
||||
target="_blank"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ page.url | getlang }}"
|
||||
{% for language in languages.languages %}
|
||||
{% if language.label == page.url | getlang %}
|
||||
dir="{{ "rtl" if language.rtl else "ltr" }}"
|
||||
{% endif %}
|
||||
{% endfor %}>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>SimpleX Privacy Policy</title>
|
||||
<meta name="Content-Type" content="text/html;charset=utf-8" />
|
||||
<meta http-equiv="onion-location" content="{% cfg 'onionLocation' %}{{ permalink }}" />
|
||||
<meta property="og:url" content="{% cfg 'siteLocation' %}{{ permalink }}" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:title" content="{{ title }}" />
|
||||
{% if image %}
|
||||
<meta property="og:image" content="{% cfg 'siteLocation' %}/blog/{{ image }}" />
|
||||
{% else %}
|
||||
<meta property="og:image" content="{% cfg 'siteLocation' %}/img/share_simplex.png" />
|
||||
{% endif %}
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon.ico" />
|
||||
<link href="/css/tailwind.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/css/blog.css" />
|
||||
<link href="/css/style.css" rel="stylesheet" />
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="bg-[#F3F6F7] dark:bg-[#0C0B13]">
|
||||
{% include "navbar.html" %}
|
||||
|
||||
<section id="article" class="container mt-[25px] mb-[75px] bg-white dark:bg-[#17203D] px-5">
|
||||
<div class="py-6 md:p-[60px]">{{ content | safe }}</div>
|
||||
</section>
|
||||
|
||||
{% include "footer.html" %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -60,6 +60,8 @@
|
||||
>Whitepaper
|
||||
<svg class="float-right" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg>
|
||||
</a></li>
|
||||
<li><a href="/privacy" class="lg:px-[20px] inline-block"
|
||||
>{{ "terms-and-privacy-policy" | i18n({}, lang ) | safe }}</a></li>
|
||||
<li><a href="https://github.com/simplex-chat/simplexmq/blob/stable/protocol/simplex-messaging.md"
|
||||
target="_blank" class="lg:px-[20px] flex items-center gap-1"
|
||||
>{{ "smp-protocol" | i18n({}, lang ) | safe }}
|
||||
|
||||
@@ -8,6 +8,7 @@ rm website/src/docs/lang/*/README.md
|
||||
cp -R blog website/src
|
||||
cp -R images website/src
|
||||
rm website/src/blog/README.md
|
||||
cp PRIVACY.md website/src/privacy.md
|
||||
cd website
|
||||
|
||||
langs=()
|
||||
|
||||