From 61961447c29d48e5a494e7c02e653d6ff00551b2 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Thu, 26 Jun 2014 08:53:25 +0800 Subject: [PATCH] MDL-45616 repositories: use json encoding instead of serialization --- repository/coursefiles/lib.php | 10 +++++----- repository/equella/callback.php | 2 +- repository/equella/lib.php | 15 ++++++++++----- repository/lib.php | 26 +++++++++++++++++++++++--- repository/local/lib.php | 6 +++--- repository/recent/lib.php | 5 +++-- repository/user/lib.php | 8 ++++---- 7 files changed, 49 insertions(+), 23 deletions(-) diff --git a/repository/coursefiles/lib.php b/repository/coursefiles/lib.php index 199be34c44f..ad4fa83faaa 100644 --- a/repository/coursefiles/lib.php +++ b/repository/coursefiles/lib.php @@ -63,7 +63,7 @@ class repository_coursefiles extends repository { $browser = get_file_browser(); if (!empty($encodedpath)) { - $params = unserialize(base64_decode($encodedpath)); + $params = json_decode(base64_decode($encodedpath), true); if (is_array($params)) { $filepath = is_null($params['filepath']) ? NULL : clean_param($params['filepath'], PARAM_PATH); $filename = is_null($params['filename']) ? NULL : clean_param($params['filename'], PARAM_FILE); @@ -80,12 +80,12 @@ class repository_coursefiles extends repository { if ($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) { // build path navigation $pathnodes = array(); - $encodedpath = base64_encode(serialize($fileinfo->get_params())); + $encodedpath = base64_encode(json_encode($fileinfo->get_params())); $pathnodes[] = array('name'=>$fileinfo->get_visible_name(), 'path'=>$encodedpath); $level = $fileinfo->get_parent(); while ($level) { $params = $level->get_params(); - $encodedpath = base64_encode(serialize($params)); + $encodedpath = base64_encode(json_encode($params)); if ($params['contextid'] != $context->id) { break; } @@ -102,7 +102,7 @@ class repository_coursefiles extends repository { if ($child->is_directory()) { $params = $child->get_params(); $subdir_children = $child->get_children(); - $encodedpath = base64_encode(serialize($params)); + $encodedpath = base64_encode(json_encode($params)); $node = array( 'title' => $child->get_visible_name(), 'datemodified' => $child->get_timemodified(), @@ -113,7 +113,7 @@ class repository_coursefiles extends repository { ); $list[] = $node; } else { - $encodedpath = base64_encode(serialize($child->get_params())); + $encodedpath = base64_encode(json_encode($child->get_params())); $node = array( 'title' => $child->get_visible_name(), 'size' => $child->get_filesize(), diff --git a/repository/equella/callback.php b/repository/equella/callback.php index 987cfcacd28..e8f25c9ac17 100644 --- a/repository/equella/callback.php +++ b/repository/equella/callback.php @@ -55,7 +55,7 @@ if (isset($info->license)) { $license = s(clean_param($info->license, PARAM_ALPHAEXT)); } -$source = base64_encode(serialize((object)array('url'=>$url,'filename'=>$filename))); +$source = base64_encode(json_encode(array('url'=>$url,'filename'=>$filename))); $js =<< diff --git a/repository/equella/lib.php b/repository/equella/lib.php index 08876a4f7ea..fbd9c8479d3 100644 --- a/repository/equella/lib.php +++ b/repository/equella/lib.php @@ -125,7 +125,11 @@ class repository_equella extends repository { * @return string file referece */ public function get_file_reference($source) { - return $source; + // Internally we store serialized value but user input is json-encoded for security reasons. + $ref = json_decode(base64_decode($source)); + $filename = clean_param($ref->filename, PARAM_FILE); + $url = clean_param($ref->url, PARAM_URL); + return base64_encode(serialize((object)array('url' => $url, 'filename' => $filename))); } /** @@ -400,12 +404,13 @@ class repository_equella extends repository { /** * Return the source information * - * @param stdClass $url + * @param string $source * @return string|null */ - public function get_file_source_info($url) { - $ref = unserialize(base64_decode($url)); - return 'EQUELLA: ' . $ref->filename; + public function get_file_source_info($source) { + $ref = json_decode(base64_decode($source)); + $filename = clean_param($ref->filename, PARAM_FILE); + return 'EQUELLA: ' . $filename; } /** diff --git a/repository/lib.php b/repository/lib.php index a353d9b8bb4..97a1783dd6c 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -1666,12 +1666,32 @@ abstract class repository implements cacheable_object { * Prepare file reference information * * @param string $source source of the file, returned by repository as 'source' and received back from user (not cleaned) - * @return string file referece + * @return string file reference, ready to be stored */ public function get_file_reference($source) { if ($source && $this->has_moodle_files()) { - $params = file_storage::unpack_reference($source); - if (!is_array($params)) { + $params = @json_decode(base64_decode($source), true); + if (!$params && !in_array($this->get_typename(), array('recent', 'user', 'local', 'coursefiles'))) { + // IMPORTANT! Since default format for moodle files was changed in the minor release as a security fix + // we maintain an old code here in order not to break 3rd party repositories that deal + // with moodle files. Repositories are strongly encouraged to be upgraded, see MDL-45616. + // In Moodle 2.8 this fallback will be removed. + $params = file_storage::unpack_reference($source, true); + return file_storage::pack_reference($params); + } + if (!is_array($params) || empty($params['contextid'])) { + throw new repository_exception('invalidparams', 'repository'); + } + $params = array( + 'component' => empty($params['component']) ? '' : clean_param($params['component'], PARAM_COMPONENT), + 'filearea' => empty($params['filearea']) ? '' : clean_param($params['filearea'], PARAM_AREA), + 'itemid' => empty($params['itemid']) ? 0 : clean_param($params['itemid'], PARAM_INT), + 'filename' => empty($params['filename']) ? null : clean_param($params['filename'], PARAM_FILE), + 'filepath' => empty($params['filepath']) ? null : clean_param($params['filepath'], PARAM_PATH), + 'contextid' => clean_param($params['contextid'], PARAM_INT) + ); + // Check if context exists. + if (!context::instance_by_id($params['contextid'], IGNORE_MISSING)) { throw new repository_exception('invalidparams', 'repository'); } return file_storage::pack_reference($params); diff --git a/repository/local/lib.php b/repository/local/lib.php index 2b49d04e726..18eb721de2e 100644 --- a/repository/local/lib.php +++ b/repository/local/lib.php @@ -56,7 +56,7 @@ class repository_local extends repository { $component = null; if (!empty($encodedpath)) { - $params = unserialize(base64_decode($encodedpath)); + $params = json_decode(base64_decode($encodedpath), true); if (is_array($params) && isset($params['contextid'])) { $component = is_null($params['component']) ? NULL : clean_param($params['component'], PARAM_COMPONENT); $filearea = is_null($params['filearea']) ? NULL : clean_param($params['filearea'], PARAM_AREA); @@ -205,7 +205,7 @@ class repository_local extends repository { */ private function get_node(file_info $fileinfo) { global $OUTPUT; - $encodedpath = base64_encode(serialize($fileinfo->get_params())); + $encodedpath = base64_encode(json_encode($fileinfo->get_params())); $node = array( 'title' => $fileinfo->get_visible_name(), 'datemodified' => $fileinfo->get_timemodified(), @@ -245,7 +245,7 @@ class repository_local extends repository { * @return array */ private function get_node_path(file_info $fileinfo) { - $encodedpath = base64_encode(serialize($fileinfo->get_params())); + $encodedpath = base64_encode(json_encode($fileinfo->get_params())); return array( 'path' => $encodedpath, 'name' => $fileinfo->get_visible_name() diff --git a/repository/recent/lib.php b/repository/recent/lib.php index f016492ab4a..09ffddf5f16 100644 --- a/repository/recent/lib.php +++ b/repository/recent/lib.php @@ -126,7 +126,7 @@ class repository_recent extends repository { $fileinfo = $browser->get_file_info($context, $file['component'], $file['filearea'], $file['itemid'], $file['filepath'], $file['filename']); if ($fileinfo) { - $params = base64_encode(serialize($file)); + $params = base64_encode(json_encode($file)); $node = array( 'title' => $fileinfo->get_visible_name(), 'size' => $fileinfo->get_filesize(), @@ -192,7 +192,8 @@ class repository_recent extends repository { */ public function file_is_accessible($source) { global $USER; - $file = self::get_moodle_file($source); + $reference = $this->get_file_reference($source); + $file = self::get_moodle_file($reference); return (!empty($file) && $file->get_userid() == $USER->id); } diff --git a/repository/user/lib.php b/repository/user/lib.php index faaf2f09627..2747f340c6c 100644 --- a/repository/user/lib.php +++ b/repository/user/lib.php @@ -61,7 +61,7 @@ class repository_user extends repository { $list = array(); if (!empty($encodedpath)) { - $params = unserialize(base64_decode($encodedpath)); + $params = json_decode(base64_decode($encodedpath), true); if (is_array($params)) { $filepath = clean_param($params['filepath'], PARAM_PATH); $filename = clean_param($params['filename'], PARAM_FILE); @@ -84,7 +84,7 @@ class repository_user extends repository { $level = $fileinfo; $params = $fileinfo->get_params(); while ($level && $params['component'] == 'user' && $params['filearea'] == 'private') { - $encodedpath = base64_encode(serialize($level->get_params())); + $encodedpath = base64_encode(json_encode($level->get_params())); $pathnodes[] = array('name'=>$level->get_visible_name(), 'path'=>$encodedpath); $level = $level->get_parent(); $params = $level->get_params(); @@ -95,7 +95,7 @@ class repository_user extends repository { $children = $fileinfo->get_children(); foreach ($children as $child) { if ($child->is_directory()) { - $encodedpath = base64_encode(serialize($child->get_params())); + $encodedpath = base64_encode(json_encode($child->get_params())); $node = array( 'title' => $child->get_visible_name(), 'datemodified' => $child->get_timemodified(), @@ -106,7 +106,7 @@ class repository_user extends repository { ); $list[] = $node; } else { - $encodedpath = base64_encode(serialize($child->get_params())); + $encodedpath = base64_encode(json_encode($child->get_params())); $node = array( 'title' => $child->get_visible_name(), 'size' => $child->get_filesize(), -- 2.11.4.GIT