initial commit
This commit is contained in:
118
README.md
118
README.md
@@ -1 +1,117 @@
|
||||
# uploader
|
||||
# File Uploader
|
||||
|
||||
A simple file uploader application that allows authenticated users to upload, list, and delete files.
|
||||
The application uses PHP and a Python authentication service running on Apache2.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Apache2, configured, up and running
|
||||
- PHP 8.1 or higher
|
||||
- Python 3
|
||||
- Required PHP extensions: `php-json`, `php-curl`
|
||||
- PAM authentication for Python
|
||||
|
||||
## Installation
|
||||
|
||||
For simplicity, I'll use my current Ubuntu instance user name, you should replace by yours.
|
||||
|
||||
### Clone or download this repository
|
||||
|
||||
```
|
||||
git clone https://github.com/yourusername/uploader.git
|
||||
cd uploader
|
||||
```
|
||||
|
||||
### Install Python prerequisites
|
||||
|
||||
```
|
||||
pip install flask pam
|
||||
```
|
||||
|
||||
### Create Python authentication service
|
||||
(note: **port 7000** is used; if you need to change port number, make needful changes in the **app.py** and php scripts - search for '7000')
|
||||
|
||||
```
|
||||
sudo nano /etc/systemd/system/flaskapp.service
|
||||
```
|
||||
|
||||
Add the following content to this file (but replace **User**, **WorkingDirectory** and **ExecStart**):
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Flask Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=ubuntu
|
||||
WorkingDirectory=/home/ubuntu/uploader
|
||||
ExecStart=/usr/bin/python3 /home/ubuntu/uploader/app.py
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### Enable and start the service:
|
||||
```
|
||||
sudo systemctl enable flaskapp
|
||||
sudo systemctl start flaskapp
|
||||
sudo systemctl status flaskapp.service
|
||||
```
|
||||
|
||||
### Configure PHP
|
||||
|
||||
Ensure the following PHP settings are in your **php.ini**:
|
||||
```
|
||||
log_errors = On
|
||||
error_log = /var/log/php_errors.log
|
||||
```
|
||||
|
||||
Also check for max upload file/post size limits in **php.ini** (adjust to your needs, like 10G):
|
||||
```
|
||||
upload_max_filesize = 10M
|
||||
post_max_size = 10M
|
||||
```
|
||||
|
||||
### Create the upload directory and set the necessary permissions:
|
||||
|
||||
```
|
||||
sudo mkdir -p /var/www/html/upload
|
||||
sudo chown -R www-data:www-data /var/www/html/upload
|
||||
sudo chmod -R 755 /var/www/html/upload
|
||||
```
|
||||
|
||||
### Create a limited user for uploading files
|
||||
(please note, I don't recommend you to use your actual ssh-enabled user account):
|
||||
|
||||
```
|
||||
sudo useradd -M -d /var/www/html/upload -s /usr/sbin/nologin uploader
|
||||
sudo passwd uploader
|
||||
sudo chown -R uploader:www-data /var/www/html/upload
|
||||
```
|
||||
|
||||
### Create application directory at webroot (or configure app/site):
|
||||
(note: with my Apache configuration, I just need to create a subdirectory)
|
||||
```
|
||||
sudo mkdir -p /var/www/html/uploader
|
||||
```
|
||||
|
||||
### Copy all files to the folder created above:
|
||||
```
|
||||
sudo cp -r * /var/www/html/uploader
|
||||
```
|
||||
|
||||
### Restart Apache to apply changes:
|
||||
|
||||
```
|
||||
sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
## Usage
|
||||
Open your web browser and navigate to https://yourserveraddress/uploader
|
||||
|
||||
Enter your username and password to authenticate.
|
||||
|
||||
Choose a file to upload and click the "Upload" button.
|
||||
|
||||
The uploaded files will be listed on the page, and you can delete them using the "Delete" button.
|
||||
|
||||
25
app.py
Normal file
25
app.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from flask import Flask, request, jsonify
|
||||
import subprocess
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def authenticate(username, password):
|
||||
command = f"echo {password} | su -c 'whoami' {username}"
|
||||
try:
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, check=True)
|
||||
return result.stdout.strip() == username
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
@app.route('/auth', methods=['POST'])
|
||||
def auth():
|
||||
data = request.json
|
||||
username = data.get('username')
|
||||
password = data.get('password')
|
||||
if authenticate(username, password):
|
||||
return jsonify({"authenticated": True}), 200
|
||||
else:
|
||||
return jsonify({"authenticated": False}), 401
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=7000)
|
||||
42
auth.js
Normal file
42
auth.js
Normal file
@@ -0,0 +1,42 @@
|
||||
let authCredentials = { username: '', password: '' };
|
||||
|
||||
async function authenticateUser(username, password) {
|
||||
const response = await fetch('auth.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
const result = await response.json();
|
||||
return result.authenticated;
|
||||
}
|
||||
|
||||
function checkAuthentication() {
|
||||
if (authCredentials.username && authCredentials.password) {
|
||||
document.getElementById('loginForm').style.display = 'none';
|
||||
document.getElementById('uploadForm').style.display = 'block';
|
||||
loadFileList();
|
||||
} else {
|
||||
document.getElementById('loginForm').style.display = 'block';
|
||||
document.getElementById('uploadForm').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('authForm').addEventListener('submit', async function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const username = document.getElementById('loginUsername').value;
|
||||
const password = document.getElementById('loginPassword').value;
|
||||
|
||||
const isAuthenticated = await authenticateUser(username, password);
|
||||
|
||||
if (isAuthenticated) {
|
||||
authCredentials = { username, password };
|
||||
checkAuthentication();
|
||||
} else {
|
||||
document.getElementById('statusMessage').innerHTML = 'Incorrect username or password!';
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', checkAuthentication);
|
||||
35
auth.php
Normal file
35
auth.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
if (session_status() == PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$username = $data['username'];
|
||||
$password = $data['password'];
|
||||
|
||||
function authenticate($username, $password) {
|
||||
$url = 'http://localhost:7000/auth';
|
||||
$data = json_encode(array("username" => $username, "password" => $password));
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'header' => "Content-Type: application/json\r\n",
|
||||
'method' => 'POST',
|
||||
'content' => $data,
|
||||
),
|
||||
);
|
||||
$context = stream_context_create($options);
|
||||
$result = file_get_contents($url, false, $context);
|
||||
$response = json_decode($result, true);
|
||||
return $response['authenticated'];
|
||||
}
|
||||
|
||||
$isAuthenticated = authenticate($username, $password);
|
||||
|
||||
if ($isAuthenticated) {
|
||||
$_SESSION['authenticated'] = true;
|
||||
echo json_encode(['authenticated' => true]);
|
||||
} else {
|
||||
$_SESSION['authenticated'] = false;
|
||||
echo json_encode(['authenticated' => false]);
|
||||
}
|
||||
?>
|
||||
8
config.php
Normal file
8
config.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
// config.php
|
||||
define('UPLOAD_DIR', '/var/www/html/upload/');
|
||||
define('BASE_URL', 'https://yoursite.com/upload/');
|
||||
define('TIMEZONE', 'America/New_York');
|
||||
define('DATE_TIME_FORMAT', 'm/d/y H:i');
|
||||
date_default_timezone_set(TIMEZONE);
|
||||
?>
|
||||
70
displayFileList.js
Normal file
70
displayFileList.js
Normal file
@@ -0,0 +1,70 @@
|
||||
let sortDirection = {};
|
||||
let sortFunctions = {
|
||||
'File Name': (a, b) => a.name.localeCompare(b.name),
|
||||
'File Size': (a, b) => a.sizeBytes - b.sizeBytes,
|
||||
'File Time': (a, b) => new Date(a.modified) - new Date(b.modified),
|
||||
'Upload Time': (a, b) => new Date(a.uploaded) - new Date(b.uploaded)
|
||||
};
|
||||
|
||||
function displayFileList(fileList) {
|
||||
const fileListContainer = document.getElementById('fileList');
|
||||
fileListContainer.innerHTML = '';
|
||||
|
||||
const table = document.createElement('table');
|
||||
const headerRow = table.insertRow();
|
||||
|
||||
['File Name', 'File Size', 'File Time', 'Upload Time', '', ''].forEach(headerText => {
|
||||
const th = document.createElement('th');
|
||||
if (headerText && headerText !== '') {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = headerText;
|
||||
button.onclick = () => sortTable(headerText, fileList);
|
||||
button.style.background = 'none';
|
||||
button.style.border = 'none';
|
||||
button.style.cursor = 'pointer';
|
||||
th.appendChild(button);
|
||||
} else {
|
||||
th.textContent = headerText;
|
||||
}
|
||||
headerRow.appendChild(th);
|
||||
});
|
||||
|
||||
fileList.forEach(file => {
|
||||
const row = table.insertRow();
|
||||
row.insertCell().textContent = file.name;
|
||||
row.insertCell().textContent = file.size;
|
||||
row.insertCell().textContent = file.modified;
|
||||
row.insertCell().textContent = file.uploaded;
|
||||
|
||||
const linkCell = row.insertCell();
|
||||
const link = document.createElement('a');
|
||||
link.href = file.url;
|
||||
link.textContent = 'Download';
|
||||
linkCell.appendChild(link);
|
||||
|
||||
const deleteCell = row.insertCell();
|
||||
const deleteButton = document.createElement('button');
|
||||
deleteButton.textContent = 'Delete';
|
||||
deleteButton.className = 'btn btn-delete';
|
||||
deleteButton.onclick = () => deleteFile(file.name);
|
||||
deleteCell.appendChild(deleteButton);
|
||||
});
|
||||
|
||||
fileListContainer.appendChild(table);
|
||||
}
|
||||
|
||||
function sortTable(column, fileList) {
|
||||
if (!sortDirection[column]) {
|
||||
sortDirection[column] = 'asc';
|
||||
} else {
|
||||
sortDirection[column] = sortDirection[column] === 'asc' ? 'desc' : 'asc';
|
||||
}
|
||||
|
||||
fileList.sort(sortFunctions[column]);
|
||||
|
||||
if (sortDirection[column] === 'desc') {
|
||||
fileList.reverse();
|
||||
}
|
||||
|
||||
displayFileList(fileList);
|
||||
}
|
||||
69
file_list.php
Normal file
69
file_list.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
function authenticate($username, $password) {
|
||||
$url = 'http://localhost:7000/auth';
|
||||
$data = json_encode(array("username" => $username, "password" => $password));
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'header' => "Content-Type: application/json\r\n",
|
||||
'method' => 'POST',
|
||||
'content' => $data,
|
||||
),
|
||||
);
|
||||
$context = stream_context_create($options);
|
||||
$result = file_get_contents($url, false, $context);
|
||||
$response = json_decode($result, true);
|
||||
return $response['authenticated'];
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$username = $data['username'];
|
||||
$password = $data['password'];
|
||||
$deleteFile = isset($data['delete']) ? basename($data['delete']) : null;
|
||||
|
||||
if (!authenticate($username, $password)) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($deleteFile) {
|
||||
$filePath = UPLOAD_DIR . $deleteFile;
|
||||
if (file_exists($filePath)) {
|
||||
unlink($filePath);
|
||||
echo json_encode(['success' => 'File deleted']);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'File not found']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
$files = array_diff(scandir(UPLOAD_DIR), array('.', '..'));
|
||||
|
||||
$fileList = [];
|
||||
foreach ($files as $file) {
|
||||
$filePath = UPLOAD_DIR . $file;
|
||||
$fileSizeBytes = filesize($filePath);
|
||||
$fileDate = date(DATE_TIME_FORMAT, filemtime($filePath));
|
||||
$uploadDate = date(DATE_TIME_FORMAT, filectime($filePath));
|
||||
$fileSizeFormatted = ($fileSizeBytes >= 1048576) ? sprintf("%.1f MB (%s bytes)", $fileSizeBytes / 1048576, number_format($fileSizeBytes)) : sprintf("%s bytes", number_format($fileSizeBytes));
|
||||
$fileUrl = BASE_URL . urlencode($file);
|
||||
$fileList[] = [
|
||||
'name' => htmlspecialchars($file, ENT_QUOTES, 'UTF-8'),
|
||||
'size' => $fileSizeFormatted,
|
||||
'sizeBytes' => $fileSizeBytes,
|
||||
'modified' => $fileDate,
|
||||
'uploaded' => $uploadDate,
|
||||
'url' => htmlspecialchars($fileUrl, ENT_QUOTES, 'UTF-8')
|
||||
];
|
||||
}
|
||||
|
||||
usort($fileList, function($a, $b) {
|
||||
return strtotime($b['uploaded']) - strtotime($a['uploaded']);
|
||||
});
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($fileList);
|
||||
?>
|
||||
158
index.html
Normal file
158
index.html
Normal file
@@ -0,0 +1,158 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>File Upload</title>
|
||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.container {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.btn-upload {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.btn-upload:disabled {
|
||||
background-color: gray;
|
||||
}
|
||||
.btn-choose-file {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.file-list {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.progress {
|
||||
margin-top: 10px;
|
||||
height: 20px; /* Narrow progress bar */
|
||||
width: 100%;
|
||||
}
|
||||
.progress-bar {
|
||||
height: 100%; /* Fill the entire height */
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table, th, td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
th, td {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5em; /* Smaller font size */
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 5px; /* Reduce vertical space between form groups */
|
||||
}
|
||||
label {
|
||||
font-size: 0.9em; /* Smaller font size */
|
||||
}
|
||||
.btn {
|
||||
font-size: 0.9em; /* Smaller font size for buttons */
|
||||
}
|
||||
.align-items-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.table th button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
#loginForm, #uploadForm {
|
||||
display: none;
|
||||
}
|
||||
.form-row {
|
||||
align-items: flex-start; /* Align items by top */
|
||||
}
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
.btn-delete {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.btn-delete:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row" id="loginForm">
|
||||
<div class="col-md-6">
|
||||
<form id="authForm" method="post">
|
||||
<div class="form-row align-items-center">
|
||||
<div class="form-group col-4 col-md-4">
|
||||
<label for="loginUsername">User:</label>
|
||||
<input type="text" class="form-control" id="loginUsername" name="username" required>
|
||||
</div>
|
||||
<div class="form-group col-4 col-md-4">
|
||||
<label for="loginPassword">Password:</label>
|
||||
<input type="password" class="form-control" id="loginPassword" name="password" required>
|
||||
</div>
|
||||
<div class="form-group col-4 col-md-4 align-items-center" style="padding-top: 26px;">
|
||||
<button type="submit" class="btn btn-upload btn-block" style="transform: translateY(2px);">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="uploadForm">
|
||||
<div class="col-md-12">
|
||||
<form id="uploadFileForm" method="post" enctype="multipart/form-data">
|
||||
<div class="form-row align-items-center">
|
||||
<div class="form-group col-4 col-md-4" style="transform: translateY(4px);">
|
||||
<label class="btn btn-choose-file btn-block">
|
||||
Choose File <input type="file" id="file" name="file" required hidden>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group col-4 col-md-4">
|
||||
<input type="submit" value="Upload" id="uploadBtn" class="btn btn-upload btn-block" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-12 full-width">
|
||||
<span id="fileName"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-12 full-width">
|
||||
<div id="statusMessage" class="ml-0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" id="progressRow" style="display: none;">
|
||||
<div class="form-group col-12">
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" style="width: 0%;" id="progressBar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-list">
|
||||
<div id="fileList" class="full-width"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
|
||||
<script src="auth.js"></script>
|
||||
<script src="upload.js"></script>
|
||||
<script src="displayFileList.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
120
upload.js
Normal file
120
upload.js
Normal file
@@ -0,0 +1,120 @@
|
||||
document.getElementById('file').addEventListener('change', function() {
|
||||
const fileInput = document.getElementById('file');
|
||||
const uploadBtn = document.getElementById('uploadBtn');
|
||||
if (fileInput.files.length > 0) {
|
||||
document.getElementById('fileName').innerHTML = `<b>${fileInput.files[0].name}</b>`;
|
||||
uploadBtn.disabled = false;
|
||||
} else {
|
||||
document.getElementById('fileName').innerHTML = '';
|
||||
uploadBtn.disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('uploadFileForm').addEventListener('submit', async function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const { username, password } = authCredentials;
|
||||
const fileInput = document.getElementById('file');
|
||||
const statusMessage = document.getElementById('statusMessage');
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
const progressRow = document.getElementById('progressRow');
|
||||
|
||||
if (fileInput.files.length > 0) {
|
||||
const file = fileInput.files[0];
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('username', username);
|
||||
formData.append('password', password);
|
||||
const fileDateTime = file.lastModified;
|
||||
formData.append('fileDateTime', fileDateTime);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', 'upload.php', true);
|
||||
|
||||
const uploadBtn = document.getElementById('uploadBtn');
|
||||
const fileBtn = document.getElementById('file');
|
||||
uploadBtn.disabled = true;
|
||||
fileBtn.disabled = true;
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
xhr.upload.onprogress = function(e) {
|
||||
if (e.lengthComputable) {
|
||||
const percentComplete = (e.loaded / e.total) * 100;
|
||||
progressBar.style.width = percentComplete + '%';
|
||||
progressBar.innerText = Math.round(percentComplete) + '%';
|
||||
progressRow.style.display = 'block'; // Show the progress bar
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function() {
|
||||
const endTime = Date.now();
|
||||
const uploadTime = (endTime - startTime) / 1000;
|
||||
const fileSize = fileInput.files[0].size;
|
||||
const uploadRate = (fileSize / 1024 / uploadTime).toFixed(2);
|
||||
|
||||
if (xhr.status === 200) {
|
||||
statusMessage.innerHTML = `File <b>${fileInput.files[0].name}</b> successfully uploaded. Upload time: <b>${uploadTime.toFixed(2)}</b> seconds. Upload rate: <b>${uploadRate}</b> KBps.`;
|
||||
loadFileList();
|
||||
} else {
|
||||
statusMessage.innerHTML = 'Upload failed!';
|
||||
}
|
||||
progressBar.style.width = '0%';
|
||||
progressBar.innerText = '';
|
||||
progressRow.style.display = 'none'; // Hide the progress bar
|
||||
document.getElementById('fileName').innerHTML = '';
|
||||
uploadBtn.disabled = true;
|
||||
fileBtn.disabled = false;
|
||||
fileBtn.value = '';
|
||||
};
|
||||
|
||||
statusMessage.innerHTML = `Uploading file ${fileInput.files[0].name}...`;
|
||||
xhr.send(formData);
|
||||
}
|
||||
});
|
||||
|
||||
async function loadFileList() {
|
||||
try {
|
||||
const { username, password } = authCredentials;
|
||||
console.log('Loading file list with credentials:', { username, password }); // Debugging
|
||||
const response = await fetch('file_list.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ username, password }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const fileList = await response.json();
|
||||
console.log('File list loaded:', fileList); // Debugging: Log the file list to the console
|
||||
displayFileList(fileList);
|
||||
} catch (error) {
|
||||
console.error('Error loading file list:', error); // Debugging: Log any errors to the console
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteFile(fileName) {
|
||||
const { username, password } = authCredentials;
|
||||
try {
|
||||
const response = await fetch('file_list.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ username, password, delete: fileName }),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
loadFileList();
|
||||
} else {
|
||||
console.error('Error deleting file:', result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting file:', error);
|
||||
}
|
||||
}
|
||||
37
upload.php
Normal file
37
upload.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
require_once 'auth.php';
|
||||
|
||||
// Check if the form was submitted
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// Get the username and password
|
||||
$username = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
$fileDateTime = isset($_POST['fileDateTime']) ? (int)$_POST['fileDateTime'] / 1000 : time();
|
||||
|
||||
// Validate the credentials using the Flask backend
|
||||
if (authenticate($username, $password)) {
|
||||
// Check if a file was uploaded
|
||||
if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
|
||||
$uploadFile = UPLOAD_DIR . basename($_FILES['file']['name']);
|
||||
$tmpFile = $_FILES['file']['tmp_name'];
|
||||
|
||||
// Move the uploaded file to the specified directory
|
||||
if (move_uploaded_file($tmpFile, $uploadFile)) {
|
||||
// Preserve the original file modification time
|
||||
touch($uploadFile, $fileDateTime);
|
||||
echo "File is valid, and was successfully uploaded.\n";
|
||||
} else {
|
||||
echo "File upload failed! ";
|
||||
print_r(error_get_last());
|
||||
}
|
||||
} else {
|
||||
echo "No file uploaded or file upload error!\n";
|
||||
echo "Error code: " . $_FILES['file']['error'];
|
||||
}
|
||||
} else {
|
||||
echo "Invalid username or password!\n";
|
||||
}
|
||||
} else {
|
||||
echo "Invalid request method!\n";
|
||||
}
|
||||
Reference in New Issue
Block a user