From 529b9e31a1efce9bfdf4d26d02cb3b439c272d37 Mon Sep 17 00:00:00 2001 From: Johnathan Reale Date: Wed, 5 Nov 2025 10:48:45 -0500 Subject: [PATCH 01/20] IP address setting, bindings --- .../packages/app-store/chain/Cargo.toml | 2 +- .../hns-indexer/hns-indexer/Cargo.toml | 2 +- .../hypermap-cacher/binding-cacher/Cargo.toml | 2 +- .../hypermap-cacher/Cargo.toml | 2 +- .../hypermap-cacher/reset-cache/Cargo.toml | 2 +- .../hypermap-cacher/set-nodes/Cargo.toml | 2 +- .../start-providing/Cargo.toml | 2 +- .../hypermap-cacher/stop-providing/Cargo.toml | 2 +- hyperdrive/src/net/mod.rs | 10 +- hyperdrive/src/register-ui/src/App.tsx | 16 ++ .../src/register-ui/src/abis/helpers.ts | 24 +-- hyperdrive/src/register-ui/src/lib/types.ts | 9 + .../register-ui/src/pages/CommitDotOsName.tsx | 70 ++++++++ .../src/register-ui/src/pages/Login.tsx | 52 +++++- .../src/register-ui/src/pages/MintCustom.tsx | 85 +++++++++- .../register-ui/src/pages/MintDotOsName.tsx | 5 +- .../src/register-ui/src/pages/ResetName.tsx | 160 +++++++++++++----- .../src/register-ui/src/pages/SetPassword.tsx | 9 +- hyperdrive/src/register.rs | 118 +++++++++++-- lib/src/kernel.rs | 20 ++- 20 files changed, 504 insertions(+), 90 deletions(-) diff --git a/hyperdrive/packages/app-store/chain/Cargo.toml b/hyperdrive/packages/app-store/chain/Cargo.toml index f859d495e..2637271c8 100644 --- a/hyperdrive/packages/app-store/chain/Cargo.toml +++ b/hyperdrive/packages/app-store/chain/Cargo.toml @@ -11,7 +11,7 @@ alloy-primitives = "0.8.15" alloy-sol-types = "0.8.15" anyhow = "1.0" bincode = "1.3.3" -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d" } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2" } process_macros = "0.1" rand = "0.8" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml b/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml index 93d00cb3d..a34f21890 100644 --- a/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml +++ b/hyperdrive/packages/hns-indexer/hns-indexer/Cargo.toml @@ -11,7 +11,7 @@ anyhow = "1.0" alloy-primitives = "0.8.15" alloy-sol-types = "0.8.15" hex = "0.4.3" -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d" , features = ["logging"] } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2" , features = ["logging"] } process_macros = "0.1" rmp-serde = "1.1.2" serde = { version = "1.0", features = ["derive"] } diff --git a/hyperdrive/packages/hypermap-cacher/binding-cacher/Cargo.toml b/hyperdrive/packages/hypermap-cacher/binding-cacher/Cargo.toml index 4341c9353..c12e544e7 100644 --- a/hyperdrive/packages/hypermap-cacher/binding-cacher/Cargo.toml +++ b/hyperdrive/packages/hypermap-cacher/binding-cacher/Cargo.toml @@ -18,7 +18,7 @@ alloy = { version = "0.8.1", features = [ ] } chrono = "0.4.41" hex = "0.4.3" -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d", features = ["logging"] } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2", features = ["logging"] } process_macros = "0.1.0" rand = "0.8" rmp-serde = "1.1.2" diff --git a/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml b/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml index 730b54bd5..b1730eb93 100644 --- a/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml +++ b/hyperdrive/packages/hypermap-cacher/hypermap-cacher/Cargo.toml @@ -18,7 +18,7 @@ alloy = { version = "0.8.1", features = [ ] } chrono = "0.4.41" hex = "0.4.3" -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d", features = ["logging"] } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2", features = ["logging"] } process_macros = "0.1.0" rand = "0.8" rmp-serde = "1.1.2" diff --git a/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml b/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml index 6e59bb18c..2f513bc6f 100644 --- a/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml +++ b/hyperdrive/packages/hypermap-cacher/reset-cache/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d" } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2" } process_macros = "0.1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml b/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml index d8a3cd911..f44e5bca6 100644 --- a/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml +++ b/hyperdrive/packages/hypermap-cacher/set-nodes/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d" } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2" } process_macros = "0.1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml b/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml index d94d592d5..dc3d9fae4 100644 --- a/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml +++ b/hyperdrive/packages/hypermap-cacher/start-providing/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d" } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2" } process_macros = "0.1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml b/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml index 96c75941f..f51c92c12 100644 --- a/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml +++ b/hyperdrive/packages/hypermap-cacher/stop-providing/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "e95ff8d" } +hyperware_process_lib = { git = "https://github.com/hyperware-ai/process_lib", rev = "a420cc2" } process_macros = "0.1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/hyperdrive/src/net/mod.rs b/hyperdrive/src/net/mod.rs index c55e0c94e..6a240bd35 100644 --- a/hyperdrive/src/net/mod.rs +++ b/hyperdrive/src/net/mod.rs @@ -88,11 +88,11 @@ pub async fn networking( match &ext.our.routing { NodeRouting::Direct { ip, ports } => { if *ext.our_ip != *ip { - return Err(anyhow::anyhow!( - "net: fatal error: IP address mismatch: {} != {}, update your HNS identity", - ext.our_ip, - ip - )); + let message = format!( + "IP address mismatch detected. Detected from environment: {}, node's data: {}. Please confirm your node is reachable at {} or restart your node to reset your networking data.", + ext.our_ip, ip, ip + ); + utils::print_loud(&ext.print_tx, &message).await; } utils::print_debug(&ext.print_tx, "going online as a direct node").await; if !ports.contains_key(WS_PROTOCOL) && !ports.contains_key(TCP_PROTOCOL) { diff --git a/hyperdrive/src/register-ui/src/App.tsx b/hyperdrive/src/register-ui/src/App.tsx index a6d54658e..5e5f480a0 100644 --- a/hyperdrive/src/register-ui/src/App.tsx +++ b/hyperdrive/src/register-ui/src/App.tsx @@ -23,6 +23,7 @@ function App() { const [keyFileName, setKeyFileName] = useState(''); const [reset, setReset] = useState(false); const [direct, setDirect] = useState(false); + const [directNodeIp, setDirectNodeIp] = useState(''); const [hnsName, setHnsName] = useState(''); const [networkingKey, setNetworkingKey] = useState(''); const [ipAddress, setIpAddress] = useState(0); @@ -72,6 +73,20 @@ function App() { } catch (e) { console.error('error getting current chain', e) } + + try { + const ipv4Response = await fetch('/ipv4', { method: 'GET', credentials: 'include' }) + + if (ipv4Response.status < 400) { + const ipv4Data: { ip: string } = await ipv4Response.json() + setDirectNodeIp(ipv4Data.ip) + console.log('IPv4 Address:', ipv4Data.ip) + } else { + console.error('error processing IPv4 response', ipv4Response) + } + } catch (e) { + console.error('error getting IPv4 address', e) + } })() }, []) // eslint-disable-line react-hooks/exhaustive-deps @@ -82,6 +97,7 @@ function App() { // todo, most of these can be removed... const props = { direct, setDirect, + directNodeIp, setDirectNodeIp, key, keyFileName, setKeyFileName, reset, setReset, diff --git a/hyperdrive/src/register-ui/src/abis/helpers.ts b/hyperdrive/src/register-ui/src/abis/helpers.ts index cd2db8602..bce823360 100644 --- a/hyperdrive/src/register-ui/src/abis/helpers.ts +++ b/hyperdrive/src/register-ui/src/abis/helpers.ts @@ -1,4 +1,3 @@ - import { NetworkingInfo } from "../lib/types"; import { hyperhash } from "../utils/hyperhash"; import { ipToBytes, portToBytes } from "../utils/hns_encoding"; @@ -13,15 +12,17 @@ const encodeRouters = (routers: string[]): `0x${string}` => { }; export const generateNetworkingKeys = async ({ - direct, - setNetworkingKey, - setWsPort, - setTcpPort, - setRouters, - reset, - customRouters, -}: { + direct, + directNodeIp, + setNetworkingKey, + setWsPort, + setTcpPort, + setRouters, + reset, + customRouters, + }: { direct: boolean, + directNodeIp?: string, label: string, our_address: `0x${string}`, setNetworkingKey: (networkingKey: string) => void; @@ -45,7 +46,9 @@ export const generateNetworkingKeys = async ({ (res) => res.json() )) as NetworkingInfo; - const ipAddress = ipToBytes(ip_address); + // Use directNodeIp if provided and direct is true, otherwise use the generated IP + const ipToUse = direct && directNodeIp ? directNodeIp : ip_address; + const ipAddress = ipToBytes(ipToUse); const routersToUse = customRouters && customRouters.length > 0 ? customRouters : allowed_routers; @@ -56,6 +59,7 @@ export const generateNetworkingKeys = async ({ setRouters(routersToUse); console.log("networking_key: ", networking_key); + console.log("IP address being used: ", ipToUse); console.log("routers being used: ", routersToUse); const netkeycall = encodeFunctionData({ diff --git a/hyperdrive/src/register-ui/src/lib/types.ts b/hyperdrive/src/register-ui/src/lib/types.ts index f3afbbacc..15be73f08 100644 --- a/hyperdrive/src/register-ui/src/lib/types.ts +++ b/hyperdrive/src/register-ui/src/lib/types.ts @@ -12,6 +12,8 @@ export interface PageProps { setRouters: React.Dispatch>, direct: boolean, setDirect: React.Dispatch>, + directNodeIp: string, + setDirectNodeIp: React.Dispatch>, hnsName: string, setHnsName: React.Dispatch>, key: string, @@ -49,6 +51,13 @@ export type InfoResponse = { allowed_routers?: string[]; initial_cache_sources: string[]; initial_base_l2_providers: string[]; + uses_direct_networking?: boolean; + hns_ip_address?: string; + detected_ip_address?: string; +} + +export type IPv4Response = { + ip: string; } export interface RpcProviderConfig { diff --git a/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx b/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx index 2950e21ed..1d5f1eacf 100644 --- a/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx +++ b/hyperdrive/src/register-ui/src/pages/CommitDotOsName.tsx @@ -1,3 +1,4 @@ + import { useState, useEffect, FormEvent, useCallback } from "react"; import { useNavigate } from "react-router-dom"; import { toAscii } from "idna-uts46-hx"; @@ -19,9 +20,14 @@ interface RegisterOsNameProps extends PageProps { } // Regex for valid router names (domain format) const ROUTER_NAME_REGEX = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*$/; +// IPv4 validation regex +const IPV4_REGEX = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; + function CommitDotOsName({ direct, setDirect, + directNodeIp, + setDirectNodeIp, setHnsName, setNetworkingKey, setIpAddress, @@ -54,6 +60,40 @@ function CommitDotOsName({ const [customRouters, setCustomRouters] = useState('') const [routerValidationErrors, setRouterValidationErrors] = useState([]) + // Track the initial IPv4 value to determine if it was auto-detected + const [initialDirectNodeIp, setInitialDirectNodeIp] = useState('') + + // Capture the initial directNodeIp value when component mounts + useEffect(() => { + setInitialDirectNodeIp(directNodeIp); + }, []); // Empty dependency array means this runs once on mount + + // Validation function for IPv4 + const isValidIPv4 = (ip: string): boolean => { + return IPV4_REGEX.test(ip); + }; + + // Check if direct node configuration is valid + const isDirectNodeValid = (): boolean => { + if (!direct) return true; // Not required if checkbox is unchecked + return directNodeIp.trim() !== '' && isValidIPv4(directNodeIp.trim()); + }; + + // Determine the appropriate label for the Direct Node IP field + const getDirectNodeIpLabel = (): string => { + const hasValidInitialIp = initialDirectNodeIp && isValidIPv4(initialDirectNodeIp); + + if (!hasValidInitialIp) { + return "Direct Node IP Address (IPv4)"; + } + + if (directNodeIp === initialDirectNodeIp) { + return "Direct Node IP Address (as detected)"; + } + + return "Direct Node IP Address (overridden by user)"; + }; + // Modified setDirect function - no longer clears custom routers const handleSetDirect = (value: boolean) => { setDirect(value); @@ -227,6 +267,35 @@ function CommitDotOsName({ Advanced Network Options
+ {direct && ( +
+ + setDirectNodeIp(e.target.value)} + placeholder="e.g., 192.168.1.100" + className={`input ${ + direct && !isDirectNodeValid() + ? 'border-red-500 focus:border-red-500' + : '' + }`} + /> + {direct && directNodeIp.trim() && !isValidIPv4(directNodeIp.trim()) && ( + + Please enter a valid IPv4 address + + )} + {direct && !directNodeIp.trim() && ( + + IP address is required for direct nodes + + )} +
+ )} {specifyRouters && (
@@ -273,6 +342,7 @@ function CommitDotOsName({ isPending || isConfirming || nameValidities.length !== 0 || + (direct && !isDirectNodeValid()) || (specifyRouters && !isCustomRoutersValid()) } > diff --git a/hyperdrive/src/register-ui/src/pages/Login.tsx b/hyperdrive/src/register-ui/src/pages/Login.tsx index 84709693b..fe6fb6189 100644 --- a/hyperdrive/src/register-ui/src/pages/Login.tsx +++ b/hyperdrive/src/register-ui/src/pages/Login.tsx @@ -1,4 +1,3 @@ - import { FormEvent, useCallback, useEffect, useState } from "react"; import { PageProps, InfoResponse } from "../lib/types"; import Loader from "../components/Loader"; @@ -40,6 +39,10 @@ function Login({ const [cacheSourceValidationErrors, setCacheSourceValidationErrors] = useState([]); const [specifyBaseL2AccessProviders, setSpecifyBaseL2AccessProviders] = useState(false); const [rpcProviders, setRpcProviders] = useState([]); + const [usesDirectNetworking, setUsesDirectNetworking] = useState(false); + const [hnsIpAddress, setHnsIpAddress] = useState(""); + const [detectedIpAddress, setDetectedIpAddress] = useState(""); + const [acknowledgeIpMismatch, setAcknowledgeIpMismatch] = useState(false); // Track initial states after data is loaded const [initialCacheSourcesChecked, setInitialCacheSourcesChecked] = useState(false); @@ -64,6 +67,17 @@ function Login({ setHnsName(infoData.name); } + // Set networking information + if (infoData.uses_direct_networking !== undefined) { + setUsesDirectNetworking(infoData.uses_direct_networking); + } + if (infoData.hns_ip_address) { + setHnsIpAddress(infoData.hns_ip_address); + } + if (infoData.detected_ip_address) { + setDetectedIpAddress(infoData.detected_ip_address); + } + // Prepopulate cache sources if (infoData.initial_cache_sources && infoData.initial_cache_sources.length > 0) { setCustomCacheSources(infoData.initial_cache_sources.join('\n')); @@ -133,6 +147,8 @@ function Login({ return errors; }; + const hasIpMismatch = usesDirectNetworking && hnsIpAddress && detectedIpAddress && hnsIpAddress !== detectedIpAddress; + // Handle custom cache sources change with validation const handleCustomCacheSourcesChange = (value: string) => { setCustomCacheSources(value); @@ -253,6 +269,12 @@ function Login({ rpcProviders.some(p => !p.url.trim() || !validateWebSocketUrl(p.url) || (p.auth && !p.auth.value.trim())) ); + // Check if login button should be disabled + const isLoginDisabled = + (specifyCacheSources && !isCustomCacheSourcesValid()) || + hasInvalidRpcProviders || + (hasIpMismatch && !acknowledgeIpMismatch); + return
{loading &&
@@ -281,6 +303,32 @@ function Login({ onChange={(e) => setPw(e.target.value)} autoFocus /> + {/* IP Mismatch Warning */} + {hasIpMismatch && ( +
+
+ ⚠️ IP Address Mismatch Detected +
+
+
HNS IP: {hnsIpAddress}
(your node's published Hypermap directory address)
+
Detected IP: {detectedIpAddress}
(your node's likely current address)
+
+
+ Please use Reset Password & Networking Info to reset your networking information, or acknowledge the following to proceed with login. +
+ +
+ )}
{/* Advanced Options Section */} @@ -356,7 +404,7 @@ function Login({