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.
Files changed (162) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +171 -0
  3. package/dist/config/default-extensions-config.json +103 -0
  4. package/dist/core/ContentProtector.d.ts +63 -0
  5. package/dist/core/ContentProtector.js +279 -0
  6. package/dist/core/index.d.ts +1 -0
  7. package/dist/core/index.js +2 -0
  8. package/dist/core/mediator/ContentProtectionMediator.d.ts +86 -0
  9. package/dist/core/mediator/ContentProtectionMediator.js +238 -0
  10. package/dist/core/mediator/eventDataTypes.d.ts +205 -0
  11. package/dist/core/mediator/eventDataTypes.js +23 -0
  12. package/dist/core/mediator/handlers/abstractEventHandler.d.ts +67 -0
  13. package/dist/core/mediator/handlers/abstractEventHandler.js +106 -0
  14. package/dist/core/mediator/handlers/baseEventHandler.d.ts +65 -0
  15. package/dist/core/mediator/handlers/baseEventHandler.js +99 -0
  16. package/dist/core/mediator/handlers/devToolsEventHandler.d.ts +9 -0
  17. package/dist/core/mediator/handlers/devToolsEventHandler.js +95 -0
  18. package/dist/core/mediator/handlers/eventHandlerRegistry.d.ts +9 -0
  19. package/dist/core/mediator/handlers/eventHandlerRegistry.js +34 -0
  20. package/dist/core/mediator/handlers/extensionEventHandlers.d.ts +40 -0
  21. package/dist/core/mediator/handlers/extensionEventHandlers.js +140 -0
  22. package/dist/core/mediator/handlers/iFrameEventHandlers.d.ts +27 -0
  23. package/dist/core/mediator/handlers/iFrameEventHandlers.js +93 -0
  24. package/dist/core/mediator/handlers/index.d.ts +9 -0
  25. package/dist/core/mediator/handlers/index.js +34 -0
  26. package/dist/core/mediator/handlers/screenShotEventHandlers.d.ts +34 -0
  27. package/dist/core/mediator/handlers/screenShotEventHandlers.js +111 -0
  28. package/dist/core/mediator/protection-event.d.ts +94 -0
  29. package/dist/core/mediator/protection-event.js +43 -0
  30. package/dist/core/mediator/types.d.ts +105 -0
  31. package/dist/core/mediator/types.js +1 -0
  32. package/dist/index.d.ts +4 -0
  33. package/dist/index.js +5 -0
  34. package/dist/strategies/AbstractStrategy.d.ts +152 -0
  35. package/dist/strategies/AbstractStrategy.js +296 -0
  36. package/dist/strategies/AbstractStrategy.mediator.d.ts +162 -0
  37. package/dist/strategies/AbstractStrategy.mediator.js +349 -0
  38. package/dist/strategies/ClipboardStrategy.d.ts +67 -0
  39. package/dist/strategies/ClipboardStrategy.js +291 -0
  40. package/dist/strategies/ContextMenuStrategy.d.ts +60 -0
  41. package/dist/strategies/ContextMenuStrategy.js +454 -0
  42. package/dist/strategies/DevToolsStrategy copy.d.ts +85 -0
  43. package/dist/strategies/DevToolsStrategy copy.js +362 -0
  44. package/dist/strategies/DevToolsStrategy-detectorManager.d.ts +70 -0
  45. package/dist/strategies/DevToolsStrategy-detectorManager.js +309 -0
  46. package/dist/strategies/DevToolsStrategy-simple.d.ts +75 -0
  47. package/dist/strategies/DevToolsStrategy-simple.js +366 -0
  48. package/dist/strategies/DevToolsStrategy.d.ts +55 -0
  49. package/dist/strategies/DevToolsStrategy.js +314 -0
  50. package/dist/strategies/ExtensionStrategy.d.ts +66 -0
  51. package/dist/strategies/ExtensionStrategy.js +486 -0
  52. package/dist/strategies/IFrameStrategy.d.ts +49 -0
  53. package/dist/strategies/IFrameStrategy.js +255 -0
  54. package/dist/strategies/KeyboardStrategy.d.ts +35 -0
  55. package/dist/strategies/KeyboardStrategy.js +130 -0
  56. package/dist/strategies/PrintStrategy.d.ts +47 -0
  57. package/dist/strategies/PrintStrategy.js +201 -0
  58. package/dist/strategies/ScreenshotStrategy.d.ts +90 -0
  59. package/dist/strategies/ScreenshotStrategy.js +488 -0
  60. package/dist/strategies/SelectionStrategy.d.ts +49 -0
  61. package/dist/strategies/SelectionStrategy.js +216 -0
  62. package/dist/strategies/StrategyRegistry.d.ts +133 -0
  63. package/dist/strategies/StrategyRegistry.js +379 -0
  64. package/dist/strategies/WatermarkStrategy.d.ts +47 -0
  65. package/dist/strategies/WatermarkStrategy.js +273 -0
  66. package/dist/strategies/index.d.ts +9 -0
  67. package/dist/strategies/index.js +10 -0
  68. package/dist/types/index.d.ts +271 -0
  69. package/dist/types/index.js +16 -0
  70. package/dist/utils/DOMObserver.d.ts +68 -0
  71. package/dist/utils/DOMObserver.js +134 -0
  72. package/dist/utils/base/LoggableComponent.d.ts +62 -0
  73. package/dist/utils/base/LoggableComponent.js +95 -0
  74. package/dist/utils/debuggerDetector/debuggerDetectionWorker.d.ts +6 -0
  75. package/dist/utils/debuggerDetector/debuggerDetectionWorker.js +24 -0
  76. package/dist/utils/debuggerDetector/debuggerDetector.d.ts +55 -0
  77. package/dist/utils/debuggerDetector/debuggerDetector.js +158 -0
  78. package/dist/utils/debuggerDetector/firefoxDetector.d.ts +8 -0
  79. package/dist/utils/debuggerDetector/firefoxDetector.js +64 -0
  80. package/dist/utils/detection.d.ts +29 -0
  81. package/dist/utils/detection.js +267 -0
  82. package/dist/utils/detectors/AbstractDevToolsDetector.d.ts +105 -0
  83. package/dist/utils/detectors/AbstractDevToolsDetector.js +136 -0
  84. package/dist/utils/detectors/dateToStringDetector.d.ts +43 -0
  85. package/dist/utils/detectors/dateToStringDetector.js +96 -0
  86. package/dist/utils/detectors/debugLibDetector.d.ts +64 -0
  87. package/dist/utils/detectors/debugLibDetector.js +195 -0
  88. package/dist/utils/detectors/debuggerDetectionWorker.d.ts +6 -0
  89. package/dist/utils/detectors/debuggerDetectionWorker.js +24 -0
  90. package/dist/utils/detectors/debuggerDetector.d.ts +51 -0
  91. package/dist/utils/detectors/debuggerDetector.js +211 -0
  92. package/dist/utils/detectors/defineGetterDetector.d.ts +48 -0
  93. package/dist/utils/detectors/defineGetterDetector.js +150 -0
  94. package/dist/utils/detectors/detectorInterface.d.ts +36 -0
  95. package/dist/utils/detectors/detectorInterface.js +1 -0
  96. package/dist/utils/detectors/devToolsDetectorManager.d.ts +88 -0
  97. package/dist/utils/detectors/devToolsDetectorManager.js +246 -0
  98. package/dist/utils/detectors/firefoxDetector.d.ts +8 -0
  99. package/dist/utils/detectors/firefoxDetector.js +64 -0
  100. package/dist/utils/detectors/funcToStringDetector.d.ts +43 -0
  101. package/dist/utils/detectors/funcToStringDetector.js +90 -0
  102. package/dist/utils/detectors/regToStringDetector.d.ts +43 -0
  103. package/dist/utils/detectors/regToStringDetector.js +129 -0
  104. package/dist/utils/detectors/sizeDetector.d.ts +54 -0
  105. package/dist/utils/detectors/sizeDetector.js +134 -0
  106. package/dist/utils/detectors/timingDetector.d.ts +55 -0
  107. package/dist/utils/detectors/timingDetector.js +143 -0
  108. package/dist/utils/dom.d.ts +20 -0
  109. package/dist/utils/dom.js +83 -0
  110. package/dist/utils/environment.d.ts +29 -0
  111. package/dist/utils/environment.js +267 -0
  112. package/dist/utils/eventManager.d.ts +167 -0
  113. package/dist/utils/eventManager.js +556 -0
  114. package/dist/utils/index.d.ts +2 -0
  115. package/dist/utils/index.js +3 -0
  116. package/dist/utils/intervalManager.d.ts +96 -0
  117. package/dist/utils/intervalManager.js +229 -0
  118. package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.d.ts +41 -0
  119. package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.js +135 -0
  120. package/dist/utils/keyboardShortcutManager/keyboardShortcuts.d.ts +18 -0
  121. package/dist/utils/keyboardShortcutManager/keyboardShortcuts.js +195 -0
  122. package/dist/utils/logging/LogLevel.d.ts +21 -0
  123. package/dist/utils/logging/LogLevel.js +46 -0
  124. package/dist/utils/logging/LoggingConfig.d.ts +68 -0
  125. package/dist/utils/logging/LoggingConfig.js +64 -0
  126. package/dist/utils/logging/LoggingFactory.d.ts +22 -0
  127. package/dist/utils/logging/LoggingFactory.js +61 -0
  128. package/dist/utils/logging/LoggingService.d.ts +235 -0
  129. package/dist/utils/logging/LoggingService.js +385 -0
  130. package/dist/utils/logging/SimpleLoggingService.d.ts +39 -0
  131. package/dist/utils/logging/SimpleLoggingService.js +58 -0
  132. package/dist/utils/logging/advanced/LogLevel.d.ts +21 -0
  133. package/dist/utils/logging/advanced/LogLevel.js +46 -0
  134. package/dist/utils/logging/advanced/LoggingConfig.d.ts +68 -0
  135. package/dist/utils/logging/advanced/LoggingConfig.js +64 -0
  136. package/dist/utils/logging/advanced/LoggingFactory.d.ts +22 -0
  137. package/dist/utils/logging/advanced/LoggingFactory.js +61 -0
  138. package/dist/utils/logging/advanced/LoggingService.d.ts +235 -0
  139. package/dist/utils/logging/advanced/LoggingService.js +385 -0
  140. package/dist/utils/logging/simple/Loggable.d.ts +33 -0
  141. package/dist/utils/logging/simple/Loggable.js +1 -0
  142. package/dist/utils/logging/simple/LoggingDelegate.d.ts +42 -0
  143. package/dist/utils/logging/simple/LoggingDelegate.js +53 -0
  144. package/dist/utils/logging/simple/SimpleLoggingService.d.ts +39 -0
  145. package/dist/utils/logging/simple/SimpleLoggingService.js +58 -0
  146. package/dist/utils/orientation.d.ts +15 -0
  147. package/dist/utils/orientation.js +32 -0
  148. package/dist/utils/protectedContentManager-simple.d.ts +86 -0
  149. package/dist/utils/protectedContentManager-simple.js +180 -0
  150. package/dist/utils/protectedContentManager.d.ts +162 -0
  151. package/dist/utils/protectedContentManager.js +427 -0
  152. package/dist/utils/screenshotDetector.d.ts +72 -0
  153. package/dist/utils/screenshotDetector.js +179 -0
  154. package/dist/utils/securityOverlayManager-observer-pause.d.ts +283 -0
  155. package/dist/utils/securityOverlayManager-observer-pause.js +878 -0
  156. package/dist/utils/securityOverlayManager-simple.d.ts +197 -0
  157. package/dist/utils/securityOverlayManager-simple.js +552 -0
  158. package/dist/utils/securityOverlayManager.d.ts +260 -0
  159. package/dist/utils/securityOverlayManager.js +774 -0
  160. package/dist/utils/timeoutManager.d.ts +55 -0
  161. package/dist/utils/timeoutManager.js +121 -0
  162. package/package.json +54 -0
