Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement geoblocking #31

Merged
merged 15 commits into from
May 8, 2024
Merged
2 changes: 0 additions & 2 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ const withPWA = NextPwa({

/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // static site export
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved

images: {
unoptimized: true,
},
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"test:coverage": "yarn test --coverage --watchAll=false",
"cmp": "./scripts/cmp.sh",
"routes": "node scripts/generate-routes.js > src/config/routes.ts && prettier -w src/config/routes.ts && cat src/config/routes.ts",
"css-vars": "ts-node-esm ./scripts/css-vars.ts > ./src/styles/vars.css && prettier -w src/styles/vars.css",
"css-vars": "npx -y tsx ./scripts/css-vars.ts > ./src/styles/vars.css && prettier -w src/styles/vars.css",
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved
"generate-types": "typechain --target ethers-v5 --out-dir src/types/contracts ./node_modules/@safe-global/safe-deployments/dist/assets/**/*.json ./node_modules/@safe-global/safe-modules-deployments/dist/assets/**/*.json ./node_modules/@openzeppelin/contracts/build/contracts/ERC20.json ./node_modules/@openzeppelin/contracts/build/contracts/ERC721.json",
"postinstall": "yarn generate-types && yarn css-vars",
"analyze": "cross-env ANALYZE=true yarn build",
Expand All @@ -29,7 +29,7 @@
"static-serve": "yarn build && yarn serve"
},
"engines": {
"node": ">=16"
"node": ">=18"
},
"pre-commit": [
"lint"
Expand Down
14 changes: 14 additions & 0 deletions src/components/terms/clabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Typography } from '@mui/material'

const Terms = () => {
return (
<div>
<Typography variant="h1" mb={2}>
Terms and Conditions
</Typography>
<p> This app shall not be accessed in any country or region sanctioned by US Law.</p>
</div>
)
}

export default Terms
7 changes: 6 additions & 1 deletion src/pages/apps/custom.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react'
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'

import { useSafeApps } from '@/hooks/safe-apps/useSafeApps'
Expand All @@ -8,6 +8,11 @@ import SafeAppList from '@/components/safe-apps/SafeAppList'
import SafeAppsSDKLink from '@/components/safe-apps/SafeAppsSDKLink'
import { RemoveCustomAppModal } from '@/components/safe-apps/RemoveCustomAppModal'
import type { SafeAppData } from '@safe-global/safe-gateway-typescript-sdk'
import { checkForForbiddenRegions } from '@/utils/geo'

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}

const CustomSafeApps: NextPage = () => {
// TODO: create a custom hook instead of use useSafeApps
Expand Down
6 changes: 6 additions & 0 deletions src/pages/apps/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import SafeAppsSDKLink from '@/components/safe-apps/SafeAppsSDKLink'
import SafeAppsHeader from '@/components/safe-apps/SafeAppsHeader'
import SafeAppList from '@/components/safe-apps/SafeAppList'
import { AppRoutes } from '@/config/routes'
import type { GetServerSideProps } from 'next'
import { checkForForbiddenRegions } from '@/utils/geo'

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}

