diff options
author | Tim Almdal <tnalmdal@shaw.ca> | 2010-02-28 15:38:39 -0800 |
---|---|---|
committer | Tim Almdal <tnalmdal@shaw.ca> | 2010-02-28 15:38:39 -0800 |
commit | e3e72ca4da0375d88b86ba69b6596b10be164e23 (patch) | |
tree | f32855f9416252b474ab8d598a345fdcf1455b7d | |
parent | f28b80fcf43e02ca65f419eb6774321dc30a2a37 (diff) | |
parent | fd94f4bec21a7deaa86d468da704a048d2be751e (diff) |
Merge branch 'master' into talmdal_dev
-rw-r--r-- | installer/views/get_db_info.html.php | 2 | ||||
-rw-r--r-- | modules/gallery/controllers/admin_maintenance.php | 1 | ||||
-rw-r--r-- | modules/gallery/controllers/l10n_client.php | 39 | ||||
-rw-r--r-- | modules/gallery/helpers/access.php | 18 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_block.php | 2 | ||||
-rw-r--r-- | modules/gallery/helpers/gallery_theme.php | 2 | ||||
-rw-r--r-- | modules/gallery/js/l10n_client.js | 20 | ||||
-rw-r--r-- | modules/gallery/libraries/Admin_View.php | 1 | ||||
-rw-r--r-- | modules/gallery/libraries/MY_Kohana_Exception.php | 57 | ||||
-rw-r--r-- | modules/gallery/tests/Kohana_Exception_Test.php | 170 | ||||
-rw-r--r-- | modules/gallery/views/kohana/error.php | 4 | ||||
-rw-r--r-- | modules/user/controllers/password.php | 2 | ||||
-rw-r--r-- | modules/user/controllers/users.php | 7 | ||||
-rw-r--r-- | system/core/Kohana.php | 16 | ||||
-rw-r--r-- | themes/admin_wind/views/admin.html.php | 8 |
15 files changed, 308 insertions, 41 deletions
diff --git a/installer/views/get_db_info.html.php b/installer/views/get_db_info.html.php index 1eeecd91..ada0793c 100644 --- a/installer/views/get_db_info.html.php +++ b/installer/views/get_db_info.html.php @@ -57,7 +57,7 @@ Password </td> <td> - <input name="dbpass" value="" type="password" /> + <input name="dbpass" value=""/> </td> </tr> <tr> diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php index c16c5c41..6ef21d41 100644 --- a/modules/gallery/controllers/admin_maintenance.php +++ b/modules/gallery/controllers/admin_maintenance.php @@ -40,6 +40,7 @@ class Admin_Maintenance_Controller extends Admin_Controller { } $view = new Admin_View("admin.html"); + $view->page_title = t("Maintenance tasks"); $view->content = new View("admin_maintenance.html"); $view->content->task_definitions = task::get_definitions(); $view->content->running_tasks = ORM::factory("task") diff --git a/modules/gallery/controllers/l10n_client.php b/modules/gallery/controllers/l10n_client.php index be0aaa11..084f88af 100644 --- a/modules/gallery/controllers/l10n_client.php +++ b/modules/gallery/controllers/l10n_client.php @@ -38,6 +38,7 @@ class L10n_Client_Controller extends Controller { } $is_plural = Gallery_I18n::is_plural_message(unserialize($root_message->message)); + $is_empty = true; if ($is_plural) { $plural_forms = l10n_client::plural_forms($locale); $translation = array(); @@ -47,9 +48,11 @@ class L10n_Client_Controller extends Controller { throw new Exception("@todo bad request data"); } $translation[$plural_form] = $value; + $is_empty = $is_empty && empty($value); } } else { $translation = $input->post("l10n-edit-translation"); + $is_empty = empty($translation); if (null === $translation || !is_string($translation)) { throw new Exception("@todo bad request data"); } @@ -60,25 +63,31 @@ class L10n_Client_Controller extends Controller { ->where("locale", "=", $locale) ->find(); - if (!$entry->loaded()) { - $entry->key = $key; - $entry->locale = $locale; - $entry->message = $root_message->message; - $entry->base_revision = null; - } + if ($is_empty) { + if ($entry->loaded()) { + $entry->delete(); + } + } else { + if (!$entry->loaded()) { + $entry->key = $key; + $entry->locale = $locale; + $entry->message = $root_message->message; + $entry->base_revision = null; + } - $entry->translation = serialize($translation); + $entry->translation = serialize($translation); - $entry_from_incoming = ORM::factory("incoming_translation") - ->where("key", "=", $key) - ->where("locale", "=", $locale) - ->find(); + $entry_from_incoming = ORM::factory("incoming_translation") + ->where("key", "=", $key) + ->where("locale", "=", $locale) + ->find(); - if (!$entry_from_incoming->loaded()) { - $entry->base_revision = $entry_from_incoming->revision; - } + if (!$entry_from_incoming->loaded()) { + $entry->base_revision = $entry_from_incoming->revision; + } - $entry->save(); + $entry->save(); + } Gallery_I18n::clear_cache($locale); diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 7e8b079a..af336798 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -637,8 +637,22 @@ class access_Core { $dirs[] = dirname($album->thumb_path()); } - $base_url = url::site("?kohana_uri=/file_proxy"); - $base_url = str_replace("/?", "?", $base_url); + $base_url = url::base(true); + $sep = "?"; + if (strpos($base_url, "?") !== false) { + $sep = "&"; + } + $base_url .= $sep . "kohana_uri=/file_proxy"; + // Replace "/index.php/?kohana..." with "/index.php?koahan..." + // Doesn't apply to "/?kohana..." or "/foo/?kohana..." + // Can't check for "index.php" since the file might be renamed, and + // there might be more Apache aliases / rewrites at work. + $url_path = parse_url($base_url, PHP_URL_PATH); + // Does the URL path have a file component? + if (preg_match("#[^/]+\.php#i", $url_path)) { + $base_url = str_replace("/?", "?", $base_url); + } + foreach ($dirs as $dir) { if ($value === self::DENY) { $fp = fopen("$dir/.htaccess", "w+"); diff --git a/modules/gallery/helpers/gallery_block.php b/modules/gallery/helpers/gallery_block.php index 46742743..eabdcebc 100644 --- a/modules/gallery/helpers/gallery_block.php +++ b/modules/gallery/helpers/gallery_block.php @@ -93,7 +93,7 @@ class gallery_block_Core { case "language": $locales = locales::installed(); - if (count($locales)) { + if (count($locales) > 1) { foreach ($locales as $locale => $display_name) { $locales[$locale] = SafeString::of_safe_html($display_name); } diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index d6944323..7f2d4ec7 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -71,6 +71,7 @@ class gallery_theme_Core { static function page_bottom($theme) { $session = Session::instance(); if ($session->get("profiler", false)) { + Profiler::enable(); $profiler = new Profiler(); $profiler->render(); } @@ -87,6 +88,7 @@ class gallery_theme_Core { static function admin_page_bottom($theme) { $session = Session::instance(); if ($session->get("profiler", false)) { + Profiler::enable(); $profiler = new Profiler(); $profiler->render(); } diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js index d0d6f619..a1170e2d 100644 --- a/modules/gallery/js/l10n_client.js +++ b/modules/gallery/js/l10n_client.js @@ -124,7 +124,7 @@ jQuery.extend(Gallery, { if (translation[form] == undefined) { translation[form] = ''; } - $('#l10n-edit-plural-translation-' + form) + $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']") .attr('value', translation[form]); $('#plural-' + form).removeClass('hidden'); } @@ -166,7 +166,7 @@ jQuery.extend(Gallery, { if (form == 'one') { text = source['one']; } - $('#l10n-edit-plural-translation-' + form) + $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']") .attr('value', text); } } else { @@ -260,18 +260,26 @@ Gallery.behaviors.l10nClient = function(context) { // Store translation in local js var translation = {}; + var is_non_empty = false; if (is_plural) { for (var i = 0; i < num_plural_forms; i++) { var form = plural_forms[i]; - translation[form] = $('#g-l10n-client-save-form #l10n-edit-plural-translation-' + form).attr('value'); + translation[form] = $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']").attr('value'); + is_non_empty = is_non_empty || translation[form]; } } else { translation = $('#l10n-edit-translation').attr('value'); + is_non_empty = translation; } Gallery.l10nClient.setString(Gallery.l10nClient.selected, translation); - // Mark message as translated. - $('#l10n-client-string-select li').eq(Gallery.l10nClient.selected).removeClass('untranslated').removeClass('active').addClass('translated'); + // Mark message as translated / untranslated. + var source_element = $('#l10n-client-string-select li').eq(Gallery.l10nClient.selected); + if (is_non_empty) { + source_element.removeClass('untranslated').removeClass('active').addClass('translated'); + } else { + source_element.removeClass('active').removeClass('translated').addClass('untranslated'); + } // Clear the translation form fields Gallery.l10nClient.showSourceMessage('', false); @@ -279,7 +287,7 @@ Gallery.behaviors.l10nClient = function(context) { for (var i = 0; i < num_plural_forms; i++) { var form = plural_forms[i]; - $('#g-l10n-client-save-form #l10n-edit-plural-translation-' + form).val(''); + $("#plural-" + form + " textarea[name='l10n-edit-plural-translation-" + form + "']").val(''); } $("#g-l10n-client-save-form input[name='l10n-message-key']").val(''); }, diff --git a/modules/gallery/libraries/Admin_View.php b/modules/gallery/libraries/Admin_View.php index e3f9dff0..f07bebf4 100644 --- a/modules/gallery/libraries/Admin_View.php +++ b/modules/gallery/libraries/Admin_View.php @@ -38,6 +38,7 @@ class Admin_View_Core extends Gallery_View { $this->set_global("user", identity::active_user()); $this->set_global("page_type", "admin"); $this->set_global("page_subtype", $name); + $this->set_global("page_title", null); } public function admin_menu() { diff --git a/modules/gallery/libraries/MY_Kohana_Exception.php b/modules/gallery/libraries/MY_Kohana_Exception.php index d6f1f467..1712d895 100644 --- a/modules/gallery/libraries/MY_Kohana_Exception.php +++ b/modules/gallery/libraries/MY_Kohana_Exception.php @@ -92,4 +92,61 @@ class Kohana_Exception extends Kohana_Exception_Core { } print $view; } + + /** + * @see Kohana_Exception::dump() + */ + public static function dump($value, $length=128, $max_level=5) { + return self::safe_dump($value, null, $length, $max_level); + } + + /** + * A safer version of dump(), eliding sensitive information in the dumped + * data, such as session ids and passwords / hashes. + */ + public static function safe_dump($value, $key, $length=128, $max_level=5) { + return parent::dump(self::_sanitize_for_dump($value, $key), $length, $max_level); + } + + /** + * Elides sensitive data which shouldn't be echoed to the client, + * such as passwords, and other secrets. + */ + /* Visible for testing*/ static function _sanitize_for_dump($value, $key=null) { + // Better elide too much than letting something through. + // Note: unanchored match is intended. + $sensitive_info_pattern = + '/(password|pass|email|hash|private_key|session_id|session|g3sid|csrf|secret)/i'; + if (preg_match($sensitive_info_pattern, $key) || + (is_string($value) && preg_match('/[a-f0-9]{20,}/i', $value))) { + return 'removed for display'; + } else if (is_object($value)) { + if ($value instanceof Database) { + // Elide database password, host, name, user, etc. + return get_class($value) . ' object - details omitted for display'; + } else if ($value instanceof User_Model) { + return get_class($value) . ' object for "' . $value->name . '" - details omitted for display'; + } + return self::_sanitize_for_dump((array) $value, $key); + } else if (is_array($value)) { + $result = array(); + foreach ($value as $k => $v) { + $actual_key = $k; + $key_for_display = $k; + if ($k[0] === "\x00") { + // Remove the access level from the variable name + $actual_key = substr($k, strrpos($k, "\x00") + 1); + $access = $k[1] === '*' ? 'protected' : 'private'; + $key_for_display = "$access: $actual_key"; + } + if (is_object($v)) { + $key_for_display .= ' (type: ' . get_class($v) . ')'; + } + $result[$key_for_display] = self::_sanitize_for_dump($v, $actual_key); + } + } else { + $result = $value; + } + return $result; + } }
\ No newline at end of file diff --git a/modules/gallery/tests/Kohana_Exception_Test.php b/modules/gallery/tests/Kohana_Exception_Test.php new file mode 100644 index 00000000..d2dbb4dc --- /dev/null +++ b/modules/gallery/tests/Kohana_Exception_Test.php @@ -0,0 +1,170 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 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 Kohana_Exception_Test extends Gallery_Unit_Test_Case { + + public function dump_test() { + // Verify the override. + $this->assert_equal('<small>string</small><span>(19)</span> "removed for display"', + Kohana_Exception::dump("1a62761b836138c6198313911")); + $this->assert_equal('<small>string</small><span>(14)</span> "original value"', + Kohana_Exception::dump("original value")); + } + + public function safe_dump_test() { + // Verify the delegation. + $this->assert_equal('<small>string</small><span>(19)</span> "removed for display"', + Kohana_Exception::safe_dump("original value", "password")); + $this->assert_equal('<small>string</small><span>(14)</span> "original value"', + Kohana_Exception::safe_dump("original value", "meow")); + } + + public function sanitize_for_dump_match_key_test() { + $this->assert_equal("removed for display", + Kohana_Exception::_sanitize_for_dump("original value", "password")); + $this->assert_equal("original value", + Kohana_Exception::_sanitize_for_dump("original value", "meow")); + } + + public function sanitize_for_dump_match_key_loosely_test() { + $this->assert_equal("removed for display", + Kohana_Exception::_sanitize_for_dump("original value", "this secret key")); + } + + public function sanitize_for_dump_match_value_test() { + // Looks like a hash / secret value. + $this->assert_equal("removed for display", + Kohana_Exception::_sanitize_for_dump("p$2a178b841c6391d6368f131", "meow")); + $this->assert_equal("original value", + Kohana_Exception::_sanitize_for_dump("original value", "meow")); + } + + public function sanitize_for_dump_array_test() { + $var = array("safe" => "original value 1", + "some hash" => "original value 2", + "three" => "2a3728788982938293b9292"); + $expected = array("safe" => "original value 1", + "some hash" => "removed for display", + "three" => "removed for display"); + + $this->assert_equal($expected, + Kohana_Exception::_sanitize_for_dump($var, "ignored")); + } + + public function sanitize_for_dump_nested_array_test() { + $var = array("safe" => "original value 1", + "safe 2" => array("some hash" => "original value 2")); + $expected = array("safe" => "original value 1", + "safe 2" => array("some hash" => "removed for display")); + $this->assert_equal($expected, + Kohana_Exception::_sanitize_for_dump($var, "ignored")); + } + + public function sanitize_for_dump_user_test() { + $user = new User_Model(); + $user->name = "john"; + $user->hash = "value 1"; + $user->email = "value 2"; + $user->full_name = "value 3"; + $this->assert_equal('User_Model object for "john" - details omitted for display', + Kohana_Exception::_sanitize_for_dump($user, "ignored")); + } + + public function sanitize_for_dump_database_test() { + $db = new Kohana_Exception_Test_Database( + array("connection" => array("user" => "john", "name" => "gallery_3"), + "cache" => array())); + $this->assert_equal("Kohana_Exception_Test_Database object - details omitted for display", + Kohana_Exception::_sanitize_for_dump($db, "ignored")); + } + + public function sanitize_for_dump_nested_database_test() { + $db = new Kohana_Exception_Test_Database( + array("connection" => array("user" => "john", "name" => "gallery_3"), + "cache" => array())); + $var = array("some" => "foo", + "bar" => $db); + $this->assert_equal( + array("some" => "foo", + "bar (type: Kohana_Exception_Test_Database)" => + "Kohana_Exception_Test_Database object - details omitted for display"), + Kohana_Exception::_sanitize_for_dump($var, "ignored")); + } + + public function sanitize_for_dump_object_test() { + $obj = new Kohana_Exception_Test_Class(); + $obj->password = "original value"; + $expected = array("var_1" => "val 1", + "protected: var_2" => "val 2", + "private: var_3" => "val 3", + "protected: hash" => "removed for display", + "private: email_address" => "removed for display", + "password" => "removed for display"); + $this->assert_equal($expected, + Kohana_Exception::_sanitize_for_dump($obj, "ignored")); + } + + public function sanitize_for_dump_nested_object_test() { + $user = new User_Model(); + $user->name = "john"; + $obj = new Kohana_Exception_Test_Class(); + $obj->meow = new Kohana_Exception_Test_Class(); + $obj->woof = "original value"; + $obj->foo = array("bar" => $user); + $expected = array("var_1" => "val 1", + "protected: var_2" => "val 2", + "private: var_3" => "val 3", + "protected: hash" => "removed for display", + "private: email_address" => "removed for display", + "meow (type: Kohana_Exception_Test_Class)" => + array("var_1" => "val 1", + "protected: var_2" => "val 2", + "private: var_3" => "val 3", + "protected: hash" => "removed for display", + "private: email_address" => "removed for display"), + "woof" => "original value", + "foo" => array("bar (type: User_Model)" => + 'User_Model object for "john" - details omitted for display')); + $this->assert_equal($expected, + Kohana_Exception::_sanitize_for_dump($obj, "ignored")); + } +} + +class Kohana_Exception_Test_Database extends Database { + function __construct($config) { parent::__construct($config); } + public function connect() {} + public function disconnect() {} + public function set_charset($charset) {} + public function query_execute($sql) {} + public function escape($value) {} + public function list_constraints($table) {} + public function list_fields($table) {} + public function list_tables() {} +} + +class Kohana_Exception_Test_Class { + public $var_1 = "val 1"; + protected $var_2 = "val 2"; + private $var_3 = "val 3"; + protected $hash = "val 4"; + private $email_address = "val 5"; + function __set($name, $val) { + $this->$name = $val; + } +}
\ No newline at end of file diff --git a/modules/gallery/views/kohana/error.php b/modules/gallery/views/kohana/error.php index 26628cf2..d55105a0 100644 --- a/modules/gallery/views/kohana/error.php +++ b/modules/gallery/views/kohana/error.php @@ -204,7 +204,7 @@ <pre><?= $name?></pre> </td> <td class="value"> - <pre><?= Kohana_Exception::dump($arg) ?></pre> + <pre><?= Kohana_Exception::safe_dump($arg, $name) ?></pre> </td> </tr> <? endforeach?> @@ -265,7 +265,7 @@ </code> </td> <td class="value"> - <pre><?= Kohana_Exception::dump($value) ?></pre> + <pre><?= Kohana_Exception::safe_dump($value, $key) ?></pre> </td> </tr> <? endforeach?> diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index f5190974..38fa66be 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -52,7 +52,7 @@ class Password_Controller extends Controller { $user_name = $form->reset->inputs["name"]->value; $user = user::lookup_by_name($user_name); if ($user && !empty($user->email)) { - $user->hash = md5(rand()); + $user->hash = md5(uniqid(mt_rand(), true)); $user->save(); $message = new View("reset_password.html"); $message->confirm_url = url::abs_site("password/do_reset?key=$user->hash"); diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index cd7d271f..a5fdd994 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -30,7 +30,8 @@ class Users_Controller extends Controller { $user->full_name = $form->edit_user->full_name->value; $user->url = $form->edit_user->url->value; - if ($user->locale != $form->edit_user->locale->value) { + if (count(locales::installed()) > 1 && + $user->locale != $form->edit_user->locale->value) { $user->locale = $form->edit_user->locale->value; $flush_locale_cookie = true; } @@ -221,6 +222,10 @@ class Users_Controller extends Controller { /** @todo combine with Admin_Users_Controller::_add_locale_dropdown */ private function _add_locale_dropdown(&$form, $user=null) { $locales = locales::installed(); + if (count($locales) <= 1) { + return; + } + foreach ($locales as $locale => $display_name) { $locales[$locale] = SafeString::of_safe_html($display_name); } diff --git a/system/core/Kohana.php b/system/core/Kohana.php index ae056d0e..f7f6b326 100644 --- a/system/core/Kohana.php +++ b/system/core/Kohana.php @@ -32,6 +32,7 @@ abstract class Kohana_Core { // Include paths protected static $include_paths; + protected static $include_paths_hash = ''; // Cache lifetime protected static $cache_lifetime; @@ -365,14 +366,7 @@ abstract class Kohana_Core { // Add SYSPATH as the last path Kohana::$include_paths[] = SYSPATH; - // Clear cached include paths - self::$internal_cache['find_file_paths'] = array(); - if ( ! isset(self::$write_cache['find_file_paths'])) - { - // Write cache at shutdown - self::$write_cache['find_file_paths'] = TRUE; - } - + Kohana::$include_paths_hash = md5(serialize(Kohana::$include_paths)); } return Kohana::$include_paths; @@ -766,8 +760,8 @@ abstract class Kohana_Core { // Search path $search = $directory.'/'.$filename.$ext; - if (isset(Kohana::$internal_cache['find_file_paths'][$search])) - return Kohana::$internal_cache['find_file_paths'][$search]; + if (isset(Kohana::$internal_cache['find_file_paths'][Kohana::$include_paths_hash][$search])) + return Kohana::$internal_cache['find_file_paths'][Kohana::$include_paths_hash][$search]; // Load include paths $paths = Kohana::$include_paths; @@ -824,7 +818,7 @@ abstract class Kohana_Core { Kohana::$write_cache['find_file_paths'] = TRUE; } - return Kohana::$internal_cache['find_file_paths'][$search] = $found; + return Kohana::$internal_cache['find_file_paths'][Kohana::$include_paths_hash][$search] = $found; } /** diff --git a/themes/admin_wind/views/admin.html.php b/themes/admin_wind/views/admin.html.php index fa79119a..2f64c847 100644 --- a/themes/admin_wind/views/admin.html.php +++ b/themes/admin_wind/views/admin.html.php @@ -4,7 +4,13 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> - <title><?= t("Admin dashboard") ?></title> + <title> + <? if ($page_title): ?> + <?= $page_title ?> + <? else: ?> + <?= t("Admin dashboard") ?> + <? endif ?> + </title> <link rel="shortcut icon" href="<?= url::file("lib/images/favicon.ico") ?>" type="image/x-icon" /> <?= $theme->css("yui/reset-fonts-grids.css") ?> |