unified-video-framework 1.4.377 → 1.4.379

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 (33) hide show
  1. package/package.json +1 -1
  2. package/packages/core/dist/interfaces/IDRMProtection.d.ts +90 -0
  3. package/packages/core/dist/interfaces/IDRMProtection.d.ts.map +1 -0
  4. package/packages/core/dist/interfaces/IDRMProtection.js +15 -0
  5. package/packages/core/dist/interfaces/IDRMProtection.js.map +1 -0
  6. package/packages/core/dist/interfaces.d.ts +1 -0
  7. package/packages/core/dist/interfaces.d.ts.map +1 -1
  8. package/packages/core/dist/interfaces.js +1 -0
  9. package/packages/core/dist/interfaces.js.map +1 -1
  10. package/packages/core/src/interfaces/IDRMProtection.ts +285 -0
  11. package/packages/core/src/interfaces.ts +2 -0
  12. package/packages/react-native/dist/drm/AndroidDRMProtection.d.ts +21 -0
  13. package/packages/react-native/dist/drm/AndroidDRMProtection.d.ts.map +1 -0
  14. package/packages/react-native/dist/drm/AndroidDRMProtection.js +184 -0
  15. package/packages/react-native/dist/drm/AndroidDRMProtection.js.map +1 -0
  16. package/packages/react-native/dist/drm/iOSDRMProtection.d.ts +21 -0
  17. package/packages/react-native/dist/drm/iOSDRMProtection.d.ts.map +1 -0
  18. package/packages/react-native/dist/drm/iOSDRMProtection.js +172 -0
  19. package/packages/react-native/dist/drm/iOSDRMProtection.js.map +1 -0
  20. package/packages/react-native/src/drm/AndroidDRMProtection.ts +419 -0
  21. package/packages/react-native/src/drm/iOSDRMProtection.ts +415 -0
  22. package/packages/web/dist/WebPlayer.js +1 -1
  23. package/packages/web/dist/drm/WebDRMProtection.d.ts +37 -0
  24. package/packages/web/dist/drm/WebDRMProtection.d.ts.map +1 -0
  25. package/packages/web/dist/drm/WebDRMProtection.js +378 -0
  26. package/packages/web/dist/drm/WebDRMProtection.js.map +1 -0
  27. package/packages/web/dist/index.d.ts +1 -0
  28. package/packages/web/dist/index.d.ts.map +1 -1
  29. package/packages/web/dist/index.js +2 -1
  30. package/packages/web/dist/index.js.map +1 -1
  31. package/packages/web/src/drm/WebDRMProtection.ts +596 -0
  32. package/packages/web/src/index.ts +3 -0
  33. package/scripts/fix-imports.js +24 -18
