core: rework incognito mode - set per connection (#2838)

This commit is contained in:
spaced4ndy
2023-08-03 17:41:23 +04:00
committed by GitHub
parent b23b109b00
commit 4e27a4ea4f
10 changed files with 292 additions and 120 deletions

View File

@@ -176,7 +176,6 @@ data ChatController = ChatController
currentCalls :: TMap ContactId Call,
config :: ChatConfig,
filesFolder :: TVar (Maybe FilePath), -- path to files folder for mobile apps,
incognitoMode :: TVar Bool,
expireCIThreads :: TMap UserId (Maybe (Async ())),
expireCIFlags :: TMap UserId Bool,
cleanupManagerAsync :: TVar (Maybe (Async ())),
@@ -187,7 +186,7 @@ data ChatController = ChatController
logFilePath :: Maybe FilePath
}
data HelpSection = HSMain | HSFiles | HSGroups | HSContacts | HSMyAddress | HSMarkdown | HSMessages | HSSettings | HSDatabase
data HelpSection = HSMain | HSFiles | HSGroups | HSContacts | HSMyAddress | HSIncognito | HSMarkdown | HSMessages | HSSettings | HSDatabase
deriving (Show, Generic)
instance ToJSON HelpSection where
@@ -223,7 +222,6 @@ data ChatCommand
| SetTempFolder FilePath
| SetFilesFolder FilePath
| APISetXFTPConfig (Maybe XFTPFileConfig)
| SetIncognito Bool
| APIExportArchive ArchiveConfig
| ExportArchive
| APIImportArchive ArchiveConfig
@@ -244,7 +242,7 @@ data ChatCommand
| APIChatUnread ChatRef Bool
| APIDeleteChat ChatRef
| APIClearChat ChatRef
| APIAcceptContact Int64
| APIAcceptContact IncognitoEnabled Int64
| APIRejectContact Int64
| APISendCallInvitation ContactId CallType
| SendCallInvitation ContactName CallType
@@ -322,11 +320,12 @@ data ChatCommand
| EnableGroupMember GroupName ContactName
| ChatHelp HelpSection
| Welcome
| APIAddContact UserId
| AddContact
| APIConnect UserId (Maybe AConnectionRequestUri)
| Connect (Maybe AConnectionRequestUri)
| ConnectSimplex -- UserId (not used in UI)
| APIAddContact UserId IncognitoEnabled
| AddContact IncognitoEnabled
| APISetConnectionIncognito Int64 IncognitoEnabled
| APIConnect UserId IncognitoEnabled (Maybe AConnectionRequestUri)
| Connect IncognitoEnabled (Maybe AConnectionRequestUri)
| ConnectSimplex IncognitoEnabled -- UserId (not used in UI)
| DeleteContact ContactName
| ClearContact ContactName
| APIListContacts UserId
@@ -341,7 +340,7 @@ data ChatCommand
| SetProfileAddress Bool
| APIAddressAutoAccept UserId (Maybe AutoAccept)
| AddressAutoAccept (Maybe AutoAccept)
| AcceptContact ContactName
| AcceptContact IncognitoEnabled ContactName
| RejectContact ContactName
| SendMessage ChatName Text
| SendLiveMessage ChatName Text
@@ -467,7 +466,8 @@ data ChatResponse
| CRUserProfileNoChange {user :: User}
| CRUserPrivacy {user :: User, updatedUser :: User}
| CRVersionInfo {versionInfo :: CoreVersionInfo, chatMigrations :: [UpMigration], agentMigrations :: [UpMigration]}
| CRInvitation {user :: User, connReqInvitation :: ConnReqInvitation}
| CRInvitation {user :: User, connReqInvitation :: ConnReqInvitation, connection :: PendingContactConnection}
| CRConnectionIncognitoUpdated {user :: User, toConnection :: PendingContactConnection}
| CRSentConfirmation {user :: User}
| CRSentInvitation {user :: User, customUserProfile :: Maybe Profile}
| CRContactUpdated {user :: User, fromContact :: Contact, toContact :: Contact}
@@ -876,6 +876,7 @@ data ChatErrorType
| CEServerProtocol {serverProtocol :: AProtocolType}
| CEAgentCommandError {message :: String}
| CEInvalidFileDescription {message :: String}
| CEConnectionIncognitoChangeProhibited
| CEInternalError {message :: String}
| CEException {message :: String}
deriving (Show, Exception, Generic)

