@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,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extensions": {
|
|
3
|
+
"evernote-web-clipper": {
|
|
4
|
+
"name": "Evernote Web Clipper",
|
|
5
|
+
"description": "Clips web content to Evernote",
|
|
6
|
+
"risk": "high",
|
|
7
|
+
"detectionMethods": {
|
|
8
|
+
"domSelectors": [".evernote-clipper", "#evernoteClipper", "#evernoteClipperToolsMain"],
|
|
9
|
+
"jsSignatures": ["EvernoteClipper", "ENClipper"]
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"onenote-clipper": {
|
|
13
|
+
"name": "OneNote Web Clipper",
|
|
14
|
+
"description": "Clips web content to OneNote",
|
|
15
|
+
"risk": "high",
|
|
16
|
+
"detectionMethods": {
|
|
17
|
+
"domSelectors": [".onenote-clipper", "#oneNoteClipper", "#oneNoteWebClipper"],
|
|
18
|
+
"jsSignatures": ["OneNoteClipper", "OneNoteWebClipper"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"notion-web-clipper": {
|
|
22
|
+
"name": "Notion Web Clipper",
|
|
23
|
+
"description": "Clips web content to Notion",
|
|
24
|
+
"risk": "high",
|
|
25
|
+
"detectionMethods": {
|
|
26
|
+
"domSelectors": [".notion-clipper", "#notionClipper"],
|
|
27
|
+
"jsSignatures": ["notionClientAPI"]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"pocket": {
|
|
31
|
+
"name": "Pocket",
|
|
32
|
+
"description": "Saves content for later reading",
|
|
33
|
+
"risk": "medium",
|
|
34
|
+
"detectionMethods": {
|
|
35
|
+
"domSelectors": [".pocket-button", "#pocket-button-container"],
|
|
36
|
+
"jsSignatures": ["Pocket", "PocketButtonManager"]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"instapaper": {
|
|
40
|
+
"name": "Instapaper",
|
|
41
|
+
"description": "Saves content for later reading",
|
|
42
|
+
"risk": "medium",
|
|
43
|
+
"detectionMethods": {
|
|
44
|
+
"domSelectors": [".instapaper-button", "#instapaper-button"],
|
|
45
|
+
"jsSignatures": ["Instapaper"]
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"readwise": {
|
|
49
|
+
"name": "Readwise",
|
|
50
|
+
"description": "Saves highlights and annotations",
|
|
51
|
+
"risk": "medium",
|
|
52
|
+
"detectionMethods": {
|
|
53
|
+
"domSelectors": [".readwise-button", "#readwise-highlights"],
|
|
54
|
+
"jsSignatures": ["readwiseAPI", "readwiseHighlighter"]
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"singlefile": {
|
|
58
|
+
"name": "SingleFile",
|
|
59
|
+
"description": "Saves complete web pages",
|
|
60
|
+
"risk": "high",
|
|
61
|
+
"detectionMethods": {
|
|
62
|
+
"domSelectors": [".singlefile-button", "#singlefile-ui"],
|
|
63
|
+
"jsSignatures": ["singlefile", "SingleFile"]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"save-page-we": {
|
|
67
|
+
"name": "Save Page WE",
|
|
68
|
+
"description": "Saves complete web pages",
|
|
69
|
+
"risk": "high",
|
|
70
|
+
"detectionMethods": {
|
|
71
|
+
"domSelectors": [".save-page-we"],
|
|
72
|
+
"jsSignatures": ["savePageWE"]
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"fireshot": {
|
|
76
|
+
"name": "Fireshot",
|
|
77
|
+
"description": "Takes screenshots of web pages",
|
|
78
|
+
"risk": "high",
|
|
79
|
+
"detectionMethods": {
|
|
80
|
+
"domSelectors": [".fireshot-ui", "#fireshot-container"],
|
|
81
|
+
"jsSignatures": ["FireShot", "FSCapture"]
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"gofullpage": {
|
|
85
|
+
"name": "GoFullPage",
|
|
86
|
+
"description": "Takes full page screenshots",
|
|
87
|
+
"risk": "high",
|
|
88
|
+
"detectionMethods": {
|
|
89
|
+
"domSelectors": [".gofullpage-ui"],
|
|
90
|
+
"jsSignatures": ["GoFullPage", "FullPageScreenshot"]
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"web-scraper": {
|
|
94
|
+
"name": "Web Scraper",
|
|
95
|
+
"description": "Extracts data from web pages",
|
|
96
|
+
"risk": "high",
|
|
97
|
+
"detectionMethods": {
|
|
98
|
+
"domSelectors": [".web-scraper-selection", "#web-scraper-selector-overlay"],
|
|
99
|
+
"jsSignatures": ["WebScraper", "SelectorGraph"]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ContentProtectionOptions, ProtectionStrategy } from "../types";
|
|
2
|
+
import { LoggableComponent } from "../utils/base/LoggableComponent";
|
|
3
|
+
/**
|
|
4
|
+
* Main class for protecting content from copying, screenshotting, and other extraction methods
|
|
5
|
+
* Coordinates multiple protection strategies and manages their lifecycle
|
|
6
|
+
*/
|
|
7
|
+
export declare class ContentProtector extends LoggableComponent {
|
|
8
|
+
private options;
|
|
9
|
+
private strategies;
|
|
10
|
+
private isActive;
|
|
11
|
+
private overlayManager;
|
|
12
|
+
private protectedContentManager;
|
|
13
|
+
private mediator;
|
|
14
|
+
private handlerRegistry;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new ContentProtector instance
|
|
17
|
+
* @param options Configuration options for content protection
|
|
18
|
+
*/
|
|
19
|
+
constructor(options?: ContentProtectionOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Initialize protection strategies based on configuration options
|
|
22
|
+
* Creates strategy instances and adds them to the strategies map
|
|
23
|
+
*/
|
|
24
|
+
private initializeStrategies;
|
|
25
|
+
/**
|
|
26
|
+
* Apply all protection strategies
|
|
27
|
+
* Activates each strategy to protect content
|
|
28
|
+
*/
|
|
29
|
+
protect(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Remove all protection strategies
|
|
32
|
+
* Deactivates each strategy and cleans up resources
|
|
33
|
+
*/
|
|
34
|
+
unprotect(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Update protection options
|
|
37
|
+
* Removes existing protection, updates options, and reapplies if needed
|
|
38
|
+
* @param options New options to apply
|
|
39
|
+
*/
|
|
40
|
+
updateOptions(options: Partial<ContentProtectionOptions>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Check if protection is currently active
|
|
43
|
+
* @returns True if protection is active
|
|
44
|
+
*/
|
|
45
|
+
isProtected(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Get a specific strategy by name
|
|
48
|
+
* @param name Strategy name
|
|
49
|
+
* @returns The strategy instance or undefined if not found
|
|
50
|
+
*/
|
|
51
|
+
getStrategy(name: string): ProtectionStrategy | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Check if a specific strategy is active
|
|
54
|
+
* @param name Strategy name
|
|
55
|
+
* @returns True if the strategy exists
|
|
56
|
+
*/
|
|
57
|
+
hasStrategy(name: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Clean up and dispose of all resources
|
|
60
|
+
* Removes protection and cleans up global managers
|
|
61
|
+
*/
|
|
62
|
+
dispose(): void;
|
|
63
|
+
}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { KeyboardStrategy, PrintStrategy, ContextMenuStrategy, WatermarkStrategy, SelectionStrategy, DevToolsStrategy, ScreenshotStrategy, BrowserExtensionDetectionStrategy, FrameEmbeddingProtectionStrategy, } from "../strategies";
|
|
2
|
+
import { ClipboardStrategy } from "../strategies/ClipboardStrategy";
|
|
3
|
+
import { SecurityOverlayManager } from "../utils/securityOverlayManager";
|
|
4
|
+
import { intervalManager } from "../utils/intervalManager";
|
|
5
|
+
import { eventManager } from "../utils/eventManager";
|
|
6
|
+
import { ContentProtectionMediator } from "./mediator/ContentProtectionMediator";
|
|
7
|
+
import { HandlerRegistry } from "./mediator/handlers/eventHandlerRegistry";
|
|
8
|
+
import { ProtectedContentManager } from "../utils/protectedContentManager";
|
|
9
|
+
import { LoggableComponent } from "../utils/base/LoggableComponent";
|
|
10
|
+
/**
|
|
11
|
+
* Main class for protecting content from copying, screenshotting, and other extraction methods
|
|
12
|
+
* Coordinates multiple protection strategies and manages their lifecycle
|
|
13
|
+
*/
|
|
14
|
+
export class ContentProtector extends LoggableComponent {
|
|
15
|
+
/**
|
|
16
|
+
* Create a new ContentProtector instance
|
|
17
|
+
* @param options Configuration options for content protection
|
|
18
|
+
*/
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
// Define default options
|
|
21
|
+
const defaults = {
|
|
22
|
+
preventKeyboardShortcuts: true,
|
|
23
|
+
preventContextMenu: true,
|
|
24
|
+
preventPrinting: true,
|
|
25
|
+
preventSelection: true,
|
|
26
|
+
preventScreenshots: true,
|
|
27
|
+
enableWatermark: false,
|
|
28
|
+
preventDevTools: false,
|
|
29
|
+
preventExtensions: false,
|
|
30
|
+
preventEmbedding: false,
|
|
31
|
+
preventClipboard: false,
|
|
32
|
+
debugMode: false,
|
|
33
|
+
};
|
|
34
|
+
// Merge defaults with provided options. We compute this before super()
|
|
35
|
+
// because super() needs the resolved debugMode flag.
|
|
36
|
+
const mergedOptions = { ...defaults, ...options };
|
|
37
|
+
super("ContentProtector", !!mergedOptions.debugMode);
|
|
38
|
+
this.strategies = new Map();
|
|
39
|
+
this.isActive = false;
|
|
40
|
+
this.options = mergedOptions;
|
|
41
|
+
// Normalize and set targetElement if not provided
|
|
42
|
+
const resolveTargetElement = (t) => {
|
|
43
|
+
if (typeof document === "undefined")
|
|
44
|
+
return null;
|
|
45
|
+
// Already an element
|
|
46
|
+
if (t instanceof HTMLElement)
|
|
47
|
+
return t;
|
|
48
|
+
// CSS selector string
|
|
49
|
+
if (typeof t === "string") {
|
|
50
|
+
try {
|
|
51
|
+
const el = document.querySelector(t);
|
|
52
|
+
return el instanceof HTMLElement ? el : null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Vue 3 ref ({ value: HTMLElement }) or Vue component ($el) or DOM-like node
|
|
59
|
+
if (t && typeof t === "object") {
|
|
60
|
+
const maybe = t;
|
|
61
|
+
if (maybe.value instanceof HTMLElement)
|
|
62
|
+
return maybe.value;
|
|
63
|
+
if (maybe.$el instanceof HTMLElement)
|
|
64
|
+
return maybe.$el;
|
|
65
|
+
if (maybe.nodeType === 1 && typeof maybe.nodeName === "string")
|
|
66
|
+
return t;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
// Normalize provided targetElement, or default to document.body
|
|
71
|
+
const normalizedTarget = resolveTargetElement(this.options.targetElement);
|
|
72
|
+
if (normalizedTarget) {
|
|
73
|
+
this.options.targetElement = normalizedTarget;
|
|
74
|
+
}
|
|
75
|
+
else if (!this.options.targetElement && typeof document !== "undefined") {
|
|
76
|
+
this.options.targetElement = document.body;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// If user provided something invalid, clear it to avoid passing non-DOM objects to strategies
|
|
80
|
+
if (this.options.targetElement) {
|
|
81
|
+
this.warn("Provided targetElement is not a DOM element - falling back to document.body if available");
|
|
82
|
+
if (typeof document !== "undefined")
|
|
83
|
+
this.options.targetElement = document.body;
|
|
84
|
+
else
|
|
85
|
+
this.options.targetElement = undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Initialize the mediator
|
|
89
|
+
this.mediator = new ContentProtectionMediator(this.options.debugMode);
|
|
90
|
+
// Initialize the handler registry
|
|
91
|
+
this.handlerRegistry = new HandlerRegistry(this.mediator, this.options.debugMode);
|
|
92
|
+
// Initialize overlay manager
|
|
93
|
+
this.overlayManager = new SecurityOverlayManager(this.options.debugMode);
|
|
94
|
+
this.overlayManager.setMediator(this.mediator);
|
|
95
|
+
// Initialize protected content manager
|
|
96
|
+
this.protectedContentManager = new ProtectedContentManager(this.options.targetElement, this.options.debugMode);
|
|
97
|
+
this.protectedContentManager.setMediator(this.mediator);
|
|
98
|
+
// Wire content visibility callbacks from customHandlers (useful for Vue re-mounting)
|
|
99
|
+
if (this.options.customHandlers) {
|
|
100
|
+
this.protectedContentManager.setContentCallbacks(this.options.customHandlers.onContentHidden, this.options.customHandlers.onContentRestored);
|
|
101
|
+
}
|
|
102
|
+
// Configure debug mode for managers
|
|
103
|
+
if (this.options.debugMode) {
|
|
104
|
+
this.logger.log("Initialized with options", this.options);
|
|
105
|
+
// Enable debug mode for the event manager
|
|
106
|
+
eventManager.setDebugMode(true);
|
|
107
|
+
// Enable debug mode for the interval manager
|
|
108
|
+
//intervalManager.setDebugMode(true);
|
|
109
|
+
}
|
|
110
|
+
this.initializeStrategies();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Initialize protection strategies based on configuration options
|
|
114
|
+
* Creates strategy instances and adds them to the strategies map
|
|
115
|
+
*/
|
|
116
|
+
initializeStrategies() {
|
|
117
|
+
const { debugMode, targetElement, customHandlers } = this.options;
|
|
118
|
+
// Initialize strategies based on options
|
|
119
|
+
if (this.options.preventKeyboardShortcuts) {
|
|
120
|
+
this.strategies.set("keyboard", new KeyboardStrategy(customHandlers?.onKeyboardShortcutBlocked, debugMode));
|
|
121
|
+
}
|
|
122
|
+
if (this.options.preventContextMenu) {
|
|
123
|
+
this.strategies.set("contextMenu", new ContextMenuStrategy(this.options.contextMenuOptions, targetElement, customHandlers?.onContextMenuAttempt, debugMode));
|
|
124
|
+
}
|
|
125
|
+
if (this.options.preventPrinting) {
|
|
126
|
+
this.strategies.set("print", new PrintStrategy(customHandlers?.onPrintAttempt, debugMode));
|
|
127
|
+
}
|
|
128
|
+
if (this.options.preventSelection) {
|
|
129
|
+
this.strategies.set("selection", new SelectionStrategy(targetElement, customHandlers?.onSelectionAttempt, debugMode));
|
|
130
|
+
}
|
|
131
|
+
if (this.options.enableWatermark && this.options.watermarkOptions) {
|
|
132
|
+
this.strategies.set("watermark", new WatermarkStrategy(this.options.watermarkOptions, targetElement, debugMode));
|
|
133
|
+
}
|
|
134
|
+
if (this.options.preventDevTools) {
|
|
135
|
+
const devToolsStrategy = new DevToolsStrategy(this.options.devToolsOptions, targetElement, customHandlers?.onDevToolsOpen, debugMode);
|
|
136
|
+
devToolsStrategy.setMediator(this.mediator);
|
|
137
|
+
this.strategies.set("devTools", devToolsStrategy);
|
|
138
|
+
}
|
|
139
|
+
if (this.options.preventScreenshots) {
|
|
140
|
+
const screenshotStrategy = new ScreenshotStrategy(this.options.screenshotOptions, targetElement, customHandlers?.onScreenshotAttempt, debugMode);
|
|
141
|
+
screenshotStrategy.setMediator(this.mediator);
|
|
142
|
+
this.strategies.set("screenshot", screenshotStrategy);
|
|
143
|
+
}
|
|
144
|
+
if (this.options.preventExtensions) {
|
|
145
|
+
const extensionStrategy = new BrowserExtensionDetectionStrategy(this.options.extensionOptions, targetElement, customHandlers?.onExtensionDetected, debugMode);
|
|
146
|
+
extensionStrategy.setMediator(this.mediator);
|
|
147
|
+
this.strategies.set("extension", extensionStrategy);
|
|
148
|
+
}
|
|
149
|
+
if (this.options.preventEmbedding) {
|
|
150
|
+
const frameStrategy = new FrameEmbeddingProtectionStrategy(this.options.frameEmbeddingOptions, targetElement, customHandlers?.onFrameEmbeddingDetected, debugMode);
|
|
151
|
+
frameStrategy.setMediator(this.mediator);
|
|
152
|
+
this.strategies.set("iFrame", frameStrategy);
|
|
153
|
+
}
|
|
154
|
+
if (this.options.preventClipboard) {
|
|
155
|
+
this.strategies.set("clipboard", new ClipboardStrategy(this.options.clipboardOptions, targetElement, customHandlers?.onClipboardAttempt, debugMode));
|
|
156
|
+
}
|
|
157
|
+
this.logger.log("Initialized strategies", Array.from(this.strategies.keys()));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Apply all protection strategies
|
|
161
|
+
* Activates each strategy to protect content
|
|
162
|
+
*/
|
|
163
|
+
protect() {
|
|
164
|
+
if (this.isActive) {
|
|
165
|
+
this.logger.log("Already protected, skipping");
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.logger.log("Applying protection strategies");
|
|
169
|
+
// Apply each strategy
|
|
170
|
+
for (const [name, strategy] of this.strategies.entries()) {
|
|
171
|
+
try {
|
|
172
|
+
this.logger.log(`Applying strategy "${name}"`);
|
|
173
|
+
strategy.apply();
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
this.logger.error(`Error applying strategy "${name}":`, error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
this.isActive = true;
|
|
180
|
+
this.logger.log("All protection strategies applied successfully");
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Remove all protection strategies
|
|
184
|
+
* Deactivates each strategy and cleans up resources
|
|
185
|
+
*/
|
|
186
|
+
unprotect() {
|
|
187
|
+
if (!this.isActive) {
|
|
188
|
+
this.logger.log("Not protected, skipping");
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
this.logger.log("Removing protection strategies");
|
|
192
|
+
// Create a copy of the strategy entries to avoid modification during iteration
|
|
193
|
+
const entries = Array.from(this.strategies.entries());
|
|
194
|
+
// Remove each strategy and track failures
|
|
195
|
+
let successCount = 0;
|
|
196
|
+
let failCount = 0;
|
|
197
|
+
for (const [name, strategy] of entries) {
|
|
198
|
+
try {
|
|
199
|
+
this.logger.log(`Removing strategy "${name}"`);
|
|
200
|
+
if (strategy.isApplied()) {
|
|
201
|
+
strategy.remove();
|
|
202
|
+
successCount++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
failCount++;
|
|
207
|
+
this.logger.error(`Error removing strategy "${name}":`, error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Clear all strategies regardless of removal success
|
|
211
|
+
this.strategies.clear();
|
|
212
|
+
this.isActive = false;
|
|
213
|
+
this.logger.log(`Protection removed (${successCount} successful, ${failCount} failed)`);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Update protection options
|
|
217
|
+
* Removes existing protection, updates options, and reapplies if needed
|
|
218
|
+
* @param options New options to apply
|
|
219
|
+
*/
|
|
220
|
+
updateOptions(options) {
|
|
221
|
+
this.logger.log("Updating options", options);
|
|
222
|
+
// Store the current state
|
|
223
|
+
const wasActive = this.isActive;
|
|
224
|
+
// Remove existing protections
|
|
225
|
+
this.unprotect();
|
|
226
|
+
// Update options
|
|
227
|
+
this.options = {
|
|
228
|
+
...this.options,
|
|
229
|
+
...options,
|
|
230
|
+
};
|
|
231
|
+
// Update debug mode for managers and logger
|
|
232
|
+
if (options.debugMode !== undefined) {
|
|
233
|
+
this.logger.setDebugMode(options.debugMode);
|
|
234
|
+
eventManager.setDebugMode(options.debugMode);
|
|
235
|
+
//intervalManager.setDebugMode(options.debugMode);
|
|
236
|
+
this.overlayManager.setDebugMode(options.debugMode);
|
|
237
|
+
}
|
|
238
|
+
this.logger.log("New options after update", this.options);
|
|
239
|
+
// Reinitialize strategies
|
|
240
|
+
this.strategies.clear();
|
|
241
|
+
this.initializeStrategies();
|
|
242
|
+
// Reapply protection if it was active before
|
|
243
|
+
if (wasActive) {
|
|
244
|
+
this.logger.log("Reapplying protection after options update");
|
|
245
|
+
this.protect();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Check if protection is currently active
|
|
250
|
+
* @returns True if protection is active
|
|
251
|
+
*/
|
|
252
|
+
isProtected() {
|
|
253
|
+
return this.isActive;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Get a specific strategy by name
|
|
257
|
+
* @param name Strategy name
|
|
258
|
+
* @returns The strategy instance or undefined if not found
|
|
259
|
+
*/
|
|
260
|
+
getStrategy(name) {
|
|
261
|
+
return this.strategies.get(name);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Check if a specific strategy is active
|
|
265
|
+
* @param name Strategy name
|
|
266
|
+
* @returns True if the strategy exists
|
|
267
|
+
*/
|
|
268
|
+
hasStrategy(name) {
|
|
269
|
+
return this.strategies.has(name);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Clean up and dispose of all resources
|
|
273
|
+
* Removes protection and cleans up global managers
|
|
274
|
+
*/
|
|
275
|
+
dispose() {
|
|
276
|
+
this.unprotect();
|
|
277
|
+
// Dispose interval manager
|
|
278
|
+
intervalManager.dispose();
|
|
279
|
+
this.logger.log("Disposed all resources");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ContentProtector } from './ContentProtector';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ProtectionEvent, ProtectionEventType } from './protection-event';
|
|
2
|
+
import { ProtectionEventHandler, ProtectionMediator, Subscription, SubscriptionOptions } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Mediator for coordinating communication between protection strategies
|
|
5
|
+
* Implements the mediator pattern to decouple strategies and enable event-based communication
|
|
6
|
+
*/
|
|
7
|
+
export declare class ContentProtectionMediator implements ProtectionMediator {
|
|
8
|
+
private subscriptions;
|
|
9
|
+
private subscriptionCounter;
|
|
10
|
+
private debugMode;
|
|
11
|
+
private eventHistory;
|
|
12
|
+
private readonly MAX_HISTORY_SIZE;
|
|
13
|
+
/**
|
|
14
|
+
* Create a new ContentProtectionMediator
|
|
15
|
+
* @param debugMode Enable debug mode for detailed logging
|
|
16
|
+
*/
|
|
17
|
+
constructor(debugMode?: boolean);
|
|
18
|
+
/**
|
|
19
|
+
* Subscribe to an event
|
|
20
|
+
* @param eventType Type of event to subscribe to
|
|
21
|
+
* @param handler Handler function for the event
|
|
22
|
+
* @param options Optional subscription options
|
|
23
|
+
* @returns Subscription ID for later unsubscribing
|
|
24
|
+
*/
|
|
25
|
+
subscribe(eventType: ProtectionEventType, handler: ProtectionEventHandler, options?: SubscriptionOptions): string;
|
|
26
|
+
/**
|
|
27
|
+
* Unsubscribe from an event
|
|
28
|
+
* @param subscriptionId ID of the subscription to remove
|
|
29
|
+
* @returns True if the subscription was found and removed
|
|
30
|
+
*/
|
|
31
|
+
unsubscribe(subscriptionId: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Unsubscribe all handlers with a specific context
|
|
34
|
+
* @param context Context to unsubscribe (e.g., strategy name)
|
|
35
|
+
* @returns Number of subscriptions removed
|
|
36
|
+
*/
|
|
37
|
+
unsubscribeByContext(context: string): number;
|
|
38
|
+
/**
|
|
39
|
+
* Publish an event to all subscribers
|
|
40
|
+
* @param event Event to publish
|
|
41
|
+
*/
|
|
42
|
+
publish(event: ProtectionEvent): void;
|
|
43
|
+
/**
|
|
44
|
+
* Get all subscriptions for a specific event type
|
|
45
|
+
* @param eventType Type of event to get subscriptions for
|
|
46
|
+
* @returns Array of subscriptions
|
|
47
|
+
*/
|
|
48
|
+
getSubscriptions(eventType: ProtectionEventType): Subscription[];
|
|
49
|
+
/**
|
|
50
|
+
* Get all subscriptions
|
|
51
|
+
* @returns Map of event types to subscriptions
|
|
52
|
+
*/
|
|
53
|
+
getAllSubscriptions(): Map<ProtectionEventType, Subscription[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Set debug mode
|
|
56
|
+
* @param enabled Whether debug mode should be enabled
|
|
57
|
+
*/
|
|
58
|
+
setDebugMode(enabled: boolean): void;
|
|
59
|
+
/**
|
|
60
|
+
* Get debug information about the mediator
|
|
61
|
+
* @returns Object with debug information
|
|
62
|
+
*/
|
|
63
|
+
getDebugInfo(): {
|
|
64
|
+
subscriptionCount: number;
|
|
65
|
+
eventTypeCount: number;
|
|
66
|
+
eventTypes: string[];
|
|
67
|
+
recentEvents: ProtectionEvent[];
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Add an event to the history
|
|
71
|
+
* @param event Event to add
|
|
72
|
+
*/
|
|
73
|
+
private addToEventHistory;
|
|
74
|
+
/**
|
|
75
|
+
* Clear all subscriptions
|
|
76
|
+
* @returns Number of subscriptions cleared
|
|
77
|
+
*/
|
|
78
|
+
clearAllSubscriptions(): number;
|
|
79
|
+
/**
|
|
80
|
+
* Helper method to create and publish an event
|
|
81
|
+
* @param type Event type
|
|
82
|
+
* @param source Source of the event
|
|
83
|
+
* @param data Additional data
|
|
84
|
+
*/
|
|
85
|
+
createAndPublishEvent(type: ProtectionEventType, source: string, data?: unknown): void;
|
|
86
|
+
}
|