scratch – Diff between revs 103 and 125

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