@@ -0,0 +1,90 @@
1
+ import type { CustomEventHandlers, ScreenshotOptions } from "../types";
2
+ import { AbstractStrategy } from "./AbstractStrategy";
3
+ /**
4
+ * Strategy for preventing screenshots and screen captures
5
+ */
6
+ export declare class ScreenshotStrategy extends AbstractStrategy {
7
+ private keydownHandler;
8
+ private keyupHandler;
9
+ private blurHandler;
10
+ private focusHandler;
11
+ private visibilityHandler;
12
+ private printHandler;
13
+ private beforePrintHandler;
14
+ private fullscreenChangeHandler;
15
+ private lastKeyEvent;
16
+ private options;
17
+ private customHandler?;
18
+ private categories;
19
+ private targetElement;
20
+ private shortcutManager;
21
+ /**
22
+ * Create a new ScreenshotStrategy
23
+ * @param options Options for customizing the screenshot protection
24
+ * @param customHandler Optional custom handler for screenshot attempts
25
+ * @param debugMode Enable debug mode for troubleshooting
26
+ */
27
+ constructor(options?: ScreenshotOptions, targetElement?: HTMLElement | null, customHandler?: CustomEventHandlers["onScreenshotAttempt"], debugMode?: boolean);
28
+ /**
29
+ * Handle keydown events to detect screenshot attempts
30
+ */
31
+ private handleKeyDown;
32
+ /**
33
+ * Handle keyup events - specifically for PrintScreen which may only trigger on keyup
34
+ */
35
+ private handleKeyUp;
36
+ /**
37
+ * Handle window blur event - might indicate screenshot tool activation
38
+ */
39
+ private handleWindowBlur;
40
+ /**
41
+ * Handle window focus event - remove overlay when focus returns
42
+ */
43
+ private handleWindowFocus;
44
+ /**
45
+ * Handle visibility change event - might indicate screenshot tool activation
46
+ */
47
+ private handleVisibilityChange;
48
+ /**
49
+ * Handle print event - might be used for screenshots
50
+ */
51
+ private handlePrint;
52
+ /**
53
+ * Handle beforeprint event - prepare for print/screenshot
54
+ */
55
+ private handleBeforePrint;
56
+ /**
57
+ * Handle fullscreen change event - detect entering fullscreen
58
+ */
59
+ private handleFullscreenChange;
60
+ /**
61
+ * Exit fullscreen mode if currently in fullscreen
62
+ */
63
+ private exitFullscreen;
64
+ /**
65
+ * Show a notification that fullscreen mode is disabled
66
+ */
67
+ private showScreenshotNotification;
68
+ /**
69
+ * Show a notification that fullscreen mode is disabled
70
+ */
71
+ private showFullscreenNotification;
72
+ /**
73
+ * Apply screenshot protection
74
+ */
75
+ apply(): void;
76
+ /**
77
+ * Remove screenshot protection
78
+ */
79
+ remove(): void;
80
+ /**
81
+ * Update screenshot options
82
+ * @param options New screenshot options
83
+ */
84
+ updateOptions(options: Record<string, unknown>): void;
85
+ /**
86
+ * Set debug mode
87
+ * @param enabled Whether debug mode should be enabled
88
+ */
89
+ setDebugMode(enabled: boolean): void;
90
+ }
@@ -0,0 +1,488 @@
1
+ import { isBrowser, isPrintSupported, isBeforePrintSupported } from "../utils/environment";
2
+ import { AbstractStrategy, StrategyErrorType } from "./AbstractStrategy";
3
+ import { ShortcutCategory } from "../utils/keyboardShortcutManager/keyboardShortcuts";
4
+ import { KeyboardShortcutManager } from "../utils/keyboardShortcutManager/keyboardShortcutManager";
5
+ import { ProtectionEventType } from "../core/mediator/protection-event";
6
+ import { timeoutManager } from "../utils/timeoutManager";
7
+ /**
8
+ * Strategy for preventing screenshots and screen captures
9
+ */
10
+ export class ScreenshotStrategy extends AbstractStrategy {
11
+ /**
12
+ * Create a new ScreenshotStrategy
13
+ * @param options Options for customizing the screenshot protection
14
+ * @param customHandler Optional custom handler for screenshot attempts
15
+ * @param debugMode Enable debug mode for troubleshooting
16
+ */
17
+ constructor(options, targetElement = null, customHandler, debugMode = false) {
18
+ super("ScreenshotStrategy", debugMode);
19
+ this.lastKeyEvent = 0;
20
+ this.categories = [ShortcutCategory.SCREENSHOT, ShortcutCategory.FULLSCREEN];
21
+ this.targetElement = null;
22
+ this.options = {
23
+ showOverlay: true,
24
+ overlayOptions: {
25
+ title: "SCREENSHOT PROTECTED",
26
+ textColor: "white",
27
+ backgroundColor: "rgba(255, 0, 0, 0.7)",
28
+ fontSize: "48px",
29
+ duration: 1000,
30
+ },
31
+ hideContent: true,
32
+ preventFullscreen: true,
33
+ fullscreenMessage: "Fullscreen mode is disabled for security reasons",
34
+ ...options,
35
+ };
36
+ this.customHandler = customHandler;
37
+ this.targetElement = targetElement;
38
+ this.keydownHandler = this.handleKeyDown.bind(this);
39
+ this.keyupHandler = this.handleKeyUp.bind(this);
40
+ this.blurHandler = this.handleWindowBlur.bind(this);
41
+ this.focusHandler = this.handleWindowFocus.bind(this);
42
+ this.visibilityHandler = this.handleVisibilityChange.bind(this);
43
+ this.printHandler = this.handlePrint.bind(this);
44
+ this.beforePrintHandler = this.handleBeforePrint.bind(this);
45
+ this.fullscreenChangeHandler = this.handleFullscreenChange.bind(this);
46
+ // Initialize shortcut manager
47
+ this.shortcutManager = KeyboardShortcutManager.getInstance();
48
+ // Set timeoutManager debug mode to match this strategy's debug mode
49
+ timeoutManager.setDebugMode(this.debugMode);
50
+ this.log("Initialized with options:", {
51
+ preventFullscreen: this.options.preventFullscreen,
52
+ duration: this.options.overlayOptions?.duration,
53
+ hideContent: this.options.hideContent,
54
+ });
55
+ }
56
+ /**
57
+ * Handle keydown events to detect screenshot attempts
58
+ */
59
+ handleKeyDown(e) {
60
+ return this.safeExecute("handleKeyDown", StrategyErrorType.EVENT_HANDLING, () => {
61
+ if (e.key === "F12") {
62
+ return; // Allow F12 to pass through
63
+ }
64
+ this.lastKeyEvent = Date.now();
65
+ // Use the shortcut manager to detect shortcuts
66
+ const shortcut = this.shortcutManager.matchesShortcut(e, this.categories);
67
+ if (shortcut) {
68
+ // Prevent the default action
69
+ e.preventDefault();
70
+ e.stopPropagation();
71
+ this.log(`Detected keyboard shortcut: ${shortcut.id} (${this.shortcutManager.getShortcutDescription(shortcut)})`);
72
+ // Handle based on category
73
+ if (shortcut.category === ShortcutCategory.SCREENSHOT) {
74
+ // Publish screenshot attempt event
75
+ if (this.mediator) {
76
+ this.showScreenshotNotification();
77
+ }
78
+ // Call custom handler if provided
79
+ if (this.customHandler) {
80
+ this.customHandler(e);
81
+ }
82
+ return false;
83
+ }
84
+ else if (shortcut.category === ShortcutCategory.FULLSCREEN && this.options.preventFullscreen) {
85
+ // Exit fullscreen if currently in fullscreen mode
86
+ this.exitFullscreen();
87
+ // Show anti-fullscreen notification
88
+ this.showFullscreenNotification();
89
+ // Call custom handler if provided
90
+ if (this.customHandler) {
91
+ this.customHandler(e);
92
+ }
93
+ return false;
94
+ }
95
+ }
96
+ });
97
+ }
98
+ /**
99
+ * Handle keyup events - specifically for PrintScreen which may only trigger on keyup
100
+ */
101
+ handleKeyUp(e) {
102
+ return this.safeExecute("handleKeyUp", StrategyErrorType.EVENT_HANDLING, () => {
103
+ // Check for PrintScreen key
104
+ const isPrintScreen = e.key === "PrintScreen" ||
105
+ e.key === "PrtScn" ||
106
+ e.key === "Print" ||
107
+ e.key === "PrtSc" ||
108
+ e.code === "PrintScreen" ||
109
+ e.keyCode === 44;
110
+ // Check for SysRq key
111
+ const isSysRq = e.key === "SysRq" || e.code === "SysRq";
112
+ if (isPrintScreen || isSysRq) {
113
+ this.log("PrintScreen/SysRq key detected on keyup");
114
+ e.preventDefault();
115
+ e.stopPropagation();
116
+ // Publish screenshot attempt event
117
+ if (this.mediator) {
118
+ this.showScreenshotNotification();
119
+ }
120
+ // Call custom handler if provided
121
+ if (this.customHandler) {
122
+ this.customHandler(e);
123
+ }
124
+ return false;
125
+ }
126
+ });
127
+ }
128
+ /**
129
+ * Handle window blur event - might indicate screenshot tool activation
130
+ */
131
+ handleWindowBlur() {
132
+ return this.safeExecute("handleWindowBlur", StrategyErrorType.EVENT_HANDLING, () => {
133
+ const timeSinceLastKey = Date.now() - this.lastKeyEvent;
134
+ // If window loses focus within 500ms of a key event, it might be a screenshot tool
135
+ if (timeSinceLastKey < 500) {
136
+ this.log("Window blur detected shortly after key event, possible screenshot attempt");
137
+ // Publish screenshot attempt event
138
+ if (this.mediator) {
139
+ this.showScreenshotNotification();
140
+ }
141
+ }
142
+ });
143
+ }
144
+ /**
145
+ * Handle window focus event - remove overlay when focus returns
146
+ */
147
+ handleWindowFocus() {
148
+ return this.safeExecute("handleWindowFocus", StrategyErrorType.EVENT_HANDLING, () => {
149
+ // No need to do anything here - the handler will manage timeouts
150
+ });
151
+ }
152
+ /**
153
+ * Handle visibility change event - might indicate screenshot tool activation
154
+ */
155
+ handleVisibilityChange() {
156
+ return this.safeExecute("handleVisibilityChange", StrategyErrorType.EVENT_HANDLING, () => {
157
+ if (document.visibilityState === "hidden") {
158
+ const timeSinceLastKey = Date.now() - this.lastKeyEvent;
159
+ // If document becomes hidden within 500ms of a key event, it might be a screenshot tool
160
+ if (timeSinceLastKey < 500) {
161
+ this.log("Visibility change detected shortly after key event, possible screenshot attempt");
162
+ // Publish screenshot attempt event
163
+ if (this.mediator) {
164
+ this.showScreenshotNotification();
165
+ }
166
+ }
167
+ }
168
+ });
169
+ }
170
+ /**
171
+ * Handle print event - might be used for screenshots
172
+ */
173
+ handlePrint() {
174
+ return this.safeExecute("handlePrint", StrategyErrorType.EVENT_HANDLING, () => {
175
+ this.log("Print event detected, possible screenshot attempt");
176
+ // Publish screenshot attempt event
177
+ if (this.mediator) {
178
+ this.showScreenshotNotification();
179
+ }
180
+ });
181
+ }
182
+ /**
183
+ * Handle beforeprint event - prepare for print/screenshot
184
+ */
185
+ handleBeforePrint() {
186
+ return this.safeExecute("handleBeforePrint", StrategyErrorType.EVENT_HANDLING, () => {
187
+ this.log("BeforePrint event detected, possible screenshot attempt");
188
+ // Publish screenshot attempt event
189
+ if (this.mediator) {
190
+ this.showScreenshotNotification();
191
+ }
192
+ });
193
+ }
194
+ /**
195
+ * Handle fullscreen change event - detect entering fullscreen
196
+ */
197
+ handleFullscreenChange() {
198
+ return this.safeExecute("handleFullscreenChange", StrategyErrorType.EVENT_HANDLING, () => {
199
+ if (!this.options.preventFullscreen)
200
+ return;
201
+ // Check if we're in fullscreen mode
202
+ const isInFullscreen = document.fullscreenElement ||
203
+ document.webkitFullscreenElement ||
204
+ document.mozFullScreenElement ||
205
+ document.msFullscreenElement;
206
+ if (isInFullscreen) {
207
+ this.log("Fullscreen mode detected, exiting fullscreen");
208
+ // Exit fullscreen mode
209
+ this.exitFullscreen();
210
+ // Show notification
211
+ this.showFullscreenNotification();
212
+ // Call custom handler if provided
213
+ if (this.customHandler) {
214
+ this.customHandler(new Event("fullscreenchange"));
215
+ }
216
+ }
217
+ });
218
+ }
219
+ /**
220
+ * Exit fullscreen mode if currently in fullscreen
221
+ */
222
+ exitFullscreen() {
223
+ return this.safeExecute("exitFullscreen", StrategyErrorType.APPLICATION, () => {
224
+ if (!isBrowser())
225
+ return;
226
+ // Check if document is active and has a fullscreen element before attempting to exit
227
+ try {
228
+ // Only attempt to exit if we're actually in fullscreen mode
229
+ const isInFullscreen = document.fullscreenElement ||
230
+ document.webkitFullscreenElement ||
231
+ document.mozFullScreenElement ||
232
+ document.msFullscreenElement;
233
+ if (isInFullscreen) {
234
+ if (document.exitFullscreen) {
235
+ document.exitFullscreen().catch((err) => {
236
+ // Silently catch errors during exit fullscreen
237
+ this.log("Error exiting fullscreen:", err.message);
238
+ });
239
+ }
240
+ else if (document.webkitExitFullscreen) {
241
+ document.webkitExitFullscreen();
242
+ }
243
+ else if (document.mozCancelFullScreen) {
244
+ document.mozCancelFullScreen();
245
+ }
246
+ else if (document.msExitFullscreen) {
247
+ document.msExitFullscreen();
248
+ }
249
+ this.log("Exited fullscreen mode");
250
+ }
251
+ else {
252
+ this.log("Not in fullscreen mode, no need to exit");
253
+ }
254
+ }
255
+ catch (error) {
256
+ this.error("Error checking fullscreen state:", error);
257
+ }
258
+ });
259
+ }
260
+ /**
261
+ * Show a notification that fullscreen mode is disabled
262
+ */
263
+ showScreenshotNotification() {
264
+ return this.safeExecute("showScreenshotNotification", StrategyErrorType.APPLICATION, () => {
265
+ if (!isBrowser() || !this.mediator)
266
+ return;
267
+ // Publish overlay shown event through the mediator
268
+ this.mediator.publish({
269
+ type: ProtectionEventType.OVERLAY_SHOWN,
270
+ source: this.STRATEGY_NAME,
271
+ timestamp: Date.now(),
272
+ data: {
273
+ strategyName: this.STRATEGY_NAME,
274
+ overlayType: "screenshot_notification",
275
+ options: {
276
+ ...this.options.overlayOptions,
277
+ blockEvents: false, // Don't block events, just show a notification
278
+ autoRestore: true,
279
+ },
280
+ priority: 5,
281
+ duration: 3000, // Show for 3 seconds
282
+ },
283
+ });
284
+ this.log("Showed screenshot disabled notification");
285
+ });
286
+ }
287
+ /**
288
+ * Show a notification that fullscreen mode is disabled
289
+ */
290
+ showFullscreenNotification() {
291
+ return this.safeExecute("showFullscreenNotification", StrategyErrorType.APPLICATION, () => {
292
+ if (!isBrowser() || !this.mediator)
293
+ return;
294
+ // Publish overlay shown event through the mediator
295
+ this.mediator.publish({
296
+ type: ProtectionEventType.OVERLAY_SHOWN,
297
+ source: this.STRATEGY_NAME,
298
+ timestamp: Date.now(),
299
+ data: {
300
+ strategyName: this.STRATEGY_NAME,
301
+ overlayType: "fullscreen_notification",
302
+ options: {
303
+ ...this.options.overlayOptions,
304
+ title: "Fullscreen Disabled",
305
+ message: this.options.fullscreenMessage || "Fullscreen mode is disabled for security reasons",
306
+ blockEvents: false, // Don't block events, just show a notification
307
+ autoRestore: true,
308
+ },
309
+ priority: 5,
310
+ duration: 3000, // Show for 3 seconds
311
+ },
312
+ });
313
+ this.log("Showed fullscreen disabled notification");
314
+ });
315
+ }
316
+ /**
317
+ * Apply screenshot protection
318
+ */
319
+ apply() {
320
+ return this.safeExecute("apply", StrategyErrorType.APPLICATION, () => {
321
+ if (this.isAppliedFlag) {
322
+ this.log("Protection already applied");
323
+ return;
324
+ }
325
+ if (isBrowser()) {
326
+ // Use both keydown and keyup to ensure we catch all PrintScreen events
327
+ this.registerEvent(document, "keydown", this.keydownHandler, {
328
+ capture: true,
329
+ priority: 10,
330
+ });
331
+ this.registerEvent(document, "keyup", this.keyupHandler, {
332
+ capture: true,
333
+ priority: 10,
334
+ });
335
+ // Add window blur/focus detection
336
+ this.registerEvent(window, "blur", this.blurHandler, { priority: 10 });
337
+ this.registerEvent(window, "focus", this.focusHandler, { priority: 10 });
338
+ // Add visibility change detection
339
+ this.registerEvent(document, "visibilitychange", this.visibilityHandler, { priority: 10 });
340
+ // Add print event detection if supported
341
+ if (isPrintSupported()) {
342
+ this.registerEvent(window, "afterprint", this.printHandler, { priority: 10 });
343
+ }
344
+ // Add beforeprint event detection if supported
345
+ if (isBeforePrintSupported()) {
346
+ this.registerEvent(window, "beforeprint", this.beforePrintHandler, { priority: 10 });
347
+ }
348
+ // Add fullscreen change event listeners if preventing fullscreen
349
+ if (this.options.preventFullscreen) {
350
+ this.registerEvent(document, "fullscreenchange", this.fullscreenChangeHandler, {
351
+ priority: 10,
352
+ });
353
+ this.registerEvent(document, "webkitfullscreenchange", this.fullscreenChangeHandler, {
354
+ priority: 10,
355
+ });
356
+ this.registerEvent(document, "mozfullscreenchange", this.fullscreenChangeHandler, {
357
+ priority: 10,
358
+ });
359
+ this.registerEvent(document, "MSFullscreenChange", this.fullscreenChangeHandler, {
360
+ priority: 10,
361
+ });
362
+ // Use a longer delay to ensure the document is fully active
363
+ setTimeout(() => {
364
+ // Use setTimeout to ensure the document is ready and active
365
+ this.exitFullscreen();
366
+ }, 500); // Increased from 0 to 500ms
367
+ }
368
+ this.isAppliedFlag = true;
369
+ this.log("Screenshot protection applied", {
370
+ printSupported: isPrintSupported(),
371
+ beforePrintSupported: isBeforePrintSupported(),
372
+ preventFullscreen: this.options.preventFullscreen,
373
+ registeredEvents: this.eventIds.length,
374
+ });
375
+ }
376
+ });
377
+ }
378
+ /**
379
+ * Remove screenshot protection
380
+ */
381
+ remove() {
382
+ return this.safeExecute("remove", StrategyErrorType.REMOVAL, () => {
383
+ if (!this.isAppliedFlag) {
384
+ this.log("Protection not applied");
385
+ return;
386
+ }
387
+ if (isBrowser()) {
388
+ // First attempt - remove by owner using the parent class method
389
+ this.removeEventsByOwner();
390
+ // Second attempt - try direct DOM removal as fallback
391
+ try {
392
+ document.removeEventListener("keydown", this.keydownHandler, { capture: true });
393
+ document.removeEventListener("keyup", this.keyupHandler, { capture: true });
394
+ window.removeEventListener("blur", this.blurHandler);
395
+ window.removeEventListener("focus", this.focusHandler);
396
+ document.removeEventListener("visibilitychange", this.visibilityHandler);
397
+ if (isPrintSupported()) {
398
+ window.removeEventListener("afterprint", this.printHandler);
399
+ }
400
+ if (isBeforePrintSupported()) {
401
+ window.removeEventListener("beforeprint", this.beforePrintHandler);
402
+ }
403
+ if (this.options.preventFullscreen) {
404
+ document.removeEventListener("fullscreenchange", this.fullscreenChangeHandler);
405
+ document.removeEventListener("webkitfullscreenchange", this.fullscreenChangeHandler);
406
+ document.removeEventListener("mozfullscreenchange", this.fullscreenChangeHandler);
407
+ document.removeEventListener("MSFullscreenChange", this.fullscreenChangeHandler);
408
+ }
409
+ this.log("Removed events via direct DOM API");
410
+ }
411
+ catch (domError) {
412
+ // Ignore errors in direct DOM removal
413
+ this.error("Error in fallback DOM removal:", domError);
414
+ }
415
+ // Clear any pending timeout using timeoutManager
416
+ timeoutManager.clearTimeout(`${this.STRATEGY_NAME}-overlay`);
417
+ // Clear tracked event IDs (parent class method will do this too, but being explicit)
418
+ this.eventIds = [];
419
+ this.isAppliedFlag = false;
420
+ this.log("Screenshot protection removed");
421
+ }
422
+ });
423
+ }
424
+ /**
425
+ * Update screenshot options
426
+ * @param options New screenshot options
427
+ */
428
+ updateOptions(options) {
429
+ return this.safeExecute("updateOptions", StrategyErrorType.OPTION_UPDATE, () => {
430
+ this.log("Updating options", options);
431
+ const typedOptions = options;
432
+ const wasPreventingFullscreen = this.options.preventFullscreen;
433
+ this.options = {
434
+ ...this.options,
435
+ ...typedOptions,
436
+ };
437
+ // If fullscreen prevention was toggled, we need to update event listeners
438
+ if (this.isAppliedFlag && wasPreventingFullscreen !== this.options.preventFullscreen) {
439
+ if (this.options.preventFullscreen) {
440
+ // Add fullscreen event listeners
441
+ this.registerEvent(document, "fullscreenchange", this.fullscreenChangeHandler, {
442
+ priority: 10,
443
+ });
444
+ this.registerEvent(document, "webkitfullscreenchange", this.fullscreenChangeHandler, {
445
+ priority: 10,
446
+ });
447
+ this.registerEvent(document, "mozfullscreenchange", this.fullscreenChangeHandler, {
448
+ priority: 10,
449
+ });
450
+ this.registerEvent(document, "MSFullscreenChange", this.fullscreenChangeHandler, {
451
+ priority: 10,
452
+ });
453
+ // Exit fullscreen if already in fullscreen mode
454
+ this.exitFullscreen();
455
+ this.log("Added fullscreen protection");
456
+ }
457
+ else {
458
+ // If we're removing fullscreen prevention while protection is active,
459
+ // it's safest to remove all event listeners and reapply the ones we still need
460
+ const wasApplied = this.isAppliedFlag;
461
+ this.remove();
462
+ if (wasApplied) {
463
+ this.apply();
464
+ }
465
+ this.log("Removed fullscreen protection and reapplied other protections");
466
+ }
467
+ }
468
+ // Handle categories if present
469
+ if (options.categories !== undefined && Array.isArray(options.categories)) {
470
+ this.categories = options.categories;
471
+ this.log("Updated shortcut categories:", this.categories);
472
+ }
473
+ // Update timeoutManager debug mode if our debug mode changed
474
+ if (options.debugMode !== undefined) {
475
+ timeoutManager.setDebugMode(!!options.debugMode);
476
+ }
477
+ });
478
+ }
479
+ /**
480
+ * Set debug mode
481
+ * @param enabled Whether debug mode should be enabled
482
+ */
483
+ setDebugMode(enabled) {
484
+ super.setDebugMode(enabled);
485
+ // Update timeoutManager debug mode
486
+ timeoutManager.setDebugMode(enabled);
487
+ }
488
+ }
@@ -0,0 +1,49 @@
1
+ import type { CustomEventHandlers } from "../types";
2
+ import { AbstractStrategy } from "./AbstractStrategy";
3
+ /**
4
+ * Strategy for preventing text selection
5
+ */
6
+ export declare class SelectionStrategy extends AbstractStrategy {
7
+ private targetElement;
8
+ private styleElement;
9
+ private selectionHandler;
10
+ private dragHandler;
11
+ private customHandler?;
12
+ private preventDrag;
13
+ /**
14
+ * Create a new SelectionStrategy
15
+ * @param targetElement Element to protect (defaults to document.body)
16
+ * @param customHandler Optional custom handler for selection attempts
17
+ * @param debugMode Enable debug mode for troubleshooting
18
+ */
19
+ constructor(targetElement?: HTMLElement | null, customHandler?: CustomEventHandlers["onSelectionAttempt"], debugMode?: boolean);
20
+ /**
21
+ * Handle selection event
22
+ */
23
+ private handleSelection;
24
+ /**
25
+ * Handle drag event
26
+ */
27
+ private handleDrag;
28
+ /**
29
+ * Inject CSS to prevent selection
30
+ */
31
+ private injectSelectionStyles;
32
+ /**
33
+ * Remove selection-blocking CSS
34
+ */
35
+ private removeSelectionStyles;
36
+ /**
37
+ * Apply selection protection
38
+ */
39
+ apply(): void;
40
+ /**
41
+ * Remove selection protection
42
+ */
43
+ remove(): void;
44
+ /**
45
+ * Update selection protection options
46
+ * @param options New options for selection protection
47
+ */
48
+ updateOptions(options: Record<string, unknown>): void;
49
+ }