diff options
43 files changed, 293 insertions, 84 deletions
diff --git a/.build_number b/.build_number index 74ed7356..d0bb43fa 100644 --- a/.build_number +++ b/.build_number @@ -3,4 +3,4 @@ ; process. You don't need to edit it. In fact.. ; ; DO NOT EDIT THIS FILE BY HAND! -build_number=193 +build_number=218 @@ -24,6 +24,12 @@ define("IN_PRODUCTION", true); version_compare(PHP_VERSION, "5.2.3", "<") and exit("Gallery requires PHP 5.2.3 or newer (you're using " . PHP_VERSION . ")"); +// PHP 5.4 requires a timezone - if one isn't set date functions aren't going to work properly. +// We'll log this once the logging system is initialized (in the gallery_event::gallery_ready). +if (!ini_get("date.timezone")) { + ini_set("date.timezone", "UTC"); +} + // Gallery requires short_tags to be on !ini_get("short_open_tag") and exit("Gallery requires short_open_tag to be on."); diff --git a/installer/install.sql b/installer/install.sql index 2b8ec11e..2ba168d2 100644 --- a/installer/install.sql +++ b/installer/install.sql @@ -246,7 +246,7 @@ CREATE TABLE {modules} ( /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO {modules} VALUES (1,1,'gallery',49,1); INSERT INTO {modules} VALUES (2,1,'user',4,2); -INSERT INTO {modules} VALUES (3,1,'comment',4,3); +INSERT INTO {modules} VALUES (3,1,'comment',6,3); INSERT INTO {modules} VALUES (4,1,'organize',4,4); INSERT INTO {modules} VALUES (5,1,'info',2,5); INSERT INTO {modules} VALUES (6,1,'rss',1,6); @@ -382,7 +382,7 @@ CREATE TABLE {vars} ( `value` text, PRIMARY KEY (`id`), UNIQUE KEY `module_name` (`module_name`,`name`) -) AUTO_INCREMENT=43 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=44 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO {vars} VALUES (NULL,'gallery','active_site_theme','wind'); INSERT INTO {vars} VALUES (NULL,'gallery','active_admin_theme','admin_wind'); @@ -419,6 +419,7 @@ INSERT INTO {vars} VALUES (NULL,'gallery','identity_provider','user'); INSERT INTO {vars} VALUES (NULL,'user','minimum_password_length','5'); INSERT INTO {vars} VALUES (NULL,'comment','spam_caught','0'); INSERT INTO {vars} VALUES (NULL,'comment','access_permissions','everybody'); +INSERT INTO {vars} VALUES (NULL,'comment','rss_visible','both'); INSERT INTO {vars} VALUES (NULL,'info','show_title','1'); INSERT INTO {vars} VALUES (NULL,'info','show_description','1'); INSERT INTO {vars} VALUES (NULL,'info','show_owner','1'); diff --git a/modules/comment/controllers/admin_comments.php b/modules/comment/controllers/admin_comments.php index bcd6a939..00a7a608 100644 --- a/modules/comment/controllers/admin_comments.php +++ b/modules/comment/controllers/admin_comments.php @@ -32,8 +32,8 @@ class Admin_Comments_Controller extends Admin_Controller { $form->validate(); module::set_var("comment", "access_permissions", $form->comment_settings->access_permissions->value); - module::set_var("comment", "rss_available", - $form->comment_settings->rss_available->value); + module::set_var("comment", "rss_visible", + $form->comment_settings->rss_visible->value); message::success(t("Comment settings updated")); url::redirect("admin/comments"); } diff --git a/modules/comment/helpers/comment_installer.php b/modules/comment/helpers/comment_installer.php index a64064f6..cbb8c783 100644 --- a/modules/comment/helpers/comment_installer.php +++ b/modules/comment/helpers/comment_installer.php @@ -48,8 +48,8 @@ class comment_installer { module::set_var("comment", "spam_caught", 0); module::set_var("comment", "access_permissions", "everybody"); - module::set_var("comment", "rss_available", "both"); - module::set_version("comment", 5); + module::set_var("comment", "rss_visible", "both"); + module::set_version("comment", 6); } static function upgrade($version) { @@ -81,6 +81,16 @@ class comment_installer { module::set_var("comment", "rss_visible", "all"); module::set_version("comment", $version = 5); } + + // In version 5 we accidentally set the installer variable to rss_available when it should + // have been rss_visible. Migrate it over now, if necessary. + if ($version == 5) { + if (!module::get_var("comment", "rss_visible")) { + module::set_var("comment", "rss_visible", module::get_var("comment", "rss_available")); + } + module::clear_var("comment", "rss_available"); + module::set_version("comment", $version = 6); + } } static function uninstall() { diff --git a/modules/comment/helpers/comment_rss.php b/modules/comment/helpers/comment_rss.php index cfee4727..be1968dc 100644 --- a/modules/comment/helpers/comment_rss.php +++ b/modules/comment/helpers/comment_rss.php @@ -65,7 +65,7 @@ class comment_rss_Core { foreach ($comments->find_all($limit, $offset) as $comment) { $item = $comment->item(); $feed->comments[] = new ArrayObject( - array("pub_date" => date("D, d M Y H:i:s T", $comment->created), + array("pub_date" => date("D, d M Y H:i:s O", $comment->created), "text" => nl2br(html::purify($comment->text)), "thumb_url" => $item->thumb_url(), "thumb_height" => $item->thumb_height, diff --git a/modules/comment/module.info b/modules/comment/module.info index ecbf8885..bd4abe9f 100644 --- a/modules/comment/module.info +++ b/modules/comment/module.info @@ -1,6 +1,6 @@ name = "Comments" description = "Allows users and guests to leave comments on photos and albums." -version = 5 +version = 6 author_name = "Gallery Team" author_url = "http://codex.gallery2.org/Gallery:Team" info_url = "http://codex.gallery2.org/Gallery3:Modules:comment" diff --git a/modules/g2_import/module.info b/modules/g2_import/module.info index 30fb46d4..6b03d097 100644 --- a/modules/g2_import/module.info +++ b/modules/g2_import/module.info @@ -1,4 +1,4 @@ -name = "Gallery2 Import" +name = "Gallery 2 Import" description = "Import your Gallery 2 content into Gallery 3" version = 2 author_name = "Gallery Team" diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php index 5c958a8d..36c6bc2a 100644 --- a/modules/gallery/controllers/file_proxy.php +++ b/modules/gallery/controllers/file_proxy.php @@ -122,7 +122,15 @@ class File_Proxy_Controller extends Controller { } else { header("Content-Type: $item->mime_type"); } - Kohana::close_buffers(false); + + // Don't use Kohana::close_buffers(false) here because that only closes all the buffers + // that Kohana started. We want to close *all* buffers at this point because otherwise we're + // going to buffer up whatever file we're proxying (and it may be very large). This may + // affect embedding or systems with PHP's output_buffering enabled. + while (ob_get_level()) { + ob_end_clean(); + } + readfile($file); } } diff --git a/modules/gallery/controllers/items.php b/modules/gallery/controllers/items.php index 0c20803c..318fb431 100644 --- a/modules/gallery/controllers/items.php +++ b/modules/gallery/controllers/items.php @@ -24,15 +24,15 @@ class Items_Controller extends Controller { throw new Kohana_404_Exception(); } - // Redirect to the more specific resource type, since it will render - // differently. We can't delegate here because we may have gotten to this - // page via /items/<id> which means that we don't have a type-specific controller. Also, we - // want to drive a single canonical resource mapping where possible. + // Redirect to the more specific resource type, since it will render differently. We can't + // delegate here because we may have gotten to this page via /items/<id> which means that we + // don't have a type-specific controller. Also, we want to drive a single canonical resource + // mapping where possible. access::required("view", $item); url::redirect($item->abs_url()); } - // Return the width/height dimensinons for the given item + // Return the width/height dimensions for the given item public function dimensions($id) { $item = ORM::factory("item", $id); access::required("view", $item); diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index db087588..6225633f 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -23,6 +23,14 @@ class gallery_event_Core { * Initialization. */ static function gallery_ready() { + if (!get_cfg_var("date.timezone")) { + if (!(rand() % 4)) { + Kohana_Log::add("error", "date.timezone setting not detected in " . + get_cfg_var("cfg_file_path") . " falling back to UTC. " . + "Consult http://php.net/manual/function.get-cfg-var.php for help."); + } + } + identity::load_user(); theme::load_themes(); locales::set_request_locale(); @@ -549,8 +557,8 @@ class gallery_event_Core { $value = $data->user->$field; if ($field == "locale") { $value = locales::display_name($value); - } elseif ($field == "url") { - $value = html::mark_clean(html::anchor($data->user->$field)); + } else if ($field == "url") { + $value = html::mark_clean(html::anchor(html::clean($data->user->$field))); } $v->user_profile_data[(string) $label] = $value; } diff --git a/modules/gallery/helpers/gallery_graphics.php b/modules/gallery/helpers/gallery_graphics.php index 02f628a1..d2b92c87 100644 --- a/modules/gallery/helpers/gallery_graphics.php +++ b/modules/gallery/helpers/gallery_graphics.php @@ -126,7 +126,7 @@ class gallery_graphics_Core { module::event("graphics_composite_completed", $input_file, $output_file, $options, $item); } catch (ErrorException $e) { - Kohana_Log::add("error", $e->get_message()); + Kohana_Log::add("error", $e->getMessage()); } } } diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 7e0bbbea..c19fbe6d 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -156,12 +156,12 @@ class graphics_Core { foreach ($ops as $target => $output_file) { if ($input_item->is_movie()) { // Convert the movie to a JPG first - $output_file = preg_replace("/...$/", "jpg", $output_file); + $output_file = legal_file::change_extension($output_file, "jpg"); try { movie::extract_frame($input_file, $output_file); } catch (Exception $e) { // Assuming this is MISSING_FFMPEG for now - copy(MODPATH . "gallery/images/missing_movie.png", $output_file); + copy(MODPATH . "gallery/images/missing_movie.jpg", $output_file); } $working_file = $output_file; } else { diff --git a/modules/gallery/helpers/legal_file.php b/modules/gallery/helpers/legal_file.php index 6ec65e97..af6472ca 100644 --- a/modules/gallery/helpers/legal_file.php +++ b/modules/gallery/helpers/legal_file.php @@ -80,4 +80,16 @@ class legal_file_Core { module::event("legal_movie_types", $types_wrapper); return $types_wrapper->types; } + + /** + * Convert the extension of a filename. If the original filename has no + * extension, add the new one to the end. + */ + static function change_extension($filename, $new_ext) { + if (strpos($filename, ".") === false) { + return "{$filename}.{$new_ext}"; + } else { + return preg_replace("/\..*?$/", ".{$new_ext}", $filename); + } + } } diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 3368e39b..7292b106 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -109,7 +109,11 @@ class module_Core { $modules->gallery->locked = true; $identity_module = module::get_var("gallery", "identity_provider", "user"); $modules->$identity_module->locked = true; - $modules->ksort(); + + function natural_name_sort($a, $b) { + return strnatcasecmp($a->name, $b->name); + } + $modules->uasort('natural_name_sort'); self::$available = $modules; } diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index 79b5a7c2..b54811df 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -106,7 +106,7 @@ class movie_Core { $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($file_path) . " 2>&1"; $result = `$cmd`; - if (preg_match("/Stream.*?Video:.*?(\d+)x(\d+)/", $result, $regs)) { + if (preg_match("/Stream.*?Video:.*?, (\d+)x(\d+)/", $result, $regs)) { list ($width, $height) = array($regs[1], $regs[2]); } else { list ($width, $height) = array(0, 0); diff --git a/modules/gallery/images/missing_movie.jpg b/modules/gallery/images/missing_movie.jpg Binary files differnew file mode 100644 index 00000000..452db225 --- /dev/null +++ b/modules/gallery/images/missing_movie.jpg diff --git a/modules/gallery/images/missing_movie.png b/modules/gallery/images/missing_movie.png Binary files differdeleted file mode 100644 index fdc97779..00000000 --- a/modules/gallery/images/missing_movie.png +++ /dev/null diff --git a/modules/gallery/libraries/Admin_View.php b/modules/gallery/libraries/Admin_View.php index fcfe7aa2..66b8c20c 100644 --- a/modules/gallery/libraries/Admin_View.php +++ b/modules/gallery/libraries/Admin_View.php @@ -31,7 +31,12 @@ class Admin_View_Core extends Gallery_View { $this->theme_name = module::get_var("gallery", "active_admin_theme"); if (identity::active_user()->admin) { - $this->theme_name = Input::instance()->get("theme", $this->theme_name); + $theme_name = Input::instance()->get("theme"); + if ($theme_name && + file_exists(THEMEPATH . $theme_name) && + strpos(realpath(THEMEPATH . $theme_name), THEMEPATH) == 0) { + $this->theme_name = $theme_name; + } } $this->sidebar = ""; $this->set_global(array("theme" => $this, diff --git a/modules/gallery/libraries/IdentityProvider.php b/modules/gallery/libraries/IdentityProvider.php index 66c68dad..c9e8688f 100644 --- a/modules/gallery/libraries/IdentityProvider.php +++ b/modules/gallery/libraries/IdentityProvider.php @@ -85,6 +85,10 @@ class IdentityProvider_Core { call_user_func("{$new_provider}_installer::initialize"); } + if (!$provider->admin_user()) { + throw new Exception("IdentityProvider $new_provider: Couldn't find the admin user!"); + } + module::event("identity_provider_changed", $current_provider, $new_provider); identity::set_active_user($provider->admin_user()); @@ -100,7 +104,12 @@ class IdentityProvider_Core { // Make sure new provider is not in the database try { module::uninstall($new_provider); + } catch (Exception $e2) { + Kohana_Log::add("error", "Error uninstalling failed new provider\n" . + $e2->getMessage() . "\n" . $e2->getTraceAsString()); + } + try { // Lets reset to the current provider so that the gallery installation is still // working. module::set_var("gallery", "identity_provider", null); diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php index 031da6de..78b74cde 100644 --- a/modules/gallery/libraries/Theme_View.php +++ b/modules/gallery/libraries/Theme_View.php @@ -33,7 +33,12 @@ class Theme_View_Core extends Gallery_View { $this->theme_name = module::get_var("gallery", "active_site_theme"); if (identity::active_user()->admin) { - $this->theme_name = Input::instance()->get("theme", $this->theme_name); + $theme_name = Input::instance()->get("theme"); + if ($theme_name && + file_exists(THEMEPATH . $theme_name) && + strpos(realpath(THEMEPATH . $theme_name), THEMEPATH) == 0) { + $this->theme_name = $theme_name; + } } $this->item = null; $this->tag = null; diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index e90e0fcb..98a2c4df 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -188,7 +188,7 @@ class Item_Model_Core extends ORM_MPTT { return $base . "/.album.jpg"; } else if ($this->is_movie()) { // Replace the extension with jpg - return preg_replace("/...$/", "jpg", $base); + return legal_file::change_extension($base, "jpg"); } } @@ -213,7 +213,7 @@ class Item_Model_Core extends ORM_MPTT { return $base . "/.album.jpg" . $cache_buster; } else if ($this->is_movie()) { // Replace the extension with jpg - $base = preg_replace("/...$/", "jpg", $base); + $base = legal_file::change_extension($base, "jpg"); return $base . $cache_buster; } } @@ -803,18 +803,22 @@ class Item_Model_Core extends ORM_MPTT { } if ($this->is_movie() || $this->is_photo()) { - if (!$this->loaded()) { + $ext = pathinfo($this->name, PATHINFO_EXTENSION); + + if (!$this->loaded() && !$ext) { // New items must have an extension - $ext = pathinfo($this->name, PATHINFO_EXTENSION); - if (!$ext) { + $v->add_error("name", "illegal_data_file_extension"); + return; + } + + if ($this->is_photo()) { + if (!in_array(strtolower($ext), legal_file::get_photo_extensions())) { $v->add_error("name", "illegal_data_file_extension"); - return; } + } - if ($this->is_photo() && - !in_array(strtolower($ext), array_map("strtolower", legal_file::get_photo_extensions())) || - $this->is_movie() && - !in_array(strtolower($ext), array_map("strtolower", legal_file::get_movie_extensions()))) { + if ($this->is_movie()) { + if (!in_array(strtolower($ext), legal_file::get_movie_extensions())) { $v->add_error("name", "illegal_data_file_extension"); } } diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index 205d0a08..6d40230f 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -333,7 +333,36 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $photo->mime_type = "video/x-flv"; $photo->save(); } catch (ORM_Validation_Exception $e) { - $this->assert_same(array("type" => "read_only"), $e->validation->errors()); + $this->assert_same( + array("name" => "illegal_data_file_extension", "type" => "read_only"), + $e->validation->errors()); + return; // pass + } + $this->assert_true(false, "Shouldn't get here"); + } + + public function photo_files_must_have_an_extension_test() { + try { + $photo = test::random_photo_unsaved(); + $photo->mime_type = "image/jpeg"; + $photo->name = "no_extension"; + $photo->save(); + } catch (ORM_Validation_Exception $e) { + $this->assert_same(array("name" => "illegal_data_file_extension"), $e->validation->errors()); + return; // pass + } + $this->assert_true(false, "Shouldn't get here"); + } + + public function movie_files_must_have_an_extension_test() { + try { + $movie = test::random_photo_unsaved(); + $movie->type = "movie"; + $movie->mime_type = "video/x-flv"; + $movie->name = "no_extension"; + $movie->save(); + } catch (ORM_Validation_Exception $e) { + $this->assert_same(array("name" => "illegal_data_file_extension"), $e->validation->errors()); return; // pass } $this->assert_true(false, "Shouldn't get here"); @@ -421,7 +450,8 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $photo->set_data_file(MODPATH . "gallery/tests/Item_Model_Test.php"); $photo->save(); } catch (ORM_Validation_Exception $e) { - $this->assert_same(array("mime_type" => "invalid"), $e->validation->errors()); + $this->assert_same(array("mime_type" => "invalid", "name" => "illegal_data_file_extension"), + $e->validation->errors()); return; // pass } $this->assert_true(false, "Shouldn't get here"); @@ -473,4 +503,20 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $this->assert_true(false, "Shouldn't get here"); } } + + public function cant_rename_to_illegal_extension_test() { + foreach (array("test.php.test", "test.php", "test.PHP", + "test.php5", "test.php4", "test.pl") as $name) { + try { + $photo = test::random_photo(item::root()); + $photo->name = $name; + $photo->save(); + } catch (ORM_Validation_Exception $e) { + $this->assert_equal(array("name" => "illegal_data_file_extension"), + $e->validation->errors()); + continue; + } + $this->assert_true(false, "Shouldn't get here"); + } + } } diff --git a/modules/gallery/tests/Legal_File_Helper_Test.php b/modules/gallery/tests/Legal_File_Helper_Test.php new file mode 100644 index 00000000..c101de10 --- /dev/null +++ b/modules/gallery/tests/Legal_File_Helper_Test.php @@ -0,0 +1,32 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2012 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Legal_File_Helper_Test extends Gallery_Unit_Test_Case { + public function change_extension_test() { + $this->assert_equal("foo.jpg", legal_file::change_extension("foo.png", "jpg")); + } + + public function change_four_letter_extension_test() { + $this->assert_equal("foo.flv", legal_file::change_extension("foo.mpeg", "flv")); + } + + public function change_extension_with_no_extension_test() { + $this->assert_equal("foo.flv", legal_file::change_extension("foo", "flv")); + } +}
\ No newline at end of file diff --git a/modules/gallery/views/error_admin.html.php b/modules/gallery/views/error_admin.html.php index af78c59c..a391746e 100644 --- a/modules/gallery/views/error_admin.html.php +++ b/modules/gallery/views/error_admin.html.php @@ -184,7 +184,7 @@ <?= $type?> [ <?= $code ?> ]: </span> <span class="message"> - <?= $message?> + <?= html::purify($message) ?> </span> </h3> <div id="<?= $error_id ?>" class="content"> diff --git a/modules/image_block/controllers/image_block.php b/modules/image_block/controllers/image_block.php new file mode 100644 index 00000000..94024b3b --- /dev/null +++ b/modules/image_block/controllers/image_block.php @@ -0,0 +1,26 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2012 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Image_Block_Controller extends Controller { + public function random($item_id) { + $item = ORM::factory("item", $item_id); + item::set_display_context_callback("Albums_Controller::get_display_context"); + url::redirect($item->abs_url()); + } +} diff --git a/modules/image_block/views/image_block_block.html.php b/modules/image_block/views/image_block_block.html.php index 2a57c395..6f68e5b8 100644 --- a/modules/image_block/views/image_block_block.html.php +++ b/modules/image_block/views/image_block_block.html.php @@ -1,7 +1,7 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <? foreach ($items as $item): ?> <div class="g-image-block"> - <a href="<?= $item->url() ?>"> + <a href="<?= url::site("image_block/random/" . $item->id); ?>"> <?= $item->thumb_img(array("class" => "g-thumbnail")) ?> </a> </div> diff --git a/modules/info/helpers/info_block.php b/modules/info/helpers/info_block.php index c4470dbe..3dcfa338 100644 --- a/modules/info/helpers/info_block.php +++ b/modules/info/helpers/info_block.php @@ -60,8 +60,9 @@ class info_block_Core { if ($theme->item->owner->url) { $info["owner"] = array( "label" => t("Owner:"), - "value" => "<a href=\"{$theme->item->owner->url}\">" . - html::clean($display_name) . "</a>" + "value" => html::anchor( + html::clean($theme->item->owner->url), + html::clean($display_name)) ); } else { $info["owner"] = array( diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 5a2c3e4f..b0c13e7d 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -56,7 +56,7 @@ class Organize_Controller extends Controller { "sort_column" => $album->sort_column, "sort_order" => $album->sort_order, "editable" => access::can("edit", $album), - "title" => $album->title, + "title" => (string)html::clean($album->title), "children" => array()); foreach ($album->viewable()->children() as $child) { @@ -67,7 +67,7 @@ class Organize_Controller extends Controller { "width" => $dims[1], "height" => $dims[0], "type" => $child->type, - "title" => $child->title); + "title" => (string)html::clean($child->title)); } json::reply($data); } @@ -81,6 +81,9 @@ class Organize_Controller extends Controller { foreach (explode(",", $input->post("source_ids")) as $source_id) { $source = ORM::factory("item", $source_id); + if (!$source->loaded()) { + continue; + } access::required("edit", $source->parent()); if ($source->contains($new_parent) || $source->id == $new_parent->id) { @@ -116,6 +119,11 @@ class Organize_Controller extends Controller { $input = Input::instance(); $target = ORM::factory("item", $input->post("target_id")); + if (!$target->loaded()) { + json::reply(null); + return; + } + $album = $target->parent(); access::required("edit", $album); @@ -187,7 +195,7 @@ class Organize_Controller extends Controller { "expandable" => false, "id" => $child->id, "leaf" => $child->children_count(array(array("type", "=", "album"))) == 0, - "text" => $child->title, + "text" => (string)html::clean($child->title), "nodeType" => "async"); // If the child is in the selected path, open it now. Else, mark it async. diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index a386fa77..9ea4d923 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -11,7 +11,7 @@ var set_title = function(title) { $("#g-dialog").dialog("option", "title", ORGANIZE_TITLE.replace("__TITLE__", title)); } - set_title("<?= $album->title ?>"); + set_title("<?= html::clean($album->title) ?>"); var done_loading = function() { $("#g-organize-app-loading").hide(); diff --git a/modules/organize/views/organize_frame.html.php b/modules/organize/views/organize_frame.html.php index 20a1a6da..51d49104 100644 --- a/modules/organize/views/organize_frame.html.php +++ b/modules/organize/views/organize_frame.html.php @@ -506,7 +506,7 @@ root: { allowDrop: Boolean(<?= access::can("edit", item::root()) ?>), nodeType: "async", - text: "<?= item::root()->title ?>", + text: "<?= html::clean(item::root()->title) ?>", draggable: false, id: "<?= item::root()->id ?>", expanded: true diff --git a/modules/rss/controllers/rss.php b/modules/rss/controllers/rss.php index 799ba989..288bf635 100644 --- a/modules/rss/controllers/rss.php +++ b/modules/rss/controllers/rss.php @@ -50,7 +50,7 @@ class Rss_Controller extends Controller { unset($feed->view); $view->feed = $feed; - $view->pub_date = date("D, d M Y H:i:s T"); + $view->pub_date = date("D, d M Y H:i:s O"); $feed->uri = url::abs_site(url::merge($_GET)); if ($page > 1) { diff --git a/modules/rss/views/feed.mrss.php b/modules/rss/views/feed.mrss.php index 3f0010bb..b609a541 100644 --- a/modules/rss/views/feed.mrss.php +++ b/modules/rss/views/feed.mrss.php @@ -25,7 +25,7 @@ <title><?= html::purify($item->title) ?></title> <link><?= url::abs_site("{$item->type}s/{$item->id}") ?></link> <guid isPermaLink="true"><?= url::abs_site("{$item->type}s/{$item->id}") ?></guid> - <pubDate><?= date("D, d M Y H:i:s T", $item->created); ?></pubDate> + <pubDate><?= date("D, d M Y H:i:s O", $item->created); ?></pubDate> <description><?= html::purify($item->description) ?></description> <content:encoded> <![CDATA[ diff --git a/modules/server_add/controllers/admin_server_add.php b/modules/server_add/controllers/admin_server_add.php index 0c741513..954c9ef6 100644 --- a/modules/server_add/controllers/admin_server_add.php +++ b/modules/server_add/controllers/admin_server_add.php @@ -35,12 +35,12 @@ class Admin_Server_Add_Controller extends Admin_Controller { $form = $this->_get_admin_form(); $paths = unserialize(module::get_var("server_add", "authorized_paths", "a:0:{}")); if ($form->validate()) { - if (is_link($form->add_path->path->value)) { + $path = html_entity_decode($form->add_path->path->value); + if (is_link($path)) { $form->add_path->path->add_error("is_symlink", 1); - } else if (!is_readable($form->add_path->path->value)) { + } else if (!is_readable($path)) { $form->add_path->path->add_error("not_readable", 1); } else { - $path = $form->add_path->path->value; $paths[$path] = 1; module::set_var("server_add", "authorized_paths", serialize($paths)); message::success(t("Added path %path", array("path" => $path))); @@ -75,7 +75,7 @@ class Admin_Server_Add_Controller extends Admin_Controller { $path_prefix = Input::instance()->get("q"); foreach (glob("{$path_prefix}*") as $file) { if (is_dir($file) && !is_link($file)) { - $directories[] = $file; + $directories[] = html::clean($file); } } diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index a3333ae2..c6d36a11 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -61,7 +61,7 @@ class Server_Add_Controller extends Admin_Controller { } if (!is_dir($file)) { $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); - if (!in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4", "m4v"))) { + if (!in_array($ext, legal_file::get_extensions())) { continue; } } @@ -169,8 +169,7 @@ class Server_Add_Controller extends Admin_Controller { foreach ($child_paths as $child_path) { if (!is_dir($child_path)) { $ext = strtolower(pathinfo($child_path, PATHINFO_EXTENSION)); - if (!in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4", "m4v")) || - !filesize($child_path)) { + if (!in_array($ext, legal_file::get_extensions()) || !filesize($child_path)) { // Not importable, skip it. continue; } @@ -256,7 +255,7 @@ class Server_Add_Controller extends Admin_Controller { } else { try { $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION)); - if (in_array($extension, array("gif", "png", "jpg", "jpeg"))) { + if (in_array($extension, legal_file::get_photo_extensions())) { $photo = ORM::factory("item"); $photo->type = "photo"; $photo->parent_id = $parent->id; @@ -266,7 +265,7 @@ class Server_Add_Controller extends Admin_Controller { $photo->owner_id = $owner_id; $photo->save(); $entry->item_id = $photo->id; - } else if (in_array($extension, array("flv", "mp4", "m4v"))) { + } else if (in_array($extension, legal_file::get_movie_extensions())) { $movie = ORM::factory("item"); $movie->type = "movie"; $movie->parent_id = $parent->id; diff --git a/modules/tag/helpers/tag_event.php b/modules/tag/helpers/tag_event.php index 26876d83..d4f1c757 100644 --- a/modules/tag/helpers/tag_event.php +++ b/modules/tag/helpers/tag_event.php @@ -149,7 +149,8 @@ class tag_event_Core { static function info_block_get_metadata($block, $item) { $tags = array(); foreach (tag::item_tags($item) as $tag) { - $tags[] = "<a href=\"{$tag->url()}\">{$tag->name}</a>"; + $tags[] = "<a href=\"{$tag->url()}\">" . + html::clean($tag->name) . "</a>"; } if ($tags) { $info = $block->content->metadata; diff --git a/modules/user/helpers/user_installer.php b/modules/user/helpers/user_installer.php index c07b624f..1ba1aeaf 100644 --- a/modules/user/helpers/user_installer.php +++ b/modules/user/helpers/user_installer.php @@ -22,7 +22,7 @@ class user_installer { return array("warn" => array(IdentityProvider::confirmation_message())); } - static function install() { + static function activate() { IdentityProvider::change_provider("user"); // Set the latest version in initialize() below } diff --git a/modules/watermark/controllers/admin_watermarks.php b/modules/watermark/controllers/admin_watermarks.php index 2c4c602d..92a44a86 100644 --- a/modules/watermark/controllers/admin_watermarks.php +++ b/modules/watermark/controllers/admin_watermarks.php @@ -106,6 +106,20 @@ class Admin_Watermarks_Controller extends Admin_Controller { return; } + if (!in_array($pathinfo["extension"], legal_file::get_photo_extensions())) { + switch ($image_info[2]) { + case IMAGETYPE_GIF: + $name = legal_file::change_extension($name, "gif"); + break; + case IMAGETYPE_JPEG: + $name = legal_file::change_extension($name, "jpg"); + break; + case IMAGETYPE_PNG: + $name = legal_file::change_extension($name, "png"); + break; + } + } + rename($file, VARPATH . "modules/watermark/$name"); module::set_var("watermark", "name", $name); module::set_var("watermark", "width", $image_info[0]); diff --git a/system/core/Kohana.php b/system/core/Kohana.php index f7f6b326..96d969ed 100644 --- a/system/core/Kohana.php +++ b/system/core/Kohana.php @@ -525,8 +525,12 @@ abstract class Kohana_Core { $close(); } - // Store the Kohana output buffer - ob_end_clean(); + // Store the Kohana output buffer. Apparently there was a change in PHP + // 5.4 such that if you call this you wind up with a blank page. + // Disabling it for now. See ticket #1839 + if (version_compare(PHP_VERSION, "5.4", "<")) { + ob_end_clean(); + } } } diff --git a/system/libraries/Input.php b/system/libraries/Input.php index c6c84fca..2bef3ff4 100644 --- a/system/libraries/Input.php +++ b/system/libraries/Input.php @@ -334,33 +334,37 @@ class Input_Core { // * Removed parentheses where possible // * Split up alternation alternatives // * Made some quantifiers possessive + // + // Gallery Modifications: + // * Wrap the loop around all the changes to detect nested exploits + + do + { + $old_data = $data; - // Fix &entity\n; - $data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data); - $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data); - $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data); - $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8'); + // Fix &entity\n; + $data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data); + $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data); + $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data); + $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8'); - // Remove any attribute starting with "on" or xmlns - $data = preg_replace('#(?:on[a-z]+|xmlns)\s*=\s*[\'"\x00-\x20]?[^\'>"]*[\'"\x00-\x20]?\s?#iu', '', $data); + // Remove any attribute starting with "on" or xmlns + $data = preg_replace('#(?:on[a-z]+|xmlns)\s*=\s*[\'"\x00-\x20]?[^\'>"]*[\'"\x00-\x20]?\s?#iu', '', $data); - // Remove javascript: and vbscript: protocols - $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data); - $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data); - $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data); + // Remove javascript: and vbscript: protocols + $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data); + $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data); + $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data); - // Only works in IE: <span style="width: expression(alert('Ping!'));"></span> - $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data); - $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data); - $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data); + // Only works in IE: <span style="width: expression(alert('Ping!'));"></span> + $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data); + $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data); + $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data); - // Remove namespaced elements (we do not need them) - $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data); + // Remove namespaced elements (we do not need them) + $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data); - do - { // Remove really unwanted tags - $old_data = $data; $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data); } while ($old_data !== $data); diff --git a/themes/admin_wind/views/admin.html.php b/themes/admin_wind/views/admin.html.php index 9a149149..0300f7af 100644 --- a/themes/admin_wind/views/admin.html.php +++ b/themes/admin_wind/views/admin.html.php @@ -1,4 +1,5 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> +<?php header("X-Frame-Options: SAMEORIGIN"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" <?= $theme->html_attributes() ?> xml:lang="en" lang="en"> diff --git a/themes/wind/views/dynamic.html.php b/themes/wind/views/dynamic.html.php index 67360da7..33e05de3 100644 --- a/themes/wind/views/dynamic.html.php +++ b/themes/wind/views/dynamic.html.php @@ -3,7 +3,7 @@ <div id="g-album-header-buttons"> <?= $theme->dynamic_top() ?> </div> - <h1><?= html::clean($title) ?></h1> + <h1><?= html::purify($title) ?></h1> </div> <ul id="g-album-grid" class="ui-helper-clearfix"> diff --git a/themes/wind/views/page.html.php b/themes/wind/views/page.html.php index 24d3347e..c3e212c5 100644 --- a/themes/wind/views/page.html.php +++ b/themes/wind/views/page.html.php @@ -1,4 +1,5 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> +<?php header("X-Frame-Options: SAMEORIGIN"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" <?= $theme->html_attributes() ?> xml:lang="en" lang="en"> @@ -10,11 +11,11 @@ <?= $page_title ?> <? else: ?> <? if ($theme->item()): ?> - <?= $theme->item()->title ?> + <?= html::purify($theme->item()->title) ?> <? elseif ($theme->tag()): ?> <?= t("Photos tagged with %tag_title", array("tag_title" => $theme->tag()->name)) ?> <? else: /* Not an item, not a tag, no page_title specified. Help! */ ?> - <?= item::root()->title ?> + <?= html::purify(item::root()->title) ?> <? endif ?> <? endif ?> </title> |