UNPKG

react-anticapture

Version:

A lightweight React component that helps prevent users from capturing (copying, selecting, printing, or screenshotting) sensitive information rendered on your website. Perfect for privacy, security, and content protection in React applications.

1 lines 22.7 kB
{"version":3,"file":"index.umd.cjs","sources":["../src/shared/constant.ts","../src/shared/utils.ts","../src/lib/FullPage/useFullPage.ts","../src/lib/FullPage/FullPage.tsx"],"sourcesContent":["export const CLIPBOARD = \"CLIPBOARD\";\r\nexport const COPY = \"COPY\";\r\nexport const ENTER = \"ENTER\";\r\nexport const DEFAULT = \"DEFAULT\";\r\n\r\nexport type AlertType = typeof CLIPBOARD | typeof COPY | typeof ENTER | typeof DEFAULT;","/**\r\n * Displays a warning message to the user, instructing them to close devtools/console.\r\n * This function directly manipulates the DOM.\r\n */\r\nexport const warningDevtools = (): void => {\r\n document.body.innerHTML = '<p class=\"font-weight-bold\">Please close devtools/console to continue.</p>';\r\n document.body.style.margin = '0';\r\n document.body.style.overflow = 'hidden';\r\n document.body.style.height = '100vh';\r\n document.body.style.display = 'flex';\r\n document.body.style.alignItems = 'center';\r\n document.body.style.justifyContent = 'center';\r\n document.body.style.backgroundColor = '#f0f0f0';\r\n document.body.style.color = '#333';\r\n};\r\n\r\n/**\r\n * Checks if a given key combination matches any of the blacklisted commands.\r\n * @param keyCombinationCodes An array of `KeyboardEvent.code` values representing the pressed keys.\r\n * @returns `true` if the combination is blacklisted, `false` otherwise.\r\n */\r\nexport const isBlacklistedCommand = (keyCombinationCodes: string[]): boolean => {\r\n // Define the blacklisted commands using the more specific 'event.code' values\r\n // For modifier keys, we will check for either left or right variants.\r\n const blacklistCommands: string[][] = [\r\n // Screenshot/Screen Recording (using event.code for precision)\r\n [\"PrintScreen\"],\r\n [\"Meta\"],\r\n [\"Alt\", \"PrintScreen\"], // This will be handled specially\r\n [\"Meta\", \"PrintScreen\"], // This will be handled specially\r\n [\"Meta\", \"Shift\"], // This will be handled specially\r\n [\"Meta\", \"Shift\", \"KeyS\"],\r\n [\"Meta\", \"Shift\", \"Digit3\"],\r\n [\"Meta\", \"Shift\", \"Digit4\"],\r\n [\"Control\", \"Shift\", \"KeyP\"], // This will be handled specially\r\n [\"Meta\", \"KeyG\"],\r\n [\"Meta\", \"Alt\", \"KeyR\"],\r\n [\"Shift\", \"Meta\", \"Digit5\"],\r\n\r\n // Inspect Element / Developer Tools\r\n [\"F12\"],\r\n [\"Control\", \"Shift\", \"KeyI\"],\r\n [\"Control\", \"Shift\", \"KeyC\"],\r\n [\"Control\", \"Shift\", \"KeyJ\"],\r\n [\"Control\", \"KeyU\"],\r\n ];\r\n\r\n // Helper function to normalize modifier codes\r\n // e.g., converts 'MetaLeft' or 'MetaRight' to 'Meta' for comparison\r\n const normalizeCode = (code: string): string => {\r\n if (code === 'MetaLeft' || code === 'MetaRight') return 'Meta';\r\n if (code === 'AltLeft' || code === 'AltRight') return 'Alt';\r\n if (code === 'ShiftLeft' || code === 'ShiftRight') return 'Shift';\r\n if (code === 'ControlLeft' || code === 'ControlRight') return 'Control';\r\n return code;\r\n };\r\n\r\n // Normalize the incoming key combination codes\r\n const normalizedKeyCombination = keyCombinationCodes.map(normalizeCode);\r\n\r\n // Sort the normalized incoming key combination for consistent comparison\r\n const sortedNormalizedKeyCombination = [...normalizedKeyCombination].sort();\r\n\r\n return blacklistCommands.some(blacklisted => {\r\n // Normalize the blacklisted command for consistent comparison\r\n const sortedNormalizedBlacklisted = [...blacklisted].map(normalizeCode).sort();\r\n\r\n // Check if the lengths match and all normalized keys are present in both arrays in order\r\n return sortedNormalizedBlacklisted.length === sortedNormalizedKeyCombination.length &&\r\n sortedNormalizedBlacklisted.every((key, index) => key === sortedNormalizedKeyCombination[index]);\r\n });\r\n};\r\n\r\n/**\r\n * Requests the browser to enter fullscreen mode for a given element.\r\n * @param element The HTML element to make fullscreen.\r\n */\r\nexport const enterFullscreen = (element: HTMLElement | null): void => {\r\n if (element) {\r\n if (element.requestFullscreen) {\r\n element.requestFullscreen();\r\n } else if ((element as any).webkitRequestFullscreen) { /* Safari */\r\n (element as any).webkitRequestFullscreen();\r\n } else if ((element as any).mozRequestFullScreen) { /* Firefox */\r\n (element as any).mozRequestFullScreen();\r\n } else if ((element as any).msRequestFullscreen) { /* IE11 */\r\n (element as any).msRequestFullscreen();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Requests the browser to exit fullscreen mode.\r\n * This function should be called on the `document` object.\r\n */\r\nexport const exitFullscreen = (): void => {\r\n if (document.fullscreenElement) {\r\n if (document.exitFullscreen) {\r\n document.exitFullscreen();\r\n } else if ((document as any).webkitExitFullscreen) { /* Safari */\r\n (document as any).webkitExitFullscreen();\r\n } else if ((document as any).mozCancelFullScreen) { /* Firefox */\r\n (document as any).mozCancelFullScreen();\r\n } else if ((document as any).msExitFullscreen) { /* IE11 */\r\n (document as any).msExitFullscreen();\r\n }\r\n }\r\n};","import devTools from \"devtools-detect\";\r\nimport { CLIPBOARD, COPY, ENTER, DEFAULT, AlertType } from \"@/shared/constant\";\r\nimport { warningDevtools, isBlacklistedCommand } from \"@/shared/utils\";\r\nimport { useState, useEffect } from 'react';\r\n\r\n/**\r\n * Interface for the props of the useAntiCapture hook.\r\n */\r\nexport interface UseAntiCaptureProps {\r\n /**\r\n * An optional HTMLElement to attach click listeners for dismissing blur.\r\n * Defaults to the component's internal wrapper if not provided.\r\n */\r\n targetClick?: HTMLElement | null;\r\n /**\r\n * If true, prevents clipboard copy/paste actions and context menu.\r\n */\r\n clipboardPrevent?: boolean;\r\n /**\r\n * If true, detects and prevents developer tools from being open.\r\n */\r\n devtoolsPrevent?: boolean;\r\n /**\r\n * If true, prevents common screenshot and screen recording keyboard shortcuts.\r\n */\r\n screenshotPrevent?: boolean;\r\n /**\r\n * If true, turn on user-select css\r\n */\r\n userSelect?: boolean;\r\n}\r\n\r\n/**\r\n * Return type of the useAntiCapture hook.\r\n */\r\nexport interface UseAntiCaptureReturn {\r\n /**\r\n * True if the page content should be blurred.\r\n */\r\n blurPage: boolean;\r\n /**\r\n * Object containing the current alert message details.\r\n */\r\n alertText: { text: string; color: string; type: AlertType };\r\n}\r\n\r\n/**\r\n * A React hook to implement anti-capture functionalities like preventing screenshots,\r\n * clipboard operations, and devtools usage.\r\n * @param props Configuration options for anti-capture features.\r\n * @returns An object containing `blurPage` state and `alertText` for UI feedback.\r\n */\r\nexport const useAntiCapture = ({\r\n targetClick,\r\n clipboardPrevent = false,\r\n devtoolsPrevent = false,\r\n screenshotPrevent = true,\r\n}: UseAntiCaptureProps): UseAntiCaptureReturn => {\r\n const [pressedKeys, setPressedKeys] = useState<Record<string, boolean>>({});\r\n const [alertText, setAlertText] = useState<{ text: string; color: string; type: AlertType }>({ text: \"Press enter to continue.\", color: 'black', type: ENTER });\r\n const [isDevToolsOpen, setIsDevToolsOpen] = useState<boolean>(devTools.isOpen);\r\n const [blurPage, setBlurPage] = useState<boolean>(true); // Controlled centrally\r\n\r\n const addObjectKey = (key: string): void => setPressedKeys((prevKeys) => ({ ...prevKeys, [key]: true }));\r\n const deleteObjectKey = (key: string): void => setPressedKeys((prevKeys) => {\r\n const newKeys = { ...prevKeys };\r\n delete newKeys[key];\r\n return newKeys;\r\n });\r\n const deleteAllObjectKey = (): void => setPressedKeys({});\r\n\r\n const setAlertPopUp = (type: AlertType): void => {\r\n switch (type) {\r\n case COPY:\r\n setAlertText({ text: \"This page is prohibited from being copied or captured!\", color: 'red', type: COPY });\r\n break;\r\n case CLIPBOARD:\r\n setAlertText({ text: \"Please allow clipboard on your browser to continue.\", color: 'red', type: CLIPBOARD });\r\n break;\r\n case ENTER:\r\n setAlertText({ text: \"Press enter to continue.\", color: 'black', type: ENTER });\r\n break;\r\n case DEFAULT:\r\n setAlertText({ text: \"\", color: '', type: DEFAULT });\r\n break;\r\n default:\r\n break;\r\n }\r\n };\r\n\r\n const keyPressedArray = (): string[] => Object.keys(pressedKeys);\r\n useEffect(() => {\r\n if (pressedKeys && Object.keys(pressedKeys).length > 0 && alertText.type !== CLIPBOARD) {\r\n const result = isBlacklistedCommand(keyPressedArray())\r\n\r\n if (result) {\r\n setBlurPage(true)\r\n setAlertPopUp(COPY)\r\n deleteAllObjectKey()\r\n }\r\n }\r\n }, [pressedKeys])\r\n\r\n // --- DevTools Prevention ---\r\n if (devtoolsPrevent) useEffect(() => {\r\n const handleChange = (event: CustomEvent<{ isOpen: boolean; orientation: 'vertical' | 'horizontal' }>) => {\r\n if (event.detail.isOpen) {\r\n setIsDevToolsOpen(true);\r\n } else {\r\n window.location.reload();\r\n }\r\n };\r\n\r\n window.addEventListener(\"devtoolschange\", handleChange as EventListener);\r\n\r\n let intervalLog: ReturnType<typeof setInterval> | undefined;\r\n if (isDevToolsOpen) {\r\n console.clear();\r\n intervalLog = setInterval(() => {\r\n console.log(\"%c Close your devtools/console!\", 'background: #222; color: #bada55; font-size: 50px; text-align: end');\r\n setTimeout(() => { console.clear(); }, 900);\r\n }, 1000);\r\n warningDevtools();\r\n }\r\n\r\n return () => {\r\n if (intervalLog) clearInterval(intervalLog);\r\n window.removeEventListener(\"devtoolschange\", handleChange as EventListener);\r\n };\r\n }, [isDevToolsOpen, devtoolsPrevent]);\r\n\r\n // --- Clipboard and Context Menu Prevention ---\r\n if (clipboardPrevent) useEffect(() => {\r\n const preventDefault = (e: Event) => e.preventDefault();\r\n const rewriteClipboard = (e: ClipboardEvent) => {\r\n e.preventDefault();\r\n navigator.clipboard.writeText(\"\");\r\n setAlertPopUp(COPY);\r\n setBlurPage(true);\r\n };\r\n\r\n window.addEventListener(\"contextmenu\", preventDefault);\r\n window.addEventListener(\"copy\", rewriteClipboard);\r\n window.addEventListener(\"paste\", rewriteClipboard);\r\n\r\n return () => {\r\n window.removeEventListener(\"contextmenu\", preventDefault);\r\n window.removeEventListener(\"copy\", rewriteClipboard);\r\n window.removeEventListener(\"paste\", rewriteClipboard);\r\n };\r\n }, [clipboardPrevent]);\r\n\r\n // --- Keydown and Keyup Handling for Screenshots/Inspect Element ---\r\n useEffect(() => {\r\n const handleKeyDown = (event: KeyboardEvent) => {\r\n if (event.key === \"Enter\") {\r\n if (alertText.type === ENTER || alertText.type === CLIPBOARD) {\r\n setAlertPopUp(DEFAULT);\r\n setBlurPage(false);\r\n }\r\n } else {\r\n if (screenshotPrevent) {\r\n // Prevent common inspect element/devtools shortcuts\r\n if (event.key === \"F12\") event.preventDefault();\r\n if (event.ctrlKey && event.code === \"KeyU\") event.preventDefault();\r\n if (event.ctrlKey && event.shiftKey && ['KeyI', 'KeyC', 'KeyJ'].includes(event.code)) event.preventDefault();\r\n }\r\n\r\n // Add pressed key using event.code\r\n addObjectKey(event.code);\r\n }\r\n };\r\n\r\n const handleKeyUp = (event: KeyboardEvent) => {\r\n if (alertText.type === ENTER || alertText.type === CLIPBOARD) {\r\n deleteObjectKey(event.code);\r\n return;\r\n }\r\n\r\n if (screenshotPrevent && event.key === \"PrintScreen\") {\r\n event.preventDefault();\r\n setBlurPage(true);\r\n setAlertPopUp(COPY);\r\n navigator.clipboard.writeText(\"\");\r\n } else {\r\n // Delete released key using event.code\r\n deleteObjectKey(event.code);\r\n }\r\n };\r\n\r\n document.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n return () => {\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [alertText.type, screenshotPrevent]);\r\n\r\n // --- Page Blur on Mouse Leave ---\r\n useEffect(() => {\r\n const blurPageOnMouseLeave = () => {\r\n if ([ENTER, CLIPBOARD].includes(alertText.type)) return;\r\n setBlurPage(true);\r\n };\r\n\r\n document.querySelector(\"html\")?.addEventListener(\"mouseleave\", blurPageOnMouseLeave);\r\n\r\n return () => {\r\n document.querySelector(\"html\")?.removeEventListener(\"mouseleave\", blurPageOnMouseLeave);\r\n };\r\n }, [alertText.type]);\r\n\r\n const handleWrapperClick = () => {\r\n\r\n if (blurPage && ![ENTER, CLIPBOARD].includes(alertText.type)) {\r\n setBlurPage(false);\r\n if (alertText.type === COPY) {\r\n setAlertPopUp(DEFAULT);\r\n }\r\n }\r\n };\r\n // --- Click to Dismiss Blur/Alert ---\r\n useEffect(() => {\r\n let targetElement: HTMLElement | null = targetClick || document.querySelector(\"html\");\r\n\r\n if (targetElement) {\r\n targetElement.addEventListener(\"click\", handleWrapperClick);\r\n }\r\n\r\n return () => {\r\n if (targetElement) {\r\n targetElement.removeEventListener(\"click\", handleWrapperClick);\r\n }\r\n };\r\n }, [alertText, blurPage, targetClick]);\r\n\r\n return {\r\n blurPage,\r\n alertText,\r\n };\r\n};\r\n","import { FC, PropsWithChildren } from 'react';\r\nimport { useAntiCapture, UseAntiCaptureProps } from './useFullPage'; // Import types\r\nimport classes from \"./FullPage.module.css\"\r\n\r\n/**\r\n * Props for the FullPage component.\r\n * Extends the UseAntiCaptureProps to allow passing hook configurations directly.\r\n */\r\nexport interface FullPageProps extends UseAntiCaptureProps {\r\n}\r\n\r\n/**\r\n * A React component that wraps your application content to provide full-page anti-capture protection.\r\n * It uses the `useAntiCapture` hook internally to manage blur, alerts, and event listeners.\r\n */\r\nconst FullPage: FC<PropsWithChildren<FullPageProps>> = ({\r\n children,\r\n userSelect = true,\r\n ...hookProps // Destructure remaining props to pass directly to the hook\r\n}) => {\r\n\r\n const { blurPage, alertText } = useAntiCapture(hookProps); // Pass hookProps to the hook\r\n\r\n return (\r\n <>\r\n <div className={classes.alertAnticapture} style={{\r\n display: alertText.text ? 'block' : 'none'\r\n }}>\r\n {alertText.text && <p style={{ fontWeight: \"bolder\", color: alertText.color, margin: 0 }}>{alertText.text}</p>}\r\n </div>\r\n <div\r\n id='anticapture-wrapper'\r\n className={`\r\n ${classes.anticaptureWrapper} \r\n ${blurPage ? classes.anticaptureBlurPage : \"\"} \r\n ${userSelect ? classes.userSelect : \"\"}\r\n `}\r\n style={{\r\n transition: 'filter 0.1s ease-in-out',\r\n }}\r\n >\r\n {children}\r\n </div>\r\n </>\r\n );\r\n};\r\n\r\nexport { FullPage };"],"names":["CLIPBOARD","COPY","ENTER","DEFAULT","warningDevtools","isBlacklistedCommand","keyCombinationCodes","blacklistCommands","normalizeCode","code","sortedNormalizedKeyCombination","blacklisted","sortedNormalizedBlacklisted","key","index","useAntiCapture","targetClick","clipboardPrevent","devtoolsPrevent","screenshotPrevent","pressedKeys","setPressedKeys","useState","alertText","setAlertText","isDevToolsOpen","setIsDevToolsOpen","devTools","blurPage","setBlurPage","addObjectKey","prevKeys","deleteObjectKey","newKeys","deleteAllObjectKey","setAlertPopUp","type","keyPressedArray","useEffect","handleChange","event","intervalLog","preventDefault","rewriteClipboard","handleKeyDown","handleKeyUp","blurPageOnMouseLeave","_a","handleWrapperClick","targetElement","children","userSelect","hookProps","jsxs","Fragment","jsx","classes"],"mappings":"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"}