mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 03:52:26 +08:00
fix(setup): stop shipping guessable admin credentials on fresh installs (fixes #7850)
Fresh Docker installs created the admin as admin@sub2api.local and accepted any ADMIN_PASSWORD (e.g. "123456"), making them easy brute-force targets. - Generate a random admin-<12 hex>@sub2api.local login email when ADMIN_EMAIL is empty; drop the fixed default from .env.example and the compose files, and have docker-deploy.sh write a random ADMIN_EMAIL. - Validate user-supplied ADMIN_PASSWORD (8-72 bytes) and ADMIN_EMAIL on the auto-setup path, only when an admin is actually about to be created, so existing deployments are never blocked at startup. - Align validateEmail with the login endpoint's email binding so setup can no longer create an admin that can never log in (e.g. "a@b", "Name <a@b.com>"). - Cap validatePassword at bcrypt's 72-byte limit; the CLI reuses it and now defaults to a random admin email instead of admin@example.com. - Update READMEs/deploy docs to stop suggesting guessable credentials.
This commit is contained in:
+5
-3
@@ -206,10 +206,12 @@ REDIS_ENABLE_TLS=false
|
||||
# -----------------------------------------------------------------------------
|
||||
# Admin Account
|
||||
# -----------------------------------------------------------------------------
|
||||
# Email for the admin account
|
||||
ADMIN_EMAIL=admin@sub2api.local
|
||||
# Email for the admin account (used as the login username)
|
||||
# Leave empty to auto-generate a random one (will be shown in logs on first run).
|
||||
# Avoid well-known values such as admin@sub2api.local: they are brute-force targets.
|
||||
ADMIN_EMAIL=
|
||||
|
||||
# Password for admin account
|
||||
# Password for admin account (8-72 bytes)
|
||||
# Leave empty to auto-generate (will be shown in logs on first run)
|
||||
ADMIN_PASSWORD=
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ nano .env
|
||||
./apple-container.sh status
|
||||
```
|
||||
|
||||
Open `http://localhost:8080`. If `ADMIN_PASSWORD` is empty, retrieve the generated password with:
|
||||
Open `http://localhost:8080`. If `ADMIN_EMAIL` / `ADMIN_PASSWORD` are empty, retrieve the generated admin email (login username) and password with:
|
||||
|
||||
```bash
|
||||
./apple-container.sh logs app
|
||||
|
||||
+8
-8
@@ -79,8 +79,8 @@ docker compose -f docker-compose.local.yml up -d
|
||||
# View logs
|
||||
docker compose -f docker-compose.local.yml logs -f sub2api
|
||||
|
||||
# If admin password was auto-generated, find it in logs:
|
||||
docker compose -f docker-compose.local.yml logs sub2api | grep "admin password"
|
||||
# If admin email/password were auto-generated, find them in logs:
|
||||
docker compose -f docker-compose.local.yml logs sub2api | grep "Generated admin"
|
||||
|
||||
# Access Web UI
|
||||
# http://localhost:8080
|
||||
@@ -112,7 +112,7 @@ mkdir -p data postgres_data redis_data
|
||||
# Start all services using local directory version
|
||||
docker compose -f docker-compose.local.yml up -d
|
||||
|
||||
# View logs (check for auto-generated admin password)
|
||||
# View logs (check for auto-generated admin email and password)
|
||||
docker compose -f docker-compose.local.yml logs -f sub2api
|
||||
|
||||
# Access Web UI
|
||||
@@ -136,14 +136,14 @@ When using Docker Compose with `AUTO_SETUP=true`:
|
||||
- Connects to PostgreSQL and Redis
|
||||
- Applies database migrations (SQL files in `backend/migrations/*.sql`) and records them in `schema_migrations`
|
||||
- Generates JWT secret (if not provided)
|
||||
- Creates admin account (password auto-generated if not provided)
|
||||
- Creates admin account (email and password auto-generated if not provided; a provided password must be 8-72 bytes)
|
||||
- Writes config.yaml
|
||||
|
||||
2. No manual Setup Wizard needed - just configure `.env` and start
|
||||
|
||||
3. If `ADMIN_PASSWORD` is not set, check logs for the generated password:
|
||||
3. If `ADMIN_EMAIL` / `ADMIN_PASSWORD` are not set, check logs for the generated admin email (login username) and password:
|
||||
```bash
|
||||
docker compose logs sub2api | grep "admin password"
|
||||
docker compose logs sub2api | grep "Generated admin"
|
||||
```
|
||||
|
||||
### Startup and Database Recovery
|
||||
@@ -257,8 +257,8 @@ docker compose down -v
|
||||
| `JWT_SECRET` | **Recommended** | *(auto-generated)* | JWT secret (fixed for persistent sessions) |
|
||||
| `TOTP_ENCRYPTION_KEY` | **Recommended** | *(auto-generated)* | TOTP encryption key (fixed for persistent 2FA) |
|
||||
| `SERVER_PORT` | No | `8080` | Server port |
|
||||
| `ADMIN_EMAIL` | No | `admin@sub2api.local` | Admin email |
|
||||
| `ADMIN_PASSWORD` | No | *(auto-generated)* | Admin password |
|
||||
| `ADMIN_EMAIL` | No | *(auto-generated)* | Admin email (login username) |
|
||||
| `ADMIN_PASSWORD` | No | *(auto-generated)* | Admin password (8-72 bytes) |
|
||||
| `TZ` | No | `Asia/Shanghai` | Timezone |
|
||||
| `UPDATE_GITHUB_TOKEN` | No | *(empty)* | Token for `api.github.com` release checks only; asset downloads remain anonymous. |
|
||||
| `GEMINI_OAUTH_CLIENT_ID` | No | *(builtin)* | Google OAuth client ID (Gemini OAuth). Leave empty to use the built-in Gemini CLI client. |
|
||||
|
||||
@@ -43,7 +43,7 @@ services:
|
||||
- REDIS_USERNAME=${REDIS_USERNAME:-}
|
||||
- REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
||||
- REDIS_DB=${REDIS_DB:-0}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
|
||||
- JWT_SECRET=${JWT_SECRET:-}
|
||||
- SETUP_MIGRATION_TIMEOUT_SECONDS=${SETUP_MIGRATION_TIMEOUT_SECONDS:-0}
|
||||
|
||||
@@ -88,7 +88,7 @@ services:
|
||||
# =======================================================================
|
||||
# Admin Account (auto-created on first run)
|
||||
# =======================================================================
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
|
||||
|
||||
# =======================================================================
|
||||
|
||||
@@ -74,7 +74,7 @@ services:
|
||||
# =======================================================================
|
||||
# Admin Account (auto-created on first run)
|
||||
# =======================================================================
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
|
||||
|
||||
# =======================================================================
|
||||
|
||||
@@ -85,7 +85,7 @@ services:
|
||||
# =======================================================================
|
||||
# Admin Account (auto-created on first run)
|
||||
# =======================================================================
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local}
|
||||
- ADMIN_EMAIL=${ADMIN_EMAIL:-}
|
||||
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
|
||||
|
||||
# =======================================================================
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# This script prepares deployment files for Sub2API:
|
||||
# - Downloads docker-compose.local.yml and .env.example
|
||||
# - Generates secure secrets (JWT_SECRET, TOTP_ENCRYPTION_KEY, POSTGRES_PASSWORD)
|
||||
# - Generates a random admin login email (ADMIN_EMAIL)
|
||||
# - Creates necessary data directories
|
||||
#
|
||||
# After running this script, you can start services with:
|
||||
@@ -45,6 +46,14 @@ generate_secret() {
|
||||
openssl rand -hex 32
|
||||
}
|
||||
|
||||
# Generate a random admin login email so new installs never use a guessable default
|
||||
generate_admin_email() {
|
||||
local suffix
|
||||
suffix=$(openssl rand -hex 6) || return 1
|
||||
[ -n "$suffix" ] || return 1
|
||||
echo "admin-${suffix}@sub2api.local"
|
||||
}
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
@@ -104,6 +113,7 @@ main() {
|
||||
JWT_SECRET=$(generate_secret)
|
||||
TOTP_ENCRYPTION_KEY=$(generate_secret)
|
||||
POSTGRES_PASSWORD=$(generate_secret)
|
||||
ADMIN_EMAIL=$(generate_admin_email)
|
||||
|
||||
# Create .env from .env.example
|
||||
cp .env.example .env
|
||||
@@ -114,11 +124,13 @@ main() {
|
||||
sed -i "s/^JWT_SECRET=.*/JWT_SECRET=${JWT_SECRET}/" .env
|
||||
sed -i "s/^TOTP_ENCRYPTION_KEY=.*/TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}/" .env
|
||||
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=${POSTGRES_PASSWORD}/" .env
|
||||
sed -i "s/^ADMIN_EMAIL=.*/ADMIN_EMAIL=${ADMIN_EMAIL}/" .env
|
||||
else
|
||||
# BSD sed (macOS)
|
||||
sed -i '' "s/^JWT_SECRET=.*/JWT_SECRET=${JWT_SECRET}/" .env
|
||||
sed -i '' "s/^TOTP_ENCRYPTION_KEY=.*/TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}/" .env
|
||||
sed -i '' "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=${POSTGRES_PASSWORD}/" .env
|
||||
sed -i '' "s/^ADMIN_EMAIL=.*/ADMIN_EMAIL=${ADMIN_EMAIL}/" .env
|
||||
fi
|
||||
|
||||
# Create data directories
|
||||
@@ -139,6 +151,7 @@ main() {
|
||||
echo " POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}"
|
||||
echo " JWT_SECRET: ${JWT_SECRET}"
|
||||
echo " TOTP_ENCRYPTION_KEY: ${TOTP_ENCRYPTION_KEY}"
|
||||
echo " ADMIN_EMAIL: ${ADMIN_EMAIL} (admin login username)"
|
||||
echo ""
|
||||
print_warning "These credentials have been saved to .env file."
|
||||
print_warning "Please keep them secure and do not share publicly!"
|
||||
|
||||
Reference in New Issue
Block a user