mirror of
https://github.com/moodle/moodle.git
synced 2025-04-22 17:02:03 +02:00
MDL-33950 check if source file is accessible in repository_ajax.php
- repository::copy_to_area() does not check access any more, and repository_recent::copy_to_area() is unnecessary - added repository::file_is_accessible() that checks access to the picked file (regardless of accessibility of the file it is referencing to)
This commit is contained in:
parent
2cbdaa77ea
commit
1bd0174743
@ -651,45 +651,60 @@ abstract class repository {
|
||||
* @return stored_file|null
|
||||
*/
|
||||
public static function get_moodle_file($source) {
|
||||
$params = unserialize(base64_decode($source));
|
||||
if (empty($params) || !is_array($params)) {
|
||||
return null;
|
||||
}
|
||||
foreach (array('contextid', 'itemid', 'filename', 'filepath', 'component') as $key) {
|
||||
if (!array_key_exists($key, $params)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$contextid = clean_param($params['contextid'], PARAM_INT);
|
||||
$component = clean_param($params['component'], PARAM_COMPONENT);
|
||||
$filearea = clean_param($params['filearea'], PARAM_AREA);
|
||||
$itemid = clean_param($params['itemid'], PARAM_INT);
|
||||
$filepath = clean_param($params['filepath'], PARAM_PATH);
|
||||
$filename = clean_param($params['filename'], PARAM_FILE);
|
||||
$params = file_storage::unpack_reference($source, true);
|
||||
$fs = get_file_storage();
|
||||
return $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename);
|
||||
return $fs->get_file($params['contextid'], $params['component'], $params['filearea'],
|
||||
$params['itemid'], $params['filepath'], $params['filename']);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to copy a moodle file to draft area
|
||||
* Repository method to make sure that user can access particular file.
|
||||
*
|
||||
* @param string $encoded The metainfo of file, it is base64 encoded php serialized data
|
||||
* This is checked when user tries to pick the file from repository to deal with
|
||||
* potential parameter substitutions is request
|
||||
*
|
||||
* @param string $source
|
||||
* @return bool whether the file is accessible by current user
|
||||
*/
|
||||
public function file_is_accessible($source) {
|
||||
if ($this->has_moodle_files()) {
|
||||
try {
|
||||
$params = file_storage::unpack_reference($source, true);
|
||||
} catch (file_reference_exception $e) {
|
||||
return false;
|
||||
}
|
||||
$browser = get_file_browser();
|
||||
$context = get_context_instance_by_id($params['contextid']);
|
||||
$file_info = $browser->get_file_info($context, $params['component'], $params['filearea'],
|
||||
$params['itemid'], $params['filepath'], $params['filename']);
|
||||
return !empty($file_info);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to copy a moodle file to draft area.
|
||||
*
|
||||
* It DOES NOT check if the user is allowed to access this file because the actual file
|
||||
* can be located in the area where user does not have access to but there is an alias
|
||||
* to this file in the area where user CAN access it.
|
||||
* {@link file_is_accessible} should be called for alias location before calling this function.
|
||||
*
|
||||
* @param string $source The metainfo of file, it is base64 encoded php serialized data
|
||||
* @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
|
||||
* attributes of the new file
|
||||
* @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
|
||||
* the limit, the file_exception is thrown.
|
||||
* @return array The information of file
|
||||
* @return array The information about the created file
|
||||
*/
|
||||
public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
|
||||
public function copy_to_area($source, $filerecord, $maxbytes = -1) {
|
||||
global $USER;
|
||||
$fs = get_file_storage();
|
||||
$browser = get_file_browser();
|
||||
|
||||
if ($this->has_moodle_files() == false) {
|
||||
throw new coding_exception('Only repository used to browse moodle files can use repository::copy_to_area()');
|
||||
}
|
||||
|
||||
$params = unserialize(base64_decode($encoded));
|
||||
$user_context = context_user::instance($USER->id);
|
||||
|
||||
$filerecord = (array)$filerecord;
|
||||
@ -701,17 +716,9 @@ abstract class repository {
|
||||
$new_filepath = $filerecord['filepath'];
|
||||
$new_filename = $filerecord['filename'];
|
||||
|
||||
$contextid = clean_param($params['contextid'], PARAM_INT);
|
||||
$fileitemid = clean_param($params['itemid'], PARAM_INT);
|
||||
$filename = clean_param($params['filename'], PARAM_FILE);
|
||||
$filepath = clean_param($params['filepath'], PARAM_PATH);;
|
||||
$filearea = clean_param($params['filearea'], PARAM_AREA);
|
||||
$component = clean_param($params['component'], PARAM_COMPONENT);
|
||||
|
||||
$context = get_context_instance_by_id($contextid);
|
||||
// the file needs to copied to draft area
|
||||
$file_info = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
|
||||
if ($maxbytes !== -1 && $file_info->get_filesize() > $maxbytes) {
|
||||
$stored_file = self::get_moodle_file($source);
|
||||
if ($maxbytes != -1 && $stored_file->get_filesize() > $maxbytes) {
|
||||
throw new file_exception('maxbytes');
|
||||
}
|
||||
|
||||
@ -719,7 +726,7 @@ abstract class repository {
|
||||
// create new file
|
||||
$unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
|
||||
$filerecord['filename'] = $unused_filename;
|
||||
$file_info->copy_to_storage($filerecord);
|
||||
$fs->create_file_from_storedfile($filerecord, $stored_file);
|
||||
$event = array();
|
||||
$event['event'] = 'fileexists';
|
||||
$event['newfile'] = new stdClass;
|
||||
@ -729,17 +736,17 @@ abstract class repository {
|
||||
$event['existingfile'] = new stdClass;
|
||||
$event['existingfile']->filepath = $new_filepath;
|
||||
$event['existingfile']->filename = $new_filename;
|
||||
$event['existingfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
|
||||
$event['existingfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();
|
||||
return $event;
|
||||
} else {
|
||||
$file_info->copy_to_storage($filerecord);
|
||||
$fs->create_file_from_storedfile($filerecord, $stored_file);
|
||||
$info = array();
|
||||
$info['itemid'] = $draftitemid;
|
||||
$info['file'] = $new_filename;
|
||||
$info['title'] = $new_filename;
|
||||
$info['file'] = $new_filename;
|
||||
$info['title'] = $new_filename;
|
||||
$info['contextid'] = $user_context->id;
|
||||
$info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
|
||||
$info['filesize'] = $file_info->get_filesize();
|
||||
$info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();
|
||||
$info['filesize'] = $stored_file->get_filesize();
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
@ -177,91 +177,22 @@ class repository_recent extends repository {
|
||||
public function supported_returntypes() {
|
||||
return FILE_INTERNAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function overwrite the default implement to copying file using file_storage
|
||||
* Repository method to make sure that user can access particular file.
|
||||
*
|
||||
* @param string $encoded The information of file, it is base64 encoded php serialized data
|
||||
* @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
|
||||
* attributes of the new file
|
||||
* @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
|
||||
* the limit, the file_exception is thrown.
|
||||
* @return array The information of file
|
||||
* This is checked when user tries to pick the file from repository to deal with
|
||||
* potential parameter substitutions is request
|
||||
*
|
||||
* @todo MDL-33805 remove this function when recent files are managed correctly
|
||||
*
|
||||
* @param string $source
|
||||
* @return bool whether the file is accessible by current user
|
||||
*/
|
||||
public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
|
||||
public function file_is_accessible($source) {
|
||||
global $USER;
|
||||
|
||||
$user_context = get_context_instance(CONTEXT_USER, $USER->id);
|
||||
|
||||
$filerecord = (array)$filerecord;
|
||||
// make sure the new file will be created in user draft area
|
||||
$filerecord['component'] = 'user'; // make sure
|
||||
$filerecord['filearea'] = 'draft'; // make sure
|
||||
$filerecord['contextid'] = $user_context->id;
|
||||
$filerecord['sortorder'] = 0;
|
||||
$draftitemid = $filerecord['itemid'];
|
||||
$new_filepath = $filerecord['filepath'];
|
||||
$new_filename = $filerecord['filename'];
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
$params = unserialize(base64_decode($encoded));
|
||||
|
||||
$contextid = clean_param($params['contextid'], PARAM_INT);
|
||||
$fileitemid = clean_param($params['itemid'], PARAM_INT);
|
||||
$filename = clean_param($params['filename'], PARAM_FILE);
|
||||
$filepath = clean_param($params['filepath'], PARAM_PATH);;
|
||||
$filearea = clean_param($params['filearea'], PARAM_AREA);
|
||||
$component = clean_param($params['component'], PARAM_COMPONENT);
|
||||
|
||||
// XXX:
|
||||
// When user try to pick a file from other filearea, normally file api will use file browse to
|
||||
// operate the files with capability check, but in some areas, users don't have permission to
|
||||
// browse the files (for example, forum_attachment area).
|
||||
//
|
||||
// To get 'recent' plugin working, we need to use lower level file_stoarge class to bypass the
|
||||
// capability check, we will use a better workaround to improve it.
|
||||
// TODO MDL-33297 apply here
|
||||
if ($stored_file = $fs->get_file($contextid, $component, $filearea, $fileitemid, $filepath, $filename)) {
|
||||
// verify user id
|
||||
if ($USER->id != $stored_file->get_userid()) {
|
||||
throw new moodle_exception('errornotyourfile', 'repository');
|
||||
}
|
||||
if ($maxbytes !== -1 && $stored_file->get_filesize() > $maxbytes) {
|
||||
throw new file_exception('maxbytes');
|
||||
}
|
||||
|
||||
// test if file already exists
|
||||
if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
|
||||
// create new file
|
||||
$unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
|
||||
$filerecord['filename'] = $unused_filename;
|
||||
// create a tmp file
|
||||
$fs->create_file_from_storedfile($filerecord, $stored_file);
|
||||
$event = array();
|
||||
$event['event'] = 'fileexists';
|
||||
$event['newfile'] = new stdClass;
|
||||
$event['newfile']->filepath = $new_filepath;
|
||||
$event['newfile']->filename = $unused_filename;
|
||||
$event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $unused_filename)->out();
|
||||
$event['existingfile'] = new stdClass;
|
||||
$event['existingfile']->filepath = $new_filepath;
|
||||
$event['existingfile']->filename = $new_filename;
|
||||
$event['existingfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
|
||||
return $event;
|
||||
} else {
|
||||
$fs->create_file_from_storedfile($filerecord, $stored_file);
|
||||
$info = array();
|
||||
$info['title'] = $new_filename;
|
||||
$info['file'] = $new_filename;
|
||||
$info['itemid'] = $draftitemid;
|
||||
$info['filesize'] = $stored_file->get_filesize();
|
||||
$info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
|
||||
$info['contextid'] = $user_context->id;
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
$file = self::get_moodle_file($source);
|
||||
return (!empty($file) && $file->get_userid() == $USER->id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,7 +232,14 @@ switch ($action) {
|
||||
$record->userid = $USER->id;
|
||||
$record->sortorder = 0;
|
||||
|
||||
// Check that user has permission to access this file
|
||||
if (!$repo->file_is_accessible($source)) {
|
||||
throw new file_exception('storedfilecannotread');
|
||||
}
|
||||
|
||||
// If file is already a reference, set $source = file source, $repo = file repository
|
||||
// note that in this case user may not have permission to access the source file directly
|
||||
// so no file_browser/file_info can be used below
|
||||
if ($repo->has_moodle_files()) {
|
||||
$file = repository::get_moodle_file($source);
|
||||
if ($file && $file->is_external_file()) {
|
||||
@ -298,13 +305,13 @@ switch ($action) {
|
||||
} else {
|
||||
// Download file to moodle.
|
||||
$downloadedfile = $repo->get_file($source, $saveas_filename);
|
||||
if ($downloadedfile['path'] === false) {
|
||||
if (empty($downloadedfile['path'])) {
|
||||
$err->error = get_string('cannotdownload', 'repository');
|
||||
die(json_encode($err));
|
||||
}
|
||||
|
||||
// Check if exceed maxbytes.
|
||||
if (($maxbytes!==-1) && (filesize($downloadedfile['path']) > $maxbytes)) {
|
||||
if ($maxbytes != -1 && filesize($downloadedfile['path']) > $maxbytes) {
|
||||
throw new file_exception('maxbytes');
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user