@@ -0,0 +1,419 @@
1
+ /**
2
+ * Android DRM Protection Implementation
3
+ *
4
+ * Implements Netflix-like content protection for Android using:
5
+ * - FLAG_SECURE for screenshot/recording prevention
6
+ * - Widevine DRM (L1/L3)
7
+ * - MediaDrm + ExoPlayer
8
+ * - Chromecast support (remote playback, not mirroring)
9
+ * - Display mirroring detection
10
+ */
11
+
12
+ import { NativeModules, NativeEventEmitter } from 'react-native';
13
+ import {
14
+ IDRMProtection,
15
+ IDRMProtectionConfig,
16
+ IDRMProtectionStatus,
17
+ CastDevice,
18
+ DRMErrorCode,
19
+ } from '@unified-video/core';
20
+
21
+ const { DRMProtectionModule } = NativeModules;
22
+ const drmEventEmitter = new NativeEventEmitter(DRMProtectionModule);
23
+
24
+ /**
25
+ * Android DRM Protection
26
+ */
27
+ export class AndroidDRMProtection implements IDRMProtection {
28
+ private config: IDRMProtectionConfig;
29
+ private status: IDRMProtectionStatus;
30
+ private listeners: any[] = [];
31
+
32
+ constructor() {
33
+ this.config = { enabled: false };
34
+ this.status = {
35
+ isProtected: false,
36
+ drmSystem: 'none',
37
+ isScreenRecordingBlocked: false,
38
+ isAudioCaptureBlocked: false,
39
+ isScreenshotBlocked: false,
40
+ isCasting: false,
41
+ screenRecordingDetected: false,
42
+ mirroringDetected: false,
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Initialize DRM protection
48
+ */
49
+ async initialize(config: IDRMProtectionConfig): Promise<void> {
50
+ this.config = {
51
+ blockScreenRecording: true,
52
+ blockAudioCapture: true,
53
+ blockScreenshots: true,
54
+ allowCasting: true,
55
+ blockMirroring: true,
56
+ widevineSecurityLevel: 'L1',
57
+ ...config,
58
+ };
59
+
60
+ if (!this.config.enabled) {
61
+ console.log('[DRM-Android] Protection disabled');
62
+ return;
63
+ }
64
+
65
+ console.log('[DRM-Android] Initializing...', this.config);
66
+
67
+ try {
68
+ // Enable FLAG_SECURE to block screenshots and screen recording
69
+ if (this.config.blockScreenshots || this.config.blockScreenRecording) {
70
+ await DRMProtectionModule.enableFlagSecure(true);
71
+ this.status.isScreenshotBlocked = true;
72
+ this.status.isScreenRecordingBlocked = true;
73
+ console.log('[DRM-Android] FLAG_SECURE enabled');
74
+ }
75
+
76
+ // Initialize Widevine DRM
77
+ if (this.config.licenseServerUrl) {
78
+ await this.initializeWidevine();
79
+ }
80
+
81
+ // Start mirroring detection
82
+ if (this.config.blockMirroring) {
83
+ await this.startMirroringDetection();
84
+ }
85
+
86
+ // Initialize Chromecast
87
+ if (this.config.allowCasting) {
88
+ await this.initializeChromecast();
89
+ }
90
+
91
+ // Setup event listeners
92
+ this.setupEventListeners();
93
+
94
+ this.status.isProtected = true;
95
+ console.log('[DRM-Android] Protection initialized');
96
+ } catch (error) {
97
+ console.error('[DRM-Android] Initialization failed:', error);
98
+ throw error;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Initialize Widevine DRM
104
+ */
105
+ private async initializeWidevine(): Promise<void> {
106
+ console.log('[DRM-Android] Initializing Widevine...');
107
+
108
+ const widevineConfig = {
109
+ licenseServerUrl: this.config.licenseServerUrl,
110
+ licenseHeaders: this.config.licenseHeaders,
111
+ securityLevel: this.config.widevineSecurityLevel,
112
+ };
113
+
114
+ const result = await DRMProtectionModule.initializeWidevine(widevineConfig);
115
+
116
+ if (result.success) {
117
+ this.status.drmSystem = 'widevine';
118
+ this.status.securityLevel = result.securityLevel;
119
+ console.log(`[DRM-Android] Widevine initialized with security level: ${result.securityLevel}`);
120
+
121
+ if (result.securityLevel === 'L3' && this.config.widevineSecurityLevel === 'L1') {
122
+ console.warn('[DRM-Android] ⚠️ Requested L1 but got L3 - device may not support hardware DRM');
123
+ }
124
+ } else {
125
+ throw {
126
+ code: DRMErrorCode.WIDEVINE_NOT_AVAILABLE,
127
+ message: 'Widevine initialization failed',
128
+ platform: 'android',
129
+ recoverable: false,
130
+ };
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Start display mirroring detection
136
+ */
137
+ private async startMirroringDetection(): Promise<void> {
138
+ console.log('[DRM-Android] Starting mirroring detection...');
139
+
140
+ // Monitor for external displays and mirroring
141
+ await DRMProtectionModule.startMirroringDetection();
142
+ }
143
+
144
+ /**
145
+ * Initialize Chromecast
146
+ */
147
+ private async initializeChromecast(): Promise<void> {
148
+ console.log('[DRM-Android] Initializing Chromecast...');
149
+
150
+ await DRMProtectionModule.initializeChromecast({
151
+ appId: 'CC1AD845', // Default Media Receiver
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Setup event listeners
157
+ */
158
+ private setupEventListeners(): void {
159
+ // Screen recording detected
160
+ this.listeners.push(
161
+ drmEventEmitter.addListener('onScreenRecordingDetected', () => {
162
+ console.warn('[DRM-Android] ⚠️ Screen recording detected!');
163
+ this.status.screenRecordingDetected = true;
164
+ this.config.onScreenRecordingDetected?.();
165
+ })
166
+ );
167
+
168
+ // Mirroring detected
169
+ this.listeners.push(
170
+ drmEventEmitter.addListener('onMirroringDetected', (event: any) => {
171
+ console.warn('[DRM-Android] ⚠️ Display mirroring detected:', event.displayName);
172
+ this.status.mirroringDetected = true;
173
+ this.config.onMirroringDetected?.();
174
+ })
175
+ );
176
+
177
+ // Casting started
178
+ this.listeners.push(
179
+ drmEventEmitter.addListener('onCastingStarted', (event: any) => {
180
+ console.log('[DRM-Android] Casting started:', event.deviceName);
181
+ this.status.isCasting = true;
182
+ this.status.castDevice = {
183
+ name: event.deviceName,
184
+ type: 'chromecast',
185
+ };
186
+ this.config.onCastingStarted?.(event.deviceName, 'chromecast');
187
+ })
188
+ );
189
+
190
+ // Casting ended
191
+ this.listeners.push(
192
+ drmEventEmitter.addListener('onCastingEnded', () => {
193
+ console.log('[DRM-Android] Casting ended');
194
+ this.status.isCasting = false;
195
+ this.status.castDevice = undefined;
196
+ this.config.onCastingEnded?.();
197
+ })
198
+ );
199
+
200
+ // License acquired
201
+ this.listeners.push(
202
+ drmEventEmitter.addListener('onLicenseAcquired', (event: any) => {
203
+ console.log('[DRM-Android] License acquired');
204
+ this.status.licenseExpiration = event.expirationTime ? new Date(event.expirationTime) : undefined;
205
+ this.config.onLicenseAcquired?.();
206
+ })
207
+ );
208
+
209
+ // DRM error
210
+ this.listeners.push(
211
+ drmEventEmitter.addListener('onDRMError', (error: any) => {
212
+ console.error('[DRM-Android] DRM Error:', error);
213
+ this.config.onDRMError?.(error);
214
+ })
215
+ );
216
+ }
217
+
218
+ /**
219
+ * Get current status
220
+ */
221
+ getStatus(): IDRMProtectionStatus {
222
+ return { ...this.status };
223
+ }
224
+
225
+ /**
226
+ * Enable/disable protection
227
+ */
228
+ setEnabled(enabled: boolean): void {
229
+ this.config.enabled = enabled;
230
+ DRMProtectionModule.setEnabled(enabled);
231
+ }
232
+
233
+ /**
234
+ * Set specific feature
235
+ */
236
+ setFeature(feature: keyof IDRMProtectionConfig, enabled: boolean): void {
237
+ (this.config as any)[feature] = enabled;
238
+
239
+ switch (feature) {
240
+ case 'blockScreenshots':
241
+ case 'blockScreenRecording':
242
+ DRMProtectionModule.enableFlagSecure(enabled);
243
+ this.status.isScreenshotBlocked = enabled;
244
+ this.status.isScreenRecordingBlocked = enabled;
245
+ break;
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Start casting
251
+ */
252
+ async startCasting(deviceId: string): Promise<void> {
253
+ await DRMProtectionModule.startCasting(deviceId);
254
+ }
255
+
256
+ /**
257
+ * Stop casting
258
+ */
259
+ async stopCasting(): Promise<void> {
260
+ await DRMProtectionModule.stopCasting();
261
+ }
262
+
263
+ /**
264
+ * Get available cast devices
265
+ */
266
+ async getAvailableCastDevices(): Promise<CastDevice[]> {
267
+ const devices = await DRMProtectionModule.getAvailableCastDevices();
268
+ return devices.map((device: any) => ({
269
+ id: device.id,
270
+ name: device.name,
271
+ type: 'chromecast',
272
+ isAvailable: device.isAvailable,
273
+ capabilities: {
274
+ supportsVideo: true,
275
+ supportsAudio: true,
276
+ supportsDRM: device.supportsDRM,
277
+ maxResolution: device.maxResolution,
278
+ },
279
+ }));
280
+ }
281
+
282
+ /**
283
+ * Renew license
284
+ */
285
+ async renewLicense(): Promise<void> {
286
+ await DRMProtectionModule.renewLicense();
287
+ }
288
+
289
+ /**
290
+ * Cleanup
291
+ */
292
+ dispose(): void {
293
+ this.listeners.forEach((listener) => listener.remove());
294
+ this.listeners = [];
295
+ DRMProtectionModule.dispose();
296
+ this.status.isProtected = false;
297
+ }
298
+ }
299
+
300
+ /**
301
+ * NATIVE ANDROID MODULE (Java/Kotlin)
302
+ *
303
+ * File: android/app/src/main/java/com/yourapp/DRMProtectionModule.kt
304
+ *
305
+ * ```kotlin
306
+ * package com.yourapp
307
+ *
308
+ * import android.view.WindowManager
309
+ * import android.hardware.display.DisplayManager
310
+ * import android.media.MediaDrm
311
+ * import com.facebook.react.bridge.*
312
+ * import com.facebook.react.modules.core.DeviceEventManagerModule
313
+ * import com.google.android.gms.cast.framework.CastContext
314
+ * import com.google.android.exoplayer2.drm.*
315
+ *
316
+ * class DRMProtectionModule(reactContext: ReactApplicationContext) :
317
+ * ReactContextBaseJavaModule(reactContext) {
318
+ *
319
+ * private val WIDEVINE_UUID = UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL)
320
+ * private var mediaDrm: MediaDrm? = null
321
+ * private var displayManager: DisplayManager? = null
322
+ *
323
+ * override fun getName(): String = "DRMProtectionModule"
324
+ *
325
+ * @ReactMethod
326
+ * fun enableFlagSecure(enabled: Boolean, promise: Promise) {
327
+ * try {
328
+ * currentActivity?.runOnUiThread {
329
+ * val window = currentActivity?.window
330
+ * if (enabled) {
331
+ * window?.setFlags(
332
+ * WindowManager.LayoutParams.FLAG_SECURE,
333
+ * WindowManager.LayoutParams.FLAG_SECURE
334
+ * )
335
+ * } else {
336
+ * window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
337
+ * }
338
+ * }
339
+ * promise.resolve(true)
340
+ * } catch (e: Exception) {
341
+ * promise.reject("FLAG_SECURE_ERROR", e.message)
342
+ * }
343
+ * }
344
+ *
345
+ * @ReactMethod
346
+ * fun initializeWidevine(config: ReadableMap, promise: Promise) {
347
+ * try {
348
+ * mediaDrm = MediaDrm(WIDEVINE_UUID)
349
+ *
350
+ * val securityLevel = mediaDrm?.getPropertyString("securityLevel")
351
+ * val hdcpLevel = mediaDrm?.getPropertyString("hdcpLevel")
352
+ *
353
+ * val result = Arguments.createMap().apply {
354
+ * putBoolean("success", true)
355
+ * putString("securityLevel", securityLevel)
356
+ * putString("hdcpLevel", hdcpLevel)
357
+ * }
358
+ *
359
+ * promise.resolve(result)
360
+ * } catch (e: Exception) {
361
+ * promise.reject("WIDEVINE_ERROR", e.message)
362
+ * }
363
+ * }
364
+ *
365
+ * @ReactMethod
366
+ * fun startMirroringDetection(promise: Promise) {
367
+ * try {
368
+ * displayManager = reactApplicationContext
369
+ * .getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
370
+ *
371
+ * val callback = object : DisplayManager.DisplayListener {
372
+ * override fun onDisplayAdded(displayId: Int) {
373
+ * val display = displayManager?.getDisplay(displayId)
374
+ * if (display != null && display.displayId != Display.DEFAULT_DISPLAY) {
375
+ * // External display detected - could be mirroring
376
+ * sendEvent("onMirroringDetected", Arguments.createMap().apply {
377
+ * putInt("displayId", displayId)
378
+ * putString("displayName", display.name)
379
+ * })
380
+ * }
381
+ * }
382
+ *
383
+ * override fun onDisplayRemoved(displayId: Int) {}
384
+ * override fun onDisplayChanged(displayId: Int) {}
385
+ * }
386
+ *
387
+ * displayManager?.registerDisplayListener(callback, null)
388
+ * promise.resolve(true)
389
+ * } catch (e: Exception) {
390
+ * promise.reject("MIRRORING_DETECTION_ERROR", e.message)
391
+ * }
392
+ * }
393
+ *
394
+ * @ReactMethod
395
+ * fun initializeChromecast(config: ReadableMap, promise: Promise) {
396
+ * try {
397
+ * // Initialize Google Cast
398
+ * CastContext.getSharedInstance(reactApplicationContext)
399
+ * promise.resolve(true)
400
+ * } catch (e: Exception) {
401
+ * promise.reject("CHROMECAST_ERROR", e.message)
402
+ * }
403
+ * }
404
+ *
405
+ * private fun sendEvent(eventName: String, params: WritableMap) {
406
+ * reactApplicationContext
407
+ * .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
408
+ * .emit(eventName, params)
409
+ * }
410
+ * }
411
+ * ```
412
+ *
413
+ * MANIFEST PERMISSIONS:
414
+ * ```xml
415
+ * <uses-permission android:name="android.permission.INTERNET" />
416
+ * <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
417
+ * <uses-permission android:name="com.google.android.gms.permission.AD_ID" />
418
+ * ```
419
+ */