protect-scr
Version:
Comprehensive client-side security protection for React applications against screenshots, printing, and unauthorized access
142 lines • 5.28 kB
JavaScript
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