# 📋 گزارش بازنویسی و ممیزی Red Fox

> سند کاری: چه‌کارها روی فورک Red Fox (برگرفته از Faoxima) انجام شده است.
> تاریخ گزارش: ۱۴۰۵/۰۵/۱۸ (۲۰۲۶-۰۸-۰۹)

---

## ۱) خلاصه‌ی کارهای انجام‌شده

| # | کار | وضعیت |
|---|-----|-------|
| 1 | دریافت و کپی پروژه‌ی پایه (Faoxima) به دایرکتوری `RedFox` | ✅ |
| 2 | بازنویسی کامل برند Faoxima → **Red Fox** (رد فاکس) | ✅ |
| 3 | بازنویسی شناسه‌های فنی (کلاس‌ها/توابع/globalها) به‌صورت **یکپارچه** | ✅ |
| 4 | نصب PHP 8.4 و PHPStan برای تحلیل استاتیک | ✅ |
| 5 | بررسی نحویِ همه‌ی فایل‌ها (`php -l`) — **۰ خطا** | ✅ |
| 6 | ممیزی امنیتی (SQLi, RCE, Shell, رمز پیش‌فرض) | ✅ |
| 7 | رفع باگ واقعی در `api/statbot.php` | ✅ |
| 8 | بهبود امنیتی: حذف رمز پیش‌فرض ضعیف phpMyAdmin در `install.sh` | ✅ |
| 9 | به‌روزرسانی README، نسخه و composer.json با ذکر منبع GPLv3 | ✅ |

---

## ۲) جزئیات بازنویسی برند (Rebrand)

ابزار اختصاصی Python با Regex (lookahead/lookbehind) نوشته شد تا جایگزینی **دقیق و امن** باشد:

- `FAOXIMA` → `REDFOX`
- `FaoximaResponse`, `FaoximaLogger`, … → `RedFoxResponse`, … (۶ کلاس)
- `faoxima_apply_curl_proxy`, `faoxima_*` → `redfox_*` (**۳۶ تابع** — حتی داخل رشته‌های `function_exists('...')`)
- `__faoxima_*` → `__redfox_*` (globalهای کش)
- متن نمایشی: `Faoxima` → `Red Fox` ، `فاکسیما` → `رد فاکس`

**نکته‌ی بحرانی که کنترل شد:** تابع `faoxima_apply_curl_proxy` هم به‌صورت شناسه و هم به‌صورت **رشته داخل `function_exists()`** استفاده می‌شد. جایگزینی یکپارچه تضمین کرد که تعریف و استفاده دقیقاً مطابق بمانند.

**آمار:** ۱۲۳ فایل تغییر کرد، ۶۷ فایل اکنون حاوی برند Red Fox هستند.
**تأیید:** بعد از بازنویسی، `php -l` روی هر ۲۰۳ فایل = **صفر خطای نحوی**.

---

## ۳) نتیجه‌ی ممیزی امنیتی و باگ‌یابی

### ✅ نقاط قوت کد (کد دفاعیِ خوب)
- **تزریق SQL:** تابع‌های `select()`/`update()` هسته، از **prepared statement** و بایند کردن پارامتر استفاده می‌کنند؛ نام جدول/فیلد با whitelist پاک‌سازی می‌شود. → مقاوم در برابر SQLi.
- **اجرای دستور سیستم:** `backupbot.php` برای تمام مقادیر از `escapeshellarg()` استفاده می‌کند؛ `bootstrap.php` دستورات ثابت می‌فرستد. → امن.
- معماری پاسخ‌ها (`RedFoxResponse`) با `exit` اجرا را متوقف می‌کند.

### 🐛 باگ واقعی رفع‌شده: `api/statbot.php`
- **مشکل:** متغیر `$data` استفاده می‌شد ولی **هرگز تعریف نمی‌شد**. همه‌ی endpointهای دیگر (`invoice.php`, `payment.php`, `service.php` …) بدنه‌ی JSON درخواست را با `json_decode(file_get_contents("php://input"))` می‌خواندند، اما این فایل نه.
- **اثر:** لاگ API همیشه `null` ذخیره می‌شد و هشدار PHP تولید می‌گردید.
- **راه‌حل:** افزودن خواندن بدنه‌ی JSON + پیش‌فرض امن `[]` + دسترسی امن به `$data['actions']`.

### 🔒 بهبود امنیتی: `install.sh`
- **مشکل:** رمز پیش‌فرض phpMyAdmin/MySQL برابر `redfoxhipass` (قبلاً `faoximahipass`) بود — یک رمز ضعیف و قابل‌حدس.
- **راه‌حل:** تولید یک رمز **تصادفیِ قوی** در زمان نصب با `openssl rand` (و fallback `/dev/urandom`) و استفاده از آن برای debconf.

