core: ratchet synchronization (#2653)

This commit is contained in:
spaced4ndy authored and GitHub committed 2023-07-05 19:44:21 +04:00
1 parent c329bf4ea1
commit ae17566a94
10 files changed
+411 -132

No files matched your search

+110 -27
View File
@@ -86,7 +86,9 @@ chatDirectTests = do
it "mark contact verified" testMarkContactVerified
it "mark group member verified" testMarkGroupMemberVerified
describe "message errors" $ do
xit "show message decryption error and update count" testMsgDecryptError
it "show message decryption error" testMsgDecryptError
it "should report ratchet de-synchronization, synchronize ratchets" testSyncRatchet
it "synchronize ratchets, reset connection code" testSyncRatchetCodeReset
describe "message reactions" $ do
it "set message reactions" testSetMessageReactions
@@ -1995,43 +1997,124 @@ testMsgDecryptError tmp =
bob <# "alice> hi"
bob #> "@alice hey"
alice <# "bob> hey"
copyDb "bob" "bob_old"
withTestChat tmp "bob" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
alice #> "@bob hello"
bob <# "alice> hello"
bob #> "@alice hello too"
alice <# "bob> hello too"
withTestChat tmp "bob_old" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
alice #> "@bob 1"
bob <# "alice> decryption error, possibly due to the device change (header)"
alice #> "@bob 2"
alice #> "@bob 3"
(bob </)
bob ##> "/tail @alice 1"
bob <# "alice> decryption error, possibly due to the device change (header, 3 messages)"
bob #> "@alice 1"
alice <# "bob> decryption error, possibly due to the device change (header)"
bob #> "@alice 2"
bob #> "@alice 3"
(alice </)
alice ##> "/tail @bob 1"
alice <# "bob> decryption error, possibly due to the device change (header, 3 messages)"
alice #> "@bob 4"
bob <# "alice> decryption error, possibly due to the device change (header)"
setupDesynchronizedRatchet tmp alice
withTestChat tmp "bob" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
alice #> "@bob hello again"
bob <# "alice> skipped message ID 5..8"
bob <# "alice> skipped message ID 5..7"
bob <# "alice> hello again"
bob #> "@alice received!"
alice <# "bob> received!"
setupDesynchronizedRatchet :: HasCallStack => FilePath -> TestCC -> IO ()
setupDesynchronizedRatchet tmp alice = do
copyDb "bob" "bob_old"
withTestChat tmp "bob" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
alice #> "@bob hello"
bob <# "alice> hello"
bob #> "@alice hello too"
alice <# "bob> hello too"
withTestChat tmp "bob_old" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
bob ##> "/sync alice"
bob <## "error: command is prohibited"
alice #> "@bob 1"
bob <## "alice: decryption error (connection out of sync), synchronization required"
bob <## "use /sync alice to synchronize"
alice #> "@bob 2"
alice #> "@bob 3"
(bob </)
bob ##> "/tail @alice 1"
bob <# "alice> decryption error, possibly due to the device change (header, 3 messages)"
bob ##> "@alice 1"
bob <## "error: command is prohibited"
(alice </)
where
copyDb from to = do
copyFile (chatStoreFile $ tmp </> from) (chatStoreFile $ tmp </> to)
copyFile (agentStoreFile $ tmp </> from) (agentStoreFile $ tmp </> to)
testSyncRatchet :: HasCallStack => FilePath -> IO ()
testSyncRatchet tmp =
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
withNewTestChat tmp "bob" bobProfile $ \bob -> do
connectUsers alice bob
alice #> "@bob hi"
bob <# "alice> hi"
bob #> "@alice hey"
alice <# "bob> hey"
setupDesynchronizedRatchet tmp alice
withTestChat tmp "bob_old" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
bob ##> "/sync alice"
bob <## "connection synchronization started"
alice <## "bob: connection synchronization agreed"
bob <## "alice: connection synchronization agreed"
alice <## "bob: connection synchronized"
bob <## "alice: connection synchronized"
bob #$> ("/_get chat @2 count=3", chat, [(1, "connection synchronization started"), (0, "connection synchronization agreed"), (0, "connection synchronized")])
alice #$> ("/_get chat @2 count=2", chat, [(0, "connection synchronization agreed"), (0, "connection synchronized")])
alice #> "@bob hello again"
bob <# "alice> hello again"
bob #> "@alice received!"
alice <# "bob> received!"
testSyncRatchetCodeReset :: HasCallStack => FilePath -> IO ()
testSyncRatchetCodeReset tmp =
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
withNewTestChat tmp "bob" bobProfile $ \bob -> do
connectUsers alice bob
alice #> "@bob hi"
bob <# "alice> hi"
bob #> "@alice hey"
alice <# "bob> hey"
-- connection not verified
bob ##> "/i alice"
aliceInfo bob
bob <## "connection not verified, use /code command to see security code"
-- verify connection
alice ##> "/code bob"
bCode <- getTermLine alice
bob ##> ("/verify alice " <> bCode)
bob <## "connection verified"
-- connection verified
bob ##> "/i alice"
aliceInfo bob
bob <## "connection verified"
setupDesynchronizedRatchet tmp alice
withTestChat tmp "bob_old" $ \bob -> do
bob <## "1 contacts connected (use /cs for the list)"
bob ##> "/sync alice"
bob <## "connection synchronization started"
alice <## "bob: connection synchronization agreed"
bob <## "alice: connection synchronization agreed"
bob <## "alice: security code changed"
alice <## "bob: connection synchronized"
bob <## "alice: connection synchronized"
bob #$> ("/_get chat @2 count=4", chat, [(1, "connection synchronization started"), (0, "connection synchronization agreed"), (0, "security code changed"), (0, "connection synchronized")])
alice #$> ("/_get chat @2 count=2", chat, [(0, "connection synchronization agreed"), (0, "connection synchronized")])
-- connection not verified
bob ##> "/i alice"
aliceInfo bob
bob <## "connection not verified, use /code command to see security code"
alice #> "@bob hello again"
bob <# "alice> hello again"
bob #> "@alice received!"
alice <# "bob> received!"
where
aliceInfo :: HasCallStack => TestCC -> IO ()
aliceInfo bob = do
bob <## "contact ID: 2"
bob <## "receiving messages via: localhost"
bob <## "sending messages via: localhost"
bob <## "you've shared main profile with this contact"
testSetMessageReactions :: HasCallStack => FilePath -> IO ()
testSetMessageReactions =
testChat2 aliceProfile bobProfile $
+137 -51
View File
@@ -56,7 +56,9 @@ chatGroupTests = do
it "group link member role" testGroupLinkMemberRole
it "leaving and deleting the group joined via link should NOT delete previously existing direct contacts" testGroupLinkLeaveDelete
describe "group message errors" $ do
xit "show message decryption error and update count" testGroupMsgDecryptError
it "show message decryption error" testGroupMsgDecryptError
it "should report ratchet de-synchronization, synchronize ratchets" testGroupSyncRatchet
it "synchronize ratchets, reset connection code" testGroupSyncRatchetCodeReset
describe "message reactions" $ do
it "set group message reactions" testSetGroupMessageReactions
@@ -2200,68 +2202,152 @@ testGroupMsgDecryptError tmp =
[bob, cath] *<# "#team alice> hi"
bob #> "#team hey"
[alice, cath] *<# "#team bob> hey"
copyDb "bob" "bob_old"
withTestChat tmp "bob" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
alice #> "#team hello"
[bob, cath] *<# "#team alice> hello"
bob #> "#team hello too"
[alice, cath] *<# "#team bob> hello too"
withTestChat tmp "bob_old" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
alice #> "#team 1"
bob <# "#team alice> decryption error, possibly due to the device change (header)"
cath <# "#team alice> 1"
alice #> "#team 2"
cath <# "#team alice> 2"
alice #> "#team 3"
cath <# "#team alice> 3"
(bob </)
bob ##> "/tail #team 1"
bob <# "#team alice> decryption error, possibly due to the device change (header, 3 messages)"
bob #> "#team 1"
alice <# "#team bob> decryption error, possibly due to the device change (header)"
-- cath <# "#team bob> 1"
bob #> "#team 2"
cath <# "#team bob> incorrect message hash"
cath <# "#team bob> 2"
bob #> "#team 3"
cath <# "#team bob> 3"
(alice </)
alice ##> "/tail #team 1"
alice <# "#team bob> decryption error, possibly due to the device change (header, 3 messages)"
alice #> "#team 4"
(bob </)
cath <# "#team alice> 4"
bob ##> "/tail #team 4"
bob
<##? [ "#team alice> decryption error, possibly due to the device change (header, 4 messages)",
"#team 1",
"#team 2",
"#team 3"
]
setupDesynchronizedRatchet tmp alice cath
withTestChat tmp "bob" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
alice #> "#team hello again"
bob <# "#team alice> skipped message ID 8..11"
bob <# "#team alice> skipped message ID 8..10"
[bob, cath] *<# "#team alice> hello again"
bob #> "#team received!"
alice <# "#team bob> received!"
bob #> "#team 4"
alice <# "#team bob> 4"
bob #> "#team 5"
cath <# "#team bob> incorrect message hash"
[alice, cath] *<# "#team bob> 5"
bob #> "#team 6"
[alice, cath] *<# "#team bob> 6"
cath <# "#team bob> received!"
setupDesynchronizedRatchet :: HasCallStack => FilePath -> TestCC -> TestCC -> IO ()
setupDesynchronizedRatchet tmp alice cath = do
copyDb "bob" "bob_old"
withTestChat tmp "bob" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
alice #> "#team hello"
[bob, cath] *<# "#team alice> hello"
bob #> "#team hello too"
[alice, cath] *<# "#team bob> hello too"
withTestChat tmp "bob_old" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
bob ##> "/sync #team alice"
bob <## "error: command is prohibited"
alice #> "#team 1"
bob <## "#team alice: decryption error (connection out of sync), synchronization required"
bob <## "use /sync #team alice to synchronize"
cath <# "#team alice> 1"
alice #> "#team 2"
cath <# "#team alice> 2"
alice #> "#team 3"
cath <# "#team alice> 3"
(bob </)
bob ##> "/tail #team 1"
bob <# "#team alice> decryption error, possibly due to the device change (header, 3 messages)"
where
copyDb from to = do
copyFile (chatStoreFile $ tmp </> from) (chatStoreFile $ tmp </> to)
copyFile (agentStoreFile $ tmp </> from) (agentStoreFile $ tmp </> to)
testGroupSyncRatchet :: HasCallStack => FilePath -> IO ()
testGroupSyncRatchet tmp =
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
withNewTestChat tmp "cath" cathProfile $ \cath -> do
withNewTestChat tmp "bob" bobProfile $ \bob -> do
createGroup3 "team" alice bob cath
alice #> "#team hi"
[bob, cath] *<# "#team alice> hi"
bob #> "#team hey"
[alice, cath] *<# "#team bob> hey"
setupDesynchronizedRatchet tmp alice cath
withTestChat tmp "bob_old" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
-- cath and bob are not fully de-synchronized
bob `send` "#team 1"
bob <## "error: command is prohibited" -- silence?
bob <# "#team 1"
(alice </)
(cath </)
cath #> "#team 1"
[alice, bob] *<# "#team cath> 1"
bob `send` "#team 2"
bob <## "error: command is prohibited"
bob <# "#team 2"
cath <# "#team bob> incorrect message hash"
cath <# "#team bob> 2"
bob `send` "#team 3"
bob <## "error: command is prohibited"
bob <# "#team 3"
cath <# "#team bob> 3"
-- synchronize bob and alice
bob ##> "/sync #team alice"
bob <## "connection synchronization started"
alice <## "#team bob: connection synchronization agreed"
bob <## "#team alice: connection synchronization agreed"
alice <## "#team bob: connection synchronized"
bob <## "#team alice: connection synchronized"
bob #$> ("/_get chat #1 count=3", chat, [(1, "connection synchronization started for alice"), (0, "connection synchronization agreed"), (0, "connection synchronized")])
alice #$> ("/_get chat #1 count=2", chat, [(0, "connection synchronization agreed"), (0, "connection synchronized")])
alice #> "#team hello again"
[bob, cath] *<# "#team alice> hello again"
bob #> "#team received!"
alice <# "#team bob> received!"
cath <# "#team bob> received!"
testGroupSyncRatchetCodeReset :: HasCallStack => FilePath -> IO ()
testGroupSyncRatchetCodeReset tmp =
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
withNewTestChat tmp "cath" cathProfile $ \cath -> do
withNewTestChat tmp "bob" bobProfile $ \bob -> do
createGroup3 "team" alice bob cath
alice #> "#team hi"
[bob, cath] *<# "#team alice> hi"
bob #> "#team hey"
[alice, cath] *<# "#team bob> hey"
-- connection not verified
bob ##> "/i #team alice"
aliceInfo bob
bob <## "connection not verified, use /code command to see security code"
-- verify connection
alice ##> "/code #team bob"
bCode <- getTermLine alice
bob ##> ("/verify #team alice " <> bCode)
bob <## "connection verified"
-- connection verified
bob ##> "/i #team alice"
aliceInfo bob
bob <## "connection verified"
setupDesynchronizedRatchet tmp alice cath
withTestChat tmp "bob_old" $ \bob -> do
bob <## "2 contacts connected (use /cs for the list)"
bob <## "#team: connected to server(s)"
bob ##> "/sync #team alice"
bob <## "connection synchronization started"
alice <## "#team bob: connection synchronization agreed"
bob <## "#team alice: connection synchronization agreed"
bob <## "#team alice: security code changed"
alice <## "#team bob: connection synchronized"
bob <## "#team alice: connection synchronized"
bob #$> ("/_get chat #1 count=4", chat, [(1, "connection synchronization started for alice"), (0, "connection synchronization agreed"), (0, "security code changed"), (0, "connection synchronized")])
alice #$> ("/_get chat #1 count=2", chat, [(0, "connection synchronization agreed"), (0, "connection synchronized")])
-- connection not verified
bob ##> "/i #team alice"
aliceInfo bob
bob <## "connection not verified, use /code command to see security code"
alice #> "#team hello again"
[bob, cath] *<# "#team alice> hello again"
bob #> "#team received!"
alice <# "#team bob> received!"
(cath </) -- bob is partially de-synchronized with cath - see test above
where
aliceInfo :: HasCallStack => TestCC -> IO ()
aliceInfo bob = do
bob <## "group ID: 1"
bob <## "member ID: 1"
bob <## "receiving messages via: localhost"
bob <## "sending messages via: localhost"
testSetGroupMessageReactions :: HasCallStack => FilePath -> IO ()
testSetGroupMessageReactions =
testChat3 aliceProfile bobProfile cathProfile $