Merge branch 'develop'

This commit is contained in:
Lars Jung 2014-04-09 18:12:33 +02:00
commit bf4870f087
18 changed files with 206 additions and 135 deletions

View file

@ -54,6 +54,13 @@ It profits from these great projects:
**h5ai** uses [semantic versioning](http://semver.org/). **h5ai** uses [semantic versioning](http://semver.org/).
### v0.24.1 - *2014-04-09*
* security fixes! (issues #268, #269)
* language updates (`fi`, `fr`, `hi`, `it`, `zh-tw`)
* fixes WinOS command detection
### v0.24.0 - *2013-09-04* ### v0.24.0 - *2013-09-04*
* updates image and text preview * updates image and text preview

View file

@ -14,7 +14,7 @@ module.exports = function (make) {
$ = make.fQuery, $ = make.fQuery,
mapSrc = $.map.p(src, build).s('.less', '.css').s('.jade', ''), mapSrc = $.map.p(src, build).s('.less', '.css').s('.jade', ''),
mapRoot = $.map.p(root, build); mapRoot = $.map.p(root, path.join(build, '_h5ai'));
make.version('>=0.10.0'); make.version('>=0.10.0');
@ -88,30 +88,30 @@ module.exports = function (make) {
var header = '/* ' + pkg.name + ' ' + pkg.version + ' - ' + pkg.url + ' */'; var header = '/* ' + pkg.name + ' ' + pkg.version + ' - ' + pkg.url + ' */';
$(src + ': _h5ai/client/js/*.js') $(src + ': _h5ai/client/js/*.js')
.modified(mapSrc, $(src + ': _h5ai/client/js/**')) .newerThan(mapSrc, $(src + ': _h5ai/client/js/**'))
.includify() .includify()
.uglifyjs({header: header}) .uglifyjs({header: header})
.WRITE(mapSrc); .WRITE(mapSrc);
$(src + ': _h5ai/client/css/*.less') $(src + ': _h5ai/client/css/*.less')
.modified(mapSrc, $(src + ': _h5ai/client/css/**')) .newerThan(mapSrc, $(src + ': _h5ai/client/css/**'))
.less() .less()
.cssmin({header: header}) .cssmin({header: header})
.WRITE(mapSrc); .WRITE(mapSrc);
$(src + ': **/*.jade') $(src + ': **/*.jade')
.modified(mapSrc) .newerThan(mapSrc)
.handlebars(make.env) .handlebars(make.env)
.jade() .jade()
.WRITE(mapSrc); .WRITE(mapSrc);
$(src + ': **, ! _h5ai/client/js/**, ! _h5ai/client/css/**, ! **/*.jade') $(src + ': **, ! _h5ai/client/js/**, ! _h5ai/client/css/**, ! **/*.jade')
.modified(mapSrc) .newerThan(mapSrc)
.handlebars(make.env) .handlebars(make.env)
.WRITE(mapSrc); .WRITE(mapSrc);
$(root + ': README*, LICENSE*') $(root + ': *.md')
.modified(mapRoot) .newerThan(mapRoot)
.WRITE(mapRoot); .WRITE(mapRoot);
}); });
@ -119,30 +119,30 @@ module.exports = function (make) {
make.target('build-uncompressed', ['check-version'], 'build all updated files without compression').sync(function () { make.target('build-uncompressed', ['check-version'], 'build all updated files without compression').sync(function () {
$(src + ': _h5ai/client/js/*.js') $(src + ': _h5ai/client/js/*.js')
.modified(mapSrc, $(src + ': _h5ai/client/js/**')) .newerThan(mapSrc, $(src + ': _h5ai/client/js/**'))
.includify() .includify()
// .uglifyjs() // .uglifyjs()
.WRITE(mapSrc); .WRITE(mapSrc);
$(src + ': _h5ai/client/css/*.less') $(src + ': _h5ai/client/css/*.less')
.modified(mapSrc, $(src + ': _h5ai/client/css/**')) .newerThan(mapSrc, $(src + ': _h5ai/client/css/**'))
.less() .less()
// .cssmin() // .cssmin()
.WRITE(mapSrc); .WRITE(mapSrc);
$(src + ': **/*.jade') $(src + ': **/*.jade')
.modified(mapSrc) .newerThan(mapSrc)
.handlebars(make.env) .handlebars(make.env)
.jade() .jade()
.WRITE(mapSrc); .WRITE(mapSrc);
$(src + ': **, ! _h5ai/client/js/**, ! _h5ai/client/css/**, ! **/*.jade') $(src + ': **, ! _h5ai/client/js/**, ! _h5ai/client/css/**, ! **/*.jade')
.modified(mapSrc) .newerThan(mapSrc)
.handlebars(make.env) .handlebars(make.env)
.WRITE(mapSrc); .WRITE(mapSrc);
$(root + ': README*, LICENSE*') $(root + ': *.md')
.modified(mapRoot) .newerThan(mapRoot)
.WRITE(mapRoot); .WRITE(mapRoot);
}); });

View file

@ -1,6 +1,6 @@
{ {
"name": "h5ai", "name": "h5ai",
"version": "0.24.0", "version": "0.24.1",
"description": "a modern HTTP web server index", "description": "a modern HTTP web server index",
"url": "http://larsjung.de/h5ai/", "url": "http://larsjung.de/h5ai/",
"author": "Lars Jung", "author": "Lars Jung",

View file

@ -16,31 +16,15 @@
} }
th { th {
padding-bottom: 18px; padding-bottom: 18px;
color: #555;
a, a:visited { font-weight: normal;
color: #555; opacity: 0.4;
font-weight: normal;
text-decoration: none;
cursor: pointer;
opacity: 0.4;
.transition(all 0.2s ease-in-out);
&:hover {
color: #555;
opacity: 0.9;
}
}
span {
color: #555;
font-weight: normal;
opacity: 0.4;
}
} }
td { td {
border-bottom: 1px solid @col-border; border-bottom: 1px solid @col-border;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
font-size: 16px; font-size: 15px;
a, a:active, a:visited { a, a:active, a:visited {
display: block; display: block;

View file

@ -68,31 +68,33 @@ body#h5ai-info {
margin: 0; margin: 0;
padding: 0; padding: 0;
.test-label { .test {
display: inline-block; .label {
width: 350px; display: inline-block;
} width: 350px;
.test-result { }
display: inline-block; .result {
width: 70px; display: inline-block;
text-align: right; width: 70px;
font-weight: bold; text-align: right;
color: #aaa; font-weight: bold;
color: #aaa;
&.test-passed { &.passed {
color: #5a5; color: #5a5;
}
&.failed {
color: #a55;
}
} }
&.test-failed { .info {
color: #a55; margin: 4px 0 12px 12px;
font-size: 0.7em;
color: #aaa;
width: 350px;
line-height: 1.2em;
} }
} }
.test-info {
margin: 4px 0 12px 12px;
font-size: 0.7em;
color: #aaa;
width: 350px;
line-height: 1.2em;
}
} }
#bottombar { #bottombar {

View file

@ -23,6 +23,22 @@ modulejs.define('core/server', ['$', '_', 'config', 'core/location'], function (
} else { } else {
callback(); callback();
} }
},
formRequest: function (data) {
var $form = $('<form method="post" style="display:none;"/>')
.attr('action', location.getAbsHref());
_.each(data, function (val, key) {
$('<input type="hidden"/>')
.attr('name', key)
.attr('value', val)
.appendTo($form);
});
$form.appendTo('body').submit().remove();
} }
}); });

