index.php (14182B)
1<?php 2 3$sites = array( 4 "home" => array ( "name" => "Home" ), 5 "login" => array ( "name" => "Login" ), 6 "register" => array ( "name" => "Register" ), 7 "files" => array ( "name" => "Files" ), 8 "users" => array ( "name" => "Users" ), 9 "report" => array ( "name" => "Contact" ), 10 "about" => array ( "name" => "About" ) 11); 12 13$db = null; 14$login = ""; 15 16$wrotehead = false; 17$head = <<<EOF 18<!DOCTYPE html> 19<html> 20<head> 21 <title>Catchbox</title> 22 <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> 23 <link rel="stylesheet" href="/static/style.css"> 24</head> 25<body> 26EOF; 27 28srand(time()); 29 30function load() { 31 global $db; 32 if ($db === null) { 33 /* https://phiresky.github.io/blog/2020/sqlite-performance-tuning/ */ 34 $db = new SQLite3("db.sqlite"); 35 $db->busyTimeout(15000); 36 $db->exec("PRAGMA journal_mode = WAL"); 37 $db->exec("PRAGMA synchronous = normal"); 38 $db->exec("PRAGMA temp_storage = memory"); 39 $db->exec("PRAGMA mmap_size = 30000000000"); 40 $db->exec("PRAGMA page_size = 32768"); 41 /* for ON DELETE CASCADE */ 42 $db->exec("PRAGMA foreign_keys = ON"); 43 } 44 return $db; 45} 46 47function writehead() { 48 global $head, $wrotehead; 49 if (!$wrotehead) { 50 echo $head; 51 } 52 $wrotehead = true; 53} 54 55function banner($msg) { 56 http_response_code(400); 57 writehead(); 58 echo "<div class=error>" . $msg . "</div>"; 59} 60 61function alphok($text) { 62 return preg_match("#^[a-zA-Z0-9\.\-_äöüÄÖÜ]*$#", $text); 63} 64 65function quit() { 66 global $db; 67 if ($db !== null) 68 $db->close(); 69 exit(); 70} 71 72function redirect($url) { 73 header("HTTP/1.1 301 Moved Permanently"); 74 header("Location: $url"); 75 quit(); 76} 77 78function serv_file($path) { 79 $path = realpath($path); 80 if ($path === false || strpos($path, "/service/files/") !== 0 81 && strpos($path, "/service/reports/") !== 0) { 82 header("HTTP/1.1 404 Not Found"); 83 quit(); 84 } 85 86 $mime = mime_content_type($path); 87 if ($mime !== false) { 88 header("Content-Type: " . $mime); 89 } 90 echo file_get_contents($path); 91 quit(); 92} 93 94function serv_post() { 95 global $db, $login; 96 if ($_POST["action"] == "register") { 97 if (!isset($_POST["username"]) || !isset($_POST["password"])) { 98 banner("Missing username / password"); 99 return "home"; 100 } 101 102 if (!alphok($_POST["username"]) || strlen($_POST["username"]) > 100) { 103 banner("Invalid username"); 104 return "home"; 105 } 106 107 if (strlen($_POST["password"]) > 100) { 108 banner("Invalid password"); 109 return "home"; 110 } 111 112 $db = load(); 113 $q = $db->prepare("SELECT user FROM users WHERE user = :user"); 114 $q->bindValue(":user", $_POST["username"]); 115 $res = $q->execute(); 116 if ($res !== false && $res->fetchArray() !== false) { 117 $q->close(); 118 banner("User already exists"); 119 return "home"; 120 } 121 $q->close(); 122 123 $auth = md5($_POST["username"] . $_POST["password"]); 124 $q = $db->prepare("INSERT INTO users (user, pass, creat, auth) " 125 . "VALUES (:user, :pass, :creat, :auth)"); 126 $q->bindValue(":user", $_POST["username"], SQLITE3_TEXT); 127 $q->bindValue(":pass", $_POST["password"], SQLITE3_TEXT); 128 $q->bindValue(":creat", time(), SQLITE3_INTEGER); 129 $q->bindValue(":auth", $auth, SQLITE3_TEXT); 130 $res = $q->execute(); 131 if ($res === false) { 132 $q->close(); 133 banner("Failed to insert user: " . $db->lastErrorMsg()); 134 return "home"; 135 } 136 $q->close(); 137 138 $login = $_POST["username"]; 139 setcookie("session", $auth); 140 141 return "files"; 142 } else if ($_POST["action"] === "login") { 143 if (!isset($_POST["username"]) || !isset($_POST["password"])) { 144 banner("Missing username / password"); 145 return "home"; 146 } 147 148 $db = load(); 149 $q = $db->prepare("SELECT auth FROM users WHERE user = :user AND pass = :pass"); 150 $q->bindValue(":user", $_POST["username"], SQLITE3_TEXT); 151 $q->bindValue(":pass", $_POST["password"], SQLITE3_TEXT); 152 $res = $q->execute(); 153 if ($res === false || ($row = $res->fetchArray()) === false) { 154 $q->close(); 155 banner("Invalid credentials"); 156 return "home"; 157 } 158 $auth = $row[0]; 159 $q->close(); 160 161 $login = $_POST["username"]; 162 setcookie("session", $auth); 163 164 return "files"; 165 } else if ($_POST["action"] === "upload") { 166 if (!isset($_COOKIE["session"])) { 167 banner("Not authenticated"); 168 return "files"; 169 } 170 171 if (!isset($_POST["filename"]) || !isset($_POST["content"])) { 172 banner("Missing content or filename"); 173 return "files"; 174 } 175 176 if (strlen($_POST["filename"]) > 100) { 177 banner("Invalid filename"); 178 return "files"; 179 } 180 181 if (strlen($_POST["content"]) > 1024) { 182 banner("File too large"); 183 return "files"; 184 } 185 186 $db = load(); 187 $q = $db->prepare("SELECT uid, user from users WHERE auth = :auth"); 188 $q->bindValue(":auth", $_COOKIE["session"], SQLITE3_TEXT); 189 $res = $q->execute(); 190 if ($res === false || ($row = $res->fetchArray()) === false) { 191 $q->close(); 192 banner("Invalid session"); 193 setcookie("session", "", 1); 194 return "files"; 195 } 196 $uid = $row[0]; 197 $user = $row[1]; 198 $login = $user; 199 $q->close(); 200 201 $parts = explode("/", $_POST["filename"]); 202 $filename = end($parts); 203 foreach ($parts as $part) { 204 if (strpos($part, "..") != false) { 205 banner("Invalid filename"); 206 return "files"; 207 } 208 } 209 210 $dir = md5($user . $filename . strval(rand())); 211 $dirpath = "files/" . $dir; 212 if (is_dir($dirpath) || mkdir($dirpath) === false) { 213 banner("File directory already exists"); 214 return "files"; 215 } 216 217 $filepath = $dirpath . "/" . $filename; 218 if (is_file($filepath)) { 219 banner("File already exists"); 220 return "files"; 221 } 222 223 $f = fopen($filepath, "w+"); 224 if ($f === false) { 225 banner("File create failed"); 226 return "files"; 227 } 228 fwrite($f, $_POST["content"]); 229 fclose($f); 230 231 $q = $db->prepare("INSERT INTO files (uid, file, dir, creat) " 232 . "VALUES (:uid, :file, :dir, :creat)"); 233 $q->bindValue(":uid", $uid, SQLITE3_INTEGER); 234 $q->bindValue(":file", $_POST["filename"], SQLITE3_TEXT); 235 $q->bindValue(":dir", $dir, SQLITE3_TEXT); 236 $q->bindValue(":creat", time(), SQLITE3_INTEGER); 237 $res = $q->execute(); 238 if ($res === false) { 239 $q->close(); 240 banner("Failed to insert file: " . $db->lastErrorMsg()); 241 return "files"; 242 } 243 $q->close(); 244 245 return "files"; 246 } else if ($_POST["action"] == "report") { 247 if (!isset($_COOKIE["session"])) { 248 banner("Not authenticated"); 249 return "files"; 250 } 251 252 if (!isset($_POST["content"])) { 253 banner("Missing content or filename"); 254 return "files"; 255 } 256 257 if (strlen($_POST["content"]) > 1024) { 258 banner("Report too long"); 259 return "files"; 260 } 261 262 $db = load(); 263 $q = $db->prepare("SELECT uid, user from users WHERE auth = :auth"); 264 $q->bindValue(":auth", $_COOKIE["session"], SQLITE3_TEXT); 265 $res = $q->execute(); 266 if ($res === false || ($row = $res->fetchArray()) === false) { 267 $q->close(); 268 banner("Invalid session"); 269 setcookie("session", "", 1); 270 return "report"; 271 } 272 $uid = $row[0]; 273 $user = $row[1]; 274 $q->close(); 275 276 $login = $user; 277 $file = md5($user); 278 279 $q = $db->prepare("INSERT INTO reports (uid, file, creat) " 280 . "VALUES (:uid, :file, :creat)"); 281 $q->bindValue(":uid", $uid, SQLITE3_INTEGER); 282 $q->bindValue(":file", $file, SQLITE3_TEXT); 283 $q->bindValue(":creat", time(), SQLITE3_INTEGER); 284 $res = $q->execute(); 285 if ($res === false) { 286 $q->close(); 287 banner("Failed to insert report: " . $db->lastErrorMsg()); 288 return "files"; 289 } 290 $q->close(); 291 292 $filepath = "reports/" . $file; 293 if (is_file($filepath)) { 294 banner("Report already exists"); 295 return "report"; 296 } 297 298 $f = fopen($filepath, "w+"); 299 if ($f === false) { 300 banner("Report create failed"); 301 return "files"; 302 } 303 fwrite($f, $_POST["content"]); 304 fclose($f); 305 306 return "report"; 307 } 308 309 return "home"; 310} 311 312function serv() { 313 global $db, $login; 314 if ($_SERVER["REQUEST_METHOD"] === "POST") { 315 $site = serv_post(); 316 } else if (isset($_GET["f"])) { 317 if (!isset($_COOKIE["session"])) { 318 banner("Not authenticated"); 319 return "files"; 320 } 321 322 $db = load(); 323 $q = $db->prepare("SELECT uid from users WHERE auth = :auth"); 324 $q->bindValue(":auth", $_COOKIE["session"], SQLITE3_TEXT); 325 $res = $q->execute(); 326 if ($res === false || ($row = $res->fetchArray()) === false) { 327 $q->close(); 328 banner("Invalid session"); 329 setcookie("session", "", 1); 330 return "files"; 331 } 332 $uid = $row[0]; 333 $q->close(); 334 335 $q = $db->prepare("SELECT dir, file from files " 336 . "WHERE uid = :uid and file = :file"); 337 $q->bindValue(":uid", $uid, SQLITE3_INTEGER); 338 $q->bindValue(":file", $_GET["f"], SQLITE3_TEXT); 339 $res = $q->execute(); 340 if ($res === false || ($row = $res->fetchArray()) === false) { 341 $q->close(); 342 banner("No such file"); 343 return "files"; 344 } 345 $path = "files/" . $row[0] . "/" . $row[1]; 346 $q->close(); 347 348 serv_file($path); 349 } else if (isset($_GET["r"])) { 350 if (!isset($_COOKIE["session"])) { 351 banner("Not authenticated"); 352 return "files"; 353 } 354 355 $db = load(); 356 $q = $db->prepare("SELECT file from reports WHERE " 357 . "uid = (SELECT uid FROM users WHERE auth = :auth)"); 358 $q->bindValue(":auth", $_COOKIE["session"], SQLITE3_TEXT); 359 $res = $q->execute(); 360 if ($res === false || ($row = $res->fetchArray()) === false) { 361 $q->close(); 362 banner("Invalid session"); 363 setcookie("session", "", 1); 364 return "files"; 365 } 366 $path = "reports/" . $row[0]; 367 $q->close(); 368 369 serv_file($path); 370 } else { 371 if (isset($_GET["q"])) 372 $site = $_GET['q']; 373 else 374 $site = "home"; 375 } 376 377 if ($site == "logout") { 378 setcookie("session", "", 1); 379 $login = ""; 380 return "home"; 381 } 382 383 return $site; 384} 385 386$site = serv(); 387 388if (isset($_COOKIE["session"]) && $login === "") { 389 $db = load(); 390 $q = $db->prepare("SELECT user FROM users WHERE auth = :auth"); 391 $q->bindValue(":auth", $_COOKIE["session"], SQLITE3_TEXT); 392 $res = $q->execute(); 393 if ($res === false || ($row = $res->fetchArray()) === false) { 394 $q->close(); 395 banner("Invalid session"); 396 setcookie("session", "", 1); 397 return $site; 398 } 399 $login = $row[0]; 400 $q->close(); 401} 402 403writehead(); 404?> 405 <div class="navbar"> 406 <img src="/static/logo.png"></img> 407 <ul> 408<?php 409 410foreach ($sites as $qname => $info) { 411 if ($site == $qname) { 412 echo '<li><a class="active" href="/?q=' . $qname . '">' . $info["name"] . '</a></li>'; 413 } else { 414 if ($login != "" && $qname != "login" && $qname != "register" 415 || $login == "" && $qname != "files" && $qname != "report") { 416 echo '<li><a href="/?q=' . $qname . '">' . $info["name"] . '</a></li>'; 417 } 418 } 419} 420 421?> 422 </ul> 423 </div> 424 <div class="main"> 425 <div class="login"> 426<?php 427 428if ($login != "") { 429 echo '<a href="/?q=logout">logged in (' . $login . ')</a>'; 430} else { 431 echo '<a href="/?q=login">log in</a>'; 432} 433 434?> 435 </div> 436<?php 437if ($site == "home") { 438 echo ' 439 <div class="text"> 440 <h1>Welcome to Catchbox™</h1> 441 <p>Host your files with us! Register now and get 5GB for free!¹</p> 442 <div> 443 <div class="footer"> 444 ¹ Terms and conditions apply. 445 </div>'; 446} else if ($site == "login") { 447 echo ' 448 <div class="text"> 449 <form action="index.php" method="post" class="login-form"> 450 <h2>Login:</h2> 451 <input class="txtinput" name="username" type="text" placeholder="username"></input> 452 <input class="txtinput" name="password" type="password" placeholder="password"></input> 453 <input type="hidden" name="action" value="login"> 454 <input type="submit"> 455 <a class=hint href=/?q=register>Need an account?</a> 456 </form> 457 <div>'; 458} else if ($site == "register") { 459 echo ' 460 <div class="text"> 461 <form action="index.php" method="post" class="login-form"> 462 <h2>Register:</h2> 463 <input class="txtinput" name="username" type="text" placeholder="username"></input> 464 <input class="txtinput" name="password" type="password" placeholder="password"></input> 465 <input type="hidden" name="action" value="register"> 466 <input type="submit"> 467 </form> 468 <div>'; 469} else if ($site == "files") { 470 echo ' 471 <div class="text"> 472 <h2>Your hosted files:</h2> 473 <ul class="mslist filelist">'; 474 $db = load(); 475 $q = $db->prepare("SELECT file, dir FROM files WHERE " 476 . "uid = (SELECT uid FROM users WHERE user = :user)"); 477 $q->bindValue(":user", $login, SQLITE3_TEXT); 478 $res = $q->execute(); 479 while (($row = $res->fetchArray())) { 480 $pub = "/uploads/" . $row[1] . "/" . $row[0]; 481 $priv = "/index.php?f=" . $row[0]; 482 echo ' 483 <li> 484 <p class="front"> 485 <a class="mfile" href="' . $priv . '">' . $row[0] . '</a> 486 </p> 487 <p class="back"> 488 <a class="textref" href="' . $pub . '">share</a> 489 </p> 490 </li>'; 491 } 492 $q->close(); 493 echo ' 494 </ul> 495 <form action="index.php" method="post" class="upload-form"> 496 <h2>Upload a file:</h2> 497 <input type=text name="filename" placeholder="name"></input><br> 498 <input type=text name="content" placeholder="content"></input><br> 499 <input type=hidden name="action" value="upload"> 500 <input type=submit> 501 </form> 502 <div>'; 503} else if ($site == "users") { 504 echo ' 505 <div class="text"> 506 <h2>Registered users:</h2> 507 <ul class="mslist userlist">'; 508 $db = load(); 509 $res = $db->query("SELECT user, creat FROM users ORDER BY creat DESC"); 510 while (($row = $res->fetchArray())) { 511 $date = date("Y-m-d H:i:s", $row[1]); 512 echo '<li><p class="front">' . $row[0] . '</p>'; 513 echo '<p class="back">' . $date . '</p></li>'; 514 } 515 echo ' 516 </ul> 517 <div>'; 518} else if ($site == "report") { 519 echo ' 520 <div class="text">'; 521 522 $db = load(); 523 $q = $db->prepare("SELECT file FROM reports WHERE " 524 . "uid = (SELECT uid FROM users WHERE user = :user)"); 525 $q->bindValue(":user", $login, SQLITE3_TEXT); 526 $res = $q->execute(); 527 if ($res === false || ($row = $res->fetchArray()) === false) { 528 echo' 529 <h2>We would love to hear from you!</h2> 530 <form action="index.php" method="post" class="upload-form"> 531 <h2>Submit feedback:</h2> 532 <input type=text name="content"></input><br> 533 <input type=hidden name="action" value="report"> 534 <input type=submit> 535 </form>'; 536 } else { 537 echo' 538 <h2>Thank you for your feedback.</h2> 539 You can view your feedback <a class=textref href="/?r">here</a>'; 540 } 541 $q->close(); 542 echo ' 543 <div>'; 544} else if ($site == "about") { 545 echo ' 546 <div class="text"> 547 <h1>We value our employees:</h1> 548 Become a member of our team today! 549 <div class="employee-pics"> 550 <img width="100%" src="/static/work.jpg"/> 551 <img width="100%" src="/static/work2.jpg"/> 552 </div> 553 </div> 554'; 555} 556?> 557 </div> 558 </body> 559</html> 560 561<?php 562 quit(); 563?>