diff --git a/apps/autonolas-registry/common-util/List/IpfsHashGenerationModal/index.jsx b/apps/autonolas-registry/common-util/List/IpfsHashGenerationModal/index.jsx
index 92824662..d1881bcb 100644
--- a/apps/autonolas-registry/common-util/List/IpfsHashGenerationModal/index.jsx
+++ b/apps/autonolas-registry/common-util/List/IpfsHashGenerationModal/index.jsx
@@ -1,4 +1,4 @@
-import { Button, Form, Input, Select } from 'antd';
+import { Button, Flex, Form, Input, Select } from 'antd';
import isNil from 'lodash/isNil';
import PropTypes from 'prop-types';
import React, { Fragment, useState } from 'react';
@@ -220,7 +220,21 @@ export const IpfsHashGenerationModal = ({
+
+ Represents your NFT on marketplaces such as OpenSea. Current supported domains are:
+
+
+ {/* TODO: fetch from middleware constant */}
+
+ - https://gateway.autonolas.tech/ipfs/*
+ - https://gateway.pinata.cloud/ipfs/*
+ - https://*.arweave.net/
+
+
+
+ }
>
diff --git a/apps/autonolas-registry/common-util/Login/LoginV2.jsx b/apps/autonolas-registry/common-util/Login/LoginV2.jsx
index 2cce86d4..db2af763 100644
--- a/apps/autonolas-registry/common-util/Login/LoginV2.jsx
+++ b/apps/autonolas-registry/common-util/Login/LoginV2.jsx
@@ -9,10 +9,11 @@ import { useAccount, useBalance, useDisconnect, useSwitchChain } from 'wagmi';
import { CannotConnectAddressOfacError, notifyError, useScreen } from '@autonolas/frontend-library';
+import { isAddressProhibited } from 'libs/util-prohibited-data/src/index';
+
import { setUserBalance } from 'store/setup';
import { YellowButton } from '../YellowButton';
-import { isAddressProhibited } from '../functions';
import { useHelpers } from '../hooks';
import { SolanaWallet } from './SolanaWallet';
diff --git a/apps/autonolas-registry/common-util/functions/index.jsx b/apps/autonolas-registry/common-util/functions/index.jsx
index 079cfcc3..dd28e049 100644
--- a/apps/autonolas-registry/common-util/functions/index.jsx
+++ b/apps/autonolas-registry/common-util/functions/index.jsx
@@ -1,5 +1,6 @@
import { PublicKey } from '@solana/web3.js';
import { ethers } from 'ethers';
+import { isString } from 'lodash';
import {
getChainIdOrDefaultToMainnet as getChainIdOrDefaultToMainnetFn,
@@ -10,9 +11,6 @@ import {
sendTransaction as sendTransactionFn,
} from '@autonolas/frontend-library';
-import prohibitedAddresses from 'libs/util-prohibited-data/src/lib/prohibited-addresses.json';
-import { isString, toLower } from 'lodash';
-
import { VM_TYPE } from '../../util/constants';
import { RPC_URLS } from '../Contracts';
import { SUPPORTED_CHAINS } from '../Login';
@@ -178,11 +176,6 @@ export const checkIfGnosisSafe = async (account, provider) => {
*/
export const doesNetworkHaveValidServiceManagerTokenFn = (chainId) => !!chainId;
-export const isAddressProhibited = (address) => {
- const addresses = prohibitedAddresses.map((e) => toLower(e));
- return addresses.includes(toLower(address));
-};
-
const doesPathIncludesComponents = (path) => !!path?.includes('components');
const doesPathIncludesAgents = (path) => !!path?.includes('agents');
export const doesPathIncludesServices = (path) => !!path?.includes('services');
diff --git a/apps/autonolas-registry/middleware.ts b/apps/autonolas-registry/middleware.ts
index d76d6935..88188c61 100644
--- a/apps/autonolas-registry/middleware.ts
+++ b/apps/autonolas-registry/middleware.ts
@@ -1,150 +1,4 @@
-import nextSafe from 'next-safe';
-import { NextRequest, NextResponse, userAgent } from 'next/server';
+import { config, middleware } from 'libs/common-middleware/src';
-import prohibitedCountries from 'libs/util-prohibited-data/src/lib/prohibited-countries.json';
-
-const prohibitedCountriesCode = Object.values(prohibitedCountries);
-
-const isDev = process.env.NODE_ENV !== 'production';
-
-const getCspHeader = (browserName?: string) => {
- if (!process.env.NEXT_PUBLIC_AUTONOLAS_SUB_GRAPH_URL) return [];
-
- const walletconnectSrc = ['https://verify.walletconnect.org', 'https://verify.walletconnect.com'];
-
- const connectSrc: CSPDirective = [
- "'self'",
- ...walletconnectSrc,
- 'https://*.olas.network/',
- 'https://*.autonolas.tech/',
- 'https://rpc.walletconnect.com/',
- 'wss://relay.walletconnect.org/',
- 'wss://relay.walletconnect.com/',
- 'https://explorer-api.walletconnect.com/',
- 'https://eth-mainnet.g.alchemy.com/v2/',
- 'https://eth-goerli.g.alchemy.com/v2/',
- 'https://gno.getblock.io/',
- 'https://polygon-mainnet.g.alchemy.com/v2/',
- 'https://polygon-mumbai-bor.publicnode.com/',
- 'https://rpc.chiado.gnosis.gateway.fm/',
- 'https://safe-transaction-mainnet.safe.global/api/v1/',
- 'https://safe-transaction-goerli.safe.global/api/',
- 'https://safe-transaction-gnosis-chain.safe.global/api/',
- 'https://safe-transaction-polygon.safe.global/api/',
- 'https://vercel.live/',
- 'https://api.devnet.solana.com/',
- 'wss://api.devnet.solana.com/',
- 'https://api.mainnet-beta.solana.com/',
- 'wss://api.mainnet-beta.solana.com/',
- 'https://holy-convincing-bird.solana-mainnet.quiknode.pro/',
- 'wss://holy-convincing-bird.solana-mainnet.quiknode.pro/',
- 'https://arb1.arbitrum.io/rpc/',
- 'https://sepolia-rollup.arbitrum.io/rpc',
- 'https://rpc.gnosischain.com/',
- 'https://mainnet.base.org/',
- 'https://sepolia.base.org/',
- 'https://mainnet.optimism.io',
- 'https://sepolia.optimism.io/',
- 'https://forno.celo.org',
- 'https://alfajores-forno.celo-testnet.org',
- 'https://api.web3modal.com/',
- 'wss://www.walletlink.org/rpc',
- 'wss://*.pusher.com/',
- process.env.NEXT_PUBLIC_AUTONOLAS_SUB_GRAPH_URL,
- ];
-
- if (isDev) {
- connectSrc.push('http://localhost');
- connectSrc.push('ws://localhost');
- }
-
- const scriptSrc = ["'self'", 'https://vercel.live/', 'https://fonts.googleapis.com/'];
-
- // Firefox blocks inline scripts by default and it's an issue with Metamask
- // reference: https://github.com/MetaMask/metamask-extension/issues/3133
- if (browserName === 'Firefox') {
- scriptSrc.push("'unsafe-inline'");
- }
-
- const nextSafeHeaders =
- typeof nextSafe === 'function'
- ? // TODO
- // @ts-expect-error: For some reason, TypeScript is not recognizing the function
- nextSafe({
- isDev,
- /**
- * Content Security Policy
- * @see https://content-security-policy.com/
- */
- contentSecurityPolicy: {
- 'default-src': "'none'",
- 'script-src': scriptSrc,
- 'connect-src': connectSrc,
- 'img-src': [
- "'self'",
- 'blob:',
- 'data:',
- 'https://*.autonolas.tech/',
- 'https://explorer-api.walletconnect.com/w3m/',
- ...walletconnectSrc,
- ],
- 'style-src': ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com/'],
- 'frame-src': ["'self'", 'https://vercel.live/', ...walletconnectSrc],
- },
- permissionsPolicyDirectiveSupport: ['standard'],
- })
- : [];
-
- const headers = [
- ...nextSafeHeaders,
- {
- key: 'Strict-Transport-Security',
- value: 'max-age=31536000; includeSubDomains',
- },
- ];
-
- return headers;
-};
-
-const getRedirectUrl = (pathName: string, countryName?: string) => {
- const isProhibited = countryName ? prohibitedCountriesCode.includes(countryName) : false;
-
- if (pathName === '/not-legal') {
- return isProhibited ? null : '/';
- }
- return isProhibited ? '/not-legal' : null;
-};
-
-export default async function middleware(request: NextRequest) {
- const country = request.geo?.country;
- const redirectUrl = getRedirectUrl(request.nextUrl.pathname, country);
-
- const response = redirectUrl
- ? NextResponse.redirect(new URL(redirectUrl, request.nextUrl))
- : NextResponse.next();
-
- const browserName = userAgent(request)?.browser.name;
- const cspHeaders = getCspHeader(browserName);
-
- // apply CSP headers
- // https://nextjs.org/docs/app/building-your-application/routing/middleware#setting-headers
- cspHeaders.forEach((header) => {
- const { key, value } = header;
- response.headers.set(key, value);
- });
-
- return response;
-}
-
-export const config = {
- matcher: [
- /*
- * Match all request paths except for the ones starting with:
- * - api (API routes)
- * - _next/static (static files)
- * - _next/image (image optimization files)
- * - favicon.ico (favicon file)
- */
- '/((?!api|_next/static|_next/image|favicon.ico).*)',
- ],
-};
+export default middleware;
+export { config };
diff --git a/apps/bond/common-util/Login/LoginV2.jsx b/apps/bond/common-util/Login/LoginV2.jsx
index ed7132cb..8df0cacc 100644
--- a/apps/bond/common-util/Login/LoginV2.jsx
+++ b/apps/bond/common-util/Login/LoginV2.jsx
@@ -12,7 +12,8 @@ import {
notifyError,
} from '@autonolas/frontend-library';
-import { isAddressProhibited } from 'common-util/functions/addresses';
+import { isAddressProhibited } from 'libs/util-prohibited-data/src/index';
+
import { getChainId, getChainIdOrDefaultToMainnet } from 'common-util/functions/frontend-library';
import { setChainId, setUserBalance } from 'store/setup';
diff --git a/apps/bond/common-util/functions/addresses.js b/apps/bond/common-util/functions/addresses.js
deleted file mode 100644
index 795639ec..00000000
--- a/apps/bond/common-util/functions/addresses.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import toLower from 'lodash/toLower';
-import prohibitedAddresses from 'libs/util-prohibited-data/src/lib/prohibited-addresses.json';
-
-export const isAddressProhibited = (address) => {
- const addresses = prohibitedAddresses.map((e) => toLower(e));
- return addresses.includes(toLower(address));
-};
diff --git a/apps/bond/common-util/functions/index.js b/apps/bond/common-util/functions/index.js
index e3520124..19554e5e 100644
--- a/apps/bond/common-util/functions/index.js
+++ b/apps/bond/common-util/functions/index.js
@@ -1,4 +1,3 @@
-export * from './addresses';
export * from './chains';
export * from './errors';
export * from './ethers';
diff --git a/apps/bond/middleware.ts b/apps/bond/middleware.ts
new file mode 100644
index 00000000..88188c61
--- /dev/null
+++ b/apps/bond/middleware.ts
@@ -0,0 +1,4 @@
+import { config, middleware } from 'libs/common-middleware/src';
+
+export default middleware;
+export { config };
diff --git a/apps/bond/next.config.js b/apps/bond/next.config.js
index 21180c94..36638391 100644
--- a/apps/bond/next.config.js
+++ b/apps/bond/next.config.js
@@ -24,41 +24,6 @@ const nextConfig = {
};
return config;
},
- async headers() {
- return [
- {
- source: '/:path*',
- headers: [
- {
- key: 'Content-Security-Policy',
- value: "frame-ancestors 'none';",
- },
- {
- key: 'X-Content-Type-Options',
- value: 'nosniff',
- },
- {
- key: 'Referrer-Policy',
- value: 'strict-origin-when-cross-origin',
- },
- {
- key: 'Strict-Transport-Security',
- value: 'max-age=31536000; includeSubDomains',
- },
- ],
- },
- {
- source: '/:all*(svg|jpg|jpeg|png|gif|ico|css|js|mov|mp4)',
- headers: [
- {
- key: 'Cache-Control',
- value: 'public, max-age=31536000, must-revalidate',
- },
- ],
- },
- ];
- },
-
};
const plugins = [
diff --git a/apps/govern/common-util/functions/addresses.ts b/apps/govern/common-util/functions/addresses.ts
index 0e423c83..11057631 100644
--- a/apps/govern/common-util/functions/addresses.ts
+++ b/apps/govern/common-util/functions/addresses.ts
@@ -1,14 +1,6 @@
import { ethers } from 'ethers';
-import { toLower } from 'lodash';
import { Address } from 'viem';
-import prohibitedAddresses from 'libs/util-prohibited-data/src/lib/prohibited-addresses.json';
-
-export const isAddressProhibited = (address: Address | undefined) => {
- const addresses = prohibitedAddresses.map((e) => toLower(e));
- return addresses.includes(toLower(address));
-};
-
export const getAddressFromBytes32 = (address: Address | string) => {
return ('0x' + address.slice(-40)) as Address;
};
diff --git a/apps/govern/components/Login/LoginV2.tsx b/apps/govern/components/Login/LoginV2.tsx
index 3c742778..03fe134a 100644
--- a/apps/govern/components/Login/LoginV2.tsx
+++ b/apps/govern/components/Login/LoginV2.tsx
@@ -3,8 +3,9 @@ import { useCallback, useEffect } from 'react';
import styled from 'styled-components';
import { useAccountEffect, useConfig, useDisconnect } from 'wagmi';
+import { isAddressProhibited } from 'libs/util-prohibited-data/src/index';
+
import { INVALIDATE_AFTER_ACCOUNT_CHANGE } from 'common-util/constants/scopeKeys';
-import { isAddressProhibited } from 'common-util/functions';
import { queryClient } from 'context/Web3ModalProvider';
import { clearUserState } from 'store/govern';
import { useAppDispatch } from 'store/index';
diff --git a/apps/govern/middleware.ts b/apps/govern/middleware.ts
new file mode 100644
index 00000000..88188c61
--- /dev/null
+++ b/apps/govern/middleware.ts
@@ -0,0 +1,4 @@
+import { config, middleware } from 'libs/common-middleware/src';
+
+export default middleware;
+export { config };
diff --git a/apps/launch/middleware.ts b/apps/launch/middleware.ts
new file mode 100644
index 00000000..88188c61
--- /dev/null
+++ b/apps/launch/middleware.ts
@@ -0,0 +1,4 @@
+import { config, middleware } from 'libs/common-middleware/src';
+
+export default middleware;
+export { config };
diff --git a/apps/tokenomics/common-util/Login/LoginV2.jsx b/apps/tokenomics/common-util/Login/LoginV2.jsx
index ed7132cb..8df0cacc 100644
--- a/apps/tokenomics/common-util/Login/LoginV2.jsx
+++ b/apps/tokenomics/common-util/Login/LoginV2.jsx
@@ -12,7 +12,8 @@ import {
notifyError,
} from '@autonolas/frontend-library';
-import { isAddressProhibited } from 'common-util/functions/addresses';
+import { isAddressProhibited } from 'libs/util-prohibited-data/src/index';
+
import { getChainId, getChainIdOrDefaultToMainnet } from 'common-util/functions/frontend-library';
import { setChainId, setUserBalance } from 'store/setup';
diff --git a/apps/tokenomics/common-util/functions/addresses.js b/apps/tokenomics/common-util/functions/addresses.js
deleted file mode 100644
index 396a40fa..00000000
--- a/apps/tokenomics/common-util/functions/addresses.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import prohibitedAddresses from 'libs/util-prohibited-data/src/lib/prohibited-addresses.json';
-import toLower from 'lodash/toLower';
-
-export const isAddressProhibited = (address) => {
- const addresses = prohibitedAddresses.map((e) => toLower(e));
- return addresses.includes(toLower(address));
-};
diff --git a/apps/tokenomics/common-util/functions/index.js b/apps/tokenomics/common-util/functions/index.js
index 4ae847cb..964ec0ad 100644
--- a/apps/tokenomics/common-util/functions/index.js
+++ b/apps/tokenomics/common-util/functions/index.js
@@ -1,4 +1,3 @@
-export * from './addresses';
export * from './errors';
export * from './ethers';
export * from './time';
diff --git a/apps/tokenomics/middleware.ts b/apps/tokenomics/middleware.ts
new file mode 100644
index 00000000..88188c61
--- /dev/null
+++ b/apps/tokenomics/middleware.ts
@@ -0,0 +1,4 @@
+import { config, middleware } from 'libs/common-middleware/src';
+
+export default middleware;
+export { config };
diff --git a/apps/tokenomics/next.config.js b/apps/tokenomics/next.config.js
index 1ab955c0..f1829759 100644
--- a/apps/tokenomics/next.config.js
+++ b/apps/tokenomics/next.config.js
@@ -40,31 +40,6 @@ const nextConfig = {
},
];
},
- async headers() {
- return [
- {
- source: '/:path*',
- headers: [
- {
- key: 'Content-Security-Policy',
- value: "frame-ancestors 'none';",
- },
- {
- key: 'X-Content-Type-Options',
- value: 'nosniff',
- },
- {
- key: 'Referrer-Policy',
- value: 'strict-origin-when-cross-origin',
- },
- {
- key: 'Strict-Transport-Security',
- value: 'max-age=31536000; includeSubDomains',
- },
- ],
- },
- ];
- },
};
const plugins = [
// Add more Next.js plugins to this list if needed.
diff --git a/libs/common-middleware/.eslintrc.json b/libs/common-middleware/.eslintrc.json
new file mode 100644
index 00000000..a39ac5d0
--- /dev/null
+++ b/libs/common-middleware/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["plugin:@nx/react", "../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/libs/common-middleware/README.md b/libs/common-middleware/README.md
new file mode 100644
index 00000000..69743456
--- /dev/null
+++ b/libs/common-middleware/README.md
@@ -0,0 +1,5 @@
+# common-middleware
+
+Common middleware for apps, including:
+- Prohibition of specific countries and addresses
+- Implementation of security headers
diff --git a/libs/common-middleware/project.json b/libs/common-middleware/project.json
new file mode 100644
index 00000000..d81cb0af
--- /dev/null
+++ b/libs/common-middleware/project.json
@@ -0,0 +1,13 @@
+{
+ "name": "common-middleware",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/common-middleware/src",
+ "projectType": "library",
+ "tags": [],
+ "targets": {
+ "lint": {
+ "executor": "@nx/eslint:lint",
+ "outputs": ["{options.outputFile}"]
+ }
+ }
+}
diff --git a/libs/common-middleware/src/index.ts b/libs/common-middleware/src/index.ts
new file mode 100644
index 00000000..965a85bc
--- /dev/null
+++ b/libs/common-middleware/src/index.ts
@@ -0,0 +1 @@
+export { config, middleware } from './middleware';
diff --git a/libs/common-middleware/src/lib/cspHeader.ts b/libs/common-middleware/src/lib/cspHeader.ts
new file mode 100644
index 00000000..44b2a302
--- /dev/null
+++ b/libs/common-middleware/src/lib/cspHeader.ts
@@ -0,0 +1,143 @@
+import nextSafe from 'next-safe';
+
+const isDev = process.env.NODE_ENV !== 'production';
+
+const WALLET_CONNECT_LINKS = [
+ 'https://verify.walletconnect.org',
+ 'https://verify.walletconnect.com',
+];
+
+const VERCEL_LINKS = ['https://vercel.com', 'https://vercel.live/'];
+
+const GATEWAY_LINKS = [
+ 'https://gateway.autonolas.tech/ipfs/*',
+ 'https://gateway.pinata.cloud/ipfs/*',
+ 'https://*.arweave.net/',
+ 'https://i.seadn.io/s/raw/files/',
+ 'https://www.askjimmy.xyz/images/',
+];
+
+const ALLOWED_ORIGINS = [
+ // internal
+ "'self'",
+ 'https://*.olas.network/',
+ 'https://*.autonolas.tech/',
+
+ // web3modal and wallet connect
+ ...WALLET_CONNECT_LINKS,
+ 'https://rpc.walletconnect.com/',
+ 'wss://relay.walletconnect.org/',
+ 'wss://relay.walletconnect.com/',
+ 'https://explorer-api.walletconnect.com/',
+ 'wss://*.pusher.com/',
+ 'wss://www.walletlink.org/rpc',
+
+ // gnosis safe
+ 'https://safe-transaction-mainnet.safe.global/api/v1/',
+ 'https://safe-transaction-goerli.safe.global/api/',
+ 'https://safe-transaction-gnosis-chain.safe.global/api/',
+ 'https://safe-transaction-polygon.safe.global/api/',
+
+ // chains
+ 'https://eth-mainnet.g.alchemy.com/v2/',
+ 'https://eth-goerli.g.alchemy.com/v2/',
+ 'https://gno.getblock.io/',
+ 'https://polygon-mainnet.g.alchemy.com/v2/',
+ 'https://polygon-mumbai-bor.publicnode.com/',
+ 'https://rpc.chiado.gnosis.gateway.fm/',
+ 'https://api.devnet.solana.com/',
+ 'wss://api.devnet.solana.com/',
+ 'https://api.mainnet-beta.solana.com/',
+ 'wss://api.mainnet-beta.solana.com/',
+ 'https://holy-convincing-bird.solana-mainnet.quiknode.pro/',
+ 'wss://holy-convincing-bird.solana-mainnet.quiknode.pro/',
+ 'https://arb1.arbitrum.io/rpc/',
+ 'https://sepolia-rollup.arbitrum.io/rpc',
+ 'https://rpc.gnosischain.com/',
+ 'https://mainnet.base.org/',
+ 'https://sepolia.base.org/',
+ 'https://mainnet.optimism.io',
+ 'https://sepolia.optimism.io/',
+ 'https://forno.celo.org',
+ 'https://alfajores-forno.celo-testnet.org',
+ 'https://api.web3modal.com/',
+
+ // tenderly
+ 'https://virtual.mainnet.rpc.tenderly.co/',
+
+ // others
+ 'https://api.thegraph.com/',
+ 'https://sockjs-us3.pusher.com/',
+
+ ...VERCEL_LINKS,
+];
+
+const SCRIPT_SRC = ["'self'", 'https://vercel.live/', 'https://fonts.googleapis.com/'];
+
+export const getCspHeaders = () => {
+ if (!process.env.NEXT_PUBLIC_AUTONOLAS_SUB_GRAPH_URL) return [];
+
+ const connectSrc: CSPDirective = [
+ ...ALLOWED_ORIGINS,
+
+ // env variables
+ process.env.NEXT_PUBLIC_AUTONOLAS_SUB_GRAPH_URL,
+ ];
+
+ if (isDev) {
+ connectSrc.push('http://localhost');
+ connectSrc.push('ws://localhost');
+ }
+
+ const getNextSafeHeaders = () => {
+ if (typeof nextSafe !== 'function') return [];
+
+ // @ts-expect-error: For some reason, TypeScript is not recognizing the function
+ return nextSafe({
+ isDev,
+ /**
+ * Content Security Policy
+ * @see https://content-security-policy.com/
+ */
+ contentSecurityPolicy: {
+ 'default-src': "'none'",
+ 'script-src': SCRIPT_SRC,
+ 'connect-src': connectSrc,
+ 'img-src': [
+ "'self'",
+ 'blob:',
+ 'data:',
+ 'https://*.autonolas.tech/',
+ 'https://explorer-api.walletconnect.com/w3m/',
+ ...WALLET_CONNECT_LINKS,
+ ...GATEWAY_LINKS,
+ ...VERCEL_LINKS,
+ ],
+ /**
+ * It is less harmful to allow 'unsafe-inline' in style-src, please read the article below
+ * @see https://scotthelme.co.uk/can-you-get-pwned-with-css/
+ */
+ 'style-src': [
+ "'self'",
+ 'https://fonts.googleapis.com/',
+ "'unsafe-inline'",
+ 'https://vercel.live/fonts',
+ ],
+ 'font-src': ["'self'", 'https://fonts.gstatic.com'],
+ 'frame-src': ["'self'", 'https://vercel.live/', ...WALLET_CONNECT_LINKS],
+ },
+ permissionsPolicyDirectiveSupport: ['standard'],
+ });
+ };
+
+ /**
+ * Some headers might throw warnings in the console - they are safe to ignore.
+ * @see https://trezy.gitbook.io/next-safe/usage/troubleshooting#why-do-i-see-so-many-unrecognized-feature-warnings
+ */
+ const headers = [
+ ...getNextSafeHeaders(),
+ { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
+ ];
+
+ return headers;
+};
diff --git a/libs/common-middleware/src/lib/prohibitedCountries.ts b/libs/common-middleware/src/lib/prohibitedCountries.ts
new file mode 100644
index 00000000..b992b378
--- /dev/null
+++ b/libs/common-middleware/src/lib/prohibitedCountries.ts
@@ -0,0 +1,13 @@
+/* eslint-disable @nx/enforce-module-boundaries */
+import prohibitedAddresses from 'libs/util-prohibited-data/src/lib/prohibited-addresses.json';
+
+export const getRedirectUrl = async (pathName: string, countryName?: string) => {
+ const prohibitedCountriesCode = Object.values(prohibitedAddresses) as unknown as string[];
+
+ const isProhibited = countryName ? prohibitedCountriesCode.includes(countryName) : false;
+
+ if (pathName === '/not-legal') {
+ return isProhibited ? null : '/';
+ }
+ return isProhibited ? '/not-legal' : null;
+};
diff --git a/libs/common-middleware/src/middleware.ts b/libs/common-middleware/src/middleware.ts
new file mode 100644
index 00000000..2e7d94b0
--- /dev/null
+++ b/libs/common-middleware/src/middleware.ts
@@ -0,0 +1,39 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+import { getCspHeaders } from './lib/cspHeader';
+import { getRedirectUrl } from './lib/prohibitedCountries';
+
+export const middleware = async (request: NextRequest) => {
+ const country = request.geo?.country;
+ const redirectUrl = await getRedirectUrl(request.nextUrl.pathname, country);
+
+ const response = redirectUrl
+ ? NextResponse.redirect(new URL(redirectUrl, request.nextUrl))
+ : NextResponse.next();
+
+ const cspHeaders = getCspHeaders();
+
+ /**
+ * apply CSP headers
+ * @see https://nextjs.org/docs/app/building-your-application/routing/middleware#setting-headers
+ */
+ cspHeaders.forEach((header) => {
+ const { key, value } = header;
+ response.headers.set(key, value);
+ });
+
+ return response;
+};
+
+export const config = {
+ matcher: [
+ /*
+ * Match all request paths except for the ones starting with:
+ * - api (API routes)
+ * - _next/static (static files)
+ * - _next/image (image optimization files)
+ * - favicon.ico (favicon file)
+ */
+ '/((?!api|_next/static|_next/image|favicon.ico).*)',
+ ],
+};
diff --git a/libs/common-middleware/tsconfig.json b/libs/common-middleware/tsconfig.json
new file mode 100644
index 00000000..95cfeb24
--- /dev/null
+++ b/libs/common-middleware/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "allowJs": false,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "strict": true
+ },
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json"
+ }
+ ],
+ "extends": "../../tsconfig.base.json"
+}
diff --git a/libs/common-middleware/tsconfig.lib.json b/libs/common-middleware/tsconfig.lib.json
new file mode 100644
index 00000000..08e579bc
--- /dev/null
+++ b/libs/common-middleware/tsconfig.lib.json
@@ -0,0 +1,25 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": [
+ "node",
+ "@nx/react/typings/cssmodule.d.ts",
+ "@nx/react/typings/image.d.ts",
+ "next",
+ "@nx/next/typings/image.d.ts"
+ ]
+ },
+ "exclude": [
+ "jest.config.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.js",
+ "src/**/*.test.js",
+ "src/**/*.spec.jsx",
+ "src/**/*.test.jsx"
+ ],
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
+}
diff --git a/libs/util-prohibited-data/src/index.ts b/libs/util-prohibited-data/src/index.ts
index fe50d205..5c7f8481 100644
--- a/libs/util-prohibited-data/src/index.ts
+++ b/libs/util-prohibited-data/src/index.ts
@@ -2,8 +2,11 @@ import { toLower } from 'lodash';
import { Address } from 'viem';
import prohibitedAddresses from './lib/prohibited-addresses.json';
+import prohibitedCountries from './lib/prohibited-countries.json';
export const isAddressProhibited = (address: Address | undefined) => {
const addresses = prohibitedAddresses.map((e) => toLower(e));
return addresses.includes(toLower(address));
};
+
+export { prohibitedCountries, prohibitedAddresses };
diff --git a/tsconfig.base.json b/tsconfig.base.json
index b33be9b6..1cad8f3d 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -33,6 +33,8 @@
"@autonolas-frontend-mono/feature-service-status-info": [
"libs/feature-service-status-info/src/index.ts"
],
+ "@autonolas-frontend-mono/common-middleware": ["libs/common-middleware/src/index.ts"],
+ "@autonolas-frontend-mono/common-middleware/server": ["libs/common-middleware/src/server.ts"],
"@autonolas-frontend-mono/service-status-info": ["libs/service-status-info/src/index.ts"],
"@autonolas-frontend-mono/ui-theme": ["libs/ui-theme/src/index.ts"],
"@autonolas-frontend-mono/util-contracts": ["libs/util-contracts/src/index.ts"],