mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-22 01:29:49 +00:00
sign address card when shared by owner
This commit is contained in:
@@ -1144,39 +1144,23 @@ processChatCommand cxt nm = \case
|
||||
_ -> Nothing
|
||||
ownerSig <-
|
||||
pure signingKeys $>>= \GroupKeys {memberPrivKey} ->
|
||||
mkLinkOwnerSig memberPrivKey groupLink memberId <$$> shareChatBinding user toSendRef
|
||||
mkLinkOwnerSig memberPrivKey groupLink (Just memberId) <$$> shareChatBinding user toSendRef
|
||||
let text = safeDecodeUtf8 $ strEncode groupLink
|
||||
pure $ CRChatMsgContent user MCChat {text, chatLink = MCLGroup groupLink gp, ownerSig}
|
||||
where
|
||||
mkLinkOwnerSig :: ConnectionModeI m => C.PrivateKeyEd25519 -> ConnShortLink m -> MemberId -> (ChatBinding, ByteString) -> LinkOwnerSig
|
||||
mkLinkOwnerSig privKey connLink MemberId {unMemberId} (cbTag, bindingData) =
|
||||
let ownerId = Just $ B64UrlByteString unMemberId
|
||||
cb = encodeChatBinding cbTag bindingData
|
||||
ownerSig = C.sign' privKey $ cb <> smpEncode connLink
|
||||
in LinkOwnerSig {ownerId, chatBinding = B64UrlByteString cb, ownerSig}
|
||||
shareChatBinding :: User -> SendRef -> CM (Maybe (ChatBinding, ByteString))
|
||||
shareChatBinding u = \case
|
||||
SRDirect contactId -> do
|
||||
ct <- withFastStore $ \db -> getContact db cxt u contactId
|
||||
forM (contactConn ct) $ \conn ->
|
||||
(CBDirect,) <$> withAgent (`getConnectionRatchetAdHash` aConnId conn)
|
||||
SRGroup toGroupId _ asGroup -> do
|
||||
GroupInfo {groupProfile = GroupProfile {publicGroup}, membership = m} <- withFastStore $ \db -> getGroupInfo db cxt u toGroupId
|
||||
pure $ mkBinding m <$> publicGroup
|
||||
where
|
||||
mkBinding GroupMember {memberId} PublicGroupProfile {publicGroupId = pgId}
|
||||
| asGroup = (CBChannel, smpEncode pgId)
|
||||
| otherwise = (CBGroup, smpEncode (pgId, memberId))
|
||||
APIShareChatMsgContent _ _ -> throwCmdError "sharing is only supported for public groups"
|
||||
APIShareMyAddress _ -> withUser $ \user -> do
|
||||
APIShareMyAddress toSendRef -> withUser $ \user -> do
|
||||
UserContactLink {connLinkContact = CCLink _ sl_, addressSettings} <- withFastStore (`getUserAddress` user)
|
||||
case sl_ of
|
||||
Nothing -> throwCmdError "your address has no short link to share"
|
||||
Just connLink -> do
|
||||
conn <- withFastStore $ \db -> getUserAddressConnection db cxt user
|
||||
ownerSig <-
|
||||
withAgent (`getConnLinkPrivKey` aConnId conn) $>>= \privKey ->
|
||||
mkLinkOwnerSig privKey connLink Nothing <$$> shareChatBinding user toSendRef
|
||||
let business = businessAddress addressSettings
|
||||
profile = userProfileDirect user Nothing Nothing True
|
||||
text = safeDecodeUtf8 $ strEncode connLink
|
||||
pure $ CRChatMsgContent user MCChat {text, chatLink = MCLContact {connLink, profile, business}, ownerSig = Nothing}
|
||||
pure $ CRChatMsgContent user MCChat {text, chatLink = MCLContact {connLink, profile, business}, ownerSig}
|
||||
APIUserRead userId -> withUserId userId $ \user -> withFastStore' (`setUserChatsRead` user) >> ok user
|
||||
UserRead -> withUser $ \User {userId} -> processChatCommand cxt nm $ APIUserRead userId
|
||||
APIChatRead chatRef@(ChatRef cType chatId scope_) -> withUser $ \_ -> case cType of
|
||||
@@ -4537,6 +4521,25 @@ processChatCommand cxt nm = \case
|
||||
serverShortLink = \case
|
||||
CSLInvitation _ srv lnkId linkKey -> CSLInvitation SLSServer srv lnkId linkKey
|
||||
CSLContact _ ct srv linkKey -> CSLContact SLSServer ct srv linkKey
|
||||
mkLinkOwnerSig :: ConnectionModeI m => C.PrivateKeyEd25519 -> ConnShortLink m -> Maybe MemberId -> (ChatBinding, ByteString) -> LinkOwnerSig
|
||||
mkLinkOwnerSig privKey connLink ownerMemberId (cbTag, bindingData) =
|
||||
let ownerId = (\MemberId {unMemberId} -> B64UrlByteString unMemberId) <$> ownerMemberId
|
||||
cb = encodeChatBinding cbTag bindingData
|
||||
ownerSig = C.sign' privKey $ cb <> smpEncode connLink
|
||||
in LinkOwnerSig {ownerId, chatBinding = B64UrlByteString cb, ownerSig}
|
||||
shareChatBinding :: User -> SendRef -> CM (Maybe (ChatBinding, ByteString))
|
||||
shareChatBinding u = \case
|
||||
SRDirect contactId -> do
|
||||
ct <- withFastStore $ \db -> getContact db cxt u contactId
|
||||
forM (contactConn ct) $ \conn ->
|
||||
(CBDirect,) <$> withAgent (`getConnectionRatchetAdHash` aConnId conn)
|
||||
SRGroup toGroupId _ asGroup -> do
|
||||
GroupInfo {groupProfile = GroupProfile {publicGroup}, membership = m} <- withFastStore $ \db -> getGroupInfo db cxt u toGroupId
|
||||
pure $ mkBinding m <$> publicGroup
|
||||
where
|
||||
mkBinding GroupMember {memberId} PublicGroupProfile {publicGroupId = pgId}
|
||||
| asGroup = (CBChannel, smpEncode pgId)
|
||||
| otherwise = (CBGroup, smpEncode (pgId, memberId))
|
||||
verifyLinkOwner :: ConnectionModeI m => C.PublicKeyEd25519 -> [OwnerAuth] -> ConnShortLink m -> Maybe LinkOwnerSig -> Maybe OwnerVerification
|
||||
verifyLinkOwner rootKey owners connLink =
|
||||
fmap $ \LinkOwnerSig {ownerId, chatBinding = B64UrlByteString bindingBytes, ownerSig} ->
|
||||
|
||||
@@ -26,9 +26,9 @@ import qualified Data.Map.Strict as M
|
||||
import Simplex.Chat.Badges (BadgeCredential, BadgeInfo (..), BadgePurchase (..), BadgeRequest (..), BadgeType (..), generateMasterKey, issueBadge, verifyPayment)
|
||||
import Simplex.Chat.Controller (ChatConfig (..), ChatController (..), ChatHooks (..), defaultChatHooks, mkStoreCxt)
|
||||
import Simplex.Chat.Options (ChatOpts (..), CoreChatOpts (..))
|
||||
import Simplex.Chat.Protocol (currentChatVersion)
|
||||
import Simplex.Chat.Protocol (LinkOwnerSig, MsgChatLink (..), MsgContent (..), currentChatVersion)
|
||||
import Simplex.Chat.Store.Shared (createContact)
|
||||
import Simplex.Chat.Types (ConnStatus (..), Profile (..), GroupRejectionReason (..))
|
||||
import Simplex.Chat.Types (ConnStatus (..), Profile (..), GroupRejectionReason (..), profileFromName)
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Crypto.BBS (BBSPublicKey, BBSSecretKey, bbsKeyGen)
|
||||
import Simplex.Chat.Types.Shared (GroupMemberRole (..))
|
||||
@@ -38,7 +38,7 @@ import Simplex.Messaging.Agent.RetryInterval
|
||||
import Simplex.Messaging.Encoding.String (StrEncoding (..))
|
||||
import Simplex.Messaging.Server.Env.STM hiding (subscriptions)
|
||||
import Simplex.Messaging.Transport
|
||||
import Simplex.Messaging.Util (encodeJSON)
|
||||
import Simplex.Messaging.Util (decodeJSON, encodeJSON)
|
||||
import System.Directory (copyFile, createDirectoryIfMissing)
|
||||
import Test.Hspec hiding (it)
|
||||
|
||||
@@ -121,6 +121,7 @@ chatProfileTests = do
|
||||
it "should connect via one-time invitation" testShortLinkInvitation
|
||||
it "should plan and connect via one-time invitation" testPlanShortLinkInvitation
|
||||
it "should connect via contact address" testShortLinkContactAddress
|
||||
it "should share contact address via chat" testShareAddressViaChat
|
||||
it "should join group" testShortLinkJoinGroup
|
||||
describe "short links with attached data" shortLinkTests
|
||||
describe "client services" $ do
|
||||
@@ -3026,6 +3027,38 @@ testPlanShortLinkInvitation =
|
||||
slSimplexScheme :: String -> String
|
||||
slSimplexScheme sl = T.unpack $ T.replace "https://localhost/" "simplex:/" (T.pack sl) <> "?h=localhost"
|
||||
|
||||
testShareAddressViaChat :: HasCallStack => TestParams -> IO ()
|
||||
testShareAddressViaChat =
|
||||
testChat3 aliceProfile bobProfile cathProfile $ \alice bob cath -> do
|
||||
alice ##> "/ad"
|
||||
_ <- getContactLinks alice True
|
||||
connectUsers alice bob
|
||||
connectUsers bob cath
|
||||
-- alice shares her signed address card to bob
|
||||
alice ##> "/share address @bob"
|
||||
alice <# "@bob contact address of @alice (signed):"
|
||||
_ <- getTermLine alice -- link
|
||||
_ <- getTermLine alice -- owner signature (testView)
|
||||
bob <# "alice> contact address of @alice (signed):"
|
||||
bLink <- getTermLine bob
|
||||
bSig <- getTermLine bob
|
||||
-- bob verifies alice's owner signature
|
||||
bob ##> ("/_connect plan 1 " <> bLink <> " sig=" <> bSig)
|
||||
bob <## "contact address: ok to connect"
|
||||
bob <## "owner signature: verified"
|
||||
_ <- getTermLine bob -- link data
|
||||
-- bob replays alice's signed card to cath: the binding was alice->bob, so cath strips the signature
|
||||
let sig = maybe (error "bad sig") id (decodeJSON (T.pack bSig) :: Maybe LinkOwnerSig)
|
||||
cLink = either error id $ strDecode (B.pack bLink)
|
||||
mc = MCChat (T.pack bLink) (MCLContact cLink (profileFromName "alice") False) (Just sig)
|
||||
cm = "{\"msgContent\":" <> T.unpack (encodeJSON mc) <> "}"
|
||||
bob ##> ("/_send @3 json [" <> cm <> "]")
|
||||
bob <# "@cath contact address of @alice (signed):"
|
||||
_ <- getTermLine bob -- link
|
||||
_ <- getTermLine bob -- owner signature (bob's sent view)
|
||||
cath <# "bob> contact address of @alice:"
|
||||
void $ getTermLine cath -- link (signature stripped)
|
||||
|
||||
testShortLinkContactAddress :: HasCallStack => TestParams -> IO ()
|
||||
testShortLinkContactAddress =
|
||||
testChat4 aliceProfile bobProfile cathProfile danProfile $ \alice bob cath dan -> do
|
||||
|
||||
Reference in New Issue
Block a user