mirror of
https://github.com/mattintech/simplefileupload-server.git
synced 2026-07-11 12:01:53 +00:00
require client-key for uploads
This commit is contained in:
7
.env.example
Normal file
7
.env.example
Normal file
@@ -0,0 +1,7 @@
|
||||
# Required for file uploads
|
||||
CLIENT_KEY=your-secret-key-here
|
||||
|
||||
# Optional configurations
|
||||
UPLOAD_FOLDER=tmp/uploads
|
||||
DEBUG=False
|
||||
MAX_CONTENT_LENGTH=16777216 # 16MB in bytes
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
tmp/
|
||||
uploads/
|
||||
file_metadata.json
|
||||
.env
|
||||
|
||||
# Python
|
||||
venv/
|
||||
|
||||
@@ -4,4 +4,10 @@ COPY ./src /app
|
||||
COPY requirements.txt /app/requirements.txt
|
||||
RUN pip install -r /app/requirements.txt
|
||||
EXPOSE 7777
|
||||
|
||||
# The actual values should be provided when running the container
|
||||
ENV CLIENT_KEY=default-secret-key \
|
||||
UPLOAD_FOLDER=tmp/uploads \
|
||||
DEBUG=False
|
||||
|
||||
CMD ["gunicorn", "wsgi:app", "--bind", "0.0.0.0:7777"]
|
||||
84
README.md
84
README.md
@@ -4,6 +4,7 @@ A lightweight Flask-based file upload and download server with a modern UI. Perf
|
||||
|
||||
## Features
|
||||
- Clean, modern UI for file downloads
|
||||
- Secure API authentication for uploads
|
||||
- Mobile-friendly upload endpoint
|
||||
- Secure 6-digit alphanumeric code system
|
||||
- Automatic file cleanup
|
||||
@@ -20,25 +21,40 @@ Built using the MVC design pattern:
|
||||
## Getting Started
|
||||
|
||||
### Local Development
|
||||
1. Clone the repository
|
||||
2. Create and activate a virtual environment:
|
||||
```bash
|
||||
# Create and activate virtual environment
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
```
|
||||
|
||||
# Install dependencies
|
||||
3. Install dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
# Run the server
|
||||
4. Set up environment variables:
|
||||
- Copy `.env.example` to `.env`
|
||||
- Set your `CLIENT_KEY` in the `.env` file
|
||||
- Adjust other settings as needed
|
||||
|
||||
5. Run the server:
|
||||
```bash
|
||||
python src/app.py
|
||||
```
|
||||
|
||||
### Docker Deployment
|
||||
1. Build the image:
|
||||
```bash
|
||||
# Build the image
|
||||
docker build -t file-upload-server .
|
||||
```
|
||||
|
||||
# Run the container
|
||||
docker run -p 7777:7777 -v $(pwd)/tmp:/app/tmp file-upload-server
|
||||
2. Run the container:
|
||||
```bash
|
||||
docker run -p 7777:7777 \
|
||||
-e CLIENT_KEY=your-secret-key \
|
||||
-v $(pwd)/tmp:/app/tmp \
|
||||
file-upload-server
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
@@ -46,10 +62,13 @@ docker run -p 7777:7777 -v $(pwd)/tmp:/app/tmp file-upload-server
|
||||
### POST /upload
|
||||
Upload a file and receive a download code.
|
||||
|
||||
**Authentication:**
|
||||
- Required: `X-Client-Key` header with your API key
|
||||
|
||||
**Form Fields:**
|
||||
- `file`: File to upload (required)
|
||||
- `max_downloads`: Maximum download count (optional, default: 1)
|
||||
- `expiry_hours`: Hours until expiry (optional, default: 24, max: 24)
|
||||
- `expiry_hours`: Hours until expiry (optional, default: 24)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
@@ -58,34 +77,75 @@ Upload a file and receive a download code.
|
||||
}
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
- 401: Invalid or missing client key
|
||||
- 400: Missing file or invalid request
|
||||
```json
|
||||
{
|
||||
"error": "Error message here"
|
||||
}
|
||||
```
|
||||
|
||||
### GET /download/{code}
|
||||
Download a file using a 6-character code.
|
||||
|
||||
**Responses:**
|
||||
- 200: File download starts
|
||||
- 404: File not found with specific error page for:
|
||||
- 404: File not found with specific error pages for:
|
||||
- Invalid code
|
||||
- Expired file
|
||||
- Download limit reached
|
||||
- File no longer exists
|
||||
|
||||
## Security Notes
|
||||
- Files are automatically deleted after:
|
||||
### DELETE /delete/{code}
|
||||
Delete a file using its code.
|
||||
|
||||
**Responses:**
|
||||
- 200: File deleted successfully
|
||||
- 404: File not found or expired
|
||||
|
||||
## Security Features
|
||||
- **API Authentication**: Client key required for file uploads
|
||||
- **Secure Downloads**: 6-digit alphanumeric codes
|
||||
- **Auto Cleanup**: Files are automatically deleted after:
|
||||
- Reaching download limit
|
||||
- Exceeding expiry time
|
||||
- Server restart (temporary storage)
|
||||
- No file execution permissions in upload directory
|
||||
- Secure filename handling
|
||||
- **Upload Security**:
|
||||
- Secure filename handling
|
||||
- No file execution permissions
|
||||
- File size limits
|
||||
|
||||
## Configuration
|
||||
All configuration is handled through environment variables:
|
||||
|
||||
### Required Settings
|
||||
- `CLIENT_KEY`: API key for file uploads (required for production)
|
||||
|
||||
### Optional Settings
|
||||
- `UPLOAD_FOLDER`: Upload directory path (default: tmp/uploads)
|
||||
- `MAX_CONTENT_LENGTH`: Maximum file size (default: 16MB)
|
||||
- `DEBUG`: Enable debug mode (default: False)
|
||||
|
||||
### Environment File
|
||||
The application supports `.env` file for configuration:
|
||||
```env
|
||||
CLIENT_KEY=your-secret-key-here
|
||||
UPLOAD_FOLDER=tmp/uploads
|
||||
DEBUG=False
|
||||
MAX_CONTENT_LENGTH=16777216
|
||||
```
|
||||
|
||||
## Contributing
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Commit your changes
|
||||
4. Push to the branch
|
||||
5. Create a Pull Request
|
||||
|
||||
## Security Best Practices
|
||||
- Always change the default client key
|
||||
- Use HTTPS in production
|
||||
- Regularly monitor disk usage
|
||||
- Set appropriate file size limits
|
||||
- Keep dependencies updated
|
||||
|
||||
6
TASK.md
6
TASK.md
@@ -7,6 +7,7 @@
|
||||
- [x] Implement download tracking and limits
|
||||
- [x] Add file expiry system
|
||||
- [x] Create modern UI with error handling
|
||||
- [x] Add API authentication for uploads
|
||||
|
||||
## 🎯 Core Features Implemented
|
||||
|
||||
@@ -24,6 +25,7 @@
|
||||
- [x] Metadata tracking
|
||||
- [x] Configurable limits
|
||||
- [x] API response format
|
||||
- [x] API key authentication
|
||||
|
||||
### Download System
|
||||
- [x] Code validation
|
||||
@@ -47,6 +49,9 @@
|
||||
- [ ] Implement file type restrictions
|
||||
- [ ] Add optional password protection
|
||||
- [ ] CSRF protection
|
||||
- [ ] Add key rotation support
|
||||
- [ ] Implement IP whitelisting
|
||||
- [ ] Add audit logging
|
||||
|
||||
### Features
|
||||
- [ ] Multi-file upload support
|
||||
@@ -61,6 +66,7 @@
|
||||
- [ ] Implement persistent storage
|
||||
- [ ] Add monitoring/metrics
|
||||
- [ ] Create backup system
|
||||
- [ ] Add health check endpoints
|
||||
|
||||
### UI/UX
|
||||
- [ ] Dark mode support
|
||||
|
||||
@@ -11,6 +11,7 @@ itsdangerous==2.2.0
|
||||
Jinja2==3.1.4
|
||||
MarkupSafe==3.0.0
|
||||
packaging==24.1
|
||||
python-dotenv==1.0.1
|
||||
requests==2.32.3
|
||||
urllib3==2.2.3
|
||||
Werkzeug==3.0.4
|
||||
|
||||
18
src/app.py
18
src/app.py
@@ -1,20 +1,36 @@
|
||||
import os
|
||||
import uuid
|
||||
from functools import wraps
|
||||
from flask import Flask, request, jsonify, send_from_directory
|
||||
from werkzeug.utils import secure_filename
|
||||
import requests
|
||||
from dotenv import load_dotenv
|
||||
import utils.mLogger as log
|
||||
from controllers.file_controller import upload_file, download_file, delete_file
|
||||
from views import views
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['UPLOAD_FOLDER'] = 'tmp/uploads'
|
||||
app.config['CLIENT_KEY'] = os.getenv('CLIENT_KEY', 'default-secret-key')
|
||||
|
||||
if not os.path.exists(app.config['UPLOAD_FOLDER']):
|
||||
os.makedirs(app.config['UPLOAD_FOLDER'])
|
||||
|
||||
def require_client_key(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
client_key = request.headers.get('X-Client-Key')
|
||||
if not client_key or client_key != app.config['CLIENT_KEY']:
|
||||
log.e("Invalid or missing client key")
|
||||
return jsonify({'error': 'Invalid or missing client key'}), 401
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
|
||||
# Route for file uploads
|
||||
app.route('/upload', methods=['POST'])(upload_file)
|
||||
app.route('/upload', methods=['POST'])(require_client_key(upload_file))
|
||||
|
||||
# Route for downloading the file
|
||||
app.route('/download/<code>', methods=['GET'])(download_file)
|
||||
|
||||
Reference in New Issue
Block a user