Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Commit

Permalink
First try for secure upload
Browse files Browse the repository at this point in the history
  • Loading branch information
malcm committed Dec 3, 2015
1 parent d7bd4a4 commit 6c6e9d3
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 102 deletions.
1 change: 0 additions & 1 deletion index.php
Expand Up @@ -26,5 +26,4 @@

$id = required_param('id', PARAM_INT);

// Rest in peace old assignment!
redirect(new moodle_url('/'));
2 changes: 1 addition & 1 deletion mod_form.php
Expand Up @@ -44,7 +44,7 @@ public function definition() {
$PAGE->requires->jquery();
$PAGE->requires->js('/mod/teletask/vendor/plupload/plupload.full.min.js', true);
$PAGE->requires->js('/mod/teletask/vendor/uuid-js/uuid.js', true);
$PAGE->requires->js_init_call('M.mod_teletask.init');
$PAGE->requires->js_init_call('M.mod_teletask.init', array('course' => 2));

$mform =& $this->_form;

Expand Down
4 changes: 2 additions & 2 deletions module.js
Expand Up @@ -8,13 +8,13 @@ M.mod_teletask = M.mod_teletask || {};
*
* @param {Object} Y YUI instance
*/
M.mod_teletask.init = function(Y) {
M.mod_teletask.init = function(Y, course) {

var uploader = new plupload.Uploader({
runtimes : 'html5,flash,silverlight,html4',
browse_button : 'pickfiles', // you can pass an id...
container: document.getElementById('container'), // ... or DOM Element itself
url : '../mod/teletask/upload.php',
url : '../mod/teletask/upload.php?id='+course,
chunk_size: '200kb',
flash_swf_url : '../mod/teletask/upload/Moxie.swf',
silverlight_xap_url : '../mod/teletask/upload/Moxie.xap',
Expand Down
216 changes: 118 additions & 98 deletions upload.php
Expand Up @@ -29,114 +29,134 @@
*
*/

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

// Make sure file is not cached (as it happens for example on iOS devices).
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
$id = required_param('id', PARAM_INT);

/*
// Support CORS
header("Access-Control-Allow-Origin: *");
// other CORS headers if any...
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit; // finish preflight CORS requests here
if (!$cm = get_coursemodule_from_id('teletask', $id)) {
print_error(get_string('incorrectcoursemoduleid', 'teletask'));
}
*/

// 5 minutes execution time.
@set_time_limit(5 * 60);

// Uncomment this one to fake upload time.

// Settings.
$targetdir = 'uploads';
$cleanuptargetdir = true; // Remove old files.
$maxfileage = 5 * 3600; // Temp file age in seconds.


// Create target dir.
if (!file_exists($targetdir)) {
@mkdir($targetdir);
if (!$course = $DB->get_record('course', array('id' => $cm->course))) {
print_error(get_string('misconfigured', 'teletask'));
}

// Get a file name.
if (isset($_REQUEST["name"])) {
$filename = $_REQUEST["name"];
} else if (!empty($_FILES)) {
$filename = $_FILES["file"]["name"];
} else {
$filename = uniqid("file_");
}

// normalize file name to avoid directory traversal attacks
// always strip any paths
$filename = basename($filename);

$filepath = $targetdir . DIRECTORY_SEPARATOR . $filename;

// Chunking might be enabled.
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;


// Remove old temp files.
if ($cleanuptargetdir) {
if (!is_dir($targetdir) || !$dir = opendir($targetdir)) {
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
require_course_login($course, false, $cm);

$context = context_module::instance($cm->id);
if(has_capability('mod/teletask:addinstance', $context))
{


// Make sure file is not cached (as it happens for example on iOS devices).
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

/*
// Support CORS
header("Access-Control-Allow-Origin: *");
// other CORS headers if any...
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit; // finish preflight CORS requests here
}

while (($file = readdir($dir)) !== false) {
$tmpfilepath = $targetdir . DIRECTORY_SEPARATOR . $file;

// If temp file is current file proceed to the next.
if ($tmpfilepath == "{$filepath}.part") {
continue;
*/

// 5 minutes execution time.
@set_time_limit(5 * 60);

// Uncomment this one to fake upload time.

// Settings.
$targetdir = 'uploads';
$cleanuptargetdir = true; // Remove old files.
$maxfileage = 5 * 3600; // Temp file age in seconds.


// Create target dir.
if (!file_exists($targetdir)) {
@mkdir($targetdir);
}

// Get a file name.
if (isset($_REQUEST["name"])) {
$filename = $_REQUEST["name"];
} else if (!empty($_FILES)) {
$filename = $_FILES["file"]["name"];
} else {
$filename = uniqid("file_");
}

// normalize file name to avoid directory traversal attacks
// always strip any paths
$filename = basename($filename);

$filepath = $targetdir . DIRECTORY_SEPARATOR . $filename;

// Chunking might be enabled.
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0;


// Remove old temp files.
if ($cleanuptargetdir) {
if (!is_dir($targetdir) || !$dir = opendir($targetdir)) {
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
}

// Remove temp file if it is older than the max age and is not the current file.
if (preg_match('/\.part$/', $file) && (filemtime($tmpfilepath) < time() - $maxfileage)) {
@unlink($tmpfilepath);

while (($file = readdir($dir)) !== false) {
$tmpfilepath = $targetdir . DIRECTORY_SEPARATOR . $file;

// If temp file is current file proceed to the next.
if ($tmpfilepath == "{$filepath}.part") {
continue;
}

// Remove temp file if it is older than the max age and is not the current file.
if (preg_match('/\.part$/', $file) && (filemtime($tmpfilepath) < time() - $maxfileage)) {
@unlink($tmpfilepath);
}
}
closedir($dir);
}
closedir($dir);
}


// Open temp file.
if (!$out = @fopen("{$filepath}.part", $chunks ? "ab" : "wb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
}

if (!empty($_FILES)) {
if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');


// Open temp file.
if (!$out = @fopen("{$filepath}.part", $chunks ? "ab" : "wb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
}

// Read binary input stream and append it to temp file.
if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');

if (!empty($_FILES)) {
if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
}

// Read binary input stream and append it to temp file.
if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
}
} else {
if (!$in = @fopen("php://input", "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
}
}
} else {
if (!$in = @fopen("php://input", "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}

@fclose($out);
@fclose($in);

// Check if file has been uploaded.
if (!$chunks || $chunk == $chunks - 1) {
// Strip the temp .part suffix off.
rename("{$filepath}.part", $filepath);
}

// Return Success JSON-RPC response.
die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
} else {
print_error(get_string('misconfigured', 'teletask'));
}

while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}

@fclose($out);
@fclose($in);

// Check if file has been uploaded.
if (!$chunks || $chunk == $chunks - 1) {
// Strip the temp .part suffix off.
rename("{$filepath}.part", $filepath);
}

// Return Success JSON-RPC response.
die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');

0 comments on commit 6c6e9d3

Please sign in to comment.