From 8263775a491da374bf60f68509c6836e21ccfd24 Mon Sep 17 00:00:00 2001 From: devinxl Date: Fri, 29 Mar 2024 16:16:24 +0800 Subject: [PATCH] feat(dcellar-web-ui): add domain validate for api --- apps/dcellar-web-ui/src/base/env.ts | 10 +++++++++- .../src/pages/api/bill_monthly/[[...slug]].ts | 6 +++++- .../src/pages/api/bill_realtime/[[...slug]].ts | 6 +++++- .../dcellar-web-ui/src/pages/api/chart/[[...slug]].ts | 6 +++++- .../src/pages/api/policies/[[...slug]].ts | 6 +++++- .../src/pages/api/total_cost/[[...slug]].ts | 6 +++++- apps/dcellar-web-ui/src/utils/req.ts | 11 +++++++++++ 7 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 apps/dcellar-web-ui/src/utils/req.ts diff --git a/apps/dcellar-web-ui/src/base/env.ts b/apps/dcellar-web-ui/src/base/env.ts index aa686826..a8036485 100644 --- a/apps/dcellar-web-ui/src/base/env.ts +++ b/apps/dcellar-web-ui/src/base/env.ts @@ -24,7 +24,12 @@ const { NEXT_PUBLIC_APOLLO_GLOBAL_NOTIFICATION, NEXT_PUBLIC_APOLLO_GLOBAL_NOTIFICATION_ETA, } = publicRuntimeConfig || {}; -const { NEXT_PRIVATE_BILLING_API_URL, NEXT_PRIVATE_EXPLORER_API_URL } = serverRuntimeConfig || {}; + +const { + NEXT_PRIVATE_BILLING_API_URL, + NEXT_PRIVATE_EXPLORER_API_URL, + NEXT_PRIVATE_ALLOWED_DOMAINS, +} = serverRuntimeConfig || {}; export type TRuntimeEnv = 'development' | 'qa' | 'testnet' | 'mainnet'; @@ -44,8 +49,11 @@ export const GREENFIELD_CHAIN_EXPLORER_URL = NEXT_PUBLIC_GREENFIELD_CHAIN_EXPLOR export const BSC_EXPLORER_URL = NEXT_PUBLIC_BSC_EXPLORER_URL; export const GREENFIELD_MAINNET_ID = NEXT_PUBLIC_GREENFIELD_CHAIN_MAINNET_ID; export const GREENFIELD_MAINNET_RPC_URL = NEXT_PUBLIC_GREENFIELD_CHAIN_MAINNET_RPC_URL; + export const BILLING_API_URL = NEXT_PRIVATE_BILLING_API_URL; export const EXPLORER_API_URL = NEXT_PRIVATE_EXPLORER_API_URL; +export const ALLOWED_DOMAINS = NEXT_PRIVATE_ALLOWED_DOMAINS; + export const mainnetSpMetaEndpoint = NEXT_PUBLIC_APOLLO_MAINNET_SP_RECOMMEND_META; export const defaultApolloConfig = { diff --git a/apps/dcellar-web-ui/src/pages/api/bill_monthly/[[...slug]].ts b/apps/dcellar-web-ui/src/pages/api/bill_monthly/[[...slug]].ts index 3864e370..2291b486 100644 --- a/apps/dcellar-web-ui/src/pages/api/bill_monthly/[[...slug]].ts +++ b/apps/dcellar-web-ui/src/pages/api/bill_monthly/[[...slug]].ts @@ -1,9 +1,13 @@ -import { BILLING_API_URL } from '@/base/env'; +import { ALLOWED_DOMAINS, BILLING_API_URL } from '@/base/env'; +import { validateReferer } from '@/utils/req'; import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; import qs from 'query-string'; const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!validateReferer(req.headers.referer || '', ALLOWED_DOMAINS)) { + res.status(403).json({ message: 'Forbidden' }); + } const { slug, ...query } = req.query; const slugs = slug as string[]; const url = `${BILLING_API_URL}/greenfield/bill_monthly/${slugs.join('/')}?${qs.stringify(query)}`; diff --git a/apps/dcellar-web-ui/src/pages/api/bill_realtime/[[...slug]].ts b/apps/dcellar-web-ui/src/pages/api/bill_realtime/[[...slug]].ts index d45bfc67..5fbd88c3 100644 --- a/apps/dcellar-web-ui/src/pages/api/bill_realtime/[[...slug]].ts +++ b/apps/dcellar-web-ui/src/pages/api/bill_realtime/[[...slug]].ts @@ -1,9 +1,13 @@ -import { BILLING_API_URL } from '@/base/env'; +import { ALLOWED_DOMAINS, BILLING_API_URL } from '@/base/env'; +import { validateReferer } from '@/utils/req'; import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; import qs from 'query-string'; const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!validateReferer(req.headers.referer || '', ALLOWED_DOMAINS)) { + res.status(403).json({ message: 'Forbidden' }); + } const { slug, ...query } = req.query; const slugs = slug as string[]; const url = `${BILLING_API_URL}/greenfield/bill_realtime/${slugs.join('/')}?${qs.stringify(query)}`; diff --git a/apps/dcellar-web-ui/src/pages/api/chart/[[...slug]].ts b/apps/dcellar-web-ui/src/pages/api/chart/[[...slug]].ts index bdd095ed..cbc418b6 100644 --- a/apps/dcellar-web-ui/src/pages/api/chart/[[...slug]].ts +++ b/apps/dcellar-web-ui/src/pages/api/chart/[[...slug]].ts @@ -1,9 +1,13 @@ import axios from 'axios'; import qs from 'query-string'; import { NextApiRequest, NextApiResponse } from 'next'; -import { EXPLORER_API_URL } from '@/base/env'; +import { ALLOWED_DOMAINS, EXPLORER_API_URL } from '@/base/env'; +import { validateReferer } from '@/utils/req'; const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!validateReferer(req.headers.referer || '', ALLOWED_DOMAINS)) { + res.status(403).json({ message: 'Forbidden' }); + } const { slug, ...query } = req.query; const slugs = slug as string[]; const url = `${EXPLORER_API_URL}/greenfield/chart/${slugs.join('/')}?${qs.stringify(query)}`; diff --git a/apps/dcellar-web-ui/src/pages/api/policies/[[...slug]].ts b/apps/dcellar-web-ui/src/pages/api/policies/[[...slug]].ts index 18c52838..192328e7 100644 --- a/apps/dcellar-web-ui/src/pages/api/policies/[[...slug]].ts +++ b/apps/dcellar-web-ui/src/pages/api/policies/[[...slug]].ts @@ -1,8 +1,12 @@ -import { EXPLORER_API_URL } from '@/base/env'; +import { ALLOWED_DOMAINS, EXPLORER_API_URL } from '@/base/env'; +import { validateReferer } from '@/utils/req'; import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!validateReferer(req.headers.referer || '', ALLOWED_DOMAINS)) { + res.status(403).json({ message: 'Forbidden' }); + } const { slug } = req.query; const slugs = slug as string[]; const url = `${EXPLORER_API_URL}/greenfield/permission/policy/list/by_resource/${slugs.join( diff --git a/apps/dcellar-web-ui/src/pages/api/total_cost/[[...slug]].ts b/apps/dcellar-web-ui/src/pages/api/total_cost/[[...slug]].ts index e7ba6837..d070de8a 100644 --- a/apps/dcellar-web-ui/src/pages/api/total_cost/[[...slug]].ts +++ b/apps/dcellar-web-ui/src/pages/api/total_cost/[[...slug]].ts @@ -1,8 +1,12 @@ -import { BILLING_API_URL } from '@/base/env'; +import { ALLOWED_DOMAINS, BILLING_API_URL } from '@/base/env'; +import { validateReferer } from '@/utils/req'; import axios from 'axios'; import { NextApiRequest, NextApiResponse } from 'next'; const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!validateReferer(req.headers.referer || '', ALLOWED_DOMAINS)) { + res.status(403).json({ message: 'Forbidden' }); + } const { slug } = req.query; const slugs = slug as string[]; const url = `${BILLING_API_URL}/greenfield/total_cost/${slugs.join('/')}`; diff --git a/apps/dcellar-web-ui/src/utils/req.ts b/apps/dcellar-web-ui/src/utils/req.ts new file mode 100644 index 00000000..3ca5f83b --- /dev/null +++ b/apps/dcellar-web-ui/src/utils/req.ts @@ -0,0 +1,11 @@ +const localhostDomains = ['localhost', '127.0.0.1', '::1']; + +export function validateReferer(referrer: string, allowedDomains: string) { + if (!referrer) { + return false; + } + const domain = new URL(referrer).hostname; + const domains = allowedDomains.split(',').concat(localhostDomains); + + return domains.includes(domain); +}