View file

@ -1,5 +1,5 @@
modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/server', 'core/location'], function (_, $, allsettings, resource, event, server, location) { modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/location', 'core/server'], function (_, $, allsettings, resource, event, location, server) {
var settings = _.extend({ var settings = _.extend({
enabled: false, enabled: false,
@ -7,8 +7,6 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
packageName: 'package' packageName: 'package'
}, allsettings.download), }, allsettings.download),
// formats = ['tar', 'zip'],
downloadBtnTemplate = '<li id="download">' + downloadBtnTemplate = '<li id="download">' +
'<a href="#">' + '<a href="#">' +
'<img src="' + resource.image('download') + '" alt="download"/>' + '<img src="' + resource.image('download') + '" alt="download"/>' +
@ -16,25 +14,14 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
'</a>' + '</a>' +
'</li>', '</li>',
selectedHrefsStr = '', selectedItems = [],
$download, $img,
failed = function () {
$download.addClass('failed');
setTimeout(function () {
$download.removeClass('failed');
}, 1000);
},
onSelection = function (items) { onSelection = function (items) {
selectedHrefsStr = ''; var $download = $('#download');
if (items.length) {
selectedHrefsStr = _.map(items, function (item) {
return item.absHref; selectedItems = items.slice(0);
}).join('|:|'); if (selectedItems.length) {
$download.appendTo('#navbar').show(); $download.appendTo('#navbar').show();
} else { } else {
$download.hide(); $download.hide();
@ -49,26 +36,21 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co
action: 'download', action: 'download',
as: (settings.packageName || location.getItem().label) + '.' + extension, as: (settings.packageName || location.getItem().label) + '.' + extension,
type: type, type: type,
hrefs: selectedHrefsStr hrefs: _.pluck(selectedItems, 'absHref').join('|:|')
}, };
$form = $('<form action="#" method="post" style="display:none;" />');
for (var key in query) { server.formRequest(query);
$form.append('<input type="hidden" name="' + key + '" value="' + query[key] + '" />');
}
$form.appendTo('body').submit().remove();
}, },
init = function () { init = function () {
if (!settings.enabled || !server.api) { if (!settings.enabled) {
return; return;
} }
$download = $(downloadBtnTemplate) $(downloadBtnTemplate)
.find('a').on('click', onClick).end() .find('a').on('click', onClick).end()
.appendTo('#navbar'); .appendTo('#navbar');
$img = $download.find('img');
event.sub('selection', onSelection); event.sub('selection', onSelection);
}; };

View file

@ -1,14 +1,14 @@
modulejs.define('info', ['$'], function ($) { modulejs.define('info', ['$'], function ($) {
var setCheckResult = function (id, result) { var setCheckResult = function (el, result) {
var $result = $(id).find('.test-result'); var $result = $(el).find('.result');
if (result) { if (result) {
$result.addClass('test-passed').text('yes'); $result.addClass('passed').text('yes');
} else { } else {
$result.addClass('test-failed').text('no'); $result.addClass('failed').text('no');
} }
}, },
@ -22,7 +22,7 @@ modulejs.define('info', ['$'], function ($) {
setCheckResult(this, json.checks[$(this).data('id')]); setCheckResult(this, json.checks[$(this).data('id')]);
}); });
$('.test.php .test-result').text(json.checks['phpversion']); $('.test.php .result').text(json.checks['phpversion']);
} }
}); });
}; };

