Skip to content

Commit b66d973

Browse files
committed
smp-server: hardcode TldRegistries (drop registry_tld_* INI keys)
1 parent 1d394f5 commit b66d973

4 files changed

Lines changed: 29 additions & 43 deletions

File tree

protocol/simplex-messaging.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,15 +1465,13 @@ rslv = %s"RSLV" SP json-bytes ; json-bytes consumes the remainder of the trans
14651465

14661466
**Server-side validation.** The names router parses `name` as a fully-qualified
14671467
domain (TLD required — bare labels are rejected), extracts the TLD, and looks
1468-
up the expected SNRC contract address in its INI whitelist
1469-
(`registry_tld_simplex`, `registry_tld_testing`, `registry_tld_all`).
1470-
`registry_tld_all` is the catch-all used when no TLD-specific entry matches
1471-
the requested TLD (and the only entry that can resolve web domains). If no
1472-
whitelist entry matches the TLD, or if the client-supplied `contract` differs
1473-
from the configured address, the server replies with `ERR AUTH` without
1474-
contacting the chain. This lets one names router safely host multiple TLDs
1475-
(each backed by its own SNRC contract) and reject clients pointing at a
1476-
contract the operator doesn't run.
1468+
up the expected SNRC contract address in a whitelist hardcoded in the server
1469+
binary (TLD-specific addresses with an optional catch-all for unspecified
1470+
TLDs and web domains). If no whitelist entry matches the TLD, or if the
1471+
client-supplied `contract` differs from the configured address, the server
1472+
replies with `ERR AUTH` without contacting the chain. This lets one names
1473+
router safely host multiple TLDs (each backed by its own SNRC contract) and
1474+
reject clients pointing at a contract the operator doesn't run.
14771475

