content-security-toolkit 1.0.1 → 1.0.2

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 (58) hide show
  1. package/README.md +22 -0
  2. package/dist/core/mediator/handlers/baseEventHandler.d.ts +65 -0
  3. package/dist/core/mediator/handlers/baseEventHandler.js +99 -0
  4. package/dist/core/mediator/handlers/index.d.ts +9 -0
  5. package/dist/core/mediator/handlers/index.js +34 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +1 -0
  8. package/dist/otel.d.ts +24 -0
  9. package/dist/otel.js +87 -0
  10. package/dist/strategies/AbstractStrategy.mediator.d.ts +162 -0
  11. package/dist/strategies/AbstractStrategy.mediator.js +349 -0
  12. package/dist/strategies/DevToolsStrategy copy.d.ts +85 -0
  13. package/dist/strategies/DevToolsStrategy copy.js +362 -0
  14. package/dist/strategies/DevToolsStrategy-detectorManager.d.ts +70 -0
  15. package/dist/strategies/DevToolsStrategy-detectorManager.js +309 -0
  16. package/dist/strategies/DevToolsStrategy-simple.d.ts +75 -0
  17. package/dist/strategies/DevToolsStrategy-simple.js +366 -0
  18. package/dist/strategies/StrategyRegistry.d.ts +133 -0
  19. package/dist/strategies/StrategyRegistry.js +379 -0
  20. package/dist/utils/base/LoggableComponent.d.ts +62 -0
  21. package/dist/utils/base/LoggableComponent.js +95 -0
  22. package/dist/utils/debuggerDetector/debuggerDetectionWorker.d.ts +6 -0
  23. package/dist/utils/debuggerDetector/debuggerDetectionWorker.js +24 -0
  24. package/dist/utils/debuggerDetector/debuggerDetector.d.ts +55 -0
  25. package/dist/utils/debuggerDetector/debuggerDetector.js +158 -0
  26. package/dist/utils/debuggerDetector/firefoxDetector.d.ts +8 -0
  27. package/dist/utils/debuggerDetector/firefoxDetector.js +64 -0
  28. package/dist/utils/detection.d.ts +29 -0
  29. package/dist/utils/detection.js +267 -0
  30. package/dist/utils/detectors/debuggerDetectionWorker.d.ts +6 -0
  31. package/dist/utils/detectors/debuggerDetectionWorker.js +24 -0
  32. package/dist/utils/detectors/firefoxDetector.d.ts +8 -0
  33. package/dist/utils/detectors/firefoxDetector.js +64 -0
  34. package/dist/utils/logging/LogLevel.d.ts +21 -0
  35. package/dist/utils/logging/LogLevel.js +46 -0
  36. package/dist/utils/logging/LoggingConfig.d.ts +68 -0
  37. package/dist/utils/logging/LoggingConfig.js +64 -0
  38. package/dist/utils/logging/LoggingFactory.d.ts +22 -0
  39. package/dist/utils/logging/LoggingFactory.js +61 -0
  40. package/dist/utils/logging/LoggingService.d.ts +235 -0
  41. package/dist/utils/logging/LoggingService.js +385 -0
  42. package/dist/utils/logging/SimpleLoggingService.d.ts +39 -0
  43. package/dist/utils/logging/SimpleLoggingService.js +58 -0
  44. package/dist/utils/logging/advanced/LogLevel.d.ts +21 -0
  45. package/dist/utils/logging/advanced/LogLevel.js +46 -0
  46. package/dist/utils/logging/advanced/LoggingConfig.d.ts +68 -0
  47. package/dist/utils/logging/advanced/LoggingConfig.js +64 -0
  48. package/dist/utils/logging/advanced/LoggingFactory.d.ts +22 -0
  49. package/dist/utils/logging/advanced/LoggingFactory.js +61 -0
  50. package/dist/utils/logging/advanced/LoggingService.d.ts +235 -0
  51. package/dist/utils/logging/advanced/LoggingService.js +385 -0
  52. package/dist/utils/protectedContentManager-simple.d.ts +86 -0
  53. package/dist/utils/protectedContentManager-simple.js +180 -0
  54. package/dist/utils/securityOverlayManager-observer-pause.d.ts +283 -0
  55. package/dist/utils/securityOverlayManager-observer-pause.js +878 -0
  56. package/dist/utils/securityOverlayManager-simple.d.ts +197 -0
  57. package/dist/utils/securityOverlayManager-simple.js +552 -0
  58. package/package.json +1 -1
