Commit e365e709 authored by Brion Vibber's avatar Brion Vibber

Merge branch 'master' into testing

parents 92538170 cbcb9b00
......@@ -203,7 +203,7 @@ class Action extends HTMLOutputter // lawsuit
if (Event::handle('StartShowStatusNetStyles', array($this)) &&
Event::handle('StartShowLaconicaStyles', array($this))) {
$this->cssLink('css/display.css',null, 'screen, projection, tv, print');
$this->primaryCssLink(null, 'screen, projection, tv, print');
Event::handle('EndShowStatusNetStyles', array($this));
Event::handle('EndShowLaconicaStyles', array($this));
}
......@@ -251,6 +251,18 @@ class Action extends HTMLOutputter // lawsuit
}
}
function primaryCssLink($mainTheme=null, $media=null)
{
// If the currently-selected theme has dependencies on other themes,
// we'll need to load their display.css files as well in order.
$theme = new Theme($mainTheme);
$baseThemes = $theme->getDeps();
foreach ($baseThemes as $baseTheme) {
$this->cssLink('css/display.css', $baseTheme, $media);
}
$this->cssLink('css/display.css', $mainTheme, $media);
}
/**
* Show javascript headers
*
......
......@@ -54,6 +54,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
class Theme
{
var $name = null;
var $dir = null;
var $path = null;
......@@ -70,6 +71,10 @@ class Theme
if (empty($name)) {
$name = common_config('site', 'theme');
}
if (!self::validName($name)) {
throw new ServerException("Invalid theme name.");
}
$this->name = $name;
// Check to see if it's in the local dir
......@@ -177,6 +182,58 @@ class Theme
return $this->path.'/'.$relative;
}
/**
* Fetch a list of other themes whose CSS needs to be pulled in before
* this theme's, based on following the theme.ini 'include' settings.
* (May be empty if this theme has no include dependencies.)
*
* @return array of strings with theme names
*/
function getDeps()
{
$chain = $this->doGetDeps(array($this->name));
array_pop($chain); // Drop us back off
return $chain;
}
protected function doGetDeps($chain)
{
$data = $this->getMetadata();
if (!empty($data['include'])) {
$include = $data['include'];
// Protect against cycles!
if (!in_array($include, $chain)) {
try {
$theme = new Theme($include);
array_unshift($chain, $include);
return $theme->doGetDeps($chain);
} catch (Exception $e) {
common_log(LOG_ERR,
"Exception while fetching theme dependencies " .
"for $this->name: " . $e->getMessage());
}
}
}
return $chain;
}
/**
* Pull data from the theme's theme.ini file.
* @fixme calling getFile will fall back to default theme, this may be unsafe.
*
* @return associative array of strings
*/
function getMetadata()
{
$iniFile = $this->getFile('theme.ini');
if (file_exists($iniFile)) {
return parse_ini_file($iniFile);
} else {
return array();
}
}
/**
* Gets the full path of a file in a theme dir based on its relative name
*
......@@ -285,4 +342,9 @@ class Theme
return $instroot;
}
static function validName($name)
{
return preg_match('/^[a-z0-9][a-z0-9_-]*$/i', $name);
}
}
......@@ -192,37 +192,52 @@ class ThemeUploader
if (in_array(strtolower($ext), $skip)) {
return true;
}
if ($filename == '' || substr($filename, 0, 1) == '.') {
// Skip Unix-style hidden files
return true;
}
if ($filename == '__MACOSX') {
// Skip awful metadata files Mac OS X slips in for you.
// Thanks Apple!
return true;
}
return false;
}
protected function validateFile($filename, $ext)
{
$this->validateFileOrFolder($filename);
$this->validateExtension($ext);
$this->validateExtension($filename, $ext);
// @fixme validate content
}
protected function validateFileOrFolder($name)
{
if (!preg_match('/^[a-z0-9_\.-]+$/i', $name)) {
common_log(LOG_ERR, "Bad theme filename: $name");
$msg = _("Theme contains invalid file or folder name. " .
"Stick with ASCII letters, digits, underscore, and minus sign.");
throw new ClientException($msg);
}
if (preg_match('/\.(php|cgi|asp|aspx|js|vb)\w/i', $name)) {
common_log(LOG_ERR, "Unsafe theme filename: $name");
$msg = _("Theme contains unsafe file extension names; may be unsafe.");
throw new ClientException($msg);
}
return true;
}
protected function validateExtension($ext)
protected function validateExtension($base, $ext)
{
$allowed = array('css', // CSS may need validation
'png', 'gif', 'jpg', 'jpeg',
'svg', // SVG images/fonts may need validation
'ttf', 'eot', 'woff');
if (!in_array(strtolower($ext), $allowed)) {
if ($ext == 'ini' && $base == 'theme') {
// theme.ini exception
return true;
}
$msg = sprintf(_("Theme contains file of type '.%s', " .
"which is not allowed."),
$ext);
......
......@@ -241,7 +241,7 @@ class MobileProfilePlugin extends WAP20Plugin
return true;
}
$action->cssLink('css/display.css');
$action->primaryCssLink();
if (file_exists(Theme::file('css/mp-screen.css'))) {
$action->cssLink('css/mp-screen.css', null, 'screen');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment