![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/.cursor-server/data/User/History/-33e3d813/ |
<?php
/**
* HLS Key Server - Serves encryption keys for HLS segments
* This is a critical security component - keys must be protected
*/
error_reporting(0);
ini_set('display_errors', 0);
ob_start();
session_start();
require_once __DIR__ . '/audio_token.php';
require_once __DIR__ . '/../config/database.php';
// Get parameters
$keyId = $_GET['key_id'] ?? '';
$token = $_GET['token'] ?? '';
$expires = isset($_GET['expires']) ? (int)$_GET['expires'] : 0;
$trackId = isset($_GET['track_id']) ? (int)$_GET['track_id'] : 0;
ob_clean();
// Validate inputs
if (empty($keyId) || empty($token) || empty($expires) || !$trackId) {
http_response_code(400);
header('Content-Type: text/plain');
echo "Invalid request";
exit;
}
// Validate token first
$user_id = $_SESSION['user_id'] ?? null;
$session_id = session_id();
if (!validateAudioToken($trackId, null, $token, $expires, $user_id, $session_id)) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied - invalid token";
exit;
}
// Get database connection
$pdo = getDBConnection();
if (!$pdo) {
http_response_code(500);
header('Content-Type: text/plain');
echo "Database error";
exit;
}
// Verify track access
$stmt = $pdo->prepare("SELECT id, is_public, user_id FROM music_tracks WHERE id = ? AND status = 'complete'");
$stmt->execute([$trackId]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
http_response_code(404);
header('Content-Type: text/plain');
echo "Track not found";
exit;
}
// Check access
$isOwner = ($user_id && $track['user_id'] == $user_id);
$isPublic = ($track['is_public'] == 1);
if (!$isOwner && !$isPublic) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied";
exit;
}
// Get or generate encryption key for this track
// Keys are stored per track and rotated periodically
function getOrCreateEncryptionKey($trackId, $pdo) {
// Create keys table if needed
try {
$pdo->exec("
CREATE TABLE IF NOT EXISTS hls_encryption_keys (
id INT AUTO_INCREMENT PRIMARY KEY,
track_id INT NOT NULL,
key_id VARCHAR(64) NOT NULL,
encryption_key BINARY(16) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NULL,
INDEX idx_track_key (track_id, key_id),
INDEX idx_expires (expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
} catch (Exception $e) {
// Table exists, continue
}
// Check for existing valid key
$stmt = $pdo->prepare("
SELECT encryption_key, key_id
FROM hls_encryption_keys
WHERE track_id = ?
AND (expires_at IS NULL OR expires_at > NOW())
ORDER BY created_at DESC
LIMIT 1
");
$stmt->execute([$trackId]);
$existing = $stmt->fetch(PDO::FETCH_ASSOC);
if ($existing) {
return [
'key' => $existing['encryption_key'],
'key_id' => $existing['key_id']
];
}
// Generate new key (AES-128 requires 16 bytes)
$newKey = random_bytes(16);
$newKeyId = bin2hex(random_bytes(16)); // 32 hex chars
// Store key (expires in 24 hours for security)
$stmt = $pdo->prepare("
INSERT INTO hls_encryption_keys (track_id, key_id, encryption_key, expires_at)
VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL 24 HOUR))
");
$stmt->execute([$trackId, $newKeyId, $newKey]);
// Clean old keys
$pdo->exec("DELETE FROM hls_encryption_keys WHERE expires_at < NOW()");
return [
'key' => $newKey,
'key_id' => $newKeyId
];
}
// Get the encryption key
$keyData = getOrCreateEncryptionKey($trackId, $pdo);
// Verify the requested key_id matches
if ($keyData['key_id'] !== $keyId) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Invalid key ID";
exit;
}
// Serve the key (binary format for HLS)
header('Content-Type: application/octet-stream');
header('Content-Length: ' . strlen($keyData['key']));
header('Cache-Control: private, no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
echo $keyData['key'];
exit;
?>