UNPKG

protect-scr

Version:

Comprehensive client-side security protection for React applications against screenshots, printing, and unauthorized access

165 lines 7.16 kB
export class ScreenshotProtector { constructor(config) { this.isActive = false; this.eventListeners = []; this.config = config; } start() { if (this.isActive) return; this.isActive = true; this.setupVisibilityDetection(); this.setupPrintScreenDetection(); this.setupMobileScreenshotDetection(); this.setupBrowserScreenshotDetection(); } stop() { if (!this.isActive) return; this.isActive = false; this.eventListeners.forEach(removeListener => removeListener()); this.eventListeners = []; // Remove blur effect if applied document.body.style.filter = ''; } setupVisibilityDetection() { const visibilityHandler = () => { if (document.hidden && this.config.blurOnFocusLoss) { // Blur content when window loses focus (potential screenshot) document.body.style.filter = 'blur(10px)'; document.body.style.transition = 'filter 0.1s'; } else { document.body.style.filter = ''; } }; document.addEventListener('visibilitychange', visibilityHandler); this.eventListeners.push(() => { document.removeEventListener('visibilitychange', visibilityHandler); }); // Also blur on window blur/focus const blurHandler = () => { var _a, _b; if (this.config.blurOnFocusLoss) { document.body.style.filter = 'blur(10px)'; } (_b = (_a = this.config).onAttempt) === null || _b === void 0 ? void 0 : _b.call(_a); }; const focusHandler = () => { document.body.style.filter = ''; }; window.addEventListener('blur', blurHandler); window.addEventListener('focus', focusHandler); this.eventListeners.push(() => { window.removeEventListener('blur', blurHandler); window.removeEventListener('focus', focusHandler); }); } setupPrintScreenDetection() { const keyHandler = (e) => { var _a, _b, _c, _d; // Detect Print Screen key if (e.key === 'PrintScreen' || e.keyCode === 44) { e.preventDefault(); e.stopPropagation(); // Clear clipboard to prevent screenshot saving if (navigator.clipboard) { navigator.clipboard.writeText('').catch(() => { // Fallback for older browsers const textArea = document.createElement('textarea'); textArea.value = ''; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); }); } (_b = (_a = this.config).onAttempt) === null || _b === void 0 ? void 0 : _b.call(_a); alert('Screenshots are not allowed for security reasons.'); return false; } // Detect Alt+Print Screen (active window screenshot) if (e.altKey && (e.key === 'PrintScreen' || e.keyCode === 44)) { e.preventDefault(); e.stopPropagation(); (_d = (_c = this.config).onAttempt) === null || _d === void 0 ? void 0 : _d.call(_c); alert('Screenshots are not allowed for security reasons.'); return false; } }; document.addEventListener('keydown', keyHandler, true); document.addEventListener('keyup', keyHandler, true); this.eventListeners.push(() => { document.removeEventListener('keydown', keyHandler, true); document.removeEventListener('keyup', keyHandler, true); }); } setupMobileScreenshotDetection() { // Detect mobile screenshot gestures (iOS and Android) let touchStartTime = 0; let simultaneousTouch = false; const touchStartHandler = (e) => { touchStartTime = Date.now(); if (e.touches.length > 1) { simultaneousTouch = true; } }; const touchEndHandler = (e) => { var _a, _b; const touchDuration = Date.now() - touchStartTime; // iOS screenshot: Home + Power button (simultaneous touch + quick release) // Android screenshot: Power + Volume Down (similar pattern) if (simultaneousTouch && touchDuration < 200) { (_b = (_a = this.config).onAttempt) === null || _b === void 0 ? void 0 : _b.call(_a); // Blur content briefly if (this.config.blurOnFocusLoss) { document.body.style.filter = 'blur(20px)'; setTimeout(() => { document.body.style.filter = ''; }, 1000); } } simultaneousTouch = false; }; document.addEventListener('touchstart', touchStartHandler, { passive: true }); document.addEventListener('touchend', touchEndHandler, { passive: true }); this.eventListeners.push(() => { document.removeEventListener('touchstart', touchStartHandler); document.removeEventListener('touchend', touchEndHandler); }); } setupBrowserScreenshotDetection() { // Detect browser screenshot extensions and tools const mediaHandler = (e) => { var _a, _b; // Detect screen capture API usage e.preventDefault(); e.stopPropagation(); (_b = (_a = this.config).onAttempt) === null || _b === void 0 ? void 0 : _b.call(_a); return false; }; // Block getUserMedia access that might be used for screen capture if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) { const originalGetDisplayMedia = navigator.mediaDevices.getDisplayMedia; navigator.mediaDevices.getDisplayMedia = function () { throw new Error('Screen capture is not allowed'); }; } // Detect canvas toDataURL calls (used by many screenshot tools) const originalToDataURL = HTMLCanvasElement.prototype.toDataURL; HTMLCanvasElement.prototype.toDataURL = function () { throw new Error('Canvas data extraction is not allowed'); }; // Detect canvas toBlob calls const originalToBlob = HTMLCanvasElement.prototype.toBlob; HTMLCanvasElement.prototype.toBlob = function () { throw new Error('Canvas data extraction is not allowed'); }; // Restore original methods on stop this.eventListeners.push(() => { HTMLCanvasElement.prototype.toDataURL = originalToDataURL; HTMLCanvasElement.prototype.toBlob = originalToBlob; }); } } //# sourceMappingURL=ScreenshotProtector.js.map