From 96e40b6cfc63734b0914accc2d6c1ea43f5a1c21 Mon Sep 17 00:00:00 2001 From: Adrian Greeve Date: Mon, 8 Jan 2018 08:38:10 +0800 Subject: [PATCH] MDL-61131 repositories: Added a key to verify incoming urls. --- lang/en/repository.php | 2 ++ repository/filepicker.js | 6 +++++- repository/lib.php | 19 +++++++++++++++++++ repository/repository_ajax.php | 11 +++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lang/en/repository.php b/lang/en/repository.php index a0e32a3b9685b..993d67574aa14 100644 --- a/lang/en/repository.php +++ b/lang/en/repository.php @@ -164,6 +164,7 @@ $string['manageinstances'] = 'Manage instances'; $string['manageurl'] = 'Manage'; $string['manageuserrepository'] = 'Manage individual repository'; +$string['missingsourcekey'] = 'The source key is missing. This key must also be provided to retrieve the file.'; $string['moving'] = 'Moving'; $string['name'] = 'Name'; $string['newfolder'] = 'New folder'; @@ -220,6 +221,7 @@ $string['setmainfile_help'] = 'If there are multiple files in the folder, the main file is the one that appears on the view page. Other files such as images or videos may be embedded in it. In filemanager the main file is indicated with a title in bold.'; $string['siteinstances'] = 'Repositories instances of the site'; $string['size'] = 'Size'; +$string['sourcekeymismatch'] = 'The source url does not match the sourcekey.'; $string['submit'] = 'Submit'; $string['sync'] = 'Sync'; $string['syncfiletimeout'] = 'Sync file timeout'; diff --git a/repository/filepicker.js b/repository/filepicker.js index 238bef2321b46..d15cce764b24a 100644 --- a/repository/filepicker.js +++ b/repository/filepicker.js @@ -1116,6 +1116,7 @@ M.core_filepicker.init = function(Y, options) { selectnode.one('.fp-setauthor input').set('value', args.author ? args.author : this.options.author); this.set_selected_license(selectnode.one('.fp-setlicense'), args.license); selectnode.one('form #filesource-'+client_id).set('value', args.source); + selectnode.one('form #filesourcekey-'+client_id).set('value', args.sourcekey); // display static information about a file (when known) var attrs = ['datemodified','datecreated','size','license','author','dimensions']; @@ -1159,7 +1160,8 @@ M.core_filepicker.init = function(Y, options) { var repository_id = this.active_repo.id; var title = selectnode.one('.fp-saveas input').get('value'); var filesource = selectnode.one('form #filesource-'+client_id).get('value'); - var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath}; + var filesourcekey = selectnode.one('form #filesourcekey-'+client_id).get('value'); + var params = {'title':title, 'source':filesource, 'savepath': this.options.savepath, sourcekey: filesourcekey}; var license = selectnode.one('.fp-setlicense select'); if (license) { params['license'] = license.get('value'); @@ -1217,6 +1219,8 @@ M.core_filepicker.init = function(Y, options) { var elform = selectnode.one('form'); elform.appendChild(Y.Node.create(''). setAttrs({type:'hidden',id:'filesource-'+client_id})); + elform.appendChild(Y.Node.create(''). + setAttrs({type:'hidden',id:'filesourcekey-'+client_id})); elform.on('keydown', function(e) { if (e.keyCode == 13) { getfile.simulate('click'); diff --git a/repository/lib.php b/repository/lib.php index 5d0d905be5b8a..188193dcf4636 100644 --- a/repository/lib.php +++ b/repository/lib.php @@ -2194,6 +2194,11 @@ protected static function prepare_list($list) { $file =& $list[$i]; $converttoobject = false; } + + if (isset($file['source'])) { + $file['sourcekey'] = sha1($file['source'] . self::get_secret_key() . sesskey()); + } + if (isset($file['size'])) { $file['size'] = (int)$file['size']; $file['size_f'] = display_size($file['size']); @@ -2789,6 +2794,20 @@ public function uses_post_requests() { debugging('The method repository::uses_post_requests() is deprecated and must not be used anymore.', DEBUG_DEVELOPER); return false; } + + /** + * Generate a secret key to be used for passing sensitive information around. + * + * @return string repository secret key. + */ + final static public function get_secret_key() { + global $CFG; + + if (!isset($CFG->reposecretkey)) { + set_config('reposecretkey', time() . random_string(32)); + } + return $CFG->reposecretkey; + } } /** diff --git a/repository/repository_ajax.php b/repository/repository_ajax.php index 6547db148fb05..4e6aaa2c09b92 100644 --- a/repository/repository_ajax.php +++ b/repository/repository_ajax.php @@ -40,6 +40,7 @@ $license = optional_param('license', $CFG->sitedefaultlicense, PARAM_TEXT); $author = optional_param('author', '', PARAM_TEXT); // File author $source = optional_param('source', '', PARAM_RAW); // File to download +$sourcekey = optional_param('sourcekey', '', PARAM_RAW); // Used to verify the source. $itemid = optional_param('itemid', 0, PARAM_INT); // Itemid $page = optional_param('page', '', PARAM_RAW); // Page $maxbytes = optional_param('maxbytes', 0, PARAM_INT); // Maxbytes @@ -157,6 +158,16 @@ // allow external links in url element all the time $allowexternallink = ($allowexternallink || ($env == 'url')); + // Validate the sourcekey. + if (empty($sourcekey)) { + throw new moodle_exception('missingsourcekey', 'repository'); + } + + // Check that the sourcekey matches. + if (sha1($source . repository::get_secret_key() . sesskey()) !== $sourcekey) { + throw new moodle_exception('sourcekeymismatch', 'repository'); + } + $reference = $repo->get_file_reference($source); // Use link of the files