mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-27 20:08:34 +00:00
show name derivation index as well in list
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@ needs a wallet, ETH and a browser:
|
||||
service - metering is off chain.
|
||||
- See what you own with `/names` and `/name info`, and find names your keys
|
||||
already hold with `/name rescan`.
|
||||
- Recovery keys: `/name keys` (names grouped by the account they sit under),
|
||||
- Recovery keys: `/name keys` (names grouped by account, each with its index),
|
||||
`keys export` (every key, not just the one in use), `keys import` (adds, never
|
||||
replaces), `keys init`, `keys use <n> [<account> [<name>]]`.
|
||||
- Recovering on a new device: `/name rescan` restores the derivation marks from
|
||||
|
||||
@@ -74,9 +74,12 @@ Recovery keys:
|
||||
|
||||
```
|
||||
/name keys 1: (in use)
|
||||
account 0 alice.simplex
|
||||
account 0
|
||||
name 0 alice.simplex
|
||||
name 1 lizzy.simplex
|
||||
2: (not written down)
|
||||
other lucy.simplex (m)
|
||||
other
|
||||
lucy.simplex m
|
||||
|
||||
/name keys export every key's phrase, each labelled with the names
|
||||
it controls - never just the one in use
|
||||
@@ -88,8 +91,9 @@ Recovery keys:
|
||||
/name keys use 2 0 5 ...and where its next name sits
|
||||
```
|
||||
|
||||
Names are listed under the account they were derived at, because that grouping
|
||||
is the only surviving record of which profile owned what — see *Recovery*.
|
||||
Names are listed under the account they were derived at, with their index in it
|
||||
— the two numbers `/name keys use` takes. That grouping is the only surviving
|
||||
record of which profile owned what; see *Recovery*.
|
||||
|
||||
A new device, with nothing but the phrase:
|
||||
|
||||
@@ -457,8 +461,8 @@ it, not on chain, and not derivable:
|
||||
|
||||
* **Which profile held which account.** Recreate two profiles on a new device and
|
||||
nothing says which was account 0. Only the user knows, so `/name keys` groups
|
||||
names by the account in their stored path and `/name keys use <n> <account>`
|
||||
pins a profile back to one.
|
||||
names by the account and index in their stored path, and
|
||||
`/name keys use <n> <account>` pins a profile back to one.
|
||||
* **Which indices are already taken.** Both high-water marks — `next_account_index`
|
||||
per seed, `wallet_next_name_index` per profile — start at 0 after an import,
|
||||
while accounts and names already exist under the phrase. A scan is the only
|
||||
|
||||
@@ -861,7 +861,7 @@ data ChatResponse
|
||||
| CRNameInfo {user :: User, regName :: Text, regOwner :: Text, regPath :: Text, nameContact :: [Text], nameChannel :: [Text], regExpiry :: UTCTime, nameEditsLeft :: Word32}
|
||||
| CRNameLinkSet {user :: User, regName :: Text, nameRecord :: Text, regTxHash :: TxHash}
|
||||
| CRNameRescan {user :: User, namesFound :: [(Text, Text)]}
|
||||
| CRNameKeys {user :: User, walletKeys :: [(Int, [(Maybe AccountIndex, [(Text, Text)])], Bool, Bool)]}
|
||||
| CRNameKeys {user :: User, walletKeys :: [(Int, [(Maybe AccountIndex, [(Maybe NameIndex, Text, Text)])], Bool, Bool)]}
|
||||
| CRNameKeyPhrases {user :: User, walletPhrases :: [(Int, Text, [Text])]}
|
||||
| CRUserAcceptedGroupSent {user :: User, groupInfo :: GroupInfo, hostContact :: Maybe Contact}
|
||||
| CRUserDeletedMembers {user :: User, groupInfo :: GroupInfo, members :: [GroupMember], withMessages :: Bool, msgSigned :: Bool}
|
||||
|
||||
@@ -66,7 +66,7 @@ import Simplex.Chat.Names.Protocol
|
||||
import Simplex.Chat.Names.Snrc (Intent (..), SnrcDeployment (..), intent712, parseRecordKey)
|
||||
import Simplex.Messaging.Eth.Address (Address, mkAddress)
|
||||
import Simplex.Chat.Store.Wallets (bindSeedAccount, boundAccount, createSeed, currentSeed, getNameKeys, getOrCreateAccountRef, listSeeds, markBackedUp, nameKeyPathTaken, raiseNextAccountIndex, raiseNextNameIndex, recordNameKey, seedOfName, setCurrentSeed, setNextNameIndex, takeNameIndex)
|
||||
import Simplex.Chat.Wallet (AccountIndex, AccountRef (..), SeedId, WalletAccount, WalletSeed (..), accountAddress, deriveAtPath, deriveNameKey, ethSignatureBytes, importRecoveryKey, newSeed, parseNameKeyPath, recoveryKeyPhrase, renderNameKeyPath, signIntent)
|
||||
import Simplex.Chat.Wallet (AccountIndex, AccountRef (..), NameIndex, SeedId, WalletAccount, WalletSeed (..), accountAddress, deriveAtPath, deriveNameKey, ethSignatureBytes, importRecoveryKey, newSeed, parseNameKeyPath, recoveryKeyPhrase, renderNameKeyPath, signIntent)
|
||||
import Simplex.Chat.Call
|
||||
import Simplex.Chat.Controller
|
||||
import Simplex.Chat.Delivery (DeliveryJobScope (..), DeliveryJobSpec (..), DeliveryWorkerScope (..))
|
||||
@@ -5246,13 +5246,18 @@ deriveNameOwner user = do
|
||||
taken <- withFastStore' $ \db -> nameKeyPathTaken db sId path
|
||||
if taken then freeNameIndex sId acctIx (tries + 1) else pure (nameIx, path)
|
||||
|
||||
-- | Names a seed owns, grouped by the account they were derived under. Names on
|
||||
-- a layout that is not ours have no account of ours and group under Nothing.
|
||||
groupByAccount :: [(Text, Text)] -> [(Maybe AccountIndex, [(Text, Text)])]
|
||||
-- | Names a seed owns, grouped by the account they were derived under and
|
||||
-- carrying the name index within it — the two numbers @\/name keys use@ takes.
|
||||
-- Names on a layout that is not ours have neither, and group under Nothing.
|
||||
groupByAccount :: [(Text, Text)] -> [(Maybe AccountIndex, [(Maybe NameIndex, Text, Text)])]
|
||||
groupByAccount ns =
|
||||
-- stable, so the accounts keep their order and the ungrouped names sort last
|
||||
sortOn (isNothing . fst) . M.toAscList . M.fromListWith (flip (<>)) $
|
||||
map (\(n, path) -> (fst <$> parseNameKeyPath path, [(n, path)])) ns
|
||||
map (fmap (sortOn (\(ix_, _, _) -> ix_))) . sortOn (isNothing . fst) . M.toAscList . M.fromListWith (flip (<>)) $
|
||||
map entry ns
|
||||
where
|
||||
entry (n, path) = case parseNameKeyPath path of
|
||||
Just (acctIx, nameIx) -> (Just acctIx, [(Just nameIx, n, path)])
|
||||
Nothing -> (Nothing, [(Nothing, n, path)])
|
||||
|
||||
-- | Names this device holds a key for, with the path each key sits at.
|
||||
ownedNames :: User -> CM [(Text, Text)]
|
||||
|
||||
@@ -232,13 +232,18 @@ chatResponseToView hu cfg@ChatConfig {logLevel, showReactions, showFullLinks, te
|
||||
-- the phrase, so after importing on a new device this listing is what tells
|
||||
-- the user which account to pin a profile back to.
|
||||
CRNameKeys u rows ->
|
||||
let name acct (n, path) = if isJust acct then n else n <> " (" <> path <> ")"
|
||||
accountRow (acct, ns) =
|
||||
let pad w t = t <> T.replicate (max 1 (w - T.length t)) " "
|
||||
-- the index is shown because it is the third argument of
|
||||
-- /name keys use; a name on a foreign layout has none, so it shows the
|
||||
-- path that replaces it
|
||||
nameRow (ix_, n, path) =
|
||||
plain $
|
||||
" "
|
||||
<> maybe "other " (\a -> "account " <> tshow a) acct
|
||||
<> " "
|
||||
<> T.intercalate ", " (map (name acct) ns)
|
||||
" "
|
||||
<> pad 9 (maybe "" (\ix -> "name " <> tshow ix) ix_)
|
||||
<> n
|
||||
<> maybe (" " <> path) (const "") ix_
|
||||
accountRow (acct, ns) =
|
||||
plain (" " <> maybe "other" (\a -> "account " <> tshow a) acct) : map nameRow ns
|
||||
keyRow (i, groups, cur, backed) =
|
||||
plain
|
||||
( tshow i
|
||||
@@ -246,7 +251,7 @@ chatResponseToView hu cfg@ChatConfig {logLevel, showReactions, showFullLinks, te
|
||||
<> (if cur then " (in use)" else "")
|
||||
<> (if backed then "" else " (not written down)")
|
||||
)
|
||||
: if null groups then [" no names yet"] else map accountRow groups
|
||||
: if null groups then [" no names yet"] else concatMap accountRow groups
|
||||
in ttyUser u $ case rows of
|
||||
[] -> ["no recovery keys yet - one is created when you buy a name"]
|
||||
_ -> concatMap keyRow rows
|
||||
|
||||
@@ -154,7 +154,8 @@ testNameAddress ps =
|
||||
-- and now exactly one key exists, controlling the name just bought
|
||||
client ##> "/name keys"
|
||||
client <## "1: (in use) (not written down)"
|
||||
client <## " account 0 carolname.simplex"
|
||||
client <## " account 0"
|
||||
client <## " name 0 carolname.simplex"
|
||||
|
||||
-- | Recovery on a new device must not re-use a key a recovered name already
|
||||
-- owns. Neither high-water mark survives an import - the phrase records only
|
||||
@@ -197,8 +198,10 @@ testRecoverMarks ps = do
|
||||
-- the scan moved both marks past index 0, so the new name is elsewhere
|
||||
client ##> "/name keys"
|
||||
client <## "1: (in use) (not written down)"
|
||||
client <## " account 0 lostname.simplex"
|
||||
client <## " account 1 foundname.simplex"
|
||||
client <## " account 0"
|
||||
client <## " name 0 lostname.simplex"
|
||||
client <## " account 1"
|
||||
client <## " name 1 foundname.simplex"
|
||||
|
||||
-- | A scan is one round trip per candidate path, taken sequentially, and
|
||||
-- outruns the harness's five second per-line read timeout. Retrying is not
|
||||
@@ -263,7 +266,9 @@ testSeedPersists ps = do
|
||||
withTestChat ps "client" $ \client -> do
|
||||
client ##> "/name keys"
|
||||
client <## "1: (in use) (not written down)"
|
||||
client <## " account 0 firstname.simplex, secondname.simplex"
|
||||
client <## " account 0"
|
||||
client <## " name 0 firstname.simplex"
|
||||
client <## " name 1 secondname.simplex"
|
||||
|
||||
-- | Reads past startup and progress lines to the registration result, returning
|
||||
-- the owner address. Keeps reading until the final progress event has arrived
|
||||
|
||||
Reference in New Issue
Block a user