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

feat(repo): add stricter headers to network requests Refs BFE-449 #300

Open
wants to merge 6 commits into
base: v2
Choose a base branch
from
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
8 changes: 1 addition & 7 deletions apps/honey/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,11 @@ export const config = {
images: {
unoptimized: process.env.NEXT_PUBLIC_HOST === "ipfs" ? true : undefined,
remotePatterns: [
{
protocol: "https",
hostname: "s2.coinmarketcap.com",
port: "",
pathname: "/static/img/coins/**",
},
{
protocol: "https",
hostname: "res.cloudinary.com",
port: "",
pathname: "/duv0g402y/image/upload/**",
pathname: "/duv0g402y/**",
},
{
protocol: "https",
Expand Down
5 changes: 3 additions & 2 deletions apps/honey/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import "../styles/globals.css";
import { IBM_Plex_Sans, Jua } from "next/font/google";
import Script from "next/script";
import { honeyName, honeyUrl } from "@bera/config";
import { honeyName, honeyUrl, isIPFS } from "@bera/config";
import {
Footer,
Header,
Expand Down Expand Up @@ -34,6 +33,8 @@ export const metadata: Metadata = {
description: "Mint, redeem, and trade Honey",
};

export const dynamic = isIPFS ? "auto" : "force-dynamic";

export default function RootLayout(props: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
Expand Down
48 changes: 45 additions & 3 deletions apps/honey/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { NextResponse, type NextRequest } from "next/server";
import {
connectionSources,
fontSources,
frameSources,
pictureSources,
} from "@bera/config";

const BLOCKED_COUNTRY = [
"BA",
Expand All @@ -22,21 +28,57 @@ const BLOCKED_COUNTRY = [
"UK",
"ZW",
];

export { default } from "next-auth/middleware";
export const config = {
matcher: ["/((?!monitoring-tunnel))"],
matcher: ["/((?!monitoring-tunnel).*)"],
};

export function middleware(req: NextRequest) {
// Extract country
const country = req.geo?.country || "CA";

// Create response object
const response = NextResponse.rewrite(req.nextUrl);
const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
const isDevelopment = process.env.NODE_ENV === "development";
const isPreview = process.env.VERCEL_ENV === "preview";

// Allow unsafe-eval for script-src in development for hot reloading and react devtools
// Allow unsafe-inline for preview for vercel toolbar and comments
const cspHeader = `
default-src 'self';
base-uri 'self';
frame-src 'self' ${frameSources.join(" ")};
script-src 'self' 'sha256-k2HGvaYkGyYZxOwKGxgE1mr06tZEDcEXNZ5mdcldK0o=' 'nonce-${nonce}' 'strict-dynamic' ${
isDevelopment ? "'unsafe-eval'" : ""
};
font-src 'self' ${fontSources.join(" ")};
style-src 'self' 'unsafe-inline';
img-src 'self' data: ${pictureSources.join(" ")};
connect-src 'self' ${connectionSources.join(" ")};
`
.replace(/\s{2,}/g, " ")
.trim();

const securityHeaders = {
"Content-Security-Policy": cspHeader,
"X-Frame-Options": "SAMEORIGIN",
"X-Content-Type-Options": "nosniff",
"X-Nonce": nonce,
};

Object.entries(securityHeaders).forEach(([key, value]) => {
response.headers.set(key, value);
});

// Specify the correct pathname
if (BLOCKED_COUNTRY.includes(country)) {
req.nextUrl.pathname = "/access-deny";
} else {
req.nextUrl.pathname = "/";
}

// Rewrite to URL
return NextResponse.rewrite(req.nextUrl);
// Return response with security headers
return response;
}
6 changes: 0 additions & 6 deletions apps/hub/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ const config = {
images: {
unoptimized: process.env.NEXT_PUBLIC_HOST === "ipfs" ? true : undefined,
remotePatterns: [
{
protocol: "https",
hostname: "s2.coinmarketcap.com",
port: "",
pathname: "/static/img/coins/**",
},
{
protocol: "https",
hostname: "res.cloudinary.com",
Expand Down
4 changes: 2 additions & 2 deletions apps/hub/src/app/PostHogPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export default function PostHogPageView(): null {
// Track pageviews
if (pathname && posthog) {
let url = window.origin + pathname;
if (searchParams.toString()) {
url = `${url}?${searchParams.toString()}`;
if (searchParams?.toString()) {
url = `${url}?${searchParams?.toString()}`;
}
posthog.capture("$pageview", {
$current_url: url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useState } from "react";

export const ProposalsList = () => {
const router = useRouter();
const parms = useParams();
const params = useParams();

const { currentTopic } = useGovernance();
const [sortBy, setSortBy] = useState<{
Expand Down Expand Up @@ -114,16 +114,16 @@ export const ProposalsList = () => {
if (!isIPFS) {
router.prefetch(
isIPFS
? `/governance/${parms.genre}/proposal/?id=${proposal.id}`
: `/governance/${parms.genre}/proposal/${proposal.id}`,
? `/governance/${params?.genre}/proposal/?id=${proposal.id}`
: `/governance/${params?.genre}/proposal/${proposal.id}`,
);
}
}}
onClick={() => {
router.push(
isIPFS
? `/governance/${parms.genre}/proposal/?id=${proposal.id}`
: `/governance/${parms.genre}/proposal/${proposal.id}`,
? `/governance/${params?.genre}/proposal/?id=${proposal.id}`
: `/governance/${params?.genre}/proposal/${proposal.id}`,
);
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function NewProposal({ genre }: { genre: PROPOSAL_GENRE }) {
if (!canPropose && account) {
openNotEnoughVotingPowerDialog({
onClose: () => {
router.replace(`/governance/${params.genre}`);
router.replace(`/governance/${params?.genre}`);
},
});
} else {
Expand All @@ -43,7 +43,7 @@ export default function NewProposal({ genre }: { genre: PROPOSAL_GENRE }) {
<div className="sm:flex sm:justify-between relative">
<div>
<Link
href={`/governance/${params.genre}`}
href={`/governance/${params?.genre}`}
className="mb-8 flex items-center gap-1 text-sm font-medium text-muted-foreground"
>
<Icons.arrowLeft className="h-4 w-4" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const SearchParamsProposal: FC = () => {
const sp = useSearchParams();

return (
<ProposalDetails proposalId={sp.get("id")!} txHash={sp.get("txHash")} />
<ProposalDetails proposalId={sp?.get("id")!} txHash={sp?.get("txHash")} />
);
};

Expand Down
8 changes: 4 additions & 4 deletions apps/hub/src/app/incentivize/incentivize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import {
rewardVaultAbi,
TransactionActionType,
truncateHash,
useMultipleTokenInformation,
usePollAllowance,
useRewardVaultIncentives,
useRewardVault,
useRewardVaultIncentives,
useTokenInformation,
type Token,
useMultipleTokenInformation,
} from "@bera/berajs";
import { blockExplorerUrl } from "@bera/config";
import {
Expand All @@ -32,8 +32,8 @@ import { Address, formatUnits, isAddress, parseUnits } from "viem";

export const Incentivize = () => {
const sp = useSearchParams();
const gauge = sp.get("gauge");
const selectedToken = sp.get("token") as Address | null;
const gauge = sp?.get("gauge");
const selectedToken = sp?.get("token") as Address | null;
//is valid pool address

const {
Expand Down
10 changes: 6 additions & 4 deletions apps/hub/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import "../styles/globals.css";
import { existsSync, readFileSync } from "fs";
import path from "path";
import { Metadata } from "next";
import dynamic from "next/dynamic";
import { default as dynamicLoad } from "next/dynamic";
import { IBM_Plex_Sans } from "next/font/google";
import Script from "next/script";
import { hubName, hubUrl, tokenListUrl } from "@bera/config";
import { hubName, hubUrl, isIPFS, tokenListUrl } from "@bera/config";
import {
Footer,
Header,
Expand Down Expand Up @@ -33,7 +32,10 @@ export const metadata: Metadata = {
default: hubName,
},
};
const PostHogPageView = dynamic(() => import("./PostHogPageView"), {

export const dynamic = isIPFS ? "auto" : "force-dynamic";

const PostHogPageView = dynamicLoad(() => import("./PostHogPageView"), {
ssr: false,
});

Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/app/pools/(ipfs)/deposit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const _AddLiquidityStaticPage = () => {
}

const searchParams = useSearchParams();
const poolId = searchParams.get("address");
const poolId = searchParams?.get("address");

if (!poolId) {
return notFound();
Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/app/pools/(ipfs)/details/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const _PoolStaticPage = () => {
}

const searchParams = useSearchParams();
const poolId = searchParams.get("address");
const poolId = searchParams?.get("address");

if (!poolId) {
return notFound();
Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/app/pools/(ipfs)/withdraw/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const _PoolStaticPage = () => {
}

const searchParams = useSearchParams();
const poolId = searchParams.get("address");
const poolId = searchParams?.get("address");

if (!poolId) {
return notFound();
Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/app/pools/PoolsPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { PoolSearch } from "./PoolsTable";

export function PoolsPageContent({ pools }: { pools?: any }) {
const sp = useSearchParams();
const poolType = sp.get("pool") as "allPools" | "userPools";
const poolType = (sp?.get("pool") as "allPools" | "userPools") ?? "allPools";

return (
<SWRFallback
Expand Down
8 changes: 4 additions & 4 deletions apps/hub/src/app/pools/PoolsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export const PoolSearch = ({
poolType: "allPools" | "userPools";
}) => {
const searchParams = useSearchParams();
const page = searchParams.get("page");
const pageSize = searchParams.get("pageSize");
const sort = searchParams.get("sort");
const direction = searchParams.get("direction");
const page = searchParams?.get("page");
const pageSize = searchParams?.get("pageSize");
const sort = searchParams?.get("sort");
const direction = searchParams?.get("direction");

const { account } = useBeraJs();
const [sorting, setSorting] = useState([
Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/app/redeem/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default function Swap() {
return (
<div className="container">
<SwapContent
inutCurrency={bgtTokenAddress}
inputCurrency={bgtTokenAddress}
outputCurrency={nativeTokenAddress}
isRedeem={true}
/>
Expand Down
12 changes: 6 additions & 6 deletions apps/hub/src/app/swap/swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ import { SwapCard } from "~/components/swap-card";

export const SwapPage: FC = () => {
const sp = useSearchParams();
const inputCurrency = sp.get("inputCurrency");
const outputCurrency = sp.get("outputCurrency");
const inputCurrency = sp?.get("inputCurrency") ?? null;
const outputCurrency = sp?.get("outputCurrency") ?? null;

return (
<div className="container">
<SwapContent
inutCurrency={inputCurrency}
inputCurrency={inputCurrency}
outputCurrency={outputCurrency}
isRedeem={false}
/>
</div>
);
};
export const SwapContent = ({
inutCurrency,
inputCurrency,
outputCurrency,
isRedeem,
}: {
inutCurrency: string | null;
inputCurrency: string | null;
outputCurrency: string | null;
isRedeem: boolean;
}) => {
Expand Down Expand Up @@ -56,7 +56,7 @@ export const SwapContent = ({
</Link>
</div>
<SwapCard
inputCurrency={inutCurrency}
inputCurrency={inputCurrency}
outputCurrency={outputCurrency}
isRedeem={isRedeem}
/>
Expand Down
4 changes: 2 additions & 2 deletions apps/hub/src/app/validators/validator/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ const SuspendedValidatorPage = () => {
return notFound();
}

if (!searchParams.get("address")) {
if (!searchParams?.get("address")) {
throw Error("No validator address found in search params");
}

return (
<Validator
validatorAddress={searchParams.get("address") as `0x${string}`}
validatorAddress={searchParams?.get("address") as `0x${string}`}
/>
);
};
Expand Down
2 changes: 1 addition & 1 deletion apps/hub/src/app/vaults/vault/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Loading from "../[address]/loading";

const Gauge: FC = () => {
const searchParams = useSearchParams();
const address = searchParams.get("address");
const address = searchParams?.get("address");

if (!address || !isAddress(address)) {
return notFound();
Expand Down
Loading
Loading