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:
shaw
2026-10-07 09:27:36 +08:00
parent d97ccc952f
commit 6e315616ed
16 changed files with 368 additions and 57 deletions
+5 -3
View File
@@ -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=
+1 -1
View File
@@ -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
View File
@@ -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. |
+1 -1
View File
@@ -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}
+1 -1
View File
@@ -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:-}
# =======================================================================
+1 -1
View File
@@ -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:-}
# =======================================================================
+1 -1
View File
@@ -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:-}
# =======================================================================
+13
View File
@@ -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!"