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.
- package/package.json +1 -1
- package/packages/core/dist/interfaces.d.ts +28 -2
- package/packages/core/dist/interfaces.d.ts.map +1 -1
- package/packages/core/dist/interfaces.js +0 -1
- package/packages/core/dist/interfaces.js.map +1 -1
- package/packages/core/src/interfaces.ts +53 -3
- package/packages/react-native/dist/drm/AndroidDRMProtection.js +1 -1
- package/packages/react-native/dist/drm/iOSDRMProtection.js +1 -1
- package/packages/web/dist/WebPlayer.d.ts +2 -0
- package/packages/web/dist/WebPlayer.d.ts.map +1 -1
- package/packages/web/dist/WebPlayer.js +9731 -9644
- package/packages/web/dist/WebPlayer.js.map +1 -1
- package/packages/web/dist/drm/DRMHelper.d.ts +28 -0
- package/packages/web/dist/drm/DRMHelper.d.ts.map +1 -0
- package/packages/web/dist/drm/DRMHelper.js +117 -0
- package/packages/web/dist/drm/DRMHelper.js.map +1 -0
- package/packages/web/dist/index.d.ts +0 -1
- package/packages/web/dist/index.d.ts.map +1 -1
- package/packages/web/dist/index.js +6 -7
- package/packages/web/dist/index.js.map +1 -1
- package/packages/web/dist/react/WebPlayerView.d.ts +21 -0
- package/packages/web/dist/react/WebPlayerView.d.ts.map +1 -1
- package/packages/web/dist/react/WebPlayerView.js.map +1 -1
- package/packages/web/dist/security/CanvasVideoRenderer.d.ts +26 -0
- package/packages/web/dist/security/CanvasVideoRenderer.d.ts.map +1 -0
- package/packages/web/dist/security/CanvasVideoRenderer.js +143 -0
- package/packages/web/dist/security/CanvasVideoRenderer.js.map +1 -0
- package/packages/web/dist/security/ScreenProtectionController.d.ts +39 -0
- package/packages/web/dist/security/ScreenProtectionController.d.ts.map +1 -0
- package/packages/web/dist/security/ScreenProtectionController.js +278 -0
- package/packages/web/dist/security/ScreenProtectionController.js.map +1 -0
- package/packages/web/src/WebPlayer.ts +120 -2
- package/packages/web/src/drm/DRMHelper.ts +203 -0
- package/packages/web/src/index.ts +0 -3
- package/packages/web/src/react/WebPlayerView.tsx +24 -0
- package/packages/web/src/security/CanvasVideoRenderer.ts +246 -0
- package/packages/web/src/security/ScreenProtectionController.ts +391 -0
- package/scripts/fix-imports.js +18 -16
- package/packages/core/src/interfaces/IDRMProtection.ts +0 -285
- package/packages/react-native/src/drm/AndroidDRMProtection.ts +0 -419
- package/packages/react-native/src/drm/iOSDRMProtection.ts +0 -415
- 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":"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"}
|
|
@@ -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
|
-
|
|
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();
|