Skip to content

Commit

Permalink
Add address network validation (#60)
Browse files Browse the repository at this point in the history
* Add network address validation

* Add API error

* remove unnecessary error

* reset client

* remove double period

* add prefix
  • Loading branch information
jribbink authored Oct 27, 2023
1 parent 81259c9 commit 8d30caf
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 2 deletions.
8 changes: 8 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,16 @@ export const CREATE_ACCOUNT_ERROR = "Account creation has failed"
export const FUND_ACCOUNT_ERROR = "Account funding has failed"
export const MISSING_FUSD_VAULT_ERROR =
"This account does not have an FUSD vault"
export const INVALID_NETWORK_ADDRESS_ERROR = (network: Networks) =>
`This address is invalid for ${network}, please verify that it is correct`

export const paths = {
root: "/",
fundAccount: "/fund-account",
}

export const ADDRESS_REGEXP = /^(0x)?[0-9a-fA-F]{16}$/

export const NETWORK_CODEWORDS = {
testnet: "0x6834ba37b3980209",
}
38 changes: 38 additions & 0 deletions lib/network.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,42 @@
import capitalize from "./capitalize"
import {ADDRESS_REGEXP, NETWORK_CODEWORDS} from "./constants"
import publicConfig from "./publicConfig"
import * as fcl from "@onflow/fcl"

export const NETWORK_DISPLAY_NAME = capitalize(publicConfig.network)

// Network address validation taken from flow-go
// https://github.com/onflow/flow-go/blob/043570794069a876072d50de4dc03bbd34f063c7/model/flow/address.go

const linearCodeN = 64
const parityCheckMatrixColumns = [
0x00001, 0x00002, 0x00004, 0x00008, 0x00010, 0x00020, 0x00040, 0x00080,
0x00100, 0x00200, 0x00400, 0x00800, 0x01000, 0x02000, 0x04000, 0x08000,
0x10000, 0x20000, 0x40000, 0x7328d, 0x6689a, 0x6112f, 0x6084b, 0x433fd,
0x42aab, 0x41951, 0x233ce, 0x22a81, 0x21948, 0x1ef60, 0x1deca, 0x1c639,
0x1bdd8, 0x1a535, 0x194ac, 0x18c46, 0x1632b, 0x1529b, 0x14a43, 0x13184,
0x12942, 0x118c1, 0x0f812, 0x0e027, 0x0d00e, 0x0c83c, 0x0b01d, 0x0a831,
0x0982b, 0x07034, 0x0682a, 0x05819, 0x03807, 0x007d2, 0x00727, 0x0068e,
0x0067c, 0x0059d, 0x004eb, 0x003b4, 0x0036a, 0x002d9, 0x001c7, 0x0003f,
]

export function isValidNetworkAddress(
address: string,
network: keyof typeof NETWORK_CODEWORDS
) {
address = fcl.withPrefix(address) || ""
if (ADDRESS_REGEXP.test(address) === false) return false

let codeword = BigInt(address) ^ BigInt(NETWORK_CODEWORDS[network])
let parity = 0

if (codeword === BigInt(0)) return false

for (let i = 0; i < linearCodeN; i++) {
if (codeword % BigInt(2) === BigInt(1)) {
parity ^= parityCheckMatrixColumns[i]
}
codeword >>= BigInt(1)
}
return parity === 0
}
3 changes: 2 additions & 1 deletion lib/validate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ACCOUNTS_KEYS_DOCS_URL,
ADDRESS_FORMAT_ERROR,
ADDRESS_MISSING_ERROR,
ADDRESS_REGEXP,
GENERATE_KEYS_DOCS_URL,
PUBLIC_KEY_FORMAT_ERROR,
PUBLIC_KEY_MISSING_ERROR,
Expand Down Expand Up @@ -53,7 +54,7 @@ export const createAccountSchemaServer = yup
const fundAccountSchemaClientShape = {
address: yup
.string()
.matches(/^(0x)?([0-9a-f]{16})$/i, () => (
.matches(ADDRESS_REGEXP, () => (
<>
{ADDRESS_FORMAT_ERROR}{" "}
<Link href={ACCOUNTS_KEYS_DOCS_URL} target="_blank" variant="underline">
Expand Down
15 changes: 14 additions & 1 deletion pages/api/fund.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import * as fcl from "@onflow/fcl"
import * as t from "@onflow/types"
import {verify} from "hcaptcha"
import {FUSD_TYPE, MISSING_FUSD_VAULT_ERROR} from "lib/constants"
import {
FUSD_TYPE,
INVALID_NETWORK_ADDRESS_ERROR,
MISSING_FUSD_VAULT_ERROR,
} from "lib/constants"
import publicConfig from "lib/publicConfig"
import {NextApiRequest, NextApiResponse} from "next"
import config from "../../lib/config"
Expand All @@ -10,6 +14,7 @@ import {getSignerKeyIndex} from "../../lib/keys"
import {fundAccountSchemaServer} from "../../lib/validate"
import {verifyAPIKey} from "../../lib/common"
import {ValidationError} from "yup"
import {isValidNetworkAddress} from "lib/network"

const scriptCheckFUSDVault = `
import FUSD from ${publicConfig.contractFUSD}
Expand Down Expand Up @@ -44,6 +49,14 @@ export default async function fund(req: NextApiRequest, res: NextApiResponse) {
const address = fcl.withPrefix(req.body.address) || ""
const token = req.body.token

// Validate address
if (!isValidNetworkAddress(address, publicConfig.network)) {
res
.status(400)
.json({errors: [INVALID_NETWORK_ADDRESS_ERROR(publicConfig.network)]})
return
}

if (token === FUSD_TYPE) {
try {
const hasFUSDVault = await fcl
Expand Down

1 comment on commit 8d30caf

@vercel
Copy link

@vercel vercel bot commented on 8d30caf Oct 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.