Iniciativa Cidadã Independente · Transparência Parlamentar
TS104 linhas2.397 bytes

apps/web/src/lib/donations.ts

SHA-256

202e57fc31141c61a78d708b5facc5bf62ae434186db92a3645f1b6c239bf1a1

Somente leiturafonte-acf635076da2
export interface DonationWallet {
  asset: string
  symbol: string
  network: string
  address: string
  uriScheme?: string
  explorerBaseUrl: string
  networkWarning: string
}

function text(value: unknown, maxLength: number): string | undefined {
  if (typeof value !== 'string') return undefined
  const result = value.trim()
  return result && result.length <= maxLength ? result : undefined
}

function parseWallet(value: unknown): DonationWallet | undefined {
  if (!value || typeof value !== 'object') return undefined

  const item = value as Record<string, unknown>
  const asset = text(item.asset, 40)
  const symbol = text(item.symbol, 12)
  const network = text(item.network, 40)
  const address = text(item.address, 160)
  const uriScheme = text(item.uriScheme, 24)
  const explorerBaseUrl = text(item.explorerBaseUrl, 240)
  const networkWarning = text(item.networkWarning, 180)

  if (
    !asset ||
    !symbol ||
    !network ||
    !address ||
    !explorerBaseUrl ||
    !networkWarning
  ) {
    return undefined
  }
  if (/\s/.test(address) || address.length < 16) return undefined
  if (uriScheme && !/^[a-z][a-z0-9+.-]*$/.test(uriScheme)) {
    return undefined
  }

  try {
    const url = new URL(explorerBaseUrl)
    if (
      url.protocol !== 'https:' ||
      !url.pathname.endsWith('/') ||
      url.username ||
      url.password ||
      url.search ||
      url.hash
    ) {
      return undefined
    }
  } catch {
    return undefined
  }

  return {
    asset,
    symbol,
    network,
    address,
    uriScheme,
    explorerBaseUrl,
    networkWarning,
  }
}

export function parseDonationWallets(
  raw: string | undefined,
): DonationWallet[] {
  if (!raw) return []

  try {
    const parsed: unknown = JSON.parse(raw)
    if (!Array.isArray(parsed)) return []

    return parsed.flatMap((item) => {
      const wallet = parseWallet(item)
      return wallet ? [wallet] : []
    })
  } catch {
    return []
  }
}

export function getDonationWallets(): DonationWallet[] {
  return parseDonationWallets(
    process.env.NEXT_PUBLIC_DONATION_WALLETS_JSON,
  )
}

export function paymentUri(wallet: DonationWallet): string {
  return wallet.uriScheme
    ? `${wallet.uriScheme}:${wallet.address}`
    : wallet.address
}

export function explorerHref(wallet: DonationWallet): string {
  return `${wallet.explorerBaseUrl}${encodeURIComponent(wallet.address)}`
}