### ⚠️ مورد بررسی‌شده ولی «بدون نیاز به تغییر» (code smell، نه باگ)
- `re/rx/admin/index.php` دارای `eval($__rx_code)` است. این **آسیب‌پذیری RCE نیست**: ورودی `eval` از فهرست فایل‌های محلی (`manifest.php`) خوانده و کنکات می‌شود، نه از ورودی کاربر. الگوی تقسیم فایل‌های لگاسی است.

### ℹ️ نویز PHPStan
بخش بزرگی از هشدارهای PHPStan از نوع «Function/Class not found» و «$pdo might not be defined» بود که **اشتباه مثبت** محسوب می‌شوند (توابع سراسری و `$pdo` از طریق `include`/`getDatabaseConnection()` در زمان اجرا بارگذاری می‌شوند و PHPStan آن‌ها را نمی‌بیند).

---

## ۴) تغییرات فایل‌های کلیدی

| فایل | تغییر |
|------|-------|
| `api/statbot.php` | 🐛 رفع باگ تعریف `$data` + دسترسی امن به `actions` |
| `install.sh` | 🔒 رمز تصادفی phpMyAdmin |
| `README.md` | 🦊 بازنویسی کامل با برند Red Fox + ذکر منبع GPLv3 |
| `version` | `0.0.2` → `1.0.0-redfox` |
| `composer.json` | نام/توضیحات به Red Fox |
| ۱۲۳ فایل کد | تغییر یکپارچه شناسه‌ها و برند |

---

## ۵) محدودیت‌ها (شفاف)
- **اجره‌ی زنده‌ی ربات تست نشده است** چون نیازمند توکن تلگرام، دیتابیس، پنل‌های واقعی و کلید درگاه‌های پرداخت است.
- تحلیل روی **کد استاتیک** انجام شد؛ خطاهای زمان‌اجرای وابسته به محیط واقعی را پوشش نمی‌دهد.
- «رفع همه‌ی باگ‌ها» بدون محیط تست واقعی قابل‌تضمین نیست؛ باگ‌های قطعیِ یافته‌شده رفع شدند.

---

## ۶) پیشنهاد برای ادامه
1. راه‌اندازی محیط تست (توکن + دیتابیس) و اجرای سناریوی کامل خرید → تایید عملی.
2. فعال‌سازی PHPStan در CI با baseline (به‌دلیل معماری include-based).
3. افزودن تست‌های خودکار برای درگاه‌های پرداخت.
4. در صورت تمایل، می‌توان الگوی `eval` در `re/rx/` را با `require_once` واقعی جایگزین کرد (نیازمند ریفکتور بیشتر).

---

## ۷) 🆕 ارتقای ماژول ۲ — تأیید خودکار رسید کارت‌به‌کارت

**کشف مهم:** این قابلیت از قبل در `cronbot/croncard.php` وجود داشت، ولی ۳ مشکل داشت که اصلاح شد:

| # | مشکل | اصلاح Red Fox |
|---|------|---------------|
| ۱ | **سقف یک‌ساعته‌ی سفت‌وسخت** (`since_start >= 3600 → skip`): رسیدی که ادمین بیش از ۱ ساعت معطل می‌ذاشت، دیگه هرگز خودکار تأیید نمی‌شد و معلق می‌موند. | خط حذف شد؛ حالا هر رسیدِ `waiting` پس از گذشت `timeauto_not_verify` دقیقه، بدون توجه به مدت غیبت ادمین، تأیید می‌شه. |
| ۲ | **اعلان «بررسی بعدی» به ادمین نبود.** | بعد از تأیید خودکار + شارژ حساب، به هر ادمین (با نقش `administrator`) پیامی با عنوان «تأیید خودکار رسید — نیازمند بررسی بعدی» ارسال می‌شه شامل کد پیگیری، آیدی کاربر، مبلغ و روش. با try/catch محافظت می‌شه تا جریان اصلی تأیید خراب نشه. |
| ۳ | **برچسب گمراه‌کننده در پنل وب:** «حذف خودکار سفارش تأییدنشده». | در `panel/settings.php` به «تأیید خودکار رسید پس از این زمان (دقیقه) — در صورت تأیید نشدن دستی» تغییر کرد. (برچسب داخل خود ربات از قبل درست بود.) |

**فایل‌های تغییرکرده:** `cronbot/croncard.php`، `panel/settings.php`.
**تأیید:** `php -l` روی این دو فایل + کل پروژه = **۰ خطای نحوی**.

### ⚠️ نکته‌ی رفتاری مهم (هشدار به ادمین)
با حذف سقف یک‌ساعته، **در اولین اجرای کرون بعد از آپدیت**، تمام رسیدهای `waiting` که از زمان `timeauto_not_verify` بیشتر گذشته (حتی رسیدهای قدیمی‌تر)، تا سقف ۵۰ مورد در هر اجرا، خودکار تأیید و حساب کاربران شارژ می‌شه. اگر رسید معلقی داری که نمی‌خوای تأیید بشه، **قبل از آپدیت آن‌ها را دستی رد/حذف کن**.

