content-security-toolkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +171 -0
- package/dist/config/default-extensions-config.json +103 -0
- package/dist/core/ContentProtector.d.ts +63 -0
- package/dist/core/ContentProtector.js +279 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +2 -0
- package/dist/core/mediator/ContentProtectionMediator.d.ts +86 -0
- package/dist/core/mediator/ContentProtectionMediator.js +238 -0
- package/dist/core/mediator/eventDataTypes.d.ts +205 -0
- package/dist/core/mediator/eventDataTypes.js +23 -0
- package/dist/core/mediator/handlers/abstractEventHandler.d.ts +67 -0
- package/dist/core/mediator/handlers/abstractEventHandler.js +106 -0
- package/dist/core/mediator/handlers/baseEventHandler.d.ts +65 -0
- package/dist/core/mediator/handlers/baseEventHandler.js +99 -0
- package/dist/core/mediator/handlers/devToolsEventHandler.d.ts +9 -0
- package/dist/core/mediator/handlers/devToolsEventHandler.js +95 -0
- package/dist/core/mediator/handlers/eventHandlerRegistry.d.ts +9 -0
- package/dist/core/mediator/handlers/eventHandlerRegistry.js +34 -0
- package/dist/core/mediator/handlers/extensionEventHandlers.d.ts +40 -0
- package/dist/core/mediator/handlers/extensionEventHandlers.js +140 -0
- package/dist/core/mediator/handlers/iFrameEventHandlers.d.ts +27 -0
- package/dist/core/mediator/handlers/iFrameEventHandlers.js +93 -0
- package/dist/core/mediator/handlers/index.d.ts +9 -0
- package/dist/core/mediator/handlers/index.js +34 -0
- package/dist/core/mediator/handlers/screenShotEventHandlers.d.ts +34 -0
- package/dist/core/mediator/handlers/screenShotEventHandlers.js +111 -0
- package/dist/core/mediator/protection-event.d.ts +94 -0
- package/dist/core/mediator/protection-event.js +43 -0
- package/dist/core/mediator/types.d.ts +105 -0
- package/dist/core/mediator/types.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/strategies/AbstractStrategy.d.ts +152 -0
- package/dist/strategies/AbstractStrategy.js +296 -0
- package/dist/strategies/AbstractStrategy.mediator.d.ts +162 -0
- package/dist/strategies/AbstractStrategy.mediator.js +349 -0
- package/dist/strategies/ClipboardStrategy.d.ts +67 -0
- package/dist/strategies/ClipboardStrategy.js +291 -0
- package/dist/strategies/ContextMenuStrategy.d.ts +60 -0
- package/dist/strategies/ContextMenuStrategy.js +454 -0
- package/dist/strategies/DevToolsStrategy copy.d.ts +85 -0
- package/dist/strategies/DevToolsStrategy copy.js +362 -0
- package/dist/strategies/DevToolsStrategy-detectorManager.d.ts +70 -0
- package/dist/strategies/DevToolsStrategy-detectorManager.js +309 -0
- package/dist/strategies/DevToolsStrategy-simple.d.ts +75 -0
- package/dist/strategies/DevToolsStrategy-simple.js +366 -0
- package/dist/strategies/DevToolsStrategy.d.ts +55 -0
- package/dist/strategies/DevToolsStrategy.js +314 -0
- package/dist/strategies/ExtensionStrategy.d.ts +66 -0
- package/dist/strategies/ExtensionStrategy.js +486 -0
- package/dist/strategies/IFrameStrategy.d.ts +49 -0
- package/dist/strategies/IFrameStrategy.js +255 -0
- package/dist/strategies/KeyboardStrategy.d.ts +35 -0
- package/dist/strategies/KeyboardStrategy.js +130 -0
- package/dist/strategies/PrintStrategy.d.ts +47 -0
- package/dist/strategies/PrintStrategy.js +201 -0
- package/dist/strategies/ScreenshotStrategy.d.ts +90 -0
- package/dist/strategies/ScreenshotStrategy.js +488 -0
- package/dist/strategies/SelectionStrategy.d.ts +49 -0
- package/dist/strategies/SelectionStrategy.js +216 -0
- package/dist/strategies/StrategyRegistry.d.ts +133 -0
- package/dist/strategies/StrategyRegistry.js +379 -0
- package/dist/strategies/WatermarkStrategy.d.ts +47 -0
- package/dist/strategies/WatermarkStrategy.js +273 -0
- package/dist/strategies/index.d.ts +9 -0
- package/dist/strategies/index.js +10 -0
- package/dist/types/index.d.ts +271 -0
- package/dist/types/index.js +16 -0
- package/dist/utils/DOMObserver.d.ts +68 -0
- package/dist/utils/DOMObserver.js +134 -0
- package/dist/utils/base/LoggableComponent.d.ts +62 -0
- package/dist/utils/base/LoggableComponent.js +95 -0
- package/dist/utils/debuggerDetector/debuggerDetectionWorker.d.ts +6 -0
- package/dist/utils/debuggerDetector/debuggerDetectionWorker.js +24 -0
- package/dist/utils/debuggerDetector/debuggerDetector.d.ts +55 -0
- package/dist/utils/debuggerDetector/debuggerDetector.js +158 -0
- package/dist/utils/debuggerDetector/firefoxDetector.d.ts +8 -0
- package/dist/utils/debuggerDetector/firefoxDetector.js +64 -0
- package/dist/utils/detection.d.ts +29 -0
- package/dist/utils/detection.js +267 -0
- package/dist/utils/detectors/AbstractDevToolsDetector.d.ts +105 -0
- package/dist/utils/detectors/AbstractDevToolsDetector.js +136 -0
- package/dist/utils/detectors/dateToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/dateToStringDetector.js +96 -0
- package/dist/utils/detectors/debugLibDetector.d.ts +64 -0
- package/dist/utils/detectors/debugLibDetector.js +195 -0
- package/dist/utils/detectors/debuggerDetectionWorker.d.ts +6 -0
- package/dist/utils/detectors/debuggerDetectionWorker.js +24 -0
- package/dist/utils/detectors/debuggerDetector.d.ts +51 -0
- package/dist/utils/detectors/debuggerDetector.js +211 -0
- package/dist/utils/detectors/defineGetterDetector.d.ts +48 -0
- package/dist/utils/detectors/defineGetterDetector.js +150 -0
- package/dist/utils/detectors/detectorInterface.d.ts +36 -0
- package/dist/utils/detectors/detectorInterface.js +1 -0
- package/dist/utils/detectors/devToolsDetectorManager.d.ts +88 -0
- package/dist/utils/detectors/devToolsDetectorManager.js +246 -0
- package/dist/utils/detectors/firefoxDetector.d.ts +8 -0
- package/dist/utils/detectors/firefoxDetector.js +64 -0
- package/dist/utils/detectors/funcToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/funcToStringDetector.js +90 -0
- package/dist/utils/detectors/regToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/regToStringDetector.js +129 -0
- package/dist/utils/detectors/sizeDetector.d.ts +54 -0
- package/dist/utils/detectors/sizeDetector.js +134 -0
- package/dist/utils/detectors/timingDetector.d.ts +55 -0
- package/dist/utils/detectors/timingDetector.js +143 -0
- package/dist/utils/dom.d.ts +20 -0
- package/dist/utils/dom.js +83 -0
- package/dist/utils/environment.d.ts +29 -0
- package/dist/utils/environment.js +267 -0
- package/dist/utils/eventManager.d.ts +167 -0
- package/dist/utils/eventManager.js +556 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/intervalManager.d.ts +96 -0
- package/dist/utils/intervalManager.js +229 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.d.ts +41 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.js +135 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcuts.d.ts +18 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcuts.js +195 -0
- package/dist/utils/logging/LogLevel.d.ts +21 -0
- package/dist/utils/logging/LogLevel.js +46 -0
- package/dist/utils/logging/LoggingConfig.d.ts +68 -0
- package/dist/utils/logging/LoggingConfig.js +64 -0
- package/dist/utils/logging/LoggingFactory.d.ts +22 -0
- package/dist/utils/logging/LoggingFactory.js +61 -0
- package/dist/utils/logging/LoggingService.d.ts +235 -0
- package/dist/utils/logging/LoggingService.js +385 -0
- package/dist/utils/logging/SimpleLoggingService.d.ts +39 -0
- package/dist/utils/logging/SimpleLoggingService.js +58 -0
- package/dist/utils/logging/advanced/LogLevel.d.ts +21 -0
- package/dist/utils/logging/advanced/LogLevel.js +46 -0
- package/dist/utils/logging/advanced/LoggingConfig.d.ts +68 -0
- package/dist/utils/logging/advanced/LoggingConfig.js +64 -0
- package/dist/utils/logging/advanced/LoggingFactory.d.ts +22 -0
- package/dist/utils/logging/advanced/LoggingFactory.js +61 -0
- package/dist/utils/logging/advanced/LoggingService.d.ts +235 -0
- package/dist/utils/logging/advanced/LoggingService.js +385 -0
- package/dist/utils/logging/simple/Loggable.d.ts +33 -0
- package/dist/utils/logging/simple/Loggable.js +1 -0
- package/dist/utils/logging/simple/LoggingDelegate.d.ts +42 -0
- package/dist/utils/logging/simple/LoggingDelegate.js +53 -0
- package/dist/utils/logging/simple/SimpleLoggingService.d.ts +39 -0
- package/dist/utils/logging/simple/SimpleLoggingService.js +58 -0
- package/dist/utils/orientation.d.ts +15 -0
- package/dist/utils/orientation.js +32 -0
- package/dist/utils/protectedContentManager-simple.d.ts +86 -0
- package/dist/utils/protectedContentManager-simple.js +180 -0
- package/dist/utils/protectedContentManager.d.ts +162 -0
- package/dist/utils/protectedContentManager.js +427 -0
- package/dist/utils/screenshotDetector.d.ts +72 -0
- package/dist/utils/screenshotDetector.js +179 -0
- package/dist/utils/securityOverlayManager-observer-pause.d.ts +283 -0
- package/dist/utils/securityOverlayManager-observer-pause.js +878 -0
- package/dist/utils/securityOverlayManager-simple.d.ts +197 -0
- package/dist/utils/securityOverlayManager-simple.js +552 -0
- package/dist/utils/securityOverlayManager.d.ts +260 -0
- package/dist/utils/securityOverlayManager.js +774 -0
- package/dist/utils/timeoutManager.d.ts +55 -0
- package/dist/utils/timeoutManager.js +121 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Iker Laforga
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Content Security Toolkit
|
|
2
|
+
|
|
3
|
+
A comprehensive toolkit for implementing content security measures in web applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Prevent keyboard shortcuts (Ctrl+P, Ctrl+S, etc.)
|
|
8
|
+
- Disable context menu (right-click)
|
|
9
|
+
- Block printing attempts
|
|
10
|
+
- Add watermarks to content
|
|
11
|
+
- Works across desktop and mobile browsers
|
|
12
|
+
- Highly configurable and extensible
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install content-security-toolkit
|
|
18
|
+
# or
|
|
19
|
+
yarn add content-security-toolkit
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Content Security Toolkit is a comprehensive JavaScript/TypeScript library designed to protect sensitive web content from unauthorized copying, extraction, and distribution. It implements multiple layers of protection strategies that work together to safeguard digital content while maintaining a good user experience for legitimate users.
|
|
23
|
+
|
|
24
|
+
Unlike traditional DRM (Digital Rights Management) systems that often require specialized software or hardware, Content Security Toolkit operates entirely within the browser environment, making it lightweight, easy to implement, and compatible with standard web applications.
|
|
25
|
+
|
|
26
|
+
## Core Architecture
|
|
27
|
+
|
|
28
|
+
The library is built on a modular, strategy-based architecture:
|
|
29
|
+
|
|
30
|
+
- **ContentProtector**: The main class that orchestrates all protection strategies
|
|
31
|
+
- **ProtectionStrategy**: The interface implemented by all protection mechanisms
|
|
32
|
+
- **Strategy Implementations**: Individual protection mechanisms that can be enabled/disabled independently
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
This architecture allows for flexible configuration and easy extension with new protection strategies.
|
|
36
|
+
|
|
37
|
+
## Available Protection Strategies
|
|
38
|
+
|
|
39
|
+
### 1. Keyboard Shortcut Protection (KeyboardStrategy)
|
|
40
|
+
|
|
41
|
+
**Purpose**: Prevents users from using keyboard shortcuts to copy, save, print, or otherwise extract content.
|
|
42
|
+
|
|
43
|
+
**Implementation Details**:
|
|
44
|
+
|
|
45
|
+
- Intercepts key combinations like Ctrl+C, Ctrl+P, Ctrl+S, Ctrl+Shift+I
|
|
46
|
+
- Configurable to block specific shortcuts
|
|
47
|
+
- Provides custom event handlers for blocked shortcuts
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### 2. Context Menu Protection (ContextMenuStrategy)
|
|
51
|
+
|
|
52
|
+
**Purpose**: Prevents users from accessing the browser's context menu (right-click menu) to copy content or view page source.
|
|
53
|
+
|
|
54
|
+
**Implementation Details**:
|
|
55
|
+
|
|
56
|
+
- Intercepts the contextmenu event on specified elements
|
|
57
|
+
- Can be applied to the entire document or specific elements
|
|
58
|
+
- Supports custom handler for context menu attempts
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
### 3. Print Protection (PrintStrategy)
|
|
62
|
+
|
|
63
|
+
**Purpose**: Prevents users from printing the page or using the browser's print functionality.
|
|
64
|
+
|
|
65
|
+
**Implementation Details**:
|
|
66
|
+
|
|
67
|
+
- Intercepts print events (window.print, Ctrl+P)
|
|
68
|
+
- Optionally displays a custom message when print is attempted
|
|
69
|
+
- Can be configured to allow printing but with watermarks
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
### 4. Selection Protection (SelectionStrategy)
|
|
73
|
+
|
|
74
|
+
**Purpose**: Prevents users from selecting and copying text content.
|
|
75
|
+
|
|
76
|
+
**Implementation Details**:
|
|
77
|
+
|
|
78
|
+
- Disables text selection via CSS and JavaScript
|
|
79
|
+
- Intercepts selection events
|
|
80
|
+
- Can be applied to specific elements or the entire document
|
|
81
|
+
- Supports custom handler for selection attempts
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
### 5. Watermark Protection (WatermarkStrategy)
|
|
85
|
+
|
|
86
|
+
**Purpose**: Adds visible watermarks to the content to discourage unauthorized sharing and identify the source.
|
|
87
|
+
|
|
88
|
+
**Implementation Details**:
|
|
89
|
+
|
|
90
|
+
- Creates a grid of semi-transparent watermarks across the content
|
|
91
|
+
- Supports customization of text, opacity, density, and positioning
|
|
92
|
+
- Includes user identification (userId) to trace leaked content
|
|
93
|
+
- **Observer Mechanism**: Implements a MutationObserver to detect when watermarks are removed from the DOM and automatically regenerates them
|
|
94
|
+
- Watermarks are positioned in a way that makes them difficult to remove without affecting the content
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
### 6. DevTools Protection (DevToolsStrategy)
|
|
98
|
+
|
|
99
|
+
**Purpose**: Detects and responds to attempts to open browser developer tools, which could be used to inspect and modify the page.
|
|
100
|
+
|
|
101
|
+
**Implementation Details**:
|
|
102
|
+
|
|
103
|
+
- Uses multiple detection techniques (window.devtools, console timing, resize detection)
|
|
104
|
+
- Provides callbacks when DevTools are opened or closed
|
|
105
|
+
- Can be configured to take specific actions when DevTools are detected
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
### 7. Screenshot Protection (ScreenshotStrategy)
|
|
109
|
+
|
|
110
|
+
**Purpose**: Detects and responds to screenshot attempts.
|
|
111
|
+
|
|
112
|
+
**Implementation Details**:
|
|
113
|
+
|
|
114
|
+
- Monitors clipboard events and screen capture APIs
|
|
115
|
+
- Blurs content or displays warning message during screenshot attempts
|
|
116
|
+
- Provides callbacks when screenshot attempts are detected
|
|
117
|
+
- Uses visual tricks to make screenshots less useful (temporary content blurring)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
## Technical Deep Dive
|
|
121
|
+
|
|
122
|
+
### Watermark Observer Mechanism
|
|
123
|
+
|
|
124
|
+
The watermark protection includes a sophisticated observer system that ensures watermarks remain present even if they're removed from the DOM.
|
|
125
|
+
This observer continuously monitors the DOM for any attempts to remove watermark elements and immediately regenerates them when such attempts are detected.
|
|
126
|
+
|
|
127
|
+
### DevTools Detection Techniques
|
|
128
|
+
|
|
129
|
+
The DevTools protection strategy employs multiple detection methods to identify when developer tools are opened:
|
|
130
|
+
|
|
131
|
+
1. **Console Timing Difference**: Measures the execution time difference between regular code and code that triggers debugger features
|
|
132
|
+
2. **Window Size Monitoring**: Detects the window size changes that occur when DevTools are opened
|
|
133
|
+
3. **Feature Detection**: Checks for the presence of DevTools-specific objects and properties
|
|
134
|
+
4. **Debugger Statement Handling**: Uses strategic debugger statements that behave differently when DevTools are open
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
### Screenshot Detection
|
|
138
|
+
|
|
139
|
+
The screenshot protection uses several techniques to detect and respond to screenshot attempts:
|
|
140
|
+
|
|
141
|
+
1. **Clipboard Event Monitoring**: Detects copy events that might indicate a screenshot
|
|
142
|
+
2. **Visual Feedback**: Can temporarily blur content or display a warning when screenshot attempts are detected
|
|
143
|
+
3. **Screen Capture API Interception**: Monitors and responds to browser screen capture API calls
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
## Known Limitations and Issues
|
|
147
|
+
|
|
148
|
+
While Content Security Toolkit provides robust protection, it's important to understand its limitations:
|
|
149
|
+
|
|
150
|
+
1. **Client-Side Only**: As a JavaScript library, all protections run in the browser and can potentially be circumvented by determined users with technical knowledge.
|
|
151
|
+
2. **No Server-Side Validation**: The library doesn't include server-side components to validate content access or enforce permissions beyond the browser.
|
|
152
|
+
3. **Browser Compatibility**: Some protection strategies rely on modern browser APIs and may not work in older browsers.
|
|
153
|
+
4. **Mobile Limitations**: Some protections (particularly DevTools detection) are less effective on mobile devices.
|
|
154
|
+
5. **Accessibility Impact**: Content protection measures can interfere with accessibility tools. Care should be taken to ensure content remains accessible to users with disabilities.
|
|
155
|
+
6. **Performance Considerations**: Extensive protection, particularly watermarking with high density, can impact page performance.
|
|
156
|
+
7. **Hardware Screenshots**: The library cannot prevent screenshots taken using physical cameras or external hardware.
|
|
157
|
+
8. **Browser Extensions**: Some browser extensions might interfere with or bypass certain protection mechanisms.
|
|
158
|
+
|
|
159
|
+
Unlike DRM systems that encrypt content and control playback through specialized software, Content Security Toolkit focuses on preventing common extraction methods while maintaining compatibility with standard web browsers. It's designed as a deterrent rather than an unbreakable protection system.
|
|
160
|
+
|
|
161
|
+
## Best Practices for Implementation
|
|
162
|
+
|
|
163
|
+
For optimal protection, consider these implementation guidelines:
|
|
164
|
+
|
|
165
|
+
1. **Layer Multiple Strategies**: Enable multiple protection mechanisms for defense in depth
|
|
166
|
+
2. **Custom Handlers**: Implement custom handlers to log protection events and take appropriate actions
|
|
167
|
+
3. **User Education**: Inform users about content protection and acceptable use policies
|
|
168
|
+
4. **Selective Protection**: Apply protection only to sensitive content to minimize performance impact
|
|
169
|
+
5. **Regular Updates**: Keep the library updated to benefit from security improvements
|
|
170
|
+
6. **Complementary Measures**: Combine with server-side protections and legal terms of use
|
|
171
|
+
7. **Accessibility Considerations**: Test with accessibility tools and provide alternative access methods for legitimate users with special needs
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extensions": {
|
|
3
|
+
"evernote-web-clipper": {
|
|
4
|
+
"name": "Evernote Web Clipper",
|
|
5
|
+
"description": "Clips web content to Evernote",
|
|
6
|
+
"risk": "high",
|
|
7
|
+
"detectionMethods": {
|
|
8
|
+
"domSelectors": [".evernote-clipper", "#evernoteClipper", "#evernoteClipperToolsMain"],
|
|
9
|
+
"jsSignatures": ["EvernoteClipper", "ENClipper"]
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"onenote-clipper": {
|
|
13
|
+
"name": "OneNote Web Clipper",
|
|
14
|
+
"description": "Clips web content to OneNote",
|
|
15
|
+
"risk": "high",
|
|
16
|
+
"detectionMethods": {
|
|
17
|
+
"domSelectors": [".onenote-clipper", "#oneNoteClipper", "#oneNoteWebClipper"],
|
|
18
|
+
"jsSignatures": ["OneNoteClipper", "OneNoteWebClipper"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"notion-web-clipper": {
|
|
22
|
+
"name": "Notion Web Clipper",
|
|
23
|
+
"description": "Clips web content to Notion",
|
|
24
|
+
"risk": "high",
|
|
25
|
+
"detectionMethods": {
|
|
26
|
+
"domSelectors": [".notion-clipper", "#notionClipper"],
|
|
27
|
+
"jsSignatures": ["notionClientAPI"]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"pocket": {
|
|
31
|
+
"name": "Pocket",
|
|
32
|
+
"description": "Saves content for later reading",
|
|
33
|
+
"risk": "medium",
|
|
34
|
+
"detectionMethods": {
|
|
35
|
+
"domSelectors": [".pocket-button", "#pocket-button-container"],
|
|
36
|
+
"jsSignatures": ["Pocket", "PocketButtonManager"]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"instapaper": {
|
|
40
|
+
"name": "Instapaper",
|
|
41
|
+
"description": "Saves content for later reading",
|
|
42
|
+
"risk": "medium",
|
|
43
|
+
"detectionMethods": {
|
|
44
|
+
"domSelectors": [".instapaper-button", "#instapaper-button"],
|
|
45
|
+
"jsSignatures": ["Instapaper"]
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"readwise": {
|
|
49
|
+
"name": "Readwise",
|
|
50
|
+
"description": "Saves highlights and annotations",
|
|
51
|
+
"risk": "medium",
|
|
52
|
+
"detectionMethods": {
|
|
53
|
+
"domSelectors": [".readwise-button", "#readwise-highlights"],
|
|
54
|
+
"jsSignatures": ["readwiseAPI", "readwiseHighlighter"]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"singlefile": {
|
|
58
|
+
"name": "SingleFile",
|
|
59
|
+
"description": "Saves complete web pages",
|
|
60
|
+
"risk": "high",
|
|
61
|
+
"detectionMethods": {
|
|
62
|
+
"domSelectors": [".singlefile-button", "#singlefile-ui"],
|
|
63
|
+
"jsSignatures": ["singlefile", "SingleFile"]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"save-page-we": {
|
|
67
|
+
"name": "Save Page WE",
|
|
68
|
+
"description": "Saves complete web pages",
|
|
69
|
+
"risk": "high",
|
|
70
|
+
"detectionMethods": {
|
|
71
|
+
"domSelectors": [".save-page-we"],
|
|
72
|
+
"jsSignatures": ["savePageWE"]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"fireshot": {
|
|
76
|
+
"name": "Fireshot",
|
|
77
|
+
"description": "Takes screenshots of web pages",
|
|
78
|
+
"risk": "high",
|
|
79
|
+
"detectionMethods": {
|
|
80
|
+
"domSelectors": [".fireshot-ui", "#fireshot-container"],
|
|
81
|
+
"jsSignatures": ["FireShot", "FSCapture"]
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"gofullpage": {
|
|
85
|
+
"name": "GoFullPage",
|
|
86
|
+
"description": "Takes full page screenshots",
|
|
87
|
+
"risk": "high",
|
|
88
|
+
"detectionMethods": {
|
|
89
|
+
"domSelectors": [".gofullpage-ui"],
|
|
90
|
+
"jsSignatures": ["GoFullPage", "FullPageScreenshot"]
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"web-scraper": {
|
|
94
|
+
"name": "Web Scraper",
|
|
95
|
+
"description": "Extracts data from web pages",
|
|
96
|
+
"risk": "high",
|
|
97
|
+
"detectionMethods": {
|
|
98
|
+
"domSelectors": [".web-scraper-selection", "#web-scraper-selector-overlay"],
|
|
99
|
+
"jsSignatures": ["WebScraper", "SelectorGraph"]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ContentProtectionOptions, ProtectionStrategy } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Main class for protecting content from copying, screenshotting, and other extraction methods
|
|
4
|
+
* Coordinates multiple protection strategies and manages their lifecycle
|
|
5
|
+
*/
|
|
6
|
+
export declare class ContentProtector {
|
|
7
|
+
private options;
|
|
8
|
+
private strategies;
|
|
9
|
+
private isActive;
|
|
10
|
+
private overlayManager;
|
|
11
|
+
private protectedContentManager;
|
|
12
|
+
private mediator;
|
|
13
|
+
private handlerRegistry;
|
|
14
|
+
private logger;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new ContentProtector instance
|
|
17
|
+
* @param options Configuration options for content protection
|
|
18
|
+
*/
|
|
19
|
+
constructor(options?: ContentProtectionOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Initialize protection strategies based on configuration options
|
|
22
|
+
* Creates strategy instances and adds them to the strategies map
|
|
23
|
+
*/
|
|
24
|
+
private initializeStrategies;
|
|
25
|
+
/**
|
|
26
|
+
* Apply all protection strategies
|
|
27
|
+
* Activates each strategy to protect content
|
|
28
|
+
*/
|
|
29
|
+
protect(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Remove all protection strategies
|
|
32
|
+
* Deactivates each strategy and cleans up resources
|
|
33
|
+
*/
|
|
34
|
+
unprotect(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Update protection options
|
|
37
|
+
* Removes existing protection, updates options, and reapplies if needed
|
|
38
|
+
* @param options New options to apply
|
|
39
|
+
*/
|
|
40
|
+
updateOptions(options: Partial<ContentProtectionOptions>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Check if protection is currently active
|
|
43
|
+
* @returns True if protection is active
|
|
44
|
+
*/
|
|
45
|
+
isProtected(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Get a specific strategy by name
|
|
48
|
+
* @param name Strategy name
|
|
49
|
+
* @returns The strategy instance or undefined if not found
|
|
50
|
+
*/
|
|
51
|
+
getStrategy(name: string): ProtectionStrategy | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Check if a specific strategy is active
|
|
54
|
+
* @param name Strategy name
|
|
55
|
+
* @returns True if the strategy exists
|
|
56
|
+
*/
|
|
57
|
+
hasStrategy(name: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Clean up and dispose of all resources
|
|
60
|
+
* Removes protection and cleans up global managers
|
|
61
|
+
*/
|
|
62
|
+
dispose(): void;
|
|
63
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { KeyboardStrategy, PrintStrategy, ContextMenuStrategy, WatermarkStrategy, SelectionStrategy, DevToolsStrategy, ScreenshotStrategy, BrowserExtensionDetectionStrategy, FrameEmbeddingProtectionStrategy, } from "../strategies";
|
|
2
|
+
import { SecurityOverlayManager } from "../utils/securityOverlayManager";
|
|
3
|
+
import { intervalManager } from "../utils/intervalManager";
|
|
4
|
+
import { eventManager } from "../utils/eventManager";
|
|
5
|
+
import { ContentProtectionMediator } from "./mediator/ContentProtectionMediator";
|
|
6
|
+
import { HandlerRegistry } from "./mediator/handlers/eventHandlerRegistry";
|
|
7
|
+
import { ProtectedContentManager } from "../utils/protectedContentManager";
|
|
8
|
+
import { SimpleLoggingService } from "../utils/logging/simple/SimpleLoggingService";
|
|
9
|
+
/**
|
|
10
|
+
* Main class for protecting content from copying, screenshotting, and other extraction methods
|
|
11
|
+
* Coordinates multiple protection strategies and manages their lifecycle
|
|
12
|
+
*/
|
|
13
|
+
export class ContentProtector {
|
|
14
|
+
/**
|
|
15
|
+
* Create a new ContentProtector instance
|
|
16
|
+
* @param options Configuration options for content protection
|
|
17
|
+
*/
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.strategies = new Map();
|
|
20
|
+
this.isActive = false;
|
|
21
|
+
// Define default options
|
|
22
|
+
const defaults = {
|
|
23
|
+
preventKeyboardShortcuts: true,
|
|
24
|
+
preventContextMenu: true,
|
|
25
|
+
preventPrinting: true,
|
|
26
|
+
preventSelection: true,
|
|
27
|
+
preventScreenshots: true,
|
|
28
|
+
enableWatermark: false,
|
|
29
|
+
preventDevTools: false,
|
|
30
|
+
preventExtensions: false,
|
|
31
|
+
preventEmbedding: false,
|
|
32
|
+
debugMode: false,
|
|
33
|
+
};
|
|
34
|
+
// Merge defaults with provided options
|
|
35
|
+
this.options = {
|
|
36
|
+
...defaults,
|
|
37
|
+
...options,
|
|
38
|
+
};
|
|
39
|
+
// Initialize logger
|
|
40
|
+
this.logger = new SimpleLoggingService("ContentProtector", this.options.debugMode);
|
|
41
|
+
// Normalize and set targetElement if not provided
|
|
42
|
+
const resolveTargetElement = (t) => {
|
|
43
|
+
if (typeof document === "undefined")
|
|
44
|
+
return null;
|
|
45
|
+
// Already an element
|
|
46
|
+
if (t instanceof HTMLElement)
|
|
47
|
+
return t;
|
|
48
|
+
// CSS selector string
|
|
49
|
+
if (typeof t === "string") {
|
|
50
|
+
try {
|
|
51
|
+
const el = document.querySelector(t);
|
|
52
|
+
return el instanceof HTMLElement ? el : null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Vue 3 ref ({ value: HTMLElement }) or Vue component ($el) or DOM-like node
|
|
59
|
+
if (t && typeof t === "object") {
|
|
60
|
+
const maybe = t;
|
|
61
|
+
if (maybe.value instanceof HTMLElement)
|
|
62
|
+
return maybe.value;
|
|
63
|
+
if (maybe.$el instanceof HTMLElement)
|
|
64
|
+
return maybe.$el;
|
|
65
|
+
if (maybe.nodeType === 1 && typeof maybe.nodeName === "string")
|
|
66
|
+
return t;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
// Normalize provided targetElement, or default to document.body
|
|
71
|
+
const normalizedTarget = resolveTargetElement(this.options.targetElement);
|
|
72
|
+
if (normalizedTarget) {
|
|
73
|
+
this.options.targetElement = normalizedTarget;
|
|
74
|
+
}
|
|
75
|
+
else if (!this.options.targetElement && typeof document !== "undefined") {
|
|
76
|
+
this.options.targetElement = document.body;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// If user provided something invalid, clear it to avoid passing non-DOM objects to strategies
|
|
80
|
+
if (this.options.targetElement) {
|
|
81
|
+
this.logger = new SimpleLoggingService("ContentProtector", this.options.debugMode);
|
|
82
|
+
this.logger.warn("Provided targetElement is not a DOM element - falling back to document.body if available");
|
|
83
|
+
if (typeof document !== "undefined")
|
|
84
|
+
this.options.targetElement = document.body;
|
|
85
|
+
else
|
|
86
|
+
this.options.targetElement = undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Initialize the mediator
|
|
90
|
+
this.mediator = new ContentProtectionMediator(this.options.debugMode);
|
|
91
|
+
// Initialize the handler registry
|
|
92
|
+
this.handlerRegistry = new HandlerRegistry(this.mediator, this.options.debugMode);
|
|
93
|
+
// Initialize overlay manager
|
|
94
|
+
this.overlayManager = new SecurityOverlayManager(this.options.debugMode);
|
|
95
|
+
this.overlayManager.setMediator(this.mediator);
|
|
96
|
+
// Initialize protected content manager
|
|
97
|
+
this.protectedContentManager = new ProtectedContentManager(this.options.targetElement, this.options.debugMode);
|
|
98
|
+
this.protectedContentManager.setMediator(this.mediator);
|
|
99
|
+
// Wire content visibility callbacks from customHandlers (useful for Vue re-mounting)
|
|
100
|
+
if (this.options.customHandlers) {
|
|
101
|
+
this.protectedContentManager.setContentCallbacks(this.options.customHandlers.onContentHidden, this.options.customHandlers.onContentRestored);
|
|
102
|
+
}
|
|
103
|
+
// Configure debug mode for managers
|
|
104
|
+
if (this.options.debugMode) {
|
|
105
|
+
this.logger.log("Initialized with options", this.options);
|
|
106
|
+
// Enable debug mode for the event manager
|
|
107
|
+
eventManager.setDebugMode(true);
|
|
108
|
+
// Enable debug mode for the interval manager
|
|
109
|
+
//intervalManager.setDebugMode(true);
|
|
110
|
+
}
|
|
111
|
+
this.initializeStrategies();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Initialize protection strategies based on configuration options
|
|
115
|
+
* Creates strategy instances and adds them to the strategies map
|
|
116
|
+
*/
|
|
117
|
+
initializeStrategies() {
|
|
118
|
+
const { debugMode, targetElement, customHandlers } = this.options;
|
|
119
|
+
// Initialize strategies based on options
|
|
120
|
+
if (this.options.preventKeyboardShortcuts) {
|
|
121
|
+
this.strategies.set("keyboard", new KeyboardStrategy(customHandlers?.onKeyboardShortcutBlocked, debugMode));
|
|
122
|
+
}
|
|
123
|
+
if (this.options.preventContextMenu) {
|
|
124
|
+
this.strategies.set("contextMenu", new ContextMenuStrategy(this.options.contextMenuOptions, targetElement, customHandlers?.onContextMenuAttempt, debugMode));
|
|
125
|
+
}
|
|
126
|
+
if (this.options.preventPrinting) {
|
|
127
|
+
this.strategies.set("print", new PrintStrategy(customHandlers?.onPrintAttempt, debugMode));
|
|
128
|
+
}
|
|
129
|
+
if (this.options.preventSelection) {
|
|
130
|
+
this.strategies.set("selection", new SelectionStrategy(targetElement, customHandlers?.onSelectionAttempt, debugMode));
|
|
131
|
+
}
|
|
132
|
+
if (this.options.enableWatermark && this.options.watermarkOptions) {
|
|
133
|
+
this.strategies.set("watermark", new WatermarkStrategy(this.options.watermarkOptions, targetElement, debugMode));
|
|
134
|
+
}
|
|
135
|
+
if (this.options.preventDevTools) {
|
|
136
|
+
const devToolsStrategy = new DevToolsStrategy(this.options.devToolsOptions, targetElement, customHandlers?.onDevToolsOpen, debugMode);
|
|
137
|
+
devToolsStrategy.setMediator(this.mediator);
|
|
138
|
+
this.strategies.set("devTools", devToolsStrategy);
|
|
139
|
+
}
|
|
140
|
+
if (this.options.preventScreenshots) {
|
|
141
|
+
const screenshotStrategy = new ScreenshotStrategy(this.options.screenshotOptions, targetElement, customHandlers?.onScreenshotAttempt, debugMode);
|
|
142
|
+
screenshotStrategy.setMediator(this.mediator);
|
|
143
|
+
this.strategies.set("screenshot", screenshotStrategy);
|
|
144
|
+
}
|
|
145
|
+
if (this.options.preventExtensions) {
|
|
146
|
+
const extensionStrategy = new BrowserExtensionDetectionStrategy(this.options.extensionOptions, targetElement, customHandlers?.onExtensionDetected, debugMode);
|
|
147
|
+
extensionStrategy.setMediator(this.mediator);
|
|
148
|
+
this.strategies.set("extension", extensionStrategy);
|
|
149
|
+
}
|
|
150
|
+
if (this.options.preventEmbedding) {
|
|
151
|
+
const frameStrategy = new FrameEmbeddingProtectionStrategy(this.options.frameEmbeddingOptions, targetElement, customHandlers?.onFrameEmbeddingDetected, debugMode);
|
|
152
|
+
frameStrategy.setMediator(this.mediator);
|
|
153
|
+
this.strategies.set("iFrame", frameStrategy);
|
|
154
|
+
}
|
|
155
|
+
this.logger.log("Initialized strategies", Array.from(this.strategies.keys()));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Apply all protection strategies
|
|
159
|
+
* Activates each strategy to protect content
|
|
160
|
+
*/
|
|
161
|
+
protect() {
|
|
162
|
+
if (this.isActive) {
|
|
163
|
+
this.logger.log("Already protected, skipping");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.logger.log("Applying protection strategies");
|
|
167
|
+
// Apply each strategy
|
|
168
|
+
for (const [name, strategy] of this.strategies.entries()) {
|
|
169
|
+
try {
|
|
170
|
+
this.logger.log(`Applying strategy "${name}"`);
|
|
171
|
+
strategy.apply();
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
this.logger.error(`Error applying strategy "${name}":`, error);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
this.isActive = true;
|
|
178
|
+
this.logger.log("All protection strategies applied successfully");
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Remove all protection strategies
|
|
182
|
+
* Deactivates each strategy and cleans up resources
|
|
183
|
+
*/
|
|
184
|
+
unprotect() {
|
|
185
|
+
if (!this.isActive) {
|
|
186
|
+
this.logger.log("Not protected, skipping");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this.logger.log("Removing protection strategies");
|
|
190
|
+
// Create a copy of the strategy entries to avoid modification during iteration
|
|
191
|
+
const entries = Array.from(this.strategies.entries());
|
|
192
|
+
// Remove each strategy and track failures
|
|
193
|
+
let successCount = 0;
|
|
194
|
+
let failCount = 0;
|
|
195
|
+
for (const [name, strategy] of entries) {
|
|
196
|
+
try {
|
|
197
|
+
this.logger.log(`Removing strategy "${name}"`);
|
|
198
|
+
if (strategy.isApplied()) {
|
|
199
|
+
strategy.remove();
|
|
200
|
+
successCount++;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
failCount++;
|
|
205
|
+
this.logger.error(`Error removing strategy "${name}":`, error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Clear all strategies regardless of removal success
|
|
209
|
+
this.strategies.clear();
|
|
210
|
+
this.isActive = false;
|
|
211
|
+
this.logger.log(`Protection removed (${successCount} successful, ${failCount} failed)`);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Update protection options
|
|
215
|
+
* Removes existing protection, updates options, and reapplies if needed
|
|
216
|
+
* @param options New options to apply
|
|
217
|
+
*/
|
|
218
|
+
updateOptions(options) {
|
|
219
|
+
this.logger.log("Updating options", options);
|
|
220
|
+
// Store the current state
|
|
221
|
+
const wasActive = this.isActive;
|
|
222
|
+
// Remove existing protections
|
|
223
|
+
this.unprotect();
|
|
224
|
+
// Update options
|
|
225
|
+
this.options = {
|
|
226
|
+
...this.options,
|
|
227
|
+
...options,
|
|
228
|
+
};
|
|
229
|
+
// Update debug mode for managers and logger
|
|
230
|
+
if (options.debugMode !== undefined) {
|
|
231
|
+
this.logger.setDebugMode(options.debugMode);
|
|
232
|
+
eventManager.setDebugMode(options.debugMode);
|
|
233
|
+
//intervalManager.setDebugMode(options.debugMode);
|
|
234
|
+
this.overlayManager.setDebugMode(options.debugMode);
|
|
235
|
+
}
|
|
236
|
+
this.logger.log("New options after update", this.options);
|
|
237
|
+
// Reinitialize strategies
|
|
238
|
+
this.strategies.clear();
|
|
239
|
+
this.initializeStrategies();
|
|
240
|
+
// Reapply protection if it was active before
|
|
241
|
+
if (wasActive) {
|
|
242
|
+
this.logger.log("Reapplying protection after options update");
|
|
243
|
+
this.protect();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if protection is currently active
|
|
248
|
+
* @returns True if protection is active
|
|
249
|
+
*/
|
|
250
|
+
isProtected() {
|
|
251
|
+
return this.isActive;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get a specific strategy by name
|
|
255
|
+
* @param name Strategy name
|
|
256
|
+
* @returns The strategy instance or undefined if not found
|
|
257
|
+
*/
|
|
258
|
+
getStrategy(name) {
|
|
259
|
+
return this.strategies.get(name);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Check if a specific strategy is active
|
|
263
|
+
* @param name Strategy name
|
|
264
|
+
* @returns True if the strategy exists
|
|
265
|
+
*/
|
|
266
|
+
hasStrategy(name) {
|
|
267
|
+
return this.strategies.has(name);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Clean up and dispose of all resources
|
|
271
|
+
* Removes protection and cleans up global managers
|
|
272
|
+
*/
|
|
273
|
+
dispose() {
|
|
274
|
+
this.unprotect();
|
|
275
|
+
// Dispose interval manager
|
|
276
|
+
intervalManager.dispose();
|
|
277
|
+
this.logger.log("Disposed all resources");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ContentProtector } from './ContentProtector';
|