View File

@@ -8,6 +8,7 @@ module Simplex.Chat.Help
groupsHelpInfo,
contactsHelpInfo,
myAddressHelpInfo,
incognitoHelpInfo,
messagesHelpInfo,
markdownInfo,
settingsInfo,
@@ -48,7 +49,7 @@ chatWelcome user =
"Welcome " <> green userName <> "!",
"Thank you for installing SimpleX Chat!",
"",
"Connect to SimpleX Chat lead developer for any questions - just type " <> highlight "/simplex",
"Connect to SimpleX Chat developers for any questions - just type " <> highlight "/simplex",
"",
"Follow our updates:",
"> Reddit: https://www.reddit.com/r/SimpleXChat/",
@@ -213,6 +214,26 @@ myAddressHelpInfo =
"The commands may be abbreviated: " <> listHighlight ["/ad", "/da", "/sa", "/ac", "/rc"]
]
incognitoHelpInfo :: [StyledString]
incognitoHelpInfo =
map
styleMarkdown
[ markdown (colored Red) "/incognito" <> " command is deprecated, use commands below instead.",
"",
"Incognito mode protects the privacy of your main profile — you can choose to create a new random profile for each new contact.",
"It allows having many anonymous connections without any shared data between them in a single chat profile.",
"When you share an incognito profile with somebody, this profile will be used for the groups they invite you to.",
"",
green "Incognito commands:",
indent <> highlight "/connect incognito " <> " - create new invitation link using incognito profile",
indent <> highlight "/connect incognito <invitation> " <> " - accept invitation using incognito profile",
indent <> highlight "/accept incognito <name> " <> " - accept contact request using incognito profile",
indent <> highlight "/simplex incognito " <> " - connect to SimpleX Chat developers using incognito profile",
"",
"The commands may be abbreviated: " <> listHighlight ["/c i", "/c i <invitation>", "/ac i <name>"],
"To find the profile used for an incognito connection, use " <> highlight "/info <contact>" <> "."
]
messagesHelpInfo :: [StyledString]
messagesHelpInfo =
map
@@ -269,7 +290,6 @@ settingsInfo =
map
styleMarkdown
[ green "Chat settings:",
indent <> highlight "/incognito on/off " <> " - enable/disable incognito mode",
indent <> highlight "/network " <> " - show / set network access options",
indent <> highlight "/smp " <> " - show / set configured SMP servers",
indent <> highlight "/xftp " <> " - show / set configured XFTP servers",
@@ -285,12 +305,12 @@ databaseHelpInfo :: [StyledString]
databaseHelpInfo =
map
styleMarkdown
[ green "Database export:",
indent <> highlight "/db export " <> " - create database export file that can be imported in mobile apps",
indent <> highlight "/files_folder <path> " <> " - set files folder path to include app files in the exported archive",
"",
green "Database encryption:",
indent <> highlight "/db encrypt <key> " <> " - encrypt chat database with key/passphrase",
indent <> highlight "/db key <current> <new>" <> " - change the key of the encrypted app database",
indent <> highlight "/db decrypt <key> " <> " - decrypt chat database"
]
[ green "Database export:",
indent <> highlight "/db export " <> " - create database export file that can be imported in mobile apps",
indent <> highlight "/files_folder <path> " <> " - set files folder path to include app files in the exported archive",
"",
green "Database encryption:",
indent <> highlight "/db encrypt <key> " <> " - encrypt chat database with key/passphrase",
indent <> highlight "/db key <current> <new>" <> " - change the key of the encrypted app database",
indent <> highlight "/db decrypt <key> " <> " - decrypt chat database"
]

View File

@@ -17,6 +17,7 @@ module Simplex.Chat.Store.Direct
getPendingContactConnection,
deletePendingContactConnection,
createDirectConnection,
createIncognitoProfile,
createConnReqConnection,
getProfileById,
getConnReqContactXContactId,
@@ -33,6 +34,8 @@ module Simplex.Chat.Store.Direct
updateContactUserPreferences,
updateContactAlias,
updateContactConnectionAlias,
updatePCCIncognito,
deletePCCIncognitoProfile,
updateContactUsed,
updateContactUnreadChat,
updateGroupUnreadChat,
@@ -171,6 +174,11 @@ createDirectConnection db User {userId} acId cReq pccConnStatus incognitoProfile
pccConnId <- insertedRowId db
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = False, viaUserContactLink = Nothing, groupLinkId = Nothing, customUserProfileId, connReqInv = Just cReq, localAlias = "", createdAt, updatedAt = createdAt}
createIncognitoProfile :: DB.Connection -> User -> Profile -> IO Int64
createIncognitoProfile db User {userId} p = do
createdAt <- getCurrentTime
createIncognitoProfile_ db userId createdAt p
createIncognitoProfile_ :: DB.Connection -> UserId -> UTCTime -> Profile -> IO Int64
createIncognitoProfile_ db userId createdAt Profile {displayName, fullName, image} = do
DB.execute
@@ -307,7 +315,30 @@ updateContactConnectionAlias db userId conn localAlias = do
WHERE user_id = ? AND connection_id = ?
|]
(localAlias, updatedAt, userId, pccConnId conn)
pure (conn :: PendingContactConnection) {localAlias}
pure (conn :: PendingContactConnection) {localAlias, updatedAt}
updatePCCIncognito :: DB.Connection -> User -> PendingContactConnection -> Maybe ProfileId -> IO PendingContactConnection
updatePCCIncognito db User {userId} conn customUserProfileId = do
updatedAt <- getCurrentTime
DB.execute
db
[sql|
UPDATE connections
SET custom_user_profile_id = ?, updated_at = ?
WHERE user_id = ? AND connection_id = ?
|]
(customUserProfileId, updatedAt, userId, pccConnId conn)
pure (conn :: PendingContactConnection) {customUserProfileId, updatedAt}
deletePCCIncognitoProfile :: DB.Connection -> User -> ProfileId -> IO ()
deletePCCIncognitoProfile db User {userId} profileId =
DB.execute
db
[sql|
DELETE FROM contact_profiles
WHERE user_id = ? AND contact_profile_id = ? AND incognito = 1
|]
(userId, profileId)
updateContactUsed :: DB.Connection -> User -> Contact -> IO ()
updateContactUsed db User {userId} Contact {contactId} = do