14781476
The names router responds with either a `NAME` response carrying the resolved
14791477
record, or `ERR AUTH` collapsing every failure mode (name not found, malformed

src/Simplex/Messaging/Protocol.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ instance J.ToJSON NameOwner where
754754

755755
instance J.FromJSON NameOwner where
756756
parseJSON = J.withText "NameOwner" $ \t -> do
757-
-- Accept "0x" and "0X" prefixes (matches Server/Main.hs:parseEthAddr via fromHex).
757+
-- Accept "0x" and "0X" prefixes (matches the Server-side hex decoder).
758758
let hex = fromMaybe t (T.stripPrefix "0x" t <|> T.stripPrefix "0X" t)
759759
case BAE.convertFromBase BAE.Base16 (encodeUtf8 hex) of
760760
Left e -> fail e

src/Simplex/Messaging/Server/Main.hs

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,8 @@ import Simplex.Messaging.Server.Web (EmbeddedWebParams (..), WebHttpsParams (..)
7777
import Simplex.Messaging.Server.MsgStore.Journal (JournalMsgStore (..), QStoreCfg (..), stmQueueStore)
7878
import Simplex.Messaging.Server.MsgStore.Types (MsgStoreClass (..), SQSType (..), SMSType (..), newMsgStore)
7979
import Network.URI (URI (..), URIAuth (..), parseAbsoluteURI)
80-
import Simplex.Messaging.Protocol (mkNameOwner, NameOwner)
80+
import Simplex.Messaging.Protocol (mkNameOwner)
8181
import Simplex.Messaging.Server.Names (NamesConfig (..), RpcAuth (..), TldRegistries (..))
82-
import Simplex.Messaging.Server.Names.Eth.RPC (fromHex)
8382
import Simplex.Messaging.Server.QueueStore.Postgres.Config
8483
import Simplex.Messaging.Server.StoreLog.ReadWrite (readQueueStore)
8584
import Simplex.Messaging.Transport (supportedProxyClientSMPRelayVRange, alpnSupportedSMPHandshakes, supportedServerSMPRelayVRange)
@@ -807,11 +806,10 @@ readNamesConfig ini
807806
| otherwise =
808807
let rpcAuth_ = either (error . ("[NAMES] rpc_auth: " <>)) Just . parseRpcAuth =<< eitherToMaybe (lookupValue "NAMES" "rpc_auth" ini)
809808
endpoint = requiredText "ethereum_endpoint"
810-
registries = readTldRegistries
811809
in Just
812810
NamesConfig
813811
{ ethereumEndpoint = either (error . ("[NAMES] ethereum_endpoint: " <>)) id (validateUrl endpoint rpcAuth_),
814-
tldRegistries = registries,
812+
tldRegistries = hardcodedTldRegistries,
815813
rpcAuth = rpcAuth_,
816814
rpcTimeoutMs = boundedIniInt 3000 100 60000 "rpc_timeout_ms",
817815
rpcMaxResponseBytes = boundedIniInt 262144 1024 16777216 "rpc_max_response_bytes",
@@ -833,18 +831,22 @@ readNamesConfig ini
833831
n | n >= floor_ && n <= ceiling_ -> n
834832
| otherwise ->
835833
error $ "[NAMES] " <> T.unpack key <> " must be in [" <> show floor_ <> ".." <> show ceiling_ <> "] (got " <> show n <> ")"
836-
readTldRegistries =
837-
let regs = TldRegistries
838-
{ tldSimplex = optionalAddr "registry_tld_simplex",
839-
tldTesting = optionalAddr "registry_tld_testing",
840-
tldAll = optionalAddr "registry_tld_all"
841-
}
842-
in case (tldSimplex regs, tldTesting regs, tldAll regs) of
843-
(Nothing, Nothing, Nothing) ->
844-
error "[NAMES] at least one of registry_tld_simplex, registry_tld_testing, registry_tld_all is required"
845-
_ -> regs
846-
optionalAddr key =
847-
either (error . (("[NAMES] " <> T.unpack key <> ": ") <>)) Just . parseEthAddr =<< eitherToMaybe (lookupValue "NAMES" key ini)
834+
835+
-- | Hardcoded SNRC contract whitelist. Placeholder addresses until the
836+
-- launch contracts are deployed; replaced in code rather than INI so
837+
-- operators can't accidentally point a names router at the wrong contract
838+
-- during the bootstrap phase. The TldRegistries shape + lookup precedence
839+
-- (TLD-specific then `tldAll` catch-all) is unchanged from the previous
840+
-- INI-driven form.
841+
hardcodedTldRegistries :: TldRegistries
842+
hardcodedTldRegistries =
843+
TldRegistries
844+
{ tldSimplex = Just (placeholderAddr '\x11'),
845+
tldTesting = Just (placeholderAddr '\x22'),
846+
tldAll = Nothing
847+
}
848+
where
849+
placeholderAddr c = either error id $ mkNameOwner (B.replicate 20 c)
848850

849851
-- | Validate the ethereum_endpoint URL:
850852
-- * scheme must be http: or https:
@@ -913,15 +915,6 @@ validateUrl url auth_ = do
913915
'0' : 'x' : rest -> all isHexDigit rest
914916
lh -> not (null lh) && all isDigit lh
915917

916-
-- | Parse a 20-byte Ethereum address as text "0x[hex40]" or "[hex40]".
917-
-- EIP-55 mixed-case checksum verification is a follow-up.
918-
parseEthAddr :: Text -> Either String NameOwner
919-
parseEthAddr t = do
920-
bs <- fromHex (encodeUtf8 t)
921-
if B.length bs == 20
922-
then mkNameOwner bs
923-
else Left "expected a 20-byte address (40 hex characters, optionally 0x-prefixed)"
924-
925918
-- | Parse an rpc_auth INI value. Scheme keyword is case-insensitive so
926919
-- "Bearer <token>" / "BEARER <token>" (Caddy / RFC 7235 convention) work
927920
-- as well as the lowercase form.

src/Simplex/Messaging/Server/Main/Init.hs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,9 @@ iniFileContent cfgPath logPath opts host basicAuth controlPortPwds =
168168
\# Central Reth via Caddy:\n\
169169
\# ethereum_endpoint: https://eth.simplex.chat:443\n\
170170
\# rpc_auth: basic <username>:<password>\n\
171-
\# Per-TLD SNRC contract whitelist. At least one entry must be set.\n\
172-
\# Each RSLV carries the contract address the client wants queried;\n\
173-
\# the server only accepts it if it matches the address configured for\n\
174-
\# that TLD (or registry_tld_all as catch-all for any unspecified TLD,\n\
175-
\# including web domains).\n\
176-
\# registry_tld_simplex: 0x<paste-your-contract-address>\n\
177-
\# registry_tld_testing: 0x<paste-your-contract-address>\n\
178-
\# registry_tld_all: 0x<paste-your-contract-address>\n\
171+
\# The SNRC contract addresses are hardcoded in the server binary; each\n\
172+
\# RSLV's contract field is verified against the binary's whitelist for\n\
173+
\# the requested TLD. Operators do NOT configure registries here.\n\
179174
\# rpc_timeout_ms: 3000\n\
180175
\# rpc_max_response_bytes: 262144\n\
181176
\# rpc_max_concurrency: 8\n\n\

0 commit comments

Comments
 (0)