Compare commits

..

106 Commits

Author SHA1 Message Date
Evgeny Poberezkin
dc8ca4cf89 Merge tag 'v5.4.0' into master-android 2023-11-25 11:23:23 +00:00
Evgeny Poberezkin
b62dd801f1 Merge branch 'master-ghc8107' into master-android 2023-11-24 20:02:05 +00:00
Evgeny Poberezkin
0c096e2c89 Merge branch 'master' into master-ghc8107 2023-11-24 19:00:30 +00:00
Evgeny Poberezkin
cc127e56fe Merge branch 'master' into master-android 2023-11-23 16:23:02 +00:00
Evgeny Poberezkin
1781495ee3 Merge branch 'master' into master-ghc8107 2023-11-23 16:22:46 +00:00
Evgeny Poberezkin
831231d8e6 Merge branch 'master-ghc8107' into master-android 2023-11-21 21:16:04 +00:00
Evgeny Poberezkin
45102442f4 Merge branch 'master' into master-ghc8107 2023-11-21 21:15:10 +00:00
spaced4ndy
f323c8e112 Merge branch 'master-ghc8107' into master-android 2023-11-21 19:42:28 +04:00
spaced4ndy
3bdc6b5e28 Merge branch 'master' into master-ghc8107 2023-11-21 19:41:06 +04:00
Evgeny Poberezkin
d8373262bc Merge branch 'master-ghc8107' into master-android 2023-11-21 00:01:20 +00:00
Evgeny Poberezkin
3597d34716 Merge branch 'master' into master-ghc8107 2023-11-21 00:00:59 +00:00
Evgeny Poberezkin
bd4259e89e update hpack 2023-11-20 14:43:20 +00:00
Evgeny Poberezkin
55ead740cc update hpack 2023-11-20 14:43:05 +00:00
Evgeny Poberezkin
5ef0eda2d7 Merge branch 'master-ghc8107' into master-android 2023-11-20 14:30:27 +00:00
Evgeny Poberezkin
49a9b0e7d6 update hpack version 2023-11-20 14:30:10 +00:00
Evgeny Poberezkin
45ada450a2 Merge branch 'master-ghc8107' into master-android 2023-11-20 13:24:07 +00:00
Evgeny Poberezkin
307a1b3c5e fix for ghc 8.10.7 2023-11-20 13:23:45 +00:00
Evgeny Poberezkin
ed6b3bbead Merge branch 'master' into master-ghc8107 2023-11-20 13:01:22 +00:00
spaced4ndy
901610eec5 Merge branch 'master-ghc8107' into master-android 2023-11-20 14:08:10 +04:00
spaced4ndy
7d4127c51d Merge branch 'master' into master-ghc8107 2023-11-20 14:07:08 +04:00
Evgeny Poberezkin
13215d91d7 Merge branch 'master-ghc8107' into master-android 2023-11-20 00:07:12 +00:00
Evgeny Poberezkin
e1a8099474 fix for GHC 8.10.7 2023-11-20 00:06:45 +00:00
Evgeny Poberezkin
daa8d9bb21 Merge branch 'master' into master-ghc8107 2023-11-19 23:42:13 +00:00
Evgeny Poberezkin
5fcbade1bc Merge branch 'master-ghc8107' into master-android 2023-11-17 11:49:35 +00:00
Evgeny Poberezkin
3937ffa9a6 Merge branch 'master' into master-ghc8107 2023-11-17 11:47:52 +00:00
Evgeny Poberezkin
80ddb50e1c Merge branch 'master-ghc8107' into master-android 2023-11-16 18:55:17 +00:00
Evgeny Poberezkin
f6e66f1c53 Merge branch 'master' into master-ghc8107 2023-11-16 18:13:02 +00:00
Evgeny Poberezkin
0c23ff9ae3 Merge branch 'master-ghc8107' into master-android 2023-11-11 13:57:32 +00:00
Evgeny Poberezkin
1570bc2b99 Merge branch 'master' into master-ghc8107 2023-11-11 13:56:53 +00:00
Evgeny Poberezkin
1e2104cabf Merge branch 'master-ghc8107' into master-android 2023-11-11 09:52:07 +00:00
Evgeny Poberezkin
f3014f258d Merge branch 'master' into master-ghc8107 2023-11-11 09:51:42 +00:00
Evgeny Poberezkin
f0991cc0ba Merge branch 'master-ghc8107' into master-android 2023-11-10 21:22:19 +00:00
Evgeny Poberezkin
74b78a8d7b Merge branch 'master' into master-ghc8107 2023-11-10 21:11:08 +00:00
Evgeny Poberezkin
82cd70a75c Merge branch 'master-ghc8107' into master-android 2023-11-10 21:08:11 +00:00
Evgeny Poberezkin
fe4eb7b5af Merge branch 'master' into master-ghc8107 without changes, to skip update for ghc 9.6.3 2023-11-10 21:04:20 +00:00
Evgeny Poberezkin
c459e71d02 Merge branch 'master-ghc8107' into master-android 2023-11-06 11:26:40 +00:00
Evgeny Poberezkin
2516d5a393 Merge branch 'master' into master-ghc8107 2023-11-06 11:26:22 +00:00
spaced4ndy
477d98d75a Merge branch 'master-ghc8107' into master-android 2023-11-06 11:42:39 +04:00
spaced4ndy
4253cd7fb9 Merge branch 'master' into master-ghc8107 2023-11-06 11:41:55 +04:00
Evgeny Poberezkin
ca78958667 Merge branch 'master-ghc8107' into master-android 2023-11-04 13:39:35 +00:00
Evgeny Poberezkin
1f5b80d560 fix for ghc8107 2023-11-04 13:37:25 +00:00
Evgeny Poberezkin
2de111e76c Merge branch 'master' into master-ghc8107 2023-11-04 13:02:08 +00:00
spaced4ndy
8343285d93 Merge branch 'master-ghc8107' into master-android 2023-10-30 21:01:16 +04:00
spaced4ndy
5dbe2b2745 Merge branch 'master' into master-ghc8107 2023-10-30 21:00:11 +04:00
Evgeny Poberezkin
fb9485190d Merge branch 'master-ghc8107' into master-android 2023-10-29 18:27:00 +00:00
Evgeny Poberezkin
6881600e06 Merge branch 'master' into master-ghc8107 2023-10-29 18:24:13 +00:00
spaced4ndy
9ed723bafa Merge branch 'master-ghc8107' into master-android 2023-10-25 10:48:37 +04:00
spaced4ndy
9ded1c9821 Merge branch 'master' into master-ghc8107 2023-10-25 10:47:35 +04:00
spaced4ndy
bb374c68b1 Merge branch 'master-ghc8107' into master-android 2023-10-24 18:14:22 +04:00
spaced4ndy
c3e82a6a4e Merge branch 'master' into master-ghc8107 2023-10-24 18:13:56 +04:00
spaced4ndy
7c12e82042 Merge branch 'master-ghc8107' into master-android 2023-10-24 17:41:19 +04:00
spaced4ndy
e7e66ff873 Merge branch 'master' into master-ghc8107 2023-10-24 17:40:55 +04:00
Evgeny Poberezkin
c4d7e5307c Merge branch 'master-ghc8107' into master-android 2023-10-22 15:35:55 +01:00
Evgeny Poberezkin
d6b9a45a39 Merge branch 'master' into master-ghc8107 2023-10-22 15:10:33 +01:00
Evgeny Poberezkin
7fd3b4d6ba Merge branch 'master-ghc8107' into master-android 2023-10-18 22:45:11 +01:00
Evgeny Poberezkin
4004aafbc5 Merge branch 'master' into master-ghc8107 2023-10-18 22:44:27 +01:00
spaced4ndy
95008eeeaf Merge branch 'master-ghc8107' into master-android 2023-10-16 20:05:49 +04:00
spaced4ndy
c7a8992043 core: fix compilation for ghc 8.10.7 2023-10-16 20:05:13 +04:00
spaced4ndy
ea2b5f2ccf Merge branch 'master-ghc8107' into master-android 2023-10-16 19:28:48 +04:00
spaced4ndy
ed9f277421 Merge branch 'master' into master-ghc8107 2023-10-16 19:28:06 +04:00
Evgeny Poberezkin
5c14c3b349 Merge branch 'master-ghc8107' into master-android 2023-10-15 18:54:16 +01:00
Evgeny Poberezkin
d8fb31f167 Merge branch 'master' into master-ghc8107 2023-10-15 18:53:23 +01:00
Evgeny Poberezkin
02db38ffd3 Merge branch 'master-ghc8107' into master-android 2023-10-11 21:58:16 +01:00
Evgeny Poberezkin
7692195bfa core: fix for ghc 8.10.7 2023-10-11 21:57:53 +01:00
Evgeny Poberezkin
c435cbdc7b Merge branch 'master-ghc8107' into master-android 2023-10-11 21:28:43 +01:00
Evgeny Poberezkin
effc281271 Merge branch 'master' into master-ghc8107 2023-10-11 21:27:21 +01:00
spaced4ndy
41eb2e5689 Merge branch 'master-ghc8107' into master-android 2023-10-11 13:22:30 +04:00
spaced4ndy
67d74a0a27 Merge branch 'master' into master-ghc8107 2023-10-11 13:21:46 +04:00
Evgeny Poberezkin
f66405e79b Merge branch 'master-ghc8107' into master-android 2023-10-09 17:31:56 +01:00
Evgeny Poberezkin
74d186af16 Merge branch 'master' into master-ghc8107 2023-10-09 17:31:27 +01:00
Evgeny Poberezkin
187fef0c5a Merge branch 'master-ghc8107' into master-android 2023-10-09 14:05:21 +01:00
Evgeny Poberezkin
4782cab507 Merge branch 'master' into master-ghc8107 2023-10-09 14:05:04 +01:00
Evgeny Poberezkin
bcbee67709 Merge branch 'master-ghc8107' into master-android 2023-10-08 08:38:40 +01:00
Evgeny Poberezkin
2501cbe55d Merge branch 'master' into master-ghc8107 2023-10-08 08:38:02 +01:00
Evgeny Poberezkin
2bd049db87 Merge branch 'master-ghc8107' into master-android 2023-10-07 21:10:22 +01:00
Evgeny Poberezkin
6b8b9ab4fd Merge branch 'master' into master-ghc8107 2023-10-07 19:06:38 +01:00
Evgeny Poberezkin
30db24265e Merge branch 'master-ghc8107' into master-android 2023-10-02 23:04:44 +01:00
Evgeny Poberezkin
316d605899 Merge branch 'master' into master-ghc8107 2023-10-02 23:04:13 +01:00
Evgeny Poberezkin
b4257f7767 Merge branch 'master-ghc8107' into master-android 2023-10-01 13:21:50 +01:00
Evgeny Poberezkin
a3f2d5c919 Merge branch 'master' into master-ghc8107 2023-10-01 13:20:06 +01:00
Evgeny Poberezkin
cf46469cd5 Merge branch 'master-ghc8107' into master-android 2023-10-01 11:19:50 +01:00
Evgeny Poberezkin
0312fde818 Merge branch 'master' into master-ghc8107 2023-10-01 11:19:27 +01:00
Evgeny Poberezkin
9defa44f0c Merge branch 'master-ghc8107' into master-android 2023-09-29 13:15:23 +01:00
Evgeny Poberezkin
915b53054c Merge branch 'master' into master-ghc8107 2023-09-29 13:14:57 +01:00
Evgeny Poberezkin
f81557b4fd Merge branch 'master-ghc8107' into master-android 2023-09-27 22:10:06 +01:00
Evgeny Poberezkin
e273bd1239 Merge branch 'master' into master-ghc8107 2023-09-27 22:04:00 +01:00
spaced4ndy
a63caf4640 Merge branch 'master-ghc8107' into master-android 2023-09-27 20:38:36 +04:00
spaced4ndy
e7f0234134 Merge branch 'master' into master-ghc8107 2023-09-27 20:11:39 +04:00
Evgeny Poberezkin
340552321e Merge branch 'master-ghc8107' into master-android 2023-09-27 16:07:24 +01:00
Evgeny Poberezkin
98a3fc214d Merge branch 'master' into master-ghc8107 2023-09-27 16:04:25 +01:00
Evgeny Poberezkin
6a578cfe3c Merge branch 'master-ghc8107' into master-android 2023-09-25 16:53:04 +01:00
Evgeny Poberezkin
dacc075fe8 Merge branch 'master' into master-ghc8107 2023-09-25 16:52:33 +01:00
spaced4ndy
55418e2bc0 Merge branch 'master-ghc8107' into master-android 2023-09-25 17:43:59 +04:00
spaced4ndy
f2b5c0f3a8 Merge branch 'master' into master-ghc8107 2023-09-25 17:43:37 +04:00
spaced4ndy
5ebdf5dba9 Merge branch 'master-ghc8107' into master-android 2023-09-25 17:07:14 +04:00
spaced4ndy
8e045764df Merge branch 'master' into master-ghc8107 2023-09-25 16:40:08 +04:00
Evgeny Poberezkin
503d3d77e6 Merge branch 'master' into master-ghc8107 2023-09-23 08:47:28 +01:00
Evgeny Poberezkin
81bd7d97c5 Merge branch 'master' into master-ghc8107 2023-09-22 17:21:54 +01:00
Evgeny Poberezkin
8f57925067 compatibility with GHC 8.10.7 2023-09-22 14:01:25 +01:00
Evgeny Poberezkin
9bf99db82e Merge branch 'master' into master-ghc8107 2023-09-22 13:46:50 +01:00
Evgeny Poberezkin
5615cdbf1a Merge branch 'master' into master-android 2023-09-21 17:04:47 +01:00
Evgeny Poberezkin
d802ae0058 Merge branch 'master' into master-android 2023-09-21 12:06:10 +01:00
Evgeny Poberezkin
8f2278198c Merge branch 'master' into master-android 2023-09-20 14:55:25 +01:00
spaced4ndy
10937a5a4e Merge branch 'master' into master-android 2023-09-20 17:36:53 +04:00
Evgeny Poberezkin
6aff6e9804 Merge branch 'master-ghc9' into master-ghc8107 2023-09-18 21:56:35 +01:00
Evgeny Poberezkin
95477cae7e core: use commit from simplexmq branch master-ghc8107 2023-09-18 21:45:50 +01:00
68 changed files with 783 additions and 1485 deletions

View File

@@ -79,10 +79,10 @@ jobs:
uses: actions/checkout@v3
- name: Setup Haskell
uses: haskell-actions/setup@v2
uses: haskell/actions/setup@v2
with:
ghc-version: "9.6.3"
cabal-version: "3.10.1.0"
ghc-version: "8.10.7"
cabal-version: "latest"
- name: Cache dependencies
uses: actions/cache@v3
@@ -188,7 +188,7 @@ jobs:
APPLE_SIMPLEX_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_APPLE_ID }}
APPLE_SIMPLEX_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_SIMPLEX_NOTARIZATION_PASSWORD }}
run: |
scripts/ci/build-desktop-mac.sh
scripts/build-desktop-mac.sh
path=$(echo $PWD/apps/multiplatform/release/main/dmg/SimpleX-*.dmg)
echo "package_path=$path" >> $GITHUB_OUTPUT
echo "package_hash=$(echo SHA2-512\(${{ matrix.desktop_asset_name }}\)= $(openssl sha512 $path | cut -d' ' -f 2))" >> $GITHUB_OUTPUT
@@ -259,10 +259,12 @@ jobs:
# Unix /
# / Windows
# rm -rf dist-newstyle/src/direct-sq* is here because of the bug in cabal's dependency which prevents second build from finishing
# * In powershell multiline commands do not fail if individual commands fail - https://github.community/t/multiline-commands-on-windows-do-not-fail-if-individual-commands-fail/16753
# * And GitHub Actions does not support parameterizing shell in a matrix job - https://github.community/t/using-matrix-to-specify-shell-is-it-possible/17065
- name: 'Setup MSYS2'
if: matrix.os == 'windows-latest'
if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'windows-latest'
uses: msys2/setup-msys2@v2
with:
msystem: ucrt64

View File

