unified-video-framework 1.4.382 → 1.4.384

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 (42) hide show
  1. package/package.json +1 -1
  2. package/packages/core/dist/interfaces.d.ts +28 -2
  3. package/packages/core/dist/interfaces.d.ts.map +1 -1
  4. package/packages/core/dist/interfaces.js +0 -1
  5. package/packages/core/dist/interfaces.js.map +1 -1
  6. package/packages/core/src/interfaces.ts +53 -3
  7. package/packages/react-native/dist/drm/AndroidDRMProtection.js +1 -1
  8. package/packages/react-native/dist/drm/iOSDRMProtection.js +1 -1
  9. package/packages/web/dist/WebPlayer.d.ts +2 -0
  10. package/packages/web/dist/WebPlayer.d.ts.map +1 -1
  11. package/packages/web/dist/WebPlayer.js +9731 -9644
  12. package/packages/web/dist/WebPlayer.js.map +1 -1
  13. package/packages/web/dist/drm/DRMHelper.d.ts +28 -0
  14. package/packages/web/dist/drm/DRMHelper.d.ts.map +1 -0
  15. package/packages/web/dist/drm/DRMHelper.js +117 -0
  16. package/packages/web/dist/drm/DRMHelper.js.map +1 -0
  17. package/packages/web/dist/index.d.ts +0 -1
  18. package/packages/web/dist/index.d.ts.map +1 -1
  19. package/packages/web/dist/index.js +6 -7
  20. package/packages/web/dist/index.js.map +1 -1
  21. package/packages/web/dist/react/WebPlayerView.d.ts +21 -0
  22. package/packages/web/dist/react/WebPlayerView.d.ts.map +1 -1
  23. package/packages/web/dist/react/WebPlayerView.js.map +1 -1
  24. package/packages/web/dist/security/CanvasVideoRenderer.d.ts +26 -0
  25. package/packages/web/dist/security/CanvasVideoRenderer.d.ts.map +1 -0
  26. package/packages/web/dist/security/CanvasVideoRenderer.js +143 -0
  27. package/packages/web/dist/security/CanvasVideoRenderer.js.map +1 -0
  28. package/packages/web/dist/security/ScreenProtectionController.d.ts +39 -0
  29. package/packages/web/dist/security/ScreenProtectionController.d.ts.map +1 -0
  30. package/packages/web/dist/security/ScreenProtectionController.js +278 -0
  31. package/packages/web/dist/security/ScreenProtectionController.js.map +1 -0
  32. package/packages/web/src/WebPlayer.ts +120 -2
  33. package/packages/web/src/drm/DRMHelper.ts +203 -0
  34. package/packages/web/src/index.ts +0 -3
  35. package/packages/web/src/react/WebPlayerView.tsx +24 -0
  36. package/packages/web/src/security/CanvasVideoRenderer.ts +246 -0
  37. package/packages/web/src/security/ScreenProtectionController.ts +391 -0
  38. package/scripts/fix-imports.js +18 -16
  39. package/packages/core/src/interfaces/IDRMProtection.ts +0 -285
  40. package/packages/react-native/src/drm/AndroidDRMProtection.ts +0 -419
  41. package/packages/react-native/src/drm/iOSDRMProtection.ts +0 -415
  42. package/packages/web/src/drm/WebDRMProtection.ts +0 -596
