Would be possible for the BF Panel to have customizations where users could create files on the server, but the file links would be hidden in the DOM?
Maybe have a key:value system where a user requests a file to download and the request is passed back to the server and then the users is served the file?
I am using SureCart’s protected file system for some projects, but that plugin is more than smaller sites need.
Thanks for the consideration.
@Daniele
ChatGPT and I built this today for my own use case and it works fine, but:
- I’m not a security expert and i don’t want to introduce any vulnerabilities - i think i did an ok job mitigating that.
- its hard to manage this in the functions.php
- there has to be a better way
but here is my thought process around the feature request.
function handle_file_download() {
if (isset($_GET['fileKey'])) {
// Initialize the uploads directory and ensure the session is secure.
$uploadDirInfo = wp_upload_dir();
$baseDir = $uploadDirInfo['basedir'];
// Define a mapping of keys to files. The actual mapping should be secure and not guessable.
$fileMapping = array(
'hfdiwekxnmsuwlrlxkjhsm' => '/2024/02/Test.txt',
);
// Sanitize the fileKey to avoid directory traversal or other injection attacks.
$fileKey = preg_replace('/[^-a-zA-Z0-9_]/', '', $_GET['fileKey']);
// Immediately terminate if the fileKey is not valid or does not exist in the mapping array.
if (!array_key_exists($fileKey, $fileMapping)) {
die('Error: Unauthorized file access.');
}
$filePath = $baseDir . $fileMapping[$fileKey];
$resolvedPath = realpath($filePath);
// Verify the file exists, is not a directory, is within the base directory, and is a regular file.
if (!$resolvedPath || !file_exists($resolvedPath) || is_dir($resolvedPath) || strpos($resolvedPath, $baseDir) !== 0 || !is_file($resolvedPath)) {
die('Error: Invalid file request.');
}
$fileName = basename($resolvedPath);
// Set headers to serve the file download.
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . htmlspecialchars($fileName, ENT_QUOTES, 'UTF-8') . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($resolvedPath));
// Clear the output buffer and read the file to serve it.
ob_clean();
flush();
readfile($resolvedPath);
exit;
}
}
add_action(‘init’, ‘handle_file_download’);