Merge pull request #54 from radiorabe/feature/configurable-cors

Make CORS great again
This commit is contained in:
Robb 2017-03-10 21:44:26 -05:00 committed by GitHub
commit 77ebfa93d3
7 changed files with 66 additions and 48 deletions

View File

@ -3,12 +3,9 @@
class CORSHelper class CORSHelper
{ {
public static function enableATProCrossOriginRequests(&$request, &$response) public static function enableCrossOriginRequests(&$request, &$response)
{ {
//Allow AJAX requests from www.airtime.pro. We use this to automatically login users
//after they sign up from the microsite.
//Chrome sends the Origin header for all requests, so we whitelist the webserver's hostname as well. //Chrome sends the Origin header for all requests, so we whitelist the webserver's hostname as well.
$response = $response->setHeader('Access-Control-Allow-Origin', '*');
$origin = $request->getHeader('Origin'); $origin = $request->getHeader('Origin');
if ((!(preg_match("/https?:\/\/localhost/", $origin) === 1)) && ($origin != "") && if ((!(preg_match("/https?:\/\/localhost/", $origin) === 1)) && ($origin != "") &&
(!in_array($origin, self::getAllowedOrigins()))) (!in_array($origin, self::getAllowedOrigins())))
@ -16,15 +13,20 @@ class CORSHelper
//Don't allow CORS from other domains to prevent XSS. //Don't allow CORS from other domains to prevent XSS.
throw new Zend_Controller_Action_Exception('Forbidden', 403); throw new Zend_Controller_Action_Exception('Forbidden', 403);
} }
//Allow AJAX requests from configured websites. We use this to allow other pages to use LibreTimes API.
if ($origin) {
$response = $response->setHeader('Access-Control-Allow-Origin', $origin);
}
} }
public static function getAllowedOrigins() public static function getAllowedOrigins()
{ {
return array("http://www.airtime.pro", $allowedCorsUrls = array_map(
"https://www.airtime.pro", function($v) { return trim($v); },
"https://account.sourcefabric.com", explode(PHP_EOL, Application_Model_Preference::GetAllowedCorsUrls())
"https://account.sourcefabric.com:5001", );
return array_merge($allowedCorsUrls, array(
"http://" . $_SERVER['SERVER_NAME'], "http://" . $_SERVER['SERVER_NAME'],
"https://" . $_SERVER['SERVER_NAME']); "https://" . $_SERVER['SERVER_NAME']));
} }
} }

View File