@@ -0,0 +1,143 @@
1
+ export class CanvasVideoRenderer {
2
+ constructor(opts) {
3
+ this.animationFrameId = null;
4
+ this.isActive = false;
5
+ this.noiseOffset = 0;
6
+ this.renderFrame = () => {
7
+ if (!this.isActive)
8
+ return;
9
+ const video = this.opts.sourceVideo;
10
+ if (video.readyState >= video.HAVE_CURRENT_DATA) {
11
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
12
+ if (this.opts.enableDynamicTransforms) {
13
+ this.ctx.save();
14
+ const jitterX = Math.sin(Date.now() / 1000) * 0.5;
15
+ const jitterY = Math.cos(Date.now() / 1000) * 0.5;
16
+ this.ctx.translate(jitterX, jitterY);
17
+ }
18
+ this.ctx.drawImage(video, 0, 0, this.canvas.width, this.canvas.height);
19
+ if (this.opts.enableNoise) {
20
+ this.applyNoiseLayer();
21
+ }
22
+ if (this.opts.watermarkText) {
23
+ this.drawDynamicWatermark();
24
+ }
25
+ if (this.opts.enableDynamicTransforms) {
26
+ this.ctx.restore();
27
+ }
28
+ }
29
+ this.animationFrameId = requestAnimationFrame(this.renderFrame);
30
+ };
31
+ this.opts = opts;
32
+ this.canvas = document.createElement('canvas');
33
+ this.canvas.className = 'uvf-canvas-video-renderer';
34
+ this.canvas.style.cssText = `
35
+ position: absolute;
36
+ top: 0;
37
+ left: 0;
38
+ width: 100%;
39
+ height: 100%;
40
+ object-fit: contain;
41
+ z-index: 2;
42
+ `;
43
+ const context = this.canvas.getContext('2d', {
44
+ alpha: false,
45
+ desynchronized: true,
46
+ willReadFrequently: false
47
+ });
48
+ if (!context) {
49
+ throw new Error('[CanvasRenderer] Failed to get 2D context');
50
+ }
51
+ this.ctx = context;
52
+ }
53
+ activate() {
54
+ if (this.isActive)
55
+ return;
56
+ console.log('[CanvasRenderer] Activating canvas-based video rendering...');
57
+ console.warn('[CanvasRenderer] WARNING: Canvas rendering does NOT prevent screenshots showing content.');
58
+ console.warn('[CanvasRenderer] This only adds obfuscation. Use DRM for true protection.');
59
+ this.opts.sourceVideo.style.opacity = '0';
60
+ this.opts.sourceVideo.style.pointerEvents = 'none';
61
+ this.opts.containerElement.appendChild(this.canvas);
62
+ this.updateCanvasSize();
63
+ this.isActive = true;
64
+ this.renderFrame();
65
+ this.opts.sourceVideo.addEventListener('loadedmetadata', () => {
66
+ this.updateCanvasSize();
67
+ });
68
+ console.log('[CanvasRenderer] Canvas rendering active');
69
+ }
70
+ deactivate() {
71
+ if (!this.isActive)
72
+ return;
73
+ console.log('[CanvasRenderer] Deactivating canvas rendering...');
74
+ this.isActive = false;
75
+ if (this.animationFrameId !== null) {
76
+ cancelAnimationFrame(this.animationFrameId);
77
+ this.animationFrameId = null;
78
+ }
79
+ this.opts.sourceVideo.style.opacity = '1';
80
+ this.opts.sourceVideo.style.pointerEvents = 'auto';
81
+ if (this.canvas.parentElement) {
82
+ this.canvas.parentElement.removeChild(this.canvas);
83
+ }
84
+ }
85
+ destroy() {
86
+ this.deactivate();
87
+ }
88
+ updateCanvasSize() {
89
+ const video = this.opts.sourceVideo;
90
+ this.canvas.width = video.videoWidth || 1920;
91
+ this.canvas.height = video.videoHeight || 1080;
92
+ console.log(`[CanvasRenderer] Canvas size: ${this.canvas.width}x${this.canvas.height}`);
93
+ }
94
+ applyNoiseLayer() {
95
+ const imageData = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
96
+ const data = imageData.data;
97
+ for (let i = 0; i < data.length; i += 4) {
98
+ const noise = (Math.random() - 0.5) * 2;
99
+ data[i] += noise;
100
+ data[i + 1] += noise;
101
+ data[i + 2] += noise;
102
+ }
103
+ this.ctx.putImageData(imageData, 0, 0);
104
+ }
105
+ drawDynamicWatermark() {
106
+ const text = this.opts.watermarkText;
107
+ const fontSize = Math.floor(this.canvas.height / 30);
108
+ this.ctx.save();
109
+ this.ctx.font = `${fontSize}px Arial, sans-serif`;
110
+ this.ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
111
+ this.ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
112
+ this.ctx.lineWidth = 1;
113
+ this.ctx.textAlign = 'center';
114
+ this.ctx.textBaseline = 'middle';
115
+ const time = Date.now() / 1000;
116
+ const positions = [
117
+ { x: this.canvas.width * 0.25, y: this.canvas.height * 0.25 },
118
+ { x: this.canvas.width * 0.75, y: this.canvas.height * 0.25 },
119
+ { x: this.canvas.width * 0.25, y: this.canvas.height * 0.75 },
120
+ { x: this.canvas.width * 0.75, y: this.canvas.height * 0.75 },
121
+ { x: this.canvas.width * 0.5, y: this.canvas.height * 0.5 }
122
+ ];
123
+ positions.forEach((pos, index) => {
124
+ this.ctx.save();
125
+ this.ctx.translate(pos.x, pos.y);
126
+ const rotation = (Math.sin(time + index) * 15 * Math.PI) / 180;
127
+ this.ctx.rotate(rotation);
128
+ const opacity = 0.2 + Math.sin(time * 2 + index) * 0.1;
129
+ this.ctx.globalAlpha = opacity;
130
+ this.ctx.strokeText(text, 0, 0);
131
+ this.ctx.fillText(text, 0, 0);
132
+ this.ctx.restore();
133
+ });
134
+ this.ctx.restore();
135
+ }
136
+ getCanvas() {
137
+ return this.canvas;
138
+ }
139
+ isRendering() {
140
+ return this.isActive;
141
+ }
142
+ }
143
+ //# sourceMappingURL=CanvasVideoRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CanvasVideoRenderer.js","sourceRoot":"","sources":["../../src/security/CanvasVideoRenderer.ts"],"names":[],"mappings":"AAyBA,MAAM,OAAO,mBAAmB;IAQ9B,YAAY,IAA2B;QAJ/B,qBAAgB,GAAkB,IAAI,CAAC;QACvC,aAAQ,GAAY,KAAK,CAAC;QAC1B,gBAAW,GAAW,CAAC,CAAC;QAiGxB,gBAAW,GAAG,GAAS,EAAE;YAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;YAGpC,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,iBAAiB,EAAE;gBAE/C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAGhE,IAAI,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE;oBACrC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;oBAGhB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;oBAClD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;oBAClD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;iBACtC;gBAGD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAGvE,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;oBACzB,IAAI,CAAC,eAAe,EAAE,CAAC;iBACxB;gBAGD,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;oBAC3B,IAAI,CAAC,oBAAoB,EAAE,CAAC;iBAC7B;gBAED,IAAI,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE;oBACrC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;iBACpB;aACF;YAGD,IAAI,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAClE,CAAC,CAAC;QAtIA,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAGjB,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,2BAA2B,CAAC;QACpD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG;;;;;;;;KAQ3B,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE;YAC3C,KAAK,EAAE,KAAK;YACZ,cAAc,EAAE,IAAI;YACpB,kBAAkB,EAAE,KAAK;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;SAC9D;QAED,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC;IACrB,CAAC;IAEM,QAAQ;QACb,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE1B,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,0FAA0F,CAAC,CAAC;QACzG,OAAO,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;QAG1F,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;QAGnD,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAGpD,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAGxB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,WAAW,EAAE,CAAC;QAGnB,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,GAAG,EAAE;YAC5D,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IAC1D,CAAC;IAEM,UAAU;QACf,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;QAEjE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QAGtB,IAAI,IAAI,CAAC,gBAAgB,KAAK,IAAI,EAAE;YAClC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5C,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;SAC9B;QAGD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;QAGnD,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE;YAC7B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SACpD;IACH,CAAC;IAEM,OAAO;QACZ,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,gBAAgB;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;QAGpC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC;QAE/C,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1F,CAAC;IA4CO,eAAe;QAErB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACrF,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;QAG5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;YACvC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YACxC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;YACjB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;YACrB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;SAEtB;QAED,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;IAEO,oBAAoB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,aAAc,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QAErD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAGhB,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,QAAQ,sBAAsB,CAAC;QAClD,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,0BAA0B,CAAC;QAChD,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,oBAAoB,CAAC;QAC5C,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC9B,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,QAAQ,CAAC;QAGjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAC/B,MAAM,SAAS,GAAG;YAChB,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE;YAC7D,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE;YAC7D,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE;YAC7D,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,EAAE;YAC7D,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;SAC5D,CAAC;QAEF,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YAChB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YAGjC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;YAC/D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAG1B,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;YACvD,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC;YAE/B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAChC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAE9B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;IAKM,SAAS;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAKM,WAAW;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ import { ScreenCaptureEvent, EnhancedScreenProtectionConfig } from '@unified-video/core';
2
+ export interface ScreenProtectionOptions {
3
+ videoElement: HTMLVideoElement;
4
+ containerElement: HTMLElement;
5
+ config: EnhancedScreenProtectionConfig;
6
+ watermarkConfig?: any;
7
+ onDetection?: (event: ScreenCaptureEvent) => void;
8
+ onDevToolsDetected?: () => void;
9
+ onPause?: () => void;
10
+ }
11
+ export declare class ScreenProtectionController {
12
+ private opts;
13
+ private overlayElement;
14
+ private canvasRenderer;
15
+ private detectionIntervals;
16
+ private eventListeners;
17
+ private isActive;
18
+ private devToolsOpen;
19
+ private originalGetDisplayMedia;
20
+ constructor(opts: ScreenProtectionOptions);
21
+ activate(): void;
22
+ deactivate(): void;
23
+ destroy(): void;
24
+ private initializeCanvasRendering;
25
+ private applyVideoProtection;
26
+ private createInterferenceOverlay;
27
+ private animateOverlay;
28
+ private setupDetection;
29
+ private detectDevTools;
30
+ private detectFocusLoss;
31
+ private detectVisibilityChange;
32
+ private detectScreenCaptureAPI;
33
+ private handleDetection;
34
+ private sendTrackingEvent;
35
+ private executeWarnAction;
36
+ private executePauseAction;
37
+ private executeDegradeAction;
38
+ }
39
+ //# sourceMappingURL=ScreenProtectionController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScreenProtectionController.d.ts","sourceRoot":"","sources":["../../src/security/ScreenProtectionController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAGzF,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,gBAAgB,EAAE,WAAW,CAAC;IAC9B,MAAM,EAAE,8BAA8B,CAAC;IACvC,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAClD,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,cAAc,CAAoC;IAC1D,OAAO,CAAC,kBAAkB,CAAwB;IAClD,OAAO,CAAC,cAAc,CAA2D;IACjF,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,uBAAuB,CAAa;gBAEhC,IAAI,EAAE,uBAAuB;IAIlC,QAAQ,IAAI,IAAI;IAsBhB,UAAU,IAAI,IAAI;IAoClB,OAAO,IAAI,IAAI;IAItB,OAAO,CAAC,yBAAyB;IA4BjC,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,yBAAyB;IAuCjC,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,cAAc;IAkCtB,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,eAAe;YA6BT,iBAAiB;IAmB/B,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,oBAAoB;CAa7B"}
@@ -0,0 +1,278 @@
1
+ import { CanvasVideoRenderer } from "./CanvasVideoRenderer.js";
2
+ export class ScreenProtectionController {
3
+ constructor(opts) {
4
+ this.overlayElement = null;
5
+ this.canvasRenderer = null;
6
+ this.detectionIntervals = [];
7
+ this.eventListeners = [];
8
+ this.isActive = false;
9
+ this.devToolsOpen = false;
10
+ this.originalGetDisplayMedia = null;
11
+ this.opts = opts;
12
+ }
13
+ activate() {
14
+ if (this.isActive)
15
+ return;
16
+ console.log('[ScreenProtectionController] Activating screen protection...');
17
+ this.applyVideoProtection();
18
+ this.initializeCanvasRendering();
19
+ if (!this.canvasRenderer) {
20
+ this.createInterferenceOverlay();
21
+ }
22
+ this.setupDetection();
23
+ this.isActive = true;
24
+ }
25
+ deactivate() {
26
+ if (!this.isActive)
27
+ return;
28
+ console.log('[ScreenProtectionController] Deactivating screen protection...');
29
+ if (this.canvasRenderer) {
30
+ this.canvasRenderer.deactivate();
31
+ this.canvasRenderer = null;
32
+ }
33
+ if (this.overlayElement && this.overlayElement.parentElement) {
34
+ this.overlayElement.parentElement.removeChild(this.overlayElement);
35
+ this.overlayElement = null;
36
+ }
37
+ this.detectionIntervals.forEach(interval => clearInterval(interval));
38
+ this.detectionIntervals = [];
39
+ this.eventListeners.forEach(({ target, event, handler }) => {
40
+ target.removeEventListener(event, handler);
41
+ });
42
+ this.eventListeners = [];
43
+ if (this.originalGetDisplayMedia && navigator.mediaDevices) {
44
+ navigator.mediaDevices.getDisplayMedia = this.originalGetDisplayMedia;
45
+ this.originalGetDisplayMedia = null;
46
+ }
47
+ this.isActive = false;
48
+ }
49
+ destroy() {
50
+ this.deactivate();
51
+ }
52
+ initializeCanvasRendering() {
53
+ if (!this.opts.config.canvasRendering?.enabled) {
54
+ return;
55
+ }
56
+ console.log('[ScreenProtectionController] Initializing canvas-based video rendering...');
57
+ console.warn('[ScreenProtectionController] WARNING: Canvas rendering does NOT prevent screenshots.');
58
+ console.warn('[ScreenProtectionController] This only adds obfuscation. Use DRM for true protection.');
59
+ const watermarkText = this.opts.config.forensicWatermark?.userId
60
+ ? `PROTECTED - ${this.opts.config.forensicWatermark.userId}`
61
+ : 'PROTECTED CONTENT';
62
+ this.canvasRenderer = new CanvasVideoRenderer({
63
+ sourceVideo: this.opts.videoElement,
64
+ containerElement: this.opts.containerElement,
65
+ watermarkText: watermarkText,
66
+ enableNoise: this.opts.config.canvasRendering.enableNoise ?? true,
67
+ enableDynamicTransforms: this.opts.config.canvasRendering.enableDynamicTransforms ?? true
68
+ });
69
+ this.canvasRenderer.activate();
70
+ }
71
+ applyVideoProtection() {
72
+ const { videoElement, containerElement } = this.opts;
73
+ try {
74
+ videoElement.disablePictureInPicture = true;
75
+ videoElement.autoPictureInPicture = false;
76
+ }
77
+ catch (e) {
78
+ console.warn('[ScreenProtection] Could not disable PiP:', e);
79
+ }
80
+ try {
81
+ if ('controlsList' in videoElement) {
82
+ videoElement.controlsList.add('nodownload');
83
+ }
84
+ }
85
+ catch (e) {
86
+ console.warn('[ScreenProtection] controlsList not supported:', e);
87
+ }
88
+ containerElement.style.userSelect = 'none';
89
+ containerElement.style.webkitUserSelect = 'none';
90
+ containerElement.style.webkitTouchCallout = 'none';
91
+ const contextMenuHandler = (e) => {
92
+ if (containerElement.contains(e.target)) {
93
+ e.preventDefault();
94
+ e.stopPropagation();
95
+ return false;
96
+ }
97
+ return true;
98
+ };
99
+ document.addEventListener('contextmenu', contextMenuHandler);
100
+ this.eventListeners.push({ target: document, event: 'contextmenu', handler: contextMenuHandler });
101
+ console.log('[ScreenProtection] Video protection applied');
102
+ }
103
+ createInterferenceOverlay() {
104
+ const { containerElement } = this.opts;
105
+ this.overlayElement = document.createElement('div');
106
+ this.overlayElement.className = 'uvf-screen-protection-overlay';
107
+ this.overlayElement.setAttribute('aria-hidden', 'true');
108
+ Object.assign(this.overlayElement.style, {
109
+ position: 'absolute',
110
+ top: '0',
111
+ left: '0',
112
+ width: '100%',
113
+ height: '100%',
114
+ pointerEvents: 'none',
115
+ zIndex: '3',
116
+ mixBlendMode: 'screen',
117
+ opacity: '0.01',
118
+ background: 'transparent',
119
+ backgroundImage: 'url("data:image/svg+xml,%3Csvg viewBox=\'0 0 256 256\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cfilter id=\'noise\'%3E%3CfeTurbulence type=\'fractalNoise\' baseFrequency=\'0.9\' numOctaves=\'4\' stitchTiles=\'stitch\'/%3E%3C/filter%3E%3Crect width=\'100%25\' height=\'100%25\' filter=\'url(%23noise)\' opacity=\'0.05\'/%3E%3C/svg%3E")',
120
+ transition: 'opacity 0.3s ease-in-out'
121
+ });
122
+ const watermarkCanvas = containerElement.querySelector('.uvf-watermark-layer');
123
+ if (watermarkCanvas) {
124
+ containerElement.insertBefore(this.overlayElement, watermarkCanvas);
125
+ }
126
+ else {
127
+ containerElement.appendChild(this.overlayElement);
128
+ }
129
+ this.animateOverlay();
130
+ console.log('[ScreenProtection] Interference overlay created');
131
+ }
132
+ animateOverlay() {
133
+ if (!this.overlayElement || !this.isActive)
134
+ return;
135
+ const baseOpacity = 0.01;
136
+ const variation = baseOpacity * 0.5;
137
+ const newOpacity = baseOpacity + (Math.random() * variation - variation / 2);
138
+ this.overlayElement.style.opacity = newOpacity.toString();
139
+ setTimeout(() => this.animateOverlay(), 3000 + Math.random() * 2000);
140
+ }
141
+ setupDetection() {
142
+ this.detectDevTools();
143
+ this.detectFocusLoss();
144
+ this.detectVisibilityChange();
145
+ this.detectScreenCaptureAPI();
146
+ console.log('[ScreenProtection] Detection mechanisms active');
147
+ }
148
+ detectDevTools() {
149
+ const threshold = 160;
150
+ let previousState = false;
151
+ const checkDevTools = () => {
152
+ if (!this.isActive)
153
+ return;
154
+ const widthDiff = window.outerWidth - window.innerWidth;
155
+ const heightDiff = window.outerHeight - window.innerHeight;
156
+ const isOpen = widthDiff > threshold || heightDiff > threshold;
157
+ if (isOpen && !previousState) {
158
+ this.devToolsOpen = true;
159
+ this.handleDetection({
160
+ type: 'devtools',
161
+ timestamp: Date.now(),
162
+ details: { widthDiff, heightDiff }
163
+ });
164
+ if (this.opts.onDevToolsDetected) {
165
+ this.opts.onDevToolsDetected();
166
+ }
167
+ }
168
+ else if (!isOpen && previousState) {
169
+ this.devToolsOpen = false;
170
+ }
171
+ previousState = isOpen;
172
+ };
173
+ const interval = setInterval(checkDevTools, 500);
174
+ this.detectionIntervals.push(interval);
175
+ }
176
+ detectFocusLoss() {
177
+ const blurHandler = () => {
178
+ this.handleDetection({
179
+ type: 'focus-loss',
180
+ timestamp: Date.now(),
181
+ details: { documentHidden: document.hidden }
182
+ });
183
+ };
184
+ window.addEventListener('blur', blurHandler);
185
+ this.eventListeners.push({ target: window, event: 'blur', handler: blurHandler });
186
+ }
187
+ detectVisibilityChange() {
188
+ const visibilityHandler = () => {
189
+ if (document.hidden) {
190
+ this.handleDetection({
191
+ type: 'visibility-change',
192
+ timestamp: Date.now(),
193
+ details: { visibilityState: document.visibilityState }
194
+ });
195
+ }
196
+ };
197
+ document.addEventListener('visibilitychange', visibilityHandler);
198
+ this.eventListeners.push({ target: document, event: 'visibilitychange', handler: visibilityHandler });
199
+ }
200
+ detectScreenCaptureAPI() {
201
+ if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
202
+ this.originalGetDisplayMedia = navigator.mediaDevices.getDisplayMedia.bind(navigator.mediaDevices);
203
+ const self = this;
204
+ navigator.mediaDevices.getDisplayMedia = async function (...args) {
205
+ self.handleDetection({
206
+ type: 'screen-capture-api',
207
+ timestamp: Date.now(),
208
+ details: { api: 'getDisplayMedia', args: args.length }
209
+ });
210
+ return self.originalGetDisplayMedia(...args);
211
+ };
212
+ }
213
+ }
214
+ handleDetection(event) {
215
+ console.warn('[ScreenProtection] Detection event:', event);
216
+ if (this.opts.onDetection) {
217
+ this.opts.onDetection(event);
218
+ }
219
+ if (this.opts.config.trackingEndpoint) {
220
+ this.sendTrackingEvent(event);
221
+ }
222
+ const action = this.opts.config.onDetection || 'warn';
223
+ switch (action) {
224
+ case 'warn':
225
+ this.executeWarnAction();
226
+ break;
227
+ case 'pause':
228
+ this.executePauseAction();
229
+ break;
230
+ case 'degrade':
231
+ this.executeDegradeAction();
232
+ break;
233
+ }
234
+ }
235
+ async sendTrackingEvent(event) {
236
+ try {
237
+ await fetch(this.opts.config.trackingEndpoint, {
238
+ method: 'POST',
239
+ headers: {
240
+ 'Content-Type': 'application/json'
241
+ },
242
+ body: JSON.stringify({
243
+ event,
244
+ userAgent: navigator.userAgent,
245
+ timestamp: new Date().toISOString(),
246
+ forensicData: this.opts.config.forensicWatermark
247
+ })
248
+ });
249
+ }
250
+ catch (error) {
251
+ console.error('[ScreenProtection] Failed to send tracking event:', error);
252
+ }
253
+ }
254
+ executeWarnAction() {
255
+ const message = this.opts.config.warningMessage ||
256
+ 'Screen recording or screenshot detected. This content is protected.';
257
+ console.warn(`[ScreenProtection] ${message}`);
258
+ }
259
+ executePauseAction() {
260
+ console.warn('[ScreenProtection] Pausing playback due to suspicious activity');
261
+ if (this.opts.onPause) {
262
+ this.opts.onPause();
263
+ }
264
+ else {
265
+ this.opts.videoElement.pause();
266
+ }
267
+ }
268
+ executeDegradeAction() {
269
+ console.warn('[ScreenProtection] Degrading video quality due to suspicious activity');
270
+ this.opts.videoElement.style.filter = 'blur(10px) brightness(0.5)';
271
+ setTimeout(() => {
272
+ if (this.opts.videoElement.style.filter) {
273
+ this.opts.videoElement.style.filter = '';
274
+ }
275
+ }, 5000);
276
+ }
277
+ }
278
+ //# sourceMappingURL=ScreenProtectionController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScreenProtectionController.js","sourceRoot":"","sources":["../../src/security/ScreenProtectionController.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,8 @@ import {
22
22
  } from './chapters/types/ChapterTypes';