const SafeApps: NextPage = () => {
const router = useRouter()
Expand Down
8 changes: 6 additions & 2 deletions src/pages/apps/open.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import { useRouter } from 'next/router'
import { useCallback } from 'react'
import { Box, CircularProgress } from '@mui/material'

import { checkForForbiddenRegions } from '@/utils/geo'
import { useSafeAppUrl } from '@/hooks/safe-apps/useSafeAppUrl'
import { useSafeApps } from '@/hooks/safe-apps/useSafeApps'
import SafeAppsInfoModal from '@/components/safe-apps/SafeAppsInfoModal'
Expand Down Expand Up @@ -84,3 +84,7 @@ const SafeApps: NextPage = () => {
}

export default SafeApps

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
7 changes: 6 additions & 1 deletion src/pages/balances/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'

import AssetsTable from '@/components/balances/AssetsTable'
import AssetsHeader from '@/components/balances/AssetsHeader'
import useBalances from '@/hooks/useBalances'
import { useState } from 'react'
import { checkForForbiddenRegions } from '@/utils/geo'

import PagePlaceholder from '@/components/common/PagePlaceholder'
import NoAssetsIcon from '@/public/images/balances/no-assets.svg'
Expand Down Expand Up @@ -41,3 +42,7 @@ const Balances: NextPage = () => {
}

export default Balances

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
7 changes: 6 additions & 1 deletion src/pages/balances/nfts.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { type ReactElement, memo } from 'react'
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'
import { Grid, Skeleton, Typography } from '@mui/material'
import AssetsHeader from '@/components/balances/AssetsHeader'
import NftCollections from '@/components/nfts/NftCollections'
import SafeAppCard from '@/components/safe-apps/SafeAppCard'
import { SafeAppsTag } from '@/config/constants'
import { useRemoteSafeApps } from '@/hooks/safe-apps/useRemoteSafeApps'
import { checkForForbiddenRegions } from '@/utils/geo'

// `React.memo` requires a `displayName`
const NftApps = memo(function NftApps(): ReactElement | null {
Expand Down Expand Up @@ -62,3 +63,7 @@ const NFTs: NextPage = () => {
}

export default NFTs

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
7 changes: 6 additions & 1 deletion src/pages/home.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'

import Dashboard from '@/components/dashboard'
import { checkForForbiddenRegions } from '@/utils/geo'

const Home: NextPage = () => {
return (
Expand All @@ -18,3 +19,7 @@ const Home: NextPage = () => {
}

export default Home

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
8 changes: 7 additions & 1 deletion src/pages/new-safe/create.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Head from 'next/head'
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'

import { checkForForbiddenRegions } from '@/utils/geo'

import CreateSafe from '@/components/new-safe/create'

Expand All @@ -16,3 +18,7 @@ const Open: NextPage = () => {
}

export default Open

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
7 changes: 6 additions & 1 deletion src/pages/new-safe/load.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
import LoadSafe, { loadSafeDefaultData } from '@/components/new-safe/load'
import { checkForForbiddenRegions } from '@/utils/geo'

const Load: NextPage = () => {
const router = useRouter()
Expand All @@ -24,3 +25,7 @@ const Load: NextPage = () => {
}

export default Load

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
6 changes: 6 additions & 0 deletions src/pages/share/safe-app.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useEffect } from 'react'
import Head from 'next/head'
import type { GetServerSideProps } from 'next'
import { useRouter } from 'next/router'
import { Box, CircularProgress } from '@mui/material'
import { useSafeAppUrl } from '@/hooks/safe-apps/useSafeAppUrl'
import { useChainFromQueryParams } from '@/hooks/safe-apps/useChainFromQueryParams'
import { SafeAppLanding } from '@/components/safe-apps/SafeAppLandingPage'
import { AppRoutes } from '@/config/routes'
import { checkForForbiddenRegions } from '@/utils/geo'

const ShareSafeApp = () => {
const router = useRouter()
Expand Down Expand Up @@ -50,3 +52,7 @@ const ShareSafeApp = () => {
}

export default ShareSafeApp

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
3 changes: 2 additions & 1 deletion src/pages/terms.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import SafeTerms from '@/components/terms'
import ClabsTerms from '@/components/terms/clabs'
import { IS_OFFICIAL_HOST } from '@/config/constants'

const Imprint: NextPage = () => {
Expand All @@ -10,7 +11,7 @@ const Imprint: NextPage = () => {
<title>{'Safe{Wallet} – Terms'}</title>
</Head>

<main>{IS_OFFICIAL_HOST && <SafeTerms />}</main>
<main>{IS_OFFICIAL_HOST ? <SafeTerms /> : <ClabsTerms />}</main>
</>
)
}
Expand Down
7 changes: 6 additions & 1 deletion src/pages/transactions/history.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'
import useTxHistory from '@/hooks/useTxHistory'
import PaginatedTxns from '@/components/common/PaginatedTxns'
Expand All @@ -10,6 +10,7 @@ import ExpandLessIcon from '@mui/icons-material/ExpandLess'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import TxFilterForm from '@/components/transactions/TxFilterForm'
import { useTxFilter } from '@/utils/tx-history-filter'
import { checkForForbiddenRegions } from '@/utils/geo'

const History: NextPage = () => {
const [filter] = useTxFilter()
Expand Down Expand Up @@ -45,3 +46,7 @@ const History: NextPage = () => {
}

export default History

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
6 changes: 6 additions & 0 deletions src/pages/transactions/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import HistoryPage from './history'
import type { GetServerSideProps } from 'next'
import { checkForForbiddenRegions } from '@/utils/geo'

export default HistoryPage

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
7 changes: 6 additions & 1 deletion src/pages/transactions/queue.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'
import Head from 'next/head'
import useTxQueue from '@/hooks/useTxQueue'
import PaginatedTxns from '@/components/common/PaginatedTxns'
Expand All @@ -7,6 +7,7 @@ import BatchExecuteButton from '@/components/transactions/BatchExecuteButton'
import { Box } from '@mui/material'
import { BatchExecuteHoverProvider } from '@/components/transactions/BatchExecuteButton/BatchExecuteHoverProvider'
import { usePendingTxsQueue, useShowUnsignedQueue } from '@/hooks/usePendingTxs'
import { checkForForbiddenRegions } from '@/utils/geo'

const Queue: NextPage = () => {
const showPending = useShowUnsignedQueue()
Expand Down Expand Up @@ -37,3 +38,7 @@ const Queue: NextPage = () => {
}

export default Queue

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
8 changes: 7 additions & 1 deletion src/pages/transactions/tx.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'

import Head from 'next/head'

import SingleTx from '@/components/transactions/SingleTx'
import Typography from '@mui/material/Typography'
import { checkForForbiddenRegions } from '@/utils/geo'

const SingleTransaction: NextPage = () => {
return (
Expand All @@ -23,3 +25,7 @@ const SingleTransaction: NextPage = () => {
}

export default SingleTransaction

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
9 changes: 8 additions & 1 deletion src/pages/welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import type { NextPage } from 'next'
import type { NextPage, GetServerSideProps } from 'next'

import Head from 'next/head'
import NewSafe from '@/components/welcome/NewSafe'

import { checkForForbiddenRegions } from '@/utils/geo'

const Welcome: NextPage = () => {
return (
<>
Expand All @@ -15,3 +18,7 @@ const Welcome: NextPage = () => {
}

export default Welcome

export const getServerSideProps: GetServerSideProps<{}> = async ({ req, res }) => {
return checkForForbiddenRegions(req, res) ?? { props: {} }
}
35 changes: 35 additions & 0 deletions src/utils/geo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { IncomingMessage, OutgoingMessage } from 'http'

export const HTTP_HEADER_COUNTRY = 'x-vercel-ip-country'
export const HTTP_HEADER_REGION = 'x-vercel-ip-country-region'

// korea, iran, cuba, syria
const RESTRICTED_COUNTRIES = new Set(['KP', 'IR', 'CU', 'SY'])

// https://www.iso.org/obp/ui/#iso:code:3166:UA although listed with UA prefix. the header/api recieved that and just used the number
const crimea = '43'
const luhansk = '09'
const donetska = '14'
//https://en.wikipedia.org/wiki/Russian-occupied_territories_of_Ukraine
const RESTRICED_SUBREGION: Record<string, Set<string>> = {
UA: new Set([crimea, luhansk, donetska]),
}

export function isForbiddenLand(iso3166Country: string, iso3166Region: string) {
const iso3166CountryUppercase = iso3166Country?.toUpperCase()
return (
RESTRICTED_COUNTRIES.has(iso3166CountryUppercase) ||
RESTRICED_SUBREGION[iso3166CountryUppercase]?.has(iso3166Region)
)
}

export function checkForForbiddenRegions(req: IncomingMessage, res: OutgoingMessage) {
const coutry = req.headers[HTTP_HEADER_COUNTRY] as string
const region = req.headers[HTTP_HEADER_REGION] as string

console.info('country', coutry, 'region', region)

if (isForbiddenLand(coutry, region)) {
return { redirect: { destination: '/terms', permanent: false } }
}
}
Loading