@tindalabs/shield 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +357 -0
- package/dist/assess.d.ts +16 -0
- package/dist/assess.js +220 -0
- package/dist/config/default-extensions-config.json +103 -0
- package/dist/core/ContentProtector.d.ts +63 -0
- package/dist/core/ContentProtector.js +281 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +2 -0
- package/dist/core/mediator/ContentProtectionMediator.d.ts +86 -0
- package/dist/core/mediator/ContentProtectionMediator.js +238 -0
- package/dist/core/mediator/eventDataTypes.d.ts +112 -0
- package/dist/core/mediator/eventDataTypes.js +23 -0
- package/dist/core/mediator/handlers/abstractEventHandler.d.ts +41 -0
- package/dist/core/mediator/handlers/abstractEventHandler.js +59 -0
- package/dist/core/mediator/handlers/devToolsEventHandler.d.ts +9 -0
- package/dist/core/mediator/handlers/devToolsEventHandler.js +95 -0
- package/dist/core/mediator/handlers/eventHandlerRegistry.d.ts +9 -0
- package/dist/core/mediator/handlers/eventHandlerRegistry.js +34 -0
- package/dist/core/mediator/handlers/extensionEventHandlers.d.ts +40 -0
- package/dist/core/mediator/handlers/extensionEventHandlers.js +140 -0
- package/dist/core/mediator/handlers/iFrameEventHandlers.d.ts +27 -0
- package/dist/core/mediator/handlers/iFrameEventHandlers.js +93 -0
- package/dist/core/mediator/handlers/screenShotEventHandlers.d.ts +34 -0
- package/dist/core/mediator/handlers/screenShotEventHandlers.js +111 -0
- package/dist/core/mediator/protection-event.d.ts +77 -0
- package/dist/core/mediator/protection-event.js +32 -0
- package/dist/core/mediator/types.d.ts +105 -0
- package/dist/core/mediator/types.js +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +7 -0
- package/dist/otel.d.ts +24 -0
- package/dist/otel.js +83 -0
- package/dist/policy.d.ts +98 -0
- package/dist/policy.js +97 -0
- package/dist/strategies/AbstractStrategy.d.ts +124 -0
- package/dist/strategies/AbstractStrategy.js +256 -0
- package/dist/strategies/ClipboardStrategy.d.ts +67 -0
- package/dist/strategies/ClipboardStrategy.js +291 -0
- package/dist/strategies/ContextMenuStrategy.d.ts +60 -0
- package/dist/strategies/ContextMenuStrategy.js +454 -0
- package/dist/strategies/DevToolsStrategy.d.ts +55 -0
- package/dist/strategies/DevToolsStrategy.js +314 -0
- package/dist/strategies/ExtensionStrategy.d.ts +66 -0
- package/dist/strategies/ExtensionStrategy.js +486 -0
- package/dist/strategies/IFrameStrategy.d.ts +49 -0
- package/dist/strategies/IFrameStrategy.js +255 -0
- package/dist/strategies/KeyboardStrategy.d.ts +35 -0
- package/dist/strategies/KeyboardStrategy.js +130 -0
- package/dist/strategies/PrintStrategy.d.ts +47 -0
- package/dist/strategies/PrintStrategy.js +201 -0
- package/dist/strategies/ScreenshotStrategy.d.ts +90 -0
- package/dist/strategies/ScreenshotStrategy.js +502 -0
- package/dist/strategies/SelectionStrategy.d.ts +49 -0
- package/dist/strategies/SelectionStrategy.js +216 -0
- package/dist/strategies/WatermarkStrategy.d.ts +56 -0
- package/dist/strategies/WatermarkStrategy.js +287 -0
- package/dist/strategies/index.d.ts +10 -0
- package/dist/strategies/index.js +11 -0
- package/dist/types/assessment.d.ts +62 -0
- package/dist/types/assessment.js +1 -0
- package/dist/types/index.d.ts +278 -0
- package/dist/types/index.js +17 -0
- package/dist/utils/DOMObserver.d.ts +68 -0
- package/dist/utils/DOMObserver.js +134 -0
- package/dist/utils/base/LoggableComponent.d.ts +44 -0
- package/dist/utils/base/LoggableComponent.js +56 -0
- package/dist/utils/detectors/AbstractDevToolsDetector.d.ts +98 -0
- package/dist/utils/detectors/AbstractDevToolsDetector.js +127 -0
- package/dist/utils/detectors/dateToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/dateToStringDetector.js +96 -0
- package/dist/utils/detectors/debugLibDetector.d.ts +64 -0
- package/dist/utils/detectors/debugLibDetector.js +195 -0
- package/dist/utils/detectors/debuggerDetector.d.ts +51 -0
- package/dist/utils/detectors/debuggerDetector.js +211 -0
- package/dist/utils/detectors/defineGetterDetector.d.ts +48 -0
- package/dist/utils/detectors/defineGetterDetector.js +150 -0
- package/dist/utils/detectors/detectorInterface.d.ts +36 -0
- package/dist/utils/detectors/detectorInterface.js +1 -0
- package/dist/utils/detectors/devToolsDetectorManager.d.ts +88 -0
- package/dist/utils/detectors/devToolsDetectorManager.js +243 -0
- package/dist/utils/detectors/funcToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/funcToStringDetector.js +90 -0
- package/dist/utils/detectors/regToStringDetector.d.ts +43 -0
- package/dist/utils/detectors/regToStringDetector.js +129 -0
- package/dist/utils/detectors/sizeDetector.d.ts +54 -0
- package/dist/utils/detectors/sizeDetector.js +134 -0
- package/dist/utils/detectors/timingDetector.d.ts +55 -0
- package/dist/utils/detectors/timingDetector.js +143 -0
- package/dist/utils/dom.d.ts +20 -0
- package/dist/utils/dom.js +83 -0
- package/dist/utils/environment.d.ts +29 -0
- package/dist/utils/environment.js +267 -0
- package/dist/utils/eventManager.d.ts +162 -0
- package/dist/utils/eventManager.js +548 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/intervalManager.d.ts +91 -0
- package/dist/utils/intervalManager.js +221 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.d.ts +41 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.js +135 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcuts.d.ts +18 -0
- package/dist/utils/keyboardShortcutManager/keyboardShortcuts.js +195 -0
- package/dist/utils/logging/simple/Loggable.d.ts +33 -0
- package/dist/utils/logging/simple/Loggable.js +1 -0
- package/dist/utils/logging/simple/LoggingDelegate.d.ts +42 -0
- package/dist/utils/logging/simple/LoggingDelegate.js +53 -0
- package/dist/utils/logging/simple/SimpleLoggingService.d.ts +39 -0
- package/dist/utils/logging/simple/SimpleLoggingService.js +58 -0
- package/dist/utils/orientation.d.ts +15 -0
- package/dist/utils/orientation.js +32 -0
- package/dist/utils/protectedContentManager.d.ts +155 -0
- package/dist/utils/protectedContentManager.js +424 -0
- package/dist/utils/securityOverlayManager.d.ts +253 -0
- package/dist/utils/securityOverlayManager.js +786 -0
- package/dist/utils/timeoutManager.d.ts +50 -0
- package/dist/utils/timeoutManager.js +113 -0
- package/package.json +61 -0
|
@@ -0,0 +1,243 @@
|
|
|
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 { AbstractDevToolsDetector } from "./AbstractDevToolsDetector";
|
|
11
|
+
/**
|
|
12
|
+
* Manager class that coordinates multiple DevTools detection methods
|
|
13
|
+
* **Chrome, Edge, Opera**: Primarily uses `DebuggerDetector` with `DefineGetterDetector` as backup
|
|
14
|
+
* **Firefox**: Uses `TimingDetector` and `RegToStringDetector` for reliable detection
|
|
15
|
+
* **Safari**: Primarily uses `DateToStringDetector` with `DefineGetterDetector` as backup
|
|
16
|
+
* **QQ Browser**: Uses `RegToStringDetector` which works particularly well for this browser
|
|
17
|
+
* **Mobile Browsers**: Always includes `DebugLibDetector` to catch third-party debugging tools
|
|
18
|
+
*/
|
|
19
|
+
export class DevToolsDetectorManager extends AbstractDevToolsDetector {
|
|
20
|
+
/**
|
|
21
|
+
* Create a new DevToolsDetectorManager
|
|
22
|
+
* @param options Configuration options
|
|
23
|
+
*/
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
super('DevToolsDetectorManager', { debugMode: !!options.debugMode });
|
|
26
|
+
this.detectors = new Map();
|
|
27
|
+
this.activeDetectors = [];
|
|
28
|
+
this.isInitialCheckDone = false;
|
|
29
|
+
this.initialCheckTimeout = null;
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
|
+
this.onDevToolsChange = options.onDevToolsChange || ((isOpen) => { });
|
|
32
|
+
this.browserInfo = getBrowser();
|
|
33
|
+
this.isMobileDevice = isMobile();
|
|
34
|
+
this.delayInitialCheck = options.delayInitialCheck !== false; // Default to true
|
|
35
|
+
this.initialCheckDelay = options.initialCheckDelay || 1000;
|
|
36
|
+
// Initialize all available detectors
|
|
37
|
+
this.initializeAllDetectors(options);
|
|
38
|
+
// Select appropriate detectors based on browser
|
|
39
|
+
this.selectActiveDetectors(options.enabledDetectors);
|
|
40
|
+
this.logger.log("Initialized for browser:", this.browserInfo.name);
|
|
41
|
+
this.logger.log("Mobile device:", this.isMobileDevice);
|
|
42
|
+
this.logger.log("Active detectors:", Array.from(this.activeDetectors).map((d) => d.constructor.name));
|
|
43
|
+
// Schedule initial check with delay to avoid false positives during page load
|
|
44
|
+
if (this.delayInitialCheck) {
|
|
45
|
+
this.logger.log(`Delaying initial check by ${this.initialCheckDelay}ms`);
|
|
46
|
+
this.initialCheckTimeout = window.setTimeout(() => {
|
|
47
|
+
this.isInitialCheckDone = true;
|
|
48
|
+
this.checkDevTools();
|
|
49
|
+
this.initialCheckTimeout = null;
|
|
50
|
+
this.logger.log("Initial check completed");
|
|
51
|
+
}, this.initialCheckDelay);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.isInitialCheckDone = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize all available detectors
|
|
59
|
+
*/
|
|
60
|
+
initializeAllDetectors(options) {
|
|
61
|
+
const commonOptions = {
|
|
62
|
+
onDevToolsChange: this.handleDetectorChange.bind(this),
|
|
63
|
+
debugMode: this.logger.isDebugEnabled(),
|
|
64
|
+
};
|
|
65
|
+
// Initialize all detectors but don't activate them yet
|
|
66
|
+
this.detectors.set("debugger", new DebuggerDetector({
|
|
67
|
+
...commonOptions,
|
|
68
|
+
timeoutDuration: options.debuggerTimeoutDuration || 50,
|
|
69
|
+
}));
|
|
70
|
+
this.detectors.set("timing", new TimingDetector({
|
|
71
|
+
...commonOptions,
|
|
72
|
+
thresholdMultiplier: 3, // Slightly higher for better reliability
|
|
73
|
+
}));
|
|
74
|
+
if (DateToStringDetector.isSupported()) {
|
|
75
|
+
this.detectors.set("dateToString", new DateToStringDetector({
|
|
76
|
+
...commonOptions,
|
|
77
|
+
threshold: 2,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
if (FuncToStringDetector.isSupported()) {
|
|
81
|
+
this.detectors.set("funcToString", new FuncToStringDetector({
|
|
82
|
+
...commonOptions,
|
|
83
|
+
threshold: 2,
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
if (RegToStringDetector.isSupported()) {
|
|
87
|
+
this.detectors.set("regToString", new RegToStringDetector({
|
|
88
|
+
...commonOptions,
|
|
89
|
+
timeThreshold: 100,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
this.detectors.set("defineGetter", new DefineGetterDetector({
|
|
93
|
+
...commonOptions,
|
|
94
|
+
checkInterval: options.checkInterval || 1000,
|
|
95
|
+
}));
|
|
96
|
+
this.detectors.set("debugLib", new DebugLibDetector({
|
|
97
|
+
...commonOptions,
|
|
98
|
+
checkInterval: options.checkInterval || 1000,
|
|
99
|
+
}));
|
|
100
|
+
if (SizeDetector.isSupported()) {
|
|
101
|
+
this.detectors.set("size", new SizeDetector({
|
|
102
|
+
...commonOptions,
|
|
103
|
+
widthThreshold: 200,
|
|
104
|
+
heightThreshold: 300,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Select which detectors to activate based on browser
|
|
110
|
+
*/
|
|
111
|
+
selectActiveDetectors(userEnabledDetectors) {
|
|
112
|
+
// If user specified detectors, use those
|
|
113
|
+
if (userEnabledDetectors && userEnabledDetectors.length > 0) {
|
|
114
|
+
this.activeDetectors = userEnabledDetectors
|
|
115
|
+
.filter((type) => this.detectors.has(type))
|
|
116
|
+
.map((type) => this.detectors.get(type))
|
|
117
|
+
.filter(Boolean);
|
|
118
|
+
this.logger.log("Using user-specified detectors");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Get browser-specific detectors
|
|
122
|
+
let detectorTypes = DevToolsDetectorManager.BROWSER_DETECTOR_MAP[this.browserInfo.name] ||
|
|
123
|
+
DevToolsDetectorManager.BROWSER_DETECTOR_MAP.unknown;
|
|
124
|
+
// Apply mobile overrides if on mobile
|
|
125
|
+
if (this.isMobileDevice) {
|
|
126
|
+
const mobileDetectorTypes = DevToolsDetectorManager.MOBILE_DETECTOR_MAP[this.browserInfo.name] ||
|
|
127
|
+
DevToolsDetectorManager.MOBILE_DETECTOR_MAP.default;
|
|
128
|
+
// Combine with browser-specific detectors, prioritizing mobile ones
|
|
129
|
+
detectorTypes = [...mobileDetectorTypes, ...detectorTypes.filter((type) => !mobileDetectorTypes.includes(type))];
|
|
130
|
+
}
|
|
131
|
+
// Activate the selected detectors
|
|
132
|
+
this.activeDetectors = detectorTypes
|
|
133
|
+
.filter((type) => this.detectors.has(type))
|
|
134
|
+
.map((type) => this.detectors.get(type))
|
|
135
|
+
.filter(Boolean);
|
|
136
|
+
// Always start the continuous detectors
|
|
137
|
+
const continuousDetector = this.detectors.get("debugLib");
|
|
138
|
+
if (continuousDetector) {
|
|
139
|
+
continuousDetector.startDetection();
|
|
140
|
+
}
|
|
141
|
+
this.logger.log("Selected detectors for", this.browserInfo.name, ":", detectorTypes);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Handle state change from any detector
|
|
145
|
+
*/
|
|
146
|
+
handleDetectorChange(isOpen) {
|
|
147
|
+
// Skip state changes until initial check is done
|
|
148
|
+
if (!this.isInitialCheckDone) {
|
|
149
|
+
this.logger.log("Ignoring state change before initial check");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.updateDevToolsState(isOpen);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Check if DevTools is open using all active detectors
|
|
156
|
+
*/
|
|
157
|
+
checkDevTools() {
|
|
158
|
+
// Skip checks until initial check is done
|
|
159
|
+
if (!this.isInitialCheckDone) {
|
|
160
|
+
this.logger.log("Skipping check before initial delay");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
for (const detector of this.activeDetectors) {
|
|
164
|
+
detector.checkDevTools();
|
|
165
|
+
// If any detector reports DevTools as open, we can stop checking
|
|
166
|
+
if (detector.isOpen()) {
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get the current DevTools state
|
|
173
|
+
* @returns True if DevTools is open
|
|
174
|
+
*/
|
|
175
|
+
isOpen() {
|
|
176
|
+
return this.isDevToolsOpen;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Clean up resources for all detectors
|
|
180
|
+
*/
|
|
181
|
+
dispose() {
|
|
182
|
+
// Clear initial check timeout if it exists
|
|
183
|
+
if (this.initialCheckTimeout !== null) {
|
|
184
|
+
clearTimeout(this.initialCheckTimeout);
|
|
185
|
+
this.initialCheckTimeout = null;
|
|
186
|
+
}
|
|
187
|
+
for (const detector of this.detectors.values()) {
|
|
188
|
+
detector.dispose();
|
|
189
|
+
}
|
|
190
|
+
this.detectors.clear();
|
|
191
|
+
this.activeDetectors = [];
|
|
192
|
+
this.logger.log("Disposed all detectors");
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Set debug mode for all detectors
|
|
196
|
+
* @param enabled Whether debug mode should be enabled
|
|
197
|
+
*/
|
|
198
|
+
setDebugMode(enabled) {
|
|
199
|
+
this.logger.setDebugMode(enabled);
|
|
200
|
+
for (const detector of this.detectors.values()) {
|
|
201
|
+
detector.setDebugMode(enabled);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Browser-specific detector mapping
|
|
206
|
+
DevToolsDetectorManager.BROWSER_DETECTOR_MAP = {
|
|
207
|
+
// Chromium-based browsers
|
|
208
|
+
chrome: ["debugger", "defineGetter"],
|
|
209
|
+
edge: ["debugger", "defineGetter"],
|
|
210
|
+
chromium: ["debugger", "defineGetter"],
|
|
211
|
+
opera: ["debugger", "defineGetter"],
|
|
212
|
+
vivaldi: ["debugger", "defineGetter"],
|
|
213
|
+
// Firefox and derivatives
|
|
214
|
+
firefox: ["timing", "regToString"],
|
|
215
|
+
// Safari
|
|
216
|
+
safari: ["dateToString", "defineGetter"],
|
|
217
|
+
// Chinese browsers
|
|
218
|
+
qq: ["regToString", "debugger"],
|
|
219
|
+
uc: ["debugger", "defineGetter"],
|
|
220
|
+
baidu: ["debugger", "defineGetter"],
|
|
221
|
+
mi: ["debugger", "defineGetter"],
|
|
222
|
+
wechat: ["debugger", "defineGetter"],
|
|
223
|
+
// Korean browsers
|
|
224
|
+
samsung: ["debugger", "defineGetter"],
|
|
225
|
+
whale: ["debugger", "defineGetter"],
|
|
226
|
+
// Russian browsers
|
|
227
|
+
yandex: ["debugger", "defineGetter"],
|
|
228
|
+
// Japanese browsers (typically WebKit/Blink based)
|
|
229
|
+
// Fallback for unknown browsers
|
|
230
|
+
unknown: ["debugger", "defineGetter", "dateToString"],
|
|
231
|
+
};
|
|
232
|
+
// Mobile-specific overrides
|
|
233
|
+
DevToolsDetectorManager.MOBILE_DETECTOR_MAP = {
|
|
234
|
+
// iOS Safari needs special handling
|
|
235
|
+
safari: ["dateToString", "debugLib"],
|
|
236
|
+
// Android Chrome/WebView
|
|
237
|
+
chrome: ["debugger", "debugLib"],
|
|
238
|
+
// UC and QQ browsers on mobile
|
|
239
|
+
uc: ["debugger", "debugLib"],
|
|
240
|
+
qq: ["regToString", "debugLib"],
|
|
241
|
+
// Default for other mobile browsers
|
|
242
|
+
default: ["debugger", "debugLib"],
|
|
243
|
+
};
|
|
@@ -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
|
+
}
|