mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-06 01:18:11 +00:00
another adversarial review's fixes
This commit is contained in:
@@ -858,7 +858,7 @@ data ChatResponse
|
||||
| CRNameQuote {user :: User, nameLabel :: Text, nameAvailable :: Bool, nameReserved :: Bool, namePriceUsdCents :: Word32, nameYears :: Word32}
|
||||
| CRNameCode {user :: User, codeMinLength :: Int, nameYears :: Word32, codeExpires :: UTCTime}
|
||||
| CRNames {user :: User, namesOwned :: [(Text, Text, UTCTime, Word32)]}
|
||||
| CRNameInfo {user :: User, regName :: Text, regOwner :: Text, regPath :: Text, nameContact :: [Text], nameChannel :: [Text], regExpiry :: UTCTime, nameEditsLeft :: Word32}
|
||||
| CRNameInfo {user :: User, regName :: Text, regOwner :: Text, regOwnerIsOurs :: Bool, 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, [(Maybe NameIndex, Text, Text)])], Bool, Bool)]}
|
||||
|
||||
@@ -63,7 +63,7 @@ import Simplex.Chat.Library.Subscriber
|
||||
import Simplex.Chat.Badges (BadgeCredential (..), LocalBadge (..), maxXFTPFileSize, mkBadgeStatus, verifyCredential)
|
||||
import Simplex.Chat.Names (SimplexDomainProof (..), SimplexDomainClaim (..), claimDomain, mkDomainClaim)
|
||||
import Simplex.Chat.Names.Protocol
|
||||
import Simplex.Chat.Names.Snrc (Intent (..), SignedIntent (..), SnrcDeployment (..), parseRecordKey, signSnrcIntent)
|
||||
import Simplex.Chat.Names.Snrc (Intent (..), SignedIntent (..), SnrcDeployment (..), devChainId, parseRecordKey, signSnrcIntent)
|
||||
import Simplex.Messaging.Eth.Address (Address, mkAddress)
|
||||
import Simplex.Chat.Store.Wallets (bindSeedAccount, createSeed, currentSeed, getNameKeys, getOrCreateAccountRef, listSeeds, markBackedUp, nameKeyPathTaken, raiseNextAccountIndex, raiseNextNameIndex, recordNameKey, seedOfName, setCurrentSeed, setNextNameIndex, takeNameIndex)
|
||||
import Simplex.Chat.Wallet (AccountIndex, AccountRef (..), NameIndex, SeedId, WalletAccount, WalletSeed (..), accountAddress, deriveAtPath, deriveNameKey, ethSignatureBytes, importRecoveryKey, newSeed, parseNameKeyPath, recoveryKeyPhrase, renderNameKeyPath)
|
||||
@@ -1511,10 +1511,14 @@ processChatCommand cxt nm = \case
|
||||
pure $ CRNames user rows
|
||||
APINameInfo sendTarget nm' -> withUser $ \user -> do
|
||||
cReq <- resolveServiceTarget nm user sendTarget
|
||||
(_, path, _) <- nameKeyOf nm'
|
||||
(_, path, acc) <- nameKeyOf nm'
|
||||
namesRPC user cReq (NRResolve nm') >>= \case
|
||||
NRPRecord {nrName, nrOwner, nrContact, nrChannel, nrExpiry, nrEditsLeft} ->
|
||||
pure $ CRNameInfo user nrName (tshow nrOwner) path nrContact nrChannel nrExpiry nrEditsLeft
|
||||
NRPRecord {nrName, nrOwner, nrContact, nrChannel, nrExpiry, nrEditsLeft} -> do
|
||||
-- The service's word against our own key. A registrar that misreports
|
||||
-- the owner cannot be caught anywhere else, and we are holding the
|
||||
-- address it should have named.
|
||||
let ours = accountAddress acc
|
||||
pure $ CRNameInfo user nrName (tshow nrOwner) (nrOwner == ours) path nrContact nrChannel nrExpiry nrEditsLeft
|
||||
_ -> throwCmdError "unexpected resolve response"
|
||||
APINameSetLink sendTarget nm' record lnk -> withUser $ \user -> do
|
||||
cReq <- resolveServiceTarget nm user sendTarget
|
||||
@@ -5208,7 +5212,9 @@ clientDeployment :: SnrcDeployment
|
||||
clientDeployment =
|
||||
SnrcDeployment
|
||||
{ sdTld = "simplex",
|
||||
sdChainId = 1,
|
||||
-- Not 1: these are placeholder contracts, and a domain separator that
|
||||
-- says "mainnet" is one that a real deployment could be made to accept.
|
||||
sdChainId = devChainId,
|
||||
sdRegistrar = mockClientAddr 1,
|
||||
sdResolver = mockClientAddr 2
|
||||
}
|
||||
|
||||
@@ -239,6 +239,7 @@ data NamesErrorCode
|
||||
| NECInternal
|
||||
| NECNameReserved
|
||||
| NECNameTooShort
|
||||
| NECNameInvalid
|
||||
| NECPaymentRejected
|
||||
| NECCodeSpent
|
||||
| NECCodeExpired
|
||||
@@ -259,6 +260,7 @@ instance TextEncoding NamesErrorCode where
|
||||
NECInternal -> "internal"
|
||||
NECNameReserved -> "name_reserved"
|
||||
NECNameTooShort -> "name_too_short"
|
||||
NECNameInvalid -> "name_invalid"
|
||||
NECPaymentRejected -> "payment_rejected"
|
||||
NECCodeSpent -> "code_spent"
|
||||
NECCodeExpired -> "code_expired"
|
||||
@@ -276,6 +278,7 @@ instance TextEncoding NamesErrorCode where
|
||||
"internal" -> NECInternal
|
||||
"name_reserved" -> NECNameReserved
|
||||
"name_too_short" -> NECNameTooShort
|
||||
"name_invalid" -> NECNameInvalid
|
||||
"payment_rejected" -> NECPaymentRejected
|
||||
"code_spent" -> NECCodeSpent
|
||||
"code_expired" -> NECCodeExpired
|
||||
|
||||
@@ -20,6 +20,7 @@ module Simplex.Chat.Names.Snrc
|
||||
intent712,
|
||||
intentDigest,
|
||||
signSnrcIntent,
|
||||
devChainId,
|
||||
)
|
||||
where
|
||||
|
||||
@@ -76,6 +77,12 @@ data SignedIntent = SignedIntent
|
||||
setTextTypeString :: ByteString
|
||||
setTextTypeString = "SetText(bytes32 node,string key,string value,uint256 nonce,uint256 deadline)"
|
||||
|
||||
-- | The chain the placeholder deployment claims. Deliberately not 1: signatures
|
||||
-- carry their chain id, and one that reads as mainnet is one that a contract
|
||||
-- deployed at the placeholder address could later be made to honour.
|
||||
devChainId :: Integer
|
||||
devChainId = 31337
|
||||
|
||||
labelHash :: ByteString -> ByteString
|
||||
labelHash = keccak256
|
||||
|
||||
|
||||
@@ -211,10 +211,10 @@ chatResponseToView hu cfg@ChatConfig {logLevel, showReactions, showFullLinks, te
|
||||
ttyUser u $ case rows of
|
||||
[] -> ["no names yet - buy one with /name buy <label> <code>"]
|
||||
_ -> map (\(n, points, expiry, edits) -> plain $ " " <> n <> " -> " <> points <> " expires " <> tshow expiry <> ", " <> tshow edits <> " edits left") rows
|
||||
CRNameInfo u n owner path contact channel expiry edits ->
|
||||
CRNameInfo u n owner ourKey path contact channel expiry edits ->
|
||||
ttyUser u $
|
||||
[ plain $ n,
|
||||
plain $ " owner " <> owner,
|
||||
plain $ " owner " <> owner <> (if ourKey then " (matches your key)" else " (NOT your key)"),
|
||||
plain $ " path " <> path
|
||||
]
|
||||
<> map (\c -> plain $ " contact " <> c) contact
|
||||
|
||||
@@ -218,10 +218,20 @@ signIntent a Eip712Intent {eiDomain, eiTypeString, eiValues} = do
|
||||
}
|
||||
|
||||
-- | Parse @r || s || v@ as it arrives from a client.
|
||||
-- | Half the secp256k1 group order. EIP-2 accepts only the lower half: for
|
||||
-- every signature there is a second one at @n - s@ that recovers the same
|
||||
-- signer, and accepting both means one authorisation has two identities.
|
||||
secp256k1HalfN :: Integer
|
||||
secp256k1HalfN = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
|
||||
|
||||
parseEthSignature :: ByteString -> Either String EthSignature
|
||||
parseEthSignature bs
|
||||
| B.length bs /= 65 = Left "signature: expected 65 bytes"
|
||||
| otherwise = Right EthSignature {esR = B.take 32 bs, esS = B.take 32 (B.drop 32 bs), esV = B.last bs}
|
||||
| beInteger s > secp256k1HalfN = Left "signature: s is not canonical (EIP-2)"
|
||||
| otherwise = Right EthSignature {esR = B.take 32 bs, esS = s, esV = B.last bs}
|
||||
where
|
||||
s = B.take 32 (B.drop 32 bs)
|
||||
beInteger = B.foldl' (\acc w -> acc * 256 + fromIntegral w) 0
|
||||
|
||||
-- | Recover the address that produced a signature over a digest — what the
|
||||
-- relayer and the contracts do.
|
||||
|
||||
Reference in New Issue
Block a user