From 7445e685b7766e560a3c77de0b55bf75342b46b3 Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Tue, 22 Sep 2026 09:29:47 +0200 Subject: [PATCH] minimize diff and align style even more --- cabal.project | 2 +- docs/rfcs/2026-09-10-wallet-keys.md | 2 +- scripts/nix/sha256map.nix | 2 +- simplex-chat.cabal | 2 +- src/Simplex/Chat/Remote.hs | 3 +-- tests/PostgresSchemaDump.hs | 34 +++++++++++++-------------- tests/SchemaDump.hs | 36 ++++++++++++++--------------- 7 files changed, 38 insertions(+), 43 deletions(-) diff --git a/cabal.project b/cabal.project index 0e00d2dbd9..49f4cb95d0 100644 --- a/cabal.project +++ b/cabal.project @@ -21,7 +21,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 33e8ef018e8080bc8134ea8bd5ad20b3b2afe987 + tag: 7dcd89d30bdf06913b03f3884bad987b75a6744a source-repository-package type: git diff --git a/docs/rfcs/2026-09-10-wallet-keys.md b/docs/rfcs/2026-09-10-wallet-keys.md index 3d2a8a1626..c11d288d8c 100644 --- a/docs/rfcs/2026-09-10-wallet-keys.md +++ b/docs/rfcs/2026-09-10-wallet-keys.md @@ -149,7 +149,7 @@ A null `account_index` marks an account whose key was imported rather than deriv - **A wallet the master phrase is imported into.** Enumerating BIP-44 accounts computes account extended public keys, and some wallets send them to a vendor, which hands that vendor every account on the device at once, across every profile. That is what an account for each name otherwise prevents. - **Whoever answers the recovery scan.** Sees every address the phrase could hold a name on, in one burst, so it links every account on the device, across profiles, and recognises addresses that hold nothing yet, which is where future accounts will be. `address` derives for any index straight from the master, so a caller can enumerate hidden profiles' addresses too. This is the sharpest cost in the design. - **A paired device.** Can run any of these commands, because they are not blocked from one: `export master` reads the whole wallet, `create` on a device that has none plants a seed the pairing controls, and `delete` destroys the only copy. Blocking `ExecChatStoreSQL` while allowing `export master` is not a coherent line, and the wallet commands need their own decision rather than the catch-all. -- **Someone reading the logs.** A remote session logs a command's verb and nothing else, so a phrase typed into `create` stays out of the log, and an answer is never logged at all. +- **Someone reading the logs.** A remote session logs the whole command line at debug level, so a phrase typed into `create` reaches the log there. Answers are never logged. Narrowing that line is work in the remote session rather than in the wallet. - **A page open in the user's browser.** The websocket server in `apps/simplex-chat/Server.hs` accepts any local connection, asks for no token and checks no `Origin`, and websockets are not bound by the same origin policy, so any page loaded while that server runs can send `export master` and read the answer. It also prints every command it receives, that phrase included. Both are properties of that server, which this change gives something worth taking, and closing them is work there rather than in the wallet. ## Known limits diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 1067ae92ec..69aca6ab3e 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."33e8ef018e8080bc8134ea8bd5ad20b3b2afe987" = "0n0d0hdk8zs49wxvbyb2mklv8lwgjnm2gdanbh5z00dgm6m7rdby"; + "https://github.com/simplex-chat/simplexmq.git"."7dcd89d30bdf06913b03f3884bad987b75a6744a" = "0357ak8sxdm6vh103gjdvd073w6lsa2yc8mv1iis937w270siwqn"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index 366b80917d..82dc113452 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -45,7 +45,6 @@ library Simplex.Chat.Badges.Service Simplex.Chat.Badges.Types Simplex.Chat.Names - Simplex.Chat.Store.Wallets Simplex.Chat.Wallet Simplex.Chat.Call Simplex.Chat.Controller @@ -96,6 +95,7 @@ library Simplex.Chat.Store.RelayRequests Simplex.Chat.Store.Remote Simplex.Chat.Store.Shared + Simplex.Chat.Store.Wallets Simplex.Chat.Styled Simplex.Chat.Types Simplex.Chat.Types.MemberRelations diff --git a/src/Simplex/Chat/Remote.hs b/src/Simplex/Chat/Remote.hs index 7be5cd1707..4de4f4f6b7 100644 --- a/src/Simplex/Chat/Remote.hs +++ b/src/Simplex/Chat/Remote.hs @@ -552,8 +552,7 @@ liftRC = liftError (ChatErrorRemoteCtrl . RCEProtocolError) handleSend :: (ByteString -> Int -> CM' (Either ChatError ChatResponse)) -> Text -> Int -> CM' RemoteResponse handleSend execCC command retryNum = do - -- only the verb: the rest of the line can carry a mnemonic - logDebug $ "Send: " <> T.takeWhile (/= ' ') command + logDebug $ "Send: " <> tshow command -- execCC is execChatCommand CSRemoteCtrl, which checks allowRemoteCommand -- convert errors thrown in execCC into error responses to prevent aborting the protocol wrapper RRChatResponse . eitherToResult <$> execCC (encodeUtf8 command) retryNum diff --git a/tests/PostgresSchemaDump.hs b/tests/PostgresSchemaDump.hs index 55344c3bce..0c6305b52d 100644 --- a/tests/PostgresSchemaDump.hs +++ b/tests/PostgresSchemaDump.hs @@ -9,7 +9,7 @@ import Control.Concurrent (threadDelay) import Control.DeepSeq import Control.Monad (unless, void) import qualified Data.ByteString.Char8 as B -import Data.Maybe (isNothing) +import Data.Maybe (fromJust, isJust, isNothing) import Simplex.Messaging.Agent.Store.Postgres (closeDBStore, createDBStore) import Simplex.Messaging.Agent.Store.Postgres.Common (DBOpts (..)) import qualified Simplex.Messaging.Agent.Store.Postgres.Migrations as Migrations @@ -39,26 +39,24 @@ postgresSchemaDumpTest migrations testDBOpts@DBOpts {connstr, schema = testDBSch st <- createDBStore testDBOpts noDownMigrations (MigrationConfig MCYesUpDown Nothing) >>= \case Right st -> pure st Left e -> error $ show e - mapM_ (testDownMigration st) $ drop (length noDownMigrations) migrations + mapM_ (testDownMigration st) $ filter (isJust . down) $ drop (length noDownMigrations) migrations closeDBStore st whenM (doesFileExist testSchemaPath) $ removeFile testSchemaPath where - testDownMigration st m = case toDownMigration m of - -- a migration with no reverse step is applied, there is nothing to test - Nothing -> Migrations.run st Nothing $ MTRUp [m] - Just downMigr -> do - putStrLn $ "down migration " <> name m - schema <- getSchema testSchemaPath - Migrations.run st Nothing $ MTRUp [m] - schema' <- getSchema testSchemaPath - schema' `shouldNotBe` schema - Migrations.run st Nothing $ MTRDown [downMigr] - unless (name m `elem` skipComparisonForDownMigrations) $ do - schema'' <- getSchema testSchemaPath - schema'' `shouldBe` schema - Migrations.run st Nothing $ MTRUp [m] - schema''' <- getSchema testSchemaPath - schema''' `shouldBe` schema' + testDownMigration st m = do + putStrLn $ "down migration " <> name m + let downMigr = fromJust $ toDownMigration m + schema <- getSchema testSchemaPath + Migrations.run st Nothing $ MTRUp [m] + schema' <- getSchema testSchemaPath + schema' `shouldNotBe` schema + Migrations.run st Nothing $ MTRDown [downMigr] + unless (name m `elem` skipComparisonForDownMigrations) $ do + schema'' <- getSchema testSchemaPath + schema'' `shouldBe` schema + Migrations.run st Nothing $ MTRUp [m] + schema''' <- getSchema testSchemaPath + schema''' `shouldBe` schema' getSchema :: FilePath -> IO String getSchema schemaPath = do diff --git a/tests/SchemaDump.hs b/tests/SchemaDump.hs index 51e8eb4221..814183b15b 100644 --- a/tests/SchemaDump.hs +++ b/tests/SchemaDump.hs @@ -13,7 +13,7 @@ import qualified Control.Exception as E import Control.Monad (unless, void) import Data.List (sort) import qualified Data.Map.Strict as M -import Data.Maybe (isNothing) +import Data.Maybe (fromJust, isJust, isNothing) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T @@ -81,28 +81,26 @@ testSchemaMigrations :: IO () testSchemaMigrations = withTmpFiles $ do let noDownMigrations = takeWhile (\Migration {down} -> isNothing down) Store.migrations Right st <- createDBStore (DBOpts testDB chatDBFunctions "" False True TQOff) noDownMigrations (MigrationConfig MCError Nothing) - mapM_ (testDownMigration st) $ drop (length noDownMigrations) Store.migrations + mapM_ (testDownMigration st) $ filter (isJust . down) $ drop (length noDownMigrations) Store.migrations closeDBStore st removeFile testDB whenM (doesFileExist testSchema) $ removeFile testSchema where - testDownMigration st m = case toDownMigration m of - -- a migration with no reverse step is applied, there is nothing to test - Nothing -> Migrations.run st Nothing True $ MTRUp [m] - Just downMigr -> do - putStrLn $ "down migration " <> name m - schema <- getSchema testDB testSchema - Migrations.run st Nothing True $ MTRUp [m] - schema' <- getSchema testDB testSchema - unless (name m `elem` skipComparisonForUpMigrations) $ - schema' `shouldNotBe` schema - Migrations.run st Nothing True $ MTRDown [downMigr] - unless (name m `elem` skipComparisonForDownMigrations) $ do - schema'' <- getSchema testDB testSchema - schema'' `shouldBe` schema - Migrations.run st Nothing True $ MTRUp [m] - schema''' <- getSchema testDB testSchema - schema''' `shouldBe` schema' + testDownMigration st m = do + putStrLn $ "down migration " <> name m + let downMigr = fromJust $ toDownMigration m + schema <- getSchema testDB testSchema + Migrations.run st Nothing True $ MTRUp [m] + schema' <- getSchema testDB testSchema + unless (name m `elem` skipComparisonForUpMigrations) $ + schema' `shouldNotBe` schema + Migrations.run st Nothing True $ MTRDown [downMigr] + unless (name m `elem` skipComparisonForDownMigrations) $ do + schema'' <- getSchema testDB testSchema + schema'' `shouldBe` schema + Migrations.run st Nothing True $ MTRUp [m] + schema''' <- getSchema testDB testSchema + schema''' `shouldBe` schema' testVerifyStrict :: IO () testVerifyStrict = do