View File

@@ -397,14 +397,14 @@ data UserContactLink = UserContactLink
instance ToJSON UserContactLink where toEncoding = J.genericToEncoding J.defaultOptions
data AutoAccept = AutoAccept
{ acceptIncognito :: Bool,
{ acceptIncognito :: IncognitoEnabled,
autoReply :: Maybe MsgContent
}
deriving (Show, Generic)
instance ToJSON AutoAccept where toEncoding = J.genericToEncoding J.defaultOptions
toUserContactLink :: (ConnReqContact, Bool, Bool, Maybe MsgContent) -> UserContactLink
toUserContactLink :: (ConnReqContact, Bool, IncognitoEnabled, Maybe MsgContent) -> UserContactLink
toUserContactLink (connReq, autoAccept, acceptIncognito, autoReply) =
UserContactLink connReq $
if autoAccept then Just AutoAccept {acceptIncognito, autoReply} else Nothing
@@ -452,9 +452,6 @@ updateUserAddressAutoAccept db user@User {userId} autoAccept = do
Just AutoAccept {acceptIncognito, autoReply} -> (True, acceptIncognito, autoReply)
_ -> (False, False, Nothing)
getProtocolServers :: forall p. ProtocolTypeI p => DB.Connection -> User -> IO [ServerCfg p]
getProtocolServers db User {userId} =
map toServerCfg

View File

@@ -203,7 +203,7 @@ createContact_ db userId connId Profile {displayName, fullName, image, contactLi
pure $ Right (ldn, contactId, profileId)
deleteUnusedIncognitoProfileById_ :: DB.Connection -> User -> ProfileId -> IO ()
deleteUnusedIncognitoProfileById_ db User {userId} profile_id =
deleteUnusedIncognitoProfileById_ db User {userId} profileId =
DB.executeNamed
db
[sql|
@@ -218,7 +218,7 @@ deleteUnusedIncognitoProfileById_ db User {userId} profile_id =
WHERE user_id = :user_id AND member_profile_id = :profile_id LIMIT 1
)
|]
[":user_id" := userId, ":profile_id" := profile_id]
[":user_id" := userId, ":profile_id" := profileId]
type ContactRow = (ContactId, ProfileId, ContactName, Maybe Int64, ContactName, Text, Maybe ImageData, Maybe ConnReqContact, LocalAlias, Bool) :. (Maybe Bool, Maybe Bool, Bool, Maybe Preferences, Preferences, UTCTime, UTCTime, Maybe UTCTime)

View File

@@ -184,7 +184,9 @@ contactConn = activeConn
contactConnId :: Contact -> ConnId
contactConnId = aConnId . contactConn
contactConnIncognito :: Contact -> Bool
type IncognitoEnabled = Bool
contactConnIncognito :: Contact -> IncognitoEnabled
contactConnIncognito = connIncognito . contactConn
contactDirect :: Contact -> Bool
@@ -595,7 +597,7 @@ memberConnId GroupMember {activeConn} = aConnId <$> activeConn
groupMemberId' :: GroupMember -> GroupMemberId
groupMemberId' GroupMember {groupMemberId} = groupMemberId
memberIncognito :: GroupMember -> Bool
memberIncognito :: GroupMember -> IncognitoEnabled
memberIncognito GroupMember {memberProfile, memberContactProfileId} = localProfileId memberProfile /= memberContactProfileId
memberSecurityCode :: GroupMember -> Maybe SecurityCode

View File

@@ -115,6 +115,7 @@ responseToView user_ ChatConfig {logLevel, showReactions, showReceipts, testView
HSGroups -> groupsHelpInfo
HSContacts -> contactsHelpInfo
HSMyAddress -> myAddressHelpInfo
HSIncognito -> incognitoHelpInfo
HSMessages -> messagesHelpInfo
HSMarkdown -> markdownInfo
HSSettings -> settingsInfo
@@ -138,7 +139,8 @@ responseToView user_ ChatConfig {logLevel, showReactions, showReceipts, testView
CRUserProfileNoChange u -> ttyUser u ["user profile did not change"]
CRUserPrivacy u u' -> ttyUserPrefix u $ viewUserPrivacy u u'
CRVersionInfo info _ _ -> viewVersionInfo logLevel info
CRInvitation u cReq -> ttyUser u $ viewConnReqInvitation cReq
CRInvitation u cReq _ -> ttyUser u $ viewConnReqInvitation cReq
CRConnectionIncognitoUpdated u c -> ttyUser u $ viewConnectionIncognitoUpdated c
CRSentConfirmation u -> ttyUser u ["confirmation sent!"]
CRSentInvitation u customUserProfile -> ttyUser u $ viewSentInvitation customUserProfile testView
CRContactDeleted u c -> ttyUser u [ttyContact' c <> ": contact is deleted"]
@@ -1148,6 +1150,11 @@ viewConnectionAliasUpdated PendingContactConnection {pccConnId, localAlias}
| localAlias == "" = ["connection " <> sShow pccConnId <> " alias removed"]
| otherwise = ["connection " <> sShow pccConnId <> " alias updated: " <> plain localAlias]
viewConnectionIncognitoUpdated :: PendingContactConnection -> [StyledString]
viewConnectionIncognitoUpdated PendingContactConnection {pccConnId, customUserProfileId}
| isJust customUserProfileId = ["connection " <> sShow pccConnId <> " changed to incognito"]
| otherwise = ["connection " <> sShow pccConnId <> " changed to non incognito"]
viewContactUpdated :: Contact -> Contact -> [StyledString]
viewContactUpdated
Contact {localDisplayName = n, profile = LocalProfile {fullName, contactLink}}
@@ -1539,6 +1546,7 @@ viewChatError logLevel = \case
CECommandError e -> ["bad chat command: " <> plain e]
CEAgentCommandError e -> ["agent command error: " <> plain e]
CEInvalidFileDescription e -> ["invalid file description: " <> plain e]
CEConnectionIncognitoChangeProhibited -> ["incognito mode change prohibited"]
CEInternalError e -> ["internal chat error: " <> plain e]
CEException e -> ["exception: " <> plain e]
-- e -> ["chat error: " <> sShow e]