mirror of
https://github.com/DumbWareio/DumbDrop.git
synced 2025-10-23 07:41:58 +00:00
Add customizable site title feature via DUMBDROP_TITLE environment variable
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
# Server Configuration
|
||||
PORT=3000 # The port the server will listen on
|
||||
DUMBDROP_TITLE=DumbDrop # Site title displayed in header (default: DumbDrop)
|
||||
|
||||
# Upload Limits
|
||||
MAX_FILE_SIZE=1024 # Maximum file size in MB (default: 1024 MB / 1 GB)
|
||||
|
||||
# Security
|
||||
DUMBDROP_PIN= # Optional 4-digit PIN protection (leave empty to disable)
|
||||
DUMBDROP_PIN= # Optional PIN protection (4-10 digits, leave empty to disable)
|
||||
|
||||
# Notifications
|
||||
APPRISE_URL= # Apprise URL for notifications (leave empty to disable)
|
||||
APPRISE_MESSAGE= # Custom message for notifications (default: "File uploaded: {filename}")
|
||||
APPRISE_MESSAGE= # Custom message for notifications (default: "File uploaded: {filename}")
|
||||
|
@@ -28,8 +28,9 @@ No auth (unless you want it now!), no storage, no nothing. Just a simple file up
|
||||
| PORT | Server port | 3000 | No |
|
||||
| MAX_FILE_SIZE| Maximum file size in MB | 1024 | No |
|
||||
| DUMBDROP_PIN | PIN protection (4-10 digits) | None | No |
|
||||
| DUMBDROP_TITLE| Site title displayed in header | DumbDrop| No |
|
||||
| APPRISE_URL | Apprise URL for notifications | None | No |
|
||||
| APPRISE_MESSAGE| Notification message template | "File uploaded: {filename}" | No |
|
||||
| APPRISE_MESSAGE| Notification message template | "File uploaded: {filename}" | No |
|
||||
|
||||
## Security Features
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DumbDrop - Simple File Upload</title>
|
||||
<title>{{SITE_TITLE}} - Simple File Upload</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
|
||||
@@ -26,7 +26,7 @@
|
||||
<line class="sun" x1="18.36" y1="5.64" x2="19.78" y2="4.22" style="display:none"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1>DumbDrop</h1>
|
||||
<h1>{{SITE_TITLE}}</h1>
|
||||
<div class="upload-container" id="dropZone">
|
||||
<div class="upload-content">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
|
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DumbDrop - Login</title>
|
||||
<title>{{SITE_TITLE}} - Login</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<style>
|
||||
.login-container {
|
||||
@@ -57,7 +57,7 @@
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<div class="pin-header">
|
||||
<h1>DumbDrop</h1>
|
||||
<h1>{{SITE_TITLE}}</h1>
|
||||
<h2>Enter PIN</h2>
|
||||
</div>
|
||||
<form id="pin-form">
|
||||
|
58
server.js
58
server.js
@@ -16,6 +16,7 @@ const uploadDir = './uploads'; // Local development
|
||||
const maxFileSize = parseInt(process.env.MAX_FILE_SIZE || '1024') * 1024 * 1024; // Convert MB to bytes
|
||||
const APPRISE_URL = process.env.APPRISE_URL;
|
||||
const APPRISE_MESSAGE = process.env.APPRISE_MESSAGE || 'File uploaded: {filename}';
|
||||
const siteTitle = process.env.DUMBDROP_TITLE || 'DumbDrop';
|
||||
|
||||
// Brute force protection setup
|
||||
const loginAttempts = new Map(); // Stores IP addresses and their attempt counts
|
||||
@@ -191,43 +192,29 @@ const requirePin = (req, res, next) => {
|
||||
next();
|
||||
};
|
||||
|
||||
// Apply pin protection to all /upload routes
|
||||
app.use('/upload', requirePin);
|
||||
|
||||
// Serve login page and its assets without PIN check
|
||||
app.use((req, res, next) => {
|
||||
if (req.path === '/login.html' || req.path === '/styles.css' || req.path.startsWith('/api/')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Check PIN requirement
|
||||
if (!PIN) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Check cookie
|
||||
const providedPin = req.cookies.DUMBDROP_PIN;
|
||||
if (!safeCompare(providedPin, PIN)) {
|
||||
// If requesting HTML or root, redirect to login
|
||||
if (req.path === '/' || req.path.endsWith('.html')) {
|
||||
return res.redirect('/login.html');
|
||||
}
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// Serve static files
|
||||
app.use(express.static('public'));
|
||||
|
||||
// Handle root route
|
||||
// Move the root and login routes before static file serving
|
||||
app.get('/', (req, res) => {
|
||||
if (PIN && !safeCompare(req.cookies.DUMBDROP_PIN, PIN)) {
|
||||
return res.redirect('/login.html');
|
||||
}
|
||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||
// Read the file and replace the title
|
||||
let html = fs.readFileSync(path.join(__dirname, 'public', 'index.html'), 'utf8');
|
||||
html = html.replace(/{{SITE_TITLE}}/g, siteTitle); // Use global replace
|
||||
res.send(html);
|
||||
});
|
||||
|
||||
app.get('/login.html', (req, res) => {
|
||||
let html = fs.readFileSync(path.join(__dirname, 'public', 'login.html'), 'utf8');
|
||||
html = html.replace(/{{SITE_TITLE}}/g, siteTitle); // Use global replace
|
||||
res.send(html);
|
||||
});
|
||||
|
||||
// Move static file serving after our dynamic routes
|
||||
app.use(express.static('public'));
|
||||
|
||||
// PIN protection middleware should be before the routes that need protection
|
||||
app.use('/upload', requirePin);
|
||||
|
||||
// Store ongoing uploads
|
||||
const uploads = new Map();
|
||||
|
||||
@@ -335,11 +322,14 @@ app.listen(port, () => {
|
||||
log.info(`Server running at http://localhost:${port}`);
|
||||
log.info(`Upload directory: ${uploadDir}`);
|
||||
|
||||
// Log custom title if set
|
||||
if (process.env.DUMBDROP_TITLE) {
|
||||
log.info(`Custom title set to: ${siteTitle}`);
|
||||
}
|
||||
|
||||
// Add Apprise configuration logging
|
||||
if (APPRISE_URL) {
|
||||
log.info(`Apprise notifications enabled`);
|
||||
log.info(`Apprise URL: ${APPRISE_URL}`);
|
||||
log.info(`Apprise message template: ${APPRISE_MESSAGE}`);
|
||||
log.info('Apprise notifications enabled');
|
||||
} else {
|
||||
log.info('Apprise notifications disabled - no URL configured');
|
||||
}
|
||||
|
Reference in New Issue
Block a user