Merge branch 'master' into testing

This commit is contained in:
Brion Vibber 2010-09-02 14:58:11 -07:00
commit e365e709c5
4 changed files with 93 additions and 4 deletions

View File

@ -203,7 +203,7 @@ class Action extends HTMLOutputter // lawsuit
if (Event::handle('StartShowStatusNetStyles', array($this)) && if (Event::handle('StartShowStatusNetStyles', array($this)) &&
Event::handle('StartShowLaconicaStyles', 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('EndShowStatusNetStyles', array($this));
Event::handle('EndShowLaconicaStyles', 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 * Show javascript headers
* *

View File

@ -54,6 +54,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
class Theme class Theme
{ {
var $name = null;
var $dir = null; var $dir = null;
var $path = null; var $path = null;
@ -70,6 +71,10 @@ class Theme
if (empty($name)) { if (empty($name)) {
$name = common_config('site', 'theme'); $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 // Check to see if it's in the local dir
@ -177,6 +182,58 @@ class Theme
return $this->path.'/'.$relative; 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 * Gets the full path of a file in a theme dir based on its relative name
* *
@ -285,4 +342,9 @@ class Theme
return $instroot; return $instroot;
} }
static function validName($name)
{
return preg_match('/^[a-z0-9][a-z0-9_-]*$/i', $name);
}
} }

View File

@ -192,37 +192,52 @@ class ThemeUploader
if (in_array(strtolower($ext), $skip)) { if (in_array(strtolower($ext), $skip)) {
return true; 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; return false;
} }
protected function validateFile($filename, $ext) protected function validateFile($filename, $ext)
{ {
$this->validateFileOrFolder($filename); $this->validateFileOrFolder($filename);
$this->validateExtension($ext); $this->validateExtension($filename, $ext);
// @fixme validate content // @fixme validate content
} }
protected function validateFileOrFolder($name) protected function validateFileOrFolder($name)
{ {
if (!preg_match('/^[a-z0-9_\.-]+$/i', $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. " . $msg = _("Theme contains invalid file or folder name. " .
"Stick with ASCII letters, digits, underscore, and minus sign."); "Stick with ASCII letters, digits, underscore, and minus sign.");
throw new ClientException($msg); throw new ClientException($msg);
} }
if (preg_match('/\.(php|cgi|asp|aspx|js|vb)\w/i', $name)) { 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."); $msg = _("Theme contains unsafe file extension names; may be unsafe.");
throw new ClientException($msg); throw new ClientException($msg);
} }
return true; return true;
} }
protected function validateExtension($ext) protected function validateExtension($base, $ext)
{ {
$allowed = array('css', // CSS may need validation $allowed = array('css', // CSS may need validation
'png', 'gif', 'jpg', 'jpeg', 'png', 'gif', 'jpg', 'jpeg',
'svg', // SVG images/fonts may need validation 'svg', // SVG images/fonts may need validation
'ttf', 'eot', 'woff'); 'ttf', 'eot', 'woff');
if (!in_array(strtolower($ext), $allowed)) { if (!in_array(strtolower($ext), $allowed)) {
if ($ext == 'ini' && $base == 'theme') {
// theme.ini exception
return true;
}
$msg = sprintf(_("Theme contains file of type '.%s', " . $msg = sprintf(_("Theme contains file of type '.%s', " .
"which is not allowed."), "which is not allowed."),
$ext); $ext);

View File

@ -241,7 +241,7 @@ class MobileProfilePlugin extends WAP20Plugin
return true; return true;
} }
$action->cssLink('css/display.css'); $action->primaryCssLink();
if (file_exists(Theme::file('css/mp-screen.css'))) { if (file_exists(Theme::file('css/mp-screen.css'))) {
$action->cssLink('css/mp-screen.css', null, 'screen'); $action->cssLink('css/mp-screen.css', null, 'screen');