@@ -0,0 +1,158 @@
1
+ import { FirefoxDevToolsDetector } from "./firefoxDetector";
2
+ export class DebuggerDetector {
3
+ /**
4
+ * Create a new DebuggerDetector
5
+ * @param options Configuration options
6
+ */
7
+ constructor(options = {}) {
8
+ this.worker = null;
9
+ this.firefoxDetector = null;
10
+ this.isChecking = false;
11
+ this.timeoutId = null;
12
+ this.isDevToolsOpen = false;
13
+ this.timeoutDuration = options.timeoutDuration || 500;
14
+ this.onDevToolsChange = options.onDevToolsChange || (() => { });
15
+ this.firefoxDetector = new FirefoxDevToolsDetector();
16
+ this.debugMode = !!options.debugMode;
17
+ this.initWorker();
18
+ if (this.debugMode) {
19
+ console.log("DebuggerDetector: Initialized with timeout:", this.timeoutDuration);
20
+ }
21
+ }
22
+ // Update the worker initialization to handle MIME type issues
23
+ initWorker() {
24
+ try {
25
+ // Create a blob URL for the worker script instead of using a file URL
26
+ // This avoids MIME type issues with server responses
27
+ const workerScript = `
28
+ // Worker script for DevTools detection
29
+ self.onmessage = function(e) {
30
+ if (e.data === "checkDevTools") {
31
+ // Send immediate response (opening heartbeat)
32
+ console.log("DebuggerDetectionWorker: Received checkDevTools message");
33
+ self.postMessage("heartbeatStart");
34
+
35
+ // This will pause execution if DevTools is open
36
+ debugger;
37
+
38
+ // If we reach here without significant delay, DevTools is closed
39
+ self.postMessage("heartbeatEnd");
40
+ }
41
+ };
42
+ `;
43
+ // Create a blob URL from the script
44
+ const blob = new Blob([workerScript], { type: "application/javascript" });
45
+ const workerUrl = URL.createObjectURL(blob);
46
+ // Create the worker using the blob URL
47
+ this.worker = new Worker(workerUrl);
48
+ this.worker.onmessage = (e) => {
49
+ if (e.data === "heartbeatStart") {
50
+ // First heartbeat received, now waiting for second
51
+ if (this.debugMode) {
52
+ console.log("DebuggerDetector: Received opening heartbeat");
53
+ }
54
+ }
55
+ else if (e.data === "heartbeatEnd") {
56
+ // Second heartbeat received, DevTools is closed
57
+ if (this.timeoutId !== null) {
58
+ clearTimeout(this.timeoutId);
59
+ this.timeoutId = null;
60
+ }
61
+ this.isChecking = false;
62
+ // Only trigger callback if state changed
63
+ if (this.isDevToolsOpen) {
64
+ this.isDevToolsOpen = false;
65
+ this.onDevToolsChange(false);
66
+ if (this.debugMode) {
67
+ console.log("DebuggerDetector: DevTools closed");
68
+ }
69
+ }
70
+ }
71
+ };
72
+ this.worker.onerror = (error) => {
73
+ console.error("DebuggerDetector: Worker error:", error);
74
+ this.isChecking = false;
75
+ // Try to recreate the worker
76
+ this.terminateWorker();
77
+ this.initWorker();
78
+ };
79
+ }
80
+ catch (error) {
81
+ console.error("DebuggerDetector: Failed to create worker:", error);
82
+ }
83
+ }
84
+ /**
85
+ * Check if DevTools is open
86
+ * @returns Promise that resolves to true if DevTools is open
87
+ */
88
+ checkDevTools() {
89
+ if (this.isChecking || !this.worker)
90
+ return;
91
+ this.isChecking = true;
92
+ try {
93
+ // Send message to worker
94
+ this.worker.postMessage("checkDevTools");
95
+ // Set timeout for missing second heartbeat
96
+ this.timeoutId = window.setTimeout(() => {
97
+ // If we reach here, the worker is paused at debugger
98
+ // which means DevTools is open
99
+ this.isChecking = false;
100
+ // Only trigger callback if state changed
101
+ if (!this.isDevToolsOpen) {
102
+ this.isDevToolsOpen = true;
103
+ this.onDevToolsChange(true);
104
+ if (this.debugMode) {
105
+ console.log("DebuggerDetector: DevTools opened");
106
+ }
107
+ }
108
+ }, this.timeoutDuration);
109
+ // FIREFOX DETECTION
110
+ /* if (this.firefoxDetector) {
111
+ console.log('Running Firefox detection', this.firefoxDetector.detect());
112
+ const isFirefoxDevToolsOpen = this.firefoxDetector.detect()
113
+ if (isFirefoxDevToolsOpen) {
114
+ this.isDevToolsOpen = true
115
+ this.onDevToolsChange(true)
116
+ }
117
+ } */
118
+ }
119
+ catch (error) {
120
+ console.error("DebuggerDetector: Error checking DevTools:", error);
121
+ this.isChecking = false;
122
+ }
123
+ }
124
+ /**
125
+ * Get the current DevTools state
126
+ * @returns True if DevTools is open
127
+ */
128
+ isOpen() {
129
+ return this.isDevToolsOpen;
130
+ }
131
+ // Update the terminateWorker method to revoke the blob URL
132
+ terminateWorker() {
133
+ if (this.worker) {
134
+ this.worker.terminate();
135
+ this.worker = null;
136
+ }
137
+ }
138
+ /**
139
+ * Clean up resources
140
+ */
141
+ dispose() {
142
+ if (this.timeoutId !== null) {
143
+ clearTimeout(this.timeoutId);
144
+ this.timeoutId = null;
145
+ }
146
+ this.terminateWorker();
147
+ if (this.debugMode) {
148
+ console.log("DebuggerDetector: Disposed");
149
+ }
150
+ }
151
+ /**
152
+ * Set debug mode
153
+ * @param enabled Whether debug mode should be enabled
154
+ */
155
+ setDebugMode(enabled) {
156
+ this.debugMode = enabled;
157
+ }
158
+ }
@@ -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,29 @@
1
+ /**
2
+ * Detect browser environment
3
+ */
4
+ export declare const isBrowser: () => boolean;
5
+ /**
6
+ * Detect mobile device
7
+ */
8
+ export declare const isMobile: () => boolean;
9
+ /**
10
+ * Detect specific browser
11
+ */
12
+ export declare const getBrowser: () => {
13
+ name: string;
14
+ version: string;
15
+ };
16
+ /**
17
+ * Detect operating system
18
+ */
19
+ export declare const getOS: () => {
20
+ name: "mac" | "linux" | "windows" | "unknown";
21
+ };
22
+ /**
23
+ * Check if print is supported
24
+ */
25
+ export declare const isPrintSupported: () => boolean;
26
+ /**
27
+ * Check if beforeprint event is supported
28
+ */
29
+ export declare const isBeforePrintSupported: () => boolean;
@@ -0,0 +1,267 @@
1
+ // FEATURE/ENVIRONMENT DETECTION
2
+ /**
3
+ * Detect browser environment
4
+ */
5
+ export const isBrowser = () => {
6
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
7
+ };
8
+ /**
9
+ * Detect mobile device
10
+ */
11
+ export const isMobile = () => {
12
+ if (!isBrowser())
13
+ return false;
14
+ const userAgent = navigator.userAgent;
15
+ // Standard mobile OS and browser detection
16
+ if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)) {
17
+ return true;
18
+ }
19
+ // Chinese mobile devices
20
+ if (/Huawei|HUAWEI|Honor|HONOR|Xiaomi|MI\/|Redmi|POCO|OPPO|vivo|OnePlus|Realme/i.test(userAgent)) {
21
+ return true;
22
+ }
23
+ // Korean mobile devices
24
+ if (/Samsung|SAMSUNG|LG|Tizen/i.test(userAgent)) {
25
+ return true;
26
+ }
27
+ // Japanese mobile devices
28
+ if (/Sony|SONY|Xperia|Sharp|SHARP|Fujitsu|FOMA|KDDI/i.test(userAgent)) {
29
+ return true;
30
+ }
31
+ // Russian mobile devices
32
+ if (/Yandex.Phone|YandexPhone|BQ-|BQru/i.test(userAgent)) {
33
+ return true;
34
+ }
35
+ // Other mobile platforms
36
+ if (/Windows Phone|WindowsPhone|Lumia|Mobile|Tablet|Phone|WPDesktop|ZuneWP|WP7|wds|Fennec|Firefox OS|KaiOS|KAIOS|Sailfish/i.test(userAgent)) {
37
+ return true;
38
+ }
39
+ // Mobile browser detection
40
+ if (/Mobile|Tablet|Android|Touch/i.test(userAgent) && !/Windows NT|Mac OS X/i.test(userAgent)) {
41
+ return true;
42
+ }
43
+ // Feature detection for touch devices (most mobile devices have touch capability)
44
+ if (isBrowser() && ("ontouchstart" in window || navigator.maxTouchPoints > 0)) {
45
+ // Additional check to avoid false positives on desktops with touch screens
46
+ if (window.innerWidth <= 1024 || /Mobi|Android/i.test(userAgent)) {
47
+ return true;
48
+ }
49
+ }
50
+ return false;
51
+ };
52
+ /**
53
+ * Detect specific browser
54
+ */
55
+ export const getBrowser = () => {
56
+ if (!isBrowser())
57
+ return { name: "unknown", version: "0" };
58
+ const ua = navigator.userAgent;
59
+ let browserName = "unknown";
60
+ let version = "0";
61
+ // Order matters here - we need to check more specific browsers first
62
+ // before falling back to more generic ones
63
+ // --- Chinese Browsers ---
64
+ if (/MicroMessenger|WeChat/.test(ua)) {
65
+ browserName = "wechat";
66
+ const match = ua.match(/MicroMessenger\/(\d+\.\d+)/);
67
+ version = match ? match[1] : "0";
68
+ }
69
+ // QQ Browser
70
+ else if (/QQBrowser/.test(ua)) {
71
+ browserName = "qq";
72
+ const match = ua.match(/QQBrowser\/(\d+\.\d+)/);
73
+ version = match ? match[1] : "0";
74
+ }
75
+ // UC Browser
76
+ else if (/UCBrowser/.test(ua)) {
77
+ browserName = "uc";
78
+ const match = ua.match(/UCBrowser\/(\d+\.\d+)/);
79
+ version = match ? match[1] : "0";
80
+ }
81
+ // Baidu Browser
82
+ else if (/Baidu|BIDUBrowser|baiduboxapp/.test(ua)) {
83
+ browserName = "baidu";
84
+ const match = ua.match(/(?:Baidu|BIDUBOX)(?:Browser)?\/(\d+\.\d+)/);
85
+ version = match ? match[1] : "0";
86
+ }
87
+ // Mi Browser
88
+ else if (/MiuiBrowser/.test(ua)) {
89
+ browserName = "mi";
90
+ const match = ua.match(/MiuiBrowser\/(\d+\.\d+)/);
91
+ version = match ? match[1] : "0";
92
+ }
93
+ // --- Russian Browsers ---
94
+ // Yandex Browser
95
+ else if (/YaBrowser/.test(ua)) {
96
+ browserName = "yandex";
97
+ const match = ua.match(/YaBrowser\/(\d+\.\d+)/);
98
+ version = match ? match[1] : "0";
99
+ }
100
+ // --- Korean Browsers ---
101
+ // Naver Whale
102
+ else if (/Whale/.test(ua)) {
103
+ browserName = "whale";
104
+ const match = ua.match(/Whale\/(\d+\.\d+)/);
105
+ version = match ? match[1] : "0";
106
+ }
107
+ // --- Mobile Browsers ---
108
+ // Samsung Internet
109
+ else if (/SamsungBrowser/.test(ua)) {
110
+ browserName = "samsung";
111
+ const match = ua.match(/SamsungBrowser\/(\d+\.\d+)/);
112
+ version = match ? match[1] : "0";
113
+ }
114
+ // Huawei Browser
115
+ else if (/HuaweiBrowser/.test(ua)) {
116
+ browserName = "huawei";
117
+ const match = ua.match(/HuaweiBrowser\/(\d+\.\d+)/);
118
+ version = match ? match[1] : "0";
119
+ }
120
+ // --- Alternative Browsers ---
121
+ // Vivaldi
122
+ else if (/Vivaldi/.test(ua)) {
123
+ browserName = "vivaldi";
124
+ const match = ua.match(/Vivaldi\/(\d+\.\d+)/);
125
+ version = match ? match[1] : "0";
126
+ }
127
+ // Lunascape
128
+ else if (/Lunascape/.test(ua)) {
129
+ browserName = "lunascape";
130
+ const match = ua.match(/Lunascape[/| ](\d+\.\d+)/);
131
+ version = match ? match[1] : "0";
132
+ }
133
+ // Opera
134
+ else if (/OPR|Opera/.test(ua)) {
135
+ browserName = "opera";
136
+ const match = ua.match(/(?:OPR|Opera)[/| ](\d+\.\d+)/);
137
+ version = match ? match[1] : "0";
138
+ }
139
+ // --- Emulators ---
140
+ // Nox Browser/Emulator
141
+ else if (/Nox/.test(ua)) {
142
+ browserName = "nox";
143
+ const match = ua.match(/Nox\/(\d+\.\d+)/);
144
+ version = match ? match[1] : "0";
145
+ }
146
+ // BlueStacks
147
+ else if (/BlueStacks/.test(ua)) {
148
+ browserName = "bluestacks";
149
+ const match = ua.match(/BlueStacks\/(\d+\.\d+)/);
150
+ version = match ? match[1] : "0";
151
+ }
152
+ // --- Major Browsers (keep these last as fallbacks) ---
153
+ // Edge
154
+ else if (/Edg/.test(ua)) {
155
+ browserName = "edge";
156
+ const match = ua.match(/Edg\/(\d+\.\d+)/);
157
+ version = match ? match[1] : "0";
158
+ }
159
+ // Chrome
160
+ else if (/Chrome/.test(ua) && !/Chromium|Edge|Edg|OPR|Opera/.test(ua)) {
161
+ browserName = "chrome";
162
+ const match = ua.match(/Chrome\/(\d+\.\d+)/);
163
+ version = match ? match[1] : "0";
164
+ }
165
+ // Firefox
166
+ else if (/Firefox/.test(ua)) {
167
+ browserName = "firefox";
168
+ const match = ua.match(/Firefox\/(\d+\.\d+)/);
169
+ version = match ? match[1] : "0";
170
+ }
171
+ // Safari
172
+ else if (/Safari/.test(ua) && !/Chrome/.test(ua)) {
173
+ browserName = "safari";
174
+ const match = ua.match(/Version\/(\d+\.\d+)/);
175
+ version = match ? match[1] : "0";
176
+ }
177
+ // IE
178
+ else if (/Trident|MSIE/.test(ua)) {
179
+ browserName = "ie";
180
+ const match = ua.match(/(?:rv:|MSIE )(\d+\.\d+)/);
181
+ version = match ? match[1] : "0";
182
+ }
183
+ // Chromium-based browsers not caught above
184
+ else if (/Chromium/.test(ua)) {
185
+ browserName = "chromium";
186
+ const match = ua.match(/Chromium\/(\d+\.\d+)/);
187
+ version = match ? match[1] : "0";
188
+ }
189
+ return { name: browserName, version };
190
+ };
191
+ /**
192
+ * Detect operating system
193
+ */
194
+ export const getOS = () => {
195
+ if (!isBrowser())
196
+ return { name: "unknown" };
197
+ const platform = navigator.platform.toLowerCase();
198
+ const userAgent = navigator.userAgent.toLowerCase();
199
+ // macOS and iOS devices
200
+ if (platform.includes("mac") ||
201
+ platform.includes("ipad") ||
202
+ platform.includes("ipod") ||
203
+ platform.includes("iphone") ||
204
+ userAgent.includes("mac") ||
205
+ userAgent.includes("iphone") ||
206
+ userAgent.includes("ipad") ||
207
+ (userAgent.includes("safari") && !userAgent.includes("chrome") && !userAgent.includes("android"))) {
208
+ return { name: "mac" };
209
+ }
210
+ // Windows detection
211
+ else if (platform.includes("win") || userAgent.includes("win") || userAgent.includes("windows nt")) {
212
+ return { name: "windows" };
213
+ }
214
+ // Linux and Linux-based OS detection
215
+ else if (
216
+ // Standard Linux
217
+ platform.includes("linux") ||
218
+ userAgent.includes("linux") ||
219
+ // Android (Linux-based)
220
+ userAgent.includes("android") ||
221
+ // Chinese OS (most are Linux-based)
222
+ userAgent.includes("harmonyos") ||
223
+ userAgent.includes("deepin") ||
224
+ userAgent.includes("uos") ||
225
+ userAgent.includes("cos") ||
226
+ // Russian Linux distributions
227
+ userAgent.includes("astra linux") ||
228
+ userAgent.includes("alt linux") ||
229
+ userAgent.includes("rosa") ||
230
+ // Korean OS
231
+ userAgent.includes("tizen") ||
232
+ userAgent.includes("gooroom") ||
233
+ // Other Linux-based OS
234
+ userAgent.includes("ubuntu") ||
235
+ userAgent.includes("debian") ||
236
+ userAgent.includes("fedora") ||
237
+ userAgent.includes("red hat") ||
238
+ userAgent.includes("suse") ||
239
+ userAgent.includes("mint") ||
240
+ // Chrome OS (Linux-based)
241
+ userAgent.includes("cros") ||
242
+ userAgent.includes("chromium os") ||
243
+ userAgent.includes("chrome os") ||
244
+ // BSD variants (Unix-like, grouped with Linux for simplicity)
245
+ userAgent.includes("freebsd") ||
246
+ userAgent.includes("openbsd") ||
247
+ userAgent.includes("netbsd")) {
248
+ return { name: "linux" };
249
+ }
250
+ // Fallback for undetected OS
251
+ return { name: "unknown" };
252
+ };
253
+ /**
254
+ * Check if print is supported
255
+ */
256
+ export const isPrintSupported = () => {
257
+ return isBrowser() && typeof window.print === 'function';
258
+ };
259
+ /**
260
+ * Check if beforeprint event is supported
261
+ */
262
+ export const isBeforePrintSupported = () => {
263
+ if (!isBrowser())
264
+ return false;
265
+ const mediaQueryList = window.matchMedia('print');
266
+ return !!mediaQueryList.addListener || 'onbeforeprint' in window;
267
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Worker script for DevTools detection
3
+ * This worker helps detect DevTools by using the debugger statement
4
+ * in a separate thread, which won't block the main UI thread
5
+ */
6
+ export type DebuggerDetectionWorker = typeof self;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Worker script for DevTools detection
3
+ * This worker helps detect DevTools by using the debugger statement
4
+ * in a separate thread, which won't block the main UI thread
5
+ */
6
+ // Set up message handler
7
+ self.onmessage = (e) => {
8
+ if (e.data === "checkDevTools") {
9
+ // Send immediate response (opening heartbeat)
10
+ console.log("DebuggerDetectionWorker: Received checkDevTools message");
11
+ self.postMessage("heartbeatStart");
12
+ // This will pause execution if DevTools is open
13
+ // We use a function to make it harder to bypass
14
+ function triggerDebugger() {
15
+ // eslint-disable-next-line no-debugger
16
+ debugger;
17
+ }
18
+ // Call the function to trigger the debugger
19
+ triggerDebugger();
20
+ // If we reach here without significant delay, DevTools is closed
21
+ self.postMessage("heartbeatEnd");
22
+ }
23
+ };
24
+ export {};
@@ -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,21 @@
1
+ /**
2
+ * Enum defining log severity levels
3
+ */
4
+ export declare enum LogLevel {
5
+ ERROR = 0,// Always shown, represents errors that need immediate attention
6
+ WARN = 1,// Important issues that don't break functionality but need attention
7
+ INFO = 2,// General information about application flow
8
+ DEBUG = 3,// Detailed information useful for debugging
9
+ TRACE = 4,// Very detailed information, including loop iterations, function entries/exits
10
+ VERBOSE = 5
11
+ }
12
+ /**
13
+ * Map of log level names to their enum values
14
+ */
15
+ export declare const LOG_LEVEL_MAP: Record<string, LogLevel>;
16
+ /**
17
+ * Get the name of a log level
18
+ * @param level The log level
19
+ * @returns The name of the log level
20
+ */
21
+ export declare function getLogLevelName(level: LogLevel): string;