content-security-toolkit 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,45 @@
1
1
  # Content Security Toolkit
2
2
 
3
- A comprehensive toolkit for implementing content security measures in web applications.
3
+ > ## ⚠️ Deprecated use [`@tindalabs/shield`](https://www.npmjs.com/package/@tindalabs/shield) instead
4
+ >
5
+ > This package has been superseded by **[`@tindalabs/shield`](https://github.com/tindalabs/shield)**, which keeps the entire `ContentProtector` API and adds structured risk assessment (`assess()`), an OpenTelemetry integration (`attachShieldToSpan()`), a declarative policy engine (`assessAndProtect()`), and zero runtime dependencies.
6
+ >
7
+ > **Migrate in two lines:**
8
+ >
9
+ > ```bash
10
+ > npm uninstall content-security-toolkit
11
+ > npm install @tindalabs/shield
12
+ > ```
13
+ >
14
+ > ```ts
15
+ > // Before: import { ContentProtector } from 'content-security-toolkit';
16
+ > // After: import { ContentProtector } from '@tindalabs/shield';
17
+ > ```
18
+ >
19
+ > Every `ContentProtector` option you used here works identically in Shield. Full migration guide: [github.com/tindalabs/shield/blob/main/MIGRATION.md](https://github.com/tindalabs/shield/blob/main/MIGRATION.md). See also [DEPRECATED.md](./DEPRECATED.md).
20
+ >
21
+ > Existing installs continue to work — the package is **not** unpublished. Security fixes and new features land in Shield only.
22
+
23
+ ---
24
+
25
+ [![npm version](https://img.shields.io/npm/v/content-security-toolkit.svg)](https://www.npmjs.com/package/content-security-toolkit) [![Build Status](https://github.com/Isonimus/content-security-toolkit/actions/workflows/publish.yml/badge.svg)](https://github.com/Isonimus/content-security-toolkit/actions) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
26
+
27
+ A comprehensive toolkit for implementing content security measures in web applications — lightweight, modular, and TypeScript-friendly.
4
28
 
5
29
  ## Features
6
30
 
7
- - Prevent keyboard shortcuts (Ctrl+P, Ctrl+S, etc.)
8
- - Disable context menu (right-click)
9
- - Block printing attempts
10
- - Add watermarks to content
11
- - Works across desktop and mobile browsers
12
- - Highly configurable and extensible
31
+ - Developer tools detection and response (DevTools detection)
32
+ - Screenshot detection and response (blur, warnings, callbacks)
33
+ - Watermarking with automatic regeneration (MutationObserver-protected)
34
+ - Keyboard shortcut prevention (copy/print/inspect shortcuts)
35
+ - Context menu blocking
36
+ - Print prevention and watermark-on-print support
37
+ - Selection / copy prevention
38
+ - Extension detection (detect suspicious browser extensions)
39
+ - Frame embedding protection (prevent unauthorized iframe embedding)
40
+ - Modular, strategy-based architecture — enable/disable strategies independently
41
+ - TypeScript typings, tests, and CI-ready workflow
42
+ - Lightweight and easy to integrate into web apps
13
43
 
14
44
  ## Installation
15
45
 
@@ -17,7 +47,102 @@ A comprehensive toolkit for implementing content security measures in web applic
17
47
  npm install content-security-toolkit
18
48
  # or
19
49
  yarn add content-security-toolkit
20
-
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ ### Simple usage (quick start)
55
+
56
+ ```javascript
57
+ import { ContentProtector } from 'content-security-toolkit'
58
+
59
+ // Protect the whole document with sensible defaults
60
+ const protector = new ContentProtector()
61
+ protector.protect()
62
+
63
+ // Later...
64
+ protector.unprotect()
65
+ protector.dispose()
66
+ ```
67
+
68
+ ### Custom usage (advanced configuration)
69
+
70
+ ```javascript
71
+ import { ContentProtector } from 'content-security-toolkit'
72
+
73
+ const protector = new ContentProtector({
74
+ targetElement: '#viewer', // CSS selector or HTMLElement
75
+ enableWatermark: true,
76
+ watermarkOptions: {
77
+ text: 'CONFIDENTIAL',
78
+ opacity: 0.12,
79
+ density: 3,
80
+ },
81
+ preventDevTools: true,
82
+ preventScreenshots: true,
83
+ preventEmbedding: true,
84
+ debugMode: false,
85
+ // Optional callbacks
86
+ customHandlers: {
87
+ onDevToolsDetected: () => console.warn('DevTools opened'),
88
+ onScreenshotDetected: () => alert('Screenshot detected'),
89
+ },
90
+ })
91
+
92
+ protector.protect()
93
+ ```
94
+
95
+ ### Framework quick examples
96
+
97
+ React (hooks):
98
+
99
+ ```jsx
100
+ import React, { useEffect } from 'react'
101
+ import { ContentProtector } from 'content-security-toolkit'
102
+
103
+ function Viewer() {
104
+ useEffect(() => {
105
+ const protector = new ContentProtector({ enableWatermark: true })
106
+ protector.protect()
107
+ return () => protector.dispose()
108
+ }, [])
109
+
110
+ return <div id="protected-content">Protected content</div>
111
+ }
112
+ ```
113
+
114
+ Vue 3 (Composition API):
115
+
116
+ ```js
117
+ import { onMounted, onUnmounted } from 'vue'
118
+ import { ContentProtector } from 'content-security-toolkit'
119
+
120
+ export default {
121
+ setup() {
122
+ let protector
123
+ onMounted(() => {
124
+ protector = new ContentProtector({ targetElement: '#protected-content' })
125
+ protector.protect()
126
+ })
127
+ onUnmounted(() => protector?.dispose())
128
+ },
129
+ }
130
+ ```
131
+
132
+ ### API highlights
133
+
134
+ - `ContentProtector.protect()` — enable protection
135
+ - `ContentProtector.unprotect()` — disable protection
136
+ - `ContentProtector.dispose()` — cleanup resources
137
+ - `ContentProtector.getStrategy(name)` — access a strategy instance for advanced control
138
+ - Options include: `targetElement`, `enableWatermark`, `watermarkOptions`, `preventDevTools`, `preventScreenshots`, `preventEmbedding`, `debugMode`, `customHandlers`
139
+
140
+ _For full examples, see `examples/` and `examples/advanced/advanced_example.ts`._
141
+ ### Where to start
142
+
143
+ - Use the simple example to get protection running quickly.
144
+ - Add `customHandlers` and `watermarkOptions` to tailor behaviour.
145
+ - See `examples/` for runnable demos and the `src/` folder for strategy implementations.
21
146
 
22
147
  Content Security Toolkit is a comprehensive JavaScript/TypeScript library designed to protect sensitive web content from unauthorized copying, extraction, and distribution. It implements multiple layers of protection strategies that work together to safeguard digital content while maintaining a good user experience for legitimate users.
23
148
 
@@ -42,46 +167,56 @@ This architecture allows for flexible configuration and easy extension with new
42
167
 
43
168
  **Implementation Details**:
44
169
 
45
- - Intercepts key combinations like Ctrl+C, Ctrl+P, Ctrl+S, Ctrl+Shift+I
170
+ - Intercepts key combinations like Ctrl/Cmd+C, Ctrl/Cmd+P, Ctrl/Cmd+S, Ctrl+Shift+I
46
171
  - Configurable to block specific shortcuts
47
172
  - Provides custom event handlers for blocked shortcuts
48
173
 
49
174
 
50
- ### 2. Context Menu Protection (ContextMenuStrategy)
175
+ ### 2. Clipboard Protection (ClipboardStrategy)
176
+
177
+ **Purpose**: Intercepts clipboard operations to prevent programmatic copying or tampering via clipboard events.
178
+
179
+ **Implementation Details**:
180
+
181
+ - Listens to `copy`, `cut` and `paste` events
182
+ - Can clear or override clipboard data or present a custom handler
183
+ - Useful in combination with selection and context menu protections
184
+
51
185
 
52
- **Purpose**: Prevents users from accessing the browser's context menu (right-click menu) to copy content or view page source.
186
+ ### 3. Context Menu Protection (ContextMenuStrategy)
187
+
188
+ **Purpose**: Prevents users from accessing the browser's context menu (right-click menu) to copy content, save assets, or inspect elements.
53
189
 
54
190
  **Implementation Details**:
55
191
 
56
- - Intercepts the contextmenu event on specified elements
192
+ - Intercepts the `contextmenu` event on specified elements
57
193
  - Can be applied to the entire document or specific elements
58
- - Supports custom handler for context menu attempts
194
+ - Supports custom handler for right-click attempts
59
195
 
60
196
 
61
- ### 3. Print Protection (PrintStrategy)
197
+ ### 4. Print Protection (PrintStrategy)
62
198
 
63
- **Purpose**: Prevents users from printing the page or using the browser's print functionality.
199
+ **Purpose**: Prevents or modifies the browser's print behavior to protect content (optionally watermark on print).
64
200
 
65
201
  **Implementation Details**:
66
202
 
67
- - Intercepts print events (window.print, Ctrl+P)
68
- - Optionally displays a custom message when print is attempted
69
- - Can be configured to allow printing but with watermarks
203
+ - Intercepts `window.print` and print keyboard shortcuts
204
+ - Optionally adds a print-only watermark or blocks printing
205
+ - Provides hooks for custom messaging when print is attempted
70
206
 
71
207
 
72
- ### 4. Selection Protection (SelectionStrategy)
208
+ ### 5. Selection Protection (SelectionStrategy)
73
209
 
74
210
  **Purpose**: Prevents users from selecting and copying text content.
75
211
 
76
212
  **Implementation Details**:
77
213
 
78
214
  - Disables text selection via CSS and JavaScript
79
- - Intercepts selection events
80
- - Can be applied to specific elements or the entire document
81
- - Supports custom handler for selection attempts
215
+ - Intercepts selection events and clears selection ranges
216
+ - Can be applied selectively to elements or site-wide
82
217
 
83
218
 
84
- ### 5. Watermark Protection (WatermarkStrategy)
219
+ ### 6. Watermark Protection (WatermarkStrategy)
85
220
 
86
221
  **Purpose**: Adds visible watermarks to the content to discourage unauthorized sharing and identify the source.
87
222
 
@@ -91,30 +226,51 @@ This architecture allows for flexible configuration and easy extension with new
91
226
  - Supports customization of text, opacity, density, and positioning
92
227
  - Includes user identification (userId) to trace leaked content
93
228
  - **Observer Mechanism**: Implements a MutationObserver to detect when watermarks are removed from the DOM and automatically regenerates them
94
- - Watermarks are positioned in a way that makes them difficult to remove without affecting the content
95
229
 
96
230
 
97
- ### 6. DevTools Protection (DevToolsStrategy)
231
+ ### 7. DevTools Protection (DevToolsStrategy)
98
232
 
99
233
  **Purpose**: Detects and responds to attempts to open browser developer tools, which could be used to inspect and modify the page.
100
234
 
101
235
  **Implementation Details**:
102
236
 
103
- - Uses multiple detection techniques (window.devtools, console timing, resize detection)
237
+ - Uses multiple detection techniques (console timing, resize detection, feature checks)
104
238
  - Provides callbacks when DevTools are opened or closed
105
- - Can be configured to take specific actions when DevTools are detected
239
+ - Can be configured to take specific actions (log, blur, overlay) when DevTools are detected
106
240
 
107
241
 
108
- ### 7. Screenshot Protection (ScreenshotStrategy)
242
+ ### 8. Screenshot Protection (ScreenshotStrategy)
109
243
 
110
244
  **Purpose**: Detects and responds to screenshot attempts.
111
245
 
112
246
  **Implementation Details**:
113
247
 
114
- - Monitors clipboard events and screen capture APIs
115
- - Blurs content or displays warning message during screenshot attempts
248
+ - Monitors clipboard events and screen capture API usage
249
+ - Blurs content or displays a warning message during screenshot attempts
116
250
  - Provides callbacks when screenshot attempts are detected
117
- - Uses visual tricks to make screenshots less useful (temporary content blurring)
251
+ - Uses visual techniques to make screenshots less useful (temporary content blurring)
252
+
253
+
254
+ ### 9. Extension Detection (BrowserExtensionDetectionStrategy)
255
+
256
+ **Purpose**: Detects suspicious or known browser extensions that may bypass protections.
257
+
258
+ **Implementation Details**:
259
+
260
+ - Heuristics and detection strategies to identify extensions
261
+ - Callbacks for detected extensions
262
+ - Optionally disable protections or report detections to a backend
263
+
264
+
265
+ ### 10. Frame Embedding Protection (FrameEmbeddingProtectionStrategy)
266
+
267
+ **Purpose**: Detects and prevents the page from being embedded into unauthorized frames.
268
+
269
+ **Implementation Details**:
270
+
271
+ - Checks `top`/`window` relationships and hostnames
272
+ - Optionally break out of frames or display a blocking overlay
273
+ - Configurable whitelist of allowed origins
118
274
 
119
275
 
120
276
  ## Technical Deep Dive
@@ -145,16 +301,27 @@ The screenshot protection uses several techniques to detect and respond to scree
145
301
 
146
302
  ## Known Limitations and Issues
147
303
 
148
- While Content Security Toolkit provides robust protection, it's important to understand its limitations:
304
+ While Content Security Toolkit provides robust protection, it's important to understand its limitations and where protections are best applied.
305
+
306
+ ### Browser compatibility & limitations
307
+
308
+ | Feature | Desktop | Mobile | Notes |
309
+ |---|---:|---:|---|
310
+ | DevTools detection | Good on modern Chromium & Firefox | Limited | Mobile devices have limited toolsets; detection techniques may be unreliable.
311
+ | Screenshot detection | Partial | Partial | Can detect some screen-capture APIs and clipboard activity; cannot prevent OS-level screenshots or photos.
312
+ | Watermarking | Good | Good | MutationObserver + DOM-based watermarks work on modern browsers; heavy density may impact layout and perf.
313
+ | Extension detection | Limited | N/A | Heuristic-based; may produce false positives and won't detect all malicious extensions.
314
+ | Frame embedding protection | Good | Good | Works when combined with proper server headers (CSP/X-Frame-Options) for stronger enforcement.
315
+
316
+ > Notes: Protections operate in the browser and are best used as a **deterrent** and part of defense-in-depth. They are not a substitute for server-side access control or legal protections.
317
+
318
+ ### Other important limitations
149
319
 
150
- 1. **Client-Side Only**: As a JavaScript library, all protections run in the browser and can potentially be circumvented by determined users with technical knowledge.
151
- 2. **No Server-Side Validation**: The library doesn't include server-side components to validate content access or enforce permissions beyond the browser.
152
- 3. **Browser Compatibility**: Some protection strategies rely on modern browser APIs and may not work in older browsers.
153
- 4. **Mobile Limitations**: Some protections (particularly DevTools detection) are less effective on mobile devices.
154
- 5. **Accessibility Impact**: Content protection measures can interfere with accessibility tools. Care should be taken to ensure content remains accessible to users with disabilities.
155
- 6. **Performance Considerations**: Extensive protection, particularly watermarking with high density, can impact page performance.
156
- 7. **Hardware Screenshots**: The library cannot prevent screenshots taken using physical cameras or external hardware.
157
- 8. **Browser Extensions**: Some browser extensions might interfere with or bypass certain protection mechanisms.
320
+ - **Client-Side Only**: All protections run in the browser and can potentially be bypassed by determined attackers.
321
+ - **Accessibility Impact**: Some protections can affect accessibility tools; test and provide alternative access for users who need it.
322
+ - **Performance Considerations**: High-density watermarks or many simultaneous observers may impact rendering performance on low-end devices.
323
+ - **Hardware Screenshots**: Cannot prevent photos taken with external cameras or devices.
324
+ - **Browser Extensions**: Extensions may interfere with or bypass protections; treat extension detection as heuristic rather than absolute.
158
325
 
159
326
  Unlike DRM systems that encrypt content and control playback through specialized software, Content Security Toolkit focuses on preventing common extraction methods while maintaining compatibility with standard web browsers. It's designed as a deterrent rather than an unbreakable protection system.
160
327
 
@@ -168,4 +335,21 @@ For optimal protection, consider these implementation guidelines:
168
335
  4. **Selective Protection**: Apply protection only to sensitive content to minimize performance impact
169
336
  5. **Regular Updates**: Keep the library updated to benefit from security improvements
170
337
  6. **Complementary Measures**: Combine with server-side protections and legal terms of use
171
- 7. **Accessibility Considerations**: Test with accessibility tools and provide alternative access methods for legitimate users with special needs
338
+ 7. **Accessibility Considerations**: Test with accessibility tools and provide alternative access methods for legitimate users with special needs
339
+
340
+ ## Contributing
341
+
342
+ Contributions are welcome! To contribute:
343
+
344
+ - Fork the repository and create a feature branch from `main`.
345
+ - Run `npm install`, `npm run lint`, `npm test`, and `npm run build` locally before pushing.
346
+ - Open a clear pull request explaining the change and link any relevant issues.
347
+ - Add tests for new behavior and update the README/examples when adding features.
348
+
349
+ Please be respectful and follow the project's Code of Conduct (see below).
350
+
351
+ ## Code of Conduct
352
+
353
+ This project follows the Contributor Covenant. By participating you agree to the terms in `CODE_OF_CONDUCT.md`.
354
+
355
+ ---
package/dist/index.d.ts CHANGED
@@ -2,3 +2,5 @@ export { ContentProtector } from './core/index.js';
2
2
  export * from './types/index.js';
3
3
  export * from './strategies/index.js';
4
4
  export * from './utils/index.js';
5
+ export { attachShieldToSpan } from './otel.js';
6
+ export type { SpanLike, SpanProvider } from './otel.js';
package/dist/index.js CHANGED
@@ -3,3 +3,4 @@ export { ContentProtector } from './core/index.js';
3
3
  export * from './types/index.js';
4
4
  export * from './strategies/index.js';
5
5
  export * from './utils/index.js';
6
+ export { attachShieldToSpan } from './otel.js';
package/dist/otel.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { ContentProtector } from '@/core/index.js';
2
+ import type { ContentProtectionOptions } from '@/types/index.js';
3
+ /**
4
+ * Minimal span interface — matches @opentelemetry/api Span without requiring
5
+ * it as a dependency. Pass any object with addEvent() — including real OTel spans
6
+ * or a Blindspot route span from getRouteSpan().
7
+ */
8
+ export interface SpanLike {
9
+ addEvent(name: string, attributes?: Record<string, string | number | boolean>): void;
10
+ }
11
+ export type SpanProvider = () => SpanLike | null | undefined;
12
+ /**
13
+ * Creates a ContentProtector with all callbacks wired to OTel span events.
14
+ *
15
+ * Pass any existing customHandlers in options — they run after the span event
16
+ * is recorded, so UI state updates and span recording both happen.
17
+ *
18
+ * @example
19
+ * // With Blindspot:
20
+ * import { getRouteSpan } from '@tindalabs/blindspot-web';
21
+ * const protector = attachShieldToSpan(options, () => getRouteSpan());
22
+ * protector.protect();
23
+ */
24
+ export declare function attachShieldToSpan(options: ContentProtectionOptions, spanProvider: SpanProvider): ContentProtector;
package/dist/otel.js ADDED
@@ -0,0 +1,87 @@
1
+ import { ContentProtector } from '@/core/index.js';
2
+ function emit(provider, name, attrs) {
3
+ try {
4
+ provider()?.addEvent(name, attrs);
5
+ }
6
+ catch { /* never let telemetry crash the app */ }
7
+ }
8
+ /**
9
+ * Creates a ContentProtector with all callbacks wired to OTel span events.
10
+ *
11
+ * Pass any existing customHandlers in options — they run after the span event
12
+ * is recorded, so UI state updates and span recording both happen.
13
+ *
14
+ * @example
15
+ * // With Blindspot:
16
+ * import { getRouteSpan } from '@tindalabs/blindspot-web';
17
+ * const protector = attachShieldToSpan(options, () => getRouteSpan());
18
+ * protector.protect();
19
+ */
20
+ export function attachShieldToSpan(options, spanProvider) {
21
+ const existing = options.customHandlers ?? {};
22
+ const handlers = {
23
+ ...existing,
24
+ onDevToolsOpen(isOpen) {
25
+ emit(spanProvider, isOpen ? 'shield.devtools.opened' : 'shield.devtools.closed');
26
+ existing.onDevToolsOpen?.(isOpen);
27
+ },
28
+ onSelectionAttempt(event) {
29
+ emit(spanProvider, 'shield.selection.attempted');
30
+ existing.onSelectionAttempt?.(event);
31
+ },
32
+ onContextMenuAttempt(event) {
33
+ emit(spanProvider, 'shield.context_menu.attempted');
34
+ existing.onContextMenuAttempt?.(event);
35
+ },
36
+ onPrintAttempt(event) {
37
+ emit(spanProvider, 'shield.print.attempted');
38
+ existing.onPrintAttempt?.(event);
39
+ },
40
+ onKeyboardShortcutBlocked(event) {
41
+ emit(spanProvider, 'shield.keyboard_shortcut.blocked', {
42
+ 'shield.keyboard.key': event.key,
43
+ 'shield.keyboard.code': event.code,
44
+ });
45
+ existing.onKeyboardShortcutBlocked?.(event);
46
+ },
47
+ onClipboardAttempt(event, action) {
48
+ emit(spanProvider, `shield.clipboard.${action}`);
49
+ existing.onClipboardAttempt?.(event, action);
50
+ },
51
+ onScreenshotAttempt(event) {
52
+ emit(spanProvider, 'shield.screenshot.attempted');
53
+ existing.onScreenshotAttempt?.(event);
54
+ },
55
+ onExtensionDetected(id, name, risk) {
56
+ emit(spanProvider, 'shield.extension.detected', {
57
+ 'shield.extension.id': id,
58
+ 'shield.extension.name': name,
59
+ 'shield.extension.risk': risk,
60
+ });
61
+ existing.onExtensionDetected?.(id, name, risk);
62
+ },
63
+ onFrameEmbeddingDetected(isEmbedded, isExternal) {
64
+ if (isEmbedded) {
65
+ emit(spanProvider, 'shield.frame.embedding.detected', {
66
+ 'shield.frame.external': isExternal,
67
+ });
68
+ }
69
+ existing.onFrameEmbeddingDetected?.(isEmbedded, isExternal);
70
+ },
71
+ onProtectionBypassed(method, event) {
72
+ emit(spanProvider, 'shield.protection.bypassed', {
73
+ 'shield.bypass.method': method,
74
+ });
75
+ existing.onProtectionBypassed?.(method, event);
76
+ },
77
+ onContentHidden(reason, target) {
78
+ emit(spanProvider, 'shield.content.hidden', { 'shield.hidden.reason': reason });
79
+ existing.onContentHidden?.(reason, target);
80
+ },
81
+ onContentRestored(target) {
82
+ emit(spanProvider, 'shield.content.restored');
83
+ existing.onContentRestored?.(target);
84
+ },
85
+ };
86
+ return new ContentProtector({ ...options, customHandlers: handlers });
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "content-security-toolkit",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",
@@ -19,12 +19,19 @@
19
19
  "examples:start": "cd examples && npm run start"
20
20
  },
21
21
  "keywords": [
22
- "security",
22
+ "content-security",
23
23
  "content-protection",
24
- "drm",
25
- "web-security"
24
+ "web-security",
25
+ "anti-screenshot",
26
+ "devtools-detection",
27
+ "watermark",
28
+ "copy-protection",
29
+ "browser-security",
30
+ "typescript",
31
+ "javascript",
32
+ "frontend-security"
26
33
  ],
27
- "author": "Iker Laforga",
34
+ "author": "Isonimus",
28
35
  "license": "MIT",
29
36
  "repository": {
30
37
  "type": "git",