scratch – Blame information for rev 94

Subversion Repositories:
Rev:
Rev Author Line No. Line
7 office 1 <?php
2  
3 ###########################################################################
4 ## Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 ##
5 ###########################################################################
6  
66 office 7 require_once('php/pseudocrypt.php');
8 require_once('php/functions.php');
87 office 9 require_once('vendor/autoload.php');
7 office 10  
67 office 11 ### Load configuration.
12 $config = spyc_load_file('config.yaml');
13  
52 office 14 #### POST -> upload / GET -> download
15 switch ($_SERVER['REQUEST_METHOD']) {
16 case 'POST':
93 office 17 #### Script restrictions.
18 if(
19 (
94 office 20 !isset($_SERVER['HTTP_X_REQUESTED_WITH']) or
21 empty($_SERVER['HTTP_X_REQUESTED_WITH']) or
93 office 22 strtoupper($_SERVER['HTTP_X_REQUESTED_WITH']) != 'XMLHTTPREQUEST'
23 )
94 office 24 or
93 office 25 (
26 (
94 office 27 !isset($_SERVER['HTTP_REFERER']) or
93 office 28 empty($_SERVER['HTTP_REFERER'])
29 )
94 office 30 and
93 office 31 (
94 office 32 strtoupper($_SERVER['HTTP_REFERER']) != strtoupper($config['URL_PATH'].'FILE.HTML') or
93 office 33 strtoupper($_SERVER['HTTP_REFERER']) != strtoupper($config['URL_PATH'].'TEXT.HTML')
34 )
35 )
36 )
37 {
38 http_response_code(403);
39 die('Forbidden.');
40 }
52 office 41 #### Retrieve uploaded file.
42 if (!empty($_FILES['file']) and
43 is_uploaded_file($_FILES['file']['tmp_name'])) {
67 office 44 if($_FILES['file']['size'] > $config['ALLOWED_ASSET_SIZE'] * 1048576) {
81 office 45 http_response_code(403);
46 die('File size exceeds '.$config['ALLOWED_ASSET_SIZE'].'MiB.');
57 office 47 }
52 office 48 # Regular multipart/form-data upload.
49 $name = $_FILES['file']['name'];
57 office 50 $data = atomized_get_contents($_FILES['file']['tmp_name']);
52 office 51 } else {
67 office 52 if((int)get_file_size("php://input") > $config['ALLOWED_ASSET_SIZE'] * 1048576) {
81 office 53 http_response_code(403);
54 die('File size exceeds '.$config['ALLOWED_ASSET_SIZE'].'MiB.');
57 office 55 }
52 office 56 # Raw POST data.
57 $name = urldecode(@$_SERVER['HTTP_X_FILE_NAME']);
57 office 58 $data = atomized_get_contents("php://input");
52 office 59 }
7 office 60  
52 office 61 #### Grab the file extension.
62 $fileExtension = pathinfo($name, PATHINFO_EXTENSION);
11 office 63  
52 office 64 #### If the extension is not allowed then change it to a text extension.
65 if (!isset($fileExtension) ||
66 !in_array(strtoupper($fileExtension),
67 office 67 array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS']))) {
81 office 68 http_response_code(403);
69 die('File extension not allowed.');
52 office 70 }
14 office 71  
52 office 72 #### Hash filename.
73 $file = strtolower(
74 PseudoCrypt::hash(
75 preg_replace(
76 '/\D/',
77 '',
78 hash(
79 'sha512',
80 $data
81 )
82 ),
67 office 83 $config['ASSET_HASH_SIZE']
7 office 84 )
52 office 85 );
14 office 86  
52 office 87 #### Build the user path.
88 $userPath = join(
89 DIRECTORY_SEPARATOR,
90 array(
67 office 91 $config['STORE_FOLDER'],
52 office 92 $file
93 )
94 );
11 office 95  
52 office 96 #### Check for path traversals
97 $pathPart = pathinfo($userPath.'.'.$fileExtension);
98 if (strcasecmp(
67 office 99 realpath($pathPart['dirname']), realpath($config['STORE_FOLDER'])) != 0) {
81 office 100 http_response_code(500);
101 die('Internal server error.');
52 office 102 }
7 office 103  
52 office 104 #### Store the file.
81 office 105 $timestamp = atomized_put_contents($userPath.'.'.$fileExtension, $data);
14 office 106  
90 office 107 ### Hook for various file extensions.
108 $opengraph = FALSE;
109 switch(strtoupper($fileExtension)) {
110 case 'GIF':
111 $opengraph = TRUE;
112 break;
113 }
114  
52 office 115 ### Return the URL to the file.
116 header('Content-Type: text/plain; charset=utf-8');
81 office 117 echo json_encode(
118 array(
119 "hash" => $file,
90 office 120 "timestamp" => $timestamp,
121 "opengraph" => $opengraph
81 office 122 )
123 );
52 office 124 break;
125 case 'GET':
83 office 126 ### Tell browser not to cache files.
127 header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
128 header("Cache-Control: post-check=0, pre-check=0", false);
129 header("Pragma: no-cache");
130  
52 office 131 ### If no file has been specified for download then return.
81 office 132 if (!isset($_GET['hash']) or empty($_GET['hash'])) {
133 http_response_code(404);
134 die('File not found.');
52 office 135 }
136  
53 office 137 ### Find the requested file.
52 office 138 $file = array_shift(
139 preg_grep(
81 office 140 '/'.$_GET['hash'].'/',
67 office 141 scandir($config['STORE_FOLDER'])
52 office 142 )
143 );
144  
81 office 145 if (!isset($file) or empty($file)) {
146 http_response_code(404);
147 die('File not found.');
148 }
53 office 149  
150 ### Check the path for path traversals.
151 $fileExtension = pathinfo($file, PATHINFO_EXTENSION);
52 office 152  
53 office 153 #### If the extension is not allowed then return.
154 if (!isset($fileExtension) ||
155 !in_array(strtoupper($fileExtension),
67 office 156 array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS']))) {
81 office 157 http_response_code(403);
158 die('File extension not allowed.');
52 office 159 }
53 office 160  
161 #### Build the user path.
162 $userPath = join(
163 DIRECTORY_SEPARATOR,
164 array(
67 office 165 $config['STORE_FOLDER'],
53 office 166 $file
167 )
168 );
52 office 169  
53 office 170 #### Check for path traversals
171 $pathPart = pathinfo($userPath);
172 if (strcasecmp(
67 office 173 realpath($pathPart['dirname']), realpath($config['STORE_FOLDER'])) != 0) {
81 office 174 http_response_code(500);
175 die('Internal server error.');
53 office 176 }
177  
83 office 178 ### Hook for various file extensions.
53 office 179 switch(strtoupper($fileExtension)) {
180 case "HTML":
181 case "HTM":
182 header('Content-type: text/html');
183 break;
184 break;
83 office 185 case "URL":
91 office 186 if(preg_match(
187 "/URL=(https?:\/\/[\-_\.\+!\*'\(\),a-zA-Z0-9]+:?[0-9]{0,5}\/.*?)\n/",
188 file_get_contents($userPath), $matches)) {
83 office 189 header('Location: '.$matches[1]);
190 return;
191 }
192 break;
53 office 193 default:
194 ### Open MIME info database and send the content type.
195 $finfo = finfo_open(FILEINFO_MIME_TYPE);
196 if (!$finfo) {
81 office 197 http_response_code(500);
198 die('Internal server error.');
53 office 199 }
200 header('Content-type: '.finfo_file($finfo, $userPath));
201 finfo_close($finfo);
202 break;
203 }
204  
52 office 205 ### Send the file along with the inline content disposition.
53 office 206 header('Content-length: '.(int)get_file_size($userPath));
207 header('Content-Disposition: inline; filename="' . basename($userPath) . '"');
208 header('Content-Transfer-Encoding: binary');
209 header('X-Sendfile: '.$userPath);
52 office 210 break;
211 }