1.0.0 • Published 8 months ago
@raqemi/video-drm v1.0.0
Raqemi Video DRM
A comprehensive Digital Rights Management (DRM) solution for Next.js applications, specifically designed to protect video content in Learning Management Systems and similar platforms.
Features
- Strong Encryption: AES-256 encryption for video content
- Secure Streaming: HLS/DASH streaming with encryption
- Multiple Storage Options: Local storage, Amazon S3, and Cloudinary
- Anti-Piracy Protection:
- Prevents screen capture and recording
- Blocks browser developer tools
- Applies dynamic watermarks
- Prevents right-click downloading
- Session Management: Controls concurrent user sessions
- Device Fingerprinting: Identifies and restricts suspicious devices
- License Management: Token-based access control for videos
- Easy Integration: React components for seamless integration
Installation
npm install @raqemi/video-drm
# or
yarn add @raqemi/video-drmQuick Start
1. Initialize the DRM System
// _app.tsx or similar entry point
import { initializeRaqemiDRM } from '@raqemi/video-drm';
initializeRaqemiDRM({
storage: {
type: 'local',
path: './videos'
// For S3:
// type: 's3',
// s3: {
// region: 'us-east-1',
// bucket: 'your-bucket',
// accessKeyId: process.env.AWS_ACCESS_KEY_ID,
// secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
// }
},
encryption: {
algorithm: 'aes-256-gcm',
keySize: 256,
secretKey: process.env.ENCRYPTION_SECRET_KEY,
enableSegmentEncryption: true
},
license: {
tokenExpiryTime: 3600, // 1 hour
jwtSecret: process.env.JWT_SECRET,
allowedDomains: ['yourdomain.com'],
maxConcurrentSessions: 2
},
protection: {
preventScreenCapture: true,
preventRightClick: true,
applyWatermark: true,
watermarkText: 'Confidential Content',
watermarkOpacity: 0.3,
detectVirtualMachines: true,
blockDevTools: true
}
});2. Create API Routes for Video Access
// pages/api/videos/[id]/stream.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { validateToken, getVideoMetadata } from '@raqemi/video-drm';
import fs from 'fs';
import path from 'path';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query;
const token = req.headers.authorization?.replace('Bearer ', '') || req.query.token as string;
try {
// Validate token
const decodedToken = await validateToken(token);
// Check if token is for the requested video
if (decodedToken.videoId !== id) {
return res.status(403).json({ error: 'Invalid token for this video' });
}
// Get video metadata
const metadata = await getVideoMetadata(id as string);
if (!metadata) {
return res.status(404).json({ error: 'Video not found' });
}
// Set headers for video streaming
res.setHeader('Content-Type', 'application/x-mpegURL');
res.setHeader('Access-Control-Allow-Origin', '*');
// Stream the video
const videoPath = path.join(process.cwd(), 'videos', metadata.fileName);
const videoStream = fs.createReadStream(videoPath);
videoStream.pipe(res);
} catch (error) {
console.error('Error streaming video:', error);
res.status(500).json({ error: 'Error streaming video' });
}
}// pages/api/license/index.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { getLicenseToken } from '@raqemi/video-drm';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { videoId, userId } = req.body;
try {
// Get JWT token for video access
const token = await getLicenseToken(videoId, userId);
res.status(200).json({ token });
} catch (error) {
console.error('Error generating license token:', error);
res.status(500).json({ error: 'Error generating license token' });
}
}3. Use the Secure Video Player Component
// pages/courses/[id].tsx
import { SecurePlayer } from '@raqemi/video-drm';
import { useEffect, useState } from 'react';
export default function CoursePage({ courseId, videoId }) {
const [token, setToken] = useState('');
useEffect(() => {
// Get license token
const fetchToken = async () => {
const response = await fetch('/api/license', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
videoId,
userId: 'user-123',
}),
});
const data = await response.json();
setToken(data.token);
};
if (videoId) {
fetchToken();
}
}, [videoId]);
if (!token) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Course Video</h1>
<SecurePlayer
videoId={videoId}
width="100%"
height="auto"
autoPlay={false}
controls={true}
watermarkText={`User: user-123 - Course: ${courseId}`}
/>
</div>
);
}4. Add the Upload Component
// pages/admin/upload.tsx
import { UploadComponent } from '@raqemi/video-drm';
import { useState } from 'react';
export default function UploadPage() {
const [uploadedVideo, setUploadedVideo] = useState(null);
const handleUploadComplete = (metadata) => {
setUploadedVideo(metadata);
// Notify server or update database
};
return (
<div>
<h1>Upload Course Video</h1>
<UploadComponent
userId="admin-user"
onUploadComplete={handleUploadComplete}
onUploadError={(error) => console.error('Upload error:', error)}
onUploadProgress={(progress) => console.log('Upload progress:', progress)}
acceptedFileTypes="video/mp4,video/webm,video/ogg"
maxFileSize={1024 * 1024 * 500} // 500MB
metadata={{
title: 'Introduction to Course',
allowedRoles: ['subscriber', 'premium']
}}
/>
{uploadedVideo && (
<div>
<h2>Upload Successful!</h2>
<p>Video ID: {uploadedVideo.id}</p>
<p>Title: {uploadedVideo.title}</p>
</div>
)}
</div>
);
}Configuration Options
Storage Configuration
| Option | Type | Description |
|---|---|---|
type | 'local' \| 's3' \| 'cloudinary' | Storage provider type |
path | string | Local storage path (for type 'local') |
s3 | object | S3 configuration object (for type 's3') |
cloudinary | object | Cloudinary configuration (for type 'cloudinary') |
Encryption Configuration
| Option | Type | Description |
|---|---|---|
algorithm | 'aes-256-cbc' \| 'aes-256-ctr' \| 'aes-256-gcm' | Encryption algorithm |
keySize | 256 \| 128 | Key size in bits |
enableSegmentEncryption | boolean | Enable per-segment encryption for HLS |
secretKey | string | Master encryption key |
ivSize | number | Initialization vector size |
License Management
| Option | Type | Description |
|---|---|---|
tokenExpiryTime | number | Token expiry time in seconds |
jwtSecret | string | Secret for JWT signing |
allowedDomains | string[] | List of domains allowed to play videos |
maxConcurrentSessions | number | Maximum number of concurrent user sessions |
Protection Features
| Option | Type | Description |
|---|---|---|
preventScreenCapture | boolean | Enable screen capture prevention |
preventRightClick | boolean | Disable right-click menu |
applyWatermark | boolean | Apply watermark to videos |
watermarkText | string | Custom watermark text |
watermarkOpacity | number | Watermark opacity (0-1) |
detectVirtualMachines | boolean | Detect and block virtual machines |
blockDevTools | boolean | Block browser developer tools |
API Reference
Components
SecurePlayer- Protected video player componentUploadComponent- Video upload component with encryption
Services
CryptoService- Handles encryption and decryptiongetLicenseToken- Generates a license token for video accessvalidateToken- Validates a license tokenuploadVideo- Uploads and encrypts a video fileprepareVideoForStreaming- Prepares a video for HLS streaming
Utilities
getFingerprint- Generates a unique device fingerprintapplyClientSideProtection- Applies protection measures to a video player
Security Considerations
- Secret Keys: Store encryption keys and JWT secrets securely and never expose them to the client
- Server-Side Validation: Always validate license tokens on the server-side
- HTTPS: Use HTTPS to prevent man-in-the-middle attacks
- Environment Variables: Store sensitive configuration in environment variables
- Regular Key Rotation: Rotate encryption keys and JWT secrets regularly
Limitations
- No DRM solution is 100% effective against determined attackers
- Some protection features may be circumvented by sophisticated tools
- Client-side protection works best when combined with server-side measures
- Screen recording protection has limitations due to browser security models
License
MIT
1.0.0
8 months ago