Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c27fa4fe22 |
@@ -0,0 +1,46 @@
|
||||
# Email accounts
|
||||
|
||||
`/account` offers registration, password login, email verification/resend, and logout.
|
||||
`/api/account/session` returns the current account; other actions use same-origin POST.
|
||||
Passwords require at least 12 characters and at most 256 UTF-8 bytes. Only verified
|
||||
accounts can log in. Verification links expire after 30 minutes and are consumed once.
|
||||
Session tokens expire after seven days; logout deletes the current token immediately.
|
||||
Only token SHA-256 digests are stored. Passwords use individually salted scrypt.
|
||||
|
||||
## Runtime configuration
|
||||
|
||||
The existing production deployment reads `/etc/prompt.env` on ces-control. Set its
|
||||
ownership to root and mode to 0600. The operator should update SMTP_PASSWORD there
|
||||
through a secure remote session, without putting it in command arguments, repository,
|
||||
CI output, release.env, or chat. Existing compose deployment reads this file without
|
||||
copying credentials into the release directory. Do not run `docker compose config`
|
||||
without `--quiet` against the production environment because interpolation shows secrets.
|
||||
Docker administrators can inspect container environment; access to Docker is privileged.
|
||||
|
||||
Set ACCOUNT_PUBLIC_ORIGIN to the exact browser origin and SMTP_HOST=smtpdm.aliyun.com,
|
||||
SMTP_PORT=465, SMTP_USERNAME and SMTP_FROM=noreply@notice.entroia.com. TLS certificate
|
||||
validation stays enabled. Missing SMTP configuration returns a generic service failure;
|
||||
resend with the registration password can recover an account whose initial delivery failed.
|
||||
|
||||
Keep AUTH_CONFIG_FILE configured for administrator access. Missing administrator
|
||||
configuration fails closed. AUTH_DISABLED_FOR_TESTS is false by default and is enabled
|
||||
only by the disposable legacy integration stack; never enable it in production.
|
||||
Email account cookies never satisfy administrator authorization. With the current HTTP
|
||||
acceptance origin use AUTH_COOKIE_SECURE=false; use true after enabling HTTPS.
|
||||
|
||||
Limits persist in PostgreSQL: 10 logins and 3 registration/resend attempts per email per
|
||||
15 minutes, plus 300 requests per 15 minutes globally. ACCOUNT_TRUST_PROXY defaults
|
||||
false. Enable it only when a trusted ingress overwrites x-forwarded-for; this changes
|
||||
the global cap to 60 per trusted client address. Do not enable it on the direct public port.
|
||||
Limits count failures and successes. Registration/resend always give the same success
|
||||
response for existing/unknown emails, and login uses a dummy KDF for unknown accounts.
|
||||
The rate limit itself can reveal recent activity for a known email; it does not reveal
|
||||
whether an account exists. No password recovery or account deletion is included.
|
||||
|
||||
## Verification
|
||||
|
||||
ces-control runs crypto/origin tests, PostgreSQL verification-token replay races,
|
||||
expired/revoked sessions, concurrent limit consumption and unverified login rejection.
|
||||
Production-auth exercises verify that account cookies cannot authorize legacy writes.
|
||||
Actual SMTP delivery and visual acceptance at http://8.211.154.134:18131/account require
|
||||
operator runtime configuration and the normal manually approved deployment.
|
||||
@@ -9,7 +9,10 @@ export function proxy(request: NextRequest) {
|
||||
if (path === '/brand-mark.svg' || path === '/login' || path === '/api/auth/login' || path === '/api/auth/logout' || path === '/api/health' || path === '/api/ready' || path.startsWith('/_next/static/')) return NextResponse.next({headers:responseHeaders});
|
||||
let config;
|
||||
try { config = authConfig(); } catch { return NextResponse.json({error:'登录服务配置不可用'}, {status:503,headers:responseHeaders}); }
|
||||
if (!config) return NextResponse.next();
|
||||
if (!config) {
|
||||
if (process.env.AUTH_DISABLED_FOR_TESTS === 'true' && process.env.AUTH_CONFIG_FILE === '') return NextResponse.next();
|
||||
return NextResponse.json({error:'管理员登录服务尚未配置'}, {status:503,headers:responseHeaders});
|
||||
}
|
||||
const bearer = request.headers.get('authorization');
|
||||
const token = bearer?.startsWith('Bearer ') ? bearer.slice(7) : request.cookies.get(SESSION_COOKIE)?.value;
|
||||
if (validSession(token,config)) {
|
||||
|
||||
@@ -12,6 +12,7 @@ x-waterfall-wiki-environment: &waterfall-wiki-environment
|
||||
CHROMIUM_PATH: /usr/bin/chromium
|
||||
RENDER_ORIGIN: http://waterfall-wiki:3000
|
||||
AUTH_CONFIG_FILE: ${AUTH_CONFIG_FILE:-}
|
||||
AUTH_DISABLED_FOR_TESTS: ${AUTH_DISABLED_FOR_TESTS:-false}
|
||||
AUTH_COOKIE_SECURE: ${AUTH_COOKIE_SECURE:-true}
|
||||
ACCOUNT_PUBLIC_ORIGIN: ${ACCOUNT_PUBLIC_ORIGIN:-http://8.211.154.134:18131}
|
||||
ACCOUNT_TRUST_PROXY: ${ACCOUNT_TRUST_PROXY:-false}
|
||||
|
||||
@@ -11,6 +11,8 @@ cleanup(){ code=$?; if [ "$code" -ne 0 ]; then compose logs --tail 160 waterfall
|
||||
trap cleanup EXIT
|
||||
# Random credentials exist only for this disposable stack; no host Node required.
|
||||
docker run --rm --entrypoint node "$WATERFALL_WIKI_IMAGE" -e "const c=require('crypto');const hex=()=>c.randomBytes(24).toString('hex');console.log('POSTGRES_PASSWORD='+hex()+'\nS3_ACCESS_KEY='+hex()+'\nS3_SECRET_KEY='+hex())" > "$TEST_ENV"
|
||||
# Explicitly isolate legacy unauthenticated integration coverage; production fails closed.
|
||||
printf '\nAUTH_DISABLED_FOR_TESTS=true\n' >> "$TEST_ENV"
|
||||
compose up -d --no-build --wait --wait-timeout 120 postgres objects
|
||||
compose run --rm --no-deps migrate
|
||||
compose up -d --no-build --wait --wait-timeout 150 waterfall-wiki waterfall-wiki-worker
|
||||
|
||||
Reference in New Issue
Block a user