Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import { WBNB_ADDRESS } from '@/constants'
import { getRandomElementFromArray } from '@/lib/utils'

const client = axios.create({
baseURL: 'https://api.etherscan.io',
params: {
chainId: 56,
},
baseURL: 'https://api.bscscan.com/api',
})

client.interceptors.request.use(
Expand Down Expand Up @@ -92,7 +89,7 @@ export async function getTokenPrice({ symbol, address }: { symbol: string, addre
}

export async function getBlockNumberByTimestamp(timestamp: number) {
const res = await client.get('/v2/api', {
const res = await client.get('', {
params: {
module: 'block',
action: 'getblocknobytime',
Expand Down Expand Up @@ -129,7 +126,7 @@ export async function getTransactions<T extends keyof TransactionActionMap>({
startblock?: number
endblock?: number
}): Promise<TransactionActionMap[T][]> {
const res = await client.get<{ result: TransactionActionMap[T][] }>('/v2/api', {
const res = await client.get<{ result: TransactionActionMap[T][] }>('', {
params: {
module: 'account',
action,
Expand Down
65 changes: 59 additions & 6 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,61 @@ export function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/api/')) {
const origin = request.headers.get('origin')
const referer = request.headers.get('referer')
const allowedDomains = ['http://localhost:3000', 'https://bn-alpha.site', 'https://www.bn-alpha.site']
const isValidOrigin = origin && allowedDomains.includes(origin)
const isValidReferer = referer && allowedDomains.some(domain => referer.startsWith(domain))
const host = request.headers.get('host')
const forwardedHost = request.headers.get('x-forwarded-host')
const forwardedProto = request.headers.get('x-forwarded-proto')
const defaultAllowedDomains = ['http://localhost:3000', 'https://bn-alpha.site', 'https://www.bn-alpha.site']
const dynamicAllowedDomains = new Set(defaultAllowedDomains)

if (!isValidOrigin && !isValidReferer) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
const normalizeProtocol = (protocol?: string | null) => {
if (!protocol)
return null
return protocol.endsWith(':') ? protocol.slice(0, -1) : protocol
}

const appendOrigin = (hostValue?: string | null, protocol?: string | null) => {
if (!hostValue)
return
const normalizedProtocol = normalizeProtocol(protocol) ?? 'https'
const baseHost = hostValue.split(',')[0]?.trim()
if (!baseHost)
return
dynamicAllowedDomains.add(`${normalizedProtocol}://${baseHost}`)
}

if (request.nextUrl.origin)
dynamicAllowedDomains.add(request.nextUrl.origin)

appendOrigin(request.nextUrl.host, request.nextUrl.protocol)
appendOrigin(host, forwardedProto ?? request.nextUrl.protocol)
appendOrigin(forwardedHost, forwardedProto)

const allowedDomains = Array.from(dynamicAllowedDomains)

const getRefererOrigin = (value?: string | null) => {
if (!value)
return null
try {
return new URL(value).origin
}
catch {
return null
}
}

const refererOrigin = getRefererOrigin(referer)
const inferredSameHostOrigin = request.nextUrl.host
? `${normalizeProtocol(request.nextUrl.protocol) ?? 'https'}://${request.nextUrl.host}`
: null

const isValidOrigin = !!origin && dynamicAllowedDomains.has(origin)
const isValidReferer = !!refererOrigin && dynamicAllowedDomains.has(refererOrigin)
const isMissingCorsHeaders = !origin && !referer
const isSameHostRequest = isMissingCorsHeaders && !!inferredSameHostOrigin && dynamicAllowedDomains.has(inferredSameHostOrigin)

if (!isValidOrigin && !isValidReferer && !isSameHostRequest)
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })

const userAgent = request.headers.get('user-agent')
const blockedUserAgents = ['curl/', 'wget/', 'python-requests/', 'postman', 'insomnia', 'httpie']

Expand All @@ -22,8 +69,14 @@ export function middleware(request: NextRequest) {

const response = NextResponse.next()

const fallbackOrigin = request.nextUrl.origin ?? inferredSameHostOrigin ?? allowedDomains[0]
const corsOrigin = (isValidOrigin && origin)
|| (isValidReferer && refererOrigin)
|| (isSameHostRequest && inferredSameHostOrigin)
|| fallbackOrigin

// CORS Headers
response.headers.set('Access-Control-Allow-Origin', origin || allowedDomains[0])
response.headers.set('Access-Control-Allow-Origin', corsOrigin)
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key')
response.headers.set('Access-Control-Max-Age', '86400')
Expand Down