@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,424 @@
1
+ import { ProtectionEventType } from "../core/mediator/protection-event";
2
+ import { isEventType } from "../core/mediator/eventDataTypes";
3
+ import { LoggableComponent } from "./base/LoggableComponent";
4
+ /**
5
+ * Utility class to manage protected content by hiding and revealing it
6
+ */
7
+ export class ProtectedContentManager extends LoggableComponent {
8
+ /**
9
+ * Create a new ProtectedContentManager
10
+ * @param targetElement Element containing sensitive content to protect
11
+ * @param debugMode Enable debug mode for troubleshooting
12
+ */
13
+ constructor(targetElement, debugMode = false) {
14
+ super("ProtectedContentManager", debugMode);
15
+ this.mediator = null;
16
+ this.originalContent = null;
17
+ // Track content states by owner
18
+ this.contentStates = new Map();
19
+ // Currently active content state
20
+ this.activeStateId = null;
21
+ // Queue of content state IDs waiting to be applied
22
+ this.stateQueue = [];
23
+ this.lastHideReason = '';
24
+ this.targetElement = targetElement;
25
+ }
26
+ /**
27
+ * Set the mediator to communicate with the other components
28
+ * @param mediator The protection mediator instance
29
+ */
30
+ setMediator(mediator) {
31
+ this.mediator = mediator;
32
+ // Subscribe only to general events directly related to content management
33
+ this.mediator.subscribe(ProtectionEventType.CONTENT_HIDDEN, this.handleContentHidden.bind(this), {
34
+ context: this.COMPONENT_NAME,
35
+ });
36
+ this.mediator.subscribe(ProtectionEventType.CONTENT_RESTORED, this.handleContentRestored.bind(this), {
37
+ context: this.COMPONENT_NAME,
38
+ });
39
+ this.logger.log("Mediator set and subscriptions established");
40
+ }
41
+ /**
42
+ * Handle content hidden event
43
+ * @param event The protection event containing content hidden data
44
+ */
45
+ handleContentHidden(event) {
46
+ try {
47
+ this.logger.log(`Received content hidden event from ${event.source}`, event.data);
48
+ // Use type guard for type-safe access
49
+ if (!isEventType(event, ProtectionEventType.CONTENT_HIDDEN)) {
50
+ this.logger.error("Received invalid event type for CONTENT_HIDDEN");
51
+ return;
52
+ }
53
+ const { data } = event;
54
+ if (!data || !data.options)
55
+ return;
56
+ // Only process if this is for our target element or we're the default handler
57
+ if (data.targetElement && data.targetElement !== this.targetElement)
58
+ return;
59
+ // Register the content state
60
+ this.registerContentState(data.strategyName, data.reason, data.options, data.priority || 0);
61
+ }
62
+ catch (error) {
63
+ this.logger.error("Error handling content hidden event", error);
64
+ }
65
+ }
66
+ /**
67
+ * Handle content restored event
68
+ * @param event The protection event containing content restored data
69
+ */
70
+ handleContentRestored(event) {
71
+ try {
72
+ this.logger.log(`Received content restored event from ${event.source}`, event.data);
73
+ // Use type guard for type-safe access
74
+ if (!isEventType(event, ProtectionEventType.CONTENT_RESTORED)) {
75
+ this.logger.error("Received invalid event type for CONTENT_RESTORED");
76
+ return;
77
+ }
78
+ const { data } = event;
79
+ // Only process if this is for our target element or we're the default handler
80
+ if (data && data.targetElement && data.targetElement !== this.targetElement)
81
+ return;
82
+ // Remove content states for this owner
83
+ this.removeContentStatesByOwner(data.strategyName);
84
+ }
85
+ catch (error) {
86
+ this.logger.error("Error handling content restored event", error);
87
+ }
88
+ }
89
+ /**
90
+ * Register a new content state
91
+ * @param owner The strategy or component that owns this state
92
+ * @param reason The reason for hiding content
93
+ * @param options Options for the placeholder
94
+ * @param priority Priority for content hiding (higher numbers take precedence)
95
+ * @returns The ID of the registered content state
96
+ */
97
+ registerContentState(owner, reason, options, priority = 0) {
98
+ // Generate a unique ID for the content state
99
+ const stateId = `content-state-${owner}-${reason}-${Date.now()}`;
100
+ // Create the stored content state object
101
+ const contentState = {
102
+ id: stateId,
103
+ owner,
104
+ reason,
105
+ options: { ...options },
106
+ priority,
107
+ hiddenAt: Date.now(),
108
+ };
109
+ // Store the content state
110
+ this.contentStates.set(stateId, contentState);
111
+ this.logger.log(`Registered content state ${stateId} for ${owner} (${reason})`);
112
+ // If no active state, apply this one immediately
113
+ if (!this.activeStateId) {
114
+ this.applyContentStateById(stateId);
115
+ }
116
+ else {
117
+ // Otherwise, add to queue based on priority
118
+ this.addToQueue(stateId);
119
+ // Check if this state should replace the current one based on priority
120
+ const activeState = this.contentStates.get(this.activeStateId);
121
+ const newState = this.contentStates.get(stateId);
122
+ if (activeState && newState && newState.priority > activeState.priority) {
123
+ this.logger.log("New state has higher priority, replacing active state");
124
+ // Re-queue the displaced active state BEFORE applying the new one,
125
+ // so it can resurface when the new (higher-priority) state is
126
+ // dismissed. Without this step the displaced state is orphaned —
127
+ // it stays in `contentStates` but is neither active nor queued,
128
+ // so the dismiss path falls back to the original content instead
129
+ // of returning to the displaced protection. Mirrors the
130
+ // SecurityOverlayManager re-queue fix in commit 4d14467.
131
+ this.addToQueue(this.activeStateId);
132
+ // Apply the new state
133
+ this.applyContentStateById(stateId);
134
+ }
135
+ }
136
+ return stateId;
137
+ }
138
+ /**
139
+ * Add a content state to the queue
140
+ * @param stateId ID of the content state to add to queue
141
+ */
142
+ addToQueue(stateId) {
143
+ // Add to queue if not already in it
144
+ if (!this.stateQueue.includes(stateId)) {
145
+ this.stateQueue.push(stateId);
146
+ // Sort queue by priority (highest first)
147
+ this.stateQueue.sort((a, b) => {
148
+ const stateA = this.contentStates.get(a);
149
+ const stateB = this.contentStates.get(b);
150
+ if (!stateA || !stateB)
151
+ return 0;
152
+ return stateB.priority - stateA.priority;
153
+ });
154
+ this.logger.log(`Added state ${stateId} to queue, position ${this.stateQueue.indexOf(stateId) + 1}/${this.stateQueue.length}`);
155
+ }
156
+ }
157
+ /**
158
+ * Apply a specific content state by ID
159
+ * @param stateId ID of the content state to apply
160
+ * @returns True if the state was applied successfully
161
+ */
162
+ applyContentStateById(stateId) {
163
+ const state = this.contentStates.get(stateId);
164
+ if (!state)
165
+ return false;
166
+ this.logger.log(`Applying content state ${stateId} (${state.reason})`);
167
+ // Track the reason for hiding content (for callback)
168
+ this.lastHideReason = state.reason;
169
+ // Hide content with the specified options
170
+ this.hideContent(state.options);
171
+ // Set as active state
172
+ this.activeStateId = stateId;
173
+ // Remove from queue if it's in there
174
+ this.stateQueue = this.stateQueue.filter((id) => id !== stateId);
175
+ return true;
176
+ }
177
+ /**
178
+ * Remove content states for a specific owner
179
+ * @param owner The owner to remove states for
180
+ * @returns The number of states removed
181
+ */
182
+ removeContentStatesByOwner(owner) {
183
+ let removedCount = 0;
184
+ const statesToRemove = [];
185
+ // Find all states owned by this owner
186
+ for (const [stateId, state] of this.contentStates.entries()) {
187
+ if (state.owner === owner) {
188
+ statesToRemove.push(stateId);
189
+ }
190
+ }
191
+ // Remove each state
192
+ for (const stateId of statesToRemove) {
193
+ this.contentStates.delete(stateId);
194
+ removedCount++;
195
+ // If this was the active state, we need to restore content or apply the next state
196
+ if (this.activeStateId === stateId) {
197
+ this.activeStateId = null;
198
+ // Check if there are other states in the queue
199
+ if (this.stateQueue.length > 0) {
200
+ // Apply the next state in the queue
201
+ const nextStateId = this.stateQueue.shift();
202
+ if (nextStateId) {
203
+ this.applyContentStateById(nextStateId);
204
+ }
205
+ }
206
+ else {
207
+ // No more states, restore the original content
208
+ this.restoreContent();
209
+ }
210
+ }
211
+ else {
212
+ // If it wasn't active, just remove from queue if present
213
+ this.stateQueue = this.stateQueue.filter((id) => id !== stateId);
214
+ }
215
+ }
216
+ if (removedCount > 0) {
217
+ this.logger.log(`Removed ${removedCount} content states for owner ${owner}`);
218
+ }
219
+ return removedCount;
220
+ }
221
+ /**
222
+ * Hide the original content and replace it with a placeholder
223
+ * @param options Options for customizing the placeholder
224
+ * @returns True if content was hidden, false if there was no content to hide
225
+ */
226
+ hideContent(options) {
227
+ if (!this.targetElement)
228
+ return false;
229
+ // Store original content if not already stored
230
+ if (this.originalContent === null) {
231
+ this.originalContent = this.targetElement.innerHTML;
232
+ this.logger.log("Original content stored");
233
+ }
234
+ // Create placeholder content with custom styles
235
+ const placeholderStyles = {
236
+ padding: "20px",
237
+ textAlign: "center",
238
+ color: options.textColor || "white",
239
+ backgroundColor: options.backgroundColor || "rgba(0, 0, 0, 0.05)",
240
+ borderRadius: "8px",
241
+ margin: "20px",
242
+ boxShadow: "0 2px 10px rgba(0, 0, 0, 0.1)",
243
+ };
244
+ // Convert styles object to inline style string
245
+ const styleString = Object.entries(placeholderStyles)
246
+ .map(([key, value]) => `${key}: ${value}`)
247
+ .join("; ");
248
+ // Replace content with a placeholder that uses the options text
249
+ this.targetElement.innerHTML = `
250
+ <div style="${styleString}">
251
+ <h2 style="font-size: 24px; margin-bottom: 20px; color: ${options.textColor || "black"};">
252
+ ${options.title || "Content Protected"}
253
+ </h2>
254
+ <p style="font-size: 16px; margin-bottom: 15px; color: ${options.textColor || "black"};">
255
+ ${options.message || "This content is protected for security reasons."}
256
+ </p>
257
+ ${options.secondaryMessage
258
+ ? `
259
+ <p style="font-size: 16px; color: ${options.textColor || "black"};">
260
+ ${options.secondaryMessage}
261
+ </p>
262
+ `
263
+ : ""}
264
+ <div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, 0.2);">
265
+ <p style="font-size: 14px; color: ${options.textColor || "black"}; opacity: 0.8;">
266
+ This content is protected by ContentSecurityToolkit
267
+ </p>
268
+ </div>
269
+ </div>
270
+ `;
271
+ this.logger.log("Content hidden");
272
+ // Call the onContentHidden callback if registered
273
+ if (this.onContentHiddenCallback) {
274
+ try {
275
+ this.onContentHiddenCallback(this.lastHideReason || 'unknown', this.targetElement);
276
+ this.logger.log("onContentHidden callback invoked");
277
+ }
278
+ catch (error) {
279
+ this.logger.error("Error in onContentHidden callback", error);
280
+ }
281
+ }
282
+ return true;
283
+ }
284
+ /**
285
+ * Restore the original content
286
+ * @returns True if content was restored, false if there was no content to restore
287
+ */
288
+ restoreContent() {
289
+ if (!this.targetElement || this.originalContent === null)
290
+ return false;
291
+ // Restore the original content
292
+ this.targetElement.innerHTML = this.originalContent;
293
+ this.originalContent = null;
294
+ this.logger.log("Original content restored");
295
+ // Call the onContentRestored callback if registered
296
+ if (this.onContentRestoredCallback) {
297
+ try {
298
+ this.onContentRestoredCallback(this.targetElement);
299
+ this.logger.log("onContentRestored callback invoked");
300
+ }
301
+ catch (error) {
302
+ this.logger.error("Error in onContentRestored callback", error);
303
+ }
304
+ }
305
+ return true;
306
+ }
307
+ /**
308
+ * Check if content is currently hidden
309
+ * @returns True if content is hidden, false otherwise
310
+ */
311
+ isContentHidden() {
312
+ return this.originalContent !== null;
313
+ }
314
+ /**
315
+ * Get the currently active content state ID
316
+ * @returns The active content state ID or null if none is active
317
+ */
318
+ getActiveContentStateId() {
319
+ return this.activeStateId;
320
+ }
321
+ /**
322
+ * Get all content states for a specific owner
323
+ * @param owner The owner to get states for
324
+ * @returns Array of content state IDs
325
+ */
326
+ getContentStatesByOwner(owner) {
327
+ const stateIds = [];
328
+ for (const [stateId, state] of this.contentStates.entries()) {
329
+ if (state.owner === owner) {
330
+ stateIds.push(stateId);
331
+ }
332
+ }
333
+ return stateIds;
334
+ }
335
+ /**
336
+ * Update the target element
337
+ * @param element New target element
338
+ */
339
+ updateTargetElement(element) {
340
+ // If content is hidden, restore it before changing the target
341
+ if (this.isContentHidden()) {
342
+ this.restoreContent();
343
+ }
344
+ this.targetElement = element;
345
+ // If we had an active state, reapply it to the new target
346
+ if (this.activeStateId) {
347
+ const activeState = this.contentStates.get(this.activeStateId);
348
+ if (activeState) {
349
+ this.hideContent(activeState.options);
350
+ }
351
+ }
352
+ this.logger.log("Target element updated");
353
+ }
354
+ /**
355
+ * Get the current target element
356
+ * @returns The current target element
357
+ */
358
+ getTargetElement() {
359
+ return this.targetElement;
360
+ }
361
+ /**
362
+ * Set callbacks for content visibility changes
363
+ * Useful for frameworks like Vue that need to re-mount components after content restoration
364
+ * @param onHidden Callback invoked when content is hidden
365
+ * @param onRestored Callback invoked when content is restored
366
+ */
367
+ setContentCallbacks(onHidden, onRestored) {
368
+ this.onContentHiddenCallback = onHidden;
369
+ this.onContentRestoredCallback = onRestored;
370
+ this.logger.log("Content callbacks set");
371
+ }
372
+ /**
373
+ * Clear all content states
374
+ * @returns The number of states removed
375
+ */
376
+ clearAllContentStates() {
377
+ const stateCount = this.contentStates.size;
378
+ // Restore content if it's hidden
379
+ if (this.isContentHidden()) {
380
+ this.restoreContent();
381
+ }
382
+ // Clear all states and queue
383
+ this.contentStates.clear();
384
+ this.stateQueue = [];
385
+ this.activeStateId = null;
386
+ if (stateCount > 0) {
387
+ this.logger.log(`Cleared all ${stateCount} content states`);
388
+ }
389
+ return stateCount;
390
+ }
391
+ /**
392
+ * Get debug information about content states
393
+ * @returns Object with debug information
394
+ */
395
+ getDebugInfo() {
396
+ const statesByOwner = {};
397
+ const statesByReason = {};
398
+ let totalStates = 0;
399
+ const stateDetails = [];
400
+ for (const [stateId, state] of this.contentStates.entries()) {
401
+ totalStates++;
402
+ // Count by owner
403
+ statesByOwner[state.owner] = (statesByOwner[state.owner] || 0) + 1;
404
+ // Count by reason
405
+ statesByReason[state.reason] = (statesByReason[state.reason] || 0) + 1;
406
+ // Add detailed state info
407
+ stateDetails.push({
408
+ id: stateId,
409
+ owner: state.owner,
410
+ reason: state.reason,
411
+ priority: state.priority,
412
+ hiddenAt: state.hiddenAt,
413
+ });
414
+ }
415
+ return {
416
+ totalStates,
417
+ statesByOwner,
418
+ statesByReason,
419
+ activeStateId: this.activeStateId,
420
+ queueLength: this.stateQueue.length,
421
+ stateDetails,
422
+ };
423
+ }
424
+ }
@@ -0,0 +1,253 @@
1
+ import type { MediatorAware, ProtectionMediator } from "../core/mediator/types";
2
+ import { LoggableComponent } from "./base/LoggableComponent";
3
+ /**
4
+ * Options for the security overlay
5
+ */
6
+ export interface OverlayOptions {
7
+ /**
8
+ * Title to display in the overlay
9
+ */
10
+ title?: string;
11
+ /**
12
+ * Main message to display
13
+ */
14
+ message?: string;
15
+ /**
16
+ * Secondary message to display
17
+ */
18
+ secondaryMessage?: string;
19
+ /**
20
+ * Text color for the overlay
21
+ */
22
+ textColor?: string;
23
+ /**
24
+ * Background color for the overlay
25
+ */
26
+ backgroundColor?: string;
27
+ /**
28
+ * Z-index for the overlay (default: 2147483647)
29
+ */
30
+ zIndex?: string;
31
+ /**
32
+ * Whether to show a close button
33
+ */
34
+ showCloseButton?: boolean;
35
+ /**
36
+ * Text for the close button
37
+ */
38
+ closeButtonText?: string;
39
+ /**
40
+ * Callback when close button is clicked
41
+ */
42
+ onCloseButtonClick?: () => void;
43
+ /**
44
+ * Duration in milliseconds to show the overlay (0 for indefinite)
45
+ */
46
+ duration?: number;
47
+ /**
48
+ * Additional custom styles for the overlay
49
+ */
50
+ customStyles?: Record<string, string>;
51
+ /**
52
+ * Additional custom styles for the text
53
+ */
54
+ textStyles?: Record<string, string>;
55
+ /**
56
+ * Font size (ScreenshotStrategy - refactor)
57
+ */
58
+ fontSize?: string;
59
+ /**
60
+ * Additional HTML content to display in the overlay
61
+ */
62
+ additionalContent?: string;
63
+ /**
64
+ * Whether to block events (create an event blocker)
65
+ */
66
+ blockEvents?: boolean;
67
+ /**
68
+ * Whether to automatically restore the overlay if it's removed from the DOM
69
+ * @default true
70
+ */
71
+ autoRestore?: boolean;
72
+ }
73
+ /**
74
+ * Utility class to manage security overlays
75
+ */
76
+ export declare class SecurityOverlayManager extends LoggableComponent implements MediatorAware {
77
+ private mediator;
78
+ private domObserver;
79
+ private overlays;
80
+ private activeOverlayId;
81
+ private overlayQueue;
82
+ private onElementsRemovedCallbacks;
83
+ /**
84
+ * Create a new SecurityOverlayManager
85
+ * @param debugMode Enable debug mode for troubleshooting
86
+ */
87
+ constructor(debugMode?: boolean);
88
+ /**
89
+ * Set the mediator to communicate with the other components
90
+ * @param mediator The protection mediator
91
+ */
92
+ setMediator(mediator: ProtectionMediator): void;
93
+ /**
94
+ * Check if an overlay with the same owner and type already exists
95
+ * @param owner The owner to check
96
+ * @param overlayType The overlay type to check
97
+ * @returns True if a matching overlay exists
98
+ */
99
+ private hasOverlayByOwnerAndType;
100
+ /**
101
+ * Handle overlay shown event
102
+ * @param event The protection event
103
+ */
104
+ private handleOverlayShown;
105
+ /**
106
+ * Handle overlay removed event
107
+ * @param event The protection event
108
+ */
109
+ private handleOverlayRemoved;
110
+ /**
111
+ * Handle overlay restored event
112
+ * @param event The protection event
113
+ */
114
+ private handleOverlayRestored;
115
+ /**
116
+ * Register a new overlay
117
+ * @param owner The strategy or component that owns this overlay
118
+ * @param overlayType The type of overlay (e.g., "screenshot", "devtools")
119
+ * @param options Options for the overlay
120
+ * @param priority Priority for display order (higher displays on top)
121
+ * @returns The ID of the registered overlay
122
+ */
123
+ registerOverlay(owner: string, overlayType: string, options: OverlayOptions, priority?: number): string;
124
+ /**
125
+ * Add an overlay to the queue
126
+ * @param overlayId ID of the overlay to add to queue
127
+ */
128
+ private addToQueue;
129
+ /**
130
+ * Show a specific overlay by ID
131
+ * @param overlayId ID of the overlay to show
132
+ * @returns True if the overlay was shown successfully
133
+ */
134
+ private showOverlayById;
135
+ /**
136
+ * Hide a specific overlay by ID without removing it from storage
137
+ * @param overlayId ID of the overlay to hide
138
+ * @param processQueue Whether to process the queue after hiding
139
+ * @returns True if the overlay was hidden successfully
140
+ */
141
+ private hideOverlayById;
142
+ /**
143
+ * Create overlay and blocker elements
144
+ * @param overlay The stored overlay information
145
+ * @returns Object containing the created elements
146
+ */
147
+ private createOverlayElements;
148
+ /**
149
+ * Remove a specific overlay by ID
150
+ * @param overlayId ID of the overlay to remove
151
+ * @returns True if the overlay was removed successfully
152
+ */
153
+ removeOverlayById(overlayId: string): boolean;
154
+ /**
155
+ * Remove all overlays for a specific owner
156
+ * @param owner The owner to remove overlays for
157
+ * @returns The number of overlays removed
158
+ */
159
+ removeOverlaysByOwner(owner: string): number;
160
+ /**
161
+ * Check and restore overlays for a specific owner
162
+ * @param owner The owner to check overlays for
163
+ * @returns The number of overlays restored
164
+ */
165
+ checkAndRestoreOverlaysByOwner(owner: string): number;
166
+ /**
167
+ * Create an overlay element
168
+ * @param options Options for the overlay
169
+ * @param owner The owner of the overlay (for data attribute)
170
+ * @returns The created overlay element
171
+ */
172
+ private createOverlay;
173
+ /**
174
+ * Create an event blocker that prevents interaction with the page
175
+ * @returns The created event blocker element
176
+ */
177
+ private createEventBlocker;
178
+ /**
179
+ * Set up DOM observer to detect when overlay elements are removed
180
+ * @param overlay The overlay to observe
181
+ */
182
+ private setupObserver;
183
+ /**
184
+ * Remove global event listeners that were added to document and window
185
+ */
186
+ private removeGlobalEventListeners;
187
+ /**
188
+ * Notify all callbacks when elements are removed
189
+ * @param removedElements The elements that were removed
190
+ */
191
+ private notifyElementsRemovedCallbacks;
192
+ /**
193
+ * Add a callback to be called when overlay elements are removed
194
+ * @param callback Callback function
195
+ */
196
+ addElementsRemovedCallback(callback: (removedElements: HTMLElement[]) => void): void;
197
+ /**
198
+ * Remove a callback
199
+ * @param callback Callback function to remove
200
+ */
201
+ removeElementsRemovedCallback(callback: (removedElements: HTMLElement[]) => void): void;
202
+ /**
203
+ * Get all overlays for a specific owner
204
+ * @param owner The owner to get overlays for
205
+ * @returns Array of overlay IDs
206
+ */
207
+ getOverlaysByOwner(owner: string): string[];
208
+ /**
209
+ * Get all active overlays
210
+ * @returns Array of active overlay IDs
211
+ */
212
+ getActiveOverlays(): string[];
213
+ /**
214
+ * Check if an overlay exists
215
+ * @param overlayId The overlay ID
216
+ * @returns True if the overlay exists
217
+ */
218
+ hasOverlay(overlayId: string): boolean;
219
+ /**
220
+ * Get the currently active overlay ID
221
+ * @returns The active overlay ID or null if none is active
222
+ */
223
+ getActiveOverlayId(): string | null;
224
+ /**
225
+ * Get the overlay queue
226
+ * @returns Array of overlay IDs in the queue
227
+ */
228
+ getOverlayQueue(): string[];
229
+ /**
230
+ * Clear all overlays
231
+ * @returns The number of overlays removed
232
+ */
233
+ clearAllOverlays(): number;
234
+ /**
235
+ * Get debug information about registered overlays
236
+ * @returns Object with debug information
237
+ */
238
+ getDebugInfo(): {
239
+ totalOverlays: number;
240
+ overlaysByOwner: Record<string, number>;
241
+ overlaysByType: Record<string, number>;
242
+ activeOverlayId: string | null;
243
+ queueLength: number;
244
+ overlayDetails: Array<{
245
+ id: string;
246
+ owner: string;
247
+ type: string;
248
+ isVisible: boolean;
249
+ priority: number;
250
+ createdAt: number;
251
+ }>;
252
+ };
253
+ }