Merge branch 'stable' into stable-android

This commit is contained in:
Evgeny Poberezkin
2025-12-10 17:46:56 +00:00
21 changed files with 338 additions and 175 deletions

View File

@@ -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}

View File

@@ -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" || :

View File

@@ -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}

View File

@@ -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)
&nbsp;
[![Android app](https://github.com/simplex-chat/.github/blob/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
[![Android app](https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
&nbsp;
[<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)
&nbsp;
[<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)
&nbsp;
[<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)
&nbsp;
[![Android app](https://github.com/simplex-chat/.github/blob/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
[![Android app](https://raw.githubusercontent.com/simplex-chat/.github/refs/heads/master/profile/images/google_play.svg)](https://play.google.com/store/apps/details?id=chat.simplex.app)
&nbsp;
[<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)
&nbsp;
[<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)
&nbsp;
[<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)

View File

@@ -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
}
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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

View File

@@ -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()

View File

@@ -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
)
}
)
}

View File

@@ -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()
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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()

View 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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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