View file

@ -0,0 +1,19 @@
{
"lang": "finnish",
"details": "tiedot",
"list": "lista",
"grid": "ruudukko",
"icons": "ikonit",
"name": "Nimi",
"lastModified": "Viimeksi muokattu",
"size": "Koko",
"parentDirectory": "Ylähakemisto",
"empty": "tyhjä",
"folders": "hakemistoa",
"files": "tiedostoa",
"download": "lataa",
"noMatch": "ei osumia",
"dateFormat": "DD.MM.YYYY HH:mm",
"filter": "suodata",
"delete": "poista"
}

View file

@ -1,6 +1,8 @@
{ {
"lang": "français", "lang": "français",
"details": "détails", "details": "détails",
"list": "liste",
"grid": "grille",
"icons": "icônes", "icons": "icônes",
"name": "Nom", "name": "Nom",
"lastModified": "Dernière modification", "lastModified": "Dernière modification",

View file

@ -0,0 +1,19 @@
{
"lang": "हिंदी",
"details": "विस्तार",
"icons": "आइकॉन",
"name": "नाम",
"lastModified": "पिछला परिवर्तन",
"size": "माप",
"parentDirectory": "मूल डायरेक्टरी",
"empty": "खाली",
"folders": "फोल्डर",
"files": "फ़ाइलें",
"download": "डाउनलोड",
"list": "सूची",
"grid": "ग्रिड",
"noMatch": "कोई समानता नहीं",
"dateFormat": "DD.MM.YYYY HH:mm",
"filter": "फ़िल्टर",
"delete": "हटाओ"
}

View file

@ -1,6 +1,8 @@
{ {
"lang": "italiano", "lang": "italiano",
"details": "dettagli", "details": "dettagli",
"list": "lista",
"grid": "griglia",
"icons": "icone", "icons": "icone",
"name": "Nome", "name": "Nome",
"lastModified": "Ultima modifica", "lastModified": "Ultima modifica",
@ -8,5 +10,10 @@
"parentDirectory": "Cartella Superiore", "parentDirectory": "Cartella Superiore",
"empty": "vuota", "empty": "vuota",
"folders": "cartelle", "folders": "cartelle",
"files": "file" "files": "file",
"download": "download",
"noMatch": "nessun risultato",
"dateFormat": "DD-MM-YYYY HH:mm",
"filter": "filtra",
"delete": "elimina"
} }

View file

@ -1,6 +1,8 @@
{ {
"lang": "正體中文", "lang": "正體中文",
"details": "詳細資料", "details": "詳細資料",
"list": "清單",
"grid": "網格",
"icons": "圖示", "icons": "圖示",
"name": "檔名", "name": "檔名",
"lastModified": "上次修改", "lastModified": "上次修改",
@ -9,5 +11,9 @@
"empty": "空資料夾", "empty": "空資料夾",
"folders": "資料夾", "folders": "資料夾",
"files": "檔案", "files": "檔案",
"download": "下載" "download": "下載",
"noMatch": "沒有符合的檔案",
"dateFormat": "YYYY-MM-DD HH:mm", /* syntax as specified on http://momentjs.com */
"filter": "過濾",
"delete": "刪除"
} }

View file

@ -159,9 +159,9 @@ Options
}, },
/* /*
Localization, for example "en", "de" etc. - see "langs" below for Localization, for example "en", "de" etc. - see "_h5ai/conf/l10n" folder for
possible values. Adjust it to your needs. If lang is not found in possible values. Adjust it to your needs. If lang is not found
"langs" it defaults to "en". it defaults to "en".
- lang: default language - lang: default language
- useBroserLang: boolean, try to use browser language - useBroserLang: boolean, try to use browser language
@ -188,7 +188,7 @@ Options
2: mode, servername and -version 2: mode, servername and -version
*/ */
"mode": { "mode": {
"enabled": false, "enabled": true,
"display": 2 "display": 2
}, },

