diff --git a/lang/en/repository.php b/lang/en/repository.php index 25713bed4aacd..5ee707f6e4803 100644 --- a/lang/en/repository.php +++ b/lang/en/repository.php @@ -158,7 +158,7 @@ $string['nofilesavailable'] = 'No files available'; $string['nomorefiles'] = 'No more attachments allowed'; $string['nopathselected'] = 'No destination path select yet (double click tree node to select)'; -$string['nopermissiontoaccess'] = 'No permission to access this repository'; +$string['nopermissiontoaccess'] = 'No permission to access this repository.'; $string['noresult'] = 'No search result'; $string['norepositoriesavailable'] = 'Sorry, none of your current repositories can return files in the required format.'; $string['norepositoriesexternalavailable'] = 'Sorry, none of your current repositories can return external files.'; diff --git a/repository/coursefiles/lib.php b/repository/coursefiles/lib.php index 959f34e344a92..cee6d858f2ddd 100644 --- a/repository/coursefiles/lib.php +++ b/repository/coursefiles/lib.php @@ -216,4 +216,13 @@ public function get_reference_file_lifetime($ref) { // this should be realtime return 0; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/equella/lib.php b/repository/equella/lib.php index d29378e01d75c..b54806b4a3f51 100644 --- a/repository/equella/lib.php +++ b/repository/equella/lib.php @@ -437,4 +437,13 @@ public function get_reference_details($reference, $filestatus = 0) { return get_string('lostsource', 'repository', ''); } } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/filesystem/lib.php b/repository/filesystem/lib.php index 432e79d4374d4..c856371954ae1 100644 --- a/repository/filesystem/lib.php +++ b/repository/filesystem/lib.php @@ -333,4 +333,13 @@ public function send_file($storedfile, $lifetime=86400 , $filter=0, $forcedownlo send_file_not_found(); } } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/flickr_public/lib.php b/repository/flickr_public/lib.php index 6b11cfc5ac56a..04d1f07d783ca 100644 --- a/repository/flickr_public/lib.php +++ b/repository/flickr_public/lib.php @@ -550,4 +550,13 @@ public function supported_returntypes() { public function get_file_source_info($photoid) { return $this->build_photo_url($photoid); } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/lib.php b/repository/lib.php index f28a2d7e755d2..0a2bf47ee0e88 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -487,6 +487,9 @@ abstract class repository { public $returntypes; /** @var stdClass repository instance database record */ public $instance; + /** @var string Type of repository (webdav, google_docs, dropbox, ...). Read from $this->get_typename(). */ + protected $typename; + /** * Constructor * @@ -558,6 +561,24 @@ public static function get_repository_by_id($repositoryid, $context, $options = } } + /** + * Returns the type name of the repository. + * + * @return string type name of the repository. + * @since 2.5 + */ + public function get_typename() { + if (empty($this->typename)) { + $matches = array(); + if (!preg_match("/^repository_(.*)$/", get_class($this), $matches)) { + throw new coding_exception('The class name of a repository should be repository_, '. + 'e.g. repository_dropbox'); + } + $this->typename = $matches[1]; + } + return $this->typename; + } + /** * Get a repository type object by a given type name. * @@ -620,19 +641,43 @@ public static function get_types($visible=null) { } /** - * Checks if user has a capability to view the current repository in current context + * Checks if user has a capability to view the current repository. * - * @return bool + * @return bool true when the user can, otherwise throws an exception. + * @throws repository_exception when the user does not meet the requirements. */ public final function check_capability() { - $capability = false; - if (preg_match("/^repository_(.*)$/", get_class($this), $matches)) { - $type = $matches[1]; - $capability = has_capability('repository/'.$type.':view', $this->context); + global $USER; + + // Ensure that the user can view the repository in the current context. + $can = has_capability('repository/'.$this->get_typename().':view', $this->context); + + // Context in which the repository has been created. + $repocontext = context::instance_by_id($this->instance->contextid); + + // Prevent access to private repositories when logged in as. + if ($can && session_is_loggedinas()) { + if ($this->contains_private_data() || $repocontext->contextlevel == CONTEXT_USER) { + $can = false; + } } - if (!$capability) { - throw new repository_exception('nopermissiontoaccess', 'repository'); + + // Ensure that the user can view the repository in the context of the repository. + // We need to perform the check when already disallowed. + if ($can) { + if ($repocontext->contextlevel == CONTEXT_USER && $repocontext->instanceid != $USER->id) { + // Prevent URL hijack to access someone else's repository. + $can = false; + } else { + $can = has_capability('repository/'.$this->get_typename().':view', $repocontext); + } + } + + if ($can) { + return true; } + + throw new repository_exception('nopermissiontoaccess', 'repository'); } /** @@ -1767,13 +1812,36 @@ public function is_visible() { */ public function get_name() { global $DB; - if ( $name = $this->instance->name ) { + if ($name = $this->instance->name) { return $name; } else { - return get_string('pluginname', 'repository_' . $this->options['type']); + return get_string('pluginname', 'repository_' . $this->get_typename()); } } + /** + * Is this repository accessing private data? + * + * This function should return true for the repositories which access external private + * data from a user. This is the case for repositories such as Dropbox, Google Docs or Box.net + * which authenticate the user and then store the auth token. + * + * Of course, many repositories store 'private data', but we only want to set + * contains_private_data() to repositories which are external to Moodle and shouldn't be accessed + * to by the users having the capability to 'login as' someone else. For instance, the repository + * 'Private files' is not considered as private because it's part of Moodle. + * + * You should not set contains_private_data() to true on repositories which allow different types + * of instances as the levels other than 'user' are, by definition, not private. Also + * the user instances will be protected when they need to. + * + * @return boolean True when the repository accesses private external data. + * @since 2.5 + */ + public function contains_private_data() { + return true; + } + /** * What kind of files will be in this repository? * @@ -1806,7 +1874,7 @@ final public function get_meta() { $meta = new stdClass(); $meta->id = $this->id; $meta->name = format_string($this->get_name()); - $meta->type = $this->options['type']; + $meta->type = $this->get_typename(); $meta->icon = $OUTPUT->pix_url('icon', 'repository_'.$meta->type)->out(false); $meta->supported_types = file_get_typegroup('extension', $this->supported_filetypes()); $meta->return_types = $this->supported_returntypes(); diff --git a/repository/local/lib.php b/repository/local/lib.php index 5798ad6f5609a..93bdd2062ec06 100644 --- a/repository/local/lib.php +++ b/repository/local/lib.php @@ -262,4 +262,13 @@ private function get_node_path(file_info $fileinfo) { 'name' => $fileinfo->get_visible_name() ); } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/merlot/lib.php b/repository/merlot/lib.php index 0ad1418419b23..187eef580535d 100644 --- a/repository/merlot/lib.php +++ b/repository/merlot/lib.php @@ -161,5 +161,14 @@ public function supported_returntypes() { public function supported_filetypes() { return array('link'); } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/recent/lib.php b/repository/recent/lib.php index 76cdb69e2a8b8..a370a33ba0e94 100644 --- a/repository/recent/lib.php +++ b/repository/recent/lib.php @@ -203,4 +203,13 @@ public function file_is_accessible($source) { public function has_moodle_files() { return true; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/s3/lib.php b/repository/s3/lib.php index 596fc09cbe3c2..346f771565638 100644 --- a/repository/s3/lib.php +++ b/repository/s3/lib.php @@ -249,4 +249,13 @@ public static function type_config_form($mform, $classname = 'repository') { public function supported_returntypes() { return FILE_INTERNAL; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/upgrade.txt b/repository/upgrade.txt index 4f420d634f44f..4728b1f7bfb5e 100644 --- a/repository/upgrade.txt +++ b/repository/upgrade.txt @@ -8,6 +8,11 @@ http://docs.moodle.org/dev/Repository_API * repository::append_suffix() has been deprecated, use repository::get_unused_filename() if you need to get a file name which has not yet been used in the draft area. +* contains_private_data() is a new method to determine if a user 'logged in as' another user + can access the content of the repository. The default is to return True (no access). + +* get_typename() returns the type of repository: dropbox, googledocs, etc... + === 2.4 === * copy_to_area() can receive a new parameter called $areamaxbytes which controls the maximum diff --git a/repository/upload/lib.php b/repository/upload/lib.php index eed039eb1acd1..1cfcf289da29e 100644 --- a/repository/upload/lib.php +++ b/repository/upload/lib.php @@ -288,4 +288,13 @@ public function get_listing($path = '', $page = '') { public function supported_returntypes() { return FILE_INTERNAL; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/url/lib.php b/repository/url/lib.php index 1255570d5d91c..45a5b3fb94836 100644 --- a/repository/url/lib.php +++ b/repository/url/lib.php @@ -237,4 +237,13 @@ public function get_file_source_info($url) { public function supported_filetypes() { return array('web_image'); } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/user/lib.php b/repository/user/lib.php index 2b8412fc0073b..4e536d56ab684 100644 --- a/repository/user/lib.php +++ b/repository/user/lib.php @@ -169,4 +169,13 @@ public function get_reference_file_lifetime($ref) { // this should be realtime return 0; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/webdav/lib.php b/repository/webdav/lib.php index e2d39bf315d9e..5a19cb360532e 100644 --- a/repository/webdav/lib.php +++ b/repository/webdav/lib.php @@ -185,4 +185,14 @@ public static function instance_config_form($mform) { public function supported_returntypes() { return (FILE_INTERNAL | FILE_EXTERNAL); } + + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/wikimedia/lib.php b/repository/wikimedia/lib.php index 09a00fb924a41..490c6d556b18e 100644 --- a/repository/wikimedia/lib.php +++ b/repository/wikimedia/lib.php @@ -189,4 +189,13 @@ public function supported_returntypes() { public function get_file_source_info($url) { return $url; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } } diff --git a/repository/youtube/lib.php b/repository/youtube/lib.php index bc2f30461c3b4..e3f39ab1ce25d 100644 --- a/repository/youtube/lib.php +++ b/repository/youtube/lib.php @@ -202,4 +202,13 @@ public function supported_filetypes() { public function supported_returntypes() { return FILE_EXTERNAL; } + + /** + * Is this repository accessing private data? + * + * @return bool + */ + public function contains_private_data() { + return false; + } }