diff --git a/.env.example b/.env.example
index 9a57b1a..128203b 100644
--- a/.env.example
+++ b/.env.example
@@ -9,8 +9,17 @@ PORT=3000
# You must update this to the url you use to access your site
BASE_URL=http://localhost:3000/
-# Node environment (default: development)
-NODE_ENV=development
+#ALLOWED_IFRAME_ORIGINS= #DEPRECATED and will be used as ALLOWED_ORIGINS if SET
+
+# Comma-separated list of allowed origins for CORS
+# (default: '*' if empty, add your base_url if you want to restrict only to base_url)
+# When adding multiple origins, base_url will be included by default
+# ALLOWED_ORIGINS: http://internalip:port,https://subdomain.example.com
+ALLOWED_ORIGINS=
+
+# Node environment (default: production)
+# When set to 'development', ALLOWED_ORIGINS will default to '*'
+NODE_ENV=production
#########################################
# FILE UPLOAD SETTINGS
@@ -62,8 +71,4 @@ APPRISE_SIZE_UNIT=Auto
#########################################
# Enable automatic upload on file selection (true/false, default: false)
-AUTO_UPLOAD=false
-
-# Comma-separated list of origins allowed to embed the app in an iframe (optional)
-# ALLOWED_IFRAME_ORIGINS=https://example.com,https://another.com
-ALLOWED_IFRAME_ORIGINS=
\ No newline at end of file
+AUTO_UPLOAD=false
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 04a9654..fa00d48 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Base stage for shared configurations
-FROM node:20-alpine as base
+FROM node:22-alpine as base
# Install python and create virtual environment with minimal dependencies
RUN apk add --no-cache python3 py3-pip && \
diff --git a/README.md b/README.md
index c93f666..4ac223d 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ A stupid simple file upload application that provides a clean, modern interface
No auth (unless you want it now!), no storage, no nothing. Just a simple file uploader to drop dumb files into a dumb folder.
## Table of Contents
+
- [Quick Start](#quick-start)
- [Production Deployment with Docker](#production-deployment-with-docker)
- [Local Development (Recommended Quick Start)](LOCAL_DEVELOPMENT.md)
@@ -21,44 +22,51 @@ No auth (unless you want it now!), no storage, no nothing. Just a simple file up
## Quick Start
### Option 1: Docker (For Dummies)
+
```bash
# Pull and run with one command
docker run -p 3000:3000 -v ./uploads:/app/uploads dumbwareio/dumbdrop:latest
```
+
1. Go to http://localhost:3000
2. Upload a File - It'll show up in ./uploads
3. Celebrate on how dumb easy this was
### Option 2: Docker Compose (For Dummies who like customizing)
+
Create a `docker-compose.yml` file:
+
```yaml
services:
- dumbdrop:
- image: dumbwareio/dumbdrop:latest
- ports:
- - 3000:3000
- volumes:
- # Where your uploaded files will land
- - ./uploads:/app/uploads
- environment:
- # Explicitly set upload directory inside the container
- UPLOAD_DIR: /app/uploads
- # The title shown in the web interface
- DUMBDROP_TITLE: DumbDrop
- # Maximum file size in MB
- MAX_FILE_SIZE: 1024
- # Optional PIN protection (leave empty to disable)
- DUMBDROP_PIN: 123456
- # Upload without clicking button
- AUTO_UPLOAD: false
- # The base URL for the application
- # You must update this to the url you use to access your site
- BASE_URL: http://localhost:3000
+ dumbdrop:
+ image: dumbwareio/dumbdrop:latest
+ ports:
+ - 3000:3000
+ volumes:
+ # Where your uploaded files will land
+ - ./uploads:/app/uploads
+ environment:
+ # Explicitly set upload directory inside the container
+ UPLOAD_DIR: /app/uploads
+ # The title shown in the web interface
+ DUMBDROP_TITLE: DumbDrop
+ # Maximum file size in MB
+ MAX_FILE_SIZE: 1024
+ # Optional PIN protection (leave empty to disable)
+ DUMBDROP_PIN: 123456
+ # Upload without clicking button
+ AUTO_UPLOAD: false
+ # The base URL for the application
+ # You must update this to the url you use to access your site
+ BASE_URL: http://localhost:3000
```
+
Then run:
+
```bash
docker compose up -d
```
+
1. Go to http://localhost:3000
2. Upload a File - It'll show up in ./uploads
3. Rejoice in the glory of your dumb uploads
@@ -90,21 +98,22 @@ For local development setup, troubleshooting, and advanced usage, see the dedica
### Environment Variables
-| Variable | Description | Default | Required |
-|------------------------|------------------------------------------------------------------|-----------------------------------------|----------|
-| PORT | Server port | 3000 | No |
-| BASE_URL | Base URL for the application | http://localhost:PORT | 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 | New file uploaded {filename} ({size}), Storage used {storage} | No |
-| APPRISE_SIZE_UNIT | Size unit for notifications (B, KB, MB, GB, TB, or Auto) | Auto | No |
-| AUTO_UPLOAD | Enable automatic upload on file selection | false | No |
-| ALLOWED_EXTENSIONS | Comma-separated list of allowed file extensions | None | No |
-| ALLOWED_IFRAME_ORIGINS | Comma-separated list of origins allowed to embed the app in an iframe | None | No |
-| UPLOAD_DIR | Directory for uploads (Docker/production; should be `/app/uploads` in container) | None (see LOCAL_UPLOAD_DIR fallback) | No |
-| LOCAL_UPLOAD_DIR | Directory for uploads (local dev, fallback: './local_uploads') | ./local_uploads | No |
+| Variable | Description | Default | Required |
+| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------- |
+| PORT | Server port | 3000 | No |
+| BASE_URL | Base URL for the application | http://localhost:PORT | 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 | New file uploaded {filename} ({size}), Storage used {storage} | No |
+| APPRISE_SIZE_UNIT | Size unit for notifications (B, KB, MB, GB, TB, or Auto) | Auto | No |
+| AUTO_UPLOAD | Enable automatic upload on file selection | false | No |
+| ALLOWED_EXTENSIONS | Comma-separated list of allowed file extensions | None | No |
+| ALLOWED_IFRAME_ORIGINS (deprecated: see ALLOWED_ORIGINS) | Comma-separated list of origins allowed to embed the app in an iframe | None | No |
+| ALLOWED_ORIGINS | You can restrict CORS to your BASE_URL or a comma-separated list of specified origins, which will automatically include your base_url | '\*' | No |
+| UPLOAD_DIR | Directory for uploads (Docker/production; should be `/app/uploads` in container) | None (see LOCAL_UPLOAD_DIR fallback) | No |
+| LOCAL_UPLOAD_DIR | Directory for uploads (local dev, fallback: './local_uploads') | ./local_uploads | No |
- **UPLOAD_DIR** is used in Docker/production. If not set, LOCAL_UPLOAD_DIR is used for local development. If neither is set, the default is `./local_uploads`.
- **Docker Note:** The Dockerfile now only creates the `uploads` directory inside the container. The host's `./local_uploads` is mounted to `/app/uploads` and should be managed on the host system.
@@ -114,50 +123,76 @@ For local development setup, troubleshooting, and advanced usage, see the dedica
See `.env.example` for a template and more details.
-ALLOWED_IFRAME_ORIGINS
+ALLOWED_IFRAME_ORIGINS (DEPRECATED: see ALLOWED_ORIGINS)
-To allow this app to be embedded in an iframe on specific origins (such as Organizr), set the `ALLOWED_IFRAME_ORIGINS` environment variable. For example:
+- This is now deprecated but still works for backwards compatibility
+- ALLOWED_IFRAME_ORIGINS will be used as a fallback if ALLOWED_ORIGINS is not set
+- Please update to ALLOWED_ORIGINS for future compatibility
+
+~~To allow this app to be embedded in an iframe on specific origins (such as Organizr), set the `ALLOWED_IFRAME_ORIGINS` environment variable. For example:~~
```env
ALLOWED_IFRAME_ORIGINS=https://organizr.example.com,https://myportal.com
```
-- If not set, the app will only allow itself to be embedded in an iframe on the same origin (default security).
-- If set, the app will allow embedding in iframes on the specified origins and itself.
-- **Security Note:** Only add trusted origins. Allowing arbitrary origins can expose your app to clickjacking and other attacks.
+- ~~If not set, the app will only allow itself to be embedded in an iframe on the same origin (default security).~~
+- ~~If set, the app will allow embedding in iframes on the specified origins and itself.~~
+- ~~**Security Note:** Only add trusted origins. Allowing arbitrary origins can expose your app to clickjacking and other attacks.~~
+
+ALLOWED_ORIGINS
+
+By default `ALLOWED_ORIGINS` is set to '\*'
+
+```env
+ALLOWED_ORIGINS=https://organizr.example.com,https://myportal.com,http://internalip:port
+```
+
+- If you would like to restrict CORS to your BASE_URL, you can set it like this: `ALLOWED_ORIGINS=http://localhost:3000`
+- If you would like to allow multiple origins, you can set it like this: `ALLOWED_ORIGINS=http://internalip:port,https://subdomain.domain.tld`
+ - This will automatically include your BASE_URL in the list of allowed origins.
+
+
File Extension Filtering
To restrict which file types can be uploaded, set the `ALLOWED_EXTENSIONS` environment variable. For example:
+
```env
ALLOWED_EXTENSIONS=.jpg,.jpeg,.png,.pdf,.doc,.docx,.txt
```
+
If not set, all file extensions will be allowed.
+
Notification Setup
#### Message Templates
+
The notification message supports the following placeholders:
+
- `{filename}`: Name of the uploaded file
- `{size}`: Size of the file (formatted according to APPRISE_SIZE_UNIT)
- `{storage}`: Total size of all files in upload directory
Example message template:
+
```env
APPRISE_MESSAGE: New file uploaded {filename} ({size}), Storage used {storage}
```
Size formatting examples:
+
- Auto (default): Chooses nearest unit (e.g., "1.44MB", "256KB")
- Fixed unit: Set APPRISE_SIZE_UNIT to B, KB, MB, GB, or TB
Both {size} and {storage} use the same formatting rules based on APPRISE_SIZE_UNIT.
#### Notification Support
+
- Integration with [Apprise](https://github.com/caronc/apprise?tab=readme-ov-file#supported-notifications) for flexible notifications
- Support for all Apprise notification services
- Customizable notification messages with filename templating
@@ -167,6 +202,7 @@ Both {size} and {storage} use the same formatting rules based on APPRISE_SIZE_UN
## Security
### Features
+
- Variable-length PIN support (4-10 digits)
- Constant-time PIN comparison
- Input sanitization
@@ -178,6 +214,7 @@ Both {size} and {storage} use the same formatting rules based on APPRISE_SIZE_UN
## Technical Details
### Stack
+
- **Backend**: Node.js (>=20.0.0) with Express
- **Frontend**: Vanilla JavaScript (ES6+)
- **Container**: Docker with multi-stage builds
@@ -186,6 +223,7 @@ Both {size} and {storage} use the same formatting rules based on APPRISE_SIZE_UN
- **Notifications**: Apprise integration
### Dependencies
+
- express: Web framework
- multer: File upload handling
- apprise: Notification system
@@ -210,8 +248,10 @@ See [Local Development (Recommended Quick Start)](LOCAL_DEVELOPMENT.md) for loca
---
+
Made with ❤️ by [DumbWare.io](https://dumbware.io)
## Future Features
+
- Camera Upload for Mobile
-> Got an idea? [Open an issue](https://github.com/dumbwareio/dumbdrop/issues) or [submit a PR](https://github.com/dumbwareio/dumbdrop/pulls)
+ > Got an idea? [Open an issue](https://github.com/dumbwareio/dumbdrop/issues) or [submit a PR](https://github.com/dumbwareio/dumbdrop/pulls)
diff --git a/docker-compose.yml b/docker-compose.yml
index 2a70e37..cfeee23 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,9 @@
services:
dumbdrop:
image: dumbwareio/dumbdrop:latest
+ # build: .
+ container_name: dumbdrop
+ restart: unless-stopped
ports:
- 3000:3000
volumes:
@@ -15,9 +18,15 @@ services:
AUTO_UPLOAD: true # Upload without clicking button
BASE_URL: http://localhost:3000 # The base URL for the application, You must update this to the url you use to access your site
+ # Comma-separated list of allowed origins for CORS
+ # (default: '*' if empty, replace with your base_url if you want to restrict only to base_url)
+ # When adding multiple origins, base_url will be included by default and does not need to the list
+ # ALLOWED_IFRAME_ORIGINS: #DEPRECATED and will be used as ALLOWED_ORIGINS if SET
+ # ALLOWED_ORIGINS: http://internalip:port,https://subdomain.example.com
+
# Additional available environment variables (commented out with defaults)
# PORT: 3000 # Server port (default: 3000)
- # NODE_ENV: production # Node environment (development/production)
+ # NODE_ENV: production # Node environment (development/production) - when not using production ALLOWED_ORIGINS will be set to '*' by default
# DEBUG: false # Debug mode for verbose logging (default: false in production, true in development)
# APPRISE_URL: "" # Apprise notification URL for upload notifications (default: none)
# APPRISE_MESSAGE: "New file uploaded - {filename} ({size}), Storage used {storage}" # Notification message template with placeholders: {filename}, {size}, {storage}
diff --git a/package-lock.json b/package-lock.json
index ba76b05..4b0ac54 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,9 @@
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-rate-limit": "^7.1.5",
- "multer": "^1.4.5-lts.1"
+ "helmet": "^8.1.0",
+ "multer": "^1.4.5-lts.1",
+ "toastify-js": "^1.12.0"
},
"devDependencies": {
"eslint": "^8.56.0",
@@ -188,9 +190,9 @@
}
},
"node_modules/acorn": {
- "version": "8.14.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
- "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
@@ -356,9 +358,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -625,9 +627,9 @@
}
},
"node_modules/debug": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
- "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1423,6 +1425,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/helmet": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz",
+ "integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -1801,6 +1812,7 @@
"version": "1.4.5-lts.2",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.2.tgz",
"integrity": "sha512-VzGiVigcG9zUAoCNU+xShztrlr1auZOlurXynNvO9GiWD1/mTBbUljOKY+qMeazBqXgRnjzeEgJI/wyjJUHg9A==",
+ "deprecated": "Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version.",
"license": "MIT",
"dependencies": {
"append-field": "^1.0.0",
@@ -2658,6 +2670,12 @@
"node": ">=8.0"
}
},
+ "node_modules/toastify-js": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz",
+ "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==",
+ "license": "MIT"
+ },
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
diff --git a/package.json b/package.json
index f3717f5..fbc064e 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,9 @@
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-rate-limit": "^7.1.5",
- "multer": "^1.4.5-lts.1"
+ "helmet": "^8.1.0",
+ "multer": "^1.4.5-lts.1",
+ "toastify-js": "^1.12.0"
},
"devDependencies": {
"eslint": "^8.56.0",
diff --git a/public/index.html b/public/index.html
index af953d6..9998091 100644
--- a/public/index.html
+++ b/public/index.html
@@ -4,12 +4,11 @@
{{SITE_TITLE}} - Simple File Upload
-
-
-
-
-
-
+
+
+
+
+