View file

@ -67,7 +67,7 @@ File types mapped to file extensions
"tiff": [".tiff"], "tiff": [".tiff"],
"unknown": [], "unknown": [],
"vcal": [".vcal"], "vcal": [".vcal"],
"video": [".avi", ".flv", ".mkv", ".mov", ".m4v", ".mp4", ".mpg", ".rm", ".swf", ".vob", ".wmv"], "video": [".avi", ".flv", ".mkv", ".mov", ".m4v", ".mp4", ".mpg", ".rm", ".swf", ".ts", ".vob", ".wmv"],
"xml": [".xml"], "xml": [".xml"],
"zip": [".7z", ".bz2", ".jar", ".lzma", ".war", ".z", ".Z", ".zip"] "zip": [".7z", ".bz2", ".jar", ".lzma", ".war", ".z", ".Z", ".zip"]
} }

View file

@ -33,53 +33,53 @@ html.no-js.browser( lang="en" )
h2 Server Details h2 Server Details
ul#tests ul#tests
li.test.php( data-id="php" ) li.test.php( data-id="php" )
span.test-label PHP version span.label PHP version
span.test-result ? span.result ?
div.test-info PHP version &gt;= 5.2.1 div.info PHP version &gt;= 5.2.1
li.test( data-id="cache" ) li.test( data-id="cache" )
span.test-label Cache directory span.label Cache directory
span.test-result ? span.result ?
div.test-info Web server has write access div.info Web server has write access
li.test( data-id="thumbs" ) li.test( data-id="thumbs" )
span.test-label Image thumbs span.label Image thumbs
span.test-result ? span.result ?
div.test-info PHP GD extension with JPEG support available div.info PHP GD extension with JPEG support available
li.test( data-id="exif" ) li.test( data-id="exif" )
span.test-label Use EXIF thumbs span.label Use EXIF thumbs
span.test-result ? span.result ?
div.test-info PHP EXIF extension available div.info PHP EXIF extension available
li.test( data-id="ffmpeg" ) li.test( data-id="ffmpeg" )
span.test-label Movie thumbs span.label Movie thumbs
span.test-result ? span.result ?
div.test-info div.info
| Command line program | Command line program
code ffmpeg code ffmpeg
| available | available
li.test( data-id="convert" ) li.test( data-id="convert" )
span.test-label PDF thumbs span.label PDF thumbs
span.test-result ? span.result ?
div.test-info div.info
| Command line program | Command line program
code convert code convert
| available | available
li.test( data-id="tar" ) li.test( data-id="tar" )
span.test-label Shell tar span.label Shell tar
span.test-result ? span.result ?
div.test-info div.info
| Command line program | Command line program
code tar code tar
| available | available
li.test( data-id="zip" ) li.test( data-id="zip" )
span.test-label Shell zip span.label Shell zip
span.test-result ? span.result ?
div.test-info div.info
| Command line program | Command line program
code zip code zip
| available | available
li.test( data-id="du" ) li.test( data-id="du" )
span.test-label Folder sizes span.label Folder sizes
span.test-result ? span.result ?
div.test-info div.info
| Command line program | Command line program
code du code du
| available | available

