simplify encoding

This commit is contained in:
Evgeny Poberezkin
2026-09-11 10:06:33 +01:00
parent ac442e4064
commit c2bd7293db
5 changed files with 29 additions and 60 deletions
-6
View File
@@ -12,7 +12,6 @@ module Simplex.Messaging.Names.Record
NamePricing (..),
USDCents (..),
NameReservedReason (..),
oldRegistration,
)
where
@@ -127,11 +126,6 @@ instance ToJSON NameReservedReason where
instance FromJSON NameReservedReason where
parseJSON = textParseJSON "NameReservedReason"
-- | A v20/v21 router's record as a registration.
oldRegistration :: NameRecord -> NameRegistration
oldRegistration nameRecord =
NRRegistered {expires = Nothing, graceUntil = Nothing, reservedReason_ = Nothing, nameRecord}
$(JQ.deriveJSON defaultJSON ''NamePricing)
-- taggedObjectJSON, not sumTypeJSON: this JSON is the RNAME payload and the
+11 -26
View File
@@ -81,12 +81,10 @@ module Simplex.Messaging.Protocol
CommandError (..),
ProxyError (..),
NameQuery (..),
queryName,
NameRegistration (..),
NamePricing (..),
USDCents (..),
NameReservedReason (..),
oldRegistration,
NameErrorType (..),
BrokerErrorType (..),
NetworkError (..),
@@ -252,7 +250,7 @@ import Data.Constraint (Dict (..))
import Data.Functor (($>))
import Data.Int (Int64)
import Data.Kind
import Data.List (find, foldl')
import Data.List (foldl')
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as L
import Data.Maybe (isJust, isNothing)
@@ -277,7 +275,7 @@ import Simplex.Messaging.Parsers
import Simplex.Messaging.Protocol.Types
import Simplex.Messaging.Server.QueueStore.QueueInfo
import Simplex.Messaging.ServiceScheme
import Simplex.Messaging.SimplexName (LabelHash, SimplexDomain (..), SimplexTLD (..), boundedNonSpace, fullDomainName, labelHash, labelHashOfText, labelHashText, tldSuffix)
import Simplex.Messaging.SimplexName (LabelHash, SimplexDomain (..), SimplexTLD (..), fullDomainName, labelHash)
import Simplex.Messaging.Transport
import Simplex.Messaging.Transport.Client (TransportHost, TransportHosts (..))
import Simplex.Messaging.Util (bshow, eitherToMaybe, safeDecodeUtf8, (<$?>))
@@ -1597,32 +1595,22 @@ data ErrorType
deriving (Eq, Show)
-- | What RSLV asks about: a name, or the hash of a second-level label.
data NameQuery = NQDomain SimplexDomain | NQHash SimplexTLD LabelHash
data NameQuery = NQDomain SimplexDomain | NQHash LabelHash SimplexTLD
deriving (Eq, Show)
instance Encoding NameQuery where
smpEncode = encodeUtf8 . queryName
smpP = nameQueryOf . safeDecodeUtf8 <$?> boundedNonSpace
-- | A hashed label is bracketed, which no name can be, so no tag is needed.
nameQueryOf :: Text -> Either String NameQuery
nameQueryOf t = case find ((`T.isSuffixOf` t) . tldSuffix) ([TLDSimplex, TLDTesting] :: [SimplexTLD]) of
Just tld | Just h <- labelHashOfText (T.dropEnd (T.length (tldSuffix tld)) t) -> Right (NQHash tld h)
_ -> NQDomain <$> strDecode (encodeUtf8 t)
smpEncode = \case
NQDomain d -> encodeUtf8 $ fullDomainName d
NQHash h tld -> strEncode h <> strEncode tld
smpP = NQHash <$> strP <*> strP <|> NQDomain <$> strP
-- | Hashed from v22, except a name with subnames or a web TLD.
hashedQuery :: NameQuery -> NameQuery
hashedQuery q = case q of
NQDomain SimplexDomain {nameTLD, domain, subDomain}
| null subDomain && nameTLD /= TLDWeb -> NQHash nameTLD (labelHash domain)
| null subDomain && nameTLD /= TLDWeb -> NQHash (labelHash domain) nameTLD
_ -> q
-- | How the backing resolver is addressed for this query.
queryName :: NameQuery -> Text
queryName = \case
NQDomain d -> fullDomainName d
NQHash tld h -> labelHashText h <> tldSuffix tld
-- | Name resolution error
data NameErrorType
= -- | the names role / resolver is not configured on this server
@@ -1856,9 +1844,7 @@ instance PartyI p => ProtocolEncoding SMPVersion ErrorType (Command p) where
PRXY host auth_ -> e (PRXY_, ' ', host, auth_)
PFWD fwdV pubKey (EncTransmission s) -> e (PFWD_, ' ', fwdV, pubKey, Tail s)
RFWD (EncFwdTransmission s) -> e (RFWD_, ' ', Tail s)
RSLV q
| v >= nameAvailSMPVersion -> e (RSLV_, ' ', hashedQuery q)
| otherwise -> e (RSLV_, ' ') <> encodeUtf8 (queryName q)
RSLV q -> e (RSLV_, ' ', if v >= nameAvailSMPVersion then hashedQuery q else q)
where
e :: Encoding a => a -> ByteString
e = smpEncode
@@ -1965,9 +1951,7 @@ instance ProtocolEncoding SMPVersion ErrorType Cmd where
CT SNotifierService NSUBS_
| v >= rcvServiceSMPVersion -> Cmd SNotifierService <$> (NSUBS <$> _smpP <*> smpP)
| otherwise -> pure $ Cmd SNotifierService $ NSUBS (-1) mempty
CT SResolver RSLV_
| v >= nameAvailSMPVersion -> Cmd SResolver . RSLV <$> _smpP <* A.takeByteString
| otherwise -> Cmd SResolver . RSLV . NQDomain <$> _smpP <* A.takeByteString
CT SResolver RSLV_ -> Cmd SResolver . RSLV <$> _smpP
fromProtocolError = fromProtocolError @SMPVersion @ErrorType @BrokerMsg
{-# INLINE fromProtocolError #-}
@@ -2065,6 +2049,7 @@ instance ProtocolEncoding SMPVersion ErrorType BrokerMsg where
| v >= nameAvailSMPVersion -> fmap RNAME . J.eitherDecodeStrict . unTail <$?> _smpP
| otherwise -> fmap (RNAME . oldRegistration) . J.eitherDecodeStrict . unTail <$?> _smpP
where
oldRegistration nameRecord = NRRegistered {expires = Nothing, graceUntil = Nothing, reservedReason_ = Nothing, nameRecord}
serviceRespP resp
| v >= rcvServiceSMPVersion = resp <$> _smpP <*> smpP
| otherwise = resp <$> _smpP <*> pure mempty
+4 -2
View File
@@ -20,7 +20,9 @@ import Control.Logger.Simple (logError)
import Data.Bifunctor (first)
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import Simplex.Messaging.Protocol (NameErrorType (..), NameQuery, NameRegistration, queryName)
import Data.Text.Encoding (decodeLatin1)
import Simplex.Messaging.Encoding
import Simplex.Messaging.Protocol (NameErrorType (..), NameQuery, NameRegistration)
import Simplex.Messaging.Server.Names.HttpResolver
( ResolverEnv,
ResolverError (..),
@@ -70,7 +72,7 @@ resolveName env q = do
fetch :: NamesEnv -> NameQuery -> IO (Either NameErrorType NameRegistration)
fetch NamesEnv {resolverEnv} q =
first mapResolverError <$> resolveHttp resolverEnv (queryName q)
first mapResolverError <$> resolveHttp resolverEnv (decodeLatin1 $ smpEncode q)
mapResolverError :: ResolverError -> NameErrorType
mapResolverError = \case
+13 -25
View File
@@ -10,11 +10,8 @@ module Simplex.Messaging.SimplexName
SimplexTLD (..),
SimplexNameType (..),
fullDomainName,
tldSuffix,
LabelHash (..),
labelHash,
labelHashText,
labelHashOfText,
boundedNonSpace,
shortNameInfoStr,
)
@@ -88,16 +85,11 @@ newtype LabelHash = LabelHash ByteString
labelHash :: Text -> LabelHash
labelHash label = LabelHash $ BA.convert (hash (encodeUtf8 (T.toLower label)) :: Digest Keccak_256)
-- | ENS's encoding for an unknown label, as the resolver's HTTP API takes it.
labelHashText :: LabelHash -> Text
labelHashText (LabelHash h) = "[" <> decodeLatin1 (BAE.convertToBase BAE.Base16 h) <> "]"
-- | The inverse: `[` cannot occur in a label, so the form is unambiguous.
labelHashOfText :: Text -> Maybe LabelHash
labelHashOfText t = do
hex <- T.stripSuffix "]" =<< T.stripPrefix "[" t
h <- eitherToMaybe (BAE.convertFromBase BAE.Base16 (encodeUtf8 hex) :: Either String ByteString)
if B.length h == 32 then Just (LabelHash h) else Nothing
instance StrEncoding LabelHash where
strEncode (LabelHash h) = '[' `B.cons` (BAE.convertToBase BAE.Base16 h `B.snoc` ']')
strP = do
h <- BAE.convertFromBase BAE.Base16 <$?> (A.char '[' *> A.takeWhile (/= ']') <* A.char ']')
if B.length h == 32 then pure $ LabelHash h else fail "bad LabelHash"
-- | Cap the name at 253 bytes (DNS full-domain limit)
boundedNonSpace :: A.Parser ByteString
@@ -137,19 +129,15 @@ instance Encoding SimplexDomain where
smpP = strP
fullDomainName :: SimplexDomain -> Text
fullDomainName SimplexDomain {nameTLD, domain, subDomain} = T.intercalate "." (reverse subDomain ++ [domain] ++ tld')
where
tld' = case nameTLD of
TLDSimplex -> ["simplex"]
TLDTesting -> ["testing"]
TLDWeb -> []
fullDomainName SimplexDomain {nameTLD, domain, subDomain} = T.intercalate "." (reverse subDomain ++ [domain]) <> decodeLatin1 (strEncode nameTLD)
-- | A web name carries its own TLD, so it gets no suffix.
tldSuffix :: SimplexTLD -> Text
tldSuffix = \case
TLDSimplex -> ".simplex"
TLDTesting -> ".testing"
TLDWeb -> ""
instance StrEncoding SimplexTLD where
strEncode = \case
TLDSimplex -> ".simplex"
TLDTesting -> ".testing"
TLDWeb -> ""
strP =
".simplex" $> TLDSimplex <|> ".testing" $> TLDTesting <|> pure TLDWeb
shortNameInfoStr :: SimplexNameInfo -> Text
shortNameInfoStr = \case
+1 -1
View File
@@ -202,7 +202,7 @@ parseNameSpec = do
mapM_
(\q -> smpDecode (smpEncode q) `shouldBe` Right q)
[ NQDomain d,
NQHash TLDSimplex (labelHash "alice")
NQHash (labelHash "alice") TLDSimplex
]
it "accepts a valid simplex-TLD name" $
case parseN "privacy.simplex" of