1.0.0 • Published 8 months ago

@raqemi/video-drm v1.0.0

Weekly downloads
-
License
MIT
Repository
-
Last release
8 months ago

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-drm

Quick 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

OptionTypeDescription
type'local' \| 's3' \| 'cloudinary'Storage provider type
pathstringLocal storage path (for type 'local')
s3objectS3 configuration object (for type 's3')
cloudinaryobjectCloudinary configuration (for type 'cloudinary')

Encryption Configuration

OptionTypeDescription
algorithm'aes-256-cbc' \| 'aes-256-ctr' \| 'aes-256-gcm'Encryption algorithm
keySize256 \| 128Key size in bits
enableSegmentEncryptionbooleanEnable per-segment encryption for HLS
secretKeystringMaster encryption key
ivSizenumberInitialization vector size

License Management

OptionTypeDescription
tokenExpiryTimenumberToken expiry time in seconds
jwtSecretstringSecret for JWT signing
allowedDomainsstring[]List of domains allowed to play videos
maxConcurrentSessionsnumberMaximum number of concurrent user sessions

Protection Features

OptionTypeDescription
preventScreenCapturebooleanEnable screen capture prevention
preventRightClickbooleanDisable right-click menu
applyWatermarkbooleanApply watermark to videos
watermarkTextstringCustom watermark text
watermarkOpacitynumberWatermark opacity (0-1)
detectVirtualMachinesbooleanDetect and block virtual machines
blockDevToolsbooleanBlock browser developer tools

API Reference

Components

  • SecurePlayer - Protected video player component
  • UploadComponent - Video upload component with encryption

Services

  • CryptoService - Handles encryption and decryption
  • getLicenseToken - Generates a license token for video access
  • validateToken - Validates a license token
  • uploadVideo - Uploads and encrypts a video file
  • prepareVideoForStreaming - Prepares a video for HLS streaming

Utilities

  • getFingerprint - Generates a unique device fingerprint
  • applyClientSideProtection - 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