UNPKG

protect-scr

Version:

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

142 lines 5.28 kB
export class WatermarkManager { constructor(config) { this.isVisible = false; this.config = { text: 'PROTECTED CONTENT', opacity: 0.1, fontSize: 48, color: '#000000', rotation: -45, ...config }; } show() { if (this.isVisible) return; this.createWatermarkElement(); this.isVisible = true; } hide() { if (!this.isVisible || !this.watermarkElement) return; this.watermarkElement.remove(); this.watermarkElement = undefined; this.isVisible = false; } updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; if (this.isVisible) { this.hide(); this.show(); } } createWatermarkElement() { this.watermarkElement = document.createElement('div'); this.watermarkElement.id = 'secure-app-shield-watermark'; // Make watermark unselectable and non-interactive this.watermarkElement.style.cssText = ` position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; pointer-events: none !important; z-index: 9999999 !important; user-select: none !important; -webkit-user-select: none !important; -moz-user-select: none !important; -ms-user-select: none !important; overflow: hidden !important; background: transparent !important; `; this.createWatermarkPattern(); // Append to body document.body.appendChild(this.watermarkElement); // Make it unremovable via developer tools this.protectWatermark(); } createWatermarkPattern() { if (!this.watermarkElement) return; // Create repeating watermark pattern const pattern = document.createElement('div'); pattern.style.cssText = ` width: 100% !important; height: 100% !important; position: relative !important; overflow: hidden !important; `; // Calculate pattern spacing const spacing = this.config.fontSize * 3; const rows = Math.ceil(window.innerHeight / spacing) + 2; const cols = Math.ceil(window.innerWidth / spacing) + 2; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const watermarkText = document.createElement('div'); watermarkText.textContent = this.config.text; watermarkText.style.cssText = ` position: absolute !important; left: ${col * spacing}px !important; top: ${row * spacing}px !important; font-size: ${this.config.fontSize}px !important; color: ${this.config.color} !important; opacity: ${this.config.opacity} !important; transform: rotate(${this.config.rotation}deg) !important; transform-origin: center !important; white-space: nowrap !important; font-family: Arial, sans-serif !important; font-weight: bold !important; pointer-events: none !important; user-select: none !important; -webkit-user-select: none !important; -moz-user-select: none !important; -ms-user-select: none !important; `; pattern.appendChild(watermarkText); } } this.watermarkElement.appendChild(pattern); } protectWatermark() { if (!this.watermarkElement) return; // Observe for removal attempts const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { mutation.removedNodes.forEach((node) => { if (node === this.watermarkElement) { // Recreate watermark if removed setTimeout(() => { if (this.isVisible) { this.createWatermarkElement(); } }, 0); } }); } // Check for style modifications if (mutation.type === 'attributes' && mutation.target === this.watermarkElement) { if (mutation.attributeName === 'style') { // Restore original styles if modified this.createWatermarkElement(); } } }); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); // Also observe the watermark element itself observer.observe(this.watermarkElement, { attributes: true, attributeFilter: ['style', 'class'] }); // Store observer reference for cleanup this.watermarkElement.__observer = observer; } } //# sourceMappingURL=WatermarkManager.js.map