diff options
| -rw-r--r-- | lib/file.php | 93 | ||||
| -rw-r--r-- | public/index.php | 15 | ||||
| -rw-r--r-- | public/upload.php | 12 |
3 files changed, 113 insertions, 7 deletions
diff --git a/lib/file.php b/lib/file.php index ebfc009..65a2abe 100644 --- a/lib/file.php +++ b/lib/file.php @@ -150,4 +150,95 @@ function remove_video_letterbox(string $input_path, string $output_path) exec("ffmpeg -nostdin -i $input_path -vf $area -c:a copy $output_path 2>&1", $output, $code); return $code == 0; -}
\ No newline at end of file +} + +function parse_zip_web_archive(string $input_path, string $output_path) +{ + $allowed_extensions = [ + "html", + "js", + "css", + "png", + "jpg", + "jpeg", + "gif", + "mp3", + "ogg", + "wasm", + "atlas", + "skin", + "txt", + "fnt", + "json", + "glb", + "glsl", + "map", + "teavmdbg", + "xml", + "ds_store", + ]; + $max_total_uncompressed = 128 * 1024 * 1024; + $max_file_size = 32 * 1024 * 1024; + + $zip = new ZipArchive(); + if ($zip->open($input_path) !== true) { + throw new RuntimeException("Invalid ZIP"); + } + + $is_webapp = false; + for ($i = 0; $i < $zip->numFiles; $i++) { + $stat = $zip->statIndex($i); + $is_webapp = $stat["name"] == "index.html"; + if ($is_webapp) { + break; + } + } + + if (!$is_webapp) { + $zip->close(); + return $is_webapp; + } + + $total_uncompressed = 0; + for ($i = 0; $i < $zip->numFiles; $i++) { + $stat = $zip->statIndex($i); + $path = $stat["name"]; + if (strpos($path, "..") !== false) { + throw new RuntimeException("Invalid file path"); + } + + if ( + strpos($path, "__MACOSX/") === 0 || + (basename($path)[0] === "." && + strstr(basename($path), 0, 2) === "._") + ) { + continue; + } + + $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + error_log($ext); + if (!in_array($ext, $allowed_extensions) && $stat["size"] > 0) { + throw new RuntimeException( + "Forbidden file type in the archive: $path", + ); + } + + $total_uncompressed += $stat["size"]; + if ( + $total_uncompressed > $max_total_uncompressed || + $stat["size"] > $max_file_size + ) { + throw new RuntimeException("ZIP too large when uncompressed"); + } + } + + mkdir($output_path, 0755, true); + if (!$zip->extractTo($output_path)) { + rmdir($output_path); + throw new RuntimeException("ZIP extraction failed"); + } + + $zip->close(); + + return $is_webapp; +} diff --git a/public/index.php b/public/index.php index e4542d8..9226066 100644 --- a/public/index.php +++ b/public/index.php @@ -83,9 +83,8 @@ if (FILE_CATALOG_FANCY_VIEW && $file_id) { '); $stmt->execute([$file_id, $file_ext]); $file = $stmt->fetch(PDO::FETCH_ASSOC) ?: null; - $file_exists = is_file(FILE_UPLOAD_DIRECTORY . "/$file_id.$file_ext"); - if (!$file || !$file_exists) { + if (!$file) { http_response_code(404); exit(); } @@ -100,7 +99,6 @@ if (FILE_CATALOG_FANCY_VIEW && $file_id) { $_SESSION['viewed_file_ids'] = $viewed_file_ids; if ( - $file_exists && isset($file['expires_at']) && ( ($file['expires_at'] == $file['uploaded_at'] && $file['views'] > 1) || @@ -223,9 +221,7 @@ $privacy_exists = is_file($_SERVER['DOCUMENT_ROOT'] . '/static/PRIVACY.txt'); <p>Reason: <b><?= $file['ban_reason'] ?></b></p> <?php endif; ?> </section> - <?php endif; ?> - - <?php if ($file_exists): ?> + <?php else: ?> <div class="row grow justify-center"> <section class="file-preview-wrapper" <?= isset($file['width']) ? ('style="max-width:' . max($file['width'], 256) . 'px;"') : '' ?>> <section class="box"> @@ -281,6 +277,13 @@ $privacy_exists = is_file($_SERVER['DOCUMENT_ROOT'] . '/static/PRIVACY.txt'); <audio controls autoplay> <source src="<?= $file['full_url'] ?>" type="<?= $file['mime'] ?>"> </audio> + <?php elseif (HTML_IFRAME_ENABLE && $file["extension"] === "html" && file_exists(sprintf("%s/%s/index.html", FILE_UPLOAD_DIRECTORY, $file["id"]))): ?> + <iframe src="<?= sprintf("%s/%s/index.html", FILE_UPLOAD_DIRECTORY_PREFIX, $file["id"]) ?>" + width="800" height="600" frameborder="0"></iframe> + <?php elseif (HTML_IFRAME_ENABLE && $file["extension"] === "html"): ?> + <iframe + src="<?= sprintf("%s/%s.%s", FILE_UPLOAD_DIRECTORY_PREFIX, $file["id"], $file["extension"]) ?>" + width="800" height="600" frameborder="0"></iframe> <?php elseif (str_starts_with($file['mime'], 'text/')): ?> <pre><?= file_get_contents(FILE_UPLOAD_DIRECTORY . "/{$file['id']}.{$file['extension']}") ?></pre> <?php elseif ($file['mime'] == 'application/x-shockwave-flash' && !empty(RUFFLE_DRIVER_PATH)): ?> diff --git a/public/upload.php b/public/upload.php index bfa1990..6eda3c6 100644 --- a/public/upload.php +++ b/public/upload.php @@ -214,6 +214,18 @@ try { unlink($input_path); } + if ( + ZIPWEBAPP_ENABLE && + $file_data["extension"] === "zip" && + parse_zip_web_archive( + $file_path, + sprintf("%s/%s", FILE_UPLOAD_DIRECTORY, $file_id), + ) + ) { + $file_data["extension"] = "html"; + $file_data["mime"] = "text/html"; + } + $file_data['size'] = filesize($file_path); if (FILE_THUMBNAILS && !is_dir(FILE_THUMBNAIL_DIRECTORY) && !mkdir(FILE_THUMBNAIL_DIRECTORY, 0777, true)) { |
