fix(security): a production server refuses to start until its keys, allowed origins and test login are right (REL-01, REL-03, SEC-04)

With NODE_ENV=production (always, in the Docker image) the API lists
every problem at once and does not start while any of these holds:
- OTP_MASTER_CODE is set: the fixed test login signs in any customer. A
  test server built from the production image must say so with
  TEST_SERVER_ALLOW_MASTER_CODE=yes.
- JWT_CUSTOMER_SECRET is missing, equal to JWT_SECRET, or under 32
  characters.
- JWT_SECRET is missing, the published dev key, or under 32 characters.
- CORS_ORIGINS is empty, `*`, or not full origins. It no longer falls
  back to allow-all.

Checked live: a misconfigured start lists all four problems; a correct
one starts, answers the allowed origin, and blocks any other.
docs/SERVER-SETUP-CHECKLIST.md is the operator's list. DELIVERY.md,
docker-compose.yml and .env.example are updated to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-10-08 17:00:17 +03:30
co-authored by Claude Opus 5.5
parent d91dcf197b
commit 9d3b5388ba
8 changed files with 256 additions and 42 deletions
+75
View File
@@ -0,0 +1,75 @@
# فهرست تنظیمات سرور اصلی
برای کسی که به سرور اصلی (سرور واقعیِ مشتری‌ها) دسترسی دارد.
از این نسخه به بعد، سرور تا وقتی سه مورد زیر درست نشده باشند **روشن نمی‌شود**.
در گزارش سرور، فهرست کامل ایرادها با هم چاپ می‌شود؛ همه را درست کنید و یک بار
دوباره راه‌اندازی کنید.
این بررسی فقط در حالت اصلی (`NODE_ENV=production`) انجام می‌شود. تصویر داکرِ
سرور همیشه در این حالت است.
---
## ۱. حذف کد ثابت ورود آزمایشی
| متغیر | مقدار درست |
|---|---|
| `OTP_MASTER_CODE` | **خالی** یا کلاً حذف‌شده |
تا وقتی این کد هست، هر کسی که آن را بداند وارد حساب **هر** مشتری می‌شود.
> سرور **آزمایشی**ای که عمداً این کد را لازم دارد، باید کنارش
> `TEST_SERVER_ALLOW_MASTER_CODE=yes` بگذارد. این را **هرگز** روی سرور اصلی
> نگذارید.
## ۲. کلید جدا برای مشتری‌ها
| متغیر | مقدار درست |
|---|---|
| `JWT_SECRET` | یک رشته‌ی تصادفی، دست‌کم ۳۲ نویسه (کلید ورود مدیرها) |
| `JWT_CUSTOMER_SECRET` | یک رشته‌ی تصادفیِ **دیگر**، دست‌کم ۳۲ نویسه (کلید ورود مشتری‌ها و کارشناس‌ها) |
دو مقدار **نباید یکی باشند**. ساختن مقدار تصادفی، روی هر سیستمی که Node دارد:
```
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```
دو بار اجرا کنید و هر خروجی را برای یکی از دو متغیر بگذارید.
⚠ **عوض کردن این کلیدها همه را از حساب بیرون می‌کند.** مدیرها و مشتری‌ها
یک بار دوباره وارد می‌شوند. اطلاعات کسی از بین نمی‌رود.
⚠ اگر `ACCOUNTING_SECRET_KEY` خالی باشد، رمز ذخیره‌شده‌ی نرم‌افزار حسابداری از
`JWT_SECRET` ساخته می‌شود. با عوض شدن `JWT_SECRET` باید یک بار دوباره در
«تنظیمات حسابداری» پنل وارد شوید. بهتر است `ACCOUNTING_SECRET_KEY` هم یک مقدار
تصادفیِ جدا بگیرد و دیگر عوض نشود.
## ۳. نشانی‌های مجاز
| متغیر | مقدار درست |
|---|---|
| `CORS_ORIGINS` | نشانی کامل پنل و اپ‌ها، با ویرگول جدا |
نمونه:
```
CORS_ORIGINS=https://adm.henzagold.ir,https://app.henzagold.ir,https://app2.henzagold.ir
```
- هر نشانی با `https://` شروع شود و **مسیر نداشته باشد**؛ مثلاً `/admin` در
آخرش نیاید.
- هر دامنه‌ای که پنل یا یکی از دو اپ از آن باز می‌شود باید در فهرست باشد؛
وگرنه آن صفحه نمی‌تواند با سرور حرف بزند.
- `*` پذیرفته نمی‌شود.
---
## بعد از تنظیم
1. سرور را دوباره راه‌اندازی کنید.
2. در گزارش سرور باید `Nest application successfully started` دیده شود.
اگر سرور بالا نیامد، فهرست ایرادها همان‌جا چاپ شده است.
3. پنل مدیریت و هر دو اپ را باز کنید و یک بار وارد شوید.
4. ورود مشتری با پیامک را امتحان کنید. کد ثابت دیگر نباید کار کند.