From 40e699aff048ac3ce4c378b9a54025a21e655b45 Mon Sep 17 00:00:00 2001 From: Melvin Jones Repol Date: Sat, 28 Mar 2026 18:25:02 +0800 Subject: [PATCH] feat: add BrowserCheck to block headless browsers - Add a client component that runs on mount and detects headless traits - Checks navigator.webdriver and navigator.hardwareConcurrency < 2 - Replaces page with an "Access Denied" message and stops loading when detected - Mount component in RootLayout alongside DevToolsDetector in production --- app/components/BrowserCheck.tsx | 27 +++++++++++++++++++++++++++ app/layout.tsx | 2 ++ 2 files changed, 29 insertions(+) create mode 100644 app/components/BrowserCheck.tsx diff --git a/app/components/BrowserCheck.tsx b/app/components/BrowserCheck.tsx new file mode 100644 index 0000000..644ce58 --- /dev/null +++ b/app/components/BrowserCheck.tsx @@ -0,0 +1,27 @@ +"use client"; + +import { useEffect } from "react"; + +export default function BrowserCheck() { + useEffect(() => { + async function detectHeadless() { + try { + const isWebdriver = navigator.webdriver; + const hardwareConcurrency = navigator.hardwareConcurrency || 0; + + if (isWebdriver || hardwareConcurrency < 2) { + document.title = "Access Denied"; + document.body.innerHTML = + "

Access Denied

"; + window.stop(); + } + } catch (err) { + console.error("Browser check error:", err); + } + } + + detectHeadless(); + }, []); + + return null; +} diff --git a/app/layout.tsx b/app/layout.tsx index fc26504..462700d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -7,6 +7,7 @@ import DevToolsDetector from "./components/DevToolsDetector"; import NextTopLoader from "nextjs-toploader"; import { headers } from "next/headers"; import NortonSafeweb from "./components/NortonSafeweb"; +import BrowserCheck from "./components/BrowserCheck"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -120,6 +121,7 @@ export default function RootLayout({ {isProduction && ( <> + )}