mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-23 08:33:09 +00:00
next review round
This commit is contained in:
1 parent
faa96e3da7
commit
6b908c87e0
5 files changed
+104
-11
No files matched your search
@@ -66,7 +66,7 @@ import Simplex.Chat.Badges.Code (badgeCodeText, parseBadgeCode)
|
||||
import Simplex.Chat.Badges.Service (BadgeBalance (..), BadgeServiceCommand (..), BadgeServiceErrorCode (..), BadgeServiceRequest (..), BadgeServiceResponse (..), BadgeStatement (..), StatementDebitType (..), StatementEntry (..), StatementEntryType (..), currentBadgeServiceVersion)
|
||||
import Simplex.Chat.Names (SimplexDomainProof (..), SimplexDomainClaim (..), claimDomain, mkDomainClaim)
|
||||
import Simplex.Chat.Store.Wallets (WalletSeed (..), accountHeldByOther, bindAccount, createWalletSeed, deleteWalletSeed, getUserAccounts, getWalletSeed, resolveAccount)
|
||||
import Simplex.Chat.Wallet (AccountIndex, AccountKey, WalletAddress (..), WalletError (..), accountSecret, checkAccountIndex, deriveAccountKey, entropyFromMnemonic, newSeedEntropy, renderAccountPath, seedMaster, seedMnemonic)
|
||||
import Simplex.Chat.Wallet (AccountIndex, AccountKey, WalletAddress (..), WalletError (..), accountSecret, deriveAccountKey, entropyFromMnemonic, newSeedEntropy, renderAccountPath, seedMaster, seedMnemonic)
|
||||
import Simplex.Messaging.Eth.Address (addressFromPrivateKey)
|
||||
import Simplex.Chat.Call
|
||||
import Simplex.Chat.Controller
|
||||
@@ -1520,8 +1520,7 @@ processChatCommand cxt nm = \case
|
||||
APIExportWalletMnemonic -> withUser $ \user ->
|
||||
CRWalletMnemonic user <$> (liftWallet . seedMnemonic . wsEntropy =<< walletSeed)
|
||||
APIExportWalletAccount n -> withUser $ \user@User {userId} -> do
|
||||
seed <- walletSeed
|
||||
liftWallet $ checkAccountIndex n
|
||||
(seed, _) <- liftWallet =<< withFastStore' (`resolveAccount` Just n)
|
||||
-- a key another profile holds is not this profile's to hand out
|
||||
heldByOther <- withFastStore' $ \db -> accountHeldByOther db (wsId seed) userId n
|
||||
when heldByOther $ throwWalletError WEAccountBound
|
||||
@@ -6643,11 +6642,11 @@ chatCommandP =
|
||||
quotedP = safeDecodeUtf8 <$> (A.char '"' *> A.takeTill (== '"') <* A.char '"')
|
||||
text1P = safeDecodeUtf8 <$> A.takeTill (== ' ')
|
||||
char_ = optional . A.char
|
||||
-- ten digits fit an Int, and the hardening bound is a typed error when the command runs
|
||||
-- a long digit run is not free to convert; the hardening bound is checked when the command runs
|
||||
accountIndexP = do
|
||||
ds <- A.takeWhile1 isDigit
|
||||
case if B.length ds <= 10 then B.readInt ds else Nothing of
|
||||
Just (i, _) | i <= fromIntegral (maxBound :: AccountIndex) -> pure $ fromIntegral i
|
||||
case if B.length ds <= 10 then B.readInteger ds else Nothing of
|
||||
Just (i, _) | i <= toInteger (maxBound :: AccountIndex) -> pure (fromInteger i)
|
||||
_ -> fail "account index too large"
|
||||
|
||||
displayNameP :: Parser Text
|
||||
|
||||
@@ -1724,6 +1724,49 @@ ALTER TABLE test_chat_schema.users ALTER COLUMN user_id ADD GENERATED ALWAYS AS
|
||||
|
||||
|
||||
|
||||
CREATE TABLE test_chat_schema.wallet_accounts (
|
||||
wallet_account_id bigint NOT NULL,
|
||||
wallet_seed_id bigint NOT NULL,
|
||||
account_index bigint,
|
||||
user_id bigint,
|
||||
CONSTRAINT wallet_accounts_account_index_check CHECK (((account_index >= 0) AND (account_index <= 2147483647)))
|
||||
);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE test_chat_schema.wallet_accounts ALTER COLUMN wallet_account_id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME test_chat_schema.wallet_accounts_wallet_account_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE test_chat_schema.wallet_seeds (
|
||||
wallet_seed_id bigint NOT NULL,
|
||||
entropy bytea NOT NULL,
|
||||
next_account_index bigint,
|
||||
single_seed smallint DEFAULT 1 NOT NULL,
|
||||
CONSTRAINT wallet_seeds_entropy_check CHECK ((length(entropy) = 32)),
|
||||
CONSTRAINT wallet_seeds_next_account_index_check CHECK (((next_account_index >= 0) AND (next_account_index <= '2147483648'::bigint)))
|
||||
);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE test_chat_schema.wallet_seeds ALTER COLUMN wallet_seed_id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME test_chat_schema.wallet_seeds_wallet_seed_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE test_chat_schema.xftp_file_descriptions (
|
||||
file_descr_id bigint NOT NULL,
|
||||
user_id bigint NOT NULL,
|
||||
@@ -2137,6 +2180,16 @@ ALTER TABLE ONLY test_chat_schema.users
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.wallet_accounts
|
||||
ADD CONSTRAINT wallet_accounts_pkey PRIMARY KEY (wallet_account_id);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.wallet_seeds
|
||||
ADD CONSTRAINT wallet_seeds_pkey PRIMARY KEY (wallet_seed_id);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.xftp_file_descriptions
|
||||
ADD CONSTRAINT xftp_file_descriptions_pkey PRIMARY KEY (file_descr_id);
|
||||
|
||||
@@ -2938,6 +2991,18 @@ CREATE INDEX idx_users_shown_badge ON test_chat_schema.users USING btree (shown_
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_wallet_accounts_user_id ON test_chat_schema.wallet_accounts USING btree (user_id);
|
||||
|
||||
|
||||
|
||||
CREATE UNIQUE INDEX idx_wallet_accounts_wallet_seed_id_account_index ON test_chat_schema.wallet_accounts USING btree (wallet_seed_id, account_index);
|
||||
|
||||
|
||||
|
||||
CREATE UNIQUE INDEX idx_wallet_seeds_single_seed ON test_chat_schema.wallet_seeds USING btree (single_seed);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX idx_xftp_file_descriptions_user_id ON test_chat_schema.xftp_file_descriptions USING btree (user_id);
|
||||
|
||||
|
||||
@@ -3663,6 +3728,16 @@ ALTER TABLE ONLY test_chat_schema.users
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.wallet_accounts
|
||||
ADD CONSTRAINT wallet_accounts_user_id_fkey FOREIGN KEY (user_id) REFERENCES test_chat_schema.users(user_id) ON DELETE SET NULL;
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.wallet_accounts
|
||||
ADD CONSTRAINT wallet_accounts_wallet_seed_id_fkey FOREIGN KEY (wallet_seed_id) REFERENCES test_chat_schema.wallet_seeds(wallet_seed_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
|
||||
ALTER TABLE ONLY test_chat_schema.xftp_file_descriptions
|
||||
ADD CONSTRAINT xftp_file_descriptions_user_id_fkey FOREIGN KEY (user_id) REFERENCES test_chat_schema.users(user_id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
@@ -975,6 +975,18 @@ CREATE TABLE badge_code_redemptions(
|
||||
created_at TEXT NOT NULL,
|
||||
UNIQUE(user_id, code)
|
||||
) STRICT;
|
||||
CREATE TABLE wallet_seeds(
|
||||
wallet_seed_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
entropy BLOB NOT NULL CHECK(length(entropy) = 32), -- BIP-39 entropy, 24 words
|
||||
next_account_index INTEGER CHECK(next_account_index BETWEEN 0 AND 2147483648),
|
||||
single_seed INTEGER NOT NULL DEFAULT 1
|
||||
) STRICT;
|
||||
CREATE TABLE wallet_accounts(
|
||||
wallet_account_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
wallet_seed_id INTEGER NOT NULL REFERENCES wallet_seeds ON DELETE CASCADE,
|
||||
account_index INTEGER CHECK(account_index BETWEEN 0 AND 2147483647),
|
||||
user_id INTEGER REFERENCES users ON DELETE SET NULL
|
||||
) STRICT;
|
||||
CREATE INDEX contact_profiles_index ON contact_profiles(
|
||||
display_name,
|
||||
full_name
|
||||
@@ -1538,6 +1550,12 @@ CREATE INDEX idx_badge_code_redemptions_user ON badge_code_redemptions(
|
||||
CREATE UNIQUE INDEX idx_badge_purchases_code_redemption ON badge_purchases(
|
||||
badge_code_redemption_id
|
||||
);
|
||||
CREATE UNIQUE INDEX idx_wallet_seeds_single_seed ON wallet_seeds(single_seed);
|
||||
CREATE UNIQUE INDEX idx_wallet_accounts_wallet_seed_id_account_index ON wallet_accounts(
|
||||
wallet_seed_id,
|
||||
account_index
|
||||
);
|
||||
CREATE INDEX idx_wallet_accounts_user_id ON wallet_accounts(user_id);
|
||||
CREATE TRIGGER on_group_members_insert_update_summary
|
||||
AFTER INSERT ON group_members
|
||||
FOR EACH ROW
|
||||
|
||||
@@ -19,7 +19,7 @@ module Simplex.Chat.Store.Wallets
|
||||
)
|
||||
where
|
||||
|
||||
import Control.Monad (join, unless, when)
|
||||
import Control.Monad (join, unless)
|
||||
import Control.Monad.Except
|
||||
import Control.Monad.IO.Class (liftIO)
|
||||
import qualified Data.ByteArray as BA
|
||||
@@ -123,10 +123,8 @@ accountHeldByOther db sId userId n = heldByOther userId <$> accountUser db sId n
|
||||
bindAccount :: DB.Connection -> UserId -> Maybe AccountIndex -> IO (Either WalletError ())
|
||||
bindAccount db userId accountIdx_ = runExceptT $ do
|
||||
(WalletSeed {wsId = sId}, n) <- ExceptT $ resolveAccount db accountIdx_
|
||||
held <- liftIO $ accountUser db sId n
|
||||
when (heldByOther userId held) $ throwError WEAccountBound
|
||||
taken <- liftIO $ case held of
|
||||
Just (Just _) -> pure True -- already this profile's
|
||||
taken <- liftIO $ accountUser db sId n >>= \case
|
||||
Just (Just heldBy) -> pure $ heldBy == userId
|
||||
-- the update takes the account only while no profile holds it, the read after says whether this one got it
|
||||
Just Nothing -> setAccountUser db sId userId n >> accountHeldBy db sId userId n
|
||||
Nothing -> True <$ insertAccount db sId userId n
|
||||
|
||||
@@ -198,6 +198,9 @@ testWalletAddress ps = withNewTestChat ps "alice" aliceProfile $ \alice -> do
|
||||
alice ##> "/_wallet address account=3"
|
||||
at3 <- getTermLine alice
|
||||
words at3 !! 1 `shouldBe` "m/44'/60'/3'/0/0"
|
||||
-- a zero-padded index is the same index
|
||||
alice ##> "/_wallet address account=0000000003"
|
||||
getTermLine alice `shouldReturn` at3
|
||||
-- a malformed index is a parse error, never a silent bind of the next account
|
||||
alice ##> "/_wallet bind account=abc"
|
||||
alice <## "bad chat command: Failed reading: empty"
|
||||
|
||||
Reference in new issue
Block a user