1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @file upload.attachments.php |
4
|
|
|
* @author Nils Laumaillé |
5
|
|
|
* @version 2.1.27 |
6
|
|
|
* @copyright (c) 2009-2017 Nils Laumaillé |
7
|
|
|
* @licensing GNU AFFERO GPL 3.0 |
8
|
|
|
* @link http://www.teampass.net |
9
|
|
|
* |
10
|
|
|
* This library is distributed in the hope that it will be useful, |
11
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
require_once('../SecureHandler.php'); |
16
|
|
|
session_start(); |
17
|
|
|
if ( |
18
|
|
|
!isset($_SESSION['CPM']) || $_SESSION['CPM'] != 1 || |
19
|
|
|
!isset($_SESSION['user_id']) || empty($_SESSION['user_id']) || |
20
|
|
|
!isset($_SESSION['key']) || empty($_SESSION['key']) |
21
|
|
|
) { |
22
|
|
|
die('Hacking attempt...'); |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
/* do checks */ |
26
|
|
|
require_once '../checks.php'; |
27
|
|
View Code Duplication |
if (!checkUser($_SESSION['user_id'], $_SESSION['key'], "items")) { |
28
|
|
|
$_SESSION['error']['code'] = ERR_NOT_ALLOWED; //not allowed page |
29
|
|
|
handleAttachmentError('Not allowed to ...', 110); |
30
|
|
|
exit(); |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
//check for session |
34
|
|
View Code Duplication |
if (isset($_POST['PHPSESSID'])) { |
35
|
|
|
session_id($_POST['PHPSESSID']); |
36
|
|
|
} elseif (isset($_GET['PHPSESSID'])) { |
37
|
|
|
session_id($_GET['PHPSESSID']); |
38
|
|
|
} else { |
39
|
|
|
handleAttachmentError('No Session was found.', 110); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
|
43
|
|
|
// Get parameters |
44
|
|
|
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0; |
45
|
|
|
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0; |
46
|
|
|
$fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : ''; |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
// token check |
50
|
|
|
if (!isset($_POST['user_token'])) { |
51
|
|
|
handleAttachmentError('No user token found.', 110); |
52
|
|
|
exit(); |
53
|
|
|
} else { |
54
|
|
|
//Connect to mysql server |
55
|
|
|
require_once '../../includes/config/settings.php'; |
56
|
|
|
require_once '../../includes/libraries/Database/Meekrodb/db.class.php'; |
57
|
|
|
DB::$host = $server; |
58
|
|
|
DB::$user = $user; |
59
|
|
|
DB::$password = $pass; |
60
|
|
|
DB::$dbName = $database; |
61
|
|
|
DB::$port = $port; |
62
|
|
|
DB::$encoding = $encoding; |
63
|
|
|
DB::$error_handler = true; |
64
|
|
|
$link = mysqli_connect($server, $user, $pass, $database, $port); |
65
|
|
|
$link->set_charset($encoding); |
66
|
|
|
|
67
|
|
|
// delete expired tokens |
68
|
|
|
DB::delete(prefix_table("tokens"), "end_timestamp < %i", time()); |
69
|
|
|
|
70
|
|
|
if (isset($_SESSION[$_POST['user_token']]) && ($chunk < $chunks - 1) && $_SESSION[$_POST['user_token']] >= 0) { |
71
|
|
|
// increase end_timestamp for token |
72
|
|
|
DB::update( |
73
|
|
|
prefix_table('tokens'), |
74
|
|
|
array( |
75
|
|
|
'end_timestamp' => time() + 10 |
76
|
|
|
), |
77
|
|
|
"user_id = %i AND token = %s", |
78
|
|
|
$_SESSION['user_id'], |
79
|
|
|
$_POST['user_token'] |
80
|
|
|
); |
81
|
|
|
} else { |
82
|
|
|
|
83
|
|
|
// create a session if several files to upload |
84
|
|
|
if (!isset($_SESSION[$_POST['user_token']]) || empty($_SESSION[$_POST['user_token']]) || $_SESSION[$_POST['user_token']] === 0) { |
85
|
|
|
$_SESSION[$_POST['user_token']] = $_POST['files_number']; |
86
|
|
|
} else if ($_SESSION[$_POST['user_token']] > 0) { |
87
|
|
|
// increase end_timestamp for token |
88
|
|
|
DB::update( |
89
|
|
|
prefix_table('tokens'), |
90
|
|
|
array( |
91
|
|
|
'end_timestamp' => time() + 30 |
92
|
|
|
), |
93
|
|
|
"user_id = %i AND token = %s", |
94
|
|
|
$_SESSION['user_id'], |
95
|
|
|
$_POST['user_token'] |
96
|
|
|
); |
97
|
|
|
// decrease counter of files to upload |
98
|
|
|
$_SESSION[$_POST['user_token']]--; |
99
|
|
|
} else { |
100
|
|
|
// no more files to upload, kill session |
101
|
|
|
unset($_SESSION[$_POST['user_token']]); |
102
|
|
|
handleAttachmentError('No user token found.', 110); |
103
|
|
|
die(); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
// check if token is expired |
107
|
|
|
$data = DB::queryFirstRow( |
108
|
|
|
"SELECT end_timestamp FROM ".prefix_table("tokens")." WHERE user_id = %i AND token = %s", |
109
|
|
|
$_SESSION['user_id'], |
110
|
|
|
$_POST['user_token'] |
111
|
|
|
); |
112
|
|
|
// clear user token |
113
|
|
|
if ($_SESSION[$_POST['user_token']] === 0) { |
114
|
|
|
DB::delete(prefix_table("tokens"), "user_id = %i AND token = %s", $_SESSION['user_id'], $_POST['user_token']); |
115
|
|
|
unset($_SESSION[$_POST['user_token']]); |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
if (time() <= $data['end_timestamp']) { |
|
|
|
|
119
|
|
|
// it is ok |
120
|
|
|
} else { |
121
|
|
|
// too old |
122
|
|
|
unset($_SESSION[$_POST['user_token']]); |
123
|
|
|
handleAttachmentError('User token expired.', 110); |
124
|
|
|
die(); |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
// HTTP headers for no cache etc |
130
|
|
|
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); |
131
|
|
|
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); |
132
|
|
|
header("Cache-Control: no-store, no-cache, must-revalidate"); |
133
|
|
|
header("Cache-Control: post-check=0, pre-check=0", false); |
134
|
|
|
header("Pragma: no-cache"); |
135
|
|
|
|
136
|
|
|
// load functions |
137
|
|
|
require_once $_SESSION['settings']['cpassman_dir'].'/sources/main.functions.php'; |
138
|
|
|
|
139
|
|
|
$targetDir = $_SESSION['settings']['path_to_upload_folder']; |
140
|
|
|
|
141
|
|
|
$cleanupTargetDir = true; // Remove old files |
142
|
|
|
$maxFileAge = 5 * 3600; // Temp file age in seconds |
143
|
|
|
$valid_chars_regex = 'A-Za-z0-9'; //accept only those characters |
144
|
|
|
$MAX_FILENAME_LENGTH = 260; |
145
|
|
|
$max_file_size_in_bytes = 2147483647; //2Go |
146
|
|
|
|
147
|
|
|
date_default_timezone_set($_POST['timezone']); |
148
|
|
|
|
149
|
|
|
// Check post_max_size |
150
|
|
|
$POST_MAX_SIZE = ini_get('post_max_size'); |
151
|
|
|
$unit = strtoupper(substr($POST_MAX_SIZE, -1)); |
152
|
|
|
$multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1))); |
153
|
|
|
if ((int) $_SERVER['CONTENT_LENGTH'] > $multiplier * (int) $POST_MAX_SIZE && $POST_MAX_SIZE) { |
154
|
|
|
handleAttachmentError('POST exceeded maximum allowed size.', 111); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
// Validate the file size (Warning: the largest files supported by this code is 2GB) |
158
|
|
|
$file_size = @filesize($_FILES['file']['tmp_name']); |
159
|
|
|
if (!$file_size || $file_size > $max_file_size_in_bytes) { |
160
|
|
|
handleAttachmentError('File exceeds the maximum allowed size', 120); |
161
|
|
|
} |
162
|
|
|
if ($file_size <= 0) { |
163
|
|
|
handleAttachmentError('File size outside allowed lower bound', 112); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
// Validate the upload |
167
|
|
|
if (!isset($_FILES['file'])) { |
168
|
|
|
handleAttachmentError('No upload found in $_FILES for Filedata', 121); |
169
|
|
|
} elseif (isset($_FILES['file']['error']) && $_FILES['file']['error'] != 0) { |
170
|
|
|
handleAttachmentError($uploadErrors[$_FILES['Filedata']['error']], 122); |
171
|
|
View Code Duplication |
} elseif (!isset($_FILES['file']['tmp_name']) || !@is_uploaded_file($_FILES['file']['tmp_name'])) { |
172
|
|
|
handleAttachmentError('Upload failed is_uploaded_file test.', 123); |
173
|
|
|
} elseif (!isset($_FILES['file']['name'])) { |
174
|
|
|
handleAttachmentError('File has no name.', 113); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
// Validate file name (for our purposes we'll just remove invalid characters) |
178
|
|
|
$file_name = preg_replace('[^'.$valid_chars_regex.']', '', strtolower(basename($_FILES['file']['name']))); |
179
|
|
View Code Duplication |
if (strlen($file_name) == 0 || strlen($file_name) > $MAX_FILENAME_LENGTH) { |
180
|
|
|
handleAttachmentError('Invalid file name: '.$file_name.'.', 114); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
// Validate file extension |
184
|
|
|
$ext = strtolower(getFileExtension($_REQUEST["name"])); |
185
|
|
View Code Duplication |
if (!in_array( |
186
|
|
|
$ext, |
187
|
|
|
explode( |
188
|
|
|
',', |
189
|
|
|
$_SESSION['settings']['upload_docext'].','.$_SESSION['settings']['upload_imagesext']. |
190
|
|
|
','.$_SESSION['settings']['upload_pkgext'].','.$_SESSION['settings']['upload_otherext'] |
191
|
|
|
) |
192
|
|
|
)) { |
193
|
|
|
handleAttachmentError('Invalid file extension.', 115); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
// 5 minutes execution time |
197
|
|
|
set_time_limit(5 * 60); |
198
|
|
|
|
199
|
|
|
// Clean the fileName for security reasons |
200
|
|
|
$fileName = preg_replace('/[^\w\._]+/', '_', $fileName); |
201
|
|
|
$fileName = preg_replace('[^'.$valid_chars_regex.']', '', strtolower(basename($fileName))); |
202
|
|
|
|
203
|
|
|
// Make sure the fileName is unique but only if chunking is disabled |
204
|
|
View Code Duplication |
if ($chunks < 2 && file_exists($targetDir.DIRECTORY_SEPARATOR.$fileName)) { |
205
|
|
|
$ext = strrpos($fileName, '.'); |
206
|
|
|
$fileNameA = substr($fileName, 0, $ext); |
207
|
|
|
$fileNameB = substr($fileName, $ext); |
208
|
|
|
|
209
|
|
|
$count = 1; |
210
|
|
|
while (file_exists($targetDir.DIRECTORY_SEPARATOR.$fileNameA.'_'.$count.$fileNameB)) { |
211
|
|
|
$count++; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
$fileName = $fileNameA.'_'.$count.$fileNameB; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
$filePath = $targetDir.DIRECTORY_SEPARATOR.$fileName; |
218
|
|
|
|
219
|
|
|
// Create target dir |
220
|
|
|
if (!file_exists($targetDir)) { |
221
|
|
|
try { |
222
|
|
|
mkdir($targetDir); |
|
|
|
|
223
|
|
|
} catch(Exception $e){ |
224
|
|
|
print_r($e); |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
// Remove old temp files |
229
|
|
View Code Duplication |
if ($cleanupTargetDir && is_dir($targetDir) && ($dir = opendir($targetDir))) { |
|
|
|
|
230
|
|
|
while (($file = readdir($dir)) !== false) { |
231
|
|
|
$tmpfilePath = $targetDir.DIRECTORY_SEPARATOR.$file; |
232
|
|
|
|
233
|
|
|
// Remove temp file if it is older than the max age and is not the current file |
234
|
|
|
if (preg_match('/\.part$/', $file) |
235
|
|
|
&& (filemtime($tmpfilePath) < time() - $maxFileAge) |
236
|
|
|
&& ($tmpfilePath != "{$filePath}.part") |
237
|
|
|
) { |
238
|
|
|
try { |
239
|
|
|
unlink($tmpfilePath); |
|
|
|
|
240
|
|
|
} catch(Exception $e){ |
241
|
|
|
print_r($e); |
242
|
|
|
} |
243
|
|
|
} |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
closedir($dir); |
247
|
|
|
} else { |
248
|
|
|
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}'); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
// Look for the content type header |
252
|
|
|
if (isset($_SERVER["HTTP_CONTENT_TYPE"])) { |
253
|
|
|
$contentType = $_SERVER["HTTP_CONTENT_TYPE"]; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
if (isset($_SERVER["CONTENT_TYPE"])) { |
257
|
|
|
$contentType = $_SERVER["CONTENT_TYPE"]; |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
// should we encrypt the attachment? |
261
|
|
|
if (isset($_SESSION['settings']['enable_attachment_encryption']) && $_SESSION['settings']['enable_attachment_encryption'] == 1) { |
262
|
|
|
// get key |
263
|
|
|
if (empty($ascii_key)) { |
264
|
|
|
$ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt"); |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
// prepare encryption of attachment |
268
|
|
|
$iv = substr(hash("md5", "iv".$ascii_key), 0, 8); |
269
|
|
|
$key = substr(hash("md5", "ssapmeat1".$ascii_key, true), 0, 24); |
270
|
|
|
$opts = array('iv'=>$iv, 'key'=>$key); |
271
|
|
|
|
272
|
|
|
$file_status = "encrypted"; |
273
|
|
|
} else { |
274
|
|
|
$file_status = "clear"; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
// Handle non multipart uploads older WebKit versions didn't support multipart in HTML5 |
278
|
|
|
if (strpos($contentType, "multipart") !== false) { |
279
|
|
|
if (isset($_FILES['file']['tmp_name']) && is_uploaded_file($_FILES['file']['tmp_name'])) { |
280
|
|
|
// Open temp file |
281
|
|
|
$out = fopen("{$filePath}.part", $chunk == 0 ? "wb" : "ab"); |
282
|
|
|
|
283
|
|
View Code Duplication |
if (isset($_SESSION['settings']['enable_attachment_encryption']) && $_SESSION['settings']['enable_attachment_encryption'] === "1") { |
284
|
|
|
// Add the Mcrypt stream filter |
285
|
|
|
stream_filter_append($out, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts); |
286
|
|
|
} |
287
|
|
|
|
288
|
|
View Code Duplication |
if ($out) { |
289
|
|
|
// Read binary input stream and append it to temp file |
290
|
|
|
$in = fopen($_FILES['file']['tmp_name'], "rb"); |
291
|
|
|
|
292
|
|
|
if ($in) { |
293
|
|
|
while ($buff = fread($in, 4096)) { |
294
|
|
|
fwrite($out, $buff); |
295
|
|
|
} |
296
|
|
|
} else { |
297
|
|
|
die( |
298
|
|
|
'{"jsonrpc" : "2.0", |
299
|
|
|
"error" : {"code": 101, "message": "Failed to open input stream."}, |
300
|
|
|
"id" : "id"}' |
301
|
|
|
); |
302
|
|
|
} |
303
|
|
|
fclose($in); |
304
|
|
|
fclose($out); |
305
|
|
|
try { |
306
|
|
|
unlink($_FILES['file']['tmp_name']); |
307
|
|
|
} catch(Exception $e){ |
308
|
|
|
print_r($e); |
309
|
|
|
} |
310
|
|
|
} else { |
311
|
|
|
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); |
312
|
|
|
} |
313
|
|
|
} else { |
314
|
|
|
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}'); |
315
|
|
|
} |
316
|
|
|
} else { |
317
|
|
|
// Open temp file |
318
|
|
|
$out = fopen("{$filePath}.part", $chunk == 0 ? "wb" : "ab"); |
319
|
|
|
|
320
|
|
View Code Duplication |
if (isset($_SESSION['settings']['enable_attachment_encryption']) && $_SESSION['settings']['enable_attachment_encryption'] === "1") { |
321
|
|
|
// Add the Mcrypt stream filter |
322
|
|
|
stream_filter_append($out, 'mcrypt.tripledes', STREAM_FILTER_WRITE, $opts); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
View Code Duplication |
if ($out) { |
326
|
|
|
// Read binary input stream and append it to temp file |
327
|
|
|
$in = fopen("php://input", "rb"); |
328
|
|
|
|
329
|
|
|
if ($in) { |
330
|
|
|
while ($buff = fread($in, 4096)) { |
331
|
|
|
fwrite($out, $buff); |
332
|
|
|
} |
333
|
|
|
} else { |
334
|
|
|
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}'); |
335
|
|
|
} |
336
|
|
|
fclose($in); |
337
|
|
|
fclose($out); |
338
|
|
|
} else { |
339
|
|
|
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}'); |
340
|
|
|
} |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
// Check if file has been uploaded |
344
|
|
|
if (!$chunks || $chunk == $chunks - 1) { |
345
|
|
|
// Strip the temp .part suffix off |
346
|
|
|
rename("{$filePath}.part", $filePath); |
|
|
|
|
347
|
|
|
} else { |
348
|
|
|
// continue uploading other chunks |
349
|
|
|
die(); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
// Get some variables |
353
|
|
|
$fileRandomId = md5($fileName.time()); |
354
|
|
|
rename($filePath, $targetDir.DIRECTORY_SEPARATOR.$fileRandomId); |
|
|
|
|
355
|
|
|
|
356
|
|
|
|
357
|
|
|
// Case ITEM ATTACHMENTS - Store to database |
358
|
|
|
if (isset($_POST['edit_item']) && $_POST['type_upload'] == "item_attachments") { |
359
|
|
|
DB::insert( |
360
|
|
|
$pre.'files', |
361
|
|
|
array( |
362
|
|
|
'id_item' => $_POST['itemId'], |
363
|
|
|
'name' => $fileName, |
364
|
|
|
'size' => $_FILES['file']['size'], |
365
|
|
|
'extension' => getFileExtension($fileName), |
366
|
|
|
'type' => $_FILES['file']['type'], |
367
|
|
|
'file' => $fileRandomId, |
368
|
|
|
'status' => $file_status |
369
|
|
|
) |
370
|
|
|
); |
371
|
|
|
// Log upload into databse only if "item edition" |
372
|
|
|
if (isset($_POST['edit_item']) && $_POST['edit_item'] === true) { |
373
|
|
|
DB::insert( |
374
|
|
|
$pre.'log_items', |
375
|
|
|
array( |
376
|
|
|
'id_item' => $_POST['itemId'], |
377
|
|
|
'date' => time(), |
378
|
|
|
'id_user' => $_SESSION['user_id'], |
379
|
|
|
'action' => 'at_modification', |
380
|
|
|
'raison' => 'at_add_file : '.addslashes($fileName) |
381
|
|
|
) |
382
|
|
|
); |
383
|
|
|
} |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
// Return JSON-RPC response |
387
|
|
|
die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}'); |
388
|
|
|
|
389
|
|
|
|
390
|
|
|
/* Handles the error output. */ |
391
|
|
|
function handleAttachmentError($message, $code) |
392
|
|
|
{ |
393
|
|
|
echo '{"jsonrpc" : "2.0", "error" : {"code": '.$code.', "message": "'.$message.'"}, "id" : "id"}'; |
|
|
|
|
394
|
|
|
exit(0); |
395
|
|
|
} |
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.