diff --git a/README.md b/README.md index 99aa3ffc..e7329f82 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,13 @@ It profits from these great projects: **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* * updates image and text preview diff --git a/makefile.js b/makefile.js index bf3e5c25..194107b5 100644 --- a/makefile.js +++ b/makefile.js @@ -14,7 +14,7 @@ module.exports = function (make) { $ = make.fQuery, 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'); @@ -88,30 +88,30 @@ module.exports = function (make) { var header = '/* ' + pkg.name + ' ' + pkg.version + ' - ' + pkg.url + ' */'; $(src + ': _h5ai/client/js/*.js') - .modified(mapSrc, $(src + ': _h5ai/client/js/**')) + .newerThan(mapSrc, $(src + ': _h5ai/client/js/**')) .includify() .uglifyjs({header: header}) .WRITE(mapSrc); $(src + ': _h5ai/client/css/*.less') - .modified(mapSrc, $(src + ': _h5ai/client/css/**')) + .newerThan(mapSrc, $(src + ': _h5ai/client/css/**')) .less() .cssmin({header: header}) .WRITE(mapSrc); $(src + ': **/*.jade') - .modified(mapSrc) + .newerThan(mapSrc) .handlebars(make.env) .jade() .WRITE(mapSrc); $(src + ': **, ! _h5ai/client/js/**, ! _h5ai/client/css/**, ! **/*.jade') - .modified(mapSrc) + .newerThan(mapSrc) .handlebars(make.env) .WRITE(mapSrc); - $(root + ': README*, LICENSE*') - .modified(mapRoot) + $(root + ': *.md') + .newerThan(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 () { $(src + ': _h5ai/client/js/*.js') - .modified(mapSrc, $(src + ': _h5ai/client/js/**')) + .newerThan(mapSrc, $(src + ': _h5ai/client/js/**')) .includify() // .uglifyjs() .WRITE(mapSrc); $(src + ': _h5ai/client/css/*.less') - .modified(mapSrc, $(src + ': _h5ai/client/css/**')) + .newerThan(mapSrc, $(src + ': _h5ai/client/css/**')) .less() // .cssmin() .WRITE(mapSrc); $(src + ': **/*.jade') - .modified(mapSrc) + .newerThan(mapSrc) .handlebars(make.env) .jade() .WRITE(mapSrc); $(src + ': **, ! _h5ai/client/js/**, ! _h5ai/client/css/**, ! **/*.jade') - .modified(mapSrc) + .newerThan(mapSrc) .handlebars(make.env) .WRITE(mapSrc); - $(root + ': README*, LICENSE*') - .modified(mapRoot) + $(root + ': *.md') + .newerThan(mapRoot) .WRITE(mapRoot); }); diff --git a/package.json b/package.json index b2c56528..70451e75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "h5ai", - "version": "0.24.0", + "version": "0.24.1", "description": "a modern HTTP web server index", "url": "http://larsjung.de/h5ai/", "author": "Lars Jung", diff --git a/src/_h5ai/client/css/inc/fallback.less b/src/_h5ai/client/css/inc/fallback.less index f73ef3eb..b779222c 100644 --- a/src/_h5ai/client/css/inc/fallback.less +++ b/src/_h5ai/client/css/inc/fallback.less @@ -16,31 +16,15 @@ } th { padding-bottom: 18px; - - a, a:visited { - color: #555; - 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; - } + color: #555; + font-weight: normal; + opacity: 0.4; } td { border-bottom: 1px solid @col-border; overflow: hidden; white-space: nowrap; - font-size: 16px; + font-size: 15px; a, a:active, a:visited { display: block; diff --git a/src/_h5ai/client/css/inc/h5ai-info.less b/src/_h5ai/client/css/inc/h5ai-info.less index d231be17..cafce35e 100644 --- a/src/_h5ai/client/css/inc/h5ai-info.less +++ b/src/_h5ai/client/css/inc/h5ai-info.less @@ -68,31 +68,33 @@ body#h5ai-info { margin: 0; padding: 0; - .test-label { - display: inline-block; - width: 350px; - } - .test-result { - display: inline-block; - width: 70px; - text-align: right; - font-weight: bold; - color: #aaa; + .test { + .label { + display: inline-block; + width: 350px; + } + .result { + display: inline-block; + width: 70px; + text-align: right; + font-weight: bold; + color: #aaa; - &.test-passed { - color: #5a5; + &.passed { + color: #5a5; + } + &.failed { + color: #a55; + } } - &.test-failed { - color: #a55; + .info { + 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 { diff --git a/src/_h5ai/client/js/inc/core/server.js b/src/_h5ai/client/js/inc/core/server.js index 3ca818f6..528c943c 100644 --- a/src/_h5ai/client/js/inc/core/server.js +++ b/src/_h5ai/client/js/inc/core/server.js @@ -23,6 +23,22 @@ modulejs.define('core/server', ['$', '_', 'config', 'core/location'], function ( } else { callback(); } + }, + + formRequest: function (data) { + + var $form = $('
') + .attr('action', location.getAbsHref()); + + _.each(data, function (val, key) { + + $('') + .attr('name', key) + .attr('value', val) + .appendTo($form); + }); + + $form.appendTo('body').submit().remove(); } }); diff --git a/src/_h5ai/client/js/inc/ext/download.js b/src/_h5ai/client/js/inc/ext/download.js index 4b1278d7..8d5b6881 100644 --- a/src/_h5ai/client/js/inc/ext/download.js +++ b/src/_h5ai/client/js/inc/ext/download.js @@ -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({ enabled: false, @@ -7,8 +7,6 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co packageName: 'package' }, allsettings.download), - // formats = ['tar', 'zip'], - downloadBtnTemplate = '
  • ' + '' + 'download' + @@ -16,25 +14,14 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co '' + '
  • ', - selectedHrefsStr = '', - $download, $img, - - failed = function () { - - $download.addClass('failed'); - setTimeout(function () { - $download.removeClass('failed'); - }, 1000); - }, + selectedItems = [], onSelection = function (items) { - selectedHrefsStr = ''; - if (items.length) { - selectedHrefsStr = _.map(items, function (item) { + var $download = $('#download'); - return item.absHref; - }).join('|:|'); + selectedItems = items.slice(0); + if (selectedItems.length) { $download.appendTo('#navbar').show(); } else { $download.hide(); @@ -49,26 +36,21 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co action: 'download', as: (settings.packageName || location.getItem().label) + '.' + extension, type: type, - hrefs: selectedHrefsStr - }, - $form = $(''); + hrefs: _.pluck(selectedItems, 'absHref').join('|:|') + }; - for (var key in query) { - $form.append(''); - } - $form.appendTo('body').submit().remove(); + server.formRequest(query); }, init = function () { - if (!settings.enabled || !server.api) { + if (!settings.enabled) { return; } - $download = $(downloadBtnTemplate) + $(downloadBtnTemplate) .find('a').on('click', onClick).end() .appendTo('#navbar'); - $img = $download.find('img'); event.sub('selection', onSelection); }; diff --git a/src/_h5ai/client/js/inc/info.js b/src/_h5ai/client/js/inc/info.js index 54bb59cc..8097b7f8 100644 --- a/src/_h5ai/client/js/inc/info.js +++ b/src/_h5ai/client/js/inc/info.js @@ -1,14 +1,14 @@ 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) { - $result.addClass('test-passed').text('yes'); + $result.addClass('passed').text('yes'); } 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')]); }); - $('.test.php .test-result').text(json.checks['phpversion']); + $('.test.php .result').text(json.checks['phpversion']); } }); }; diff --git a/src/_h5ai/conf/l10n/fi.json b/src/_h5ai/conf/l10n/fi.json new file mode 100644 index 00000000..c6715bf0 --- /dev/null +++ b/src/_h5ai/conf/l10n/fi.json @@ -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" +} diff --git a/src/_h5ai/conf/l10n/fr.json b/src/_h5ai/conf/l10n/fr.json index ef29b765..e2431cd1 100644 --- a/src/_h5ai/conf/l10n/fr.json +++ b/src/_h5ai/conf/l10n/fr.json @@ -1,6 +1,8 @@ { "lang": "français", "details": "détails", + "list": "liste", + "grid": "grille", "icons": "icônes", "name": "Nom", "lastModified": "Dernière modification", @@ -14,4 +16,4 @@ "dateFormat": "DD/MM/YYYY HH:mm", "filter": "filtre", "delete": "supprimer" -} \ No newline at end of file +} diff --git a/src/_h5ai/conf/l10n/hi.json b/src/_h5ai/conf/l10n/hi.json new file mode 100644 index 00000000..a6b4f619 --- /dev/null +++ b/src/_h5ai/conf/l10n/hi.json @@ -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": "हटाओ" +} diff --git a/src/_h5ai/conf/l10n/it.json b/src/_h5ai/conf/l10n/it.json index 4e733887..6f4cb90f 100644 --- a/src/_h5ai/conf/l10n/it.json +++ b/src/_h5ai/conf/l10n/it.json @@ -1,6 +1,8 @@ { "lang": "italiano", "details": "dettagli", + "list": "lista", + "grid": "griglia", "icons": "icone", "name": "Nome", "lastModified": "Ultima modifica", @@ -8,5 +10,10 @@ "parentDirectory": "Cartella Superiore", "empty": "vuota", "folders": "cartelle", - "files": "file" + "files": "file", + "download": "download", + "noMatch": "nessun risultato", + "dateFormat": "DD-MM-YYYY HH:mm", + "filter": "filtra", + "delete": "elimina" } \ No newline at end of file diff --git a/src/_h5ai/conf/l10n/zh-tw.json b/src/_h5ai/conf/l10n/zh-tw.json index 2ff1ab01..1170f347 100644 --- a/src/_h5ai/conf/l10n/zh-tw.json +++ b/src/_h5ai/conf/l10n/zh-tw.json @@ -1,6 +1,8 @@ { "lang": "正體中文", "details": "詳細資料", + "list": "清單", + "grid": "網格", "icons": "圖示", "name": "檔名", "lastModified": "上次修改", @@ -9,5 +11,9 @@ "empty": "空資料夾", "folders": "資料夾", "files": "檔案", - "download": "下載" -} \ No newline at end of file + "download": "下載", + "noMatch": "沒有符合的檔案", + "dateFormat": "YYYY-MM-DD HH:mm", /* syntax as specified on http://momentjs.com */ + "filter": "過濾", + "delete": "刪除" +} diff --git a/src/_h5ai/conf/options.json b/src/_h5ai/conf/options.json index 12f3f40c..eb8671c6 100644 --- a/src/_h5ai/conf/options.json +++ b/src/_h5ai/conf/options.json @@ -159,9 +159,9 @@ Options }, /* - Localization, for example "en", "de" etc. - see "langs" below for - possible values. Adjust it to your needs. If lang is not found in - "langs" it defaults to "en". + Localization, for example "en", "de" etc. - see "_h5ai/conf/l10n" folder for + possible values. Adjust it to your needs. If lang is not found + it defaults to "en". - lang: default language - useBroserLang: boolean, try to use browser language @@ -188,7 +188,7 @@ Options 2: mode, servername and -version */ "mode": { - "enabled": false, + "enabled": true, "display": 2 }, diff --git a/src/_h5ai/conf/types.json b/src/_h5ai/conf/types.json index bf0f5f1a..3fa61997 100644 --- a/src/_h5ai/conf/types.json +++ b/src/_h5ai/conf/types.json @@ -67,7 +67,7 @@ File types mapped to file extensions "tiff": [".tiff"], "unknown": [], "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"], "zip": [".7z", ".bz2", ".jar", ".lzma", ".war", ".z", ".Z", ".zip"] } diff --git a/src/_h5ai/index.html.jade b/src/_h5ai/index.html.jade index eea96a56..e09cbed6 100644 --- a/src/_h5ai/index.html.jade +++ b/src/_h5ai/index.html.jade @@ -33,53 +33,53 @@ html.no-js.browser( lang="en" ) h2 Server Details ul#tests li.test.php( data-id="php" ) - span.test-label PHP version - span.test-result ? - div.test-info PHP version >= 5.2.1 + span.label PHP version + span.result ? + div.info PHP version >= 5.2.1 li.test( data-id="cache" ) - span.test-label Cache directory - span.test-result ? - div.test-info Web server has write access + span.label Cache directory + span.result ? + div.info Web server has write access li.test( data-id="thumbs" ) - span.test-label Image thumbs - span.test-result ? - div.test-info PHP GD extension with JPEG support available + span.label Image thumbs + span.result ? + div.info PHP GD extension with JPEG support available li.test( data-id="exif" ) - span.test-label Use EXIF thumbs - span.test-result ? - div.test-info PHP EXIF extension available + span.label Use EXIF thumbs + span.result ? + div.info PHP EXIF extension available li.test( data-id="ffmpeg" ) - span.test-label Movie thumbs - span.test-result ? - div.test-info + span.label Movie thumbs + span.result ? + div.info | Command line program code ffmpeg | available li.test( data-id="convert" ) - span.test-label PDF thumbs - span.test-result ? - div.test-info + span.label PDF thumbs + span.result ? + div.info | Command line program code convert | available li.test( data-id="tar" ) - span.test-label Shell tar - span.test-result ? - div.test-info + span.label Shell tar + span.result ? + div.info | Command line program code tar | available li.test( data-id="zip" ) - span.test-label Shell zip - span.test-result ? - div.test-info + span.label Shell zip + span.result ? + div.info | Command line program code zip | available li.test( data-id="du" ) - span.test-label Folder sizes - span.test-result ? - div.test-info + span.label Folder sizes + span.result ? + div.info | Command line program code du | available diff --git a/src/_h5ai/server/php/inc/App.php b/src/_h5ai/server/php/inc/App.php index c353f3c9..a292d71d 100644 --- a/src/_h5ai/server/php/inc/App.php +++ b/src/_h5ai/server/php/inc/App.php @@ -137,7 +137,7 @@ class App { $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; } @@ -170,6 +170,11 @@ class App { public function get_items($abs_href, $what) { + $code = $this->get_http_code($abs_href); + if ($code != App::$MAGIC_SEQUENCE) { + return array(); + } + $cache = array(); $folder = Item::get($this, $this->get_abs_path($abs_href), $cache); @@ -207,20 +212,34 @@ class App { uasort($items, array("Item", "cmp")); $html = ""; - $html .= ""; + + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + if ($folder->get_parent($cache)) { - $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; + $html .= ""; } + foreach ($items as $item) { $type = $item->is_folder ? "folder" : "default"; $html .= ""; - $html .= ""; - $html .= ""; + $html .= ""; + $html .= ""; $html .= ""; $html .= ""; $html .= ""; } + $html .= "
    NameLast modifiedSize
    NameLast modifiedSize
    app_abs_href . "client/icons/96/folder-parent.png\" alt=\"folder-parent\"/>Parent Directory
    folder-parentParent Directory
    app_abs_href . "client/icons/96/" . $type . ".png\" alt=\"" . $type . "\"/>abs_href . "\">" . basename($item->abs_path) . "" . $type . "" . basename($item->abs_path) . "" . date("Y-m-d H:i", $item->date) . "" . ($item->size !== null ? intval($item->size / 1000) . " KB" : "" ) . "
    "; return $html; @@ -282,11 +301,19 @@ class App { } $exif = function_exists("exif_thumbnail"); $cache = @is_writable($this->get_cache_abs_path()); - $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; + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $tar = @preg_match("/tar(.exe)?$/i", `which tar`) > 0; + $zip = @preg_match("/zip(.exe)?$/i", `which zip`) > 0; + $convert = @preg_match("/convert(.exe)?$/i", `which convert`) > 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( "idx" => $this->app_abs_href . "server/php/index.php", diff --git a/src/_h5ai/server/php/inc/Thumb.php b/src/_h5ai/server/php/inc/Thumb.php index 5912f376..c4a878f3 100644 --- a/src/_h5ai/server/php/inc/Thumb.php +++ b/src/_h5ai/server/php/inc/Thumb.php @@ -2,7 +2,7 @@ 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 $THUMB_CACHE = "thumbs";