23
23
  import type { FlashNewsTickerConfig } from './react/types/FlashNewsTickerTypes';
24
24
  import YouTubeExtractor from './utils/YouTubeExtractor';
25
+ import { ScreenProtectionController } from './security/ScreenProtectionController';
26
+ import type { ScreenCaptureEvent } from '../../core/dist';
25
27
 
26
28
  // Dynamic imports for streaming libraries
27
29
  declare global {
@@ -93,6 +95,9 @@ export class WebPlayer extends BasePlayer {
93
95
  // Paywall
94
96
  private paywallController: any = null;
95
97
 
98
+ // Screen protection
99
+ private screenProtectionController: ScreenProtectionController | null = null;
100
+
96
101
  // Play/pause coordination to prevent race conditions
97
102
  private _playPromise: Promise<void> | null = null;
98
103
  private _deferredPause = false;
@@ -353,6 +358,11 @@ export class WebPlayer extends BasePlayer {
353
358
  this.setupFullscreenListeners();
354
359
  this.setupUserInteractionTracking();
355
360
 
361
+ // Setup screen protection if enabled
362
+ if ((this.config as any).screenProtection === true) {
363
+ this.initializeScreenProtection();
364
+ }
365
+
356
366
  // Initialize chapter manager if enabled
357
367
  if (this.chapterConfig.enabled && this.video) {
358
368
  this.setupChapterManager();
@@ -8110,10 +8120,27 @@ export class WebPlayer extends BasePlayer {
8110
8120
  }
8111
8121
 
8112
8122
  // Render the watermark
8113
- ctx.fillText(text, x, y);
8123
+ // If screen protection is active, render multiple watermarks
8124
+ if ((this.config as any).screenProtection && this.screenProtectionController) {
8125
+ const positions = [
8126
+ { x: 20, y: 40 },
8127
+ { x: Math.max(20, this.watermarkCanvas!.width - 200), y: 40 },
8128
+ { x: 20, y: Math.max(40, this.watermarkCanvas!.height - 60) },
8129
+ { x: Math.max(20, this.watermarkCanvas!.width - 200), y: Math.max(40, this.watermarkCanvas!.height - 60) }
8130
+ ];
8131
+
8132
+ positions.forEach((pos) => {
8133
+ const offsetX = Math.random() * 100 - 50;
8134
+ const offsetY = Math.random() * 50 - 25;
8135
+ ctx.fillText(text, pos.x + offsetX, pos.y + offsetY);
8136
+ });
8137
+ } else {
8138
+ // Normal single watermark rendering
8139
+ ctx.fillText(text, x, y);
8140
+ }
8114
8141
  ctx.restore();
8115
8142
 
8116
- this.debugLog('Watermark rendered:', { text, x, y });
8143
+ this.debugLog('Watermark rendered:', { text, x, y, multiWatermark: !!((this.config as any).screenProtection && this.screenProtectionController) });
8117
8144
  };
8118
8145
 
8119
8146
  // Set up interval with configured frequency
@@ -8123,6 +8150,91 @@ export class WebPlayer extends BasePlayer {
8123
8150
  this.debugLog('Watermark setup complete with update interval:', config.updateInterval + 'ms');
8124
8151
  }
8125
8152
 
8153
+ private initializeScreenProtection(): void {
8154
+ if (!this.video || !this.container) return;
8155
+
8156
+ // Normalize config: convert boolean to EnhancedScreenProtectionConfig
8157
+ const screenProtConfig = (this.config as any).screenProtection;
8158
+ const enhancedConfig = typeof screenProtConfig === 'boolean'
8159
+ ? { enabled: true } // Simple mode: just { enabled: true }
8160
+ : screenProtConfig; // Advanced mode: full config object
8161
+
8162
+ if (!enhancedConfig || !enhancedConfig.enabled) return;
8163
+
8164
+ console.warn(
8165
+ '[Unified Video Framework] Screen Protection Enabled\n' +
8166
+ 'Note: Browsers cannot completely block screen recording. ' +
8167
+ 'This provides detection and deterrence through watermarking and monitoring.\n' +
8168
+ 'For DRM-level protection, use encrypted content with Widevine/FairPlay.'
8169
+ );
8170
+
8171
+ // Enhance watermark for protection
8172
+ const watermarkText = enhancedConfig.forensicWatermark?.userId
8173
+ ? `PROTECTED - ${enhancedConfig.forensicWatermark.userId}`
8174
+ : 'PROTECTED CONTENT';
8175
+
8176
+ if (!(this.config as any).watermark) {
8177
+ (this.config as any).watermark = {
8178
+ enabled: true,
8179
+ text: watermarkText,
8180
+ randomPosition: true,
8181
+ updateInterval: 1000 // Rapid updates
8182
+ };
8183
+ } else if ((this.config as any).watermark.enabled !== false) {
8184
+ // Force aggressive watermarking
8185
+ (this.config as any).watermark.randomPosition = true;
8186
+ (this.config as any).watermark.updateInterval = Math.min(
8187
+ (this.config as any).watermark.updateInterval || 5000,
8188
+ 1000
8189
+ );
8190
+ // Add forensic watermark user ID if provided
8191
+ if (enhancedConfig.forensicWatermark?.userId) {
8192
+ (this.config as any).watermark.text = watermarkText;
8193
+ }
8194
+ }
8195
+ this.setupWatermark(); // Re-setup with new config
8196
+
8197
+ // Create protection controller
8198
+ this.screenProtectionController = new ScreenProtectionController({
8199
+ videoElement: this.video,
8200
+ containerElement: this.container,
8201
+ config: enhancedConfig,
8202
+ watermarkConfig: (this.config as any).watermark,
8203
+ onDetection: (event: ScreenCaptureEvent) => {
8204
+ console.warn('[Screen Protection] Detection:', event);
8205
+ this.emit('onScreenCaptureDetected', event);
8206
+
8207
+ // Call config callback if provided
8208
+ if (enhancedConfig.onScreenCaptureDetected) {
8209
+ enhancedConfig.onScreenCaptureDetected(event);
8210
+ }
8211
+ // Also check legacy callback
8212
+ if ((this.config as any).onScreenCaptureDetected) {
8213
+ (this.config as any).onScreenCaptureDetected(event);
8214
+ }
8215
+ },
8216
+ onDevToolsDetected: () => {
8217
+ console.warn('[Screen Protection] DevTools detected');
8218
+ this.emit('onDevToolsDetected');
8219
+
8220
+ // Call config callback if provided
8221
+ if (enhancedConfig.onDevToolsDetected) {
8222
+ enhancedConfig.onDevToolsDetected();
8223
+ }
8224
+ // Also check legacy callback
8225
+ if ((this.config as any).onDevToolsDetected) {
8226
+ (this.config as any).onDevToolsDetected();
8227
+ }
8228
+ },
8229
+ onPause: () => {
8230
+ // Pause video when requested by protection controller
8231
+ this.pause();
8232
+ }
8233
+ });
8234
+
8235
+ this.screenProtectionController.activate();
8236
+ }
8237
+
8126
8238
  public setPaywallConfig(config: any) {
8127
8239
  try {
8128
8240
  if (!config) return;
@@ -11278,6 +11390,12 @@ export class WebPlayer extends BasePlayer {
11278
11390
  this.paywallController = null;
11279
11391
  }
11280
11392
 
11393
+ // Destroy screen protection controller
11394
+ if (this.screenProtectionController) {
11395
+ this.screenProtectionController.destroy();
11396
+ this.screenProtectionController = null;
11397
+ }
11398
+
11281
11399
  // Destroy chapter managers
11282
11400
  if (this.chapterManager && typeof this.chapterManager.destroy === 'function') {
11283
11401
  this.chapterManager.destroy();