aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt42
-rw-r--r--CONTRIBUTORS.txt5
-rw-r--r--actions/profile/edit.php42
-rw-r--r--engine/classes/ElggMenuBuilder.php32
-rw-r--r--engine/classes/ElggMenuItem.php3
-rw-r--r--engine/classes/ElggObject.php2
-rw-r--r--engine/lib/output.php46
-rw-r--r--engine/lib/upgrades/2010052601.php12
-rw-r--r--install/ElggInstaller.php2
-rw-r--r--install/cli/sample_installer.php35
-rw-r--r--js/lib/elgglib.js2
-rw-r--r--mod/blog/views/default/forms/blog/save.php9
-rw-r--r--mod/groups/actions/groups/edit.php8
-rw-r--r--mod/messages/pages/messages/read.php2
-rw-r--r--version.php4
-rw-r--r--views/default/forms/profile/edit.php3
-rw-r--r--views/default/object/plugin/elements/dependencies.php2
-rw-r--r--views/default/output/email.php4
18 files changed, 202 insertions, 53 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 7a3422d7d..5eb9aca0d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,45 @@
+Version 1.8.9
+(November 11, 2012 from https://github.com/Elgg/Elgg/tree/1.8)
+
+ Contributing Developers:
+ * Brett Profitt
+ * Cash Costello
+ * Evan Winslow
+ * Jeroen Dalsem
+ * Jerome Bakker
+ * Matt Beckett
+ * Paweł Sroka
+ * Sem
+ * Steve Clay
+
+ Security Enhancements:
+ * Sample CLI installer cannot break site
+ * Removed XSS vulnerabilities in titles and user profiles
+
+ Enhancements:
+ * UX: A group's owner can transfer ownership to another member
+ * UX: Search queries persist in the search box
+ * Several (X)HTML validation improvements
+ * Improved performance via more aggressive entity and metadata caching
+ * BC: 1.7 group profile URLs forward correctly
+
+ Bugfixes:
+ * UX: Titles containing HTML tokens are never mangled
+ * UX: Empty user profile values saved properly
+ * UX: Blog creator always mentioned in activity stream (not user who published it)
+ * UI: Fixed ordering of registered menu items in some cases
+ * UI: Embed dialog does not break file inputs
+ * UI: Datepicker now respects language
+ * UI: More reliable display of access input in widgets
+ * UI: Group edit form is sticky
+ * UI: Site categories are sticky in forms
+ * API: Language fallback works in Javascript
+ * API: Fallback to default viewtype if invalid one given
+ * API: Notices reported for missing language keys
+ * Memcache now safe to use; never bypasses access control
+ * BC: upgrade shows comments consistently in activity stream
+
+
Version 1.8.8
(July 11, 2012 from https://github.com/Elgg/Elgg/tree/1.8)
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 0163757e7..a8e74d3a4 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -1,6 +1,7 @@
The following have made notable contributions to the Elgg Project.
(List in alphabetical order.)
+Steve Clay - http://www.mrclay.org/, https://twitter.com/mrclay_org
Cash Costello - cash@elgg.org, http://cashcostello.com/
@@ -20,10 +21,10 @@ Tom Read - MITRE http://mitre.org/
Justin Richer - MITRE http://mitre.org/
-Dave Tosh - davidgtosh@gmail.com, http://twitter.com/davetosh
+Dave Tosh - davidgtosh@gmail.com, http://twitter.com/davetosh
Ben Werdmuller - http://benwerd.com/
-Nicholas Whitt - nick.whitt@gmail.com, http://twitter.com/nogoodnick
+Nicholas Whitt - nick.whitt@gmail.com, http://twitter.com/nogoodnick
Evan Winslow - evan@elgg.org, http://evanwinslow.com/
diff --git a/actions/profile/edit.php b/actions/profile/edit.php
index 8ca60f246..89bf2bc0b 100644
--- a/actions/profile/edit.php
+++ b/actions/profile/edit.php
@@ -25,7 +25,7 @@ if (!is_array($accesslevel)) {
* wrapper for recursive array walk decoding
*/
function profile_array_decoder(&$v) {
- $v = html_entity_decode($v, ENT_COMPAT, 'UTF-8');
+ $v = _elgg_html_decode($v);
}
$profile_fields = elgg_get_config('profile_fields');
@@ -37,7 +37,7 @@ foreach ($profile_fields as $shortname => $valuetype) {
if (is_array($value)) {
array_walk_recursive($value, 'profile_array_decoder');
} else {
- $value = html_entity_decode($value, ENT_COMPAT, 'UTF-8');
+ $value = _elgg_html_decode($value);
}
// limit to reasonable sizes
@@ -51,7 +51,7 @@ foreach ($profile_fields as $shortname => $valuetype) {
if ($valuetype == 'tags') {
$value = string_to_tag_array($value);
}
-
+
$input[$shortname] = $value;
}
@@ -71,24 +71,30 @@ if (sizeof($input) > 0) {
foreach ($input as $shortname => $value) {
$options = array(
'guid' => $owner->guid,
- 'metadata_name' => $shortname
+ 'metadata_name' => $shortname,
+ 'limit' => false
);
elgg_delete_metadata($options);
- if (isset($accesslevel[$shortname])) {
- $access_id = (int) $accesslevel[$shortname];
- } else {
- // this should never be executed since the access level should always be set
- $access_id = ACCESS_DEFAULT;
- }
- if (is_array($value)) {
- $i = 0;
- foreach ($value as $interval) {
- $i++;
- $multiple = ($i > 1) ? TRUE : FALSE;
- create_metadata($owner->guid, $shortname, $interval, 'text', $owner->guid, $access_id, $multiple);
+
+ if(!is_null($value) && ($value !== '')){
+ // only create metadata for non empty values (0 is allowed) to prevent metadata records with empty string values #4858
+
+ if (isset($accesslevel[$shortname])) {
+ $access_id = (int) $accesslevel[$shortname];
+ } else {
+ // this should never be executed since the access level should always be set
+ $access_id = ACCESS_DEFAULT;
+ }
+ if (is_array($value)) {
+ $i = 0;
+ foreach ($value as $interval) {
+ $i++;
+ $multiple = ($i > 1) ? TRUE : FALSE;
+ create_metadata($owner->guid, $shortname, $interval, 'text', $owner->guid, $access_id, $multiple);
+ }
+ } else {
+ create_metadata($owner->getGUID(), $shortname, $value, 'text', $owner->getGUID(), $access_id);
}
- } else {
- create_metadata($owner->getGUID(), $shortname, $value, 'text', $owner->getGUID(), $access_id);
}
}
diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php
index 06000c923..f43599999 100644
--- a/engine/classes/ElggMenuBuilder.php
+++ b/engine/classes/ElggMenuBuilder.php
@@ -204,6 +204,9 @@ class ElggMenuBuilder {
// sort each section
foreach ($this->menu as $index => $section) {
+ foreach ($section as $key => $node) {
+ $section[$key]->original_order = $key;
+ }
usort($section, $sort_callback);
$this->menu[$index] = $section;
@@ -232,10 +235,14 @@ class ElggMenuBuilder {
* @return bool
*/
public static function compareByText($a, $b) {
- $a = $a->getText();
- $b = $b->getText();
+ $at = $a->getText();
+ $bt = $b->getText();
- return strnatcmp($a, $b);
+ $result = strnatcmp($at, $bt);
+ if ($result === 0) {
+ return $a->original_order - $b->original_order;
+ }
+ return $result;
}
/**
@@ -246,10 +253,14 @@ class ElggMenuBuilder {
* @return bool
*/
public static function compareByName($a, $b) {
- $a = $a->getName();
- $b = $b->getName();
+ $an = $a->getName();
+ $bn = $b->getName();
- return strcmp($a, $b);
+ $result = strcmp($an, $bn);
+ if ($result === 0) {
+ return $a->original_order - $b->original_order;
+ }
+ return $result;
}
/**
@@ -260,9 +271,12 @@ class ElggMenuBuilder {
* @return bool
*/
public static function compareByWeight($a, $b) {
- $a = $a->getWeight();
- $b = $b->getWeight();
+ $aw = $a->getWeight();
+ $bw = $b->getWeight();
- return $a > $b;
+ if ($aw == $bw) {
+ return $a->original_order - $b->original_order;
+ }
+ return $aw - $bw;
}
}
diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php
index 4bc9144d4..fe25f3ddd 100644
--- a/engine/classes/ElggMenuItem.php
+++ b/engine/classes/ElggMenuItem.php
@@ -542,6 +542,9 @@ class ElggMenuItem {
* @return void
*/
public function sortChildren($sortFunction) {
+ foreach ($this->data['children'] as $key => $node) {
+ $this->data['children'][$key]->original_order = $key;
+ }
usort($this->data['children'], $sortFunction);
}
diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php
index b4bae6825..fa6296c8c 100644
--- a/engine/classes/ElggObject.php
+++ b/engine/classes/ElggObject.php
@@ -223,7 +223,7 @@ class ElggObject extends ElggEntity {
// must be member of group
if (elgg_instanceof($this->getContainerEntity(), 'group')) {
- if (!$this->getContainerEntity()->canWriteToContainer(get_user($user_guid))) {
+ if (!$this->getContainerEntity()->canWriteToContainer($user_guid)) {
return false;
}
}
diff --git a/engine/lib/output.php b/engine/lib/output.php
index 7bfc4be6e..352de863b 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -271,8 +271,8 @@ function elgg_normalize_url($url) {
// '?query=test', #target
return $url;
- } elseif (stripos($url, 'javascript:') === 0) {
- // 'javascript:'
+ } elseif (stripos($url, 'javascript:') === 0 || stripos($url, 'mailto:') === 0) {
+ // 'javascript:' and 'mailto:'
// Not covered in FILTER_VALIDATE_URL
return $url;
@@ -398,3 +398,45 @@ function elgg_strip_tags($string) {
return $string;
}
+
+/**
+ * Apply html_entity_decode() to a string while re-entitising HTML
+ * special char entities to prevent them from being decoded back to their
+ * unsafe original forms.
+ *
+ * This relies on html_entity_decode() not translating entities when
+ * doing so leaves behind another entity, e.g. > if decoded would
+ * create > which is another entity itself. This seems to escape the
+ * usual behaviour where any two paired entities creating a HTML tag are
+ * usually decoded, i.e. a lone > is not decoded, but <foo> would
+ * be decoded to <foo> since it creates a full tag.
+ *
+ * Note: This function is poorly explained in the manual - which is really
+ * bad given its potential for misuse on user input already escaped elsewhere.
+ * Stackoverflow is littered with advice to use this function in the precise
+ * way that would lead to user input being capable of injecting arbitrary HTML.
+ *
+ * @param string $string
+ *
+ * @return string
+ *
+ * @author Pádraic Brady
+ * @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
+ * @license Released under dual-license GPL2/MIT by explicit permission of Pádraic Brady
+ *
+ * @access private
+ */
+function _elgg_html_decode($string) {
+ $string = str_replace(
+ array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'),
+ array('&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'),
+ $string
+ );
+ $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8');
+ $string = str_replace(
+ array('&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'),
+ array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'),
+ $string
+ );
+ return $string;
+}
diff --git a/engine/lib/upgrades/2010052601.php b/engine/lib/upgrades/2010052601.php
index 5b477910f..a9cca6dc5 100644
--- a/engine/lib/upgrades/2010052601.php
+++ b/engine/lib/upgrades/2010052601.php
@@ -9,14 +9,14 @@ $params = array('type' => 'group',
$groups = elgg_get_entities($params);
if ($groups) {
foreach ($groups as $group) {
- $group->name = html_entity_decode($group->name, ENT_COMPAT, 'UTF-8');
- $group->description = html_entity_decode($group->description, ENT_COMPAT, 'UTF-8');
- $group->briefdescription = html_entity_decode($group->briefdescription, ENT_COMPAT, 'UTF-8');
- $group->website = html_entity_decode($group->website, ENT_COMPAT, 'UTF-8');
+ $group->name = _elgg_html_decode($group->name);
+ $group->description = _elgg_html_decode($group->description);
+ $group->briefdescription = _elgg_html_decode($group->briefdescription);
+ $group->website = _elgg_html_decode($group->website);
if ($group->interests) {
$tags = $group->interests;
- foreach ($tags as $index=>$tag) {
- $tags[$index] = html_entity_decode($tag, ENT_COMPAT, 'UTF-8');
+ foreach ($tags as $index => $tag) {
+ $tags[$index] = _elgg_html_decode($tag);
}
$group->interests = $tags;
}
diff --git a/install/ElggInstaller.php b/install/ElggInstaller.php
index 03c84a43e..934b38d28 100644
--- a/install/ElggInstaller.php
+++ b/install/ElggInstaller.php
@@ -157,7 +157,7 @@ class ElggInstaller {
'password',
);
foreach ($requiredParams as $key) {
- if (!array_key_exists($key, $params)) {
+ if (empty($params[$key])) {
$msg = elgg_echo('install:error:requiredfield', array($key));
throw new InstallationException($msg);
}
diff --git a/install/cli/sample_installer.php b/install/cli/sample_installer.php
index 954169a6a..0bae0cd23 100644
--- a/install/cli/sample_installer.php
+++ b/install/cli/sample_installer.php
@@ -3,10 +3,27 @@
* Sample cli installer script
*/
+$enabled = false;
+
+// Do not edit below this line. //////////////////////////////
+
+
+if (!$enabled) {
+ echo "To enable this script, change \$enabled to true.\n";
+ echo "You *must* disable this script after a successful installation.\n";
+ exit;
+}
+
+if (PHP_SAPI !== 'cli') {
+ echo "You must use the command line to run this script.";
+ exit;
+}
+
require_once(dirname(dirname(__FILE__)) . "/ElggInstaller.php");
$installer = new ElggInstaller();
+// none of the following may be empty
$params = array(
// database parameters
'dbuser' => '',
@@ -28,3 +45,21 @@ $params = array(
// install and create the .htaccess file
$installer->batchInstall($params, TRUE);
+
+// at this point installation has completed (otherwise an exception halted execution).
+
+// try to rewrite the script to disable it.
+if (is_writable(__FILE__)) {
+ $code = file_get_contents(__FILE__);
+ if (preg_match('~\\$enabled\\s*=\\s*(true|1)\\s*;~i', $code)) {
+ // looks safe to rewrite
+ $code = preg_replace('~\\$enabled\\s*=\\s*(true|1)\\s*;~i', '$enabled = false;', $code);
+ file_put_contents(__FILE__, $code);
+
+ echo "\nNote: This script has been disabled for your safety.\n";
+ exit;
+ }
+}
+
+echo "\nWarning: You *must* disable this script by setting \$enabled = false;.\n";
+echo "Leaving this script enabled could endanger your installation.\n";
diff --git a/js/lib/elgglib.js b/js/lib/elgglib.js
index 81209ebd0..dc7c07165 100644
--- a/js/lib/elgglib.js
+++ b/js/lib/elgglib.js
@@ -283,7 +283,7 @@ elgg.normalize_url = function(url) {
}
// 'javascript:'
- else if (url.indexOf('javascript:') === 0) {
+ else if (url.indexOf('javascript:') === 0 || url.indexOf('mailto:') === 0 ) {
return url;
}
diff --git a/mod/blog/views/default/forms/blog/save.php b/mod/blog/views/default/forms/blog/save.php
index a805541bd..7c3265c8d 100644
--- a/mod/blog/views/default/forms/blog/save.php
+++ b/mod/blog/views/default/forms/blog/save.php
@@ -53,7 +53,7 @@ $excerpt_label = elgg_echo('blog:excerpt');
$excerpt_input = elgg_view('input/text', array(
'name' => 'excerpt',
'id' => 'blog_excerpt',
- 'value' => html_entity_decode($vars['excerpt'], ENT_COMPAT, 'UTF-8')
+ 'value' => _elgg_html_decode($vars['excerpt'])
));
$body_label = elgg_echo('blog:body');
@@ -125,9 +125,10 @@ $draft_warning
$excerpt_input
</div>
-<label for="blog_description">$body_label</label>
-$body_input
-<br />
+<div>
+ <label for="blog_description">$body_label</label>
+ $body_input
+</div>
<div>
<label for="blog_tags">$tags_label</label>
diff --git a/mod/groups/actions/groups/edit.php b/mod/groups/actions/groups/edit.php
index a4169461a..2d7e1f023 100644
--- a/mod/groups/actions/groups/edit.php
+++ b/mod/groups/actions/groups/edit.php
@@ -8,15 +8,15 @@
// Load configuration
global $CONFIG;
+elgg_make_sticky_form('groups');
+
/**
* wrapper for recursive array walk decoding
*/
function profile_array_decoder(&$v) {
- $v = html_entity_decode($v, ENT_COMPAT, 'UTF-8');
+ $v = _elgg_html_decode($v);
}
-elgg_make_sticky_form('groups');
-
// Get group fields
$input = array();
foreach ($CONFIG->group as $shortname => $valuetype) {
@@ -25,7 +25,7 @@ foreach ($CONFIG->group as $shortname => $valuetype) {
if (is_array($input[$shortname])) {
array_walk_recursive($input[$shortname], 'profile_array_decoder');
} else {
- $input[$shortname] = html_entity_decode($input[$shortname], ENT_COMPAT, 'UTF-8');
+ $input[$shortname] = _elgg_html_decode($input[$shortname]);
}
if ($valuetype == 'tags') {
diff --git a/mod/messages/pages/messages/read.php b/mod/messages/pages/messages/read.php
index eb36eaa4b..a64623564 100644
--- a/mod/messages/pages/messages/read.php
+++ b/mod/messages/pages/messages/read.php
@@ -38,7 +38,7 @@ if ($inbox) {
);
$body_params = array('message' => $message);
$content .= elgg_view_form('messages/reply', $form_params, $body_params);
- $from_user = get_user($message->fromID);
+ $from_user = get_user($message->fromId);
if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid() && $from_user) {
elgg_register_menu_item('title', array(
diff --git a/version.php b/version.php
index dda087c52..a2417d848 100644
--- a/version.php
+++ b/version.php
@@ -11,7 +11,7 @@
// YYYYMMDD = Elgg Date
// XX = Interim incrementer
-$version = 2012071100;
+$version = 2012111100;
// Human-friendly version name
-$release = '1.8.8';
+$release = '1.8.9';
diff --git a/views/default/forms/profile/edit.php b/views/default/forms/profile/edit.php
index 222935344..9538b779e 100644
--- a/views/default/forms/profile/edit.php
+++ b/views/default/forms/profile/edit.php
@@ -18,7 +18,8 @@ if (is_array($profile_fields) && count($profile_fields) > 0) {
foreach ($profile_fields as $shortname => $valtype) {
$metadata = elgg_get_metadata(array(
'guid' => $vars['entity']->guid,
- 'metadata_name' => $shortname
+ 'metadata_name' => $shortname,
+ 'limit' => false
));
if ($metadata) {
if (is_array($metadata)) {
diff --git a/views/default/object/plugin/elements/dependencies.php b/views/default/object/plugin/elements/dependencies.php
index 8abd61692..d8daedd33 100644
--- a/views/default/object/plugin/elements/dependencies.php
+++ b/views/default/object/plugin/elements/dependencies.php
@@ -29,6 +29,8 @@ foreach ($deps as $dep) {
if ($dep['status']) {
$class = "elgg-state-success elgg-dependency elgg-dependency-$type";
+ } elseif ($dep['type'] == 'suggests') {
+ $class = "elgg-state-warning elgg-dependency elgg-dependency-$type";
} else {
$class = "elgg-state-error elgg-dependency elgg-dependency-$type";
}
diff --git a/views/default/output/email.php b/views/default/output/email.php
index 00eefad1f..f5a8bc4b8 100644
--- a/views/default/output/email.php
+++ b/views/default/output/email.php
@@ -10,6 +10,8 @@
*
*/
+$encoded_value = htmlspecialchars($vars['value'], ENT_QUOTES, 'UTF-8');
+
if (!empty($vars['value'])) {
- echo "<a href=\"mailto:" . $vars['value'] . "\">". htmlspecialchars($vars['value'], ENT_QUOTES, 'UTF-8', false) ."</a>";
+ echo "<a href=\"mailto:$encoded_value\">$encoded_value</a>";
} \ No newline at end of file