### 🔧 نحوه‌ی فعال‌سازی (پس از آپدیت)
1. در پنل وب ← تنظیمات: «تأیید خودکار رسید پس از این زمان» را روی تعداد دقیقه‌ی دلخواه تنظیم کن (مثلاً ۳۰).
2. تایید شد که تاگل «تایید خودکار سفارش (بدون تایید رسید)» روشن باشد (اگر قبلاً روشن نبود).
3. مطمئن شو کرون `cronbot/croncard.php` در حال اجراست.

---

---

## ۸) 🆕 ارتقای ماژول ۱ — مدیریت نمایندگان در پنل وب + محافظت اعتبار

این ماژول شامل دو بخش است:

### ۸-۱) صفحه‌ی مدیریت نمایندگان در پنل وب (جدید)
فایل جدید **`panel/agents.php`** + ورودی منو «مدیریت نمایندگان» در `header.php`. این صفحه روی فیلدهای **موجود** سیستم نمایندگی کار می‌کند و منطق را **دقیقاً مطابق گردش‌کار ربات** تکرار می‌کند:

| امکان | توضیح |
|------|-------|
| لیست درخواست‌های در انتظار | از جدول `Requestagent` (status=waiting) |
| تأیید درخواست | status→accept، type→n، user.agent→n، expire→NULL + پیام به کاربر (مانند `cfmacea_`) |
| رد درخواست | status→reject، type→None، **بازگشت هزینه‌ی درخواست** (`agentreqprice`) به کیف پول + پیام (مانند `cfmreja_`) |
| تغییر نوع نماینده | n (عادی) ↔ n2 (پیشرفته) |
| شارژ اعتبار کیف پول | Balance += مبلغ + پیام به نماینده |
| تنظیم سقف بدهی (maxbuyagent) | حداکثر بدهی مجاز نماینده |
| لغو نمایندگی | user.agent→f + پیام (مانند `finance.php`) |

> امنیت: فقط کاربر با `rule='administrator'` می‌تواند عملیات انجام دهد. نوتیفیکیشن‌ها از طریق توابع `botapi.php` ارسال می‌شوند.

### ۸-۲) محافظت اعتبار نماینده از منفی‌شدن (کف صفر) + نوتیفیکیشن
طبق درخواست مالک: «کیف پول/اعتبار نماینده نباید هنگام فروش کانفیگ منفی شود؛ اگر منفی می‌شد، فروش متوقف و به نماینده (برای شارژ) و ادمین (اطلاع) پیام داده شود.»

**تغییر در `re/rx/index/finalize.php` (مسیر فروش کانفیگ):**
- گارد جدید: اگر نماینده‌ی پیشرفته (`n2`) موجودی کافی برای فروش نداشته باشد (موجودی − قیمت < ۰)، فروش متوقف می‌شود و:
  - 📨 به **نماینده** پیام «موجودی کافی نیست، شارژ کنید» (با مبلغ لازم و موجودی فعلی).
  - 📨 به **تمام ادمین‌ها** پیام «تلاش ناموفق فروش توسط نماینده + اطلاعات».
- مقدار `allowNeg` در `balance_atomic_charge` برای n2 از `maxbuyagent` به **۰** تغییر یافت تا حتی در سطح دیتابیس منفی مجاز نباشد (گارد بالاتر از قبل موجودی کافی را تضمین می‌کند، پس فروش‌های قانونی دست‌نخورده می‌مانند).
- نماینده‌ی عادی (`n`) از قبل از طریق مسیر پرداخت هدایت می‌شود و منفی نمی‌شد؛ لذا تغییر فقط روی مسیر n2 (تنها مسیر منفی‌شونده) اثر دارد.

**نکته‌ی رفتاری مهم:** با این تغییر، نماینده‌ی پیشرفته (n2) دیگر نمی‌تواند بدهی (تا سقف maxbuyagent) بگیرد؛ یعنی قابلیت اعتبار/بدهی n2 عملاً غیرفعال می‌شود و نماینده باید **قبل از فروش، کیف پول را شارژ کند**. اگر می‌خواهی بدهی n2 حفظ شود، فقط کافیست گارد را به جای «کف صفر» روی سقف دلخواه تنظیم کنی (قابل تغییر است).

**فایل‌های تغییرکرده:** `panel/agents.php` (جدید)، `panel/header.php`، `re/rx/index/finalize.php`.
**تأیید:** `php -l` روی این فایل‌ها + کل پروژه = **۰ خطای نحوی**.

---

🦊 *Red Fox — GPLv3*
