Skip to content

Commit

Permalink
MDL-36754 core_files: Add a token version of pluginfile
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Aug 13, 2018
1 parent 6e44567 commit 4a74ab0
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 5 deletions.
95 changes: 94 additions & 1 deletion files/classes/privacy/provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
defined('MOODLE_INTERNAL') || die();

use core_privacy\local\metadata\collection;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;

/**
* Data provider class.
Expand All @@ -41,7 +43,10 @@
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\plugin_provider {
\core_privacy\local\request\subsystem\plugin_provider,

// We store a userkey for token-based file access.
\core_privacy\local\request\subsystem\provider {

/**
* Returns metadata.
Expand All @@ -65,7 +70,95 @@ public static function get_metadata(collection $collection) : collection {
'timemodified' => 'privacy:metadata:files:timemodified',
], 'privacy:metadata:files');

$collection->add_subsystem_link('core_userkey', [], 'privacy:metadata:core_userkey');

return $collection;
}

/**
* Get the list of contexts that contain user information for the specified user.
*
* This is currently just the user context.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid) : contextlist {
$sql = "SELECT ctx.id
FROM {user_private_key} k
JOIN {user} u ON k.userid = u.id
JOIN {context} ctx ON ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel
WHERE k.userid = :userid AND k.script = :script";
$params = [
'userid' => $userid,
'contextlevel' => CONTEXT_USER,
'script' => 'core_files',
];
$contextlist = new contextlist();
$contextlist->add_from_sql($sql, $params);

return $contextlist;
}

/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
// If the user has data, then only the CONTEXT_USER should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}

// Sanity check that context is at the user context level, then get the userid.
$context = reset($contexts);
if ($context->contextlevel !== CONTEXT_USER) {
return;
}

// Export associated userkeys.
$subcontext = [
get_string('files'),
];
\core_userkey\privacy\provider::export_userkeys($context, $subcontext, 'core_files');
}

/**
* Delete all use data which matches the specified deletion_criteria.
*
* @param context $context A user context.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
// Sanity check that context is at the user context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
return;
}

// Delete all the userkeys.
\core_userkey\privacy\provider::delete_userkeys('core_files', $context->instanceid);
}

/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
// If the user has data, then only the user context should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}

// Sanity check that context is at the user context level, then get the userid.
$context = reset($contexts);
if ($context->contextlevel !== CONTEXT_USER) {
return;
}

// Delete all the userkeys for core_files..
\core_userkey\privacy\provider::delete_userkeys('core_files', $context->instanceid);
}
}
1 change: 1 addition & 0 deletions lang/en/files.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@
$string['privacy:metadata:files:timecreated'] = 'The time when the file was created';
$string['privacy:metadata:files:timemodified'] = 'The time when the file was last modified';
$string['privacy:metadata:files:userid'] = 'The user who created the file';
$string['privacy:metadata:core_userkey'] = 'A private token is generated and stored. This token can be used to access Moodle files without requiring you to log in.';
7 changes: 5 additions & 2 deletions lib/moodlelib.php
Original file line number Diff line number Diff line change
Expand Up @@ -3112,9 +3112,10 @@ function validate_user_key($keyvalue, $script, $instance) {
* @uses PARAM_ALPHANUM
* @param string $script unique script identifier
* @param int $instance optional instance id
* @param string $keyvalue The key. If not supplied, this will be fetched from the current session.
* @return int Instance ID
*/
function require_user_key_login($script, $instance=null) {
function require_user_key_login($script, $instance = null, $keyvalue = null) {
global $DB;

if (!NO_MOODLE_COOKIES) {
Expand All @@ -3124,7 +3125,9 @@ function require_user_key_login($script, $instance=null) {
// Extra safety.
\core\session\manager::write_close();

$keyvalue = required_param('key', PARAM_ALPHANUM);
if (null === $keyvalue) {
$keyvalue = required_param('key', PARAM_ALPHANUM);
}

$key = validate_user_key($keyvalue, $script, $instance);

Expand Down
8 changes: 6 additions & 2 deletions pluginfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@
*/

// Disable moodle specific debug messages and any errors in output.
define('NO_DEBUG_DISPLAY', true);
if (!defined('NO_DEBUG_DISPLAY')) {
define('NO_DEBUG_DISPLAY', true);
}

require_once('config.php');
require_once('lib/filelib.php');

$relativepath = get_file_argument();
if (empty($relativepath)) {
$relativepath = get_file_argument();
}
$forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
$preview = optional_param('preview', null, PARAM_ALPHANUM);
// Offline means download the file from the repository and serve it, even if it was an external link.
Expand Down
44 changes: 44 additions & 0 deletions tokenpluginfile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Entry point for token-based access to pluginfile.php.
*
* @package core
* @copyright 2018 Andrew Nicols <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

// Disable the use of sessions/cookies - we recreate $USER for every call.
define('NO_MOODLE_COOKIES', true);

// Disable debugging for this script.
// It is typically used to display images.
define('NO_DEBUG_DISPLAY', true);

require_once('config.php');

$relativepath = get_file_argument();
$token = optional_param('token', '', PARAM_ALPHANUM);
if (0 == strpos($relativepath, '/token/')) {
$relativepath = ltrim($relativepath, '/');
$pathparts = explode('/', $relativepath, 2);
$token = $pathparts[0];
$relativepath = "/{$pathparts[1]}";
}

require_user_key_login('core_files', null, $token);
require_once('pluginfile.php');

0 comments on commit 4a74ab0

Please sign in to comment.