View file

@ -137,7 +137,7 @@ class App {
$abs_path = $this->get_abs_path($abs_href); $abs_path = $this->get_abs_path($abs_href);
if (!is_dir($abs_path)) { if (!is_dir($abs_path) || strpos($abs_path, '../') || strpos($abs_path, '/..') || $abs_path == '..') {
return 500; return 500;
} }
@ -170,6 +170,11 @@ class App {
public function get_items($abs_href, $what) { public function get_items($abs_href, $what) {
$code = $this->get_http_code($abs_href);
if ($code != App::$MAGIC_SEQUENCE) {
return array();
}
$cache = array(); $cache = array();
$folder = Item::get($this, $this->get_abs_path($abs_href), $cache); $folder = Item::get($this, $this->get_abs_path($abs_href), $cache);
@ -207,20 +212,34 @@ class App {
uasort($items, array("Item", "cmp")); uasort($items, array("Item", "cmp"));
$html = "<table>"; $html = "<table>";
$html .= "<tr><th></th><th><span>Name</span></th><th><span>Last modified</span></th><th><span>Size</span></th></tr>";
$html .= "<tr>";
$html .= "<th></th>";
$html .= "<th><span>Name</span></th>";
$html .= "<th><span>Last modified</span></th>";
$html .= "<th><span>Size</span></th>";
$html .= "</tr>";
if ($folder->get_parent($cache)) { if ($folder->get_parent($cache)) {
$html .= "<tr><td><img src=\"" . $this->app_abs_href . "client/icons/96/folder-parent.png\" alt=\"folder-parent\"/></td><td><a href=\"..\">Parent Directory</a></td><td></td><td></td></tr>"; $html .= "<tr>";
$html .= "<td><img src='" . $this->app_abs_href . "client/icons/96/folder-parent.png' alt='folder-parent'/></td>";
$html .= "<td><a href='..'>Parent Directory</a></td>";
$html .= "<td></td>";
$html .= "<td></td>";
$html .= "</tr>";
} }
foreach ($items as $item) { foreach ($items as $item) {
$type = $item->is_folder ? "folder" : "default"; $type = $item->is_folder ? "folder" : "default";
$html .= "<tr>"; $html .= "<tr>";
$html .= "<td><img src=\"" . $this->app_abs_href . "client/icons/96/" . $type . ".png\" alt=\"" . $type . "\"/></td>"; $html .= "<td><img src='" . $this->app_abs_href . "client/icons/96/" . $type . ".png' alt='" . $type . "'/></td>";
$html .= "<td><a href=\"" . $item->abs_href . "\">" . basename($item->abs_path) . "</a></td>"; $html .= "<td><a href='" . $item->abs_href . "'>" . basename($item->abs_path) . "</a></td>";
$html .= "<td>" . date("Y-m-d H:i", $item->date) . "</td>"; $html .= "<td>" . date("Y-m-d H:i", $item->date) . "</td>";
$html .= "<td>" . ($item->size !== null ? intval($item->size / 1000) . " KB" : "" ) . "</td>"; $html .= "<td>" . ($item->size !== null ? intval($item->size / 1000) . " KB" : "" ) . "</td>";
$html .= "</tr>"; $html .= "</tr>";
} }
$html .= "</table>"; $html .= "</table>";
return $html; return $html;
@ -282,11 +301,19 @@ class App {
} }
$exif = function_exists("exif_thumbnail"); $exif = function_exists("exif_thumbnail");
$cache = @is_writable($this->get_cache_abs_path()); $cache = @is_writable($this->get_cache_abs_path());
$tar = @preg_match("/tar(.exe)?$/i", `command -v tar`) > 0; if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$zip = @preg_match("/zip(.exe)?$/i", `command -v zip`) > 0; $tar = @preg_match("/tar(.exe)?$/i", `which tar`) > 0;
$convert = @preg_match("/convert(.exe)?$/i", `command -v convert`) > 0; $zip = @preg_match("/zip(.exe)?$/i", `which zip`) > 0;
$ffmpeg = @preg_match("/ffmpeg(.exe)?$/i", `command -v ffmpeg`) > 0; $convert = @preg_match("/convert(.exe)?$/i", `which convert`) > 0;
$du = @preg_match("/du(.exe)?$/i", `command -v du`) > 0; $ffmpeg = @preg_match("/ffmpeg(.exe)?$/i", `which ffmpeg`) > 0;
$du = @preg_match("/du(.exe)?$/i", `which du`) > 0;
} else {
$tar = @preg_match("/tar(.exe)?$/i", `command -v tar`) > 0;
$zip = @preg_match("/zip(.exe)?$/i", `command -v zip`) > 0;
$convert = @preg_match("/convert(.exe)?$/i", `command -v convert`) > 0;
$ffmpeg = @preg_match("/ffmpeg(.exe)?$/i", `command -v ffmpeg`) > 0;
$du = @preg_match("/du(.exe)?$/i", `command -v du`) > 0;
}
return array( return array(
"idx" => $this->app_abs_href . "server/php/index.php", "idx" => $this->app_abs_href . "server/php/index.php",

View file

@ -2,7 +2,7 @@
class Thumb { class Thumb {
private static $FFMPEG_CMD = "ffmpeg -i [SOURCE] -an -ss 3 -vframes 1 [TARGET]"; private static $FFMPEG_CMD = "ffmpeg -ss 0:01:00 -i [SOURCE] -an -vframes 1 [TARGET]";
private static $CONVERT_CMD = "convert -strip [SOURCE][0] [TARGET]"; private static $CONVERT_CMD = "convert -strip [SOURCE][0] [TARGET]";
private static $THUMB_CACHE = "thumbs"; private static $THUMB_CACHE = "thumbs";