mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c418e91970 |
+1
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
|||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/simplex-chat/simplexmq.git
|
location: https://github.com/simplex-chat/simplexmq.git
|
||||||
tag: 56986f82c89b04beae84a61208db8b55eb0098e3
|
tag: f940ce234ebc3831c3bbedb3fc653907cdb7a064
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"https://github.com/simplex-chat/simplexmq.git"."56986f82c89b04beae84a61208db8b55eb0098e3" = "0vqvdnm560xrfq7kjsghdbpk67vn4hcdpp58dfqgh9l2c9f79bin";
|
"https://github.com/simplex-chat/simplexmq.git"."f940ce234ebc3831c3bbedb3fc653907cdb7a064" = "16y4ix3v7sd8qd1qfrxk0nshvh0p1a415y2sw5am2jhx0mjr8w1q";
|
||||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
"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/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||||
|
|||||||
+9
-8
@@ -40,6 +40,7 @@ import Data.Either (fromRight, lefts, partitionEithers, rights)
|
|||||||
import Data.Fixed (div')
|
import Data.Fixed (div')
|
||||||
import Data.Functor (($>))
|
import Data.Functor (($>))
|
||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
|
import Data.IORef (IORef)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.List (find, foldl', isSuffixOf, mapAccumL, partition, sortOn)
|
import Data.List (find, foldl', isSuffixOf, mapAccumL, partition, sortOn)
|
||||||
import Data.List.NonEmpty (NonEmpty (..), nonEmpty, toList, (<|))
|
import Data.List.NonEmpty (NonEmpty (..), nonEmpty, toList, (<|))
|
||||||
@@ -1057,7 +1058,7 @@ processChatCommand' vr = \case
|
|||||||
fsNewPath <- liftIO $ filesFolder `uniqueCombine` fileName
|
fsNewPath <- liftIO $ filesFolder `uniqueCombine` fileName
|
||||||
liftIO $ B.writeFile fsNewPath "" -- create empty file
|
liftIO $ B.writeFile fsNewPath "" -- create empty file
|
||||||
encrypt <- chatReadVar encryptLocalFiles
|
encrypt <- chatReadVar encryptLocalFiles
|
||||||
cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing
|
cfArgs <- if encrypt then Just <$> (liftIO . CF.randomArgs =<< asks random) else pure Nothing
|
||||||
let toCF = CryptoFile fsNewPath cfArgs
|
let toCF = CryptoFile fsNewPath cfArgs
|
||||||
-- to keep forwarded file in case original is deleted
|
-- to keep forwarded file in case original is deleted
|
||||||
liftIOEither $ runExceptT $ withExceptT (ChatError . CEInternalError . show) $ copyCryptoFile (fromCF {filePath = fsFromPath} :: CryptoFile) toCF
|
liftIOEither $ runExceptT $ withExceptT (ChatError . CEInternalError . show) $ copyCryptoFile (fromCF {filePath = fsFromPath} :: CryptoFile) toCF
|
||||||
@@ -1264,9 +1265,9 @@ processChatCommand' vr = \case
|
|||||||
calls <- asks currentCalls
|
calls <- asks currentCalls
|
||||||
withContactLock "sendCallInvitation" contactId $ do
|
withContactLock "sendCallInvitation" contactId $ do
|
||||||
g <- asks random
|
g <- asks random
|
||||||
callId <- atomically $ CallId <$> C.randomBytes 16 g
|
callId <- liftIO $ CallId <$> C.randomBytes 16 g
|
||||||
callUUID <- UUID.toText <$> liftIO V4.nextRandom
|
callUUID <- UUID.toText <$> liftIO V4.nextRandom
|
||||||
dhKeyPair <- atomically $ if encryptedCall callType then Just <$> C.generateKeyPair g else pure Nothing
|
dhKeyPair <- liftIO $ if encryptedCall callType then Just <$> C.generateKeyPair g else pure Nothing
|
||||||
let invitation = CallInvitation {callType, callDhPubKey = fst <$> dhKeyPair}
|
let invitation = CallInvitation {callType, callDhPubKey = fst <$> dhKeyPair}
|
||||||
callState = CallInvitationSent {localCallType = callType, localDhPrivKey = snd <$> dhKeyPair}
|
callState = CallInvitationSent {localCallType = callType, localDhPrivKey = snd <$> dhKeyPair}
|
||||||
(msg, _) <- sendDirectContactMessage user ct (XCallInv callId invitation)
|
(msg, _) <- sendDirectContactMessage user ct (XCallInv callId invitation)
|
||||||
@@ -2234,7 +2235,7 @@ processChatCommand' vr = \case
|
|||||||
SetFileToReceive fileId userApprovedRelays encrypted_ -> withUser $ \_ -> do
|
SetFileToReceive fileId userApprovedRelays encrypted_ -> withUser $ \_ -> do
|
||||||
withFileLock "setFileToReceive" fileId . procCmd $ do
|
withFileLock "setFileToReceive" fileId . procCmd $ do
|
||||||
encrypt <- (`fromMaybe` encrypted_) <$> chatReadVar encryptLocalFiles
|
encrypt <- (`fromMaybe` encrypted_) <$> chatReadVar encryptLocalFiles
|
||||||
cfArgs <- if encrypt then Just <$> (atomically . CF.randomArgs =<< asks random) else pure Nothing
|
cfArgs <- if encrypt then Just <$> (liftIO . CF.randomArgs =<< asks random) else pure Nothing
|
||||||
withStore' $ \db -> setRcvFileToReceive db fileId userApprovedRelays cfArgs
|
withStore' $ \db -> setRcvFileToReceive db fileId userApprovedRelays cfArgs
|
||||||
ok_
|
ok_
|
||||||
CancelFile fileId -> withUser $ \user@User {userId} ->
|
CancelFile fileId -> withUser $ \user@User {userId} ->
|
||||||
@@ -2719,7 +2720,7 @@ processChatCommand' vr = \case
|
|||||||
forM_ (timed_ >>= timedDeleteAt') $
|
forM_ (timed_ >>= timedDeleteAt') $
|
||||||
startProximateTimedItemThread user (ChatRef CTDirect contactId, chatItemId' ci)
|
startProximateTimedItemThread user (ChatRef CTDirect contactId, chatItemId' ci)
|
||||||
drgRandomBytes :: Int -> CM ByteString
|
drgRandomBytes :: Int -> CM ByteString
|
||||||
drgRandomBytes n = asks random >>= atomically . C.randomBytes n
|
drgRandomBytes n = asks random >>= liftIO . C.randomBytes n
|
||||||
privateGetUser :: UserId -> CM User
|
privateGetUser :: UserId -> CM User
|
||||||
privateGetUser userId =
|
privateGetUser userId =
|
||||||
tryChatError (withStore (`getUser` userId)) >>= \case
|
tryChatError (withStore (`getUser` userId)) >>= \case
|
||||||
@@ -3244,7 +3245,7 @@ toFSFilePath f =
|
|||||||
|
|
||||||
setFileToEncrypt :: RcvFileTransfer -> CM RcvFileTransfer
|
setFileToEncrypt :: RcvFileTransfer -> CM RcvFileTransfer
|
||||||
setFileToEncrypt ft@RcvFileTransfer {fileId} = do
|
setFileToEncrypt ft@RcvFileTransfer {fileId} = do
|
||||||
cfArgs <- atomically . CF.randomArgs =<< asks random
|
cfArgs <- liftIO . CF.randomArgs =<< asks random
|
||||||
withStore' $ \db -> setFileCryptoArgs db fileId cfArgs
|
withStore' $ \db -> setFileCryptoArgs db fileId cfArgs
|
||||||
pure (ft :: RcvFileTransfer) {cryptoArgs = Just cfArgs}
|
pure (ft :: RcvFileTransfer) {cryptoArgs = Just cfArgs}
|
||||||
|
|
||||||
@@ -5956,7 +5957,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
|||||||
if featureAllowed SCFCalls forContact ct
|
if featureAllowed SCFCalls forContact ct
|
||||||
then do
|
then do
|
||||||
g <- asks random
|
g <- asks random
|
||||||
dhKeyPair <- atomically $ if encryptedCall callType then Just <$> C.generateKeyPair g else pure Nothing
|
dhKeyPair <- liftIO $ if encryptedCall callType then Just <$> C.generateKeyPair g else pure Nothing
|
||||||
ci <- saveCallItem CISCallPending
|
ci <- saveCallItem CISCallPending
|
||||||
callUUID <- UUID.toText <$> liftIO V4.nextRandom
|
callUUID <- UUID.toText <$> liftIO V4.nextRandom
|
||||||
let sharedKey = C.Key . C.dhBytes' <$> (C.dh' <$> callDhPubKey <*> (snd <$> dhKeyPair))
|
let sharedKey = C.Key . C.dhBytes' <$> (C.dh' <$> callDhPubKey <*> (snd <$> dhKeyPair))
|
||||||
@@ -6875,7 +6876,7 @@ createSndMessages idsEvents = do
|
|||||||
vr <- chatVersionRange'
|
vr <- chatVersionRange'
|
||||||
withStoreBatch $ \db -> fmap (createMsg db g vr) idsEvents
|
withStoreBatch $ \db -> fmap (createMsg db g vr) idsEvents
|
||||||
where
|
where
|
||||||
createMsg :: DB.Connection -> TVar ChaChaDRG -> VersionRangeChat -> (ConnOrGroupId, ChatMsgEvent e) -> IO (Either ChatError SndMessage)
|
createMsg :: DB.Connection -> IORef ChaChaDRG -> VersionRangeChat -> (ConnOrGroupId, ChatMsgEvent e) -> IO (Either ChatError SndMessage)
|
||||||
createMsg db g vr (connOrGroupId, evnt) = runExceptT $ do
|
createMsg db g vr (connOrGroupId, evnt) = runExceptT $ do
|
||||||
withExceptT ChatErrorStore $ createNewSndMessage db g connOrGroupId evnt encodeMessage
|
withExceptT ChatErrorStore $ createNewSndMessage db g connOrGroupId evnt encodeMessage
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import Data.ByteString.Char8 (ByteString)
|
|||||||
import qualified Data.ByteString.Char8 as B
|
import qualified Data.ByteString.Char8 as B
|
||||||
import Data.Char (ord)
|
import Data.Char (ord)
|
||||||
import Data.Constraint (Dict (..))
|
import Data.Constraint (Dict (..))
|
||||||
|
import Data.IORef (IORef)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.List.NonEmpty (NonEmpty)
|
import Data.List.NonEmpty (NonEmpty)
|
||||||
import Data.Map.Strict (Map)
|
import Data.Map.Strict (Map)
|
||||||
@@ -209,7 +210,7 @@ data ChatController = ChatController
|
|||||||
agentAsync :: TVar (Maybe (Async (), Maybe (Async ()))),
|
agentAsync :: TVar (Maybe (Async (), Maybe (Async ()))),
|
||||||
chatStore :: SQLiteStore,
|
chatStore :: SQLiteStore,
|
||||||
chatStoreChanged :: TVar Bool, -- if True, chat should be fully restarted
|
chatStoreChanged :: TVar Bool, -- if True, chat should be fully restarted
|
||||||
random :: TVar ChaChaDRG,
|
random :: IORef ChaChaDRG,
|
||||||
eventSeq :: TVar Int,
|
eventSeq :: TVar Int,
|
||||||
inputQ :: TBQueue String,
|
inputQ :: TBQueue String,
|
||||||
outputQ :: TBQueue (Maybe CorrId, Maybe RemoteHostId, ChatResponse),
|
outputQ :: TBQueue (Maybe CorrId, Maybe RemoteHostId, ChatResponse),
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import qualified Simplex.Messaging.Crypto.File as CF
|
|||||||
import Simplex.Messaging.Encoding.String
|
import Simplex.Messaging.Encoding.String
|
||||||
import Simplex.Messaging.Parsers (dropPrefix, sumTypeJSON)
|
import Simplex.Messaging.Parsers (dropPrefix, sumTypeJSON)
|
||||||
import Simplex.Messaging.Util (catchAll)
|
import Simplex.Messaging.Util (catchAll)
|
||||||
import UnliftIO (Handle, IOMode (..), atomically, withFile)
|
import UnliftIO (Handle, IOMode (..), withFile)
|
||||||
|
|
||||||
data WriteFileResult
|
data WriteFileResult
|
||||||
= WFResult {cryptoArgs :: CryptoFileArgs}
|
= WFResult {cryptoArgs :: CryptoFileArgs}
|
||||||
@@ -60,7 +60,7 @@ cChatWriteFile cc cPath ptr len = do
|
|||||||
|
|
||||||
chatWriteFile :: ChatController -> FilePath -> ByteString -> IO WriteFileResult
|
chatWriteFile :: ChatController -> FilePath -> ByteString -> IO WriteFileResult
|
||||||
chatWriteFile ChatController {random} path s = do
|
chatWriteFile ChatController {random} path s = do
|
||||||
cfArgs <- atomically $ CF.randomArgs random
|
cfArgs <- CF.randomArgs random
|
||||||
let file = CryptoFile path $ Just cfArgs
|
let file = CryptoFile path $ Just cfArgs
|
||||||
either WFError (\_ -> WFResult cfArgs)
|
either WFError (\_ -> WFResult cfArgs)
|
||||||
<$> runCatchExceptT (withExceptT show $ CF.writeFile file $ LB.fromStrict s)
|
<$> runCatchExceptT (withExceptT show $ CF.writeFile file $ LB.fromStrict s)
|
||||||
@@ -104,7 +104,7 @@ chatEncryptFile ChatController {random} fromPath toPath =
|
|||||||
either WFError WFResult <$> runCatchExceptT encrypt
|
either WFError WFResult <$> runCatchExceptT encrypt
|
||||||
where
|
where
|
||||||
encrypt = do
|
encrypt = do
|
||||||
cfArgs <- atomically $ CF.randomArgs random
|
cfArgs <- liftIO $ CF.randomArgs random
|
||||||
encryptFile fromPath toPath cfArgs
|
encryptFile fromPath toPath cfArgs
|
||||||
pure cfArgs
|
pure cfArgs
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import Foreign.StablePtr
|
|||||||
import Simplex.Chat.Controller (ChatController (..))
|
import Simplex.Chat.Controller (ChatController (..))
|
||||||
import Simplex.Chat.Mobile.Shared
|
import Simplex.Chat.Mobile.Shared
|
||||||
import qualified Simplex.Messaging.Crypto as C
|
import qualified Simplex.Messaging.Crypto as C
|
||||||
import UnliftIO (atomically)
|
|
||||||
|
|
||||||
cChatEncryptMedia :: StablePtr ChatController -> CString -> Ptr Word8 -> CInt -> IO CString
|
cChatEncryptMedia :: StablePtr ChatController -> CString -> Ptr Word8 -> CInt -> IO CString
|
||||||
cChatEncryptMedia = cTransformMedia . chatEncryptMedia
|
cChatEncryptMedia = cTransformMedia . chatEncryptMedia
|
||||||
@@ -48,7 +47,7 @@ chatEncryptMedia cc keyStr frame = do
|
|||||||
ChatController {random} <- liftIO $ deRefStablePtr cc
|
ChatController {random} <- liftIO $ deRefStablePtr cc
|
||||||
len <- checkFrameLen frame
|
len <- checkFrameLen frame
|
||||||
key <- decodeKey keyStr
|
key <- decodeKey keyStr
|
||||||
iv <- atomically $ C.randomGCMIV random
|
iv <- liftIO $ C.randomGCMIV random
|
||||||
(tag, frame') <- withExceptT show $ C.encryptAESNoPad key iv $ B.take len frame
|
(tag, frame') <- withExceptT show $ C.encryptAESNoPad key iv $ B.take len frame
|
||||||
pure $ frame' <> BA.convert (C.unAuthTag tag) <> C.unGCMIV iv
|
pure $ frame' <> BA.convert (C.unAuthTag tag) <> C.unGCMIV iv
|
||||||
|
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ storeRemoteFile rhId encrypted_ localPath = do
|
|||||||
tmpDir <- lift getChatTempDirectory
|
tmpDir <- lift getChatTempDirectory
|
||||||
createDirectoryIfMissing True tmpDir
|
createDirectoryIfMissing True tmpDir
|
||||||
tmpFile <- liftIO $ tmpDir `uniqueCombine` takeFileName localPath
|
tmpFile <- liftIO $ tmpDir `uniqueCombine` takeFileName localPath
|
||||||
cfArgs <- atomically . CF.randomArgs =<< asks random
|
cfArgs <- liftIO . CF.randomArgs =<< asks random
|
||||||
liftError (ChatError . CEFileWrite tmpFile) $ encryptFile localPath tmpFile cfArgs
|
liftError (ChatError . CEFileWrite tmpFile) $ encryptFile localPath tmpFile cfArgs
|
||||||
pure $ CryptoFile tmpFile $ Just cfArgs
|
pure $ CryptoFile tmpFile $ Just cfArgs
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type EncryptedFile = ((Handle, Word32), C.CbNonce, LC.SbState)
|
|||||||
|
|
||||||
prepareEncryptedFile :: RemoteCrypto -> (Handle, Word32) -> ExceptT RemoteProtocolError IO EncryptedFile
|
prepareEncryptedFile :: RemoteCrypto -> (Handle, Word32) -> ExceptT RemoteProtocolError IO EncryptedFile
|
||||||
prepareEncryptedFile RemoteCrypto {drg, hybridKey} f = do
|
prepareEncryptedFile RemoteCrypto {drg, hybridKey} f = do
|
||||||
nonce <- atomically $ C.randomCbNonce drg
|
nonce <- liftIO $ C.randomCbNonce drg
|
||||||
sbState <- liftEitherWith (const $ PRERemoteControl RCEEncrypt) $ LC.kcbInit hybridKey nonce
|
sbState <- liftEitherWith (const $ PRERemoteControl RCEEncrypt) $ LC.kcbInit hybridKey nonce
|
||||||
pure (f, nonce, sbState)
|
pure (f, nonce, sbState)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import Control.Exception (Exception)
|
|||||||
import Crypto.Random (ChaChaDRG)
|
import Crypto.Random (ChaChaDRG)
|
||||||
import qualified Data.Aeson.TH as J
|
import qualified Data.Aeson.TH as J
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
|
import Data.IORef (IORef)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.Word (Word16)
|
import Data.Word (Word16)
|
||||||
@@ -40,7 +41,7 @@ data RemoteHostClient = RemoteHostClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
data RemoteCrypto = RemoteCrypto
|
data RemoteCrypto = RemoteCrypto
|
||||||
{ drg :: TVar ChaChaDRG,
|
{ drg :: IORef ChaChaDRG,
|
||||||
counter :: TVar Int64,
|
counter :: TVar Int64,
|
||||||
sessionCode :: ByteString,
|
sessionCode :: ByteString,
|
||||||
hybridKey :: KEMHybridSecret,
|
hybridKey :: KEMHybridSecret,
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ import Control.Monad.IO.Class
|
|||||||
import Crypto.Random (ChaChaDRG)
|
import Crypto.Random (ChaChaDRG)
|
||||||
import Data.Bifunctor (second)
|
import Data.Bifunctor (second)
|
||||||
import Data.Either (rights)
|
import Data.Either (rights)
|
||||||
|
import Data.IORef (IORef)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.List (partition, sortOn)
|
import Data.List (partition, sortOn)
|
||||||
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
|
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
|
||||||
@@ -151,7 +152,6 @@ import Simplex.Messaging.Crypto.Ratchet (pattern PQEncOff, pattern PQSupportOff)
|
|||||||
import Simplex.Messaging.Protocol (SubscriptionMode (..))
|
import Simplex.Messaging.Protocol (SubscriptionMode (..))
|
||||||
import Simplex.Messaging.Util (eitherToMaybe, ($>>=), (<$$>))
|
import Simplex.Messaging.Util (eitherToMaybe, ($>>=), (<$$>))
|
||||||
import Simplex.Messaging.Version
|
import Simplex.Messaging.Version
|
||||||
import UnliftIO.STM
|
|
||||||
|
|
||||||
type GroupInfoRow = (Int64, GroupName, GroupName, Text, Maybe Text, Maybe ImageData, Maybe ProfileId, Maybe MsgFilter, Maybe Bool, Bool, Maybe GroupPreferences) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime, Maybe UIThemeEntityOverrides, Maybe CustomData) :. GroupMemberRow
|
type GroupInfoRow = (Int64, GroupName, GroupName, Text, Maybe Text, Maybe ImageData, Maybe ProfileId, Maybe MsgFilter, Maybe Bool, Bool, Maybe GroupPreferences) :. (UTCTime, UTCTime, Maybe UTCTime, Maybe UTCTime, Maybe UIThemeEntityOverrides, Maybe CustomData) :. GroupMemberRow
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ getGroupAndMember db User {userId, userContactId} groupMemberId vr =
|
|||||||
in (groupInfo, (member :: GroupMember) {activeConn = toMaybeConnection vr connRow})
|
in (groupInfo, (member :: GroupMember) {activeConn = toMaybeConnection vr connRow})
|
||||||
|
|
||||||
-- | creates completely new group with a single member - the current user
|
-- | creates completely new group with a single member - the current user
|
||||||
createNewGroup :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupProfile -> Maybe Profile -> ExceptT StoreError IO GroupInfo
|
createNewGroup :: DB.Connection -> VersionRangeChat -> IORef ChaChaDRG -> User -> GroupProfile -> Maybe Profile -> ExceptT StoreError IO GroupInfo
|
||||||
createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = ExceptT $ do
|
createNewGroup db vr gVar user@User {userId} groupProfile incognitoProfile = ExceptT $ do
|
||||||
let GroupProfile {displayName, fullName, description, image, groupPreferences} = groupProfile
|
let GroupProfile {displayName, fullName, description, image, groupPreferences} = groupProfile
|
||||||
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
fullGroupPreferences = mergeGroupPreferences groupPreferences
|
||||||
@@ -798,7 +798,7 @@ getGroupInvitation db vr user groupId =
|
|||||||
firstRow fromOnly (SEGroupNotFound groupId) $
|
firstRow fromOnly (SEGroupNotFound groupId) $
|
||||||
DB.query db "SELECT g.inv_queue_info FROM groups g WHERE g.group_id = ? AND g.user_id = ?" (groupId, userId)
|
DB.query db "SELECT g.inv_queue_info FROM groups g WHERE g.group_id = ? AND g.user_id = ?" (groupId, userId)
|
||||||
|
|
||||||
createNewContactMember :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> ConnId -> ConnReqInvitation -> SubscriptionMode -> ExceptT StoreError IO GroupMember
|
createNewContactMember :: DB.Connection -> IORef ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> ConnId -> ConnReqInvitation -> SubscriptionMode -> ExceptT StoreError IO GroupMember
|
||||||
createNewContactMember _ _ _ _ Contact {localDisplayName, activeConn = Nothing} _ _ _ _ = throwError $ SEContactNotReady localDisplayName
|
createNewContactMember _ _ _ _ Contact {localDisplayName, activeConn = Nothing} _ _ _ _ = throwError $ SEContactNotReady localDisplayName
|
||||||
createNewContactMember db gVar User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile, activeConn = Just Connection {connChatVersion, peerChatVRange}} memberRole agentConnId connRequest subMode =
|
createNewContactMember db gVar User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile, activeConn = Just Connection {connChatVersion, peerChatVRange}} memberRole agentConnId connRequest subMode =
|
||||||
createWithRandomId gVar $ \memId -> do
|
createWithRandomId gVar $ \memId -> do
|
||||||
@@ -847,7 +847,7 @@ createNewContactMember db gVar User {userId, userContactId} GroupInfo {groupId,
|
|||||||
:. (minV, maxV)
|
:. (minV, maxV)
|
||||||
)
|
)
|
||||||
|
|
||||||
createNewContactMemberAsync :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> (CommandId, ConnId) -> VersionChat -> VersionRangeChat -> SubscriptionMode -> ExceptT StoreError IO ()
|
createNewContactMemberAsync :: DB.Connection -> IORef ChaChaDRG -> User -> GroupInfo -> Contact -> GroupMemberRole -> (CommandId, ConnId) -> VersionChat -> VersionRangeChat -> SubscriptionMode -> ExceptT StoreError IO ()
|
||||||
createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile} memberRole (cmdId, agentConnId) chatV peerChatVRange subMode =
|
createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo {groupId, membership} Contact {contactId, localDisplayName, profile} memberRole (cmdId, agentConnId) chatV peerChatVRange subMode =
|
||||||
createWithRandomId gVar $ \memId -> do
|
createWithRandomId gVar $ \memId -> do
|
||||||
createdAt <- liftIO getCurrentTime
|
createdAt <- liftIO getCurrentTime
|
||||||
@@ -872,7 +872,7 @@ createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo
|
|||||||
:. (minV, maxV)
|
:. (minV, maxV)
|
||||||
)
|
)
|
||||||
|
|
||||||
createAcceptedMember :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> UserContactRequest -> GroupMemberRole -> ExceptT StoreError IO (GroupMemberId, MemberId)
|
createAcceptedMember :: DB.Connection -> IORef ChaChaDRG -> User -> GroupInfo -> UserContactRequest -> GroupMemberRole -> ExceptT StoreError IO (GroupMemberId, MemberId)
|
||||||
createAcceptedMember
|
createAcceptedMember
|
||||||
db
|
db
|
||||||
gVar
|
gVar
|
||||||
@@ -1544,7 +1544,7 @@ getMatchingMemberContacts db vr user@User {userId} GroupMember {memberProfile =
|
|||||||
AND p.display_name = ? AND p.full_name = ?
|
AND p.display_name = ? AND p.full_name = ?
|
||||||
|]
|
|]
|
||||||
|
|
||||||
createSentProbe :: DB.Connection -> TVar ChaChaDRG -> UserId -> ContactOrMember -> ExceptT StoreError IO (Probe, Int64)
|
createSentProbe :: DB.Connection -> IORef ChaChaDRG -> UserId -> ContactOrMember -> ExceptT StoreError IO (Probe, Int64)
|
||||||
createSentProbe db gVar userId to =
|
createSentProbe db gVar userId to =
|
||||||
createWithRandomBytes 32 gVar $ \probe -> do
|
createWithRandomBytes 32 gVar $ \probe -> do
|
||||||
currentTs <- getCurrentTime
|
currentTs <- getCurrentTime
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ import Crypto.Random (ChaChaDRG)
|
|||||||
import Data.Bifunctor (first)
|
import Data.Bifunctor (first)
|
||||||
import Data.ByteString.Char8 (ByteString)
|
import Data.ByteString.Char8 (ByteString)
|
||||||
import Data.Either (fromRight, rights)
|
import Data.Either (fromRight, rights)
|
||||||
|
import Data.IORef (IORef)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.List (sortBy)
|
import Data.List (sortBy)
|
||||||
import Data.Maybe (fromMaybe, isJust, mapMaybe)
|
import Data.Maybe (fromMaybe, isJust, mapMaybe)
|
||||||
@@ -176,7 +177,7 @@ deleteGroupChatItemsMessages db User {userId} GroupInfo {groupId} = do
|
|||||||
DB.execute db "DELETE FROM chat_item_reactions WHERE group_id = ?" (Only groupId)
|
DB.execute db "DELETE FROM chat_item_reactions WHERE group_id = ?" (Only groupId)
|
||||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND group_id = ?" (userId, groupId)
|
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND group_id = ?" (userId, groupId)
|
||||||
|
|
||||||
createNewSndMessage :: MsgEncodingI e => DB.Connection -> TVar ChaChaDRG -> ConnOrGroupId -> ChatMsgEvent e -> (SharedMsgId -> EncodedChatMessage) -> ExceptT StoreError IO SndMessage
|
createNewSndMessage :: MsgEncodingI e => DB.Connection -> IORef ChaChaDRG -> ConnOrGroupId -> ChatMsgEvent e -> (SharedMsgId -> EncodedChatMessage) -> ExceptT StoreError IO SndMessage
|
||||||
createNewSndMessage db gVar connOrGroupId chatMsgEvent encodeMessage =
|
createNewSndMessage db gVar connOrGroupId chatMsgEvent encodeMessage =
|
||||||
createWithRandomId' gVar $ \sharedMsgId ->
|
createWithRandomId' gVar $ \sharedMsgId ->
|
||||||
case encodeMessage (SharedMsgId sharedMsgId) of
|
case encodeMessage (SharedMsgId sharedMsgId) of
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import Crypto.Random (ChaChaDRG)
|
|||||||
import qualified Data.Aeson.TH as J
|
import qualified Data.Aeson.TH as J
|
||||||
import qualified Data.ByteString.Base64 as B64
|
import qualified Data.ByteString.Base64 as B64
|
||||||
import Data.ByteString.Char8 (ByteString)
|
import Data.ByteString.Char8 (ByteString)
|
||||||
|
import Data.IORef (IORef)
|
||||||
import Data.Int (Int64)
|
import Data.Int (Int64)
|
||||||
import Data.Maybe (fromMaybe, isJust, listToMaybe)
|
import Data.Maybe (fromMaybe, isJust, listToMaybe)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@@ -44,7 +45,6 @@ import Simplex.Messaging.Parsers (dropPrefix, sumTypeJSON)
|
|||||||
import Simplex.Messaging.Protocol (SubscriptionMode (..))
|
import Simplex.Messaging.Protocol (SubscriptionMode (..))
|
||||||
import Simplex.Messaging.Util (allFinally)
|
import Simplex.Messaging.Util (allFinally)
|
||||||
import Simplex.Messaging.Version
|
import Simplex.Messaging.Version
|
||||||
import UnliftIO.STM
|
|
||||||
|
|
||||||
data ChatLockEntity
|
data ChatLockEntity
|
||||||
= CLInvitation ByteString
|
= CLInvitation ByteString
|
||||||
@@ -488,16 +488,16 @@ withLocalDisplayName db userId displayName action = getLdnSuffix >>= (`tryCreate
|
|||||||
|]
|
|]
|
||||||
(ldn, displayName, ldnSuffix, userId, ts, ts)
|
(ldn, displayName, ldnSuffix, userId, ts, ts)
|
||||||
|
|
||||||
createWithRandomId :: forall a. TVar ChaChaDRG -> (ByteString -> IO a) -> ExceptT StoreError IO a
|
createWithRandomId :: forall a. IORef ChaChaDRG -> (ByteString -> IO a) -> ExceptT StoreError IO a
|
||||||
createWithRandomId = createWithRandomBytes 12
|
createWithRandomId = createWithRandomBytes 12
|
||||||
|
|
||||||
createWithRandomId' :: forall a. TVar ChaChaDRG -> (ByteString -> IO (Either StoreError a)) -> ExceptT StoreError IO a
|
createWithRandomId' :: forall a. IORef ChaChaDRG -> (ByteString -> IO (Either StoreError a)) -> ExceptT StoreError IO a
|
||||||
createWithRandomId' = createWithRandomBytes' 12
|
createWithRandomId' = createWithRandomBytes' 12
|
||||||
|
|
||||||
createWithRandomBytes :: forall a. Int -> TVar ChaChaDRG -> (ByteString -> IO a) -> ExceptT StoreError IO a
|
createWithRandomBytes :: forall a. Int -> IORef ChaChaDRG -> (ByteString -> IO a) -> ExceptT StoreError IO a
|
||||||
createWithRandomBytes size gVar create = createWithRandomBytes' size gVar (fmap Right . create)
|
createWithRandomBytes size gVar create = createWithRandomBytes' size gVar (fmap Right . create)
|
||||||
|
|
||||||
createWithRandomBytes' :: forall a. Int -> TVar ChaChaDRG -> (ByteString -> IO (Either StoreError a)) -> ExceptT StoreError IO a
|
createWithRandomBytes' :: forall a. Int -> IORef ChaChaDRG -> (ByteString -> IO (Either StoreError a)) -> ExceptT StoreError IO a
|
||||||
createWithRandomBytes' size gVar create = tryCreate 3
|
createWithRandomBytes' size gVar create = tryCreate 3
|
||||||
where
|
where
|
||||||
tryCreate :: Int -> ExceptT StoreError IO a
|
tryCreate :: Int -> ExceptT StoreError IO a
|
||||||
@@ -510,8 +510,8 @@ createWithRandomBytes' size gVar create = tryCreate 3
|
|||||||
| SQL.sqlError e == SQL.ErrorConstraint -> tryCreate (n - 1)
|
| SQL.sqlError e == SQL.ErrorConstraint -> tryCreate (n - 1)
|
||||||
| otherwise -> throwError . SEInternalError $ show e
|
| otherwise -> throwError . SEInternalError $ show e
|
||||||
|
|
||||||
encodedRandomBytes :: TVar ChaChaDRG -> Int -> IO ByteString
|
encodedRandomBytes :: IORef ChaChaDRG -> Int -> IO ByteString
|
||||||
encodedRandomBytes gVar n = atomically $ B64.encode <$> C.randomBytes n gVar
|
encodedRandomBytes gVar n = B64.encode <$> C.randomBytes n gVar
|
||||||
|
|
||||||
assertNotUser :: DB.Connection -> User -> Contact -> ExceptT StoreError IO ()
|
assertNotUser :: DB.Connection -> User -> Contact -> ExceptT StoreError IO ()
|
||||||
assertNotUser db User {userId} Contact {contactId, localDisplayName} = do
|
assertNotUser db User {userId} Contact {contactId, localDisplayName} = do
|
||||||
|
|||||||
@@ -442,6 +442,7 @@ smpServerCfg =
|
|||||||
logStatsStartTime = 0,
|
logStatsStartTime = 0,
|
||||||
serverStatsLogFile = "tests/smp-server-stats.daily.log",
|
serverStatsLogFile = "tests/smp-server-stats.daily.log",
|
||||||
serverStatsBackupFile = Nothing,
|
serverStatsBackupFile = Nothing,
|
||||||
|
pendingENDInterval = 500000,
|
||||||
smpServerVRange = supportedServerSMPRelayVRange,
|
smpServerVRange = supportedServerSMPRelayVRange,
|
||||||
transportConfig = defaultTransportServerConfig {alpn = Just supportedSMPHandshakes},
|
transportConfig = defaultTransportServerConfig {alpn = Just supportedSMPHandshakes},
|
||||||
smpHandshakeTimeout = 1000000,
|
smpHandshakeTimeout = 1000000,
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ sndRcvImg pqEnc enabled (cc1, msg, v1) (cc2, v2) = do
|
|||||||
name1 <- userName cc1
|
name1 <- userName cc1
|
||||||
name2 <- userName cc2
|
name2 <- userName cc2
|
||||||
g <- C.newRandom
|
g <- C.newRandom
|
||||||
img <- atomically $ B64.encode <$> C.randomBytes lrgLen g
|
img <- B64.encode <$> C.randomBytes lrgLen g
|
||||||
cc1 `send` ("/_send @2 json {\"msgContent\":{\"type\":\"image\",\"text\":\"" <> msg <> "\",\"image\":\"" <> B.unpack img <> "\"}}")
|
cc1 `send` ("/_send @2 json {\"msgContent\":{\"type\":\"image\",\"text\":\"" <> msg <> "\",\"image\":\"" <> B.unpack img <> "\"}}")
|
||||||
cc1 .<## "}}"
|
cc1 .<## "}}"
|
||||||
cc1 <### ([ConsoleString (name2 <> ": quantum resistant end-to-end encryption enabled") | enabled] <> [WithTime ("@" <> name2 <> " " <> msg)])
|
cc1 <### ([ConsoleString (name2 <> ": quantum resistant end-to-end encryption enabled") | enabled] <> [WithTime ("@" <> name2 <> " " <> msg)])
|
||||||
@@ -231,7 +231,7 @@ sndRcvImg pqEnc enabled (cc1, msg, v1) (cc2, v2) = do
|
|||||||
genProfileImg :: IO ByteString
|
genProfileImg :: IO ByteString
|
||||||
genProfileImg = do
|
genProfileImg = do
|
||||||
g <- C.newRandom
|
g <- C.newRandom
|
||||||
atomically $ B64.encode <$> C.randomBytes lrgLen g
|
B64.encode <$> C.randomBytes lrgLen g
|
||||||
where
|
where
|
||||||
lrgLen = maxEncodedInfoLength * 3 `div` 4 - 420
|
lrgLen = maxEncodedInfoLength * 3 `div` 4 - 420
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
module MobileTests where
|
module MobileTests where
|
||||||
|
|
||||||
import ChatTests.Utils
|
import ChatTests.Utils
|
||||||
import Control.Concurrent.STM
|
|
||||||
import Control.Monad.Except
|
import Control.Monad.Except
|
||||||
import Data.Aeson (FromJSON)
|
import Data.Aeson (FromJSON)
|
||||||
import qualified Data.Aeson as J
|
import qualified Data.Aeson as J
|
||||||
@@ -232,8 +231,8 @@ testMediaApi :: HasCallStack => FilePath -> IO ()
|
|||||||
testMediaApi tmp = do
|
testMediaApi tmp = do
|
||||||
Right c@ChatController {random = g} <- chatMigrateInit (tmp </> "1") "" "yesUp"
|
Right c@ChatController {random = g} <- chatMigrateInit (tmp </> "1") "" "yesUp"
|
||||||
cc <- newStablePtr c
|
cc <- newStablePtr c
|
||||||
key <- atomically $ C.randomBytes 32 g
|
key <- C.randomBytes 32 g
|
||||||
frame <- atomically $ C.randomBytes 100 g
|
frame <- C.randomBytes 100 g
|
||||||
let keyStr = strEncode key
|
let keyStr = strEncode key
|
||||||
reserved = B.replicate (C.authTagSize + C.gcmIVSize) 0
|
reserved = B.replicate (C.authTagSize + C.gcmIVSize) 0
|
||||||
frame' = frame <> reserved
|
frame' = frame <> reserved
|
||||||
@@ -246,8 +245,8 @@ testMediaCApi :: HasCallStack => FilePath -> IO ()
|
|||||||
testMediaCApi tmp = do
|
testMediaCApi tmp = do
|
||||||
Right c@ChatController {random = g} <- chatMigrateInit (tmp </> "1") "" "yesUp"
|
Right c@ChatController {random = g} <- chatMigrateInit (tmp </> "1") "" "yesUp"
|
||||||
cc <- newStablePtr c
|
cc <- newStablePtr c
|
||||||
key <- atomically $ C.randomBytes 32 g
|
key <- C.randomBytes 32 g
|
||||||
frame <- atomically $ C.randomBytes 100 g
|
frame <- C.randomBytes 100 g
|
||||||
let keyStr = strEncode key
|
let keyStr = strEncode key
|
||||||
reserved = B.replicate (C.authTagSize + C.gcmIVSize) 0
|
reserved = B.replicate (C.authTagSize + C.gcmIVSize) 0
|
||||||
frame' = frame <> reserved
|
frame' = frame <> reserved
|
||||||
@@ -300,7 +299,7 @@ testMissingFileCApi :: FilePath -> IO ()
|
|||||||
testMissingFileCApi tmp = do
|
testMissingFileCApi tmp = do
|
||||||
let path = tmp </> "missing_file"
|
let path = tmp </> "missing_file"
|
||||||
cPath <- newCString path
|
cPath <- newCString path
|
||||||
CFArgs key nonce <- atomically . CF.randomArgs =<< C.newRandom
|
CFArgs key nonce <- CF.randomArgs =<< C.newRandom
|
||||||
cKey <- encodedCString key
|
cKey <- encodedCString key
|
||||||
cNonce <- encodedCString nonce
|
cNonce <- encodedCString nonce
|
||||||
ptr <- cChatReadFile cPath cKey cNonce
|
ptr <- cChatReadFile cPath cKey cNonce
|
||||||
@@ -337,7 +336,7 @@ testMissingFileEncryptionCApi tmp = do
|
|||||||
r <- peekCAString =<< cChatEncryptFile cc cFromPath cToPath
|
r <- peekCAString =<< cChatEncryptFile cc cFromPath cToPath
|
||||||
Just (WFError err) <- jDecode r
|
Just (WFError err) <- jDecode r
|
||||||
err `shouldContain` fromPath
|
err `shouldContain` fromPath
|
||||||
CFArgs key nonce <- atomically . CF.randomArgs =<< C.newRandom
|
CFArgs key nonce <- CF.randomArgs =<< C.newRandom
|
||||||
cKey <- encodedCString key
|
cKey <- encodedCString key
|
||||||
cNonce <- encodedCString nonce
|
cNonce <- encodedCString nonce
|
||||||
let toPath' = tmp </> "missing_file.decrypted.pdf"
|
let toPath' = tmp </> "missing_file.decrypted.pdf"
|
||||||
|
|||||||
Reference in New Issue
Block a user