@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.
Files changed (118) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +357 -0
  3. package/dist/assess.d.ts +16 -0
  4. package/dist/assess.js +220 -0
  5. package/dist/config/default-extensions-config.json +103 -0
  6. package/dist/core/ContentProtector.d.ts +63 -0
  7. package/dist/core/ContentProtector.js +281 -0
  8. package/dist/core/index.d.ts +1 -0
  9. package/dist/core/index.js +2 -0
  10. package/dist/core/mediator/ContentProtectionMediator.d.ts +86 -0
  11. package/dist/core/mediator/ContentProtectionMediator.js +238 -0
  12. package/dist/core/mediator/eventDataTypes.d.ts +112 -0
  13. package/dist/core/mediator/eventDataTypes.js +23 -0
  14. package/dist/core/mediator/handlers/abstractEventHandler.d.ts +41 -0
  15. package/dist/core/mediator/handlers/abstractEventHandler.js +59 -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/screenShotEventHandlers.d.ts +34 -0
  25. package/dist/core/mediator/handlers/screenShotEventHandlers.js +111 -0
  26. package/dist/core/mediator/protection-event.d.ts +77 -0
  27. package/dist/core/mediator/protection-event.js +32 -0
  28. package/dist/core/mediator/types.d.ts +105 -0
  29. package/dist/core/mediator/types.js +1 -0
  30. package/dist/index.d.ts +10 -0
  31. package/dist/index.js +7 -0
  32. package/dist/otel.d.ts +24 -0
  33. package/dist/otel.js +83 -0
  34. package/dist/policy.d.ts +98 -0
  35. package/dist/policy.js +97 -0
  36. package/dist/strategies/AbstractStrategy.d.ts +124 -0
  37. package/dist/strategies/AbstractStrategy.js +256 -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.d.ts +55 -0
  43. package/dist/strategies/DevToolsStrategy.js +314 -0
  44. package/dist/strategies/ExtensionStrategy.d.ts +66 -0
  45. package/dist/strategies/ExtensionStrategy.js +486 -0
  46. package/dist/strategies/IFrameStrategy.d.ts +49 -0
  47. package/dist/strategies/IFrameStrategy.js +255 -0
  48. package/dist/strategies/KeyboardStrategy.d.ts +35 -0
  49. package/dist/strategies/KeyboardStrategy.js +130 -0
  50. package/dist/strategies/PrintStrategy.d.ts +47 -0
  51. package/dist/strategies/PrintStrategy.js +201 -0
  52. package/dist/strategies/ScreenshotStrategy.d.ts +90 -0
  53. package/dist/strategies/ScreenshotStrategy.js +502 -0
  54. package/dist/strategies/SelectionStrategy.d.ts +49 -0
  55. package/dist/strategies/SelectionStrategy.js +216 -0
  56. package/dist/strategies/WatermarkStrategy.d.ts +56 -0
  57. package/dist/strategies/WatermarkStrategy.js +287 -0
  58. package/dist/strategies/index.d.ts +10 -0
  59. package/dist/strategies/index.js +11 -0
  60. package/dist/types/assessment.d.ts +62 -0
  61. package/dist/types/assessment.js +1 -0
  62. package/dist/types/index.d.ts +278 -0
  63. package/dist/types/index.js +17 -0
  64. package/dist/utils/DOMObserver.d.ts +68 -0
  65. package/dist/utils/DOMObserver.js +134 -0
  66. package/dist/utils/base/LoggableComponent.d.ts +44 -0
  67. package/dist/utils/base/LoggableComponent.js +56 -0
  68. package/dist/utils/detectors/AbstractDevToolsDetector.d.ts +98 -0
  69. package/dist/utils/detectors/AbstractDevToolsDetector.js +127 -0
  70. package/dist/utils/detectors/dateToStringDetector.d.ts +43 -0
  71. package/dist/utils/detectors/dateToStringDetector.js +96 -0
  72. package/dist/utils/detectors/debugLibDetector.d.ts +64 -0
  73. package/dist/utils/detectors/debugLibDetector.js +195 -0
  74. package/dist/utils/detectors/debuggerDetector.d.ts +51 -0
  75. package/dist/utils/detectors/debuggerDetector.js +211 -0
  76. package/dist/utils/detectors/defineGetterDetector.d.ts +48 -0
  77. package/dist/utils/detectors/defineGetterDetector.js +150 -0
  78. package/dist/utils/detectors/detectorInterface.d.ts +36 -0
  79. package/dist/utils/detectors/detectorInterface.js +1 -0
  80. package/dist/utils/detectors/devToolsDetectorManager.d.ts +88 -0
  81. package/dist/utils/detectors/devToolsDetectorManager.js +243 -0
  82. package/dist/utils/detectors/funcToStringDetector.d.ts +43 -0
  83. package/dist/utils/detectors/funcToStringDetector.js +90 -0
  84. package/dist/utils/detectors/regToStringDetector.d.ts +43 -0
  85. package/dist/utils/detectors/regToStringDetector.js +129 -0
  86. package/dist/utils/detectors/sizeDetector.d.ts +54 -0
  87. package/dist/utils/detectors/sizeDetector.js +134 -0
  88. package/dist/utils/detectors/timingDetector.d.ts +55 -0
  89. package/dist/utils/detectors/timingDetector.js +143 -0
  90. package/dist/utils/dom.d.ts +20 -0
  91. package/dist/utils/dom.js +83 -0
  92. package/dist/utils/environment.d.ts +29 -0
  93. package/dist/utils/environment.js +267 -0
  94. package/dist/utils/eventManager.d.ts +162 -0
  95. package/dist/utils/eventManager.js +548 -0
  96. package/dist/utils/index.d.ts +2 -0
  97. package/dist/utils/index.js +3 -0
  98. package/dist/utils/intervalManager.d.ts +91 -0
  99. package/dist/utils/intervalManager.js +221 -0
  100. package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.d.ts +41 -0
  101. package/dist/utils/keyboardShortcutManager/keyboardShortcutManager.js +135 -0
  102. package/dist/utils/keyboardShortcutManager/keyboardShortcuts.d.ts +18 -0
  103. package/dist/utils/keyboardShortcutManager/keyboardShortcuts.js +195 -0
  104. package/dist/utils/logging/simple/Loggable.d.ts +33 -0
  105. package/dist/utils/logging/simple/Loggable.js +1 -0
  106. package/dist/utils/logging/simple/LoggingDelegate.d.ts +42 -0
  107. package/dist/utils/logging/simple/LoggingDelegate.js +53 -0
  108. package/dist/utils/logging/simple/SimpleLoggingService.d.ts +39 -0
  109. package/dist/utils/logging/simple/SimpleLoggingService.js +58 -0
  110. package/dist/utils/orientation.d.ts +15 -0
  111. package/dist/utils/orientation.js +32 -0
  112. package/dist/utils/protectedContentManager.d.ts +155 -0
  113. package/dist/utils/protectedContentManager.js +424 -0
  114. package/dist/utils/securityOverlayManager.d.ts +253 -0
  115. package/dist/utils/securityOverlayManager.js +786 -0
  116. package/dist/utils/timeoutManager.d.ts +50 -0
  117. package/dist/utils/timeoutManager.js +113 -0
  118. package/package.json +61 -0
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Mediator for coordinating communication between protection strategies
3
+ * Implements the mediator pattern to decouple strategies and enable event-based communication
4
+ */
5
+ export class ContentProtectionMediator {
6
+ /**
7
+ * Create a new ContentProtectionMediator
8
+ * @param debugMode Enable debug mode for detailed logging
9
+ */
10
+ constructor(debugMode = false) {
11
+ this.subscriptions = new Map();
12
+ this.subscriptionCounter = 0;
13
+ this.eventHistory = [];
14
+ this.MAX_HISTORY_SIZE = 100;
15
+ this.debugMode = debugMode;
16
+ if (this.debugMode) {
17
+ console.log('ContentProtectionMediator: Initialized');
18
+ }
19
+ }
20
+ /**
21
+ * Subscribe to an event
22
+ * @param eventType Type of event to subscribe to
23
+ * @param handler Handler function for the event
24
+ * @param options Optional subscription options
25
+ * @returns Subscription ID for later unsubscribing
26
+ */
27
+ subscribe(eventType, handler, options) {
28
+ if (!handler || typeof handler !== 'function') {
29
+ console.error('ContentProtectionMediator: Invalid handler provided to subscribe');
30
+ return '';
31
+ }
32
+ // Generate a unique subscription ID
33
+ const subscriptionId = `sub_${++this.subscriptionCounter}`;
34
+ // Create the subscription object
35
+ const subscription = {
36
+ id: subscriptionId,
37
+ eventType,
38
+ handler,
39
+ filter: options?.filter,
40
+ priority: options?.priority || 0,
41
+ context: options?.context
42
+ };
43
+ // Get or create the array of subscriptions for this event type
44
+ if (!this.subscriptions.has(eventType)) {
45
+ this.subscriptions.set(eventType, []);
46
+ }
47
+ // Add the subscription to the array
48
+ const subscriptionsForType = this.subscriptions.get(eventType);
49
+ subscriptionsForType.push(subscription);
50
+ // Sort by priority (higher numbers first)
51
+ subscriptionsForType.sort((a, b) => (b.priority || 0) - (a.priority || 0));
52
+ if (this.debugMode) {
53
+ console.log(`ContentProtectionMediator: Subscribed to ${eventType} with ID ${subscriptionId}`, options ? `(priority: ${options.priority || 0}, context: ${options.context || 'none'})` : '');
54
+ }
55
+ return subscriptionId;
56
+ }
57
+ /**
58
+ * Unsubscribe from an event
59
+ * @param subscriptionId ID of the subscription to remove
60
+ * @returns True if the subscription was found and removed
61
+ */
62
+ unsubscribe(subscriptionId) {
63
+ if (!subscriptionId)
64
+ return false;
65
+ let found = false;
66
+ // Check all event types
67
+ for (const [eventType, subscriptions] of this.subscriptions.entries()) {
68
+ const initialLength = subscriptions.length;
69
+ // Filter out the subscription with the given ID
70
+ const filteredSubscriptions = subscriptions.filter(sub => sub.id !== subscriptionId);
71
+ if (filteredSubscriptions.length < initialLength) {
72
+ // We found and removed the subscription
73
+ this.subscriptions.set(eventType, filteredSubscriptions);
74
+ found = true;
75
+ if (this.debugMode) {
76
+ console.log(`ContentProtectionMediator: Unsubscribed from ${eventType} with ID ${subscriptionId}`);
77
+ }
78
+ break;
79
+ }
80
+ }
81
+ return found;
82
+ }
83
+ /**
84
+ * Unsubscribe all handlers with a specific context
85
+ * @param context Context to unsubscribe (e.g., strategy name)
86
+ * @returns Number of subscriptions removed
87
+ */
88
+ unsubscribeByContext(context) {
89
+ if (!context)
90
+ return 0;
91
+ let removedCount = 0;
92
+ // Check all event types
93
+ for (const [eventType, subscriptions] of this.subscriptions.entries()) {
94
+ const initialLength = subscriptions.length;
95
+ // Filter out subscriptions with the given context
96
+ const filteredSubscriptions = subscriptions.filter(sub => sub.context !== context);
97
+ if (filteredSubscriptions.length < initialLength) {
98
+ // We found and removed subscriptions
99
+ const removed = initialLength - filteredSubscriptions.length;
100
+ removedCount += removed;
101
+ this.subscriptions.set(eventType, filteredSubscriptions);
102
+ if (this.debugMode) {
103
+ console.log(`ContentProtectionMediator: Unsubscribed ${removed} handlers for ${context} from ${eventType}`);
104
+ }
105
+ }
106
+ }
107
+ return removedCount;
108
+ }
109
+ /**
110
+ * Publish an event to all subscribers
111
+ * @param event Event to publish
112
+ */
113
+ publish(event) {
114
+ console.log('Publishing event', event);
115
+ if (!event || !event.type) {
116
+ console.error('ContentProtectionMediator: Invalid event provided to publish');
117
+ return;
118
+ }
119
+ // Add timestamp if not provided
120
+ if (!event.timestamp) {
121
+ event.timestamp = Date.now();
122
+ }
123
+ // Store in history for debugging
124
+ this.addToEventHistory(event);
125
+ // Get subscriptions for this event type
126
+ const subscriptions = this.subscriptions.get(event.type) || [];
127
+ if (subscriptions.length === 0) {
128
+ if (this.debugMode) {
129
+ console.log(`ContentProtectionMediator: No subscribers for ${event.type}`);
130
+ }
131
+ return;
132
+ }
133
+ if (this.debugMode) {
134
+ console.log(`ContentProtectionMediator: Publishing ${event.type} from ${event.source}`, event.data ? `with data: ${JSON.stringify(event.data)}` : '');
135
+ }
136
+ // Call each handler
137
+ for (const subscription of subscriptions) {
138
+ try {
139
+ // Apply filter if provided
140
+ if (subscription.filter && !subscription.filter(event)) {
141
+ continue;
142
+ }
143
+ // Call the handler
144
+ subscription.handler(event);
145
+ }
146
+ catch (error) {
147
+ console.error(`ContentProtectionMediator: Error in handler for ${event.type}:`, error);
148
+ }
149
+ }
150
+ }
151
+ /**
152
+ * Get all subscriptions for a specific event type
153
+ * @param eventType Type of event to get subscriptions for
154
+ * @returns Array of subscriptions
155
+ */
156
+ getSubscriptions(eventType) {
157
+ return [...(this.subscriptions.get(eventType) || [])];
158
+ }
159
+ /**
160
+ * Get all subscriptions
161
+ * @returns Map of event types to subscriptions
162
+ */
163
+ getAllSubscriptions() {
164
+ // Return a deep copy to prevent external modification
165
+ const result = new Map();
166
+ for (const [eventType, subscriptions] of this.subscriptions.entries()) {
167
+ result.set(eventType, [...subscriptions]);
168
+ }
169
+ return result;
170
+ }
171
+ /**
172
+ * Set debug mode
173
+ * @param enabled Whether debug mode should be enabled
174
+ */
175
+ setDebugMode(enabled) {
176
+ this.debugMode = enabled;
177
+ if (this.debugMode) {
178
+ console.log('ContentProtectionMediator: Debug mode enabled');
179
+ }
180
+ }
181
+ /**
182
+ * Get debug information about the mediator
183
+ * @returns Object with debug information
184
+ */
185
+ getDebugInfo() {
186
+ let totalSubscriptions = 0;
187
+ for (const subscriptions of this.subscriptions.values()) {
188
+ totalSubscriptions += subscriptions.length;
189
+ }
190
+ return {
191
+ subscriptionCount: totalSubscriptions,
192
+ eventTypeCount: this.subscriptions.size,
193
+ eventTypes: Array.from(this.subscriptions.keys()),
194
+ recentEvents: [...this.eventHistory]
195
+ };
196
+ }
197
+ /**
198
+ * Add an event to the history
199
+ * @param event Event to add
200
+ */
201
+ addToEventHistory(event) {
202
+ this.eventHistory.unshift(event);
203
+ // Limit history size
204
+ if (this.eventHistory.length > this.MAX_HISTORY_SIZE) {
205
+ this.eventHistory.pop();
206
+ }
207
+ }
208
+ /**
209
+ * Clear all subscriptions
210
+ * @returns Number of subscriptions cleared
211
+ */
212
+ clearAllSubscriptions() {
213
+ let count = 0;
214
+ for (const subscriptions of this.subscriptions.values()) {
215
+ count += subscriptions.length;
216
+ }
217
+ this.subscriptions.clear();
218
+ if (this.debugMode) {
219
+ console.log(`ContentProtectionMediator: Cleared ${count} subscriptions`);
220
+ }
221
+ return count;
222
+ }
223
+ /**
224
+ * Helper method to create and publish an event
225
+ * @param type Event type
226
+ * @param source Source of the event
227
+ * @param data Additional data
228
+ */
229
+ createAndPublishEvent(type, source, data) {
230
+ const event = {
231
+ type,
232
+ source,
233
+ timestamp: Date.now(),
234
+ data
235
+ };
236
+ this.publish(event);
237
+ }
238
+ }
@@ -0,0 +1,112 @@
1
+ import { OverlayOptions } from "@/utils/securityOverlayManager";
2
+ import { ProtectionEventType } from "./protection-event";
3
+ import { PlaceholderOptions } from "@/utils/protectedContentManager";
4
+ import { ExtensionConfig } from "@/types";
5
+ /**
6
+ * Interface defining the data structure for each event type.
7
+ *
8
+ * Keep this in sync with the {@link ProtectionEventType} enum — every value
9
+ * in the enum should have a matching `[ProtectionEventType.X]: { ... }` entry
10
+ * here. The trailing index signature catches any drift (and lets ad-hoc
11
+ * subscribers attach handlers for not-yet-typed events without compile errors).
12
+ */
13
+ export interface EventDataMap {
14
+ [ProtectionEventType.DEVTOOLS_STATE_CHANGE]: {
15
+ isOpen: boolean;
16
+ target?: HTMLElement | null;
17
+ showOverlay?: boolean | null;
18
+ overlayOptions?: OverlayOptions | null;
19
+ hideContent?: boolean | null;
20
+ };
21
+ [ProtectionEventType.EXTENSION_DETECTED]: {
22
+ extension: ExtensionConfig | null;
23
+ showOverlay?: boolean | null;
24
+ overlayOptions?: OverlayOptions | null;
25
+ hideContent?: boolean | null;
26
+ priority: number;
27
+ reason: string;
28
+ target?: HTMLElement | null;
29
+ };
30
+ [ProtectionEventType.SCREENSHOT_ATTEMPT]: {
31
+ showOverlay?: boolean | null;
32
+ hideContent?: boolean | null;
33
+ overlayOptions?: OverlayOptions | null;
34
+ duration?: number | null;
35
+ priority: number;
36
+ reason: string;
37
+ target?: HTMLElement | null;
38
+ };
39
+ [ProtectionEventType.FRAME_EMBEDDING_DETECTED]: {
40
+ isEmbedded: boolean;
41
+ isExternalFrame: boolean;
42
+ parentDomain?: string;
43
+ targetElement?: HTMLElement | null;
44
+ showOverlay?: boolean | null;
45
+ hideContent?: boolean | null;
46
+ overlayOptions?: OverlayOptions | null;
47
+ };
48
+ [ProtectionEventType.CONTENT_HIDDEN]: {
49
+ strategyName: string;
50
+ reason: string;
51
+ options: PlaceholderOptions;
52
+ targetElement?: HTMLElement | null;
53
+ priority: number;
54
+ };
55
+ [ProtectionEventType.CONTENT_RESTORED]: {
56
+ strategyName: string;
57
+ targetElement?: HTMLElement | null;
58
+ };
59
+ [ProtectionEventType.OVERLAY_SHOWN]: {
60
+ strategyName: string;
61
+ overlayType: string;
62
+ options: OverlayOptions;
63
+ priority: number;
64
+ duration?: number;
65
+ };
66
+ [ProtectionEventType.OVERLAY_REMOVED]: {
67
+ strategyName: string;
68
+ overlayType: string;
69
+ reason?: string;
70
+ };
71
+ [ProtectionEventType.OVERLAY_RESTORED]: {
72
+ strategyName: string;
73
+ overlayType: string;
74
+ reason?: string;
75
+ };
76
+ [ProtectionEventType.STRATEGY_REMOVED]: {
77
+ strategyName: string;
78
+ reason?: string;
79
+ };
80
+ [key: string]: Record<string, unknown>;
81
+ }
82
+ /**
83
+ * Type-safe typed event interface
84
+ * Use this instead of unsafe `as` assertions
85
+ */
86
+ export interface TypedProtectionEvent<T extends ProtectionEventType> {
87
+ type: T;
88
+ source: string;
89
+ timestamp: number;
90
+ data: EventDataMap[T];
91
+ }
92
+ /**
93
+ * Type guard to check if an event has a specific type
94
+ * @param event The event to check
95
+ * @param eventType The expected event type
96
+ * @returns True if the event matches the type
97
+ */
98
+ export declare function isEventType<T extends ProtectionEventType>(event: {
99
+ type: ProtectionEventType;
100
+ data?: unknown;
101
+ }, eventType: T): event is TypedProtectionEvent<T>;
102
+ /**
103
+ * Get typed event data with type safety
104
+ * Returns undefined if the event type doesn't match
105
+ * @param event The protection event
106
+ * @param eventType The expected event type
107
+ * @returns The typed data or undefined
108
+ */
109
+ export declare function getTypedEventData<T extends ProtectionEventType>(event: {
110
+ type: ProtectionEventType;
111
+ data?: unknown;
112
+ }, eventType: T): EventDataMap[T] | undefined;
@@ -0,0 +1,23 @@
1
+ import { ProtectionEventType } from "./protection-event";
2
+ /**
3
+ * Type guard to check if an event has a specific type
4
+ * @param event The event to check
5
+ * @param eventType The expected event type
6
+ * @returns True if the event matches the type
7
+ */
8
+ export function isEventType(event, eventType) {
9
+ return event.type === eventType;
10
+ }
11
+ /**
12
+ * Get typed event data with type safety
13
+ * Returns undefined if the event type doesn't match
14
+ * @param event The protection event
15
+ * @param eventType The expected event type
16
+ * @returns The typed data or undefined
17
+ */
18
+ export function getTypedEventData(event, eventType) {
19
+ if (event.type === eventType) {
20
+ return event.data;
21
+ }
22
+ return undefined;
23
+ }
@@ -0,0 +1,41 @@
1
+ import type { ProtectionMediator } from "../types";
2
+ import type { ProtectionEvent, ProtectionEventType } from "../protection-event";
3
+ import { LoggableComponent } from "../../../utils/base/LoggableComponent";
4
+ /**
5
+ * Abstract base class for all event handlers
6
+ */
7
+ export declare abstract class AbstractEventHandler extends LoggableComponent {
8
+ protected mediator: ProtectionMediator;
9
+ protected subscriptionIds: string[];
10
+ /**
11
+ * Create a new event handler
12
+ * @param mediator The protection mediator
13
+ * @param componentName The name of the component
14
+ * @param debugMode Enable debug mode for troubleshooting
15
+ */
16
+ constructor(mediator: ProtectionMediator, componentName: string, debugMode?: boolean);
17
+ /**
18
+ * Initialize the handler and subscribe to events
19
+ * This method should be implemented by subclasses
20
+ */
21
+ protected abstract initialize(): void;
22
+ /**
23
+ * Subscribe to an event and track the subscription ID
24
+ * @param eventType The event type to subscribe to
25
+ * @param handler The event handler function
26
+ * @param options Optional subscription options
27
+ * @returns The subscription ID
28
+ */
29
+ protected subscribe(eventType: ProtectionEventType, handler: (event: ProtectionEvent) => void, options?: {
30
+ context?: string;
31
+ }): string;
32
+ /**
33
+ * Unsubscribe from all events and clean up
34
+ */
35
+ dispose(): void;
36
+ /**
37
+ * Additional cleanup to be performed on disposal
38
+ * This method can be overridden by subclasses
39
+ */
40
+ protected onDispose(): void;
41
+ }
@@ -0,0 +1,59 @@
1
+ import { LoggableComponent } from "../../../utils/base/LoggableComponent";
2
+ /**
3
+ * Abstract base class for all event handlers
4
+ */
5
+ export class AbstractEventHandler extends LoggableComponent {
6
+ /**
7
+ * Create a new event handler
8
+ * @param mediator The protection mediator
9
+ * @param componentName The name of the component
10
+ * @param debugMode Enable debug mode for troubleshooting
11
+ */
12
+ constructor(mediator, componentName, debugMode = false) {
13
+ super(componentName, debugMode);
14
+ this.subscriptionIds = [];
15
+ this.mediator = mediator;
16
+ this.initialize();
17
+ // `log` is debug-gated by the logger; the outer check is unnecessary.
18
+ this.log("Initialized and subscribed to events");
19
+ }
20
+ /**
21
+ * Subscribe to an event and track the subscription ID
22
+ * @param eventType The event type to subscribe to
23
+ * @param handler The event handler function
24
+ * @param options Optional subscription options
25
+ * @returns The subscription ID
26
+ */
27
+ subscribe(eventType, handler, options) {
28
+ const subId = this.mediator.subscribe(eventType, handler, {
29
+ ...options,
30
+ context: options?.context || this.COMPONENT_NAME,
31
+ });
32
+ this.subscriptionIds.push(subId);
33
+ if (this.debugMode) {
34
+ this.log(`Subscribed to ${eventType} with ID ${subId}`);
35
+ }
36
+ return subId;
37
+ }
38
+ /**
39
+ * Unsubscribe from all events and clean up
40
+ */
41
+ dispose() {
42
+ if (this.debugMode) {
43
+ this.log(`Disposing handler, unsubscribing from ${this.subscriptionIds.length} events`);
44
+ }
45
+ // Unsubscribe from all events
46
+ for (const id of this.subscriptionIds) {
47
+ this.mediator.unsubscribe(id);
48
+ }
49
+ this.subscriptionIds = [];
50
+ this.onDispose();
51
+ }
52
+ /**
53
+ * Additional cleanup to be performed on disposal
54
+ * This method can be overridden by subclasses
55
+ */
56
+ onDispose() {
57
+ // Default implementation does nothing
58
+ }
59
+ }
@@ -0,0 +1,9 @@
1
+ import type { ProtectionMediator } from "../types";
2
+ import { AbstractEventHandler } from "./abstractEventHandler";
3
+ export declare class DevToolsEventHandler extends AbstractEventHandler {
4
+ constructor(mediator: ProtectionMediator, debugMode?: boolean);
5
+ protected initialize(): void;
6
+ private handleDevToolsStateChange;
7
+ private handleDevToolsOpened;
8
+ private handleDevToolsClosed;
9
+ }
@@ -0,0 +1,95 @@
1
+ import { ProtectionEventType } from "../protection-event";
2
+ import { isEventType } from "../eventDataTypes";
3
+ import { AbstractEventHandler } from "./abstractEventHandler";
4
+ export class DevToolsEventHandler extends AbstractEventHandler {
5
+ constructor(mediator, debugMode = false) {
6
+ super(mediator, "DevToolsEventHandler", debugMode);
7
+ }
8
+ initialize() {
9
+ this.subscribe(ProtectionEventType.DEVTOOLS_STATE_CHANGE, this.handleDevToolsStateChange.bind(this));
10
+ }
11
+ handleDevToolsStateChange(event) {
12
+ // Use type guard for type-safe access
13
+ if (!isEventType(event, ProtectionEventType.DEVTOOLS_STATE_CHANGE)) {
14
+ this.error("Received invalid event type");
15
+ return;
16
+ }
17
+ this.log(`Handling DevTools state change, isOpen=${event.data.isOpen}`);
18
+ if (event.data.isOpen) {
19
+ this.handleDevToolsOpened(event);
20
+ }
21
+ else {
22
+ this.handleDevToolsClosed(event);
23
+ }
24
+ }
25
+ handleDevToolsOpened(event) {
26
+ const { data } = event;
27
+ // Show overlay if showOverlay is enabled (defaults to true)
28
+ if (data.showOverlay !== false) {
29
+ this.mediator.publish({
30
+ type: ProtectionEventType.OVERLAY_SHOWN,
31
+ source: this.COMPONENT_NAME,
32
+ timestamp: Date.now(),
33
+ data: {
34
+ strategyName: this.COMPONENT_NAME,
35
+ overlayType: "devtools",
36
+ options: {
37
+ ...data.overlayOptions,
38
+ blockEvents: true,
39
+ autoRestore: true,
40
+ },
41
+ priority: 10,
42
+ },
43
+ });
44
+ }
45
+ // Only hide content if hideContent option is explicitly enabled
46
+ if (data.hideContent === true) {
47
+ this.mediator.publish({
48
+ type: ProtectionEventType.CONTENT_HIDDEN,
49
+ source: this.COMPONENT_NAME,
50
+ timestamp: Date.now(),
51
+ data: {
52
+ strategyName: this.COMPONENT_NAME,
53
+ reason: "devtools_opened",
54
+ options: {
55
+ title: data.overlayOptions?.title,
56
+ message: data.overlayOptions?.message,
57
+ secondaryMessage: data.overlayOptions?.secondaryMessage,
58
+ textColor: 'black',
59
+ backgroundColor: data.overlayOptions?.backgroundColor,
60
+ },
61
+ targetElement: data.target,
62
+ priority: 10,
63
+ },
64
+ });
65
+ }
66
+ }
67
+ handleDevToolsClosed(event) {
68
+ const { data } = event;
69
+ // Remove overlay if showOverlay was enabled
70
+ if (data.showOverlay !== false) {
71
+ this.mediator.publish({
72
+ type: ProtectionEventType.OVERLAY_REMOVED,
73
+ source: this.COMPONENT_NAME,
74
+ timestamp: Date.now(),
75
+ data: {
76
+ strategyName: this.COMPONENT_NAME,
77
+ overlayType: "devtools",
78
+ reason: "devtools_closed",
79
+ },
80
+ });
81
+ }
82
+ // Only restore content if hideContent was explicitly enabled
83
+ if (data.hideContent === true) {
84
+ this.mediator.publish({
85
+ type: ProtectionEventType.CONTENT_RESTORED,
86
+ source: this.COMPONENT_NAME,
87
+ timestamp: Date.now(),
88
+ data: {
89
+ strategyName: this.COMPONENT_NAME,
90
+ targetElement: data.target,
91
+ },
92
+ });
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,9 @@
1
+ import type { ProtectionMediator } from "../types";
2
+ export declare class HandlerRegistry {
3
+ private handlers;
4
+ private mediator;
5
+ private debugMode;
6
+ constructor(mediator: ProtectionMediator, debugMode?: boolean);
7
+ private initializeHandlers;
8
+ setDebugMode(enabled: boolean): void;
9
+ }
@@ -0,0 +1,34 @@
1
+ import { DevToolsEventHandler } from "./devToolsEventHandler";
2
+ import { BrowserExtensionEventHandler } from "./extensionEventHandlers";
3
+ import { FrameEmbeddingEventHandler } from "./iFrameEventHandlers";
4
+ import { ScreenshotEventHandler } from "./screenShotEventHandlers";
5
+ export class HandlerRegistry {
6
+ constructor(mediator, debugMode = false) {
7
+ this.handlers = {};
8
+ this.mediator = mediator;
9
+ this.debugMode = debugMode;
10
+ this.initializeHandlers();
11
+ }
12
+ initializeHandlers() {
13
+ // Initialize all handlers
14
+ this.handlers.devTools = new DevToolsEventHandler(this.mediator, this.debugMode);
15
+ this.handlers.extension = new BrowserExtensionEventHandler(this.mediator, this.debugMode);
16
+ this.handlers.screenshot = new ScreenshotEventHandler(this.mediator, this.debugMode);
17
+ this.handlers.iFrame = new FrameEmbeddingEventHandler(this.mediator, this.debugMode);
18
+ // Add more handlers as you implement them
19
+ // this.handlers.screenshot = new ScreenshotEventHandler(this.mediator, this.debugMode);
20
+ // this.handlers.frameEmbedding = new FrameEmbeddingEventHandler(this.mediator, this.debugMode);
21
+ if (this.debugMode) {
22
+ console.log("HandlerRegistry: Initialized all event handlers");
23
+ }
24
+ }
25
+ setDebugMode(enabled) {
26
+ this.debugMode = enabled;
27
+ // Update debug mode for all handlers
28
+ Object.values(this.handlers).forEach(handler => {
29
+ if (typeof handler.setDebugMode === 'function') {
30
+ handler.setDebugMode(enabled);
31
+ }
32
+ });
33
+ }
34
+ }
@@ -0,0 +1,40 @@
1
+ import type { ProtectionMediator } from "../types";
2
+ import { ProtectionEvent, ProtectionEventType } from "../protection-event";
3
+ import { TypedProtectionEvent } from "../eventDataTypes";
4
+ import { AbstractEventHandler } from "./abstractEventHandler";
5
+ type ExtensionDetectedEvent = TypedProtectionEvent<typeof ProtectionEventType.EXTENSION_DETECTED>;
6
+ /**
7
+ * Handler for browser extension detection events
8
+ */
9
+ export declare class BrowserExtensionEventHandler extends AbstractEventHandler {
10
+ /**
11
+ * Create a new BrowserExtensionEventHandler
12
+ * @param mediator The protection mediator
13
+ * @param debugMode Enable debug mode for troubleshooting
14
+ */
15
+ constructor(mediator: ProtectionMediator, debugMode?: boolean);
16
+ /**
17
+ * Initialize the handler and subscribe to events
18
+ */
19
+ protected initialize(): void;
20
+ /**
21
+ * Handle extension detection
22
+ * @param event the ProtectionEvent
23
+ */
24
+ handleExtensionDetected(event: ProtectionEvent): void;
25
+ /**
26
+ * Handle extension detection
27
+ * @param event the typed ExtensionDetectedEvent
28
+ */
29
+ applyExtensionProtection(event: ExtensionDetectedEvent): void;
30
+ /**
31
+ * Remove extension protection
32
+ * @param event The typed ExtensionDetectedEvent
33
+ */
34
+ removeExtensionProtection(event: ExtensionDetectedEvent): void;
35
+ /**
36
+ * Additional cleanup to be performed on disposal
37
+ */
38
+ protected onDispose(): void;
39
+ }
40
+ export {};