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,246 @@
1
+ import { DebuggerDetector } from "./debuggerDetector";
2
+ import { TimingDetector } from "./timingDetector";
3
+ import { DateToStringDetector } from "./dateToStringDetector";
4
+ import { FuncToStringDetector } from "./funcToStringDetector";
5
+ import { RegToStringDetector } from "./regToStringDetector";
6
+ import { DefineGetterDetector } from "./defineGetterDetector";
7
+ import { DebugLibDetector } from "./debugLibDetector";
8
+ import { SizeDetector } from "./sizeDetector";
9
+ import { getBrowser, isMobile } from "../environment";
10
+ import { SimpleLoggingService } from "../logging/simple/SimpleLoggingService";
11
+ import { AbstractDevToolsDetector } from "./AbstractDevToolsDetector";
12
+ /**
13
+ * Manager class that coordinates multiple DevTools detection methods
14
+ * **Chrome, Edge, Opera**: Primarily uses `DebuggerDetector` with `DefineGetterDetector` as backup
15
+ * **Firefox**: Uses `TimingDetector` and `RegToStringDetector` for reliable detection
16
+ * **Safari**: Primarily uses `DateToStringDetector` with `DefineGetterDetector` as backup
17
+ * **QQ Browser**: Uses `RegToStringDetector` which works particularly well for this browser
18
+ * **Mobile Browsers**: Always includes `DebugLibDetector` to catch third-party debugging tools
19
+ */
20
+ export class DevToolsDetectorManager extends AbstractDevToolsDetector {
21
+ /**
22
+ * Create a new DevToolsDetectorManager
23
+ * @param options Configuration options
24
+ */
25
+ constructor(options = {}) {
26
+ super('DevToolsDetectorManager');
27
+ this.detectors = new Map();
28
+ this.activeDetectors = [];
29
+ this.isInitialCheckDone = false;
30
+ this.initialCheckTimeout = null;
31
+ const debugMode = !!options.debugMode;
32
+ this.logger = new SimpleLoggingService("DevToolsDetectorManager", debugMode);
33
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
34
+ this.onDevToolsChange = options.onDevToolsChange || ((isOpen) => { });
35
+ this.browserInfo = getBrowser();
36
+ this.isMobileDevice = isMobile();
37
+ this.delayInitialCheck = options.delayInitialCheck !== false; // Default to true
38
+ this.initialCheckDelay = options.initialCheckDelay || 1000;
39
+ // Initialize all available detectors
40
+ this.initializeAllDetectors(options);
41
+ // Select appropriate detectors based on browser
42
+ this.selectActiveDetectors(options.enabledDetectors);
43
+ this.logger.log("Initialized for browser:", this.browserInfo.name);
44
+ this.logger.log("Mobile device:", this.isMobileDevice);
45
+ this.logger.log("Active detectors:", Array.from(this.activeDetectors).map((d) => d.constructor.name));
46
+ // Schedule initial check with delay to avoid false positives during page load
47
+ if (this.delayInitialCheck) {
48
+ this.logger.log(`Delaying initial check by ${this.initialCheckDelay}ms`);
49
+ this.initialCheckTimeout = window.setTimeout(() => {
50
+ this.isInitialCheckDone = true;
51
+ this.checkDevTools();
52
+ this.initialCheckTimeout = null;
53
+ this.logger.log("Initial check completed");
54
+ }, this.initialCheckDelay);
55
+ }
56
+ else {
57
+ this.isInitialCheckDone = true;
58
+ }
59
+ }
60
+ /**
61
+ * Initialize all available detectors
62
+ */
63
+ initializeAllDetectors(options) {
64
+ const commonOptions = {
65
+ onDevToolsChange: this.handleDetectorChange.bind(this),
66
+ debugMode: this.logger.isDebugEnabled(),
67
+ };
68
+ // Initialize all detectors but don't activate them yet
69
+ this.detectors.set("debugger", new DebuggerDetector({
70
+ ...commonOptions,
71
+ timeoutDuration: options.debuggerTimeoutDuration || 50,
72
+ }));
73
+ this.detectors.set("timing", new TimingDetector({
74
+ ...commonOptions,
75
+ thresholdMultiplier: 3, // Slightly higher for better reliability
76
+ }));
77
+ if (DateToStringDetector.isSupported()) {
78
+ this.detectors.set("dateToString", new DateToStringDetector({
79
+ ...commonOptions,
80
+ threshold: 2,
81
+ }));
82
+ }
83
+ if (FuncToStringDetector.isSupported()) {
84
+ this.detectors.set("funcToString", new FuncToStringDetector({
85
+ ...commonOptions,
86
+ threshold: 2,
87
+ }));
88
+ }
89
+ if (RegToStringDetector.isSupported()) {
90
+ this.detectors.set("regToString", new RegToStringDetector({
91
+ ...commonOptions,
92
+ timeThreshold: 100,
93
+ }));
94
+ }
95
+ this.detectors.set("defineGetter", new DefineGetterDetector({
96
+ ...commonOptions,
97
+ checkInterval: options.checkInterval || 1000,
98
+ }));
99
+ this.detectors.set("debugLib", new DebugLibDetector({
100
+ ...commonOptions,
101
+ checkInterval: options.checkInterval || 1000,
102
+ }));
103
+ if (SizeDetector.isSupported()) {
104
+ this.detectors.set("size", new SizeDetector({
105
+ ...commonOptions,
106
+ widthThreshold: 200,
107
+ heightThreshold: 300,
108
+ }));
109
+ }
110
+ }
111
+ /**
112
+ * Select which detectors to activate based on browser
113
+ */
114
+ selectActiveDetectors(userEnabledDetectors) {
115
+ // If user specified detectors, use those
116
+ if (userEnabledDetectors && userEnabledDetectors.length > 0) {
117
+ this.activeDetectors = userEnabledDetectors
118
+ .filter((type) => this.detectors.has(type))
119
+ .map((type) => this.detectors.get(type))
120
+ .filter(Boolean);
121
+ this.logger.log("Using user-specified detectors");
122
+ return;
123
+ }
124
+ // Get browser-specific detectors
125
+ let detectorTypes = DevToolsDetectorManager.BROWSER_DETECTOR_MAP[this.browserInfo.name] ||
126
+ DevToolsDetectorManager.BROWSER_DETECTOR_MAP.unknown;
127
+ // Apply mobile overrides if on mobile
128
+ if (this.isMobileDevice) {
129
+ const mobileDetectorTypes = DevToolsDetectorManager.MOBILE_DETECTOR_MAP[this.browserInfo.name] ||
130
+ DevToolsDetectorManager.MOBILE_DETECTOR_MAP.default;
131
+ // Combine with browser-specific detectors, prioritizing mobile ones
132
+ detectorTypes = [...mobileDetectorTypes, ...detectorTypes.filter((type) => !mobileDetectorTypes.includes(type))];
133
+ }
134
+ // Activate the selected detectors
135
+ this.activeDetectors = detectorTypes
136
+ .filter((type) => this.detectors.has(type))
137
+ .map((type) => this.detectors.get(type))
138
+ .filter(Boolean);
139
+ // Always start the continuous detectors
140
+ const continuousDetector = this.detectors.get("debugLib");
141
+ if (continuousDetector) {
142
+ continuousDetector.startDetection();
143
+ }
144
+ this.logger.log("Selected detectors for", this.browserInfo.name, ":", detectorTypes);
145
+ }
146
+ /**
147
+ * Handle state change from any detector
148
+ */
149
+ handleDetectorChange(isOpen) {
150
+ // Skip state changes until initial check is done
151
+ if (!this.isInitialCheckDone) {
152
+ this.logger.log("Ignoring state change before initial check");
153
+ return;
154
+ }
155
+ this.updateDevToolsState(isOpen);
156
+ }
157
+ /**
158
+ * Check if DevTools is open using all active detectors
159
+ */
160
+ checkDevTools() {
161
+ // Skip checks until initial check is done
162
+ if (!this.isInitialCheckDone) {
163
+ this.logger.log("Skipping check before initial delay");
164
+ return;
165
+ }
166
+ for (const detector of this.activeDetectors) {
167
+ detector.checkDevTools();
168
+ // If any detector reports DevTools as open, we can stop checking
169
+ if (detector.isOpen()) {
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ /**
175
+ * Get the current DevTools state
176
+ * @returns True if DevTools is open
177
+ */
178
+ isOpen() {
179
+ return this.isDevToolsOpen;
180
+ }
181
+ /**
182
+ * Clean up resources for all detectors
183
+ */
184
+ dispose() {
185
+ // Clear initial check timeout if it exists
186
+ if (this.initialCheckTimeout !== null) {
187
+ clearTimeout(this.initialCheckTimeout);
188
+ this.initialCheckTimeout = null;
189
+ }
190
+ for (const detector of this.detectors.values()) {
191
+ detector.dispose();
192
+ }
193
+ this.detectors.clear();
194
+ this.activeDetectors = [];
195
+ this.logger.log("Disposed all detectors");
196
+ }
197
+ /**
198
+ * Set debug mode for all detectors
199
+ * @param enabled Whether debug mode should be enabled
200
+ */
201
+ setDebugMode(enabled) {
202
+ this.logger.setDebugMode(enabled);
203
+ for (const detector of this.detectors.values()) {
204
+ detector.setDebugMode(enabled);
205
+ }
206
+ }
207
+ }
208
+ // Browser-specific detector mapping
209
+ DevToolsDetectorManager.BROWSER_DETECTOR_MAP = {
210
+ // Chromium-based browsers
211
+ chrome: ["debugger", "defineGetter"],
212
+ edge: ["debugger", "defineGetter"],
213
+ chromium: ["debugger", "defineGetter"],
214
+ opera: ["debugger", "defineGetter"],
215
+ vivaldi: ["debugger", "defineGetter"],
216
+ // Firefox and derivatives
217
+ firefox: ["timing", "regToString"],
218
+ // Safari
219
+ safari: ["dateToString", "defineGetter"],
220
+ // Chinese browsers
221
+ qq: ["regToString", "debugger"],
222
+ uc: ["debugger", "defineGetter"],
223
+ baidu: ["debugger", "defineGetter"],
224
+ mi: ["debugger", "defineGetter"],
225
+ wechat: ["debugger", "defineGetter"],
226
+ // Korean browsers
227
+ samsung: ["debugger", "defineGetter"],
228
+ whale: ["debugger", "defineGetter"],
229
+ // Russian browsers
230
+ yandex: ["debugger", "defineGetter"],
231
+ // Japanese browsers (typically WebKit/Blink based)
232
+ // Fallback for unknown browsers
233
+ unknown: ["debugger", "defineGetter", "dateToString"],
234
+ };
235
+ // Mobile-specific overrides
236
+ DevToolsDetectorManager.MOBILE_DETECTOR_MAP = {
237
+ // iOS Safari needs special handling
238
+ safari: ["dateToString", "debugLib"],
239
+ // Android Chrome/WebView
240
+ chrome: ["debugger", "debugLib"],
241
+ // UC and QQ browsers on mobile
242
+ uc: ["debugger", "debugLib"],
243
+ qq: ["regToString", "debugLib"],
244
+ // Default for other mobile browsers
245
+ default: ["debugger", "debugLib"],
246
+ };
@@ -0,0 +1,8 @@
1
+ export declare class FirefoxDevToolsDetector {
2
+ private debugMode;
3
+ constructor(debugMode?: boolean);
4
+ detect(): boolean;
5
+ private checkDevToolsElements;
6
+ private checkDevToolsProperties;
7
+ private checkTimingAnomaly;
8
+ }
@@ -0,0 +1,64 @@
1
+ export class FirefoxDevToolsDetector {
2
+ constructor(debugMode = false) {
3
+ this.debugMode = debugMode;
4
+ }
5
+ detect() {
6
+ // Method 1: Check for Firefox-specific DevTools elements
7
+ const hasDevToolsElements = this.checkDevToolsElements();
8
+ console.log('devtools elements', hasDevToolsElements);
9
+ // Method 2: Check for Firefox-specific DevTools properties
10
+ const hasDevToolsProperties = this.checkDevToolsProperties();
11
+ console.log('devtools properties', hasDevToolsProperties);
12
+ // Method 3: Performance timing check
13
+ const hasTimingAnomaly = this.checkTimingAnomaly();
14
+ console.log('timing anomaly', hasTimingAnomaly);
15
+ return hasDevToolsElements || hasDevToolsProperties || hasTimingAnomaly;
16
+ }
17
+ checkDevToolsElements() {
18
+ // Firefox adds specific elements when DevTools is open
19
+ console.log('checking devtools elements');
20
+ return !!(document.documentElement.getAttribute('debug') ||
21
+ document.documentElement.getAttribute('webdriver') ||
22
+ document.documentElement.getAttribute('firefox-devtools'));
23
+ }
24
+ checkDevToolsProperties() {
25
+ console.log('checking devtools properties');
26
+ // Firefox exposes specific properties when DevTools is open
27
+ return !!(window.mozInnerScreenX !== undefined ||
28
+ // Check for Firefox debugger
29
+ Object.prototype.hasOwnProperty.call(window, '__firefox__') ||
30
+ Object.prototype.hasOwnProperty.call(window, 'netscape'));
31
+ }
32
+ checkTimingAnomaly() {
33
+ console.log('Checking timing anomaly');
34
+ const start = performance.now();
35
+ // Create and manipulate a large array with operations that are
36
+ // significantly affected by Firefox DevTools' debugger
37
+ const array = new Array(100000);
38
+ // Fill with incrementing numbers and perform operations
39
+ // This specific pattern is more reliably affected by Firefox's debugger
40
+ for (let i = 0; i < array.length; i++) {
41
+ array[i] = i;
42
+ // Add some basic operations that debugger will need to track
43
+ const temp = array[i] * 2;
44
+ array[i] = temp + 1;
45
+ }
46
+ // Add a reduce operation which is particularly sensitive to debugger overhead
47
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
48
+ const sum = array.reduce((acc, curr) => acc + curr, 0);
49
+ const end = performance.now();
50
+ const timeTaken = end - start;
51
+ console.log(timeTaken);
52
+ if (this.debugMode) {
53
+ console.log('Firefox timing check:', {
54
+ timeTaken,
55
+ operationsPerformed: array.length * 3, // 3 operations per item
56
+ averageTimePerOperation: timeTaken / (array.length * 3)
57
+ });
58
+ }
59
+ // Threshold is based on empirical testing
60
+ // Normal execution: ~5-20ms
61
+ // With DevTools open: >100ms
62
+ return timeTaken > 100;
63
+ }
64
+ }
@@ -0,0 +1,43 @@
1
+ import { AbstractDevToolsDetector } from "./AbstractDevToolsDetector";
2
+ import { DevToolsDetectorOptions } from "./detectorInterface";
3
+ /**
4
+ * Options for the FuncToStringDetector
5
+ */
6
+ export interface FuncToStringDetectorOptions extends DevToolsDetectorOptions {
7
+ /**
8
+ * Threshold for detection (number of toString calls)
9
+ */
10
+ threshold?: number;
11
+ }
12
+ /**
13
+ * Utility class for detecting DevTools using Function.toString behavior
14
+ * This approach works by detecting multiple calls to toString when a function is logged
15
+ * and DevTools is open
16
+ */
17
+ export declare class FuncToStringDetector extends AbstractDevToolsDetector {
18
+ private func;
19
+ private count;
20
+ private threshold;
21
+ /**
22
+ * Create a new FuncToStringDetector
23
+ * @param options Configuration options
24
+ */
25
+ constructor(options?: FuncToStringDetectorOptions);
26
+ /**
27
+ * Initialize the function with custom toString method
28
+ */
29
+ private initFunction;
30
+ /**
31
+ * Check if DevTools is open using Function.toString behavior
32
+ */
33
+ checkDevTools(): void;
34
+ /**
35
+ * Clean up resources
36
+ */
37
+ dispose(): void;
38
+ /**
39
+ * Check if this detector is supported in the current browser
40
+ * @returns True if supported
41
+ */
42
+ static isSupported(): boolean;
43
+ }
@@ -0,0 +1,90 @@
1
+ import { isBrowser, getBrowser, isMobile } from "../environment";
2
+ import { AbstractDevToolsDetector, DetectorErrorType } from "./AbstractDevToolsDetector";
3
+ /**
4
+ * Utility class for detecting DevTools using Function.toString behavior
5
+ * This approach works by detecting multiple calls to toString when a function is logged
6
+ * and DevTools is open
7
+ */
8
+ export class FuncToStringDetector extends AbstractDevToolsDetector {
9
+ /**
10
+ * Create a new FuncToStringDetector
11
+ * @param options Configuration options
12
+ */
13
+ constructor(options = {}) {
14
+ super("FuncToStringDetector", options);
15
+ this.func = null;
16
+ this.count = 0;
17
+ this.threshold = options.threshold || 2;
18
+ // Initialize the function with custom toString
19
+ this.initFunction();
20
+ this.logger.log("Initialized with threshold:", this.threshold);
21
+ }
22
+ /**
23
+ * Initialize the function with custom toString method
24
+ */
25
+ initFunction() {
26
+ this.safeExecute("initFunction", DetectorErrorType.INITIALIZATION_ERROR, () => {
27
+ if (!isBrowser())
28
+ return;
29
+ // Create an empty function
30
+ this.func = () => { };
31
+ // Override toString to count calls
32
+ this.func.toString = () => {
33
+ this.count++;
34
+ this.logger.log(`toString called (${this.count} times)`);
35
+ return "";
36
+ };
37
+ this.logger.log("Function initialized with custom toString");
38
+ });
39
+ }
40
+ /**
41
+ * Check if DevTools is open using Function.toString behavior
42
+ */
43
+ checkDevTools() {
44
+ if (this.isChecking || !isBrowser())
45
+ return;
46
+ this.isChecking = true;
47
+ this.safeExecute("checkDevTools", DetectorErrorType.DETECTION_ERROR, () => {
48
+ // Reset counter
49
+ this.count = 0;
50
+ // Log the function - this will trigger toString
51
+ console.log(this.func);
52
+ // Clear console to avoid clutter
53
+ if (!this.debugMode) {
54
+ console.clear();
55
+ }
56
+ // If toString was called multiple times, DevTools is likely open
57
+ const isOpen = this.count >= this.threshold;
58
+ // Update state and notify listeners if changed
59
+ this.updateDevToolsState(isOpen);
60
+ this.logger.log(`toString called ${this.count} times, threshold: ${this.threshold}`);
61
+ });
62
+ // Ensure isChecking is reset even if an error occurs
63
+ this.isChecking = false;
64
+ }
65
+ /**
66
+ * Clean up resources
67
+ */
68
+ dispose() {
69
+ this.safeExecute("dispose", DetectorErrorType.DISPOSAL_ERROR, () => {
70
+ this.func = null;
71
+ this.logger.log("Disposed");
72
+ });
73
+ super.dispose();
74
+ }
75
+ /**
76
+ * Check if this detector is supported in the current browser
77
+ * @returns True if supported
78
+ */
79
+ static isSupported() {
80
+ if (!isBrowser())
81
+ return false;
82
+ const browser = getBrowser();
83
+ const isMobileDevice = isMobile();
84
+ // Not supported in iOS Chrome or iOS Edge
85
+ if (isMobileDevice && (browser.name === "chrome" || browser.name === "edge")) {
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+ }
@@ -0,0 +1,43 @@
1
+ import { AbstractDevToolsDetector } from "./AbstractDevToolsDetector";
2
+ import { DevToolsDetectorOptions } from "./detectorInterface";
3
+ /**
4
+ * Options for the RegToStringDetector
5
+ */
6
+ export interface RegToStringDetectorOptions extends DevToolsDetectorOptions {
7
+ /**
8
+ * Time threshold in milliseconds for QQ Browser detection
9
+ * If two toString calls happen within this time, DevTools is considered open
10
+ */
11
+ timeThreshold?: number;
12
+ }
13
+ /**
14
+ * Utility class for detecting DevTools using RegExp.toString behavior
15
+ * This approach works especially well in Firefox and QQ Browser
16
+ */
17
+ export declare class RegToStringDetector extends AbstractDevToolsDetector {
18
+ private reg;
19
+ private lastCallTime;
20
+ private timeThreshold;
21
+ /**
22
+ * Create a new RegToStringDetector
23
+ * @param options Configuration options
24
+ */
25
+ constructor(options?: RegToStringDetectorOptions);
26
+ /**
27
+ * Initialize the RegExp object with custom toString method
28
+ */
29
+ private initRegExpObject;
30
+ /**
31
+ * Check if DevTools is open using RegExp.toString behavior
32
+ */
33
+ checkDevTools(): void;
34
+ /**
35
+ * Clean up resources
36
+ */
37
+ dispose(): void;
38
+ /**
39
+ * Check if this detector is supported in the current browser
40
+ * @returns True if supported
41
+ */
42
+ static isSupported(): boolean;
43
+ }
@@ -0,0 +1,129 @@
1
+ import { isBrowser, getBrowser } from "../environment";
2
+ import { AbstractDevToolsDetector, DetectorErrorType } from "./AbstractDevToolsDetector";
3
+ /**
4
+ * Utility class for detecting DevTools using RegExp.toString behavior
5
+ * This approach works especially well in Firefox and QQ Browser
6
+ */
7
+ export class RegToStringDetector extends AbstractDevToolsDetector {
8
+ /**
9
+ * Create a new RegToStringDetector
10
+ * @param options Configuration options
11
+ */
12
+ constructor(options = {}) {
13
+ super("RegToStringDetector", options);
14
+ this.reg = null;
15
+ this.lastCallTime = 0;
16
+ this.timeThreshold = options.timeThreshold || 100;
17
+ // Initialize the RegExp object with custom toString
18
+ this.initRegExpObject();
19
+ this.logger.log("Initialized with time threshold:", this.timeThreshold);
20
+ }
21
+ /**
22
+ * Initialize the RegExp object with custom toString method
23
+ */
24
+ initRegExpObject() {
25
+ this.safeExecute("initRegExpObject", DetectorErrorType.INITIALIZATION_ERROR, () => {
26
+ if (!isBrowser())
27
+ return;
28
+ this.reg = /./;
29
+ // Override toString to detect DevTools
30
+ this.reg.toString = () => {
31
+ const browser = getBrowser();
32
+ const isQQBrowser = browser.name === "qq" || navigator.userAgent.toLowerCase().includes("qqbrowser");
33
+ const isFirefox = browser.name === "firefox";
34
+ if (isQQBrowser) {
35
+ // For QQ Browser: When DevTools is closed, toString is called once.
36
+ // When DevTools is open, toString is called twice in quick succession.
37
+ // We use this timing difference to detect if DevTools is open.
38
+ const currentTime = Date.now();
39
+ if (this.lastCallTime && currentTime - this.lastCallTime < this.timeThreshold) {
40
+ // Two calls in quick succession - DevTools is likely open
41
+ this.updateDevToolsState(true);
42
+ this.logger.log("DevTools opened (QQ Browser detection)");
43
+ }
44
+ else {
45
+ // First call or calls too far apart
46
+ this.lastCallTime = currentTime;
47
+ }
48
+ }
49
+ else if (isFirefox) {
50
+ // For Firefox: toString is only called when DevTools is open
51
+ this.updateDevToolsState(true);
52
+ this.logger.log("DevTools opened (Firefox detection)");
53
+ }
54
+ return "";
55
+ };
56
+ this.logger.log("RegExp object initialized");
57
+ });
58
+ }
59
+ /**
60
+ * Check if DevTools is open using RegExp.toString behavior
61
+ */
62
+ checkDevTools() {
63
+ if (this.isChecking || !isBrowser() || !this.reg)
64
+ return;
65
+ this.isChecking = true;
66
+ this.safeExecute("checkDevTools", DetectorErrorType.DETECTION_ERROR, () => {
67
+ // Reset detection state for Firefox
68
+ const browser = getBrowser();
69
+ if (browser.name === "firefox" && this.isDevToolsOpen) {
70
+ this.updateDevToolsState(false);
71
+ }
72
+ // Log the RegExp object - this will trigger toString
73
+ console.log(this.reg);
74
+ // Clear console to avoid clutter
75
+ if (!this.debugMode) {
76
+ console.clear();
77
+ }
78
+ // For browsers other than Firefox and QQ Browser, we need to check if
79
+ // DevTools is closed after a short delay
80
+ setTimeout(() => {
81
+ this.safeExecute("checkDevToolsTimeout", DetectorErrorType.DETECTION_ERROR, () => {
82
+ const browser = getBrowser();
83
+ const isQQBrowser = browser.name === "qq" || navigator.userAgent.toLowerCase().includes("qqbrowser");
84
+ const isFirefox = browser.name === "firefox";
85
+ // If we're not in Firefox or QQ Browser and DevTools is open,
86
+ // check if it should be marked as closed
87
+ if (!isFirefox && !isQQBrowser && this.isDevToolsOpen) {
88
+ const currentTime = Date.now();
89
+ // If no recent toString calls, DevTools is likely closed
90
+ if (currentTime - this.lastCallTime > this.timeThreshold * 2) {
91
+ this.updateDevToolsState(false);
92
+ this.logger.log("DevTools closed");
93
+ }
94
+ }
95
+ this.isChecking = false;
96
+ });
97
+ }, this.timeThreshold * 2);
98
+ });
99
+ // Ensure isChecking is reset if an error occurs
100
+ if (this.isChecking) {
101
+ setTimeout(() => {
102
+ this.isChecking = false;
103
+ }, this.timeThreshold * 3);
104
+ }
105
+ }
106
+ /**
107
+ * Clean up resources
108
+ */
109
+ dispose() {
110
+ this.safeExecute("dispose", DetectorErrorType.DISPOSAL_ERROR, () => {
111
+ this.reg = null;
112
+ this.logger.log("Disposed");
113
+ });
114
+ super.dispose();
115
+ }
116
+ /**
117
+ * Check if this detector is supported in the current browser
118
+ * @returns True if supported
119
+ */
120
+ static isSupported() {
121
+ if (!isBrowser())
122
+ return false;
123
+ const browser = getBrowser();
124
+ const isQQBrowser = browser.name === "qq" || navigator.userAgent.toLowerCase().includes("qqbrowser");
125
+ const isFirefox = browser.name === "firefox";
126
+ // This detector works best in Firefox and QQ Browser
127
+ return isFirefox || isQQBrowser;
128
+ }
129
+ }
@@ -0,0 +1,54 @@
1
+ import { AbstractDevToolsDetector } from "./AbstractDevToolsDetector";
2
+ import { DevToolsDetectorOptions } from "./detectorInterface";
3
+ /**
4
+ * Options for the SizeDetector
5
+ */
6
+ export interface SizeDetectorOptions extends DevToolsDetectorOptions {
7
+ /**
8
+ * Width threshold in pixels
9
+ * If the difference between outer and inner width exceeds this, DevTools is considered open
10
+ */
11
+ widthThreshold?: number;
12
+ /**
13
+ * Height threshold in pixels
14
+ * If the difference between outer and inner height exceeds this, DevTools is considered open
15
+ */
16
+ heightThreshold?: number;
17
+ }
18
+ /**
19
+ * Utility class for detecting DevTools using window size differences
20
+ * This approach works by detecting unusual differences between outer and inner window dimensions
21
+ * that typically occur when DevTools are open
22
+ */
23
+ export declare class SizeDetector extends AbstractDevToolsDetector {
24
+ private widthThreshold;
25
+ private heightThreshold;
26
+ private resizeEventId;
27
+ /**
28
+ * Create a new SizeDetector
29
+ * @param options Configuration options
30
+ */
31
+ constructor(options?: SizeDetectorOptions);
32
+ /**
33
+ * Initialize resize event listener
34
+ */
35
+ private initResizeListener;
36
+ /**
37
+ * Calculate screen zoom ratio
38
+ * @returns The screen zoom ratio or false if it can't be determined
39
+ */
40
+ private getScreenZoomRatio;
41
+ /**
42
+ * Check if DevTools is open using window size differences
43
+ */
44
+ checkDevTools(): void;
45
+ /**
46
+ * Clean up resources
47
+ */
48
+ dispose(): void;
49
+ /**
50
+ * Check if this detector is supported in the current browser
51
+ * @returns True if supported
52
+ */
53
+ static isSupported(): boolean;
54
+ }