@@ -232,8 +232,6 @@ You can use SimpleX with your own servers and still communicate with people usin
Recent and important updates:
[Nov 25, 2023. SimpleX Chat v5.4 released: link mobile and desktop apps via quantum resistant protocol, and much better groups](./blog/20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.md).
[Sep 25, 2023. SimpleX Chat v5.3 released: desktop app, local file encryption, improved groups and directory service](./blog/20230925-simplex-chat-v5-3-desktop-app-local-file-encryption-directory-service.md).
[Jul 22, 2023. SimpleX Chat: v5.2 released with message delivery receipts](./blog/20230722-simplex-chat-v5-2-message-delivery-receipts.md).
@@ -368,13 +366,13 @@ Please also join [#simplex-devs](https://simplex.chat/contact#/?v=1-2&smp=smp%3A
- ✅ Message delivery confirmation (with sender opt-out per contact).
- ✅ Desktop client.
- ✅ Encryption of local files stored in the app.
- Using mobile profiles from the desktop app.
- 🏗 Improve experience for the new users.
- 🏗 Post-quantum resistant key exchange in double ratchet protocol.
- 🏗 Large groups, communities and public channels.
- 🏗 Using mobile profiles from the desktop app.
- Message delivery relay for senders (to conceal IP address from the recipients' servers and to reduce the traffic).
- Post-quantum resistant key exchange in double ratchet protocol.
- Large groups, communities and public channels.
- Privacy & security slider - a simple way to set all settings at once.
- Improve sending videos (including encryption of locally stored videos).
- Improve experience for the new users.
- SMP queue redundancy and rotation (manual is supported).
- Include optional message into connection request sent via contact address.
- Improved navigation and search in the conversation (expand and scroll to quoted message, scroll to search results, etc.).

View File

@@ -208,7 +208,7 @@ struct ConnectDesktopView: View {
Section("Found desktop") {
Text("Waiting for desktop...").italic()
Button {
disconnectDesktop()
disconnectDesktop(.dismiss)
} label: {
Label("Scan QR code", systemImage: "qrcode")
}

View File

@@ -120,11 +120,11 @@
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; };
5CD67B8F2B0E858A00C510B1 /* hs_init.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CD67B8D2B0E858A00C510B1 /* hs_init.h */; settings = {ATTRIBUTES = (Public, ); }; };
5CD67B902B0E858A00C510B1 /* hs_init.c in Sources */ = {isa = PBXBuildFile; fileRef = 5CD67B8E2B0E858A00C510B1 /* hs_init.c */; };
5CD67BA02B120ADF00C510B1 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B9B2B120ADF00C510B1 /* libgmp.a */; };
5CD67BA12B120ADF00C510B1 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B9C2B120ADF00C510B1 /* libgmpxx.a */; };
5CD67BA22B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B9D2B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u.a */; };
5CD67BA32B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B9E2B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u-ghc8.10.7.a */; };
5CD67BA42B120ADF00C510B1 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B9F2B120ADF00C510B1 /* libffi.a */; };
5CD67B962B11416700C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B912B11416600C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9.a */; };
5CD67B972B11416700C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B922B11416600C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9-ghc9.6.3.a */; };
5CD67B982B11416700C510B1 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B932B11416600C510B1 /* libffi.a */; };
5CD67B992B11416700C510B1 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B942B11416600C510B1 /* libgmp.a */; };
5CD67B9A2B11416700C510B1 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CD67B952B11416700C510B1 /* libgmpxx.a */; };
5CDCAD482818589900503DA2 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CDCAD472818589900503DA2 /* NotificationService.swift */; };
5CE2BA702845308900EC33A6 /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; };
5CE2BA712845308900EC33A6 /* SimpleXChat.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -165,6 +165,11 @@
64466DC829FC2B3B00E3D48D /* CreateSimpleXAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64466DC729FC2B3B00E3D48D /* CreateSimpleXAddress.swift */; };
64466DCC29FFE3E800E3D48D /* MailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64466DCB29FFE3E800E3D48D /* MailView.swift */; };
6448BBB628FA9D56000D2AB9 /* GroupLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6448BBB528FA9D56000D2AB9 /* GroupLinkView.swift */; };
6449333A2AF8E51000AC506E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644933352AF8E51000AC506E /* libgmpxx.a */; };
6449333B2AF8E51000AC506E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644933362AF8E51000AC506E /* libgmp.a */; };
6449333C2AF8E51000AC506E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644933372AF8E51000AC506E /* libffi.a */; };
6449333D2AF8E51000AC506E /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644933382AF8E51000AC506E /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a */; };
6449333E2AF8E51000AC506E /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 644933392AF8E51000AC506E /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a */; };
644EFFDE292BCD9D00525D5B /* ComposeVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFDD292BCD9D00525D5B /* ComposeVoiceView.swift */; };
644EFFE0292CFD7F00525D5B /* CIVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFDF292CFD7F00525D5B /* CIVoiceView.swift */; };
644EFFE2292D089800525D5B /* FramedCIVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 644EFFE1292D089800525D5B /* FramedCIVoiceView.swift */; };
@@ -403,11 +408,11 @@
5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = "<group>"; };
5CD67B8D2B0E858A00C510B1 /* hs_init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hs_init.h; sourceTree = "<group>"; };
5CD67B8E2B0E858A00C510B1 /* hs_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hs_init.c; sourceTree = "<group>"; };
5CD67B9B2B120ADF00C510B1 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CD67B9C2B120ADF00C510B1 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CD67B9D2B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u.a"; sourceTree = "<group>"; };
5CD67B9E2B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u-ghc8.10.7.a"; sourceTree = "<group>"; };
5CD67B9F2B120ADF00C510B1 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CD67B912B11416600C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9.a"; sourceTree = "<group>"; };
5CD67B922B11416600C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9-ghc9.6.3.a"; sourceTree = "<group>"; };
5CD67B932B11416600C510B1 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CD67B942B11416600C510B1 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CD67B952B11416700C510B1 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CDCAD452818589900503DA2 /* SimpleX NSE.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "SimpleX NSE.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
5CDCAD472818589900503DA2 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
5CDCAD492818589900503DA2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -448,6 +453,11 @@
64466DC729FC2B3B00E3D48D /* CreateSimpleXAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSimpleXAddress.swift; sourceTree = "<group>"; };
64466DCB29FFE3E800E3D48D /* MailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailView.swift; sourceTree = "<group>"; };
6448BBB528FA9D56000D2AB9 /* GroupLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupLinkView.swift; sourceTree = "<group>"; };
644933352AF8E51000AC506E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
644933362AF8E51000AC506E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
644933372AF8E51000AC506E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
644933382AF8E51000AC506E /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8-ghc9.6.3.a"; sourceTree = "<group>"; };
644933392AF8E51000AC506E /* libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.4.0.3-EnhmkSQK6HvJ11g1uZERg8.a"; sourceTree = "<group>"; };
644EFFDD292BCD9D00525D5B /* ComposeVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeVoiceView.swift; sourceTree = "<group>"; };
644EFFDF292CFD7F00525D5B /* CIVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIVoiceView.swift; sourceTree = "<group>"; };
644EFFE1292D089800525D5B /* FramedCIVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FramedCIVoiceView.swift; sourceTree = "<group>"; };
@@ -511,13 +521,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5CD67BA12B120ADF00C510B1 /* libgmpxx.a in Frameworks */,
5CD67BA22B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u.a in Frameworks */,
5CD67B972B11416700C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9-ghc9.6.3.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
5CD67BA02B120ADF00C510B1 /* libgmp.a in Frameworks */,
5CD67BA42B120ADF00C510B1 /* libffi.a in Frameworks */,
5CD67BA32B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u-ghc8.10.7.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
5CD67B982B11416700C510B1 /* libffi.a in Frameworks */,
5CD67B992B11416700C510B1 /* libgmp.a in Frameworks */,
5CD67B962B11416700C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9.a in Frameworks */,
5CD67B9A2B11416700C510B1 /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -579,11 +589,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5CD67B9F2B120ADF00C510B1 /* libffi.a */,
5CD67B9B2B120ADF00C510B1 /* libgmp.a */,
5CD67B9C2B120ADF00C510B1 /* libgmpxx.a */,
5CD67B9E2B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u-ghc8.10.7.a */,
5CD67B9D2B120ADF00C510B1 /* libHSsimplex-chat-5.4.0.6-9DfazyElTA72omjHp0C93u.a */,
5CD67B932B11416600C510B1 /* libffi.a */,
5CD67B942B11416600C510B1 /* libgmp.a */,
5CD67B952B11416700C510B1 /* libgmpxx.a */,
5CD67B922B11416600C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9-ghc9.6.3.a */,
5CD67B912B11416600C510B1 /* libHSsimplex-chat-5.4.0.6-95eerlCBwIgI8jyla1GCr9.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1502,7 +1512,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
CURRENT_PROJECT_VERSION = 183;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1545,7 +1555,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
CURRENT_PROJECT_VERSION = 183;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@@ -1626,7 +1636,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
CURRENT_PROJECT_VERSION = 183;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1658,7 +1668,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
CURRENT_PROJECT_VERSION = 183;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GENERATE_INFOPLIST_FILE = YES;
@@ -1690,7 +1700,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
CURRENT_PROJECT_VERSION = 183;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1736,7 +1746,7 @@
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 184;
CURRENT_PROJECT_VERSION = 183;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;

View File

@@ -71,7 +71,7 @@ if(NOT APPLE)
else()
# Without direct linking it can't find hs_init in linking step
add_library( rts SHARED IMPORTED )
FILE(GLOB RTSLIB ${CMAKE_SOURCE_DIR}/libs/${OS_LIB_PATH}-${OS_LIB_ARCH}/libHSrts*_thr-*.${OS_LIB_EXT})
FILE(GLOB RTSLIB ${CMAKE_SOURCE_DIR}/libs/${OS_LIB_PATH}-${OS_LIB_ARCH}/deps/libHSrts*_thr-*.${OS_LIB_EXT})
set_target_properties( rts PROPERTIES IMPORTED_LOCATION ${RTSLIB})
target_link_libraries(app-lib rts simplex)

View File

@@ -8,7 +8,7 @@ module Main where
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Reader
import qualified Data.Text as T
import Simplex.Chat.Bot
import Simplex.Chat.Controller

View File

@@ -9,7 +9,7 @@ module Broadcast.Bot where
import Control.Concurrent (forkIO)
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Reader
import qualified Data.Text as T
import Broadcast.Options
import Simplex.Chat.Bot

View File

@@ -8,7 +8,6 @@
module Server where
import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import Data.Aeson (FromJSON, ToJSON)

View File

@@ -15,7 +15,7 @@ where
import Control.Concurrent (forkIO)
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Reader
import qualified Data.ByteString.Char8 as B
import Data.List (sortOn)
import Data.Maybe (fromMaybe, maybeToList)

View File

@@ -2,128 +2,48 @@
layout: layouts/article.html
title: "SimpleX Chat v5.4 - link mobile and desktop apps via quantum resistant protocol, and much better groups."
date: 2023-11-25
previewBody: blog_previews/20231125.html
image: images/20231125-mobile2.png
permalink: "/blog/20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.html"
preview: SimpleX Chat v5.4 - link mobile and desktop apps via quantum resistant protocol, and much better groups.
# image: images/20231125-remote-desktop.jpg
draft: true
imageWide: true
permalink: "/blog/20231125-simplex-chat-v5-4-quantum-resistant-mobile-from-desktop-better-groups.html"
---
TODO stub for release announcement
# SimpleX Chat v5.4 - link mobile and desktop apps via quantum resistant protocol, and much better groups.
**Published:** Nov 25, 2023
**What's new in v5.4:**
- [Link mobile and desktop apps via secure quantum-resistant protocol](#link-mobile-and-desktop-apps-via-secure-quantum-resistant-protocol).
- ⚡️ Quick start - how to use it.
- How does it work?
- 🤖 Connecting to remote CLI.
- [Better groups](#better-groups).
- [Faster to join and more reliable](#faster-to-join-with-more-reliable-message-delivery).
- [New group features](#new-group-features):
- create groups with incognito profile,
- block group members to reduce noise,
- prohibit files and media in a group.
- [Better calls](#better-calls): faster to connect, with screen sharing on desktop.
- [Quick start: control SimpleX Chat mobile app from CLI](#⚡️-quick-start-use-profiles-in-SimpleX-Chat-mobile-from-desktop-app)
- [What's the problem](#whats-the-problem)
- [Why didn't we use some existing solution?](#why-didnt-we-use-some-existing-solution)
There are many [other improvements](#other-improvements) and fixes in this release:
- profile names now allow spaces.
- when you delete contacts, they are optionally notified.
- previously used and your own SimpleX links are recognized by the app.
- and more - see the [release notes](https://github.com/simplex-chat/simplex-chat/releases/tag/v5.4.0).
## ⚡️ Quick start: use profiles in SimpleX Chat mobile from desktop app
## Link mobile and desktop apps via secure quantum-resistant protocol
## What's the problem?
This release allows to use chat profiles you have in mobile app from desktop app.
Currently you cannot use the same SimpleX Chat profile on mobile and desktop devices. Even though you can use small groups instead of direct conversations as a workaround, it is quite inconvenient read status and delivery receipts become much less useful.
This is only possible when both devices are connected to the same local network. To send and receive messages mobile app has to be connected to the Internet.
So, we need a way to use the same profile on desktop as we use on mobile.
### ⚡️ Quick start - how to use it
If SimpleX Chat profile was stored on the server, the problem would have been simpler - you can just connect to it from another device. But even in this case, accessing the conversation history without compromising the security of double ratchet end-to-end encryption is not really possible.
**On desktop**
So we decided to implement the solution that is similar to what WhatsApp and WeChat did in early days - allowing a desktop device access profile on mobile via network. Unlike these big apps, we don't use the server to connect to mobile, but instead use the connection over the local network.
If you don't have desktop app installed yet, [download it](https://simplex.chat/downloads/) and create any chat profile - you don't need to use it, and when you create it there are no server requests sent and no accounts are created. Think about it as about user profile on your computer.
The downside of this approach is that mobile device has to be with you and connected to the same local network (and in case of iOS, the app has to be in the foreground as well). But the upside is that we the connection can be secure, and that you do not have to have a copy of your profiles on the desktop, which usually has lower security.
Then in desktop app settings choose *Link a mobile* - it will show a QR code.
## Why didn't we use some existing solution?
<img src="./images/20231125-desktop1.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-desktop2.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-desktop3.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-desktop4.png" width="510">
While there are several existing protocols for remote access, all of them are vulnerable to spoofing and man
**On mobile**
in many cases support of sending files and images is not very good, and sending videos and large files is simply impossible. There are currently these problems:
In mobile app settings choose *Use from desktop*, scan the QR code and verify session code when it appears on both devices - it should be the same. Verifying session code confirms that the devices are connected directly via a secure encrypted connection. There is an option to verify this code on subsequent connections too, but by default it is only required once.
- the sender has to be online for file transfer to complete, once it was confirmed by the recipient.
- when the file is sent to the group, the sender will have to transfer it separately to each member, creating a lot of traffic.
- the file transfer is slow, as it is sent in small chunks - approximately 16kb per message.
<img src="./images/20231125-mobile1.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-mobile1a.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-mobile2.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-mobile3.png" width="170"> <img src="./images/arrow.png" width="24"> <img src="./images/20231125-mobile4.png" width="170">
The devices are now paired, and you can continue using all mobile profiles from desktop.
If it is an Android app, you can move the app to background, but iOS app has to remain open. In both cases, while you are using mobile profiles from desktop, you won't be able to use mobile app.
The subsequent connections happen much faster - by default, the desktop app broadcasts its session address to the network, in encrypted form, and mobile app connects to it once you choose *Use from desktop* in mobile app settings.
### How does it work?
The way we designed this solution avoided any security compromises, and the end-to-end encryption remained as secure as it was - it uses [double-ratchet algorithm](../docs/GLOSSARY.md#double-ratchet-algorithm), with [perfect forward secrecy](../docs/GLOSSARY.md#forward-secrecy), [post-compromise security](../docs/GLOSSARY.md#post-compromise-security) and deniability.
This solution is similar to WhatsApp and WeChat. But unlike these apps, no server is involved in the connection between mobile and desktop. The connection itself uses a new SimpleX Remote Control Protocol (XRCP) based on secure TLS 1.3 and additional quantum-resistant encryption inside TLS. You can read XRCP protocol specification and threat model in [this document](https://github.com/simplex-chat/simplexmq/blob/master/rfcs/2023-10-25-remote-control.md). We will soon be [augmenting double ratchet](https://github.com/simplex-chat/simplex-chat/blob/master/docs/rfcs/2023-09-30-pq-double-ratchet.md) to be resistant to quantum computers as well.
The downside of this approach is that mobile device has to be connected to the same local network as desktop. But the upside is that the connection is secure, and you do not need to have a copy of all your data on desktop, which usually has lower security than mobile.
Please note, that the files you send, save or play from desktop app, and also images you view are automatically saved on your desktop device (encrypted by default except videos). To remove all these files you can unlink the paired mobile device from the desktop app settings there will be an option soon allowing to remove the files without unlinking the mobile.
### 🤖 Connecting to remote SimpleX CLI
*Warning*: this section is for technically advanced users!
If you run SimpleX CLI on a computer in another network - e.g., in the cloud VM or on a Raspberry Pi at home while you are at work, you can also use if from desktop via SSH tunnel. Below assumes that you have remote machine connected via SSH and CLI running there - you can use `tmux` for it to keep running when you are not connected via ssh.
Follow these steps to use remote CLI from desktop app:
1. On the remote machine add the IP address of your desktop to the firewall rules, so that when CLI tries to connect to this address, it connects to `localhost` instead: `iptables -t nat -A OUTPUT -p all -d 192.168.1.100 -j DNAT --to-destination 127.0.0.1` (replace `192.168.1.100` with the actual address of your desktop, and make sure it is not needed for something else on your remote machine).
2. Also on the remote machine, run Simplex CLI with the option `--device-name 'SimpleX CLI'`, or any other name you like. You can also use the command `/set device name <name>` to set it for the CLI.
3. Choose *Link a mobile* in desktop app settings, note the port it shows under the QR code, and click "Share link".
4. Run ssh port forwarding on desktop computer to let your remote machine connect to desktop app: `ssh -R 12345:127.0.0.1:12345 -N user@example.com` where `12345` is the port on which desktop app is listening for the connections from step 3, `example.com` is the hostname or IP address of your remote machine, and `user` is some username on remote machine. You can run port forwarding in the background by adding `-f` option.
5. On the remote machine, run CLI command `/connect remote ctrl <link>`, where `<link>` is the desktop session address copied in step 3. You should run this command within 1 minute from choosing *Link a mobile*.
6. If the connection is successful, the CLI will ask you to verify the session code (you need to copy and paste the command) with the one shown in desktop app. Once you use `/verify remote ctrl <code>` command, CLI can be used from desktop app.
7. To stop remote session use `/stop remote ctrl` command.
## Better groups
### Faster to join, with more reliable message delivery
We improved the protocols for groups, by making joining groups much faster, and also by adding message forwarding. Previously, the problem was that until a new member connects directly with each existing group member, they did not see each other messages in the group. The problem is explained in detail in [this video](https://www.youtube.com/watch?v=7yjQFmhAftE&t=1104s) at 18:23.
With v5.4, the admin who added members to the group forwards messages to and from the new members until they connect to the existing members. So you should no longer miss any messages and be surprised with replies to messages you have never seen once you and new group members upgrade.
### New group features
<img src="./images/20231125-group1.png" width="220" class="float-to-left"> <img src="./images/20231125-block.png" width="220" class="float-to-left">
**Create groups with incognito profile**
Previously, you could only create groups with your main profile. This version allows creating groups with incognito profile directly. You will not be able to add your contacts, they can only join via group link.
**Block group members to reduce noise**
You now can block messages from group members that send too many messages, or the messages you don't won't to see. Blocked members won't know that you blocked their messages. When they send messages they will appear in the conversation as one line, showing how many messages were blocked. You can reveal them, or delete all sequential blocked messages at once.
**Prohibit files and media in a group**
Group owners now have an option to prohibit sending files and media. This can be useful if you don't won't any images shared, and only want to allow text messages.
## Better calls
Calls in SimpleX Chat still require a lot of work to become stable, but this version improved the speed of connecting calls, and they should work for more users.
We also added screen sharing in video calls to desktop app.
## Other improvements
This version also has many small and large improvements to make the app more usable and reliable.
The new users and group profiles now allow spaces in the names, to make them more readable. To message these contacts in CLI you need to use quotes, for example, `@'John Doe' Hello!`.
When you delete contacts, you can notify them - to let them know they can't message you.
When you try to connect to the same contact or join the same group, or connect via your own link, the app will recognize it and warn you, or simply open the correct conversation.
You can find the full list of fixed bugs and small improvements in the [release notes](https://github.com/simplex-chat/simplex-chat/releases/tag/v5.4.0).
As a result, we limited the supported size of files in the app to 8mb. Even for supported files, it is quite inefficient for sending any files to large groups.
## SimpleX platform

View File

@@ -1,27 +1,5 @@
# Blog
Nov 25, 2023 [SimpleX Chat v5.4 released](./20231125-simplex-chat-v5-4-link-mobile-desktop-quantum-resistant-better-groups.md)
- Link mobile and desktop apps via secure quantum-resistant protocol. 🔗
- Better groups:
- faster to join and more reliable.
- create groups with incognito profile.
- block group members to reduce noise.
- prohibit files and media in a group.
- Better calls: faster to connect, with screen sharing on desktop.
- Many other improvements.
---
Sep 25, 2023 [SimpleX Chat v5.3 released](./20230925-simplex-chat-v5-3-desktop-app-local-file-encryption-directory-service.md)
- new desktop app! 💻
- directory service and other group improvements.
- encrypted local files and media with forward secrecy.
- simplified incognito mode.
---
July 22, 2023 [SimpleX Chat v5.2 released](./20230722-simplex-chat-v5-2-message-delivery-receipts.md)
**What's new in v5.2:**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -2,14 +2,14 @@ packages: .
-- packages: . ../simplexmq
-- packages: . ../simplexmq ../direct-sqlcipher ../sqlcipher-simple
with-compiler: ghc-9.6.3
with-compiler: ghc-8.10.7
constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 757b7eec81341d8560a326deab303bb6fb6a26a3
tag: 281bdebcb82aed4c8c2c08438b9cafc7908183a1
source-repository-package
type: git
@@ -24,12 +24,12 @@ source-repository-package
source-repository-package
type: git
location: https://github.com/simplex-chat/direct-sqlcipher.git
tag: f814ee68b16a9447fbb467ccc8f29bdd3546bfd9
tag: 34309410eb2069b029b8fc1872deb1e0db123294
source-repository-package
type: git
location: https://github.com/simplex-chat/sqlcipher-simple.git
tag: a46bd361a19376c5211f1058908fc0ae6bf42446
tag: 5e154a2aeccc33ead6c243ec07195ab673137221
source-repository-package
type: git
@@ -43,10 +43,5 @@ source-repository-package
source-repository-package
type: git
location: https://github.com/simplex-chat/android-support.git
tag: 9aa09f148089d6752ce563b14c2df1895718d806
source-repository-package
type: git
location: https://github.com/simplex-chat/network-transport.git
tag: 0013798272a683e35ca38d2fdaf480942311fba8
location: https://github.com/zw3rk/android-support.git
tag: 3c3a5ab0b8b137a072c98d3d0937cbdc96918ddb

View File

@@ -1,13 +1,13 @@
---
title: Download SimpleX apps
permalink: /downloads/index.html
revision: 25.11.2023
revision: 01.10.2023
---
| Updated 25.11.2023 | Languages: EN |
| Updated 01.10.2023 | Languages: EN |
# Download SimpleX apps
The latest stable version is v5.4.0.
The latest stable version is v5.3.2.
You can get the latest beta releases from [GitHub](https://github.com/simplex-chat/simplex-chat/releases).
@@ -21,24 +21,24 @@ You can get the latest beta releases from [GitHub](https://github.com/simplex-ch
Using the same profile as on mobile device is not yet supported you need to create a separate profile to use desktop apps.
**Linux**: [AppImage](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-desktop-x86_64.AppImage) (most Linux distros), [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-desktop-ubuntu-20_04-x86_64.deb) (and Debian-based distros), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-desktop-ubuntu-22_04-x86_64.deb).
**Linux**: [AppImage](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-desktop-x86_64.AppImage) (most Linux distros), [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-desktop-ubuntu-20_04-x86_64.deb) (and Debian-based distros), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-desktop-ubuntu-22_04-x86_64.deb).
**Mac**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-desktop-macos-x86_64.dmg) (Intel), [aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-desktop-macos-aarch64.dmg) (Apple Silicon).
**Mac**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-desktop-macos-x86_64.dmg) (Intel), [aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.1/simplex-desktop-macos-aarch64.dmg) (Apple Silicon).
**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-desktop-windows-x86_64.msi).
**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0-beta.3/simplex-desktop-windows-x86-64.msi) (BETA).
## Mobile apps
**iOS**: [App store](https://apps.apple.com/us/app/simplex-chat/id1605771084), [TestFlight](https://testflight.apple.com/join/DWuT2LQu).
**Android**: [Play store](https://play.google.com/store/apps/details?id=chat.simplex.app), [F-Droid](https://simplex.chat/fdroid/), [APK aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex.apk), [APK armv7](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-armv7a.apk).
**Android**: [Play store](https://play.google.com/store/apps/details?id=chat.simplex.app), [F-Droid](https://simplex.chat/fdroid/), [APK aarch64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex.apk), [APK armv7](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-armv7a.apk).
## Terminal (console) app
See [Using terminal app](/docs/CLI.md).
**Linux**: [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-chat-ubuntu-20_04-x86-64), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-chat-ubuntu-22_04-x86-64).
**Linux**: [Ubuntu 20.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-chat-ubuntu-20_04-x86-64), [Ubuntu 22.04](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-chat-ubuntu-22_04-x86-64).
**Mac** [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-chat-macos-x86-64), aarch64 - [compile from source](./CLI.md#).
**Mac** [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-chat-macos-x86-64), aarch64 - [compile from source](./CLI.md#).
**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.4.0/simplex-chat-windows-x86-64).
**Windows**: [x86_64](https://github.com/simplex-chat/simplex-chat/releases/download/v5.3.2/simplex-chat-windows-x86-64).

View File

@@ -8,7 +8,7 @@ title: App settings
To open app settings:
- Open the app.
- Tap on your user profile image in the upper left-hand of the screen.
- Tap on your user profile image in the upper right-hand of the screen.
- If you have more than one profile, tap the current profile again or choose Settings.
## Your profile settings

View File

@@ -1,224 +0,0 @@
# Post-quantum resistant augmented double ratchet algorithm
- [Overview](#overview)
- [Problem](#problem)
- [Comparison of the proposed solutions](#comparison-of-the-proposed-solutions)
- [PQXDH for post-quantum key agreement](#pqxdh-for-post-quantum-key-agreement) (Signal)
- [Hybrid Signal protocol for post-quantum encryption](#hybrid-signal-protocol-for-post-quantum-encryption) (Tutanota)
- [Problems with ML-KEM / Kyber](#problems-with-ml-kem--kyber)
- [Proposed solution: augmented double ratchet algorithm](#proposed-solution-augmented-double-ratchet-algorithm)
- [Double ratchet with encrypted headers augmented with double PQ KEM](#double-ratchet-with-encrypted-headers-augmented-with-double-pq-kem)
- [Initialization](#initialization)
- [Encrypting messages](#encrypting-messages)
- [Decrypting messages](#decrypting-messages)
- [Alternative approach: CTIDH](#alternative-approach-ctidh)
- [Implementation considerations for SimpleX Chat](#implementation-considerations-for-simplex-chat)
- [Summary](#summary)
- [Notes](#notes)
## 1. Overview
Currently SimpleX Chat uses [double-ratchet with header encryption](https://signal.org/docs/specifications/doubleratchet/#double-ratchet-with-header-encryption) to provide end-to-end encryption to messages and files. This document proposes a way to augment this algorithm with post-quantum key encapsulation mechanism (KEM) to make it resistant to quantum computers.
This document is purposefully written in an informal style to make it understandable for general audience with some technical, but without mathematical background. It does not compromise on the technical accuracy though.
## 2. Problem
It is a reasonable assumption that "record-now-decrypt-later" attacks are ongoing, so the users want to use cryptographic schemes for end-to-end encryption that are augmented with some post-quantum algorithm that is believed to be resistant to quantum computers.
Double-ratchet algorithm is a state of the art solution for end to end encryption offering a set of qualities that is unmatched by any other algorithm:
- perfect forward secrecy, i.e. compromise of session or long term keys does not lead to the ability to decrypt any of the past messages.
- deniability (also known as repudiation), i.e. the fact that the recipient of the message cannot prove to a third party that the sender actually sent this message [1].
- break-in recovery [2] (also know as post-compromise security or future secrecy), i.e. the ability of the end-to-end encryption security to recover from the compromise of the long term keys. This is achieved by generating a new random key pair whenever a new DH key is received (DH ratchet step).
It is desirable to preserve all these qualities when augmenting the algorithm with a post-quantum algorithm, and having these qualities resistant (or "believed to be" resistant [3]) to both conventional and quantum computers.
## Comparison of the proposed solutions
### PQXDH for post-quantum key agreement
[The solution](https://signal.org/docs/specifications/pqxdh/) recently [introduced by Signal](https://signal.org/blog/pqxdh/) augments the initial key agreement ([X3DH](https://signal.org/docs/specifications/x3dh/)) that is made prior to double ratchet algorithm. This is believed to provide protection from "record-now-decrypt-later" attack, but if the attacker at any point obtains long term keys from any of the devices, the break-in recovery will not be post-quantum resistant, and the attacker would be able to decrypt all the subsequent messages.
In addition to that, the authentication of parties in the proposed scheme is also not post-quantum resistant, although this is not part of double ratchet algorithm.
### Hybrid Signal protocol for post-quantum encryption
[The solution](https://eprint.iacr.org/2021/875.pdf) [proposed by Tutanota](https://tutanota.com/blog/posts/pqmail-update/) aims to preserve the break-in recovery property of double ratchet, but in doing so it:
- replaces rather than augments DH key agreement with post-quantum KEM mechanism, making it potentially vulnerable to conventional computers.
- adds signature to the DH ratchet step, to compensate for not keeping DH key agreement, but losing the deniability property for some of the messages.
### Problems with ML-KEM / Kyber
ML-KEM / Kyber used in both Signal and Tutanota schemes is the chosen algorithm by NIST, but its standardisation process raised some concerns amongst the experts:
- hashing of random numbers that was present in the original submission was removed from the standardised version of the algorithm. See lines 304-314 in the published spec (https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf) and also the linked discussion on the subject: https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/WFRDl8DqYQ4. This decision polarised the experts, with some of them saying that it effectively created a backdoor.
- calculation of security levels of Kyber appears to have been done incorrectly, and overall, the chosen Kyber seems worse than rejected NTRU according to [the analysis by Daniel Bernstein](https://blog.cr.yp.to/20231003-countcorrectly.html).
## Proposed solution: augmented double ratchet algorithm
We will augment the double ratchet algorithm with post-quantum KEM mechanism, preserving all properties of the double ratchet algorithm.
It is possible, because although double ratchet uses DH (which is a non-interactive key exchange [4]), it uses it "interactively", when the new DH keys are generated by both parties in turns. Parties of double-ratchet encrypted communication can run one or two post-quantum key encapsulation mechanisms in parallel with DH key agreement on each DH ratchet step, making break-in recovery of double ratchet algorithm post-quantum resistant (unlike Signal PQXDH scheme), without losing deniability or resistance to conventional computers (unlike Tutanota scheme).
Specifically, it is proposed to augment [double ratchet with encrypted headers](https://signal.org/docs/specifications/doubleratchet/#double-ratchet-with-header-encryption) with some post-quantum key encapsulation mechanism (KEM) as described below. A possible algorithm for PQ KEM is [NTRU-prime](https://ntruprime.cr.yp.to), that is currently adopted in SSH and has available implementations. It is important though that the proposed scheme can be used with any PQ KEM algorithm.
The downside of the proposed scheme is its substantial size overhead, as the encapsulation key and/or encapsulated shared secret are added to the header of each message. For the scheme described below, when both the encapsulation key and encapsulated secret are added to each message header, NTRU-prime adds ~2-4kb to each message (depending on the key size and the chosen variant). See [this table](https://ntruprime.cr.yp.to/security.html) for key and ciphertext sizes and the assessment of the security level for various key sizes.
## Double ratchet with encrypted headers augmented with double PQ KEM
Algorithm below assumes that in addition to shared secret from the initial key agreement, there will be an encapsulation key available from the party that published its keys (Bob).
### Initialization
The double ratchet initialization is defined in pseudocode as follows:
```
// Alice obtained Bob's keys and initializes ratchet first
def RatchetInitAlicePQ2HE(state, SK, bob_dh_public_key, shared_hka, shared_nhkb, bob_pq_kem_encapsulation_key):
state.DHRs = GENERATE_DH()
state.DHRr = bob_dh_public_key
// below added for post-quantum KEM
state.PQRs = GENERATE_PQKEM()
state.PQRr = bob_pq_kem_encapsulation_key
state.PQRss = random // shared secret for KEM
state.PQRenc_ss = PQKEM-ENC(state.PQRr.encaps, state.PQRss) // encapsulated additional shared secret
// above added for KEM
// below augments DH key agreement with PQ shared secret
state.RK, state.CKs, state.NHKs = KDF_RK_HE(SK, DH(state.DHRs, state.DHRr) || state.PQRss)
state.CKr = None
state.Ns = 0
state.Nr = 0
state.PN = 0
state.MKSKIPPED = {}
state.HKs = shared_hka
state.HKr = None
state.NHKr = shared_nhkb
// Bob initializes ratchet second, having received Alice's connection request
def RatchetInitBobPQ2HE(state, SK, bob_dh_key_pair, shared_hka, shared_nhkb, bob_pq_kem_key_pair):
state.DHRs = bob_dh_key_pair
state.DHRr = None
// below added for KEM
state.PQRs = bob_pq_kem_key_pair
state.PQRr = None
state.PQRss = None
state.PQRenc_ss = None
// above added for KEM
state.RK = SK
state.CKs = None
state.CKr = None
state.Ns = 0
state.Nr = 0
state.PN = 0
state.MKSKIPPED = {}
state.HKs = None
state.NHKs = shared_nhkb
state.HKr = None
state.NHKr = shared_hka
```
`GENERATE_PQKEM` generates decapsulation/encapsulation key pair.
`PQKEM-ENC` is key encapsulation algorithm.
Other than commented lines, the above adds parameters `bob_pq_kem_encapsulation_key` and `bob_pq_kem_key_pair` to the ratchet intialization. Otherwise it is identical to the original double ratchet initialization.
### Encrypting messages
```
def RatchetEncryptPQ2HE(state, plaintext, AD):
state.CKs, mk = KDF_CK(state.CKs)
// encapsulation key from PQRs and encapsulated shared secret is added to header
header = HEADER_PQ2(
dh = state.DHRs.public,
pn = state.PN,
n = state.Ns,
encaps = state.PQRs.encaps, // added for KEM #1
enc_ss = state.PQRenc_ss // added for KEM #2
)
enc_header = HENCRYPT(state.HKs, header)
state.Ns += 1
return enc_header, ENCRYPT(mk, plaintext, CONCAT(AD, enc_header))
```
Other than adding encapsulation key and encapsulated shared secret into the header, the above is identical to the original double ratchet message encryption step.
As an optimization, to save space, it might be possible to add encapsulation key and encapsulated secret only when they change. The downside of this optimization would be that it will be impossible to decrypt the message when the message that has them is skipped or lost, compromising the ability of double ratchet to manage skipped messages.
### Decrypting messages
```
def RatchetDecryptPQ2HE(state, enc_header, ciphertext, AD):
plaintext = TrySkippedMessageKeysHE(state, enc_header, ciphertext, AD)
if plaintext != None:
return plaintext
header, dh_ratchet = DecryptHeader(state, enc_header) // DecryptHeader is the same as in double ratchet specification
if dh_ratchet:
SkipMessageKeysHE(state, header.pn) // SkipMessageKeysHE is the same as in double ratchet specification
DHRatchetPQ2HE(state, header)
SkipMessageKeysHE(state, header.n)
state.CKr, mk = KDF_CK(state.CKr)
state.Nr += 1
return DECRYPT(mk, ciphertext, CONCAT(AD, enc_header))
def DHRatchetPQ2HE(state, header):
state.PN = state.Ns
state.Ns = 0
state.Nr = 0
state.HKs = state.NHKs
state.HKr = state.NHKr
state.DHRr = header.dh
// save new encapsulation key from header
state.PQRr = header.encaps
// decapsulate shared secret from header - KEM #2
ss = PQKEM-DEC(state.PQRs.decaps, header.enc_ss)
// use decapsulated shared secret with receiving ratchet
state.RK, state.CKr, state.NHKr = KDF_RK_HE(state.RK, DH(state.DHRs, state.DHRr) || ss)
state.DHRs = GENERATE_DH()
// below is added for KEM
state.PQRs = GENERATE_PQKEM() // generate new PQ key pair
state.PQRss = random // shared secret for KEM
state.PQRenc_ss = PQKEM-ENC(state.PQRr.encaps, state.PQRss) // encapsulated additional shared secret KEM #1
// above is added for KEM
// use new shared secret with sending ratchet
state.RK, state.CKs, state.NHKs = KDF_RK_HE(state.RK, DH(state.DHRs, state.DHRr) || state.PQRss)
```
`PQKEM-DEC` is key decapsulation algorithm.
`DHRatchetPQ2HE` augments both DH agreements with decapsulated shared secret from the received header and with the new shared secret, respectively. The new shared secret together with the new encapsulation key are saved in the state and will be added to the header in the next sent message.
Other than augmenting DH key agreements with the shared secrets from KEM, the above is identical to the original double ratchet DH ratchet step.
It is worth noting that while DH agreements work as ping-pong, when the new received DH key is used for both DH agreements (and only the sent DH key is updated for the second DH key agreement), PQ KEM agreements in the proposed scheme work as a "parallel ping-pong", with two balls in play all the time (two KEM agreements run in parallel).
## Alternative approach: CTIDH
Instead of using KEM, we can consider using [CTIDH](https://ctidh.isogeny.org). The advantage is a smaller key size, and also as CTIDH is non-interactive [4], there is no need to run two key agreements in parallel, the PQ keys would simply augment DH keys and would be used in the same way.
The main downside is the absense of performance-efficient implementation for aarch64 architecture.
## Implementation considerations for SimpleX Chat
As SimpleX Chat pads messages to a fixed size, using 16kb transport blocks, the size increase introduced by this scheme will not cause additional traffic in most cases. For large texts it may require additional messages to be sent. Similarly, for media previews it may require either reducing the preview size (and quality) or sending additional messages.
That might be the primary reason why this scheme was not adopted by Signal, as it would have resulted in substantial traffic growth to the best of our knowledge, Signal messages are not padded to a fixed size.
Sharing the initial keys in case of SimpleX Chat it is equivalent to sharing the invitation link. As encapsulation key is large, it may be inconvenient to share it in the link in some contexts.
It is possible to postpone sharing the encapsulation key until the first message from Alice (confirmation message in SMP protocol), the party sending connection request. The upside here is that the invitation link size would not increase. The downside is that the user profile shared in this confirmation will not be encrypted with PQ-resistant algorithm. To mitigate it, the hadnshake protocol can be modified to postpone sending the user profile until the second message from Alice (HELLO message in SMP protocol).
## Summary
If chosen PQ KEM proves secure against quantum computer attacks, then the proposed augmented double ratchet will also be secure against quantum computer attack, including break-in recovery property, while keeping deniability and forward secrecy, because the [same proof](https://eprint.iacr.org/2016/1013.pdf) as for double ratchet algorithm would hold here, provided KEM is secure.
## Notes
[1] This is often misunderstood to mean that the recipient cannot prove that the sender sent the message at all, which is incorrect, as the recipient has the proof that either themselves or the sender encrypted the message, and as they know that the recipient themselves did not encrypt it, therefore the sender did. So the communication is secure and authenticated for the parties, without providing a proof to a third party.
[2] The term "break-in recovery" is used in this document, consistent with the terminology of the double ratchet algorithm specification, and also because it can be used to mean both the quality of being able to recover from the compromise and the actual process used to recover.
[3] This is important to remember that no existing post-quantum algorithms are proven to be resistant to quantum or even conventional computers, therefore the correct approach is to augment rather than replace existing algorithms with the post-quantum ones.
[4] Non-interactive key exchange is a type of key agreement that allows both parties to generate key pairs independently, without input from another parties, and then use the public keys from each other to compute the same shared secret.

687
flake.lock generated
View File

@@ -16,6 +16,21 @@
"type": "github"
}
},
"blank": {
"locked": {
"lastModified": 1625557891,
"narHash": "sha256-O8/MWsPBGhhyPoPLHZAuoZiiHo9q6FLlEeIDEXuj6T4=",
"owner": "divnix",
"repo": "blank",
"rev": "5a5d2684073d9f563072ed07c871d577a6c614a8",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "blank",
"type": "github"
}
},
"cabal-32": {
"flake": false,
"locked": {
@@ -83,6 +98,64 @@
"type": "github"
}
},
"devshell": {
"inputs": {
"flake-utils": [
"haskellNix",
"tullia",
"std",
"flake-utils"
],
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1663445644,
"narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=",
"owner": "numtide",
"repo": "devshell",
"rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"dmerge": {
"inputs": {
"nixlib": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
],
"yants": [
"haskellNix",
"tullia",
"std",
"yants"
]
},
"locked": {
"lastModified": 1659548052,
"narHash": "sha256-fzI2gp1skGA8mQo/FBFrUAtY0GQkAIAaV/V127TJPyY=",
"owner": "divnix",
"repo": "data-merge",
"rev": "d160d18ce7b1a45b88344aa3f13ed1163954b497",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "data-merge",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
@@ -100,21 +173,19 @@
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1698579227,
"narHash": "sha256-KVWjFZky+gRuWennKsbo6cWyo7c/z/VgCte5pR9pEKg=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "f76e870d64779109e41370848074ac4eaa1606ec",
"lastModified": 1650374568,
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
@@ -133,6 +204,51 @@
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"ghc-8.6.5-iohk": {
"flake": false,
"locked": {
@@ -150,51 +266,33 @@
"type": "github"
}
},
"ghc98X": {
"flake": false,
"gomod2nix": {
"inputs": {
"nixpkgs": "nixpkgs_2",
"utils": "utils"
},
"locked": {
"lastModified": 1696643148,
"narHash": "sha256-E02DfgISH7EvvNAu0BHiPvl1E5FGMDi0pWdNZtIBC9I=",
"ref": "ghc-9.8",
"rev": "443e870d977b1ab6fc05f47a9a17bc49296adbd6",
"revCount": 61642,
"submodules": true,
"type": "git",
"url": "https://gitlab.haskell.org/ghc/ghc"
"lastModified": 1655245309,
"narHash": "sha256-d/YPoQ/vFn1+GTmSdvbSBSTOai61FONxB4+Lt6w/IVI=",
"owner": "tweag",
"repo": "gomod2nix",
"rev": "40d32f82fc60d66402eb0972e6e368aeab3faf58",
"type": "github"
},
"original": {
"ref": "ghc-9.8",
"submodules": true,
"type": "git",
"url": "https://gitlab.haskell.org/ghc/ghc"
}
},
"ghc99": {
"flake": false,
"locked": {
"lastModified": 1697054644,
"narHash": "sha256-kKarOuXUaAH3QWv7ASx+gGFMHaHKe0pK5Zu37ky2AL4=",
"ref": "refs/heads/master",
"rev": "f383a242c76f90bcca8a4d7ee001dcb49c172a9a",
"revCount": 62040,
"submodules": true,
"type": "git",
"url": "https://gitlab.haskell.org/ghc/ghc"
},
"original": {
"submodules": true,
"type": "git",
"url": "https://gitlab.haskell.org/ghc/ghc"
"owner": "tweag",
"repo": "gomod2nix",
"type": "github"
}
},
"hackage": {
"flake": false,
"locked": {
"lastModified": 1699834964,
"narHash": "sha256-733KT+G0c1euCeb60/u1qbX22Kvu9lNnIDfAmk6Jxq0=",
"lastModified": 1696724662,
"narHash": "sha256-jV2ugSjZE0FjMYR2YIx0p2cDBqd+xxhZrRxp5BmieYk=",
"owner": "input-output-hk",
"repo": "hackage.nix",
"rev": "2e891e530400187ea1083ffef15adf259061be41",
"rev": "df603bff8606d8653a0876ae0c3fd1f9014882f2",
"type": "github"
},
"original": {
@@ -211,40 +309,33 @@
"cabal-36": "cabal-36",
"cardano-shell": "cardano-shell",
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_2",
"ghc-8.6.5-iohk": "ghc-8.6.5-iohk",
"ghc98X": "ghc98X",
"ghc99": "ghc99",
"hackage": [
"hackage"
],
"hls-1.10": "hls-1.10",
"hls-2.0": "hls-2.0",
"hls-2.2": "hls-2.2",
"hls-2.3": "hls-2.3",
"hls-2.4": "hls-2.4",
"hpc-coveralls": "hpc-coveralls",
"hydra": "hydra",
"iserv-proxy": "iserv-proxy",
"nixpkgs": [
"haskellNix",
"nixpkgs-unstable"
"nixpkgs"
],
"nixpkgs-2003": "nixpkgs-2003",
"nixpkgs-2105": "nixpkgs-2105",
"nixpkgs-2111": "nixpkgs-2111",
"nixpkgs-2205": "nixpkgs-2205",
"nixpkgs-2211": "nixpkgs-2211",
"nixpkgs-2305": "nixpkgs-2305",
"nixpkgs-unstable": "nixpkgs-unstable",
"old-ghc-nix": "old-ghc-nix",
"stackage": "stackage"
"stackage": "stackage",
"tullia": "tullia"
},
"locked": {
"lastModified": 1700119633,
"narHash": "sha256-nZY2eIo8TkRbXgJXEWMm9zor330GuUtcNzvUN9tN64U=",
"lastModified": 1677975916,
"narHash": "sha256-dbe8lEEPyfzjdRwpePClv7J9p9lQg7BwbBqAMCw4RLw=",
"owner": "input-output-hk",
"repo": "haskell.nix",
"rev": "1fe47a3d52e1ecd6247c8ab83811a21de2e2f074",
"rev": "ab5efd87ce3fd8ade38a01d97693d29a4f1ae7e4",
"type": "github"
},
"original": {
@@ -254,91 +345,6 @@
"type": "github"
}
},
"hls-1.10": {
"flake": false,
"locked": {
"lastModified": 1680000865,
"narHash": "sha256-rc7iiUAcrHxwRM/s0ErEsSPxOR3u8t7DvFeWlMycWgo=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "b08691db779f7a35ff322b71e72a12f6e3376fd9",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "1.10.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.0": {
"flake": false,
"locked": {
"lastModified": 1687698105,
"narHash": "sha256-OHXlgRzs/kuJH8q7Sxh507H+0Rb8b7VOiPAjcY9sM1k=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "783905f211ac63edf982dd1889c671653327e441",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.0.0.1",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.2": {
"flake": false,
"locked": {
"lastModified": 1693064058,
"narHash": "sha256-8DGIyz5GjuCFmohY6Fa79hHA/p1iIqubfJUTGQElbNk=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "b30f4b6cf5822f3112c35d14a0cba51f3fe23b85",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.2.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.3": {
"flake": false,
"locked": {
"lastModified": 1695910642,
"narHash": "sha256-tR58doOs3DncFehHwCLczJgntyG/zlsSd7DgDgMPOkI=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "458ccdb55c9ea22cd5d13ec3051aaefb295321be",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.3.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hls-2.4": {
"flake": false,
"locked": {
"lastModified": 1696939266,
"narHash": "sha256-VOMf5+kyOeOmfXTHlv4LNFJuDGa7G3pDnOxtzYR40IU=",
"owner": "haskell",
"repo": "haskell-language-server",
"rev": "362fdd1293efb4b82410b676ab1273479f6d17ee",
"type": "github"
},
"original": {
"owner": "haskell",
"ref": "2.4.0.0",
"repo": "haskell-language-server",
"type": "github"
}
},
"hpc-coveralls": {
"flake": false,
"locked": {
@@ -378,14 +384,37 @@
"type": "indirect"
}
},
"incl": {
"inputs": {
"nixlib": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1669263024,
"narHash": "sha256-E/+23NKtxAqYG/0ydYgxlgarKnxmDbg6rCMWnOBqn9Q=",
"owner": "divnix",
"repo": "incl",
"rev": "ce7bebaee048e4cd7ebdb4cee7885e00c4e2abca",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "incl",
"type": "github"
}
},
"iserv-proxy": {
"flake": false,
"locked": {
"lastModified": 1691634696,
"narHash": "sha256-MZH2NznKC/gbgBu8NgIibtSUZeJ00HTLJ0PlWKCBHb0=",
"lastModified": 1670983692,
"narHash": "sha256-avLo34JnI9HNyOuauK5R69usJm+GfW3MlyGlYxZhTgY=",
"ref": "hkm/remote-iserv",
"rev": "43a979272d9addc29fbffc2e8542c5d96e993d73",
"revCount": 14,
"rev": "50d0abb3317ac439a4e7495b185a64af9b7b9300",
"revCount": 10,
"type": "git",
"url": "https://gitlab.haskell.org/hamishmack/iserv-proxy.git"
},
@@ -411,22 +440,32 @@
"type": "github"
}
},
"mac2ios": {
"n2c": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs_2"
"flake-utils": [
"haskellNix",
"tullia",
"std",
"flake-utils"
],
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1699767871,
"narHash": "sha256-kxeCUfwC/Vgh2FvVMlBUq0eVx1JvfHyN+5MPKUik9mE=",
"owner": "zw3rk",
"repo": "mobile-core-tools",
"rev": "4dcb77d5ea896d749381806dfab5358851b08951",
"lastModified": 1665039323,
"narHash": "sha256-SAh3ZjFGsaCI8FRzXQyp56qcGdAqgKEfJWPCQ0Sr7tQ=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "b008fe329ffb59b67bf9e7b08ede6ee792f2741a",
"type": "github"
},
"original": {
"owner": "zw3rk",
"repo": "mobile-core-tools",
"owner": "nlewo",
"repo": "nix2container",
"type": "github"
}
},
@@ -451,6 +490,95 @@
"type": "github"
}
},
"nix-nomad": {
"inputs": {
"flake-compat": "flake-compat_2",
"flake-utils": [
"haskellNix",
"tullia",
"nix2container",
"flake-utils"
],
"gomod2nix": "gomod2nix",
"nixpkgs": [
"haskellNix",
"tullia",
"nixpkgs"
],
"nixpkgs-lib": [
"haskellNix",
"tullia",
"nixpkgs"
]
},
"locked": {
"lastModified": 1658277770,
"narHash": "sha256-T/PgG3wUn8Z2rnzfxf2VqlR1CBjInPE0l1yVzXxPnt0=",
"owner": "tristanpemble",
"repo": "nix-nomad",
"rev": "054adcbdd0a836ae1c20951b67ed549131fd2d70",
"type": "github"
},
"original": {
"owner": "tristanpemble",
"repo": "nix-nomad",
"type": "github"
}
},
"nix2container": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1658567952,
"narHash": "sha256-XZ4ETYAMU7XcpEeAFP3NOl9yDXNuZAen/aIJ84G+VgA=",
"owner": "nlewo",
"repo": "nix2container",
"rev": "60bb43d405991c1378baf15a40b5811a53e32ffa",
"type": "github"
},
"original": {
"owner": "nlewo",
"repo": "nix2container",
"type": "github"
}
},
"nixago": {
"inputs": {
"flake-utils": [
"haskellNix",
"tullia",
"std",
"flake-utils"
],
"nixago-exts": [
"haskellNix",
"tullia",
"std",
"blank"
],
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1661824785,
"narHash": "sha256-/PnwdWoO/JugJZHtDUioQp3uRiWeXHUdgvoyNbXesz8=",
"owner": "nix-community",
"repo": "nixago",
"rev": "8c1f9e5f1578d4b2ea989f618588d62a335083c3",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixago",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1657693803,
@@ -517,11 +645,11 @@
},
"nixpkgs-2205": {
"locked": {
"lastModified": 1685573264,
"narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=",
"lastModified": 1672580127,
"narHash": "sha256-3lW3xZslREhJogoOkjeZtlBtvFMyxHku7I/9IVehhT8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "380be19fbd2d9079f677978361792cb25e8a3635",
"rev": "0874168639713f547c05947c76124f78441ea46c",
"type": "github"
},
"original": {
@@ -533,11 +661,11 @@
},
"nixpkgs-2211": {
"locked": {
"lastModified": 1688392541,
"narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=",
"lastModified": 1675730325,
"narHash": "sha256-uNvD7fzO5hNlltNQUAFBPlcEjNG5Gkbhl/ROiX+GZU4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b",
"rev": "b7ce17b1ebf600a72178f6302c77b6382d09323f",
"type": "github"
},
"original": {
@@ -547,40 +675,6 @@
"type": "github"
}
},
"nixpkgs-2305": {
"locked": {
"lastModified": 1695416179,
"narHash": "sha256-610o1+pwbSu+QuF3GE0NU5xQdTHM3t9wyYhB9l94Cd8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "715d72e967ec1dd5ecc71290ee072bcaf5181ed6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-23.05-darwin",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"dir": "lib",
"lastModified": 1696019113,
"narHash": "sha256-X3+DKYWJm93DRSdC5M6K5hLqzSya9BjibtBsuARoPco=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "f5892ddac112a1e9b3612c39af1b72987ee5783a",
"type": "github"
},
"original": {
"dir": "lib",
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
@@ -599,11 +693,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1695318763,
"narHash": "sha256-FHVPDRP2AfvsxAdc+AsgFJevMz5VBmnZglFUMlxBkcY=",
"lastModified": 1675758091,
"narHash": "sha256-7gFSQbSVAFUHtGCNHPF7mPc5CcqDk9M2+inlVPZSneg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e12483116b3b51a185a33a272bf351e357ba9a99",
"rev": "747927516efcb5e31ba03b7ff32f61f6d47e7d87",
"type": "github"
},
"original": {
@@ -615,20 +709,82 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1698434055,
"narHash": "sha256-Phxi5mUKSoL7A0IYUiYtkI9e8NcGaaV5PJEaJApU1Ko=",
"lastModified": 1653581809,
"narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1a3c95e3b23b3cdb26750621c08cc2f1560cb883",
"rev": "83658b28fe638a170a19b8933aa008b30640fbd1",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.05",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1654807842,
"narHash": "sha256-ADymZpr6LuTEBXcy6RtFHcUZdjKTBRTMYwu19WOx17E=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "fc909087cc3386955f21b4665731dbdaceefb1d8",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1665087388,
"narHash": "sha256-FZFPuW9NWHJteATOf79rZfwfRn5fE0wi9kRzvGfDHPA=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "95fda953f6db2e9496d2682c4fc7b82f959878f7",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1676726892,
"narHash": "sha256-M7OYVR6dKmzmlebIjybFf3l18S2uur8lMyWWnHQooLY=",
"owner": "angerman",
"repo": "nixpkgs",
"rev": "729469087592bdea58b360de59dadf6d58714c42",
"type": "github"
},
"original": {
"owner": "angerman",
"ref": "release-22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nosys": {
"locked": {
"lastModified": 1667881534,
"narHash": "sha256-FhwJ15uPLRsvaxtt/bNuqE/ykMpNAPF0upozFKhTtXM=",
"owner": "divnix",
"repo": "nosys",
"rev": "2d0d5207f6a230e9d0f660903f8db9807b54814f",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "nosys",
"type": "github"
}
},
"old-ghc-nix": {
"flake": false,
"locked": {
@@ -651,21 +807,17 @@
"flake-utils": "flake-utils",
"hackage": "hackage",
"haskellNix": "haskellNix",
"mac2ios": "mac2ios",
"nixpkgs": [
"haskellNix",
"nixpkgs-2305"
]
"nixpkgs": "nixpkgs_5"
}
},
"stackage": {
"flake": false,
"locked": {
"lastModified": 1699834215,
"narHash": "sha256-g/JKy0BCvJaxPuYDl3QVc4OY8cFEomgG+hW/eEV470M=",
"lastModified": 1677888571,
"narHash": "sha256-YkhRNOaN6QVagZo1cfykYV8KqkI8/q6r2F5+jypOma4=",
"owner": "input-output-hk",
"repo": "stackage.nix",
"rev": "47aacd04abcce6bad57f43cbbbd133538380248e",
"rev": "cb50e6fabdfb2d7e655059039012ad0623f06a27",
"type": "github"
},
"original": {
@@ -673,6 +825,113 @@
"repo": "stackage.nix",
"type": "github"
}
},
"std": {
"inputs": {
"arion": [
"haskellNix",
"tullia",
"std",
"blank"
],
"blank": "blank",
"devshell": "devshell",
"dmerge": "dmerge",
"flake-utils": "flake-utils_4",
"incl": "incl",
"makes": [
"haskellNix",
"tullia",
"std",
"blank"
],
"microvm": [
"haskellNix",
"tullia",
"std",
"blank"
],
"n2c": "n2c",
"nixago": "nixago",
"nixpkgs": "nixpkgs_4",
"nosys": "nosys",
"yants": "yants"
},
"locked": {
"lastModified": 1674526466,
"narHash": "sha256-tMTaS0bqLx6VJ+K+ZT6xqsXNpzvSXJTmogkraBGzymg=",
"owner": "divnix",
"repo": "std",
"rev": "516387e3d8d059b50e742a2ff1909ed3c8f82826",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "std",
"type": "github"
}
},
"tullia": {
"inputs": {
"nix-nomad": "nix-nomad",
"nix2container": "nix2container",
"nixpkgs": [
"haskellNix",
"nixpkgs"
],
"std": "std"
},
"locked": {
"lastModified": 1675695930,
"narHash": "sha256-B7rEZ/DBUMlK1AcJ9ajnAPPxqXY6zW2SBX+51bZV0Ac=",
"owner": "input-output-hk",
"repo": "tullia",
"rev": "621365f2c725608f381b3ad5b57afef389fd4c31",
"type": "github"
},
"original": {
"owner": "input-output-hk",
"repo": "tullia",
"type": "github"
}
},
"utils": {
"locked": {
"lastModified": 1653893745,
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"yants": {
"inputs": {
"nixpkgs": [
"haskellNix",
"tullia",
"std",
"nixpkgs"
]
},
"locked": {
"lastModified": 1667096281,
"narHash": "sha256-wRRec6ze0gJHmGn6m57/zhz/Kdvp9HS4Nl5fkQ+uIuA=",
"owner": "divnix",
"repo": "yants",
"rev": "d18f356ec25cb94dc9c275870c3a7927a10f8c3c",
"type": "github"
},
"original": {
"owner": "divnix",
"repo": "yants",
"type": "github"
}
}
},
"root": "root",

288
flake.nix
View File

@@ -1,15 +1,15 @@
{
description = "nix flake for simplex-chat";
inputs.nixpkgs.url = "github:angerman/nixpkgs/release-22.11";
inputs.haskellNix.url = "github:input-output-hk/haskell.nix/armv7a";
inputs.nixpkgs.follows = "haskellNix/nixpkgs-2305";
inputs.mac2ios.url = "github:zw3rk/mobile-core-tools";
inputs.haskellNix.inputs.nixpkgs.follows = "nixpkgs";
inputs.hackage = {
url = "github:input-output-hk/hackage.nix";
flake = false;
};
inputs.haskellNix.inputs.hackage.follows = "hackage";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, haskellNix, nixpkgs, flake-utils, mac2ios, ... }:
outputs = { self, haskellNix, nixpkgs, flake-utils, ... }:
let systems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; in
flake-utils.lib.eachSystem systems (system:
# this android26 overlay makes the pkgsCross.{aarch64-android,armv7a-android-prebuilt} to set stdVer to 26 (Android 8).
@@ -30,8 +30,8 @@
# `appendOverlays` with a singleton is identical to `extend`.
let pkgs = haskellNix.legacyPackages.${system}.appendOverlays [android26]; in
let drv' = { extra-modules, pkgs', ... }: pkgs'.haskell-nix.project {
compiler-nix-name = "ghc963";
index-state = "2023-10-20T00:00:00Z";
compiler-nix-name = "ghc8107";
index-state = "2023-10-06T00:00:00Z";
# We need this, to specify we want the cabal project.
# If the stack.yaml was dropped, this would not be necessary.
projectFileName = "cabal.project";
@@ -40,12 +40,9 @@
src = ./.;
};
sha256map = import ./scripts/nix/sha256map.nix;
modules = [
({ pkgs, lib, ...}: lib.mkIf (!pkgs.stdenv.hostPlatform.isWindows) {
# This patch adds `dl` as an extra-library to direct-sqlciper, which is needed
# on pretty much all unix platforms, but then blows up on windows m(
modules = [{
packages.direct-sqlcipher.patches = [ ./scripts/nix/direct-sqlcipher-2.3.27.patch ];
})
}
({ pkgs,lib, ... }: lib.mkIf (pkgs.stdenv.hostPlatform.isAndroid) {
packages.simplex-chat.components.library.ghcOptions = [ "-pie" ];
})] ++ extra-modules;
@@ -77,11 +74,6 @@
find ${pkgs.gmp6.override { withStatic = true; }}/lib -name "*.a" -exec cp {} $out/_pkg \;
# There is no static libc
${pkgs.tree}/bin/tree $out/_pkg
for pkg in $out/_pkg/*.a; do
chmod +w $pkg
${mac2ios.packages.${system}.mac2ios}/bin/mac2ios $pkg
chmod -w $pkg
done
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${bundleName}.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
@@ -127,149 +119,13 @@
hardeningDisable = [ "fortify" ];
}
);in {
# STATIC x86_64-linux
"${pkgs.pkgsCross.musl64.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl64).simplex-chat.components.exes.simplex-chat;
# STATIC i686-linux
"${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv' {
pkgs' = pkgs.pkgsCross.musl32;
extra-modules = [{
# 32 bit patches
packages.basement.patches = [
./scripts/nix/basement-pr-573.patch
];
packages.memory.patches = [
./scripts/nix/memory-pr-99.patch
];
}];
}).simplex-chat.components.exes.simplex-chat;
# WINDOWS x86_64-mingwW64
"${pkgs.pkgsCross.mingwW64.hostPlatform.system}:exe:simplex-chat" = (drv' {
pkgs' = pkgs.pkgsCross.mingwW64;
extra-modules = [{
packages.direct-sqlcipher.flags.openssl = true;
packages.bitvec.flags.simd = false;
packages.direct-sqlcipher.patches = [
./scripts/nix/direct-sqlcipher-2.3.27-win.patch
];
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
(pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; })
];
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
(pkgs.pkgsCross.mingwW64.openssl) #.override) # { static = true; enableKTLS = false; })
];
packages.unix-time.postPatch = ''
sed -i 's/mingwex//g' unix-time.cabal
'';
}];
}).simplex-chat.components.exes.simplex-chat.override {
postInstall = ''
set -x
${pkgs.tree}/bin/tree $out
mkdir -p $out/_pkg
cp $out/bin/* $out/_pkg
${pkgs.tree}/bin/tree $out/_pkg
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/${pkgs.pkgsCross.mingwW64.hostPlatform.system}-simplex-chat.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
};
"${pkgs.pkgsCross.mingwW64.hostPlatform.system}:lib:simplex-chat" = (drv' rec {
pkgs' = pkgs.pkgsCross.mingwW64;
extra-modules = [{
packages.direct-sqlcipher.flags.openssl = true;
# simd will try to read __cpu_model, which we don't expose
# from the rts (yet!).
packages.bitvec.flags.simd = false;
packages.direct-sqlcipher.patches = [
./scripts/nix/direct-sqlcipher-2.3.27-win.patch
];
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
pkgs.pkgsCross.mingwW64.openssl
];
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
pkgs.pkgsCross.mingwW64.openssl
];
packages.unix-time.postPatch = ''
sed -i 's/mingwex//g' unix-time.cabal
'';
}];
}).simplex-chat.components.library
.override (p: {
# enableShared = false;
setupBuildFlags = p.component.setupBuildFlags ++ map (x: "--ghc-option=${x}") [
"-shared"
"-threaded"
"-o" "libsimplex.dll"
# "-optl-lHSrts_thr"
"-optl-lffi"
# "-optl-static-libgcc"
# We can't do -optl-static-libstdc++ with gcc. g++ might
# but then we are chaning the compiler altogether.
"${./libsimplex.dll.def}"
];
postInstall = ''
set -x
function deps() {
${pkgs.binutils}/bin/strings "$1" | grep '.\.dll'|grep -v -E 'Winsock|ADVAPI32|dbghelp|KERNEL32|msvcrt|ntdll|ole32|RPCRT4|SHELL32|USER32|WINMM|WS2_32|kernel32|GDI32'|grep -v "$1"
}
${pkgs.tree}/bin/tree $out
mkdir -p $out/_pkg
cp libsimplex.dll $out/_pkg
cp libsimplex.dll.a $out/_pkg
mkdir $out/libs
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.openssl} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.libffi} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.gmp} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.stdenv.cc.cc} -name "*.dll" -exec cp {} $out/libs \;
find ${pkgs.lib.getBin pkgs.pkgsCross.mingwW64.windows.mcfgthreads} -name "*.dll" -exec cp {} $out/libs \;
pushd $out/_pkg
function copyDeps() {
for dep in $(deps "$1"); do
if [ ! -f "$dep" ]; then
if [ ! -f ../libs/"$dep" ]; then
echo "WARN: $1 -> $dep not found!"
else
cp ../libs/"$dep" .
copyDeps "$dep"
fi
fi
done
}
copyDeps libsimplex.dll
popd
${pkgs.tree}/bin/tree $out/_pkg
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-${pkgs.pkgsCross.mingwW64.hostPlatform.system}-libsimplex.zip *)
rm -fR $out/_pkg
mkdir -p $out/nix-support
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
});
"${pkgs.pkgsCross.musl32.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.musl32).simplex-chat.components.exes.simplex-chat;
# "${pkgs.pkgsCross.muslpi.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.muslpi).simplex-chat.components.exes.simplex-chat;
# STATIC aarch64-linux
"${pkgs.pkgsCross.aarch64-multiplatform-musl.hostPlatform.system}-static:exe:simplex-chat" = (drv pkgs.pkgsCross.aarch64-multiplatform-musl).simplex-chat.components.exes.simplex-chat;
"armv7a-android:lib:support" = (drv android32Pkgs).android-support.components.library.override (p: {
smallAddressSpace = true;
# we won't want -dyamic (see aarch64-android:lib:simplex-chat)
enableShared = false;
# we also do not want to have any dependencies listed (especially no rts!)
enableStatic = false;
# This used to work with 8.10.7...
# setupBuildFlags = p.component.setupBuildFlags ++ map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
# ... but now with 9.6+
# we have to do the -shared thing by hand.
postBuild = ''
armv7a-unknown-linux-androideabi-ghc -shared -o libsupport.so \
-optl-Wl,-u,setLineBuffering \
-optl-Wl,-u,pipe_std_to_socket \
dist/build/*.a
'';
"armv7a-android:lib:support" = (drv android32Pkgs).android-support.components.library.override {
smallAddressSpace = true; enableShared = false;
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
postInstall = ''
mkdir -p $out/_pkg
@@ -282,29 +138,14 @@
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
});
# The android-support package is at
# https://github.com/simplex-chat/android-support
"aarch64-android:lib:support" = (drv androidPkgs).android-support.components.library.override (p: {
smallAddressSpace = true;
# no -dynamic
enableShared = false;
# but also no -staticlib
enableStatic = false;
# we have to do the -shared thing by hand.
postBuild = ''
aarch64-unknown-linux-android-ghc -shared -o libsupport.so \
-optl-Wl,-u,setLineBuffering \
-optl-Wl,-u,pipe_std_to_socket \
dist/build/*.a
'';
};
"aarch64-android:lib:support" = (drv androidPkgs).android-support.components.library.override {
smallAddressSpace = true; enableShared = false;
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsupport.so" ];
postInstall = ''
mkdir -p $out/_pkg
cp libsupport.so $out/_pkg
ls -lah $out/_pkg/*
${pkgs.patchelf}/bin/patchelf --remove-needed libunwind.so.1 $out/_pkg/libsupport.so
(cd $out/_pkg; ${pkgs.zip}/bin/zip -r -9 $out/pkg-aarch64-android-libsupport.zip *)
rm -fR $out/_pkg
@@ -313,11 +154,10 @@
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
});
};
"armv7a-android:lib:simplex-chat" = (drv' {
pkgs' = android32Pkgs;
extra-modules = [{
packages.text.flags.simdutf = false;
packages.direct-sqlcipher.flags.openssl = true;
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
@@ -328,55 +168,13 @@
packages.simplexmq.components.library.libs = pkgs.lib.mkForce [
(android32Pkgs.openssl.override { static = true; enableKTLS = false; })
];
# 32 bit patches
packages.basement.patches = [
./scripts/nix/basement-pr-573.patch
];
packages.memory.patches = [
./scripts/nix/memory-pr-99.patch
];
}];
}).simplex-chat.components.library.override (p: {
smallAddressSpace = true;
# we want -shared, but not -dyanmic, hence `enableShared = false`.
enableShared = false;
# we _do_ want rts, and other libs. Hence `enableStatic = true`.
enableStatic = true;
}).simplex-chat.components.library.override {
smallAddressSpace = true; enableShared = false;
# for android we build a shared library, passing these arguments is a bit tricky, as
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
setupBuildFlags = p.component.setupBuildFlags
# flags to tell GHC we want to produce a -shared object, and we want to also link
# - the ffi library (ffi)
++ map (x: "--ghc-option=${x}") [
"-shared" "-o" "libsimplex.so"
"-threaded"
# "-debug"
"-optl-lffi"
]
# This is fairly idiotic. LLD will strip out foreign exported
# symbols (a GHC bug? Codegen bug?). So we need to pass `-u <sym>`
# to ensure they stay in the produced library. Having them
# _undefined_ and _lazy_ (lld will tell with -y <sym> that the
# symbol is lazy), makes them _defined_. m(
++ map (sym: "--ghc-option=-optl-Wl,-u,${sym}") [
"chat_close_store"
"chat_decrypt_file"
"chat_decrypt_media"
"chat_encrypt_file"
"chat_encrypt_media"
"chat_migrate_init"
"chat_parse_markdown"
"chat_parse_server"
"chat_password_hash"
"chat_read_file"
"chat_recv_msg"
"chat_recv_msg_wait"
"chat_send_cmd"
"chat_send_remote_cmd"
"chat_valid_name"
"chat_write_file"
];
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
postInstall = ''
set -x
${pkgs.tree}/bin/tree $out
@@ -420,11 +218,10 @@
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
});
};
"aarch64-android:lib:simplex-chat" = (drv' {
pkgs' = androidPkgs;
extra-modules = [{
packages.text.flags.simdutf = false;
packages.direct-sqlcipher.flags.openssl = true;
packages.direct-sqlcipher.components.library.libs = pkgs.lib.mkForce [
(androidPkgs.openssl.override { static = true; })
@@ -436,49 +233,12 @@
(androidPkgs.openssl.override { static = true; })
];
}];
}).simplex-chat.components.library.override (p: {
smallAddressSpace = true;
# we do not want a dynamically linked object, even though we _do_
# want to produce a _shared_ object. But `shared` implied -dyanmic
# with cabal, so we disable and pass `-shared` explicitly.
enableShared = false;
# we do want static (e.g. pass all dependencies in, so we get -staticlib)
enableStatic = true;
}).simplex-chat.components.library.override {
smallAddressSpace = true; enableShared = false;
# for android we build a shared library, passing these arguments is a bit tricky, as
# we want only the threaded rts (HSrts_thr) and ffi to be linked, but not fed into iserv for
# template haskell cross compilation. Thus we just pass them as linker options (-optl).
setupBuildFlags = p.component.setupBuildFlags
# flags to tell GHC we want to produce a -shared object, and we want to also link
# - the ffi library (ffi)
++ map (x: "--ghc-option=${x}") [
"-shared" "-o" "libsimplex.so"
"-threaded"
# "-debug"
"-optl-lffi"
]
# This is fairly idiotic. LLD will strip out foreign exported
# symbols (a GHC bug? Codegen bug?). So we need to pass `-u <sym>`
# to ensure they stay in the produced library. Having them
# _undefined_ and _lazy_ (lld will tell with -y <sym> that the
# symbol is lazy), makes them _defined_. m(
++ map (sym: "--ghc-option=-optl-Wl,-u,${sym}") [
"chat_close_store"
"chat_decrypt_file"
"chat_decrypt_media"
"chat_encrypt_file"
"chat_encrypt_media"
"chat_migrate_init"
"chat_parse_markdown"
"chat_parse_server"
"chat_password_hash"
"chat_read_file"
"chat_recv_msg"
"chat_recv_msg_wait"
"chat_send_cmd"
"chat_send_remote_cmd"
"chat_valid_name"
"chat_write_file"
];
setupBuildFlags = map (x: "--ghc-option=${x}") [ "-shared" "-o" "libsimplex.so" "-optl-lHSrts_thr" "-optl-lffi"];
postInstall = ''
set -x
${pkgs.tree}/bin/tree $out
@@ -522,7 +282,7 @@
echo "file binary-dist \"$(echo $out/*.zip)\"" \
> $out/nix-support/hydra-build-products
'';
});
};
};
# builds for iOS and iOS simulator

View File

@@ -19,11 +19,11 @@ dependencies:
- attoparsec == 0.14.*
- base >= 4.7 && < 5
- base64-bytestring >= 1.0 && < 1.3
- bytestring == 0.11.*
- bytestring == 0.10.*
- composition == 1.0.*
- constraints >= 0.12 && < 0.14
- containers == 0.6.*
- cryptonite == 0.30.*
- cryptonite >= 0.27 && < 0.30
- data-default >= 0.7 && < 0.8
- directory == 1.3.*
- direct-sqlcipher == 2.3.*
@@ -32,8 +32,8 @@ dependencies:
- filepath == 1.4.*
- http-types == 0.12.*
- http2 >= 4.2.2 && < 4.3
- memory == 0.18.*
- mtl == 2.3.*
- memory == 0.15.*
- mtl == 2.2.*
- network >= 3.1.2.7 && < 3.2
- network-transport == 0.5.6
- optparse-applicative >= 0.15 && < 0.17
@@ -45,14 +45,14 @@ dependencies:
- socks == 0.6.*
- sqlcipher-simple == 0.4.*
- stm == 2.5.*
- template-haskell == 2.20.*
- template-haskell == 2.16.*
- terminal == 0.2.*
- text == 2.0.*
- text == 1.2.*
- time == 1.9.*
- tls >= 1.6.0 && < 1.7
- unliftio == 0.2.*
- unliftio-core == 0.2.*
- zip == 2.0.*
- zip == 1.7.*
flags:
swift:
@@ -124,7 +124,7 @@ tests:
- async == 2.2.*
- deepseq == 1.4.*
- generic-random == 1.5.*
- hspec == 2.11.*
- hspec == 2.7.*
- network == 3.1.*
- silently == 1.2.*
- stm == 2.5.*

View File

@@ -1,10 +0,0 @@
#!/bin/bash
security create-keychain -p "" simplex.keychain
security set-keychain-settings -u simplex.keychain
security add-certificates -k simplex.keychain "Developer ID Application: SimpleX Chat Ltd (5NN7GUYB6T).cer"
security add-certificates -k simplex.keychain "Developer ID Certification Authority.cer"
# Private key with access from any app
security import "SimpleX Chat.p12" -P "" -k simplex.keychain -A
# Public key
security import "SimpleX Chat.pem" -k simplex.keychain

View File

@@ -2,7 +2,7 @@
set -e
trap "rm apps/multiplatform/local.properties 2> /dev/null || true; rm local.properties 2> /dev/null || true; rm /tmp/simplex.keychain" EXIT
trap "rm apps/multiplatform/local.properties || true; rm local.properties || true; rm /tmp/simplex.keychain || true" EXIT
echo "desktop.mac.signing.identity=Developer ID Application: SimpleX Chat Ltd (5NN7GUYB6T)" >> apps/multiplatform/local.properties
echo "desktop.mac.signing.keychain=/tmp/simplex.keychain" >> apps/multiplatform/local.properties
echo "desktop.mac.notarization.apple_id=$APPLE_SIMPLEX_NOTARIZATION_APPLE_ID" >> apps/multiplatform/local.properties
@@ -10,10 +10,6 @@ echo "desktop.mac.notarization.password=$APPLE_SIMPLEX_NOTARIZATION_PASSWORD" >>
echo "desktop.mac.notarization.team_id=5NN7GUYB6T" >> apps/multiplatform/local.properties
echo "$APPLE_SIMPLEX_SIGNING_KEYCHAIN" | base64 --decode - > /tmp/simplex.keychain
security unlock-keychain -p "" /tmp/simplex.keychain
# Adding keychain to the list of keychains.
# Otherwise, it can find cert but exits while signing with "error: The specified item could not be found in the keychain."
security list-keychains -s `security list-keychains | xargs` /tmp/simplex.keychain
scripts/desktop/build-lib-mac.sh
cd apps/multiplatform
./gradlew packageDmg

View File

@@ -8,7 +8,7 @@ function readlink() {
OS=linux
ARCH=${1:-`uname -a | rev | cut -d' ' -f2 | rev`}
GHC_VERSION=9.6.3
GHC_VERSION=8.10.7
if [ "$ARCH" == "aarch64" ]; then
COMPOSE_ARCH=arm64
@@ -21,7 +21,7 @@ cd $root_dir
BUILD_DIR=dist-newstyle/build/$ARCH-$OS/ghc-${GHC_VERSION}/simplex-chat-*
rm -rf $BUILD_DIR
cabal build lib:simplex-chat --ghc-options='-optl-Wl,-rpath,$ORIGIN -flink-rts -threaded'
cabal build lib:simplex-chat --ghc-options='-optl-Wl,-rpath,$ORIGIN' --ghc-options="-optl-L$(ghc --print-libdir)/rts -optl-Wl,--as-needed,-lHSrts_thr-ghc$GHC_VERSION"
cd $BUILD_DIR/build
#patchelf --add-needed libHSrts_thr-ghc${GHC_VERSION}.so libHSsimplex-chat-*-inplace-ghc${GHC_VERSION}.so
#patchelf --add-rpath '$ORIGIN' libHSsimplex-chat-*-inplace-ghc${GHC_VERSION}.so

View File

@@ -5,14 +5,13 @@ set -e
OS=mac
ARCH="${1:-`uname -a | rev | cut -d' ' -f1 | rev`}"
COMPOSE_ARCH=$ARCH
GHC_VERSION=9.6.3
GHC_VERSION=8.10.7
if [ "$ARCH" == "arm64" ]; then
ARCH=aarch64
else
COMPOSE_ARCH=x64
fi
LIB_EXT=dylib
LIB=libHSsimplex-chat-*-inplace-ghc*.$LIB_EXT
GHC_LIBS_DIR=$(ghc --print-libdir)
@@ -20,26 +19,13 @@ GHC_LIBS_DIR=$(ghc --print-libdir)
BUILD_DIR=dist-newstyle/build/$ARCH-*/ghc-*/simplex-chat-*
rm -rf $BUILD_DIR
cabal build lib:simplex-chat lib:simplex-chat --ghc-options="-optl-Wl,-rpath,@loader_path -optl-Wl,-L$GHC_LIBS_DIR/$ARCH-osx-ghc-$GHC_VERSION -optl-lHSrts_thr-ghc$GHC_VERSION -optl-lffi"
cabal build lib:simplex-chat lib:simplex-chat --ghc-options="-optl-Wl,-rpath,@loader_path -optl-Wl,-L$GHC_LIBS_DIR/rts -optl-lHSrts_thr-ghc8.10.7 -optl-lffi"
cd $BUILD_DIR/build
mkdir deps 2> /dev/null || true
# It's not included by default for some reason. Compiled lib tries to find system one but it's not always available
#cp $GHC_LIBS_DIR/libffi.dylib ./deps
(
BUILD=$PWD
cp /tmp/libffi-3.4.4/*-apple-darwin*/.libs/libffi.dylib $BUILD/deps || \
( \
cd /tmp && \
curl "https://gitlab.haskell.org/ghc/libffi-tarballs/-/raw/libffi-3.4.4/libffi-3.4.4.tar.gz?inline=false" -o libffi.tar.gz && \
tar -xzvf libffi.tar.gz && \
cd "libffi-3.4.4" && \
./configure && \
make && \
cp *-apple-darwin*/.libs/libffi.dylib $BUILD/deps \
)
)
cp $GHC_LIBS_DIR/rts/libffi.dylib ./deps
DYLIBS=`otool -L $LIB | grep @rpath | tail -n +2 | cut -d' ' -f 1 | cut -d'/' -f2`
RPATHS=`otool -l $LIB | grep "path "| cut -d' ' -f11`
@@ -80,8 +66,6 @@ function copy_deps() {
}
copy_deps $LIB
# Special case
cp $(ghc --print-libdir)/$ARCH-osx-ghc-$GHC_VERSION/libHSghc-boot-th-$GHC_VERSION-ghc$GHC_VERSION.dylib deps
rm deps/`basename $LIB`
cd -

