mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-03-30 18:35:59 +00:00
* agent: make createConnection and setConnShortLink apis support setting all link data fields * add functions * refactor * refactor * fix tests --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
143 lines
6.8 KiB
Haskell
143 lines
6.8 KiB
Haskell
{-# LANGUAGE DataKinds #-}
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
|
{-# LANGUAGE GADTs #-}
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE TypeApplications #-}
|
|
|
|
module AgentTests.ShortLinkTests (shortLinkTests) where
|
|
|
|
import AgentTests.ConnectionRequestTests (contactConnRequest, invConnRequest)
|
|
import AgentTests.EqInstances ()
|
|
import Control.Concurrent.STM
|
|
import Control.Monad.Except
|
|
import Simplex.Messaging.Encoding.String
|
|
import Simplex.Messaging.Agent.Protocol (AgentErrorType (..), ConnLinkData (..), ConnectionMode (..), ConnShortLink (..), LinkKey (..), UserConnLinkData (..), SConnectionMode (..), SMPAgentError (..), UserContactData (..), UserLinkData (..), linkUserData, supportedSMPAgentVRange)
|
|
import qualified Simplex.Messaging.Crypto as C
|
|
import qualified Simplex.Messaging.Crypto.ShortLink as SL
|
|
import Test.Hspec hiding (fit, it)
|
|
import Util
|
|
|
|
shortLinkTests :: Spec
|
|
shortLinkTests = do
|
|
describe "invitation short link" $ do
|
|
it "should encrypt and decrypt link data" testInvShortLink
|
|
it "should fail to decrypt invitation data with bad hash" testInvShortLinkBadDataHash
|
|
describe "contact short link" $ do
|
|
it "should encrypt and decrypt data" testContactShortLink
|
|
it "should encrypt updated user data" testUpdateContactShortLink
|
|
it "should fail to decrypt contact data with bad hash" testContactShortLinkBadDataHash
|
|
it "should fail to decrypt contact data with bad signature" testContactShortLinkBadSignature
|
|
|
|
testInvShortLink :: IO ()
|
|
testInvShortLink = do
|
|
-- encrypt
|
|
g <- C.newRandom
|
|
sigKeys <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let userData = UserLinkData "some user data"
|
|
userLinkData = UserInvLinkData userData
|
|
(linkKey, linkData) = SL.encodeSignLinkData sigKeys supportedSMPAgentVRange invConnRequest userLinkData
|
|
k = SL.invShortLinkKdf linkKey
|
|
Right srvData <- runExceptT $ SL.encryptLinkData g k linkData
|
|
-- decrypt
|
|
Right (connReq, connData') <- pure $ SL.decryptLinkData linkKey k srvData
|
|
connReq `shouldBe` invConnRequest
|
|
linkUserData connData' `shouldBe` userData
|
|
|
|
testInvShortLinkBadDataHash :: IO ()
|
|
testInvShortLinkBadDataHash = do
|
|
-- encrypt
|
|
g <- C.newRandom
|
|
sigKeys <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let userData = UserLinkData "some user data"
|
|
userLinkData = UserInvLinkData userData
|
|
(_linkKey, linkData) = SL.encodeSignLinkData sigKeys supportedSMPAgentVRange invConnRequest userLinkData
|
|
-- different key
|
|
linkKey <- LinkKey <$> atomically (C.randomBytes 32 g)
|
|
let k = SL.invShortLinkKdf linkKey
|
|
Right srvData <- runExceptT $ SL.encryptLinkData g k linkData
|
|
-- decryption fails
|
|
SL.decryptLinkData @'CMInvitation linkKey k srvData
|
|
`shouldBe` Left (AGENT (A_LINK "link data hash"))
|
|
|
|
relayLink1 :: ConnShortLink 'CMContact
|
|
relayLink1 = either error id $ strDecode "https://localhost/a#4AkRDmhf64tdRlN406g8lJRg5OCmhD6ynIhi6glOcCM?p=7001&c=LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI"
|
|
|
|
relayLink2 :: ConnShortLink 'CMContact
|
|
relayLink2 = either error id $ strDecode "https://localhost/a#4AkRDmhf64tdRlN406g8lJRg5OCmhD6ynIhi6glOcCM"
|
|
|
|
testContactShortLink :: IO ()
|
|
testContactShortLink = do
|
|
-- encrypt
|
|
g <- C.newRandom
|
|
sigKeys <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let userData = UserLinkData "some user data"
|
|
userCtData = UserContactData {direct = True, owners = [], relays = [], userData}
|
|
userLinkData = UserContactLinkData userCtData
|
|
(linkKey, linkData) = SL.encodeSignLinkData sigKeys supportedSMPAgentVRange contactConnRequest userLinkData
|
|
(_linkId, k) = SL.contactShortLinkKdf linkKey
|
|
Right srvData <- runExceptT $ SL.encryptLinkData g k linkData
|
|
-- decrypt
|
|
Right (connReq, ContactLinkData _ userCtData') <- pure $ SL.decryptLinkData @'CMContact linkKey k srvData
|
|
connReq `shouldBe` contactConnRequest
|
|
userCtData' `shouldBe` userCtData
|
|
|
|
testUpdateContactShortLink :: IO ()
|
|
testUpdateContactShortLink = do
|
|
-- encrypt
|
|
g <- C.newRandom
|
|
sigKeys <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let userData = UserLinkData "some user data"
|
|
userCtData = UserContactData {direct = True, owners = [], relays = [], userData}
|
|
userLinkData = UserContactLinkData userCtData
|
|
(linkKey, linkData) = SL.encodeSignLinkData sigKeys supportedSMPAgentVRange contactConnRequest userLinkData
|
|
(_linkId, k) = SL.contactShortLinkKdf linkKey
|
|
Right (fd, _ud) <- runExceptT $ SL.encryptLinkData g k linkData
|
|
-- encrypt updated user data
|
|
let updatedUserData = UserLinkData "updated user data"
|
|
userCtData' = UserContactData {direct = False, owners = [], relays = [relayLink1, relayLink2], userData = updatedUserData}
|
|
userLinkData' = UserContactLinkData userCtData'
|
|
signed = SL.encodeSignUserData SCMContact (snd sigKeys) supportedSMPAgentVRange userLinkData'
|
|
Right ud' <- runExceptT $ SL.encryptUserData g k signed
|
|
-- decrypt
|
|
Right (connReq, ContactLinkData _ userCtData'') <- pure $ SL.decryptLinkData @'CMContact linkKey k (fd, ud')
|
|
connReq `shouldBe` contactConnRequest
|
|
userCtData'' `shouldBe` userCtData'
|
|
|
|
testContactShortLinkBadDataHash :: IO ()
|
|
testContactShortLinkBadDataHash = do
|
|
-- encrypt
|
|
g <- C.newRandom
|
|
sigKeys <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let userData = UserLinkData "some user data"
|
|
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
|
|
(_linkKey, linkData) = SL.encodeSignLinkData sigKeys supportedSMPAgentVRange contactConnRequest userLinkData
|
|
-- different key
|
|
linkKey <- LinkKey <$> atomically (C.randomBytes 32 g)
|
|
let (_linkId, k) = SL.contactShortLinkKdf linkKey
|
|
Right srvData <- runExceptT $ SL.encryptLinkData g k linkData
|
|
-- decryption fails
|
|
SL.decryptLinkData @'CMContact linkKey k srvData
|
|
`shouldBe` Left (AGENT (A_LINK "link data hash"))
|
|
|
|
testContactShortLinkBadSignature :: IO ()
|
|
testContactShortLinkBadSignature = do
|
|
-- encrypt
|
|
g <- C.newRandom
|
|
sigKeys <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let userData = UserLinkData "some user data"
|
|
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
|
|
(linkKey, linkData) = SL.encodeSignLinkData sigKeys supportedSMPAgentVRange contactConnRequest userLinkData
|
|
(_linkId, k) = SL.contactShortLinkKdf linkKey
|
|
Right (fd, _ud) <- runExceptT $ SL.encryptLinkData g k linkData
|
|
-- encrypt updated user data
|
|
let updatedUserData = UserLinkData "updated user data"
|
|
userLinkData' = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData = updatedUserData}
|
|
-- another signature key
|
|
(_, pk) <- atomically $ C.generateKeyPair @'C.Ed25519 g
|
|
let signed = SL.encodeSignUserData SCMContact pk supportedSMPAgentVRange userLinkData'
|
|
Right ud' <- runExceptT $ SL.encryptUserData g k signed
|
|
-- decryption fails
|
|
SL.decryptLinkData @'CMContact linkKey k (fd, ud')
|
|
`shouldBe` Left (AGENT (A_LINK "user data signature"))
|