protect-scr
Version:
Comprehensive client-side security protection for React applications against screenshots, printing, and unauthorized access
224 lines (223 loc) • 8.43 kB
JavaScript
import { DevToolsDetector } from './DevToolsDetector';
import { ScreenshotProtector } from './ScreenshotProtector';
import { KeyboardProtector } from './KeyboardProtector';
import { PrintProtector } from './PrintProtector';
import { WatermarkManager } from './WatermarkManager';
export class SecurityManager {
constructor(config = {}) {
this.isActive = false;
this.eventListeners = [];
this.config = this.mergeWithDefaults(config);
}
mergeWithDefaults(config) {
return {
disableRightClick: true,
disableTextSelection: true,
disableKeyboardShortcuts: true,
preventScreenshots: true,
preventPrinting: true,
preventPDFGeneration: true,
preventDevTools: true,
blurOnFocusLoss: true,
showWarningOnProtectedAction: true,
customWarningMessage: 'This action is not allowed for security reasons.',
devToolsDetectionSensitivity: 'medium',
watermark: {
enabled: false,
text: 'PROTECTED CONTENT',
opacity: 0.1,
fontSize: 48,
color: '#000000',
rotation: -45
},
...config
};
}
enable() {
if (this.isActive)
return;
this.isActive = true;
this.applySecurityMeasures();
}
disable() {
if (!this.isActive)
return;
this.isActive = false;
this.removeSecurityMeasures();
}
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
if (this.isActive) {
this.disable();
this.enable();
}
}
isEnabled() {
return this.isActive;
}
getConfig() {
return { ...this.config };
}
applySecurityMeasures() {
var _a;
// Apply CSS-based protections
this.applyCSSProtections();
// Initialize protection modules
if (this.config.preventDevTools) {
this.devToolsDetector = new DevToolsDetector({
sensitivity: this.config.devToolsDetectionSensitivity,
onDetected: this.config.onDevToolsDetected,
redirectUrl: this.config.redirectOnDevToolsDetection
});
this.devToolsDetector.start();
}
if (this.config.preventScreenshots) {
this.screenshotProtector = new ScreenshotProtector({
blurOnFocusLoss: this.config.blurOnFocusLoss,
onAttempt: this.config.onScreenshotAttempt
});
this.screenshotProtector.start();
}
if (this.config.disableKeyboardShortcuts) {
this.keyboardProtector = new KeyboardProtector({
showWarning: this.config.showWarningOnProtectedAction,
warningMessage: this.config.customWarningMessage,
onAttempt: this.config.onProtectedActionAttempt
});
this.keyboardProtector.start();
}
if (this.config.preventPrinting || this.config.preventPDFGeneration) {
this.printProtector = new PrintProtector({
preventPrinting: this.config.preventPrinting,
preventPDFGeneration: this.config.preventPDFGeneration,
showWarning: this.config.showWarningOnProtectedAction
});
this.printProtector.start();
}
if ((_a = this.config.watermark) === null || _a === void 0 ? void 0 : _a.enabled) {
this.watermarkManager = new WatermarkManager(this.config.watermark);
this.watermarkManager.show();
}
// Mouse and touch protections
this.setupMouseProtections();
}
applyCSSProtections() {
const styleId = 'secure-app-shield-styles';
let styleElement = document.getElementById(styleId);
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.id = styleId;
document.head.appendChild(styleElement);
}
let css = '';
if (this.config.disableTextSelection) {
css += `
body, * {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
-webkit-touch-callout: none !important;
-webkit-tap-highlight-color: transparent !important;
}
`;
}
if (this.config.preventPrinting) {
css += `
print {
body * {
visibility: hidden !important;
}
body::before {
content: "Printing is not allowed" !important;
visibility: visible !important;
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
font-size: 24px !important;
font-weight: bold !important;
}
}
`;
}
// Add mobile-specific protections
css += `
body {
-webkit-app-region: no-drag !important;
-webkit-user-drag: none !important;
-webkit-user-modify: read-only !important;
}
img, video, canvas, svg {
-webkit-user-drag: none !important;
-webkit-user-select: none !important;
pointer-events: none !important;
}
`;
styleElement.textContent = css;
}
setupMouseProtections() {
if (this.config.disableRightClick) {
const contextMenuHandler = (e) => {
var _a, _b;
e.preventDefault();
e.stopPropagation();
if (this.config.showWarningOnProtectedAction) {
this.showWarning('Right-click is disabled');
}
(_b = (_a = this.config).onProtectedActionAttempt) === null || _b === void 0 ? void 0 : _b.call(_a, 'right-click');
return false;
};
document.addEventListener('contextmenu', contextMenuHandler, true);
this.eventListeners.push(() => {
document.removeEventListener('contextmenu', contextMenuHandler, true);
});
}
// Disable drag and drop
const dragHandler = (e) => {
e.preventDefault();
e.stopPropagation();
return false;
};
['dragstart', 'drag', 'dragenter', 'dragover', 'dragleave', 'drop'].forEach(event => {
document.addEventListener(event, dragHandler, true);
this.eventListeners.push(() => {
document.removeEventListener(event, dragHandler, true);
});
});
// Disable text selection via mouse
if (this.config.disableTextSelection) {
const selectHandler = (e) => {
e.preventDefault();
return false;
};
document.addEventListener('selectstart', selectHandler, true);
this.eventListeners.push(() => {
document.removeEventListener('selectstart', selectHandler, true);
});
}
}
removeSecurityMeasures() {
var _a, _b, _c, _d, _e;
// Remove CSS protections
const styleElement = document.getElementById('secure-app-shield-styles');
if (styleElement) {
styleElement.remove();
}
// Stop protection modules
(_a = this.devToolsDetector) === null || _a === void 0 ? void 0 : _a.stop();
(_b = this.screenshotProtector) === null || _b === void 0 ? void 0 : _b.stop();
(_c = this.keyboardProtector) === null || _c === void 0 ? void 0 : _c.stop();
(_d = this.printProtector) === null || _d === void 0 ? void 0 : _d.stop();
(_e = this.watermarkManager) === null || _e === void 0 ? void 0 : _e.hide();
// Remove event listeners
this.eventListeners.forEach(removeListener => removeListener());
this.eventListeners = [];
}
showWarning(message) {
if (typeof window !== 'undefined' && typeof window.alert === 'function') {
alert(this.config.customWarningMessage || message);
}
}
}
//# sourceMappingURL=SecurityManager.js.map