import { clsx } from 'clsx' import { Client } from 'xrpl' import React = require("react"); import { CLASS_GOOD } from "../components/LogEntry"; import { AccountFields } from "./XrplToml"; // Decode a hexadecimal string into a regular string, assuming 8-bit characters. // Not proper unicode decoding, but it'll work for domains which are supposed // to be a subset of ASCII anyway. function decodeHex(hex) { let str = ''; for (let i = 0; i < hex.length; i += 2) { str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)) } return str } function getWsUrlForNetwork(net: string) { let wsNetworkUrl: string if (net === "main") { wsNetworkUrl = 'wss://s1.ripple.com:51233' } else if (net == "testnet") { wsNetworkUrl = 'wss://s.altnet.rippletest.net:51233' } else if (net === "devnet") { wsNetworkUrl = 'wss://s.devnet.rippletest.net:51233/' } else if (net === "xahau") { wsNetworkUrl = 'wss://xahau-test.net:51233' } else { wsNetworkUrl = undefined } return wsNetworkUrl } async function validateAddressDomainOnNet(addressToVerify: string, domain: string, net: string) { if (!domain) { return undefined } // Can't validate an empty domain value const wsNetworkUrl = getWsUrlForNetwork(net) if(!wsNetworkUrl) { console.error(`The XRPL TOML Checker does not currently support verifying addresses on ${net}. Please open an issue to add support for this network.`) return undefined } const api = new Client(wsNetworkUrl) await api.connect() let accountInfoResponse try { accountInfoResponse = await api.request({ "command": "account_info", "account": addressToVerify }) } catch(e) { console.warn(`failed to look up address ${addressToVerify} on ${net} network"`, e) return undefined } finally { await api.disconnect() } if (accountInfoResponse.result.account_data.Domain === undefined) { console.info(`Address ${addressToVerify} has no Domain defined on-ledger`) return undefined } let decodedDomain try { decodedDomain = decodeHex(accountInfoResponse.result.account_data.Domain) } catch(e) { console.warn("error decoding domain value", accountInfoResponse.result.account_data.Domain, e) return undefined } if(decodedDomain) { const doesDomainMatch = decodedDomain === domain if(!doesDomainMatch) { console.debug(addressToVerify, ": Domain mismatch ("+decodedDomain+" vs. "+domain+")") } return doesDomainMatch } else { console.debug(addressToVerify, ": Domain is undefined in settings") return undefined } } /** * A formatted list item displaying content from a single field of a toml file. * * @param props Field info to display * @returns A formatted list item */ function FieldListItem(props: { fieldName: string, fieldValue: string}) { return (
  • {props.fieldName}: {props.fieldValue}
  • ) } /** * Get an array of HTML lists that can be used to display toml data. * If no data exists or none matches the filter it will return an empty array instead. * * @param fields An array of objects to parse into bullet points * @param filter Optional function to filter displayed fields to only ones which return true. */ export async function getListEntries(fields: Object[], filter?: Function, domainToVerify?: string) { const formattedEntries: JSX.Element[] = [] for(let i = 0; i < fields.length; i++) { const entry = fields[i] if(!filter || filter(entry)) { const fieldNames = Object.keys(entry) const displayedFields: JSX.Element[] = [] fieldNames.forEach((fieldName) => { if(entry[fieldName] && Array.isArray(entry[fieldName])) { const internalList = [] entry[fieldName].forEach((value) => { internalList.push( ) }) displayedFields.push(
      {internalList}
    ) } else { displayedFields.push( ) } }) const key = `entry-${formattedEntries.length}` const promises = [] if(domainToVerify) { const accountEntry = entry as AccountFields if(accountEntry.address) { const net = accountEntry.network ?? "main" const domainIsValid = validateAddressDomainOnNet(accountEntry.address, domainToVerify, net) domainIsValid.then((wasValidated) => { if(wasValidated) { displayedFields.push(
  • DOMAIN VALIDATED
  • ) } }) promises.push(domainIsValid) } } await Promise.all(promises) formattedEntries.push((
    • {displayedFields}
  • )) } } return formattedEntries }