mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 14:15:55 +00:00
Merge branch 'stable' into stable-android
This commit is contained in:
40
.github/workflows/build.yml
vendored
40
.github/workflows/build.yml
vendored
@@ -221,6 +221,16 @@ jobs:
|
||||
done
|
||||
strip /out/simplex-chat
|
||||
|
||||
- name: Build CLI deb
|
||||
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
|
||||
shell: docker exec -t builder sh -eu {0}
|
||||
run: |
|
||||
version=${{ github.ref }}
|
||||
version=${version#refs/tags/v}
|
||||
version=${version%-*}
|
||||
|
||||
./scripts/desktop/build-cli-deb.sh "$version"
|
||||
|
||||
- name: Copy tests from container
|
||||
if: matrix.should_run == true
|
||||
shell: bash
|
||||
@@ -232,21 +242,41 @@ jobs:
|
||||
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
|
||||
shell: bash
|
||||
run: |
|
||||
docker cp builder:/out/simplex-chat ./simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}
|
||||
path="${{ github.workspace }}/simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}"
|
||||
echo "bin_path=$path" >> $GITHUB_OUTPUT
|
||||
echo "bin_hash=$(echo SHA2-256\(simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}\)= $(openssl sha256 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
|
||||
cli_name="simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}"
|
||||
cli_deb_name="${cli_name}.deb"
|
||||
cli_path="${{ github.workspace }}"
|
||||
|
||||
docker cp builder:/out/simplex-chat "./${cli_name}"
|
||||
docker cp builder:/out/deb-build/simplex-chat.deb "./${cli_deb_name}"
|
||||
|
||||
echo "bin_name=${cli_name}" >> $GITHUB_OUTPUT
|
||||
echo "bin_path=${cli_path}/${cli_name}" >> $GITHUB_OUTPUT
|
||||
echo "bin_hash=$(echo SHA2-256\(${cli_name}\)= $(openssl sha256 "${cli_path}/${cli_name}" | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "deb_name=${cli_deb_name}" >> $GITHUB_OUTPUT
|
||||
echo "deb_path=${cli_path}/${cli_deb_name}" >> $GITHUB_OUTPUT
|
||||
echo "deb_hash=$(echo SHA2-256\(${cli_deb_name}\)= $(openssl sha256 "${cli_path}/${cli_deb_name}" | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload CLI
|
||||
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
|
||||
uses: ./.github/actions/prepare-release
|
||||
with:
|
||||
bin_name: ${{ steps.linux_cli_prepare.outputs.bin_name }}
|
||||
bin_path: ${{ steps.linux_cli_prepare.outputs.bin_path }}
|
||||
bin_name: simplex-chat-ubuntu-${{ matrix.os_underscore }}-${{ matrix.arch }}
|
||||
bin_hash: ${{ steps.linux_cli_prepare.outputs.bin_hash }}
|
||||
github_ref: ${{ github.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload CLI deb
|
||||
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
|
||||
uses: ./.github/actions/prepare-release
|
||||
with:
|
||||
bin_name: ${{ steps.linux_cli_prepare.outputs.deb_name }}
|
||||
bin_path: ${{ steps.linux_cli_prepare.outputs.deb_path }}
|
||||
bin_hash: ${{ steps.linux_cli_prepare.outputs.deb_hash }}
|
||||
github_ref: ${{ github.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build Desktop
|
||||
if: startsWith(github.ref, 'refs/tags/v') && matrix.should_run == true
|
||||
shell: docker exec -t builder sh -eu {0}
|
||||
|
||||
13
.github/workflows/reproduce-schedule.yml
vendored
13
.github/workflows/reproduce-schedule.yml
vendored
@@ -9,9 +9,6 @@ jobs:
|
||||
reproduce:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get latest release
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -23,6 +20,16 @@ jobs:
|
||||
grep -i "tag_name" | \
|
||||
awk -F \" '{print "TAG="$4}' >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.TAG }}
|
||||
repository: simplex-chat/simplex-chat
|
||||
|
||||
# Otherwise we run out of disk space with Docker build
|
||||
- name: Free disk space
|
||||
shell: bash
|
||||
run: ./scripts/ci/linux_util_free_space.sh
|
||||
- name: Execute reproduce script
|
||||
run: |
|
||||
${GITHUB_WORKSPACE}/scripts/simplex-chat-reproduce-builds.sh "$TAG" || :
|
||||
|
||||
@@ -6,7 +6,9 @@ FROM ubuntu:${TAG} AS build
|
||||
|
||||
ARG GHC=9.6.3
|
||||
ARG CABAL=3.10.2.0
|
||||
ARG JAVA=17
|
||||
ARG JAVA_VER=17.0.17.10.1
|
||||
ARG JAVA_HASH_AMD64=e3e11daa5c22a45153bbeff1a0c21bf08631791e4e8d8ed14deba31c7cf9af1a
|
||||
ARG JAVA_HASH_ARM64=2b460859b681757b33a7591b6238ecaf51569d05d2684984e5f0a89c6514acbc
|
||||
|
||||
ENV TZ=Etc/UTC \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
@@ -44,10 +46,26 @@ RUN apt-get update && \
|
||||
# depends on libjpeg.so.8 and liblcms2.so.2 which are NOT copied into final
|
||||
# /usr/lib/runtime/lib directory and I do not have time to figure out gradle.kotlin
|
||||
# to fix this :(
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf 'https://apt.corretto.aws/corretto.key' | gpg --dearmor -o /usr/share/keyrings/corretto-keyring.gpg &&\
|
||||
echo "deb [signed-by=/usr/share/keyrings/corretto-keyring.gpg] https://apt.corretto.aws stable main" > /etc/apt/sources.list.d/corretto.list &&\
|
||||
apt update &&\
|
||||
apt install -y java-${JAVA}-amazon-corretto-jdk
|
||||
RUN export JAVA_FILENAME='java-corretto.deb' \
|
||||
JAVA_VER_MAJOR=$(printf "${JAVA_VER}" | awk -F. '{print $1}') \
|
||||
JAVA_VER_DEB=$(printf "${JAVA_VER}" | sed 's/\.1$/-1/') && \
|
||||
case "$(uname -m)" in \
|
||||
x86_64) export JAVA_ARCH='amd64' JAVA_HASH="$JAVA_HASH_AMD64" ;; \
|
||||
aarch64) export JAVA_ARCH='arm64' JAVA_HASH="$JAVA_HASH_ARM64" ;; \
|
||||
*) echo "unknown arch $(uname -m)" && exit 1 ;; \
|
||||
esac && \
|
||||
curl --proto '=https' --tlsv1.2 -sSf \
|
||||
"https://corretto.aws/downloads/resources/${JAVA_VER}/java-${JAVA_VER_MAJOR}-amazon-corretto-jdk_${JAVA_VER_DEB}_${JAVA_ARCH}.deb" \
|
||||
-o "${JAVA_FILENAME}" && \
|
||||
if echo "${JAVA_HASH} ${JAVA_FILENAME}" | sha256sum -c -; then \
|
||||
if apt install -y ./"${JAVA_FILENAME}"; then \
|
||||
rm ./"${JAVA_FILENAME}"; \
|
||||
else \
|
||||
echo "Failed to install Java Corretto" && exit 1; \
|
||||
fi \
|
||||
else \
|
||||
echo "Checksum mismatch" && exit 1; \
|
||||
fi
|
||||
|
||||
# Specify bootstrap Haskell versions
|
||||
ENV BOOTSTRAP_HASKELL_GHC_VERSION=${GHC}
|
||||
|
||||
22
README.md
22
README.md
@@ -24,15 +24,15 @@
|
||||
|
||||
## Install the app
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
|
||||
- 🖲 Protects your messages and metadata - who you talk to and when.
|
||||
- 🔐 Double ratchet end-to-end encryption, with additional encryption layer.
|
||||
@@ -102,7 +102,7 @@ You need to share a link with your friend or scan a QR code from their phone, in
|
||||
|
||||
The channel through which you share the link does not have to be secure - it is enough that you can confirm who sent you the message and that your SimpleX connection is established.
|
||||
|
||||
<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app1.png" alt="Make a private connection" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/arrow.png" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app2.png" alt="Conversation" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/arrow.png" height="360"> <img src="https://github.com/simplex-chat/.github/blob/master/profile/images/app3.png" alt="Video call" height="360">
|
||||
<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/app1.png" alt="Make a private connection" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/arrow.png" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/app2.png" alt="Conversation" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/arrow.png" height="360"> <img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/app3.png" alt="Video call" height="360">
|
||||
|
||||
After you connect, you can [verify connection security code](./blog/20230103-simplex-chat-v4.4-disappearing-messages.md#connection-security-verification).
|
||||
|
||||
@@ -443,12 +443,12 @@ Please do NOT report security vulnerabilities via GitHub issues.
|
||||
|
||||
This software is licensed under the GNU Affero General Public License version 3 (AGPLv3). See the [LICENSE](./LICENSE) file for details. The SimpleX and SimpleX Chat name, logo, and associated branding materials are not covered by this license and are subject to the terms outlined in the [TRADEMARK](./docs/TRADEMARK.md) file.
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apple_store.svg" alt="iOS app" height="42">](https://apps.apple.com/us/app/simplex-chat/id1605771084)
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
[](https://play.google.com/store/apps/details?id=chat.simplex.app)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/f_droid.svg" alt="F-Droid" height="41">](https://app.simplex.chat)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/testflight.png" alt="iOS TestFlight" height="41">](https://testflight.apple.com/join/DWuT2LQu)
|
||||
|
||||
[<img src="https://github.com/simplex-chat/.github/blob/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
[<img src="https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/apk_icon.png" alt="APK" height="41">](https://github.com/simplex-chat/simplex-chat/releases/latest/download/simplex.apk)
|
||||
|
||||
@@ -48,7 +48,7 @@ func apiSetEncryptLocalFiles(_ enable: Bool) throws {
|
||||
throw r.unexpected
|
||||
}
|
||||
|
||||
func apiGetChats(userId: User.ID) throws -> Array<ChatData> {
|
||||
func apiGetChats(userId: User.ID) throws -> Array<SEChatData> {
|
||||
let r: APIResult<SEChatResponse> = sendSimpleXCmd(SEChatCommand.apiGetChats(userId: userId))
|
||||
if case let .result(.apiChats(user: _, chats: chats)) = r { return chats }
|
||||
throw r.unexpected
|
||||
@@ -170,7 +170,7 @@ enum SEChatResponse: Decodable, ChatAPIResult {
|
||||
case activeUser(user: User)
|
||||
case chatStarted
|
||||
case chatRunning
|
||||
case apiChats(user: UserRef, chats: [ChatData])
|
||||
case apiChats(user: UserRef, chats: [SEChatData])
|
||||
case newChatItems(user: UserRef, chatItems: [AChatItem])
|
||||
case cmdOk(user_: UserRef?)
|
||||
|
||||
@@ -199,7 +199,7 @@ enum SEChatResponse: Decodable, ChatAPIResult {
|
||||
}
|
||||
|
||||
static func fallbackResult(_ type: String, _ json: NSDictionary) -> SEChatResponse? {
|
||||
if type == "apiChats", let r = parseApiChats(json) {
|
||||
if type == "apiChats", let r = seParseApiChats(json) {
|
||||
.apiChats(user: r.user, chats: r.chats)
|
||||
} else {
|
||||
nil
|
||||
@@ -239,3 +239,35 @@ enum SEChatEvent: Decodable, ChatAPIResult {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct SEChatData: Decodable, Identifiable, Hashable, ChatLike {
|
||||
public var chatInfo: ChatInfo
|
||||
|
||||
public var id: ChatId { get { chatInfo.id } }
|
||||
|
||||
public init(chatInfo: ChatInfo) {
|
||||
self.chatInfo = chatInfo
|
||||
}
|
||||
|
||||
public static func invalidJSON(_ json: Data?) -> SEChatData {
|
||||
SEChatData(chatInfo: .invalidJSON(json: json))
|
||||
}
|
||||
}
|
||||
|
||||
public func seParseApiChats(_ jResp: NSDictionary) -> (user: UserRef, chats: [SEChatData])? {
|
||||
if let jApiChats = jResp["apiChats"] as? NSDictionary,
|
||||
let user: UserRef = try? decodeObject(jApiChats["user"] as Any),
|
||||
let jChats = jApiChats["chats"] as? NSArray {
|
||||
let chats: [SEChatData] = jChats.map { jChat in
|
||||
if let jChatDict = jChat as? NSDictionary,
|
||||
let jChatInfo = jChatDict["chatInfo"],
|
||||
let chatInfo: ChatInfo = try? decodeObject(jChatInfo) {
|
||||
return SEChatData(chatInfo: chatInfo)
|
||||
}
|
||||
return SEChatData.invalidJSON(serializeJSON(jChat, options: .prettyPrinted))
|
||||
}
|
||||
return (user, chats)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ private let MAX_DOWNSAMPLE_SIZE: Int64 = 2000
|
||||
|
||||
class ShareModel: ObservableObject {
|
||||
@Published var sharedContent: SharedContent?
|
||||
@Published var chats: [ChatData] = []
|
||||
@Published var chats: [SEChatData] = []
|
||||
@Published var profileImages: [ChatInfo.ID: UIImage] = [:]
|
||||
@Published var search = ""
|
||||
@Published var comment = ""
|
||||
@Published var selected: ChatData?
|
||||
@Published var selected: SEChatData?
|
||||
@Published var isLoaded = false
|
||||
@Published var bottomBar: BottomBar = .loadingSpinner
|
||||
@Published var errorAlert: ErrorAlert?
|
||||
@@ -60,13 +60,13 @@ class ShareModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func isProhibited(_ chat: ChatData?) -> Bool {
|
||||
func isProhibited(_ chat: SEChatData?) -> Bool {
|
||||
if let chat, let sharedContent {
|
||||
sharedContent.prohibited(in: chat, hasSimplexLink: hasSimplexLink)
|
||||
} else { false }
|
||||
}
|
||||
|
||||
var filteredChats: [ChatData] {
|
||||
var filteredChats: [SEChatData] {
|
||||
search.isEmpty
|
||||
? filterChatsToForwardTo(chats: chats)
|
||||
: filterChatsToForwardTo(chats: chats)
|
||||
@@ -253,7 +253,7 @@ class ShareModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchChats() -> Result<Array<ChatData>, ErrorAlert> {
|
||||
private func fetchChats() -> Result<Array<SEChatData>, ErrorAlert> {
|
||||
do {
|
||||
guard let user = try apiGetActiveUser() else {
|
||||
return .failure(
|
||||
@@ -396,7 +396,7 @@ enum SharedContent {
|
||||
}
|
||||
}
|
||||
|
||||
func prohibited(in chatData: ChatData, hasSimplexLink: Bool) -> Bool {
|
||||
func prohibited(in chatData: SEChatData, hasSimplexLink: Bool) -> Bool {
|
||||
chatData.prohibitedByPref(
|
||||
hasSimplexLink: hasSimplexLink,
|
||||
isMediaOrFileAttachment: cryptoFile != nil,
|
||||
|
||||
@@ -178,8 +178,8 @@
|
||||
64C3B0212A0D359700E19930 /* CustomTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C3B0202A0D359700E19930 /* CustomTimePicker.swift */; };
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829982D54AEED006B9E89 /* libgmp.a */; };
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C829992D54AEEE006B9E89 /* libffi.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf.a */; };
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW-ghc9.6.3.a */; };
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW.a */; };
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64C8299C2D54AEEE006B9E89 /* libgmpxx.a */; };
|
||||
64D0C2C029F9688300B38D5F /* UserAddressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2BF29F9688300B38D5F /* UserAddressView.swift */; };
|
||||
64D0C2C229FA57AB00B38D5F /* UserAddressLearnMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */; };
|
||||
@@ -545,8 +545,8 @@
|
||||
64C3B0202A0D359700E19930 /* CustomTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTimePicker.swift; sourceTree = "<group>"; };
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf.a"; sourceTree = "<group>"; };
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW-ghc9.6.3.a"; sourceTree = "<group>"; };
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW.a"; sourceTree = "<group>"; };
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
64D0C2BF29F9688300B38D5F /* UserAddressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressView.swift; sourceTree = "<group>"; };
|
||||
64D0C2C129FA57AB00B38D5F /* UserAddressLearnMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAddressLearnMore.swift; sourceTree = "<group>"; };
|
||||
@@ -708,8 +708,8 @@
|
||||
64C8299D2D54AEEE006B9E89 /* libgmp.a in Frameworks */,
|
||||
64C8299E2D54AEEE006B9E89 /* libffi.a in Frameworks */,
|
||||
64C829A12D54AEEE006B9E89 /* libgmpxx.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf.a in Frameworks */,
|
||||
64C8299F2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW-ghc9.6.3.a in Frameworks */,
|
||||
64C829A02D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW.a in Frameworks */,
|
||||
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -795,8 +795,8 @@
|
||||
64C829992D54AEEE006B9E89 /* libffi.a */,
|
||||
64C829982D54AEED006B9E89 /* libgmp.a */,
|
||||
64C8299C2D54AEEE006B9E89 /* libgmpxx.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.0-2IZGcIMPMD3yeDBZO9qRf.a */,
|
||||
64C8299A2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW-ghc9.6.3.a */,
|
||||
64C8299B2D54AEEE006B9E89 /* libHSsimplex-chat-6.4.7.1-A5UtRanLEGiKe0gro2y2nW.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@@ -2003,7 +2003,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2053,7 +2053,7 @@
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -2095,7 +2095,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
@@ -2115,7 +2115,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
@@ -2140,7 +2140,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = s;
|
||||
@@ -2177,7 +2177,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_CODE_COVERAGE = NO;
|
||||
@@ -2214,7 +2214,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -2265,7 +2265,7 @@
|
||||
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
|
||||
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
@@ -2316,7 +2316,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
@@ -2350,7 +2350,7 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 311;
|
||||
DEVELOPMENT_TEAM = 5NN7GUYB6T;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
public protocol ChatLike {
|
||||
var chatInfo: ChatInfo { get}
|
||||
var chatItems: [ChatItem] { get }
|
||||
var chatStats: ChatStats { get }
|
||||
var chatInfo: ChatInfo { get }
|
||||
}
|
||||
|
||||
extension ChatLike {
|
||||
|
||||
@@ -21,7 +21,7 @@ sealed class WriteFileResult {
|
||||
* */
|
||||
|
||||
fun writeCryptoFile(path: String, data: ByteArray): CryptoFileArgs {
|
||||
val ctrl = ChatController.ctrl ?: throw Exception("Controller is not initialized")
|
||||
val ctrl = ChatController.getChatCtrl() ?: throw Exception("Controller is not initialized")
|
||||
val buffer = ByteBuffer.allocateDirect(data.size)
|
||||
buffer.put(data)
|
||||
buffer.rewind()
|
||||
@@ -44,7 +44,7 @@ fun readCryptoFile(path: String, cryptoArgs: CryptoFileArgs): ByteArray {
|
||||
}
|
||||
|
||||
fun encryptCryptoFile(fromPath: String, toPath: String): CryptoFileArgs {
|
||||
val ctrl = ChatController.ctrl ?: throw Exception("Controller is not initialized")
|
||||
val ctrl = ChatController.getChatCtrl() ?: throw Exception("Controller is not initialized")
|
||||
val str = chatEncryptFile(ctrl, fromPath, toPath)
|
||||
val d = json.decodeFromString(WriteFileResult.serializer(), str)
|
||||
return when (d) {
|
||||
|
||||
@@ -482,17 +482,26 @@ class AppPreferences {
|
||||
private const val MESSAGE_TIMEOUT: Int = 300_000_000
|
||||
|
||||
object ChatController {
|
||||
var ctrl: ChatCtrl? = -1
|
||||
private var chatCtrl: ChatCtrl? = -1
|
||||
val appPrefs: AppPreferences by lazy { AppPreferences() }
|
||||
|
||||
val messagesChannel: Channel<API> = Channel()
|
||||
|
||||
val chatModel = ChatModel
|
||||
private var receiverStarted = false
|
||||
private var receiverJob: Job? = null
|
||||
var lastMsgReceivedTimestamp: Long = System.currentTimeMillis()
|
||||
private set
|
||||
|
||||
fun hasChatCtrl() = ctrl != -1L && ctrl != null
|
||||
fun hasChatCtrl() = chatCtrl != -1L && chatCtrl != null
|
||||
|
||||
fun getChatCtrl(): ChatCtrl? = chatCtrl
|
||||
|
||||
fun setChatCtrl(ctrl: ChatCtrl?) {
|
||||
val wasRunning = receiverJob != null
|
||||
stopReceiver()
|
||||
chatCtrl = ctrl
|
||||
if (wasRunning && ctrl != null) startReceiver()
|
||||
}
|
||||
|
||||
suspend fun getAgentSubsTotal(rh: Long?): Pair<SMPServerSubs, Boolean>? {
|
||||
val userId = currentUserId("getAgentSubsTotal")
|
||||
@@ -639,17 +648,16 @@ object ChatController {
|
||||
|
||||
private fun startReceiver() {
|
||||
Log.d(TAG, "ChatController startReceiver")
|
||||
if (receiverStarted) return
|
||||
receiverStarted = true
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
if (receiverJob != null || chatCtrl == null) return
|
||||
receiverJob = CoroutineScope(Dispatchers.IO).launch {
|
||||
var releaseLock: (() -> Unit) = {}
|
||||
while (true) {
|
||||
while (isActive) {
|
||||
/** Global [ctrl] can be null. It's needed for having the same [ChatModel] that already made in [ChatController] without the need
|
||||
* to change it everywhere in code after changing a database.
|
||||
* Since it can be changed in background thread, making this check to prevent NullPointerException */
|
||||
val ctrl = ctrl
|
||||
val ctrl = chatCtrl
|
||||
if (ctrl == null) {
|
||||
receiverStarted = false
|
||||
stopReceiver()
|
||||
break
|
||||
}
|
||||
try {
|
||||
@@ -689,6 +697,15 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopReceiver() {
|
||||
Log.d(TAG, "ChatController stopReceiver")
|
||||
val job = receiverJob
|
||||
if (job != null) {
|
||||
receiverJob = null
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun sendCmdWithRetry(rhId: Long?, cmd: CC, inProgress: MutableState<Boolean>? = null, retryNum: Int = 0): API? {
|
||||
val r = sendCmd(rhId, cmd, retryNum = retryNum)
|
||||
val alert = if (r is API.Error) retryableNetworkErrorAlert(r.err) else null
|
||||
@@ -773,7 +790,7 @@ object ChatController {
|
||||
}
|
||||
|
||||
suspend fun sendCmd(rhId: Long?, cmd: CC, otherCtrl: ChatCtrl? = null, retryNum: Int = 0, log: Boolean = true): API {
|
||||
val ctrl = otherCtrl ?: ctrl ?: throw Exception("Controller is not initialized")
|
||||
val ctrl = otherCtrl ?: chatCtrl ?: throw Exception("Controller is not initialized")
|
||||
|
||||
return withContext(Dispatchers.IO) {
|
||||
val c = cmd.cmdString
|
||||
|
||||
@@ -56,6 +56,7 @@ fun initChatControllerOnStart() {
|
||||
}
|
||||
|
||||
suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: () -> CompletableDeferred<Boolean> = { CompletableDeferred(true) }) {
|
||||
Log.d(TAG, "initChatController")
|
||||
try {
|
||||
if (chatModel.ctrlInitInProgress.value) return
|
||||
chatModel.ctrlInitInProgress.value = true
|
||||
@@ -92,7 +93,7 @@ suspend fun initChatController(useKey: String? = null, confirmMigrations: Migrat
|
||||
val ctrl = if (res is DBMigrationResult.OK) {
|
||||
migrated[1] as Long
|
||||
} else null
|
||||
chatController.ctrl = ctrl
|
||||
chatController.setChatCtrl(ctrl)
|
||||
chatModel.chatDbEncrypted.value = dbKey != ""
|
||||
chatModel.chatDbStatus.value = res
|
||||
if (res != DBMigrationResult.OK) {
|
||||
@@ -206,7 +207,7 @@ fun chatInitControllerRemovingDatabases() {
|
||||
}.getOrElse { DBMigrationResult.Unknown(migrated[0] as String) }
|
||||
|
||||
val ctrl = migrated[1] as Long
|
||||
chatController.ctrl = ctrl
|
||||
chatController.setChatCtrl(ctrl)
|
||||
// We need only controller, not databases
|
||||
File(dbPath + "_chat.db").delete()
|
||||
File(dbPath + "_agent.db").delete()
|
||||
|
||||
@@ -804,7 +804,8 @@ fun SimpleXTheme(darkTheme: Boolean? = null, content: @Composable () -> Unit) {
|
||||
LocalAppColors provides rememberedAppColors,
|
||||
LocalAppWallpaper provides rememberedWallpaper,
|
||||
LocalDensity provides density,
|
||||
content = content)
|
||||
content = content
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ fun UserPicker(
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
// Controller.ctrl can be null when self-destructing activates
|
||||
if (controller.ctrl != null && controller.ctrl != -1L) {
|
||||
if (controller.hasChatCtrl()) {
|
||||
withBGApi {
|
||||
controller.reloadRemoteHosts()
|
||||
}
|
||||
|
||||
@@ -366,6 +366,7 @@ fun startChat(
|
||||
chatDbChanged: MutableState<Boolean>,
|
||||
progressIndicator: MutableState<Boolean>? = null
|
||||
) {
|
||||
Log.d(TAG, "startChat")
|
||||
withLongRunningApi {
|
||||
try {
|
||||
progressIndicator?.value = true
|
||||
@@ -532,7 +533,7 @@ fun deleteChatDatabaseFilesAndState() {
|
||||
appPrefs.newDatabaseInitialized.set(false)
|
||||
chatModel.desktopOnboardingRandomPassword.value = false
|
||||
controller.appPrefs.storeDBPassphrase.set(true)
|
||||
controller.ctrl = null
|
||||
controller.setChatCtrl(null)
|
||||
|
||||
// Clear sensitive data on screen just in case ModalManager will fail to prevent hiding its modals while database encrypts itself
|
||||
chatModel.chatId.value = null
|
||||
|
||||
@@ -33,7 +33,7 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) {
|
||||
}
|
||||
} else {
|
||||
val r: LAResult = if (passcode.value == authRequest.password) {
|
||||
if (authRequest.selfDestruct && sdPassword != null && controller.ctrl == -1L) {
|
||||
if (authRequest.selfDestruct && sdPassword != null && controller.getChatCtrl() == -1L) {
|
||||
initChatControllerOnStart()
|
||||
}
|
||||
LAResult.Success
|
||||
@@ -58,7 +58,7 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (
|
||||
if (m.chatRunning.value == true) {
|
||||
stopChatAsync(m)
|
||||
}
|
||||
val ctrl = m.controller.ctrl
|
||||
val ctrl = m.controller.getChatCtrl()
|
||||
if (ctrl != null && ctrl != -1L) {
|
||||
/**
|
||||
* The following sequence can bring a user here:
|
||||
|
||||
@@ -633,7 +633,7 @@ private fun MutableState<MigrationToState?>.startDownloading(
|
||||
private fun MutableState<MigrationToState?>.importArchive(archivePath: String, netCfg: NetCfg, networkProxy: NetworkProxy?) {
|
||||
withLongRunningApi {
|
||||
try {
|
||||
if (ChatController.ctrl == null || ChatController.ctrl == -1L) {
|
||||
if (!ChatController.hasChatCtrl()) {
|
||||
chatInitControllerRemovingDatabases()
|
||||
}
|
||||
controller.apiDeleteStorage()
|
||||
|
||||
37
scripts/desktop/build-cli-deb.sh
Executable file
37
scripts/desktop/build-cli-deb.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env sh
|
||||
set -eu
|
||||
|
||||
export SOURCE_DATE_EPOCH=1764547200
|
||||
|
||||
CLI_VERSION="$1"
|
||||
CLI_PATH_TO_BIN="${2:-/out/simplex-chat}"
|
||||
BUILD_FOLDER="${3:-/out/deb-build}"
|
||||
|
||||
size=$(stat -c '%s' "$CLI_PATH_TO_BIN" | awk '{printf "%.0f\n", ($1+1023)/1024}')
|
||||
arch=$(case "$(uname -m)" in x86_64) printf "amd64" ;; aarch64) printf "arm64" ;; *) printf "unknown" ;; esac)
|
||||
package='simplex-chat'
|
||||
|
||||
mkdir "$BUILD_FOLDER"
|
||||
cd "$BUILD_FOLDER"
|
||||
|
||||
mkdir -p ./${package}/DEBIAN
|
||||
mkdir -p ./${package}/usr/bin
|
||||
cat > ./${package}/DEBIAN/control << EOF
|
||||
Package: ${package}
|
||||
Version: ${CLI_VERSION}
|
||||
Section: Messenger
|
||||
Priority: optional
|
||||
Architecture: ${arch}
|
||||
Maintainer: SimpleX Chat <chat@simplex.chat>
|
||||
Description: SimpleX - the first messaging platform that has no user identifiers of any kind - 100% private by design! (CLI)
|
||||
Installed-Size: ${size}
|
||||
EOF
|
||||
|
||||
cp "$CLI_PATH_TO_BIN" ./${package}/usr/bin/simplex-chat
|
||||
chmod +x ./${package}/usr/bin/simplex-chat
|
||||
|
||||
find ./${package} -exec touch -d "@${SOURCE_DATE_EPOCH}" {} +
|
||||
|
||||
dpkg-deb --build --root-owner-group --uniform-compression ./${package}
|
||||
|
||||
strip-nondeterminism "./${package}.deb"
|
||||
@@ -20,115 +20,133 @@ package direct-sqlcipher
|
||||
|
||||
export DOCKER_BUILDKIT=1
|
||||
|
||||
version=${TAG#v}
|
||||
version=${version%-*}
|
||||
|
||||
cleanup() {
|
||||
docker exec -t "${container_name}" sh -c 'rm -rf ./dist-newstyle ./apps' 2>/dev/null || :
|
||||
rm -rf -- "${tempdir}"
|
||||
docker rm --force "${container_name}" 2>/dev/null || :
|
||||
docker image rm "${image_name}" 2>/dev/null || :
|
||||
cd "${init_dir}"
|
||||
docker exec -t "${container_name}" sh -c 'rm -rf ./dist-newstyle ./apps' 2>/dev/null || :
|
||||
rm -rf -- "${tempdir}"
|
||||
docker rm --force "${container_name}" 2>/dev/null || :
|
||||
docker image rm "${image_name}" 2>/dev/null || :
|
||||
cd "${init_dir}"
|
||||
}
|
||||
trap 'cleanup' EXIT INT
|
||||
|
||||
mkdir -p "${init_dir}/${TAG}-${repo_name}/from-source" "${init_dir}/${TAG}-${repo_name}/prebuilt"
|
||||
|
||||
git -C "${tempdir}" clone "${repo}.git" &&\
|
||||
cd "${tempdir}/${repo_name}" &&\
|
||||
git checkout "${TAG}"
|
||||
cd "${tempdir}/${repo_name}" &&\
|
||||
git checkout "${TAG}"
|
||||
|
||||
for os in '22.04' '24.04'; do
|
||||
os_url="$(printf '%s' "${os}" | tr '.' '_')"
|
||||
os_url="$(printf '%s' "${os}" | tr '.' '_')"
|
||||
|
||||
cli_name="simplex-chat-ubuntu-${os_url}-x86_64"
|
||||
deb_name="simplex-desktop-ubuntu-${os_url}-x86_64.deb"
|
||||
appimage_name="simplex-desktop-x86_64.AppImage"
|
||||
cli_name="simplex-chat-ubuntu-${os_url}-x86_64"
|
||||
deb_name="simplex-desktop-ubuntu-${os_url}-x86_64.deb"
|
||||
appimage_name="simplex-desktop-x86_64.AppImage"
|
||||
|
||||
# Build image
|
||||
docker build \
|
||||
--no-cache \
|
||||
--build-arg TAG="${os}" \
|
||||
--build-arg GHC="${ghc}" \
|
||||
-f "${tempdir}/${repo_name}/Dockerfile.build" \
|
||||
-t "${image_name}" \
|
||||
.
|
||||
# Build image
|
||||
docker build \
|
||||
--no-cache \
|
||||
--build-arg TAG="${os}" \
|
||||
--build-arg GHC="${ghc}" \
|
||||
-f "${tempdir}/${repo_name}/Dockerfile.build" \
|
||||
-t "${image_name}" \
|
||||
.
|
||||
|
||||
printf '%s' "${cabal_local}" > "${tempdir}/${repo_name}/cabal.project.local"
|
||||
printf '%s' "${cabal_local}" > "${tempdir}/${repo_name}/cabal.project.local"
|
||||
|
||||
# Run container in background
|
||||
docker run -t -d \
|
||||
--name "${container_name}" \
|
||||
--device /dev/fuse \
|
||||
--cap-add SYS_ADMIN \
|
||||
--security-opt apparmor:unconfined \
|
||||
-v "${tempdir}/${repo_name}:/project" \
|
||||
"${image_name}"
|
||||
# Run container in background
|
||||
docker run -t -d \
|
||||
--name "${container_name}" \
|
||||
--device /dev/fuse \
|
||||
--cap-add SYS_ADMIN \
|
||||
--security-opt apparmor:unconfined \
|
||||
-v "${tempdir}/${repo_name}:/project" \
|
||||
"${image_name}"
|
||||
|
||||
# Consistent permissions
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c 'find /project -type d -exec chmod 755 {} \; ; find /project -type f -perm /111 -exec chmod 755 {} \; ; find /project -type f ! -perm /111 -exec chmod 644 {} \;'
|
||||
# Consistent permissions
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c 'find /project -type d -exec chmod 755 {} \; ; find /project -type f -perm /111 -exec chmod 755 {} \; ; find /project -type f ! -perm /111 -exec chmod 644 {} \;'
|
||||
|
||||
# CLI
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c 'cabal clean && cabal update && cabal build -j && mkdir -p /out && for i in simplex-chat; do bin=$(find /project/dist-newstyle -name "$i" -type f -executable) && chmod +x "$bin" && mv "$bin" /out/; done && strip /out/simplex-chat'
|
||||
# CLI
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c 'cabal clean && cabal update && cabal build -j && mkdir -p /out && for i in simplex-chat; do bin=$(find /project/dist-newstyle -name "$i" -type f -executable) && chmod +x "$bin" && mv "$bin" /out/; done && strip /out/simplex-chat'
|
||||
|
||||
# Copy CLI
|
||||
docker cp \
|
||||
"${container_name}":/out/simplex-chat \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${cli_name}"
|
||||
# Copy CLI
|
||||
docker cp \
|
||||
"${container_name}":/out/simplex-chat \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${cli_name}"
|
||||
|
||||
# Download prebuilt CLI binary
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${cli_name}"
|
||||
# Download prebuilt CLI binary
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${cli_name}"
|
||||
|
||||
# Desktop: deb
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c './scripts/desktop/make-deb-linux.sh'
|
||||
# CLI: deb
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c "./scripts/desktop/build-cli-deb.sh ${version}"
|
||||
|
||||
# Copy deb
|
||||
docker cp \
|
||||
"${container_name}":/project/apps/multiplatform/release/main/deb/simplex_x86_64.deb \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${deb_name}"
|
||||
# Copy CLI: deb
|
||||
docker cp \
|
||||
"${container_name}":/out/deb-build/simplex-chat.deb \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${cli_name}.deb"
|
||||
|
||||
# Download prebuilt deb package
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${deb_name}"
|
||||
# Download prebuilt CLI: deb binary
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${cli_name}.deb"
|
||||
|
||||
# Desktop: appimage. Build only on 22.04
|
||||
case "$os" in
|
||||
22.04)
|
||||
# Appimage
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c './scripts/desktop/make-appimage-linux.sh && mv ./apps/multiplatform/release/main/*imple*.AppImage ./apps/multiplatform/release/main/simplex.appimage'
|
||||
# Desktop: deb
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c './scripts/desktop/make-deb-linux.sh'
|
||||
|
||||
# Copy appimage
|
||||
docker cp \
|
||||
"${container_name}":/project/apps/multiplatform/release/main/simplex.appimage \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${appimage_name}"
|
||||
# Copy deb
|
||||
docker cp \
|
||||
"${container_name}":/project/apps/multiplatform/release/main/deb/simplex_x86_64.deb \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${deb_name}"
|
||||
|
||||
# Download prebuilt appimage binary
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${appimage_name}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Important! Remove dist-newstyle for the next interation
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c 'rm -rf ./dist-newstyle ./apps/multiplatform'
|
||||
# Download prebuilt deb package
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${deb_name}"
|
||||
|
||||
# Also restore git to previous state
|
||||
git reset --hard && git clean -dfx
|
||||
# Desktop: appimage. Build only on 22.04
|
||||
case "$os" in
|
||||
22.04)
|
||||
# Appimage
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c './scripts/desktop/make-appimage-linux.sh && mv ./apps/multiplatform/release/main/*imple*.AppImage ./apps/multiplatform/release/main/simplex.appimage'
|
||||
|
||||
# Stop containers, delete images
|
||||
docker stop "${container_name}"
|
||||
docker rm --force "${container_name}"
|
||||
docker image rm "${image_name}"
|
||||
# Copy appimage
|
||||
docker cp \
|
||||
"${container_name}":/project/apps/multiplatform/release/main/simplex.appimage \
|
||||
"${init_dir}/${TAG}-${repo_name}/from-source/${appimage_name}"
|
||||
|
||||
# Download prebuilt appimage binary
|
||||
curl -L \
|
||||
--output-dir "${init_dir}/${TAG}-${repo_name}/prebuilt/" \
|
||||
-O "${repo}/releases/download/${TAG}/${appimage_name}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Important! Remove dist-newstyle for the next interation
|
||||
docker exec \
|
||||
-t "${container_name}" \
|
||||
sh -c 'rm -rf ./dist-newstyle ./apps/multiplatform'
|
||||
|
||||
# Also restore git to previous state
|
||||
git reset --hard && git clean -dfx
|
||||
|
||||
# Stop containers, delete images
|
||||
docker stop "${container_name}"
|
||||
docker rm --force "${container_name}"
|
||||
docker image rm "${image_name}"
|
||||
done
|
||||
|
||||
# Cleanup
|
||||
@@ -145,27 +163,27 @@ bad=0
|
||||
|
||||
# Check hashes for all binaries
|
||||
for file in "${path_bin}"/from-source/*; do
|
||||
# Extract binary name
|
||||
app="$(basename ${file})"
|
||||
# Extract binary name
|
||||
app="$(basename ${file})"
|
||||
|
||||
# Compute hash for compiled binary
|
||||
compiled=$(sha256sum "${path_bin}/from-source/${app}" | awk '{print $1}')
|
||||
# Compute hash for prebuilt binary
|
||||
prebuilt=$(sha256sum "${path_bin}/prebuilt/${app}" | awk '{print $1}')
|
||||
# Compute hash for compiled binary
|
||||
compiled=$(sha256sum "${path_bin}/from-source/${app}" | awk '{print $1}')
|
||||
# Compute hash for prebuilt binary
|
||||
prebuilt=$(sha256sum "${path_bin}/prebuilt/${app}" | awk '{print $1}')
|
||||
|
||||
# Compare
|
||||
if [ "${compiled}" != "${prebuilt}" ]; then
|
||||
# If hashes doesn't match, set bad...
|
||||
bad=1
|
||||
# Compare
|
||||
if [ "${compiled}" != "${prebuilt}" ]; then
|
||||
# If hashes doesn't match, set bad...
|
||||
bad=1
|
||||
|
||||
# ... and print affected binary
|
||||
printf "%s - sha256sum hash doesn't match\n" "${app}"
|
||||
fi
|
||||
# ... and print affected binary
|
||||
printf "%s - sha256sum hash doesn't match\n" "${app}"
|
||||
fi
|
||||
done
|
||||
|
||||
# If everything is still okay, compute checksums file
|
||||
if [ "${bad}" = 0 ]; then
|
||||
sha256sum "${path_bin}"/from-source/* | sed -e "s|$PWD/||g" -e 's|from-source/||g' -e "s|-$repo_name||g" > "${path_bin}/_sha256sums"
|
||||
sha256sum "${path_bin}"/from-source/* | sed -e "s|$PWD/||g" -e 's|from-source/||g' -e "s|-$repo_name||g" > "${path_bin}/_sha256sums"
|
||||
|
||||
printf 'Checksums computed - %s\n' "${path_bin}/_sha256sums"
|
||||
printf 'Checksums computed - %s\n' "${path_bin}/_sha256sums"
|
||||
fi
|
||||
|
||||
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 6.4.7.1
|
||||
version: 6.4.8.0
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
|
||||
@@ -93,6 +93,9 @@ xit' = if os == "linux" then xit else it
|
||||
xit'' :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
|
||||
xit'' = ifCI xit Hspec.it
|
||||
|
||||
xitMacCI :: HasCallStack => String -> (TestParams -> Expectation) -> SpecWith (Arg (TestParams -> Expectation))
|
||||
xitMacCI = ifCI (if os == "darwin" then xit else it) it
|
||||
|
||||
xdescribe'' :: HasCallStack => String -> SpecWith a -> SpecWith a
|
||||
xdescribe'' = ifCI xdescribe describe
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ remoteTests = describe "Remote" $ do
|
||||
it "connects with new pairing (stops mobile)" $ remoteHandshakeTest False
|
||||
it "connects with new pairing (stops desktop)" $ remoteHandshakeTest True
|
||||
it "connects with stored pairing" remoteHandshakeStoredTest
|
||||
it "connects with multicast discovery" remoteHandshakeDiscoverTest
|
||||
xitMacCI "connects with multicast discovery" remoteHandshakeDiscoverTest
|
||||
it "refuses invalid client cert" remoteHandshakeRejectTest
|
||||
it "connects with stored server bindings" storedBindingsTest
|
||||
it "sends messages" remoteMessageTest
|
||||
|
||||
Reference in New Issue
Block a user