<?php
require_once('.rtmp_auth/.config.php');
/**
* @author Gernot WALZL
*/
class Authenticator {
protected $config = null;
function __construct($config) {
$this->config = $config;
}
function authenticate() {
header('WWW-Authenticate: Basic');
header('HTTP/1.0 401 Unauthorized');
return false;
}
function verify($username, $password) {
$result = false;
if (isset($this->config->pass_hashes[$username])) {
$pass_hash = $this->config->pass_hashes[$username];
$result = password_verify($password, $pass_hash);
}
return $result;
}
}
/**
* @author Gernot WALZL
*/
class RtmpAuthDAO {
function authorize_addr($user, $addr) {
if (false !== strpos($user, '..')) {
return false;
}
$filename = dirname(__FILE__).'/.rtmp_auth/'.$user.'.addr';
$result = false;
$fp = fopen($filename, 'w');
if ($fp) {
if (fwrite($fp, $addr."\n") > 0) {
$result = true;
}
fclose($fp);
}
return $result;
}
function get_addr($user) {
if (false !== strpos($user, '..')) {
return null;
}
$filepath = dirname(__FILE__).'/.rtmp_auth/'.$user.'.addr';
$result = null;
if (is_file($filepath)) {
$result = trim(file_get_contents($filepath));
}
return $result;
}
function is_authorized_addr($addr) {
$result = false;
$path = dirname(__FILE__).'/.rtmp_auth';
if ($handle = opendir($path)) {
while (false !== ($entry = readdir($handle))) {
$filepath = $path.'/'.$entry;
if (is_file($filepath)) {
$path_parts = pathinfo($filepath);
if ($path_parts['extension'] === 'addr') {
if ($addr == $this->get_addr($path_parts['filename'])) {
$result = true;
break;
}
}
}
}
closedir($handle);
}
return $result;
}
}
/**
* @author Gernot WALZL
*/
class RtmpAuthHTML {
function println($msg) {
print($msg."\n");
}
function print_head($title='RTMP Authentication') {
$this->println('<!DOCTYPE html>');
$this->println('<html lang="en">');
$this->println('<head>');
$this->println('<meta charset="utf-8" />');
$this->println('<title>'.$title.'</title>');
$this->println('<meta name="viewport" '.
'content="width=device-width, initial-scale=1.0" />');
$this->println('</head>');
$this->println('<body>');
$this->println('<h1>'.$title.'</h1>');
}
function print_foot() {
$this->println('</body>');
$this->println('</html>');
}
function print_unauthorized() {
$this->println('<p>This server could not verify that you are '.
'authorized to access the document requested.</p>');
}
function print_authorized($user, $addr) {
$this->println('<p>User <em>'.$user.'</em> has authorized<br />');
$this->println('the address <code>'.$addr.'</code><br />');
$this->println('for RTMP.</p>');
}
}
if (isset($_POST['call'])) { // nginx-rtmp-module always sets call
if (isset($_POST['addr'])) {
$addr = $_POST['addr'];
$dao = new RtmpAuthDAO();
if ($dao->is_authorized_addr($addr)) {
http_response_code(200);
} else {
http_response_code(401);
}
} else {
http_response_code(401);
}
} else {
if (!isset($_SERVER['HTTPS'])) {
header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
exit();
}
$config = new RtmpAuthConfig();
$html = new RtmpAuthHTML();
$auth = new Authenticator($config);
$user = '';
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
if ($auth->verify($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
$user = $_SERVER['PHP_AUTH_USER'];
}
}
if (empty($user)) {
if (!$auth->authenticate()) {
$html->print_head('401 Unauthorized');
$html->print_unauthorized();
$html->print_foot();
}
} else {
$dao = new RtmpAuthDAO();
$dao->authorize_addr($user, $_SERVER['REMOTE_ADDR']);
$html->print_head();
$html->print_authorized($user, $dao->get_addr($user));
$html->print_foot();
}
}
?>