@ -209,7 +209,7 @@ class ApiController extends Zend_Controller_Action
$result["station_down"] = true; $result["station_down"] = true;
} }
echo isset($_GET['callback']) ? $_GET['callback'].'('.json_encode($result).')' : json_encode($result); $this->returnJsonOrJsonp($request, $result);
} }
/** /**
@ -295,15 +295,8 @@ class ApiController extends Zend_Controller_Action
// used by caller to determine if the airtime they are running or widgets in use is out of date. // used by caller to determine if the airtime they are running or widgets in use is out of date.
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
header("Content-Type: application/json");
if (version_compare(phpversion(), '5.4.0', '<')) { $this->returnJsonOrJsonp($request, $result);
$js = json_encode($result);
} else {
$js = json_encode($result, JSON_PRETTY_PRINT);
}
// If a callback is not given, then just provide the raw JSON.
echo isset($_GET['callback']) ? $_GET['callback'].'('.$js.')' : $js;
} else { } else {
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
print _('You are not allowed to access this resource. '); print _('You are not allowed to access this resource. ');
@ -368,15 +361,8 @@ class ApiController extends Zend_Controller_Action
// used by caller to determine if the airtime they are running or widgets in use is out of date. // used by caller to determine if the airtime they are running or widgets in use is out of date.
$result["station"]["AIRTIME_API_VERSION"] = AIRTIME_API_VERSION; $result["station"]["AIRTIME_API_VERSION"] = AIRTIME_API_VERSION;
header("Content-Type: application/json");
if (version_compare(phpversion(), '5.4.0', '<')) { $this->returnJsonOrJsonp($request, $result);
$js = json_encode($result);
} else {
$js = json_encode($result, JSON_PRETTY_PRINT);
}
// If a callback is not given, then just provide the raw JSON.
echo isset($_GET['callback']) ? $_GET['callback'].'('.$js.')' : $js;
} else { } else {
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
print _('You are not allowed to access this resource. '); print _('You are not allowed to access this resource. ');
@ -443,15 +429,7 @@ class ApiController extends Zend_Controller_Action
//used by caller to determine if the airtime they are running or widgets in use is out of date. //used by caller to determine if the airtime they are running or widgets in use is out of date.
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
header("Content-type: text/javascript"); $this->returnJsonOrJsonp($request, $result);
if (version_compare(phpversion(), '5.4.0', '<')) {
$js = json_encode($result);
} else {
$js = json_encode($result, JSON_PRETTY_PRINT);
}
// If a callback is not given, then just provide the raw JSON.
echo isset($_GET['callback']) ? $_GET['callback'].'('.$js.')' : $js;
} else { } else {
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
print _('You are not allowed to access this resource. '); print _('You are not allowed to access this resource. ');
@ -534,15 +512,8 @@ class ApiController extends Zend_Controller_Action
// used by caller to determine if the airtime they are running or widgets in use is out of date. // used by caller to determine if the airtime they are running or widgets in use is out of date.
$result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION; $result['AIRTIME_API_VERSION'] = AIRTIME_API_VERSION;
header("Content-type: text/javascript");
if (version_compare(phpversion(), '5.4.0', '<')) { $this->returnJsonOrJsonp($request, $result);
$js = json_encode($result);
} else {
$js = json_encode($result, JSON_PRETTY_PRINT);
}
// If a callback is not given, then just provide the raw JSON.
echo isset($_GET['callback']) ? $_GET['callback'].'('.$js.')' : $js;
} else { } else {
header('HTTP/1.0 401 Unauthorized'); header('HTTP/1.0 401 Unauthorized');
print _('You are not allowed to access this resource. '); print _('You are not allowed to access this resource. ');
@ -1599,4 +1570,21 @@ class ApiController extends Zend_Controller_Action
} }
echo("Recalculated $total shows."); echo("Recalculated $total shows.");
} }
private final function returnJsonOrJsonp($request, $result) {
$callback = $request->getParam('callback');
$response = $this->getResponse();
$response->setHeader('Content-Type', 'application/json');
$body = $this->_helper->json->encodeJson($result, false);
if ($callback) {
$response->setHeader('Content-Type', 'application/javascript');
$body = sprintf('%s(%s)', $callback, $body);
}
$response->setBody($body);
// enable cors access from configured URLs
CORSHelper::enableCrossOriginRequests($request, $response);
}
} }

View File

@ -24,7 +24,7 @@ class LoginController extends Zend_Controller_Action
$stationLocale = Application_Model_Preference::GetDefaultLocale(); $stationLocale = Application_Model_Preference::GetDefaultLocale();
//Enable AJAX requests from www.airtime.pro for the sign-in process. //Enable AJAX requests from www.airtime.pro for the sign-in process.
CORSHelper::enableATProCrossOriginRequests($request, $response); CORSHelper::enableCrossOriginRequests($request, $response);
Application_Model_Locale::configureLocalization($request->getcookie('airtime_locale', $stationLocale)); Application_Model_Locale::configureLocalization($request->getcookie('airtime_locale', $stationLocale));

View File

@ -46,6 +46,7 @@ class PreferenceController extends Zend_Controller_Action
Application_Model_Preference::SetDefaultFadeIn($values["stationDefaultFadeIn"]); Application_Model_Preference::SetDefaultFadeIn($values["stationDefaultFadeIn"]);
Application_Model_Preference::SetDefaultFadeOut($values["stationDefaultFadeOut"]); Application_Model_Preference::SetDefaultFadeOut($values["stationDefaultFadeOut"]);
Application_Model_Preference::SetAllow3rdPartyApi($values["thirdPartyApi"]); Application_Model_Preference::SetAllow3rdPartyApi($values["thirdPartyApi"]);
Application_Model_Preference::SetAllowedCorsUrls($values["allowedCorsUrls"]);
Application_Model_Preference::SetDefaultLocale($values["locale"]); Application_Model_Preference::SetDefaultLocale($values["locale"]);
Application_Model_Preference::SetDefaultTimezone($values["timezone"]); Application_Model_Preference::SetDefaultTimezone($values["timezone"]);
Application_Model_Preference::SetWeekStartDay($values["weekStartDay"]); Application_Model_Preference::SetWeekStartDay($values["weekStartDay"]);

View File

@ -118,6 +118,13 @@ class Application_Form_GeneralPreferences extends Zend_Form_SubForm
)); ));
$this->addElement($third_party_api); $this->addElement($third_party_api);
$allowedCorsUrlsValue = Application_Model_Preference::GetAllowedCorsUrls();
$allowedCorsUrls = new Zend_Form_Element_Textarea('allowedCorsUrls');
$allowedCorsUrls->setLabel(_('Allowed CORS URLs'));
$allowedCorsUrls->setDescription(_('Remote URLs that are allowed to access this LibreTime instance in a browser. One URL per line.'));
$allowedCorsUrls->setValue($allowedCorsUrlsValue);
$this->addElement($allowedCorsUrls);
$locale = new Zend_Form_Element_Select("locale"); $locale = new Zend_Form_Element_Select("locale");
$locale->setLabel(_("Default Language")); $locale->setLabel(_("Default Language"));
$locale->setMultiOptions(Application_Model_Locale::getLocales()); $locale->setMultiOptions(Application_Model_Locale::getLocales());

View File

@ -1645,4 +1645,23 @@ class Application_Model_Preference
public static function setBandwidthLimitUpdateTimer() { public static function setBandwidthLimitUpdateTimer() {
self::setValue("bandwidth_limit_update_timer", microtime(true)); self::setValue("bandwidth_limit_update_timer", microtime(true));
} }
/**
* Getter for CORS URLs
*
* @return string
*/
public static function GetAllowedCorsUrls() {
return self::getValue('allowed_cors_urls');
}
/**
* Setter for CORS URLs
*
* @param string $value
* @return void
*/
public static function SetAllowedCorsUrls($value) {
self::setValue('allowed_cors_urls', $value);
}
} }

View File

@ -32,6 +32,7 @@
<?php echo $this->element->getElement('stationDefaultCrossfadeDuration')->render() ?> <?php echo $this->element->getElement('stationDefaultCrossfadeDuration')->render() ?>
<?php echo $this->element->getElement('thirdPartyApi')->render() ?> <?php echo $this->element->getElement('thirdPartyApi')->render() ?>
<?php echo $this->element->getElement('allowedCorsUrls')->render() ?>
<?php echo $this->element->getElement('radioPageLoginButton')->renderViewHelper() ?> <?php echo $this->element->getElement('radioPageLoginButton')->renderViewHelper() ?>
<?php echo $this->element->getElement('radioPageLoginButton')->renderLabel() ?> <?php echo $this->element->getElement('radioPageLoginButton')->renderLabel() ?>