View File

@@ -1,242 +0,0 @@
From 38be2c93acb6f459d24ed6c626981c35ccf44095 Mon Sep 17 00:00:00 2001
From: Sylvain Henry <sylvain@haskus.fr>
Date: Thu, 16 Feb 2023 15:40:45 +0100
Subject: [PATCH] Fix build on 32-bit architectures
---
Basement/Bits.hs | 4 ++++
Basement/From.hs | 24 -----------------------
Basement/Numerical/Additive.hs | 4 ++++
Basement/Numerical/Conversion.hs | 20 +++++++++++++++++++
Basement/PrimType.hs | 6 +++++-
Basement/Types/OffsetSize.hs | 22 +++++++++++++++++++--
6 files changed, 53 insertions(+), 27 deletions(-)
diff --git a/Basement/Bits.hs b/Basement/Bits.hs
index 7eeea0f5..24520ed7 100644
--- a/Basement/Bits.hs
+++ b/Basement/Bits.hs
@@ -54,8 +54,12 @@ import GHC.Int
import Basement.Compat.Primitive
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+import GHC.Exts
+#else
import GHC.IntWord64
#endif
+#endif
-- | operation over finite bits
class FiniteBitsOps bits where
diff --git a/Basement/From.hs b/Basement/From.hs
index 7bbe141c..80014b3e 100644
--- a/Basement/From.hs
+++ b/Basement/From.hs
@@ -272,23 +272,11 @@ instance (NatWithinBound (CountOf ty) n, KnownNat n, PrimType ty)
tryFrom = BlockN.toBlockN . UArray.toBlock . BoxArray.mapToUnboxed id
instance (KnownNat n, NatWithinBound Word8 n) => From (Zn64 n) Word8 where
-#if __GLASGOW_HASKELL__ >= 904
- from = narrow . unZn64 where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# (GHC.Prim.word64ToWord# w)))
-#else
from = narrow . unZn64 where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# w))
-#endif
instance (KnownNat n, NatWithinBound Word16 n) => From (Zn64 n) Word16 where
-#if __GLASGOW_HASKELL__ >= 904
- from = narrow . unZn64 where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# (GHC.Prim.word64ToWord# w)))
-#else
from = narrow . unZn64 where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# w))
-#endif
instance (KnownNat n, NatWithinBound Word32 n) => From (Zn64 n) Word32 where
-#if __GLASGOW_HASKELL__ >= 904
- from = narrow . unZn64 where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# (GHC.Prim.word64ToWord# w)))
-#else
from = narrow . unZn64 where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# w))
-#endif
instance From (Zn64 n) Word64 where
from = unZn64
instance From (Zn64 n) Word128 where
@@ -297,23 +285,11 @@ instance From (Zn64 n) Word256 where
from = from . unZn64
instance (KnownNat n, NatWithinBound Word8 n) => From (Zn n) Word8 where
-#if __GLASGOW_HASKELL__ >= 904
- from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# (GHC.Prim.word64ToWord# w)))
-#else
from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W8# (wordToWord8# (word64ToWord# w))
-#endif
instance (KnownNat n, NatWithinBound Word16 n) => From (Zn n) Word16 where
-#if __GLASGOW_HASKELL__ >= 904
- from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# (GHC.Prim.word64ToWord# w)))
-#else
from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W16# (wordToWord16# (word64ToWord# w))
-#endif
instance (KnownNat n, NatWithinBound Word32 n) => From (Zn n) Word32 where
-#if __GLASGOW_HASKELL__ >= 904
- from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# (GHC.Prim.word64ToWord# w)))
-#else
from = narrow . naturalToWord64 . unZn where narrow (W64# w) = W32# (wordToWord32# (word64ToWord# w))
-#endif
instance (KnownNat n, NatWithinBound Word64 n) => From (Zn n) Word64 where
from = naturalToWord64 . unZn
instance (KnownNat n, NatWithinBound Word128 n) => From (Zn n) Word128 where
diff --git a/Basement/Numerical/Additive.hs b/Basement/Numerical/Additive.hs
index d0dfb973..8ab65aa0 100644
--- a/Basement/Numerical/Additive.hs
+++ b/Basement/Numerical/Additive.hs
@@ -30,8 +30,12 @@ import qualified Basement.Types.Word128 as Word128
import qualified Basement.Types.Word256 as Word256
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+import GHC.Exts
+#else
import GHC.IntWord64
#endif
+#endif
-- | Represent class of things that can be added together,
-- contains a neutral element and is commutative.
diff --git a/Basement/Numerical/Conversion.hs b/Basement/Numerical/Conversion.hs
index db502c07..fddc8232 100644
--- a/Basement/Numerical/Conversion.hs
+++ b/Basement/Numerical/Conversion.hs
@@ -26,8 +26,12 @@ import GHC.Word
import Basement.Compat.Primitive
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+import GHC.Exts
+#else
import GHC.IntWord64
#endif
+#endif
intToInt64 :: Int -> Int64
#if WORD_SIZE_IN_BITS == 64
@@ -96,11 +100,22 @@ int64ToWord64 (I64# i) = W64# (int64ToWord64# i)
#endif
#if WORD_SIZE_IN_BITS == 64
+#if __GLASGOW_HASKELL__ >= 904
+word64ToWord# :: Word64# -> Word#
+word64ToWord# i = word64ToWord# i
+#else
word64ToWord# :: Word# -> Word#
word64ToWord# i = i
+#endif
{-# INLINE word64ToWord# #-}
#endif
+#if WORD_SIZE_IN_BITS < 64
+word64ToWord32# :: Word64# -> Word32#
+word64ToWord32# i = wordToWord32# (word64ToWord# i)
+{-# INLINE word64ToWord32# #-}
+#endif
+
-- | 2 Word32s
data Word32x2 = Word32x2 {-# UNPACK #-} !Word32
{-# UNPACK #-} !Word32
@@ -113,9 +128,14 @@ word64ToWord32s (W64# w64) = Word32x2 (W32# (wordToWord32# (uncheckedShiftRL# (G
word64ToWord32s (W64# w64) = Word32x2 (W32# (wordToWord32# (uncheckedShiftRL# w64 32#))) (W32# (wordToWord32# w64))
#endif
#else
+#if __GLASGOW_HASKELL__ >= 904
+word64ToWord32s :: Word64 -> Word32x2
+word64ToWord32s (W64# w64) = Word32x2 (W32# (word64ToWord32# (uncheckedShiftRL64# w64 32#))) (W32# (word64ToWord32# w64))
+#else
word64ToWord32s :: Word64 -> Word32x2
word64ToWord32s (W64# w64) = Word32x2 (W32# (word64ToWord# (uncheckedShiftRL64# w64 32#))) (W32# (word64ToWord# w64))
#endif
+#endif
wordToChar :: Word -> Char
wordToChar (W# word) = C# (chr# (word2Int# word))
diff --git a/Basement/PrimType.hs b/Basement/PrimType.hs
index f8ca2926..a888ec91 100644
--- a/Basement/PrimType.hs
+++ b/Basement/PrimType.hs
@@ -54,7 +54,11 @@ import Basement.Nat
import qualified Prelude (quot)
#if WORD_SIZE_IN_BITS < 64
-import GHC.IntWord64
+#if __GLASGOW_HASKELL__ >= 904
+import GHC.Exts
+#else
+import GHC.IntWord64
+#endif
#endif
#ifdef FOUNDATION_BOUNDS_CHECK
diff --git a/Basement/Types/OffsetSize.hs b/Basement/Types/OffsetSize.hs
index cd944927..1ea80dad 100644
--- a/Basement/Types/OffsetSize.hs
+++ b/Basement/Types/OffsetSize.hs
@@ -70,8 +70,12 @@ import Data.List (foldl')
import qualified Prelude
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+import GHC.Exts
+#else
import GHC.IntWord64
#endif
+#endif
-- | File size in bytes
newtype FileSize = FileSize Word64
@@ -225,20 +229,26 @@ countOfRoundUp alignment (CountOf n) = CountOf ((n + (alignment-1)) .&. compleme
csizeOfSize :: CountOf Word8 -> CSize
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+csizeOfSize (CountOf (I# sz)) = CSize (W32# (wordToWord32# (int2Word# sz)))
+#else
csizeOfSize (CountOf (I# sz)) = CSize (W32# (int2Word# sz))
+#endif
#else
#if __GLASGOW_HASKELL__ >= 904
csizeOfSize (CountOf (I# sz)) = CSize (W64# (wordToWord64# (int2Word# sz)))
-
#else
csizeOfSize (CountOf (I# sz)) = CSize (W64# (int2Word# sz))
-
#endif
#endif
csizeOfOffset :: Offset8 -> CSize
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+csizeOfOffset (Offset (I# sz)) = CSize (W32# (wordToWord32# (int2Word# sz)))
+#else
csizeOfOffset (Offset (I# sz)) = CSize (W32# (int2Word# sz))
+#endif
#else
#if __GLASGOW_HASKELL__ >= 904
csizeOfOffset (Offset (I# sz)) = CSize (W64# (wordToWord64# (int2Word# sz)))
@@ -250,7 +260,11 @@ csizeOfOffset (Offset (I# sz)) = CSize (W64# (int2Word# sz))
sizeOfCSSize :: CSsize -> CountOf Word8
sizeOfCSSize (CSsize (-1)) = error "invalid size: CSSize is -1"
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+sizeOfCSSize (CSsize (I32# sz)) = CountOf (I# (int32ToInt# sz))
+#else
sizeOfCSSize (CSsize (I32# sz)) = CountOf (I# sz)
+#endif
#else
#if __GLASGOW_HASKELL__ >= 904
sizeOfCSSize (CSsize (I64# sz)) = CountOf (I# (int64ToInt# sz))
@@ -261,7 +275,11 @@ sizeOfCSSize (CSsize (I64# sz)) = CountOf (I# sz)
sizeOfCSize :: CSize -> CountOf Word8
#if WORD_SIZE_IN_BITS < 64
+#if __GLASGOW_HASKELL__ >= 904
+sizeOfCSize (CSize (W32# sz)) = CountOf (I# (word2Int# (word32ToWord# sz)))
+#else
sizeOfCSize (CSize (W32# sz)) = CountOf (I# (word2Int# sz))
+#endif
#else
#if __GLASGOW_HASKELL__ >= 904
sizeOfCSize (CSize (W64# sz)) = CountOf (I# (word2Int# (word64ToWord# sz)))

View File

@@ -1,12 +0,0 @@
diff --git a/direct-sqlcipher.cabal b/direct-sqlcipher.cabal
index 728ba3e..c63745e 100644
--- a/direct-sqlcipher.cabal
+++ b/direct-sqlcipher.cabal
@@ -84,6 +84,8 @@ library
cc-options: -DSQLITE_TEMP_STORE=2
-DSQLITE_HAS_CODEC
+ extra-libraries: ws2_32
+
if !os(windows) && !os(android)
extra-libraries: pthread

View File

@@ -1,36 +0,0 @@
From 2738929ce15b4c8704bbbac24a08539b5d4bf30e Mon Sep 17 00:00:00 2001
From: sternenseemann <sternenseemann@systemli.org>
Date: Mon, 14 Aug 2023 10:51:30 +0200
Subject: [PATCH] Data.Memory.Internal.CompatPrim64: fix 32 bit with GHC >= 9.4
Since 9.4, GHC.Prim exports Word64# operations like timesWord64# even on
i686 whereas GHC.IntWord64 no longer exists. Therefore, we can just use
the ready made solution.
Closes #98, as it should be the better solution.
---
Data/Memory/Internal/CompatPrim64.hs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Data/Memory/Internal/CompatPrim64.hs b/Data/Memory/Internal/CompatPrim64.hs
index b9eef8a..a134c88 100644
--- a/Data/Memory/Internal/CompatPrim64.hs
+++ b/Data/Memory/Internal/CompatPrim64.hs
@@ -150,6 +150,7 @@ w64# :: Word# -> Word# -> Word# -> Word64#
w64# w _ _ = w
#elif WORD_SIZE_IN_BITS == 32
+#if __GLASGOW_HASKELL__ < 904
import GHC.IntWord64
import GHC.Prim (Word#)
@@ -158,6 +159,9 @@ timesWord64# a b =
let !ai = word64ToInt64# a
!bi = word64ToInt64# b
in int64ToWord64# (timesInt64# ai bi)
+#else
+import GHC.Prim
+#endif
w64# :: Word# -> Word# -> Word# -> Word64#
w64# _ hw lw =

View File

@@ -1,11 +1,10 @@
{
"https://github.com/simplex-chat/simplexmq.git"."757b7eec81341d8560a326deab303bb6fb6a26a3" = "0kqnxpyz8v43802fncqxdg6i2ni70yv7jg7a1nbkny1w937fwf40";
"https://github.com/simplex-chat/simplexmq.git"."281bdebcb82aed4c8c2c08438b9cafc7908183a1" = "0dly5rnpcnb7mbfxgpxna5xbabk6n0dh5qz53nm4l93gzdy18hpb";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/kazu-yamamoto/http2.git"."f5525b755ff2418e6e6ecc69e877363b0d0bcaeb" = "0fyx0047gvhm99ilp212mmz37j84cwrfnpmssib5dw363fyb88b6";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
"https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd";
"https://github.com/simplex-chat/sqlcipher-simple.git"."5e154a2aeccc33ead6c243ec07195ab673137221" = "1d1gc5wax4vqg0801ajsmx1sbwvd9y7p7b8mmskvqsmpbwgbh0m0";
"https://github.com/simplex-chat/aeson.git"."aab7b5a14d6c5ea64c64dcaee418de1bb00dcc2b" = "0jz7kda8gai893vyvj96fy962ncv8dcsx71fbddyy8zrvc88jfrr";
"https://github.com/simplex-chat/haskell-terminal.git"."f708b00009b54890172068f168bf98508ffcd495" = "0zmq7lmfsk8m340g47g5963yba7i88n4afa6z93sg9px5jv1mijj";
"https://github.com/simplex-chat/android-support.git"."9aa09f148089d6752ce563b14c2df1895718d806" = "0pbf2pf13v2kjzi397nr13f1h3jv0imvsq8rpiyy2qyx5vd50pqn";
"https://github.com/simplex-chat/network-transport.git"."0013798272a683e35ca38d2fdaf480942311fba8" = "0dnn62apgvc248df0m8ib7phrzn63wm0xs71xvlypv52j6cgwzkb";
"https://github.com/zw3rk/android-support.git"."3c3a5ab0b8b137a072c98d3d0937cbdc96918ddb" = "1r6jyxbim3dsvrmakqfyxbd6ms6miaghpbwyl0sr6dzwpgaprz97";
}

View File

@@ -11,7 +11,7 @@ BEGIN {
/tag/ && isGit == true { ref=$2 }
isGit == true && loc != "" && ref != "" {
cmd = "nix-prefetch-git --fetch-submodules --quiet "loc" "ref" | jq -r .sha256"
cmd = "nix-prefetch-git --quiet "loc" "ref" | jq -r .sha256"
cmd | getline sha256
close(cmd)
print " \""loc"\".\""ref"\" = \""sha256"\";";

View File

@@ -1,6 +1,6 @@
cabal-version: 1.12
-- This file has been generated from package.yaml by hpack version 0.36.0.
-- This file has been generated from package.yaml by hpack version 0.35.0.
--
-- see: https://github.com/sol/hpack
@@ -170,11 +170,11 @@ library
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, direct-sqlcipher ==2.3.*
, directory ==1.3.*
@@ -183,10 +183,10 @@ library
, filepath ==1.4.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -196,14 +196,14 @@ library
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON
@@ -222,11 +222,11 @@ executable simplex-bot
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, direct-sqlcipher ==2.3.*
, directory ==1.3.*
@@ -235,10 +235,10 @@ executable simplex-bot
, filepath ==1.4.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -249,14 +249,14 @@ executable simplex-bot
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON
@@ -275,11 +275,11 @@ executable simplex-bot-advanced
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, direct-sqlcipher ==2.3.*
, directory ==1.3.*
@@ -288,10 +288,10 @@ executable simplex-bot-advanced
, filepath ==1.4.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -302,14 +302,14 @@ executable simplex-bot-advanced
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON
@@ -330,11 +330,11 @@ executable simplex-broadcast-bot
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, direct-sqlcipher ==2.3.*
, directory ==1.3.*
@@ -343,10 +343,10 @@ executable simplex-broadcast-bot
, filepath ==1.4.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -357,14 +357,14 @@ executable simplex-broadcast-bot
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON
@@ -384,11 +384,11 @@ executable simplex-chat
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, direct-sqlcipher ==2.3.*
, directory ==1.3.*
@@ -397,10 +397,10 @@ executable simplex-chat
, filepath ==1.4.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network ==3.1.*
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -411,15 +411,15 @@ executable simplex-chat
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, websockets ==0.12.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON
@@ -442,11 +442,11 @@ executable simplex-directory-service
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, direct-sqlcipher ==2.3.*
, directory ==1.3.*
@@ -455,10 +455,10 @@ executable simplex-directory-service
, filepath ==1.4.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network >=3.1.2.7 && <3.2
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -469,14 +469,14 @@ executable simplex-directory-service
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON
@@ -523,11 +523,11 @@ test-suite simplex-chat-test
, attoparsec ==0.14.*
, base >=4.7 && <5
, base64-bytestring >=1.0 && <1.3
, bytestring ==0.11.*
, bytestring ==0.10.*
, composition ==1.0.*
, constraints >=0.12 && <0.14
, containers ==0.6.*
, cryptonite ==0.30.*
, cryptonite >=0.27 && <0.30
, data-default ==0.7.*
, deepseq ==1.4.*
, direct-sqlcipher ==2.3.*
@@ -536,13 +536,13 @@ test-suite simplex-chat-test
, exceptions ==0.10.*
, filepath ==1.4.*
, generic-random ==1.5.*
, hspec ==2.11.*
, hspec ==2.7.*
, http-types ==0.12.*
, http2 >=4.2.2 && <4.3
, memory ==0.18.*
, mtl ==2.3.*
, memory ==0.15.*
, mtl ==2.2.*
, network ==3.1.*
, network-transport ==0.5.6
, network-transport ==0.5.4
, optparse-applicative >=0.15 && <0.17
, process ==1.6.*
, random >=1.1 && <1.3
@@ -554,14 +554,14 @@ test-suite simplex-chat-test
, socks ==0.6.*
, sqlcipher-simple ==0.4.*
, stm ==2.5.*
, template-haskell ==2.20.*
, template-haskell ==2.16.*
, terminal ==0.2.*
, text ==2.0.*
, text ==1.2.*
, time ==1.9.*
, tls >=1.6.0 && <1.7
, unliftio ==0.2.*
, unliftio-core ==0.2.*
, zip ==2.0.*
, zip ==1.7.*
default-language: Haskell2010
if flag(swift)
cpp-options: -DswiftJSON

View File

@@ -5,7 +5,6 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -13,14 +12,11 @@
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat where
import Control.Applicative (optional, (<|>))
import Control.Concurrent.STM (retry)
import Control.Logger.Simple
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Unlift
import Control.Monad.Reader
@@ -274,8 +270,8 @@ newChatController ChatDatabase {chatStore, agentStore} user cfg@ChatConfig {agen
where
configServers :: DefaultAgentServers
configServers =
let smp' = fromMaybe (defaultServers.smp) (nonEmpty smpServers)
xftp' = fromMaybe (defaultServers.xftp) (nonEmpty xftpServers)
let smp' = fromMaybe (smp (defaultServers :: DefaultAgentServers)) (nonEmpty smpServers)
xftp' = fromMaybe (xftp (defaultServers :: DefaultAgentServers)) (nonEmpty xftpServers)
in defaultServers {smp = smp', xftp = xftp', netCfg = networkConfig}
agentServers :: ChatConfig -> IO InitialAgentServers
agentServers config@ChatConfig {defaultServers = defServers@DefaultAgentServers {ntf, netCfg}} = do
@@ -302,9 +298,9 @@ activeAgentServers ChatConfig {defaultServers} p =
. filter (\ServerCfg {enabled} -> enabled)
cfgServers :: UserProtocol p => SProtocolType p -> (DefaultAgentServers -> NonEmpty (ProtoServerWithAuth p))
cfgServers p s = case p of
SPSMP -> s.smp
SPXFTP -> s.xftp
cfgServers = \case
SPSMP -> smp
SPXFTP -> xftp
startChatController :: forall m. ChatMonad' m => Bool -> Bool -> Bool -> m (Async ())
startChatController subConns enableExpireCIs startXFTPWorkers = do
@@ -779,9 +775,7 @@ processChatCommand = \case
MCVoice {} -> False
MCUnknown {} -> True
qText = msgContentText qmc
getFileName :: CIFile d -> String
getFileName CIFile{fileName} = fileName
qFileName = maybe qText (T.pack . getFileName) ciFile_
qFileName = maybe qText (T.pack . (fileName :: CIFile d -> String)) ciFile_
qTextOrFile = if T.null qText then qFileName else qText
xftpSndFileTransfer :: User -> CryptoFile -> Integer -> Int -> ContactOrGroup -> m (FileInvitation, CIFile 'MDSnd, FileTransferMeta)
xftpSndFileTransfer user file@(CryptoFile filePath cfArgs) fileSize n contactOrGroup = do
@@ -994,7 +988,7 @@ processChatCommand = \case
pure $ CRContactConnectionDeleted user conn
CTGroup -> do
Group gInfo@GroupInfo {membership} members <- withStore $ \db -> getGroup db user chatId
let isOwner = membership.memberRole == GROwner
let isOwner = memberRole (membership :: GroupMember) == GROwner
canDelete = isOwner || not (memberCurrent membership)
unless canDelete $ throwChatError $ CEGroupUserRole gInfo GROwner
filesInfo <- withStore' $ \db -> getGroupFileInfo db user gInfo
@@ -1173,9 +1167,7 @@ processChatCommand = \case
APIGetNtfMessage nonce encNtfInfo -> withUser $ \_ -> do
(NotificationInfo {ntfConnId, ntfMsgMeta}, msgs) <- withAgent $ \a -> getNotificationMessage a nonce encNtfInfo
let ntfMessages = map (\SMP.SMPMsgMeta {msgTs, msgFlags} -> NtfMsgInfo {msgTs = systemToUTCTime msgTs, msgFlags}) msgs
getMsgTs :: SMP.NMsgMeta -> SystemTime
getMsgTs SMP.NMsgMeta{msgTs} = msgTs
msgTs' = systemToUTCTime . getMsgTs <$> ntfMsgMeta
msgTs' = systemToUTCTime . (SMP.msgTs :: SMP.NMsgMeta -> SystemTime) <$> ntfMsgMeta
agentConnId = AgentConnId ntfConnId
user_ <- withStore' (`getUserByAConnId` agentConnId)
connEntity <-
@@ -1640,7 +1632,7 @@ processChatCommand = \case
case activeConn of
Just Connection {peerChatVRange} -> do
subMode <- chatReadVar subscriptionMode
dm <- directMessage $ XGrpAcpt membership.memberId
dm <- directMessage $ XGrpAcpt (memberId (membership :: GroupMember))
agentConnId <- withAgent $ \a -> joinConnection a (aUserId user) True connRequest dm subMode
withStore' $ \db -> do
createMemberConnection db userId fromMember agentConnId (fromJVersionRange peerChatVRange) subMode
@@ -1797,7 +1789,7 @@ processChatCommand = \case
case memberConn m of
Just mConn -> do
let msg = XGrpDirectInv cReq msgContent_
(sndMsg, _) <- sendDirectMessage mConn msg (GroupId $ g.groupId)
(sndMsg, _) <- sendDirectMessage mConn msg (GroupId $ groupId (g :: GroupInfo))
withStore' $ \db -> setContactGrpInvSent db ct True
let ct' = ct {contactGrpInvSent = True}
forM_ msgContent_ $ \mc -> do
@@ -1988,8 +1980,7 @@ processChatCommand = \case
DeleteRemoteCtrl rc -> withUser_ $ deleteRemoteCtrl rc >> ok_
QuitChat -> liftIO exitSuccess
ShowVersion -> do
-- simplexmqCommitQ makes iOS builds crash m(
let versionInfo = coreVersionInfo "" -- $(simplexmqCommitQ)
let versionInfo = coreVersionInfo $(simplexmqCommitQ)
chatMigrations <- map upMigration <$> withStore' (Migrations.getCurrent . DB.conn)
agentMigrations <- withAgent getAgentMigrations
pure $ CRVersionInfo {versionInfo, chatMigrations, agentMigrations}
@@ -2215,7 +2206,7 @@ processChatCommand = \case
when (displayName /= validName) $ throwChatError CEInvalidDisplayName {displayName, validName}
assertUserGroupRole :: GroupInfo -> GroupMemberRole -> m ()
assertUserGroupRole g@GroupInfo {membership} requiredRole = do
when (membership.memberRole < requiredRole) $ throwChatError $ CEGroupUserRole g requiredRole
when (memberRole (membership :: GroupMember) < requiredRole) $ throwChatError $ CEGroupUserRole g requiredRole
when (memberStatus membership == GSMemInvited) $ throwChatError (CEGroupNotJoined g)
when (memberRemoved membership) $ throwChatError CEGroupMemberUserRemoved
unless (memberActive membership) $ throwChatError CEGroupMemberNotActive
@@ -2259,7 +2250,7 @@ processChatCommand = \case
forwardFile chatName fileId sendCommand = withUser $ \user -> do
withStore (\db -> getFileTransfer db user fileId) >>= \case
FTRcv RcvFileTransfer {fileStatus = RFSComplete RcvFileInfo {filePath}, cryptoArgs} -> forward filePath cryptoArgs
FTSnd {fileTransferMeta = FileTransferMeta {filePath, xftpSndFile}} -> forward filePath $ xftpSndFile >>= \f -> f.cryptoArgs
FTSnd {fileTransferMeta = FileTransferMeta {filePath, xftpSndFile}} -> forward filePath $ xftpSndFile >>= \XFTPSndFile {cryptoArgs} -> cryptoArgs
_ -> throwChatError CEFileNotReceived {fileId}
where
forward path cfArgs = processChatCommand . sendCommand chatName $ CryptoFile path cfArgs
@@ -2368,6 +2359,7 @@ processChatCommand = \case
( CRInvitationUri crData {crScheme = CRSSimplex} e2e,
CRInvitationUri crData {crScheme = simplexChat} e2e
)
_ -> (cReq, cReq) -- ghc8107
connectPlan user (ACR SCMContact cReq) = do
let CRContactUri ConnReqUriData {crClientData} = cReq
groupLinkId = crClientData >>= decodeJSON >>= \(CRDataGroup gli) -> Just gli
@@ -2414,6 +2406,7 @@ processChatCommand = \case
( CRContactUri crData {crScheme = CRSSimplex},
CRContactUri crData {crScheme = simplexChat}
)
_ -> (cReq, cReq) -- ghc8107
cReqHashes :: (ConnReqUriHash, ConnReqUriHash)
cReqHashes = bimap hash hash cReqSchemas
hash = ConnReqUriHash . C.sha256Hash . strEncode
@@ -3515,7 +3508,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
| sameMemberId memId m -> do
-- TODO update member profile
-- [async agent commands] no continuation needed, but command should be asynchronous for stability
allowAgentConnectionAsync user conn' confId $ XGrpMemInfo membership.memberId (fromLocalProfile $ memberProfile membership)
allowAgentConnectionAsync user conn' confId $ XGrpMemInfo (memberId (membership :: GroupMember)) (fromLocalProfile $ memberProfile membership)
| otherwise -> messageError "x.grp.mem.info: memberId is different from expected"
_ -> messageError "CONF from member must have x.grp.mem.info"
INFO connInfo -> do
@@ -3586,19 +3579,19 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
forM_ (invitedByGroupMemberId membership) $ \hostId -> do
host <- withStore $ \db -> getGroupMember db user groupId hostId
forM_ (memberConn host) $ \hostConn ->
void $ sendDirectMessage hostConn (XGrpMemCon m.memberId) (GroupId groupId)
void $ sendDirectMessage hostConn (XGrpMemCon $ memberId (m :: GroupMember)) (GroupId groupId)
GCPostMember ->
forM_ (invitedByGroupMemberId m) $ \invitingMemberId -> do
im <- withStore $ \db -> getGroupMember db user groupId invitingMemberId
forM_ (memberConn im) $ \imConn ->
void $ sendDirectMessage imConn (XGrpMemCon m.memberId) (GroupId groupId)
void $ sendDirectMessage imConn (XGrpMemCon $ memberId (m :: GroupMember)) (GroupId groupId)
_ -> messageWarning "sendXGrpMemCon: member category GCPreMember or GCPostMember is expected"
MSG msgMeta _msgFlags msgBody -> do
cmdId <- createAckCmd conn
tryChatError (processChatMessage cmdId) >>= \case
Right (ACMsg _ chatMsg, withRcpt) -> do
ackMsg agentConnId cmdId msgMeta $ if withRcpt then Just "" else Nothing
when (membership.memberRole >= GRAdmin) $ forwardMsg_ chatMsg
when (memberRole (membership :: GroupMember) >= GRAdmin) $ forwardMsg_ chatMsg
Left e -> ackMsg agentConnId cmdId msgMeta Nothing >> throwError e
where
processChatMessage :: Int64 -> m (AChatMessage, Bool)
@@ -3676,7 +3669,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
-- invited members to which this member was introduced
invitedMembers <- withStore' $ \db -> getForwardInvitedMembers db user m highlyAvailable
let ms = introducedMembers <> invitedMembers
msg = XGrpMsgForward m.memberId chatMsg' brokerTs
msg = XGrpMsgForward (memberId (m :: GroupMember)) chatMsg' brokerTs
unless (null ms) $
void $ sendGroupMessage user gInfo ms msg
RCVD msgMeta msgRcpt ->
@@ -3938,8 +3931,8 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
_ -> pure ()
memberCanSend :: GroupMember -> m () -> m ()
memberCanSend mem a
| mem.memberRole <= GRObserver = messageError "member is not allowed to send messages"
memberCanSend GroupMember {memberRole} a
| memberRole <= GRObserver = messageError "member is not allowed to send messages"
| otherwise = a
incAuthErrCounter :: ConnectionEntity -> Connection -> AgentErrorType -> m ()
@@ -5007,7 +5000,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
withStore' $ \db -> saveMemberInvitation db toMember introInv
subMode <- chatReadVar subscriptionMode
-- [incognito] send membership incognito profile, create direct connection as incognito
dm <- directMessage $ XGrpMemInfo membership.memberId (fromLocalProfile $ memberProfile membership)
dm <- directMessage $ XGrpMemInfo (memberId (membership :: GroupMember)) (fromLocalProfile $ memberProfile membership)
-- [async agent commands] no continuation needed, but commands should be asynchronous for stability
groupConnIds <- joinAgentConnectionAsync user (chatHasNtfs chatSettings) groupConnReq dm subMode
directConnIds <- forM directConnReq $ \dcr -> joinAgentConnectionAsync user True dcr dm subMode
@@ -5017,7 +5010,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
xGrpMemRole :: GroupInfo -> GroupMember -> MemberId -> GroupMemberRole -> RcvMessage -> UTCTime -> m ()
xGrpMemRole gInfo@GroupInfo {membership} m@GroupMember {memberRole = senderRole} memId memRole msg brokerTs
| membership.memberId == memId =
| memberId (membership :: GroupMember) == memId =
let gInfo' = gInfo {membership = membership {memberRole = memRole}}
in changeMemberRole gInfo' membership $ RGEUserRole memRole
| otherwise =
@@ -5077,7 +5070,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
xGrpMemDel :: GroupInfo -> GroupMember -> MemberId -> RcvMessage -> UTCTime -> m ()
xGrpMemDel gInfo@GroupInfo {membership} m@GroupMember {memberRole = senderRole} memId msg brokerTs = do
if membership.memberId == memId
if memberId (membership :: GroupMember) == memId
then checkRole membership $ do
deleteGroupLinkIfExists user gInfo
-- member records are not deleted to keep history
@@ -5189,8 +5182,8 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
createInternalChatItem user (CDDirectRcv ct) (CIRcvConnEvent RCEVerificationCodeReset) Nothing
xGrpMsgForward :: GroupInfo -> GroupMember -> MemberId -> ChatMessage 'Json -> UTCTime -> m ()
xGrpMsgForward gInfo@GroupInfo {groupId} m memberId msg msgTs = do
when (m.memberRole < GRAdmin) $ throwChatError (CEGroupContactRole m.localDisplayName)
xGrpMsgForward gInfo@GroupInfo {groupId} m@GroupMember {memberRole, localDisplayName} memberId msg msgTs = do
when (memberRole < GRAdmin) $ throwChatError (CEGroupContactRole localDisplayName)
author <- withStore $ \db -> getGroupMemberByMemberId db user gInfo memberId
processForwardedMsg author msg
where
@@ -5365,7 +5358,7 @@ parseFileChunk :: ChatMonad m => ByteString -> m FileChunk
parseFileChunk = liftEither . first (ChatError . CEFileRcvChunk) . smpDecode
appendFileChunk :: forall m. ChatMonad m => RcvFileTransfer -> Integer -> ByteString -> Bool -> m ()
appendFileChunk ft@RcvFileTransfer {fileId, fileStatus, cryptoArgs} chunkNo chunk final =
appendFileChunk ft@RcvFileTransfer {fileId, fileInvitation, fileStatus, cryptoArgs} chunkNo chunk final =
case fileStatus of
RFSConnected RcvFileInfo {filePath} -> append_ filePath
-- sometimes update of file transfer status to FSConnected
@@ -5383,7 +5376,7 @@ appendFileChunk ft@RcvFileTransfer {fileId, fileStatus, cryptoArgs} chunkNo chun
when final $ do
closeFileHandle fileId rcvFiles
forM_ cryptoArgs $ \cfArgs -> do
tmpFile <- getChatTempDirectory >>= (`uniqueCombine` ft.fileInvitation.fileName)
tmpFile <- getChatTempDirectory >>= (`uniqueCombine` fileName (fileInvitation :: FileInvitation))
tryChatError (liftError encryptErr $ encryptFile fsFilePath tmpFile cfArgs) >>= \case
Right () -> do
removeFile fsFilePath `catchChatError` \_ -> pure ()
@@ -5554,7 +5547,7 @@ sendGroupMessage' user members chatMsgEvent groupId introId_ postDeliver = do
forwardSupported = do
let mcvr = memberChatVRange' m
isCompatibleRange mcvr groupForwardVRange && invitingMemberSupportsForward
invitingMemberSupportsForward = case m.invitedByGroupMemberId of
invitingMemberSupportsForward = case invitedByGroupMemberId m of
Just invMemberId ->
-- can be optimized for large groups by replacing [GroupMember] with Map GroupMemberId GroupMember
case find (\m' -> groupMemberId' m' == invMemberId) members of
@@ -5608,13 +5601,13 @@ saveGroupRcvMsg user groupId authorMember conn@Connection {connId} agentMsgMeta
let agentMsgId = fst $ recipient agentMsgMeta
newMsg = NewMessage {chatMsgEvent, msgBody}
rcvMsgDelivery = RcvMsgDelivery {connId, agentMsgId, agentMsgMeta, agentAckCmdId}
amId = Just am'.groupMemberId
amId = Just $ groupMemberId' am'
msg <- withStore (\db -> createNewMessageAndRcvMsgDelivery db (GroupId groupId) newMsg sharedMsgId_ rcvMsgDelivery amId)
`catchChatError` \e -> case e of
ChatErrorStore (SEDuplicateGroupMessage _ _ _ (Just forwardedByGroupMemberId)) -> do
fm <- withStore $ \db -> getGroupMember db user groupId forwardedByGroupMemberId
forM_ (memberConn fm) $ \fmConn ->
void $ sendDirectMessage fmConn (XGrpMemCon am'.memberId) (GroupId groupId)
void $ sendDirectMessage fmConn (XGrpMemCon $ memberId (am' :: GroupMember)) (GroupId groupId)
throwError e
_ -> throwError e
pure (am', conn', msg)
@@ -5628,9 +5621,9 @@ saveGroupFwdRcvMsg user groupId forwardingMember refAuthorMember msgBody ChatMes
`catchChatError` \e -> case e of
ChatErrorStore (SEDuplicateGroupMessage _ _ (Just authorGroupMemberId) Nothing) -> do
am <- withStore $ \db -> getGroupMember db user groupId authorGroupMemberId
if sameMemberId refAuthorMember.memberId am
if sameMemberId (memberId (refAuthorMember :: GroupMember)) am
then forM_ (memberConn forwardingMember) $ \fmConn ->
void $ sendDirectMessage fmConn (XGrpMemCon am.memberId) (GroupId groupId)
void $ sendDirectMessage fmConn (XGrpMemCon $ memberId (am :: GroupMember)) (GroupId groupId)
else toView $ CRMessageError user "error" "saveGroupFwdRcvMsg: referenced author member id doesn't match message member id"
throwError e
_ -> throwError e
@@ -5776,7 +5769,7 @@ createSndFeatureItems :: forall m. ChatMonad m => User -> Contact -> Contact ->
createSndFeatureItems user ct ct' =
createFeatureItems user ct ct' CDDirectSnd CISndChatFeature CISndChatPreference getPref
where
getPref u = (userPreference u).preference
getPref = (preference :: ContactUserPref (FeaturePreference f) -> FeaturePreference f) . userPreference
type FeatureContent a d = ChatFeature -> a -> Maybe Int -> CIContent d
@@ -5860,7 +5853,7 @@ getCreateActiveUser st testView = do
Right user -> pure user
selectUser :: [User] -> IO User
selectUser [user] = do
withTransaction st (`setActiveUser` user.userId)
withTransaction st (`setActiveUser` userId (user :: User))
pure user
selectUser users = do
putStrLn "Select user profile:"
@@ -5875,7 +5868,7 @@ getCreateActiveUser st testView = do
| n <= 0 || n > length users -> putStrLn "invalid user number" >> loop
| otherwise -> do
let user = users !! (n - 1)
withTransaction st (`setActiveUser` user.userId)
withTransaction st (`setActiveUser` userId (user :: User))
pure user
userStr :: User -> String
userStr User {localDisplayName, profile = LocalProfile {fullName}} =

View File

@@ -14,7 +14,6 @@ module Simplex.Chat.Archive
where
import qualified Codec.Archive.Zip as Z
import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import Data.Functor (($>))

View File

@@ -8,7 +8,7 @@ module Simplex.Chat.Bot where
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Reader
import qualified Data.ByteString.Char8 as B
import qualified Data.Text as T
import Simplex.Chat.Controller

View File

@@ -5,15 +5,12 @@
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Messages where
import Control.Applicative ((<|>))
@@ -345,7 +342,7 @@ contactTimedTTL Contact {mergedPreferences = ContactUserPreferences {timedMessag
| forUser enabled && forContact enabled = Just ttl
| otherwise = Nothing
where
TimedMessagesPreference {ttl} = userPreference.preference
TimedMessagesPreference {ttl} = preference (userPreference :: ContactUserPref TimedMessagesPreference)
groupTimedTTL :: GroupInfo -> Maybe (Maybe Int)
groupTimedTTL GroupInfo {fullGroupPreferences = FullGroupPreferences {timedMessages = TimedMessagesGroupPreference {enable, ttl}}}

View File

@@ -16,7 +16,6 @@ module Simplex.Chat.Mobile.File
)
where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import qualified Data.Aeson as J

View File

@@ -16,12 +16,12 @@ type JSONByteString = LB.ByteString
getByteString :: Ptr Word8 -> CInt -> IO ByteString
getByteString ptr len = do
fp <- newForeignPtr_ ptr
pure $ BS fp $ fromIntegral len
pure $ PS fp 0 $ fromIntegral len
{-# INLINE getByteString #-}
putByteString :: Ptr Word8 -> ByteString -> IO ()
putByteString ptr (BS fp len) =
withForeignPtr fp $ \p -> memcpy ptr p len
putByteString ptr (PS fp offset len) =
withForeignPtr fp $ \p -> memcpy ptr (p `plusPtr` offset) len
{-# INLINE putByteString #-}
putLazyByteString :: Ptr Word8 -> LB.ByteString -> IO ()

View File

@@ -8,9 +8,7 @@ module Simplex.Chat.Mobile.WebRTC (
reservedSize,
) where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import qualified Crypto.Cipher.Types as AES
import Data.Bifunctor (bimap)
import qualified Data.ByteArray as BA

View File

@@ -14,8 +14,6 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Protocol where
import Control.Applicative ((<|>))

View File

@@ -5,8 +5,6 @@
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Store.Connections
( getConnectionEntity,
getConnectionEntityByConnReq,
@@ -17,7 +15,6 @@ module Simplex.Chat.Store.Connections
where
import Control.Applicative ((<|>))
import Control.Monad
import Control.Monad.Except
import Data.Int (Int64)
import Data.Maybe (catMaybes, fromMaybe)

View File

@@ -1,5 +1,4 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
@@ -8,8 +7,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Store.Direct
( updateContact_,
updateContactProfile_,
@@ -68,9 +65,7 @@ module Simplex.Chat.Store.Direct
)
where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import Data.Either (rights)
import Data.Functor (($>))
import Data.Int (Int64)
@@ -481,7 +476,7 @@ createOrUpdateContactRequest db user@User {userId} userContactLinkId invId (Vers
ExceptT $
maybeM getContactRequestByXContactId xContactId_ >>= \case
Nothing -> createContactRequest
Just cr -> updateContactRequest cr $> Right cr.contactRequestId
Just cr -> updateContactRequest cr $> Right (contactRequestId (cr :: UserContactRequest))
getContactRequest db user cReqId
createContactRequest :: IO (Either StoreError Int64)
createContactRequest = do

View File

@@ -2,7 +2,6 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -78,9 +77,7 @@ module Simplex.Chat.Store.Files
where
import Control.Applicative ((<|>))
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import Data.Either (rights)
import Data.Int (Int64)
import Data.Maybe (fromMaybe, isJust, listToMaybe)
@@ -490,7 +487,7 @@ createRcvFileTransfer :: DB.Connection -> UserId -> Contact -> FileInvitation ->
createRcvFileTransfer db userId Contact {contactId, localDisplayName = c} f@FileInvitation {fileName, fileSize, fileConnReq, fileInline, fileDescr} rcvFileInline chunkSize = do
currentTs <- liftIO getCurrentTime
rfd_ <- mapM (createRcvFD_ db userId currentTs) fileDescr
let rfdId = (\RcvFileDescr {fileDescrId} -> fileDescrId) <$> rfd_
let rfdId = (fileDescrId :: RcvFileDescr -> Int64) <$> rfd_
-- cryptoArgs = Nothing here, the decision to encrypt is made when receiving it
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId = Nothing, agentRcvFileDeleted = False}) <$> rfd_
fileProtocol = if isJust rfd_ then FPXFTP else FPSMP
@@ -511,7 +508,7 @@ createRcvGroupFileTransfer :: DB.Connection -> UserId -> GroupMember -> FileInvi
createRcvGroupFileTransfer db userId GroupMember {groupId, groupMemberId, localDisplayName = c} f@FileInvitation {fileName, fileSize, fileConnReq, fileInline, fileDescr} rcvFileInline chunkSize = do
currentTs <- liftIO getCurrentTime
rfd_ <- mapM (createRcvFD_ db userId currentTs) fileDescr
let rfdId = (\RcvFileDescr {fileDescrId} -> fileDescrId) <$> rfd_
let rfdId = (fileDescrId :: RcvFileDescr -> Int64) <$> rfd_
-- cryptoArgs = Nothing here, the decision to encrypt is made when receiving it
xftpRcvFile = (\rfd -> XFTPRcvFile {rcvFileDescription = rfd, agentRcvFileId = Nothing, agentRcvFileDeleted = False}) <$> rfd_
fileProtocol = if isJust rfd_ then FPXFTP else FPSMP
@@ -906,7 +903,7 @@ getLocalCryptoFile db userId fileId sent =
_ -> do
unless sent $ throwError $ SEFileNotFound fileId
FileTransferMeta {filePath, xftpSndFile} <- getFileTransferMeta_ db userId fileId
pure $ CryptoFile filePath $ xftpSndFile >>= \f -> f.cryptoArgs
pure $ CryptoFile filePath $ xftpSndFile >>= \XFTPSndFile {cryptoArgs} -> cryptoArgs
updateDirectCIFileStatus :: forall d. MsgDirectionI d => DB.Connection -> User -> Int64 -> CIFileStatus d -> ExceptT StoreError IO AChatItem
updateDirectCIFileStatus db user fileId fileStatus = do

View File

@@ -8,9 +8,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Store.Groups
( -- * Util methods
@@ -115,9 +112,7 @@ module Simplex.Chat.Store.Groups
)
where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import Crypto.Random (ChaChaDRG)
import Data.Either (rights)
import Data.Int (Int64)
@@ -359,7 +354,7 @@ createGroupInvitation db user@User {userId} contact@Contact {contactId, activeCo
"INSERT INTO groups (group_profile_id, local_display_name, inv_queue_info, host_conn_custom_user_profile_id, user_id, enable_ntfs, created_at, updated_at, chat_ts) VALUES (?,?,?,?,?,?,?,?,?)"
(profileId, localDisplayName, connRequest, customUserProfileId, userId, True, currentTs, currentTs, currentTs)
insertedRowId db
let JVersionRange hostVRange = hostConn.peerChatVRange
let JVersionRange hostVRange = peerChatVRange hostConn
GroupMember {groupMemberId} <- createContactMemberInv_ db user groupId Nothing contact fromMember GCHostMember GSMemInvited IBUnknown Nothing currentTs hostVRange
membership <- createContactMemberInv_ db user groupId (Just groupMemberId) user invitedMember GCUserMember GSMemInvited (IBContact contactId) incognitoProfileId currentTs supportedChatVRange
let chatSettings = ChatSettings {enableNtfs = MFAll, sendRcpts = Nothing, favorite = False}
@@ -1055,7 +1050,7 @@ saveIntroInvitation db reMember toMember introInv = do
WHERE group_member_intro_id = :intro_id
|]
[ ":intro_status" := GMIntroInvReceived,
":group_queue_info" := introInv.groupConnReq,
":group_queue_info" := groupConnReq (introInv :: IntroInvitation),
":direct_queue_info" := directConnReq introInv,
":updated_at" := currentTs,
":intro_id" := introId intro
@@ -1163,7 +1158,7 @@ createIntroReMember db user@User {userId} gInfo@GroupInfo {groupId} _host@GroupM
createIntroToMemberContact :: DB.Connection -> User -> GroupMember -> GroupMember -> VersionRange -> (CommandId, ConnId) -> Maybe (CommandId, ConnId) -> Maybe ProfileId -> SubscriptionMode -> IO ()
createIntroToMemberContact db user@User {userId} GroupMember {memberContactId = viaContactId, activeConn} _to@GroupMember {groupMemberId, localDisplayName} mcvr (groupCmdId, groupAgentConnId) directConnIds customUserProfileId subMode = do
let cLevel = 1 + maybe 0 (\Connection {connLevel} -> connLevel) activeConn
let cLevel = 1 + maybe 0 (connLevel :: Connection -> Int) activeConn
currentTs <- getCurrentTime
Connection {connId = groupConnId} <- createMemberConnection_ db userId groupMemberId groupAgentConnId mcvr viaContactId cLevel currentTs subMode
setCommandConnId db user groupCmdId groupConnId

View File

@@ -11,8 +11,6 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Store.Messages
( getContactConnIds_,
@@ -102,9 +100,7 @@ module Simplex.Chat.Store.Messages
)
where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import Crypto.Random (ChaChaDRG)
import Data.Bifunctor (first)
import Data.ByteString.Char8 (ByteString)

View File

@@ -9,8 +9,6 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module Simplex.Chat.Store.Profiles
( AutoAccept (..),
UserMsgReceiptSettings (..),
@@ -60,7 +58,6 @@ module Simplex.Chat.Store.Profiles
)
where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import qualified Data.Aeson.TH as J
@@ -297,7 +294,7 @@ getUserContactProfiles db User {userId} =
|]
(Only userId)
where
toContactProfile :: (ContactName, Text, Maybe ImageData, Maybe ConnReqContact, Maybe Preferences) -> Profile
toContactProfile :: (ContactName, Text, Maybe ImageData, Maybe ConnReqContact, Maybe Preferences) -> (Profile)
toContactProfile (displayName, fullName, image, contactLink, preferences) = Profile {displayName, fullName, image, contactLink, preferences}
createUserContactLink :: DB.Connection -> User -> ConnId -> ConnReqContact -> SubscriptionMode -> ExceptT StoreError IO ()

View File

@@ -12,9 +12,7 @@ module Simplex.Chat.Store.Shared where
import Control.Exception (Exception)
import qualified Control.Exception as E
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import Crypto.Random (ChaChaDRG, randomBytesGenerate)
import qualified Data.Aeson.TH as J
import qualified Data.ByteString.Base64 as B64

View File

@@ -5,7 +5,7 @@
module Simplex.Chat.Terminal where
import Control.Exception (handle, throwIO)
import Control.Monad
import Control.Monad.Except
import qualified Data.List.NonEmpty as L
import Database.SQLite.Simple (SQLError (..))
import qualified Database.SQLite.Simple as DB

View File

@@ -12,7 +12,6 @@ module Simplex.Chat.Terminal.Input where
import Control.Applicative (optional, (<|>))
import Control.Concurrent (forkFinally, forkIO, killThread, mkWeakThreadId, threadDelay)
import Control.Monad
import Control.Monad.Except
import Control.Monad.Reader
import qualified Data.Attoparsec.ByteString.Char8 as A

View File

@@ -9,7 +9,6 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -17,7 +16,6 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Use newtype instead of data" #-}
@@ -62,21 +60,21 @@ class IsContact a where
preferences' :: a -> Maybe Preferences
instance IsContact User where
contactId' u = u.userContactId
contactId' = userContactId
{-# INLINE contactId' #-}
profile' u = u.profile
profile' = profile
{-# INLINE profile' #-}
localDisplayName' u = u.localDisplayName
localDisplayName' = localDisplayName
{-# INLINE localDisplayName' #-}
preferences' User {profile = LocalProfile {preferences}} = preferences
{-# INLINE preferences' #-}
instance IsContact Contact where
contactId' c = c.contactId
contactId' = contactId
{-# INLINE contactId' #-}
profile' c = c.profile
profile' = profile
{-# INLINE profile' #-}
localDisplayName' c = c.localDisplayName
localDisplayName' = localDisplayName
{-# INLINE localDisplayName' #-}
preferences' Contact {profile = LocalProfile {preferences}} = preferences
{-# INLINE preferences' #-}
@@ -196,7 +194,7 @@ directOrUsed ct@Contact {contactUsed} =
contactDirect ct || contactUsed
anyDirectOrUsed :: Contact -> Bool
anyDirectOrUsed Contact {contactUsed, activeConn} = ((\c -> c.connLevel) <$> activeConn) == Just 0 || contactUsed
anyDirectOrUsed Contact {contactUsed, activeConn} = ((\Connection {connLevel} -> connLevel) <$> activeConn) == Just 0 || contactUsed
contactReady :: Contact -> Bool
contactReady Contact {activeConn} = maybe False connReady activeConn
@@ -498,7 +496,7 @@ data LocalProfile = LocalProfile
deriving (Eq, Show)
localProfileId :: LocalProfile -> ProfileId
localProfileId LocalProfile{profileId} = profileId
localProfileId = profileId
toLocalProfile :: ProfileId -> Profile -> LocalAlias -> LocalProfile
toLocalProfile profileId Profile {displayName, fullName, image, contactLink, preferences} localAlias =

View File

@@ -7,16 +7,13 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
{-# HLINT ignore "Use newtype instead of data" #-}
@@ -80,12 +77,12 @@ allChatFeatures =
]
chatPrefSel :: SChatFeature f -> Preferences -> Maybe (FeaturePreference f)
chatPrefSel f ps = case f of
SCFTimedMessages -> ps.timedMessages
SCFFullDelete -> ps.fullDelete
SCFReactions -> ps.reactions
SCFVoice -> ps.voice
SCFCalls -> ps.calls
chatPrefSel = \case
SCFTimedMessages -> timedMessages
SCFFullDelete -> fullDelete
SCFReactions -> reactions
SCFVoice -> voice
SCFCalls -> calls
chatFeature :: SChatFeature f -> ChatFeature
chatFeature = \case
@@ -105,12 +102,12 @@ instance PreferenceI (Maybe Preferences) where
getPreference f prefs = fromMaybe (getPreference f defaultChatPrefs) (chatPrefSel f =<< prefs)
instance PreferenceI FullPreferences where
getPreference f ps = case f of
SCFTimedMessages -> ps.timedMessages
SCFFullDelete -> ps.fullDelete
SCFReactions -> ps.reactions
SCFVoice -> ps.voice
SCFCalls -> ps.calls
getPreference = \case
SCFTimedMessages -> timedMessages
SCFFullDelete -> fullDelete
SCFReactions -> reactions
SCFVoice -> voice
SCFCalls -> calls
{-# INLINE getPreference #-}
setPreference :: forall f. FeatureI f => SChatFeature f -> Maybe FeatureAllowed -> Maybe Preferences -> Preferences
@@ -193,13 +190,13 @@ allGroupFeatures =
]
groupPrefSel :: SGroupFeature f -> GroupPreferences -> Maybe (GroupFeaturePreference f)
groupPrefSel f ps = case f of
SGFTimedMessages -> ps.timedMessages
SGFDirectMessages -> ps.directMessages
SGFFullDelete -> ps.fullDelete
SGFReactions -> ps.reactions
SGFVoice -> ps.voice
SGFFiles -> ps.files
groupPrefSel = \case
SGFTimedMessages -> timedMessages
SGFDirectMessages -> directMessages
SGFFullDelete -> fullDelete
SGFReactions -> reactions
SGFVoice -> voice
SGFFiles -> files
toGroupFeature :: SGroupFeature f -> GroupFeature
toGroupFeature = \case
@@ -220,13 +217,13 @@ instance GroupPreferenceI (Maybe GroupPreferences) where
getGroupPreference pt prefs = fromMaybe (getGroupPreference pt defaultGroupPrefs) (groupPrefSel pt =<< prefs)
instance GroupPreferenceI FullGroupPreferences where
getGroupPreference f ps = case f of
SGFTimedMessages -> ps.timedMessages
SGFDirectMessages -> ps.directMessages
SGFFullDelete -> ps.fullDelete
SGFReactions -> ps.reactions
SGFVoice -> ps.voice
SGFFiles -> ps.files
getGroupPreference = \case
SGFTimedMessages -> timedMessages
SGFDirectMessages -> directMessages
SGFFullDelete -> fullDelete
SGFReactions -> reactions
SGFVoice -> voice
SGFFiles -> files
{-# INLINE getGroupPreference #-}
-- collection of optional group preferences
@@ -372,19 +369,19 @@ class (Eq (FeaturePreference f), HasField "allow" (FeaturePreference f) FeatureA
prefParam :: FeaturePreference f -> Maybe Int
instance HasField "allow" TimedMessagesPreference FeatureAllowed where
hasField p = (\allow -> p {allow}, p.allow)
hasField p = (\allow -> p {allow}, allow (p :: TimedMessagesPreference))
instance HasField "allow" FullDeletePreference FeatureAllowed where
hasField p = (\allow -> p {allow}, p.allow)
hasField p = (\allow -> p {allow}, allow (p :: FullDeletePreference))
instance HasField "allow" ReactionsPreference FeatureAllowed where
hasField p = (\allow -> p {allow}, p.allow)
hasField p = (\allow -> p {allow}, allow (p :: ReactionsPreference))
instance HasField "allow" VoicePreference FeatureAllowed where
hasField p = (\allow -> p {allow}, p.allow)
hasField p = (\allow -> p {allow}, allow (p :: VoicePreference))
instance HasField "allow" CallsPreference FeatureAllowed where
hasField p = (\allow -> p {allow}, p.allow)
hasField p = (\allow -> p {allow}, allow (p :: CallsPreference))
instance FeatureI 'CFTimedMessages where
type FeaturePreference 'CFTimedMessages = TimedMessagesPreference
@@ -447,25 +444,25 @@ class (Eq (GroupFeaturePreference f), HasField "enable" (GroupFeaturePreference
groupPrefParam :: GroupFeaturePreference f -> Maybe Int
instance HasField "enable" GroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: GroupPreference))
instance HasField "enable" TimedMessagesGroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: TimedMessagesGroupPreference))
instance HasField "enable" DirectMessagesGroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: DirectMessagesGroupPreference))
instance HasField "enable" ReactionsGroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: ReactionsGroupPreference))
instance HasField "enable" FullDeleteGroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: FullDeleteGroupPreference))
instance HasField "enable" VoiceGroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: VoiceGroupPreference))
instance HasField "enable" FilesGroupPreference GroupFeatureEnabled where
hasField p = (\enable -> p {enable}, p.enable)
hasField p = (\enable -> p {enable}, enable (p :: FilesGroupPreference))
instance GroupFeatureI 'GFTimedMessages where
type GroupFeaturePreference 'GFTimedMessages = TimedMessagesGroupPreference
@@ -696,12 +693,12 @@ preferenceState pref =
in (allow, param)
getContactUserPreference :: SChatFeature f -> ContactUserPreferences -> ContactUserPreference (FeaturePreference f)
getContactUserPreference f ps = case f of
SCFTimedMessages -> ps.timedMessages
SCFFullDelete -> ps.fullDelete
SCFReactions -> ps.reactions
SCFVoice -> ps.voice
SCFCalls -> ps.calls
getContactUserPreference = \case
SCFTimedMessages -> timedMessages
SCFFullDelete -> fullDelete
SCFReactions -> reactions
SCFVoice -> voice
SCFCalls -> calls
$(J.deriveJSON (enumJSON $ dropPrefix "CF") ''ChatFeature)

View File

@@ -2,7 +2,6 @@ module Simplex.Chat.Util (week, encryptFile, chunkSize) where
import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class
import qualified Data.ByteString.Lazy as LB
import Data.Time (NominalDiffTime)
import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..))

View File

@@ -3,7 +3,6 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -211,7 +210,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
CRContactConnecting u _ -> ttyUser u []
CRContactConnected u ct userCustomProfile -> ttyUser u $ viewContactConnected ct userCustomProfile testView
CRContactAnotherClient u c -> ttyUser u [ttyContact' c <> ": contact is connected to another client"]
CRSubscriptionEnd u acEntity -> ttyUser u [sShow ((entityConnection acEntity).connId) <> ": END"]
CRSubscriptionEnd u acEntity -> ttyUser u [sShow (connId (entityConnection acEntity :: Connection)) <> ": END"]
CRContactsDisconnected srv cs -> [plain $ "server disconnected " <> showSMPServer srv <> " (" <> contactList cs <> ")"]
CRContactsSubscribed srv cs -> [plain $ "server connected " <> showSMPServer srv <> " (" <> contactList cs <> ")"]
CRContactSubError u c e -> ttyUser u [ttyContact' c <> ": contact error " <> sShow e]
@@ -490,7 +489,7 @@ viewGroupSubscribed :: GroupInfo -> [StyledString]
viewGroupSubscribed g = [membershipIncognito g <> ttyFullGroup g <> ": connected to server(s)"]
showSMPServer :: SMPServer -> String
showSMPServer srv = B.unpack $ strEncode srv.host
showSMPServer ProtocolServer {host} = B.unpack $ strEncode host
viewHostEvent :: AProtocolType -> TransportHost -> String
viewHostEvent p h = map toUpper (B.unpack $ strEncode p) <> " host " <> B.unpack (strEncode h)
@@ -787,9 +786,7 @@ viewChatCleared (AChatInfo _ chatInfo) = case chatInfo of
viewContactsList :: [Contact] -> [StyledString]
viewContactsList =
let getLDN :: Contact -> ContactName
getLDN Contact{localDisplayName} = localDisplayName
ldn = T.toLower . getLDN
let ldn = T.toLower . (localDisplayName :: Contact -> ContactName)
in map (\ct -> ctIncognito ct <> ttyFullContact ct <> muted' ct <> alias ct) . sortOn ldn
where
muted' Contact {chatSettings, localDisplayName = ldn}
@@ -948,7 +945,7 @@ viewGroupMembers (Group GroupInfo {membership} members) = map groupMember . filt
removedOrLeft m = let s = memberStatus m in s == GSMemRemoved || s == GSMemLeft
groupMember m = memIncognito m <> ttyFullMember m <> ": " <> plain (intercalate ", " $ [role m] <> category m <> status m <> muted m)
role :: GroupMember -> String
role m = B.unpack . strEncode $ m.memberRole
role m = B.unpack . strEncode $ memberRole (m :: GroupMember)
category m = case memberCategory m of
GCUserMember -> ["you"]
GCInviteeMember -> ["invited"]
@@ -986,7 +983,7 @@ viewGroupsList [] = ["you have no groups!", "to create: " <> highlight' "/g <nam
viewGroupsList gs = map groupSS $ sortOn (ldn_ . fst) gs
where
ldn_ :: GroupInfo -> Text
ldn_ g = T.toLower g.localDisplayName
ldn_ = T.toLower . (localDisplayName :: GroupInfo -> GroupName)
groupSS (g@GroupInfo {membership, chatSettings = ChatSettings {enableNtfs}}, GroupSummary {currentMembers}) =
case memberStatus membership of
GSMemInvited -> groupInvitation' g
@@ -1590,8 +1587,7 @@ viewFileTransferStatus (FTSnd FileTransferMeta {cancelled} fts@(ft : _), chunksN
case concatMap recipientsTransferStatus $ groupBy ((==) `on` fs) $ sortOn fs fts of
[recipientsStatus] -> ["sending " <> sndFile ft <> " " <> recipientsStatus]
recipientsStatuses -> ("sending " <> sndFile ft <> ": ") : map (" " <>) recipientsStatuses
fs :: SndFileTransfer -> FileStatus
fs SndFileTransfer{fileStatus} = fileStatus
fs = fileStatus :: SndFileTransfer -> FileStatus
recipientsTransferStatus [] = []
recipientsTransferStatus ts@(SndFileTransfer {fileStatus, fileSize, chunkSize} : _) = [sndStatus <> ": " <> listRecipients ts]
where
@@ -1894,7 +1890,7 @@ viewChatError logLevel testView = \case
"[" <> connEntityLabel entity <> ", userContactLinkId: " <> sShow userContactLinkId <> ", connId: " <> cId conn <> "] "
Nothing -> ""
cId :: Connection -> StyledString
cId conn = sShow conn.connId
cId conn = sShow (connId (conn :: Connection))
ChatErrorRemoteCtrl e -> [plain $ "remote controller error: " <> show e]
ChatErrorRemoteHost RHNew e -> [plain $ "new remote host error: " <> show e]
ChatErrorRemoteHost (RHId rhId) e -> [plain $ "remote host " <> show rhId <> " error: " <> show e]

View File

@@ -49,24 +49,20 @@ extra-deps:
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
# - ../simplexmq
- github: simplex-chat/simplexmq
commit: 757b7eec81341d8560a326deab303bb6fb6a26a3
commit: 281bdebcb82aed4c8c2c08438b9cafc7908183a1
- github: kazu-yamamoto/http2
commit: f5525b755ff2418e6e6ecc69e877363b0d0bcaeb
# - ../direct-sqlcipher
- github: simplex-chat/direct-sqlcipher
commit: f814ee68b16a9447fbb467ccc8f29bdd3546bfd9
commit: 34309410eb2069b029b8fc1872deb1e0db123294
# - ../sqlcipher-simple
- github: simplex-chat/sqlcipher-simple
commit: a46bd361a19376c5211f1058908fc0ae6bf42446
commit: 5e154a2aeccc33ead6c243ec07195ab673137221
# - terminal-0.2.0.0@sha256:de6770ecaae3197c66ac1f0db5a80cf5a5b1d3b64a66a05b50f442de5ad39570,2977
- github: simplex-chat/aeson
commit: aab7b5a14d6c5ea64c64dcaee418de1bb00dcc2b
- github: simplex-chat/haskell-terminal
commit: f708b00009b54890172068f168bf98508ffcd495
- github: simplex-chat/android-support
commit: 9aa09f148089d6752ce563b14c2df1895718d806
- github: simplex-chat/network-transport
commit: 0013798272a683e35ca38d2fdaf480942311fba8
#
# extra-deps: []

View File

@@ -1,6 +1,5 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
module Bots.BroadcastTests where
@@ -34,7 +33,7 @@ broadcastBotProfile = Profile {displayName = "broadcast_bot", fullName = "Broadc
mkBotOpts :: FilePath -> [KnownContact] -> BroadcastBotOpts
mkBotOpts tmp publishers =
BroadcastBotOpts
{ coreOptions = testOpts.coreOptions {dbFilePrefix = tmp </> botDbPrefix},
{ coreOptions = (coreOptions (testOpts :: ChatOpts)) {dbFilePrefix = tmp </> botDbPrefix},
publishers,
welcomeMessage = defaultWelcomeMessage publishers,
prohibitedMessage = defaultWelcomeMessage publishers

View File

@@ -1,6 +1,5 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PostfixOperators #-}
@@ -63,7 +62,7 @@ directoryProfile = Profile {displayName = "SimpleX-Directory", fullName = "", im
mkDirectoryOpts :: FilePath -> [KnownContact] -> DirectoryOpts
mkDirectoryOpts tmp superUsers =
DirectoryOpts
{ coreOptions = testOpts.coreOptions {dbFilePrefix = tmp </> serviceDbPrefix},
{ coreOptions = (coreOptions (testOpts :: ChatOpts)) {dbFilePrefix = tmp </> serviceDbPrefix},
superUsers,
directoryLog = Just $ tmp </> "directory_service.log",
serviceName = "SimpleX-Directory",

View File

@@ -6,15 +6,12 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module ChatClient where
import Control.Concurrent (forkIOWithUnmask, killThread, threadDelay)
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Exception (bracket, bracket_)
import Control.Monad
import Control.Monad.Except
import Data.Functor (($>))
import Data.List (dropWhileEnd, find)

View File

@@ -2,8 +2,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PostfixOperators #-}
{-# OPTIONS_GHC -fno-warn-ambiguous-fields #-}
module ChatTests.Files where
import ChatClient

View File

@@ -1,15 +0,0 @@
<p><strong>v5.4 is released:</strong></p>
<ul class="mb-[12px]">
<li>Link mobile and desktop apps via secure quantum-resistant protocol. 🔗</li>
<li><p>Better groups:</p>
<ul>
<li>faster to join and more reliable.</li>
<li>create groups with incognito profile.</li>
<li>block group members to reduce noise.</li>
<li>prohibit files and media in a group.</li>
</ul>
</li>
<li>Better calls: faster to connect, with screen sharing on desktop.</li>
<li>Many other improvements.</li>
</ul>