mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-14 19:05:27 +00:00
core: validate full encoded profile size
Add checkProfileSize / checkGroupProfileSize that encode the full ChatMessage and check against maxEncodedInfoLength, so a long displayName/bio combined with a near-max image is also caught at command time instead of failing later at send time with CEException. Run alongside the existing checkProfileImageSize (image-only cap of 12500 bytes, matching mobile UIs) in CreateActiveUser, updateProfile_, newGroup, runUpdateGroupProfile. Update genProfileImg to fit the cap.
This commit is contained in:
@@ -158,6 +158,22 @@ checkProfileImageSize = mapM_ $ \(ImageData t) ->
|
||||
let size = T.length t
|
||||
in when (size > maxProfileImageSize) $ throwCmdError $ "Profile image is too large " <> show size
|
||||
|
||||
checkProfileSize :: Profile -> CM ()
|
||||
checkProfileSize profile = do
|
||||
vr <- chatVersionRange
|
||||
let info = ChatMessage {chatVRange = vr, msgId = Nothing, chatMsgEvent = XInfo profile}
|
||||
case encodeChatMessage maxEncodedInfoLength info of
|
||||
ECMEncoded _ -> pure ()
|
||||
ECMLarge -> throwCmdError "Profile is too large"
|
||||
|
||||
checkGroupProfileSize :: GroupProfile -> CM ()
|
||||
checkGroupProfileSize gProfile = do
|
||||
vr <- chatVersionRange
|
||||
let info = ChatMessage {chatVRange = vr, msgId = Nothing, chatMsgEvent = XGrpInfo gProfile}
|
||||
case encodeChatMessage maxEncodedInfoLength info of
|
||||
ECMEncoded _ -> pure ()
|
||||
ECMLarge -> throwCmdError "Group profile is too large"
|
||||
|
||||
imageExtensions :: [String]
|
||||
imageExtensions = [".jpg", ".jpeg", ".png", ".gif"]
|
||||
|
||||
@@ -358,9 +374,10 @@ processChatCommand :: VersionRangeChat -> NetworkRequestMode -> ChatCommand -> C
|
||||
processChatCommand vr nm = \case
|
||||
ShowActiveUser -> withUser' $ pure . CRActiveUser
|
||||
CreateActiveUser NewUser {profile, pastTimestamp, userChatRelay} -> do
|
||||
forM_ profile $ \Profile {displayName, image} -> do
|
||||
forM_ profile $ \p@Profile {displayName, image} -> do
|
||||
checkValidName displayName
|
||||
checkProfileImageSize image
|
||||
checkProfileSize p
|
||||
p@Profile {displayName} <- liftIO $ maybe generateRandomProfile pure profile
|
||||
u <- asks currentUser
|
||||
users <- withFastStore' getUsers
|
||||
@@ -3640,6 +3657,7 @@ processChatCommand vr nm = \case
|
||||
| otherwise = do
|
||||
when (n /= n') $ checkValidName n'
|
||||
checkProfileImageSize img'
|
||||
checkProfileSize p'
|
||||
-- read contacts before user update to correctly merge preferences
|
||||
contacts <- withFastStore' $ \db -> getUserContacts db vr user
|
||||
user' <- updateUser
|
||||
@@ -3725,6 +3743,7 @@ processChatCommand vr nm = \case
|
||||
assertUserGroupRole gInfo GROwner
|
||||
when (n /= n') $ checkValidName n'
|
||||
checkProfileImageSize img'
|
||||
checkGroupProfileSize p'
|
||||
gInfo' <- withStore $ \db -> updateGroupProfile db user gInfo p'
|
||||
msg <- case businessChat of
|
||||
Just BusinessChatInfo {businessId} -> do
|
||||
@@ -3868,6 +3887,7 @@ processChatCommand vr nm = \case
|
||||
newGroup user incognito gProfile@GroupProfile {displayName, image} useRelays memberId groupKeys_ publicMemberCount_ = do
|
||||
checkValidName displayName
|
||||
checkProfileImageSize image
|
||||
checkGroupProfileSize gProfile
|
||||
-- [incognito] generate incognito profile for group membership
|
||||
incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing
|
||||
withFastStore $ \db -> createNewGroup db vr user gProfile incognitoProfile useRelays memberId groupKeys_ publicMemberCount_
|
||||
|
||||
@@ -24,6 +24,7 @@ import Data.Maybe (fromMaybe)
|
||||
import Data.String
|
||||
import qualified Data.Text as T
|
||||
import Simplex.Chat.Controller (ChatConfig (..), ChatController (..))
|
||||
import Simplex.Chat.Library.Commands (maxProfileImageSize)
|
||||
import Simplex.Chat.Markdown (viewName)
|
||||
import Simplex.Chat.Messages.CIContent (e2eInfoNoPQText, e2eInfoPQText)
|
||||
import Simplex.Chat.Protocol
|
||||
@@ -235,7 +236,9 @@ genProfileImg = do
|
||||
g <- C.newRandom
|
||||
atomically $ B64.encode <$> C.randomBytes lrgLen g
|
||||
where
|
||||
lrgLen = maxEncodedInfoLength * 3 `div` 4 - 420
|
||||
-- raw bytes that base64-encode to fit maxProfileImageSize when prefixed with "data:image/png;base64,"
|
||||
lrgLen = (maxProfileImageSize - imagePrefixLen) * 3 `div` 4 - 1
|
||||
imagePrefixLen = 22
|
||||
|
||||
-- PQ combinators /
|
||||
|
||||
|
||||
Reference in New Issue
Block a user