Browse Source

refactor: use better route filter & unify route name

M1Screw 2 years ago
parent
commit
8a4aed3391
50 changed files with 559 additions and 491 deletions
  1. 115 101
      app/routes.php
  2. 20 20
      composer.lock
  3. 2 2
      resources/views/tabler/admin/header.tpl
  4. 1 1
      resources/views/tabler/admin/log/money.tpl
  5. 1 1
      resources/views/tabler/admin/log/traffic.tpl
  6. 1 1
      resources/views/tabler/admin/node/edit.tpl
  7. 1 1
      resources/views/tabler/admin/setting/email.tpl
  8. 3 3
      resources/views/tabler/admin/setting/im.tpl
  9. 1 1
      resources/views/tabler/user/header.tpl
  10. 67 0
      src/Controllers/Admin/DetectBanController.php
  11. 0 236
      src/Controllers/Admin/DetectController.php
  12. 72 0
      src/Controllers/Admin/DetectLogController.php
  13. 126 0
      src/Controllers/Admin/DetectRuleController.php
  14. 1 1
      src/Controllers/Admin/InviteController.php
  15. 1 1
      src/Controllers/Admin/NodeController.php
  16. 2 2
      src/Controllers/Admin/Setting/BillingController.php
  17. 2 2
      src/Controllers/Admin/Setting/CaptchaController.php
  18. 2 2
      src/Controllers/Admin/Setting/CronController.php
  19. 2 2
      src/Controllers/Admin/Setting/EmailController.php
  20. 2 2
      src/Controllers/Admin/Setting/FeatureController.php
  21. 2 2
      src/Controllers/Admin/Setting/ImController.php
  22. 2 2
      src/Controllers/Admin/Setting/RefController.php
  23. 2 2
      src/Controllers/Admin/Setting/RegController.php
  24. 3 3
      src/Controllers/Admin/Setting/SubController.php
  25. 2 2
      src/Controllers/Admin/Setting/SupportController.php
  26. 1 1
      src/Controllers/Admin/SubLogController.php
  27. 1 1
      src/Controllers/Admin/TicketController.php
  28. 1 1
      src/Controllers/Admin/UserController.php
  29. 37 0
      src/Controllers/User/DetectLogController.php
  30. 1 1
      src/Controllers/User/DetectRuleController.php
  31. 1 1
      src/Controllers/User/InfoController.php
  32. 1 1
      src/Controllers/User/InvoiceController.php
  33. 0 62
      src/Controllers/User/LogController.php
  34. 1 1
      src/Controllers/User/MoneyController.php
  35. 1 1
      src/Controllers/User/OrderController.php
  36. 1 1
      src/Controllers/User/ProductController.php
  37. 1 1
      src/Controllers/User/ServerController.php
  38. 34 0
      src/Controllers/User/SubLogController.php
  39. 4 4
      src/Controllers/User/TicketController.php
  40. 1 1
      src/Middleware/AdminApi.php
  41. 2 2
      src/Middleware/Auth.php
  42. 1 1
      src/Middleware/NodeApi.php
  43. 25 0
      src/Middleware/UserApi.php
  44. 1 1
      src/Models/DetectRule.php
  45. 0 3
      src/Services/Auth.php
  46. 2 2
      src/Services/Bot/Telegram/Callback.php
  47. 1 7
      src/Services/Config.php
  48. 4 4
      src/Services/GeoIP2.php
  49. 1 1
      src/Utils/Tools.php
  50. 3 3
      tests/App/Services/ConfigTest.php

+ 115 - 101
app/routes.php

@@ -22,6 +22,10 @@ return static function (Slim\App $app): void {
     // OAuth
     $app->post('/oauth/{type}', App\Controllers\OAuthController::class . ':index');
     $app->get('/oauth/{type}', App\Controllers\OAuthController::class . ':index');
+    // 传统订阅(SS/V2Ray/Trojan etc.)
+    $app->get('/link/{token}', App\Controllers\SubController::class . ':getTraditionalSubContent');
+    // 通用订阅(Json/Clash/SIP008)
+    $app->get('/sub/{token}/{subtype}', App\Controllers\SubController::class . ':getUniversalSubContent');
     // User Center
     $app->group('/user', static function (RouteCollectorProxy $group): void {
         $group->get('', App\Controllers\UserController::class . ':index');
@@ -32,25 +36,27 @@ return static function (Slim\App $app): void {
         $group->get('/announcement', App\Controllers\UserController::class . ':announcement');
         // 文档
         $group->get('/docs', App\Controllers\User\DocsController::class . ':index');
-        $group->get('/docs/{id}/view', App\Controllers\User\DocsController::class . ':detail');
+        $group->get('/docs/{id:[0-9]+}/view', App\Controllers\User\DocsController::class . ':detail');
         // 个人资料
         $group->get('/profile', App\Controllers\UserController::class . ':profile');
         $group->get('/invite', App\Controllers\UserController::class . ':invite');
         // 封禁
         $group->get('/banned', App\Controllers\UserController::class . ':banned');
         // 节点
-        $group->get('/server', App\Controllers\User\ServerController::class . ':server');
+        $group->get('/server', App\Controllers\User\ServerController::class . ':index');
         // 动态倍率
         $group->get('/rate', App\Controllers\User\RateController::class . ':index');
         $group->post('/rate', App\Controllers\User\RateController::class . ':ajax');
-        // 审计
-        $group->get('/detect', App\Controllers\User\DetectController::class . ':index');
+        // 审计规则
+        $group->get('/detect', App\Controllers\User\DetectRuleController::class . ':index');
+        // 审计记录
+        $group->get('/detect/log', App\Controllers\User\DetectLogController::class . ':index');
         // 工单
-        $group->get('/ticket', App\Controllers\User\TicketController::class . ':ticket');
-        $group->get('/ticket/create', App\Controllers\User\TicketController::class . ':ticketCreate');
-        $group->post('/ticket', App\Controllers\User\TicketController::class . ':ticketAdd');
-        $group->get('/ticket/{id}/view', App\Controllers\User\TicketController::class . ':ticketView');
-        $group->put('/ticket/{id}', App\Controllers\User\TicketController::class . ':ticketUpdate');
+        $group->get('/ticket', App\Controllers\User\TicketController::class . ':index');
+        $group->get('/ticket/create', App\Controllers\User\TicketController::class . ':create');
+        $group->post('/ticket', App\Controllers\User\TicketController::class . ':add');
+        $group->get('/ticket/{id:[0-9]+}/view', App\Controllers\User\TicketController::class . ':detail');
+        $group->put('/ticket/{id:[0-9]+}', App\Controllers\User\TicketController::class . ':update');
         // 资料编辑
         $group->get('/edit', App\Controllers\User\InfoController::class . ':index');
         $group->post('/email', App\Controllers\User\InfoController::class . ':updateEmail');
@@ -68,32 +74,28 @@ return static function (Slim\App $app): void {
         $group->post('/kill', App\Controllers\User\InfoController::class . ':sendToGulag');
         // 发送验证邮件
         $group->post('/send', App\Controllers\AuthController::class . ':sendVerify');
-        // 登出
-        $group->get('/logout', App\Controllers\UserController::class . ':logout');
         // MFA
         $group->post('/ga_check', App\Controllers\User\MFAController::class . ':checkGa');
         $group->post('/ga_set', App\Controllers\User\MFAController::class . ':setGa');
         $group->post('/ga_reset', App\Controllers\User\MFAController::class . ':resetGa');
         // 深色模式切换
         $group->post('/switch_theme_mode', App\Controllers\UserController::class . ':switchThemeMode');
-        // 记录
-        $group->get('/subscribe/log', App\Controllers\User\LogController::class . ':subscribe');
-        $group->get('/detect/log', App\Controllers\User\LogController::class . ':detect');
+        // 订阅记录
+        $group->get('/subscribe', App\Controllers\User\SubLogController::class . ':index');
         // 账户余额
-        $group->get('/money', App\Controllers\User\MoneyController::class . ':money');
-        // 礼品卡兑换
+        $group->get('/money', App\Controllers\User\MoneyController::class . ':index');
         $group->post('/giftcard', App\Controllers\User\MoneyController::class . ':applyGiftCard');
         // 产品页面
-        $group->get('/product', App\Controllers\User\ProductController::class . ':product');
+        $group->get('/product', App\Controllers\User\ProductController::class . ':index');
         // 订单页面
-        $group->get('/order', App\Controllers\User\OrderController::class . ':order');
+        $group->get('/order', App\Controllers\User\OrderController::class . ':index');
         $group->get('/order/create', App\Controllers\User\OrderController::class . ':create');
         $group->post('/order/create', App\Controllers\User\OrderController::class . ':process');
-        $group->get('/order/{id}/view', App\Controllers\User\OrderController::class . ':detail');
+        $group->get('/order/{id:[0-9]+}/view', App\Controllers\User\OrderController::class . ':detail');
         $group->post('/order/ajax', App\Controllers\User\OrderController::class . ':ajax');
         // 账单页面
-        $group->get('/invoice', App\Controllers\User\InvoiceController::class . ':invoice');
-        $group->get('/invoice/{id}/view', App\Controllers\User\InvoiceController::class . ':detail');
+        $group->get('/invoice', App\Controllers\User\InvoiceController::class . ':index');
+        $group->get('/invoice/{id:[0-9]+}/view', App\Controllers\User\InvoiceController::class . ':detail');
         $group->post('/invoice/pay_balance', App\Controllers\User\InvoiceController::class . ':payBalance');
         $group->post('/invoice/ajax', App\Controllers\User\InvoiceController::class . ':ajax');
         // 新优惠码系统
@@ -104,6 +106,8 @@ return static function (Slim\App $app): void {
         $group->get('/payment/return/{type}', App\Services\Payment::class . ':returnHTML');
         // Get Clients
         $group->get('/clients/{name}', App\Controllers\User\ClientController::class . ':getClients');
+        // 登出
+        $group->get('/logout', App\Controllers\UserController::class . ':logout');
     })->add(new Auth());
 
     $app->group('/payment', static function (RouteCollectorProxy $group): void {
@@ -138,61 +142,63 @@ return static function (Slim\App $app): void {
         $group->get('/node', App\Controllers\Admin\NodeController::class . ':index');
         $group->get('/node/create', App\Controllers\Admin\NodeController::class . ':create');
         $group->post('/node', App\Controllers\Admin\NodeController::class . ':add');
-        $group->get('/node/{id}/edit', App\Controllers\Admin\NodeController::class . ':edit');
-        $group->post('/node/{id}/password_reset', App\Controllers\Admin\NodeController::class . ':resetNodePassword');
-        $group->post('/node/{id}/copy', App\Controllers\Admin\NodeController::class . ':copy');
-        $group->put('/node/{id}', App\Controllers\Admin\NodeController::class . ':update');
-        $group->delete('/node/{id}', App\Controllers\Admin\NodeController::class . ':delete');
+        $group->get('/node/{id:[0-9]+}/edit', App\Controllers\Admin\NodeController::class . ':edit');
+        $group->post('/node/{id:[0-9]+}/reset', App\Controllers\Admin\NodeController::class . ':reset');
+        $group->post('/node/{id:[0-9]+}/copy', App\Controllers\Admin\NodeController::class . ':copy');
+        $group->put('/node/{id:[0-9]+}', App\Controllers\Admin\NodeController::class . ':update');
+        $group->delete('/node/{id:[0-9]+}', App\Controllers\Admin\NodeController::class . ':delete');
         $group->post('/node/ajax', App\Controllers\Admin\NodeController::class . ':ajax');
         // Ticket
         $group->get('/ticket', App\Controllers\Admin\TicketController::class . ':index');
         $group->post('/ticket', App\Controllers\Admin\TicketController::class . ':add');
-        $group->get('/ticket/{id}/view', App\Controllers\Admin\TicketController::class . ':ticketView');
-        $group->put('/ticket/{id}/close', App\Controllers\Admin\TicketController::class . ':close');
-        $group->put('/ticket/{id}', App\Controllers\Admin\TicketController::class . ':update');
-        $group->put('/ticket/{id}/ai', App\Controllers\Admin\TicketController::class . ':updateAI');
-        $group->delete('/ticket/{id}', App\Controllers\Admin\TicketController::class . ':delete');
+        $group->get('/ticket/{id:[0-9]+}/view', App\Controllers\Admin\TicketController::class . ':detail');
+        $group->put('/ticket/{id:[0-9]+}/close', App\Controllers\Admin\TicketController::class . ':close');
+        $group->put('/ticket/{id:[0-9]+}', App\Controllers\Admin\TicketController::class . ':update');
+        $group->put('/ticket/{id:[0-9]+}/ai', App\Controllers\Admin\TicketController::class . ':updateAI');
+        $group->delete('/ticket/{id:[0-9]+}', App\Controllers\Admin\TicketController::class . ':delete');
         $group->post('/ticket/ajax', App\Controllers\Admin\TicketController::class . ':ajax');
         // Ann
         $group->get('/announcement', App\Controllers\Admin\AnnController::class . ':index');
         $group->get('/announcement/create', App\Controllers\Admin\AnnController::class . ':create');
         $group->post('/announcement', App\Controllers\Admin\AnnController::class . ':add');
-        $group->get('/announcement/{id}/edit', App\Controllers\Admin\AnnController::class . ':edit');
-        $group->put('/announcement/{id}', App\Controllers\Admin\AnnController::class . ':update');
-        $group->delete('/announcement/{id}', App\Controllers\Admin\AnnController::class . ':delete');
+        $group->get('/announcement/{id:[0-9]+}/edit', App\Controllers\Admin\AnnController::class . ':edit');
+        $group->put('/announcement/{id:[0-9]+}', App\Controllers\Admin\AnnController::class . ':update');
+        $group->delete('/announcement/{id:[0-9]+}', App\Controllers\Admin\AnnController::class . ':delete');
         $group->post('/announcement/ajax', App\Controllers\Admin\AnnController::class . ':ajax');
         // Docs
         $group->get('/docs', App\Controllers\Admin\DocsController::class . ':index');
         $group->get('/docs/create', App\Controllers\Admin\DocsController::class . ':create');
         $group->post('/docs', App\Controllers\Admin\DocsController::class . ':add');
         $group->post('/docs/generate', App\Controllers\Admin\DocsController::class . ':generate');
-        $group->get('/docs/{id}/edit', App\Controllers\Admin\DocsController::class . ':edit');
-        $group->put('/docs/{id}', App\Controllers\Admin\DocsController::class . ':update');
-        $group->delete('/docs/{id}', App\Controllers\Admin\DocsController::class . ':delete');
+        $group->get('/docs/{id:[0-9]+}/edit', App\Controllers\Admin\DocsController::class . ':edit');
+        $group->put('/docs/{id:[0-9]+}', App\Controllers\Admin\DocsController::class . ':update');
+        $group->delete('/docs/{id:[0-9]+}', App\Controllers\Admin\DocsController::class . ':delete');
         $group->post('/docs/ajax', App\Controllers\Admin\DocsController::class . ':ajax');
         // 审计
-        $group->get('/detect', App\Controllers\Admin\DetectController::class . ':detect');
-        $group->get('/detect/create', App\Controllers\Admin\DetectController::class . ':create');
-        $group->post('/detect/add', App\Controllers\Admin\DetectController::class . ':add');
-        $group->delete('/detect/{id}', App\Controllers\Admin\DetectController::class . ':delete');
-        $group->post('/detect/ajax', App\Controllers\Admin\DetectController::class . ':ajaxRule');
-        $group->get('/detect/log', App\Controllers\Admin\DetectController::class . ':log');
-        $group->post('/detect/log/ajax', App\Controllers\Admin\DetectController::class . ':ajaxLog');
-        $group->get('/detect/ban', App\Controllers\Admin\DetectController::class . ':ban');
-        $group->post('/detect/ban/ajax', App\Controllers\Admin\DetectController::class . ':ajaxBan');
+        $group->get('/detect', App\Controllers\Admin\DetectRuleController::class . ':index');
+        $group->get('/detect/create', App\Controllers\Admin\DetectRuleController::class . ':create');
+        $group->post('/detect/add', App\Controllers\Admin\DetectRuleController::class . ':add');
+        $group->delete('/detect/{id:[0-9]+}', App\Controllers\Admin\DetectRuleController::class . ':delete');
+        $group->post('/detect/ajax', App\Controllers\Admin\DetectRuleController::class . ':ajax');
+        // 审计触发日志
+        $group->get('/detect/log', App\Controllers\Admin\DetectLogController::class . ':index');
+        $group->post('/detect/log/ajax', App\Controllers\Admin\DetectLogController::class . ':ajax');
+        // 审计封禁日志
+        $group->get('/detect/ban', App\Controllers\Admin\DetectBanController::class . ':index');
+        $group->post('/detect/ban/ajax', App\Controllers\Admin\DetectBanController::class . ':ajax');
         // User
         $group->get('/user', App\Controllers\Admin\UserController::class . ':index');
-        $group->get('/user/{id}/edit', App\Controllers\Admin\UserController::class . ':edit');
-        $group->put('/user/{id}', App\Controllers\Admin\UserController::class . ':update');
-        $group->post('/user/create', App\Controllers\Admin\UserController::class . ':createNewUser');
+        $group->get('/user/{id:[0-9]+}/edit', App\Controllers\Admin\UserController::class . ':edit');
+        $group->put('/user/{id:[0-9]+}', App\Controllers\Admin\UserController::class . ':update');
+        $group->post('/user/create', App\Controllers\Admin\UserController::class . ':create');
         $group->delete('/user/{id}', App\Controllers\Admin\UserController::class . ':delete');
         $group->post('/user/ajax', App\Controllers\Admin\UserController::class . ':ajax');
         // Coupon
         $group->get('/coupon', App\Controllers\Admin\CouponController::class . ':index');
         $group->post('/coupon', App\Controllers\Admin\CouponController::class . ':add');
         $group->post('/coupon/ajax', App\Controllers\Admin\CouponController::class . ':ajax');
-        $group->delete('/coupon/{id}', App\Controllers\Admin\CouponController::class . ':delete');
-        $group->post('/coupon/{id}/disable', App\Controllers\Admin\CouponController::class . ':disable');
+        $group->delete('/coupon/{id:[0-9]+}', App\Controllers\Admin\CouponController::class . ':delete');
+        $group->post('/coupon/{id:[0-9]+}/disable', App\Controllers\Admin\CouponController::class . ':disable');
         // 登录日志
         $group->get('/login', App\Controllers\Admin\LoginLogController::class . ':index');
         $group->post('/login/ajax', App\Controllers\Admin\LoginLogController::class . ':ajax');
@@ -200,19 +206,19 @@ return static function (Slim\App $app): void {
         $group->get('/online', App\Controllers\Admin\OnlineLogController::class . ':index');
         $group->post('/online/ajax', App\Controllers\Admin\OnlineLogController::class . ':ajax');
         // 订阅日志
-        $group->get('/subscribe', App\Controllers\Admin\SubscribeLogController::class . ':index');
-        $group->post('/subscribe/ajax', App\Controllers\Admin\SubscribeLogController::class . ':ajax');
+        $group->get('/subscribe', App\Controllers\Admin\SubLogController::class . ':index');
+        $group->post('/subscribe/ajax', App\Controllers\Admin\SubLogController::class . ':ajax');
         // 邀请日志
-        $group->get('/invite', App\Controllers\Admin\InviteController::class . ':invite');
+        $group->get('/invite', App\Controllers\Admin\InviteController::class . ':index');
         $group->post('/invite/update_invite', App\Controllers\Admin\InviteController::class . ':update');
         $group->post('/invite/add_invite', App\Controllers\Admin\InviteController::class . ':add');
         $group->post('/invite/ajax', App\Controllers\Admin\InviteController::class . ':ajax');
         // 流量日志
-        $group->get('/trafficlog', App\Controllers\Admin\TrafficLogController::class . ':index');
-        $group->post('/trafficlog/ajax', App\Controllers\Admin\TrafficLogController::class . ':ajax');
+        $group->get('/traffic', App\Controllers\Admin\TrafficLogController::class . ':index');
+        $group->post('/traffic/ajax', App\Controllers\Admin\TrafficLogController::class . ':ajax');
         // 用户余额日志
-        $group->get('/moneylog', App\Controllers\Admin\MoneyLogController::class . ':index');
-        $group->post('/moneylog/ajax', App\Controllers\Admin\MoneyLogController::class . ':ajax');
+        $group->get('/money', App\Controllers\Admin\MoneyLogController::class . ':index');
+        $group->post('/money/ajax', App\Controllers\Admin\MoneyLogController::class . ':ajax');
         // 支付网关日志
         $group->get('/gateway', App\Controllers\Admin\PaylistController::class . ':index');
         $group->post('/gateway/ajax', App\Controllers\Admin\PaylistController::class . ':ajax');
@@ -220,30 +226,31 @@ return static function (Slim\App $app): void {
         $group->get('/system', App\Controllers\Admin\SystemController::class . ':index');
         $group->post('/system/check_update', App\Controllers\Admin\SystemController::class . ':checkUpdate');
         // 设置中心
-        $group->get('/setting/billing', App\Controllers\Admin\Setting\BillingController::class . ':billing');
-        $group->post('/setting/billing', App\Controllers\Admin\Setting\BillingController::class . ':saveBilling');
-        $group->get('/setting/captcha', App\Controllers\Admin\Setting\CaptchaController::class . ':captcha');
-        $group->post('/setting/captcha', App\Controllers\Admin\Setting\CaptchaController::class . ':saveCaptcha');
-        $group->get('/setting/cron', App\Controllers\Admin\Setting\CronController::class . ':cron');
-        $group->post('/setting/cron', App\Controllers\Admin\Setting\CronController::class . ':saveCron');
-        $group->get('/setting/email', App\Controllers\Admin\Setting\EmailController::class . ':email');
-        $group->post('/setting/email', App\Controllers\Admin\Setting\EmailController::class . ':saveEmail');
-        $group->get('/setting/feature', App\Controllers\Admin\Setting\FeatureController::class . ':feature');
-        $group->post('/setting/feature', App\Controllers\Admin\Setting\FeatureController::class . ':saveFeature');
-        $group->get('/setting/im', App\Controllers\Admin\Setting\ImController::class . ':im');
-        $group->post('/setting/im', App\Controllers\Admin\Setting\ImController::class . ':saveIm');
-        $group->get('/setting/ref', App\Controllers\Admin\Setting\RefController::class . ':ref');
-        $group->post('/setting/ref', App\Controllers\Admin\Setting\RefController::class . ':saveRef');
-        $group->get('/setting/reg', App\Controllers\Admin\Setting\RegController::class . ':reg');
-        $group->post('/setting/reg', App\Controllers\Admin\Setting\RegController::class . ':saveReg');
-        $group->get('/setting/sub', App\Controllers\Admin\Setting\SubscribeController::class . ':sub');
-        $group->post('/setting/sub', App\Controllers\Admin\Setting\SubscribeController::class . ':saveSub');
-        $group->get('/setting/support', App\Controllers\Admin\Setting\SupportController::class . ':support');
-        $group->post('/setting/support', App\Controllers\Admin\Setting\SupportController::class . ':saveSupport');
-        $group->post('/setting/test_email', App\Controllers\Admin\Setting\EmailController::class . ':testEmail');
-        $group->post('/setting/test_telegram', App\Controllers\Admin\Setting\ImController::class . ':testTelegram');
-        $group->post('/setting/test_discord', App\Controllers\Admin\Setting\ImController::class . ':testDiscord');
-        $group->post('/setting/test_slack', App\Controllers\Admin\Setting\ImController::class . ':testSlack');
+        $group->get('/setting/billing', App\Controllers\Admin\Setting\BillingController::class . ':index');
+        $group->post('/setting/billing', App\Controllers\Admin\Setting\BillingController::class . ':save');
+        $group->get('/setting/captcha', App\Controllers\Admin\Setting\CaptchaController::class . ':index');
+        $group->post('/setting/captcha', App\Controllers\Admin\Setting\CaptchaController::class . ':save');
+        $group->get('/setting/cron', App\Controllers\Admin\Setting\CronController::class . ':index');
+        $group->post('/setting/cron', App\Controllers\Admin\Setting\CronController::class . ':save');
+        $group->get('/setting/email', App\Controllers\Admin\Setting\EmailController::class . ':index');
+        $group->post('/setting/email', App\Controllers\Admin\Setting\EmailController::class . ':save');
+        $group->get('/setting/feature', App\Controllers\Admin\Setting\FeatureController::class . ':index');
+        $group->post('/setting/feature', App\Controllers\Admin\Setting\FeatureController::class . ':save');
+        $group->get('/setting/im', App\Controllers\Admin\Setting\ImController::class . ':index');
+        $group->post('/setting/im', App\Controllers\Admin\Setting\ImController::class . ':save');
+        $group->get('/setting/ref', App\Controllers\Admin\Setting\RefController::class . ':index');
+        $group->post('/setting/ref', App\Controllers\Admin\Setting\RefController::class . ':save');
+        $group->get('/setting/reg', App\Controllers\Admin\Setting\RegController::class . ':index');
+        $group->post('/setting/reg', App\Controllers\Admin\Setting\RegController::class . ':save');
+        $group->get('/setting/sub', App\Controllers\Admin\Setting\SubController::class . ':index');
+        $group->post('/setting/sub', App\Controllers\Admin\Setting\SubController::class . ':save');
+        $group->get('/setting/support', App\Controllers\Admin\Setting\SupportController::class . ':index');
+        $group->post('/setting/support', App\Controllers\Admin\Setting\SupportController::class . ':save');
+        // 设置测试
+        $group->post('/setting/test/email', App\Controllers\Admin\Setting\EmailController::class . ':testEmail');
+        $group->post('/setting/test/telegram', App\Controllers\Admin\Setting\ImController::class . ':testTelegram');
+        $group->post('/setting/test/discord', App\Controllers\Admin\Setting\ImController::class . ':testDiscord');
+        $group->post('/setting/test/slack', App\Controllers\Admin\Setting\ImController::class . ':testSlack');
         // 礼品卡
         $group->get('/giftcard', App\Controllers\Admin\GiftCardController::class . ':index');
         $group->post('/giftcard', App\Controllers\Admin\GiftCardController::class . ':add');
@@ -253,31 +260,43 @@ return static function (Slim\App $app): void {
         $group->get('/product', App\Controllers\Admin\ProductController::class . ':index');
         $group->get('/product/create', App\Controllers\Admin\ProductController::class . ':create');
         $group->post('/product', App\Controllers\Admin\ProductController::class . ':add');
-        $group->get('/product/{id}/edit', App\Controllers\Admin\ProductController::class . ':edit');
-        $group->post('/product/{id}/copy', App\Controllers\Admin\ProductController::class . ':copy');
-        $group->put('/product/{id}', App\Controllers\Admin\ProductController::class . ':update');
-        $group->delete('/product/{id}', App\Controllers\Admin\ProductController::class . ':delete');
+        $group->get('/product/{id:[0-9]+}/edit', App\Controllers\Admin\ProductController::class . ':edit');
+        $group->post('/product/{id:[0-9]+}/copy', App\Controllers\Admin\ProductController::class . ':copy');
+        $group->put('/product/{id:[0-9]+}', App\Controllers\Admin\ProductController::class . ':update');
+        $group->delete('/product/{id:[0-9]+}', App\Controllers\Admin\ProductController::class . ':delete');
         $group->post('/product/ajax', App\Controllers\Admin\ProductController::class . ':ajax');
         // 订单
         $group->get('/order', App\Controllers\Admin\OrderController::class . ':index');
-        $group->get('/order/{id}/view', App\Controllers\Admin\OrderController::class . ':detail');
-        $group->post('/order/{id}/cancel', App\Controllers\Admin\OrderController::class . ':cancel');
+        $group->get('/order/{id:[0-9]+}/view', App\Controllers\Admin\OrderController::class . ':detail');
+        $group->post('/order/{id:[0-9]+}/cancel', App\Controllers\Admin\OrderController::class . ':cancel');
         $group->delete('/order/{id}', App\Controllers\Admin\OrderController::class . ':delete');
         $group->post('/order/ajax', App\Controllers\Admin\OrderController::class . ':ajax');
         // 账单
         $group->get('/invoice', App\Controllers\Admin\InvoiceController::class . ':index');
-        $group->get('/invoice/{id}/view', App\Controllers\Admin\InvoiceController::class . ':detail');
-        $group->post('/invoice/{id}/mark_paid', App\Controllers\Admin\InvoiceController::class . ':markPaid');
+        $group->get('/invoice/{id:[0-9]+}/view', App\Controllers\Admin\InvoiceController::class . ':detail');
+        $group->post('/invoice/{id:[0-9]+}/mark_paid', App\Controllers\Admin\InvoiceController::class . ':markPaid');
         $group->post('/invoice/ajax', App\Controllers\Admin\InvoiceController::class . ':ajax');
     })->add(new Admin());
 
-    //$app->group('/admin/api', function (RouteCollectorProxy $group): void {
-    //    $group->post('/{action}', App\Controllers\Api\AdminApiController::class . ':actionHandler');
-    //})->add(new AdminApiToken());
+    // Admin CLI API
+    //$app->group('/admin/api/v1', function (RouteCollectorProxy $group): void {
+    //    $group->post('/{action}', App\Controllers\Api\AdminApiV1Controller::class . ':actionHandler');
+    //})->add(new AdminApi());
+
+    // User CLI API
+    //$app->group('/user/api/v1', function (RouteCollectorProxy $group): void {
+    //    $group->post('/{action}', App\Controllers\Api\UserApiV1Controller::class . ':actionHandler');
+    //})->add(new UserApi());
 
-    //$app->group('/user/api', function (RouteCollectorProxy $group): void {
-    //    $group->post('/{action}', App\Controllers\Api\UserApiController::class . ':actionHandler');
-    //})->add(new UserApiToken());
+    // WebAPI V2(Aka Node API V1)
+    //$app->group('/node/api/v1', function (RouteCollectorProxy $group): void {
+    //    $group->get('/info', App\Controllers\Api\NodeApiV1Controller::class . ':info');
+    //    $group->get('/user', App\Controllers\Api\NodeApiV1Controller::class . ':user');
+    //    $group->get('/detect_rule', App\Controllers\Api\NodeApiV1Controller::class . ':detectRule');
+    //    $group->post('/user/traffic', App\Controllers\Api\NodeApiV1Controller::class . ':userTraffic');
+    //    $group->post('/user/online_ip', App\Controllers\Api\NodeApiV1Controller::class . ':userOnlineIp');
+    //    $group->post('/user/detect_log', App\Controllers\Api\NodeApiV1Controller::class . ':userDetectLog');
+    //})->add(new WebApi());
 
     // WebAPI
     $app->group('/mod_mu', static function (RouteCollectorProxy $group): void {
@@ -292,9 +311,4 @@ return static function (Slim\App $app): void {
         $group->get('/func/detect_rules', App\Controllers\WebAPI\FuncController::class . ':getDetectRules');
         $group->get('/func/ping', App\Controllers\WebAPI\FuncController::class . ':ping');
     })->add(new NodeToken());
-
-    // 传统订阅(SS/V2Ray/Trojan etc.)
-    $app->get('/link/{token}', App\Controllers\SubController::class . ':getTraditionalSubContent');
-    // 通用订阅(Json/Clash/SIP008)
-    $app->get('/sub/{token}/{subtype}', App\Controllers\SubController::class . ':getUniversalSubContent');
 };

+ 20 - 20
composer.lock

@@ -123,16 +123,16 @@
         },
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.283.14",
+            "version": "3.283.15",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "331894cd4751a06a4e5b3e4e2918a9233c9568dc"
+                "reference": "44b70c15c2a5d0fd2cfc74ee529a7877f1e7457d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/331894cd4751a06a4e5b3e4e2918a9233c9568dc",
-                "reference": "331894cd4751a06a4e5b3e4e2918a9233c9568dc",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/44b70c15c2a5d0fd2cfc74ee529a7877f1e7457d",
+                "reference": "44b70c15c2a5d0fd2cfc74ee529a7877f1e7457d",
                 "shasum": ""
             },
             "require": {
@@ -212,9 +212,9 @@
             "support": {
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.283.14"
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.283.15"
             },
-            "time": "2023-10-27T18:06:59+00:00"
+            "time": "2023-10-30T18:09:22+00:00"
         },
         {
             "name": "bacon/bacon-qr-code",
@@ -1815,16 +1815,16 @@
         },
         {
             "name": "lcobucci/jwt",
-            "version": "5.0.0",
+            "version": "5.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/lcobucci/jwt.git",
-                "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34"
+                "reference": "f0031c07b96db6a0ca649206e7eacddb7e9d5908"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/lcobucci/jwt/zipball/47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34",
-                "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34",
+                "url": "https://api.github.com/repos/lcobucci/jwt/zipball/f0031c07b96db6a0ca649206e7eacddb7e9d5908",
+                "reference": "f0031c07b96db6a0ca649206e7eacddb7e9d5908",
                 "shasum": ""
             },
             "require": {
@@ -1832,20 +1832,20 @@
                 "ext-json": "*",
                 "ext-openssl": "*",
                 "ext-sodium": "*",
-                "php": "~8.1.0 || ~8.2.0",
+                "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
                 "psr/clock": "^1.0"
             },
             "require-dev": {
-                "infection/infection": "^0.26.19",
+                "infection/infection": "^0.27.0",
                 "lcobucci/clock": "^3.0",
-                "lcobucci/coding-standard": "^9.0",
-                "phpbench/phpbench": "^1.2.8",
+                "lcobucci/coding-standard": "^11.0",
+                "phpbench/phpbench": "^1.2.9",
                 "phpstan/extension-installer": "^1.2",
-                "phpstan/phpstan": "^1.10.3",
-                "phpstan/phpstan-deprecation-rules": "^1.1.2",
-                "phpstan/phpstan-phpunit": "^1.3.8",
+                "phpstan/phpstan": "^1.10.7",
+                "phpstan/phpstan-deprecation-rules": "^1.1.3",
+                "phpstan/phpstan-phpunit": "^1.3.10",
                 "phpstan/phpstan-strict-rules": "^1.5.0",
-                "phpunit/phpunit": "^10.0.12"
+                "phpunit/phpunit": "^10.2.6"
             },
             "suggest": {
                 "lcobucci/clock": ">= 3.0"
@@ -1874,7 +1874,7 @@
             ],
             "support": {
                 "issues": "https://github.com/lcobucci/jwt/issues",
-                "source": "https://github.com/lcobucci/jwt/tree/5.0.0"
+                "source": "https://github.com/lcobucci/jwt/tree/5.1.0"
             },
             "funding": [
                 {
@@ -1886,7 +1886,7 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2023-02-25T21:35:16+00:00"
+            "time": "2023-10-31T06:41:47+00:00"
         },
         {
             "name": "league/event",

+ 2 - 2
resources/views/tabler/admin/header.tpl

@@ -193,7 +193,7 @@
                                     <i class="ti ti-friends"></i>&nbsp;
                                     邀请
                                 </a>
-                                <a class="dropdown-item" href="/admin/moneylog">
+                                <a class="dropdown-item" href="/admin/money">
                                     <i class="ti ti-coin"></i>&nbsp;
                                     余额
                                 </a>
@@ -205,7 +205,7 @@
                                     <i class="ti ti-router"></i>&nbsp;
                                     在线IP
                                 </a>
-                                <a class="dropdown-item" href="/admin/trafficlog">
+                                <a class="dropdown-item" href="/admin/traffic">
                                     <i class="ti ti-arrows-up-down"></i>&nbsp;
                                     流量使用
                                 </a>

+ 1 - 1
resources/views/tabler/admin/log/money.tpl

@@ -40,7 +40,7 @@
     <script>
         var table = $('#data_table').DataTable({
             ajax: {
-                url: '/admin/moneylog/ajax',
+                url: '/admin/money/ajax',
                 type: 'POST',
                 dataSrc: 'money_logs'
             },

+ 1 - 1
resources/views/tabler/admin/log/traffic.tpl

@@ -43,7 +43,7 @@
             "searching": false,
             "ordering": false,
             ajax: {
-                url: '/admin/trafficlog/ajax',
+                url: '/admin/traffic/ajax',
                 type: 'POST',
                 dataSrc: 'trafficlogs.data'
             },

+ 1 - 1
resources/views/tabler/admin/node/edit.tpl

@@ -228,7 +228,7 @@
 
     $("#reset-node-password").click(function () {
         $.ajax({
-            url: '/admin/node/{$node->id}/password_reset',
+            url: '/admin/node/{$node->id}/reset',
             type: 'POST',
             dataType: "json",
             success: function (data) {

+ 1 - 1
resources/views/tabler/admin/setting/email.tpl

@@ -367,7 +367,7 @@
 
             $("#test-email").click(function () {
                 $.ajax({
-                    url: '/admin/setting/test_email',
+                    url: '/admin/setting/test/email',
                     type: 'POST',
                     dataType: "json",
                     data: {

+ 3 - 3
resources/views/tabler/admin/setting/im.tpl

@@ -519,7 +519,7 @@
 
             $("#test-telegram").click(function () {
                 $.ajax({
-                    url: '/admin/setting/test_telegram',
+                    url: '/admin/setting/test/telegram',
                     type: 'POST',
                     dataType: "json",
                     data: {
@@ -539,7 +539,7 @@
 
             $("#test-discord").click(function () {
                 $.ajax({
-                    url: '/admin/setting/test_discord',
+                    url: '/admin/setting/test/discord',
                     type: 'POST',
                     dataType: "json",
                     data: {
@@ -559,7 +559,7 @@
 
             $("#test-slack").click(function () {
                 $.ajax({
-                    url: '/admin/setting/test_slack',
+                    url: '/admin/setting/test/slack',
                     type: 'POST',
                     dataType: "json",
                     data: {

+ 1 - 1
resources/views/tabler/user/header.tpl

@@ -104,7 +104,7 @@
                                             资料
                                         </a>
                                         {if $public_setting['subscribe_log']}
-                                            <a class="dropdown-item" href="/user/subscribe/log">
+                                            <a class="dropdown-item" href="/user/subscribe">
                                                 <i class="ti ti-rss"></i></i>&nbsp;
                                                 订阅
                                             </a>

+ 67 - 0
src/Controllers/Admin/DetectBanController.php

@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controllers\Admin;
+
+use App\Controllers\BaseController;
+use App\Models\DetectBanLog;
+use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+
+final class DetectBanController extends BaseController
+{
+    private static array $details =
+        [
+            'field' => [
+                'id' => '事件ID',
+                'user_name' => '用户名',
+                'user_id' => '用户ID',
+                'email' => '用户邮箱',
+                'detect_number' => '违规次数',
+                'ban_time' => '封禁时长(分钟)',
+                'start_time' => '统计开始时间',
+                'end_time' => '统计结束&封禁开始时间',
+                'ban_end_time' => '封禁结束时间',
+                'all_detect_number' => '累计违规次数',
+            ],
+        ];
+
+    /**
+     * @throws Exception
+     */
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        return $response->write(
+            $this->view()
+                ->assign('details', self::$details)
+                ->fetch('admin/log/detect_ban.tpl')
+        );
+    }
+
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $length = $request->getParam('length');
+        $page = $request->getParam('start') / $length + 1;
+        $draw = $request->getParam('draw');
+
+        $bans = DetectBanLog::orderBy('id', 'desc')->paginate($length, '*', '', $page);
+        $total = DetectBanLog::count();
+
+        foreach ($bans as $ban) {
+            $ban->start_time = Tools::toDateTime((int) $ban->start_time);
+            $ban->end_time = Tools::toDateTime((int) $ban->end_time);
+            $ban->ban_end_time = $ban->banEndTime();
+        }
+
+        return $response->withJson([
+            'draw' => $draw,
+            'recordsTotal' => $total,
+            'recordsFiltered' => $total,
+            'bans' => $bans,
+        ]);
+    }
+}

+ 0 - 236
src/Controllers/Admin/DetectController.php

@@ -1,236 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Controllers\Admin;
-
-use App\Controllers\BaseController;
-use App\Models\DetectBanLog;
-use App\Models\DetectLog;
-use App\Models\DetectRule;
-use App\Services\IM\Telegram;
-use App\Utils\Tools;
-use Exception;
-use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Response;
-use Slim\Http\ServerRequest;
-use Telegram\Bot\Exceptions\TelegramSDKException;
-
-final class DetectController extends BaseController
-{
-    private static array $rule_details =
-        [
-            'field' => [
-                'op' => '操作',
-                'id' => '规则ID',
-                'name' => '规则名称',
-                'text' => '规则介绍',
-                'regex' => '正则表达式',
-                'type' => '规则类型',
-            ],
-            'add_dialog' => [
-                [
-                    'id' => 'name',
-                    'info' => '规则名称',
-                    'type' => 'input',
-                    'placeholder' => '审计规则名称',
-                ],
-                [
-                    'id' => 'text',
-                    'info' => '规则介绍',
-                    'type' => 'input',
-                    'placeholder' => '简洁明了地描述审计规则',
-                ],
-                [
-                    'id' => 'regex',
-                    'info' => '正则表达式',
-                    'type' => 'input',
-                    'placeholder' => '用以匹配审计内容的正则表达式',
-                ],
-                [
-                    'id' => 'type',
-                    'info' => '规则类型',
-                    'type' => 'select',
-                    'select' => [
-                        '1' => '数据包明文匹配',
-                        '0' => '数据包十六进制匹配',
-                    ],
-                ],
-            ],
-        ];
-
-    private static array $log_details =
-        [
-            'field' => [
-                'id' => '事件ID',
-                'user_id' => '用户ID',
-                'user_name' => '用户名',
-                'node_id' => '节点ID',
-                'node_name' => '节点名',
-                'list_id' => '规则ID',
-                'rule_name' => '规则名',
-                'rule_text' => '规则描述',
-                'rule_regex' => '规则正则表达式',
-                'rule_type' => '规则类型',
-                'datetime' => '时间',
-            ],
-        ];
-
-    private static array $ban_details =
-        [
-            'field' => [
-                'id' => '事件ID',
-                'user_name' => '用户名',
-                'user_id' => '用户ID',
-                'email' => '用户邮箱',
-                'detect_number' => '违规次数',
-                'ban_time' => '封禁时长(分钟)',
-                'start_time' => '统计开始时间',
-                'end_time' => '统计结束&封禁开始时间',
-                'ban_end_time' => '封禁结束时间',
-                'all_detect_number' => '累计违规次数',
-            ],
-        ];
-
-    /**
-     * @throws Exception
-     */
-    public function detect(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        return $response->write(
-            $this->view()
-                ->assign('details', self::$rule_details)
-                ->fetch('admin/detect.tpl')
-        );
-    }
-
-    /**
-     * @throws TelegramSDKException
-     */
-    public function add(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $rule = new DetectRule();
-        $rule->name = $request->getParam('name');
-        $rule->text = $request->getParam('text');
-        $rule->regex = $request->getParam('regex');
-        $rule->type = $request->getParam('type');
-
-        if (! $rule->save()) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '添加失败',
-            ]);
-        }
-
-        (new Telegram())->sendMarkdown(0, '有新的审计规则:' . $rule->name);
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '添加成功',
-        ]);
-    }
-
-    public function delete(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $id = $args['id'];
-        $rule = DetectRule::find($id);
-        if (! $rule->delete()) {
-            return $response->withJson([
-                'ret' => 0,
-                'msg' => '删除失败',
-            ]);
-        }
-        return $response->withJson([
-            'ret' => 1,
-            'msg' => '删除成功',
-        ]);
-    }
-
-    /**
-     * @throws Exception
-     */
-    public function log(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        return $response->write(
-            $this->view()
-                ->assign('details', self::$log_details)
-                ->fetch('admin/log/detect.tpl')
-        );
-    }
-
-    /**
-     * @throws Exception
-     */
-    public function ban(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        return $response->write(
-            $this->view()
-                ->assign('details', self::$ban_details)
-                ->fetch('admin/log/detect_ban.tpl')
-        );
-    }
-
-    public function ajaxRule(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $rules = DetectRule::orderBy('id', 'desc')->get();
-
-        foreach ($rules as $rule) {
-            $rule->op = '<button type="button" class="btn btn-red" id="delete-rule-' . $rule->id .
-                '" onclick="deleteRule(' . $rule->id . ')">删除</button>';
-            $rule->type = $rule->type();
-        }
-
-        return $response->withJson([
-            'rules' => $rules,
-        ]);
-    }
-
-    public function ajaxLog(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $length = $request->getParam('length');
-        $page = $request->getParam('start') / $length + 1;
-        $draw = $request->getParam('draw');
-
-        $logs = DetectLog::orderBy('id', 'desc')->paginate($length, '*', '', $page);
-        $total = DetectLog::count();
-
-        foreach ($logs as $log) {
-            $log->user_name = $log->userName();
-            $log->node_name = $log->nodeName();
-            $log->rule_name = $log->ruleName();
-            $log->rule_text = $log->ruleText();
-            $log->rule_regex = $log->ruleRegex();
-            $log->rule_type = $log->ruleType();
-            $log->datetime = Tools::toDateTime((int) $log->datetime);
-        }
-
-        return $response->withJson([
-            'draw' => $draw,
-            'recordsTotal' => $total,
-            'recordsFiltered' => $total,
-            'logs' => $logs,
-        ]);
-    }
-
-    public function ajaxBan(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $length = $request->getParam('length');
-        $page = $request->getParam('start') / $length + 1;
-        $draw = $request->getParam('draw');
-
-        $bans = DetectBanLog::orderBy('id', 'desc')->paginate($length, '*', '', $page);
-        $total = DetectBanLog::count();
-
-        foreach ($bans as $ban) {
-            $ban->start_time = Tools::toDateTime((int) $ban->start_time);
-            $ban->end_time = Tools::toDateTime((int) $ban->end_time);
-            $ban->ban_end_time = $ban->banEndTime();
-        }
-
-        return $response->withJson([
-            'draw' => $draw,
-            'recordsTotal' => $total,
-            'recordsFiltered' => $total,
-            'bans' => $bans,
-        ]);
-    }
-}

+ 72 - 0
src/Controllers/Admin/DetectLogController.php

@@ -0,0 +1,72 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controllers\Admin;
+
+use App\Controllers\BaseController;
+use App\Models\DetectLog;
+use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+
+final class DetectLogController extends BaseController
+{
+    private static array $details =
+        [
+            'field' => [
+                'id' => '事件ID',
+                'user_id' => '用户ID',
+                'user_name' => '用户名',
+                'node_id' => '节点ID',
+                'node_name' => '节点名',
+                'list_id' => '规则ID',
+                'rule_name' => '规则名',
+                'rule_text' => '规则描述',
+                'rule_regex' => '规则正则表达式',
+                'rule_type' => '规则类型',
+                'datetime' => '时间',
+            ],
+        ];
+
+    /**
+     * @throws Exception
+     */
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        return $response->write(
+            $this->view()
+                ->assign('details', self::$details)
+                ->fetch('admin/log/detect.tpl')
+        );
+    }
+
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $length = $request->getParam('length');
+        $page = $request->getParam('start') / $length + 1;
+        $draw = $request->getParam('draw');
+
+        $logs = DetectLog::orderBy('id', 'desc')->paginate($length, '*', '', $page);
+        $total = DetectLog::count();
+
+        foreach ($logs as $log) {
+            $log->user_name = $log->userName();
+            $log->node_name = $log->nodeName();
+            $log->rule_name = $log->ruleName();
+            $log->rule_text = $log->ruleText();
+            $log->rule_regex = $log->ruleRegex();
+            $log->rule_type = $log->ruleType();
+            $log->datetime = Tools::toDateTime((int) $log->datetime);
+        }
+
+        return $response->withJson([
+            'draw' => $draw,
+            'recordsTotal' => $total,
+            'recordsFiltered' => $total,
+            'logs' => $logs,
+        ]);
+    }
+}

+ 126 - 0
src/Controllers/Admin/DetectRuleController.php

@@ -0,0 +1,126 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controllers\Admin;
+
+use App\Controllers\BaseController;
+use App\Models\DetectRule;
+use App\Services\IM\Telegram;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+use Telegram\Bot\Exceptions\TelegramSDKException;
+
+final class DetectRuleController extends BaseController
+{
+    private static array $details =
+        [
+            'field' => [
+                'op' => '操作',
+                'id' => '规则ID',
+                'name' => '规则名称',
+                'text' => '规则介绍',
+                'regex' => '正则表达式',
+                'type' => '规则类型',
+            ],
+            'add_dialog' => [
+                [
+                    'id' => 'name',
+                    'info' => '规则名称',
+                    'type' => 'input',
+                    'placeholder' => '审计规则名称',
+                ],
+                [
+                    'id' => 'text',
+                    'info' => '规则介绍',
+                    'type' => 'input',
+                    'placeholder' => '简洁明了地描述审计规则',
+                ],
+                [
+                    'id' => 'regex',
+                    'info' => '正则表达式',
+                    'type' => 'input',
+                    'placeholder' => '用以匹配审计内容的正则表达式',
+                ],
+                [
+                    'id' => 'type',
+                    'info' => '规则类型',
+                    'type' => 'select',
+                    'select' => [
+                        '1' => '数据包明文匹配',
+                        '0' => '数据包十六进制匹配',
+                    ],
+                ],
+            ],
+        ];
+
+    /**
+     * @throws Exception
+     */
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        return $response->write(
+            $this->view()
+                ->assign('details', self::$details)
+                ->fetch('admin/detect.tpl')
+        );
+    }
+
+    /**
+     * @throws TelegramSDKException
+     */
+    public function add(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $rule = new DetectRule();
+        $rule->name = $request->getParam('name');
+        $rule->text = $request->getParam('text');
+        $rule->regex = $request->getParam('regex');
+        $rule->type = $request->getParam('type');
+
+        if (! $rule->save()) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '添加失败',
+            ]);
+        }
+
+        (new Telegram())->sendMarkdown(0, '有新的审计规则:' . $rule->name);
+        return $response->withJson([
+            'ret' => 1,
+            'msg' => '添加成功',
+        ]);
+    }
+
+    public function delete(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $id = $args['id'];
+        $rule = DetectRule::find($id);
+        if (! $rule->delete()) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => '删除失败',
+            ]);
+        }
+        return $response->withJson([
+            'ret' => 1,
+            'msg' => '删除成功',
+        ]);
+    }
+
+    public function ajax(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $rules = DetectRule::orderBy('id', 'desc')->get();
+
+        foreach ($rules as $rule) {
+            $rule->op = '<button type="button" class="btn btn-red" id="delete-rule-' . $rule->id .
+                '" onclick="deleteRule(' . $rule->id . ')">删除</button>';
+            $rule->type = $rule->type();
+        }
+
+        return $response->withJson([
+            'rules' => $rules,
+        ]);
+    }
+}

+ 1 - 1
src/Controllers/Admin/InviteController.php

@@ -63,7 +63,7 @@ final class InviteController extends BaseController
      *
      * @throws Exception
      */
-    public function invite(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()

+ 1 - 1
src/Controllers/Admin/NodeController.php

@@ -287,7 +287,7 @@ final class NodeController extends BaseController
         ]);
     }
 
-    public function resetNodePassword(
+    public function reset(
         ServerRequest $request,
         Response $response,
         array $args

+ 2 - 2
src/Controllers/Admin/Setting/BillingController.php

@@ -50,7 +50,7 @@ final class BillingController extends BaseController
     /**
      * @throws Exception
      */
-    public function billing($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('billing');
 
@@ -64,7 +64,7 @@ final class BillingController extends BaseController
         );
     }
 
-    public function saveBilling($request, $response, $args)
+    public function save($request, $response, $args)
     {
         $gateway_in_use = [];
 

+ 2 - 2
src/Controllers/Admin/Setting/CaptchaController.php

@@ -27,7 +27,7 @@ final class CaptchaController extends BaseController
     /**
      * @throws Exception
      */
-    public function captcha($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('captcha');
 
@@ -39,7 +39,7 @@ final class CaptchaController extends BaseController
         );
     }
 
-    public function saveCaptcha($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 2 - 2
src/Controllers/Admin/Setting/CronController.php

@@ -27,7 +27,7 @@ final class CronController extends BaseController
     /**
      * @throws Exception
      */
-    public function cron($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('cron');
 
@@ -39,7 +39,7 @@ final class CronController extends BaseController
         );
     }
 
-    public function saveCron($request, $response, $args)
+    public function save($request, $response, $args)
     {
         $daily_job_hour = (int) $request->getParam('daily_job_hour');
         $daily_job_minute = (int) $request->getParam('daily_job_minute');

+ 2 - 2
src/Controllers/Admin/Setting/EmailController.php

@@ -51,7 +51,7 @@ final class EmailController extends BaseController
     /**
      * @throws Exception
      */
-    public function email($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('email');
 
@@ -63,7 +63,7 @@ final class EmailController extends BaseController
         );
     }
 
-    public function saveEmail($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 2 - 2
src/Controllers/Admin/Setting/FeatureController.php

@@ -26,7 +26,7 @@ final class FeatureController extends BaseController
     /**
      * @throws Exception
      */
-    public function feature($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('feature');
 
@@ -38,7 +38,7 @@ final class FeatureController extends BaseController
         );
     }
 
-    public function saveFeature($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 2 - 2
src/Controllers/Admin/Setting/ImController.php

@@ -64,7 +64,7 @@ final class ImController extends BaseController
     /**
      * @throws Exception
      */
-    public function im($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('im');
 
@@ -76,7 +76,7 @@ final class ImController extends BaseController
         );
     }
 
-    public function saveIm($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 2 - 2
src/Controllers/Admin/Setting/RefController.php

@@ -24,7 +24,7 @@ final class RefController extends BaseController
     /**
      * @throws Exception
      */
-    public function ref($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('ref');
 
@@ -36,7 +36,7 @@ final class RefController extends BaseController
         );
     }
 
-    public function saveRef($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 2 - 2
src/Controllers/Admin/Setting/RegController.php

@@ -33,7 +33,7 @@ final class RegController extends BaseController
     /**
      * @throws Exception
      */
-    public function reg($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('reg');
 
@@ -45,7 +45,7 @@ final class RegController extends BaseController
         );
     }
 
-    public function saveReg($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 3 - 3
src/Controllers/Admin/Setting/SubscribeController.php → src/Controllers/Admin/Setting/SubController.php

@@ -8,7 +8,7 @@ use App\Controllers\BaseController;
 use App\Models\Setting;
 use Exception;
 
-final class SubscribeController extends BaseController
+final class SubController extends BaseController
 {
     private static array $update_field = [
         'enable_forced_replacement',
@@ -21,7 +21,7 @@ final class SubscribeController extends BaseController
     /**
      * @throws Exception
      */
-    public function sub($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('subscribe');
 
@@ -33,7 +33,7 @@ final class SubscribeController extends BaseController
         );
     }
 
-    public function saveSub($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 2 - 2
src/Controllers/Admin/Setting/SupportController.php

@@ -25,7 +25,7 @@ final class SupportController extends BaseController
     /**
      * @throws Exception
      */
-    public function support($request, $response, $args)
+    public function index($request, $response, $args)
     {
         $settings = Setting::getClass('support');
 
@@ -37,7 +37,7 @@ final class SupportController extends BaseController
         );
     }
 
-    public function saveSupport($request, $response, $args)
+    public function save($request, $response, $args)
     {
         foreach (self::$update_field as $item) {
             if (! Setting::set($item, $request->getParam($item))) {

+ 1 - 1
src/Controllers/Admin/SubscribeLogController.php → src/Controllers/Admin/SubLogController.php

@@ -13,7 +13,7 @@ use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
-final class SubscribeLogController extends BaseController
+final class SubLogController extends BaseController
 {
     private static array $details =
         [

+ 1 - 1
src/Controllers/Admin/TicketController.php

@@ -161,7 +161,7 @@ final class TicketController extends BaseController
      *
      * @throws Exception
      */
-    public function ticketView(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function detail(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $id = $args['id'];
         $ticket = Ticket::where('id', '=', $id)->first();

+ 1 - 1
src/Controllers/Admin/UserController.php

@@ -118,7 +118,7 @@ final class UserController extends BaseController
      * @throws ClientExceptionInterface
      * @throws TelegramSDKException
      */
-    public function createNewUser(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function create(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $email = $request->getParam('email');
         $ref_by = $request->getParam('ref_by');

+ 37 - 0
src/Controllers/User/DetectLogController.php

@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controllers\User;
+
+use App\Controllers\BaseController;
+use App\Models\DetectLog;
+use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+
+final class DetectLogController extends BaseController
+{
+    /**
+     * 审计碰撞记录
+     *
+     * @throws Exception
+     */
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $logs = DetectLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
+
+        foreach ($logs as $log) {
+            $log->node_name = $log->nodeName();
+            $log->rule = $log->rule();
+            $log->rule->type = $log->ruleType();
+            $log->datetime = Tools::toDateTime($log->datetime);
+        }
+
+        return $response->write($this->view()
+            ->assign('logs', $logs)
+            ->fetch('user/detect/log.tpl'));
+    }
+}

+ 1 - 1
src/Controllers/User/DetectController.php → src/Controllers/User/DetectRuleController.php

@@ -11,7 +11,7 @@ use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
-final class DetectController extends BaseController
+final class DetectRuleController extends BaseController
 {
     /**
      * @throws Exception

+ 1 - 1
src/Controllers/User/InfoController.php

@@ -37,7 +37,7 @@ final class InfoController extends BaseController
     public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $themes = Tools::getDir(BASE_PATH . '/resources/views');
-        $methods = Config::getSupportParam('method');
+        $methods = Config::getSsMethod('method');
         $ga_url = MFA::getGaUrl($this->user);
 
         return $response->write($this->view()

+ 1 - 1
src/Controllers/User/InvoiceController.php

@@ -36,7 +36,7 @@ final class InvoiceController extends BaseController
     /**
      * @throws Exception
      */
-    public function invoice(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()

+ 0 - 62
src/Controllers/User/LogController.php

@@ -1,62 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Controllers\User;
-
-use App\Controllers\BaseController;
-use App\Models\DetectLog;
-use App\Models\SubscribeLog;
-use App\Utils\Tools;
-use Exception;
-use Psr\Http\Message\ResponseInterface;
-use Slim\Http\Response;
-use Slim\Http\ServerRequest;
-
-final class LogController extends BaseController
-{
-    /**
-     * 订阅记录
-     *
-     * @throws Exception
-     */
-    public function subscribe(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $logs = SubscribeLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
-
-        foreach ($logs as $log) {
-            $log->request_time = Tools::toDateTime($log->request_time);
-        }
-
-        return $response->write($this->view()
-            ->assign('logs', $logs)
-            ->fetch('user/subscribe_log.tpl'));
-    }
-
-    /**
-     * 审计碰撞记录
-     *
-     * @throws Exception
-     */
-    public function detect(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
-    {
-        $logs = DetectLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
-
-        foreach ($logs as $log) {
-            $log->node_name = $log->nodeName();
-            $log->rule = $log->rule();
-
-            if ($log->rule->type === 1) {
-                $log->rule->type = '数据包明文匹配';
-            } elseif ($log->type === 2) {
-                $log->rule->type = '数据包 hex 匹配';
-            }
-
-            $log->datetime = Tools::toDateTime($log->datetime);
-        }
-
-        return $response->write($this->view()
-            ->assign('logs', $logs)
-            ->fetch('user/detect/log.tpl'));
-    }
-}

+ 1 - 1
src/Controllers/User/MoneyController.php

@@ -23,7 +23,7 @@ final class MoneyController extends BaseController
     /**
      * @throws Exception
      */
-    public function money(ServerRequest $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $moneylogs = UserMoneyLog::where('user_id', $user->id)->orderBy('id', 'desc')->get();

+ 1 - 1
src/Controllers/User/OrderController.php

@@ -45,7 +45,7 @@ final class OrderController extends BaseController
     /**
      * @throws Exception
      */
-    public function order(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         return $response->write(
             $this->view()

+ 1 - 1
src/Controllers/User/ProductController.php

@@ -17,7 +17,7 @@ final class ProductController extends BaseController
     /**
      * @throws Exception
      */
-    public function product(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
     {
         $tabps = Product::where('status', '1')
             ->where('type', 'tabp')

+ 1 - 1
src/Controllers/User/ServerController.php

@@ -20,7 +20,7 @@ final class ServerController extends BaseController
     /**
      * @throws Exception
      */
-    public function server(ServerRequest $request, Response $response, array $args): ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $user = $this->user;
         $query = Node::query();

+ 34 - 0
src/Controllers/User/SubLogController.php

@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Controllers\User;
+
+use App\Controllers\BaseController;
+use App\Models\SubscribeLog;
+use App\Utils\Tools;
+use Exception;
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+
+final class SubLogController extends BaseController
+{
+    /**
+     * 订阅记录
+     *
+     * @throws Exception
+     */
+    public function index(ServerRequest $request, Response $response, array $args): Response|ResponseInterface
+    {
+        $logs = SubscribeLog::orderBy('id', 'desc')->where('user_id', $this->user->id)->get();
+
+        foreach ($logs as $log) {
+            $log->request_time = Tools::toDateTime($log->request_time);
+        }
+
+        return $response->write($this->view()
+            ->assign('logs', $logs)
+            ->fetch('user/subscribe_log.tpl'));
+    }
+}

+ 4 - 4
src/Controllers/User/TicketController.php

@@ -35,7 +35,7 @@ final class TicketController extends BaseController
     /**
      * @throws Exception
      */
-    public function ticket(ServerRequest $request, Response $response, array $args): ?ResponseInterface
+    public function index(ServerRequest $request, Response $response, array $args): ?ResponseInterface
     {
         if (! Setting::obtain('enable_ticket')) {
             return $response->withRedirect('/user');
@@ -62,7 +62,7 @@ final class TicketController extends BaseController
      * @throws TelegramSDKException
      * @throws GuzzleException
      */
-    public function ticketAdd(ServerRequest $request, Response $response, array $args): ResponseInterface
+    public function add(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $title = $request->getParam('title') ?? '';
         $comment = $request->getParam('comment') ?? '';
@@ -119,7 +119,7 @@ final class TicketController extends BaseController
      * @throws TelegramSDKException
      * @throws ClientExceptionInterface
      */
-    public function ticketUpdate(ServerRequest $request, Response $response, array $args): ResponseInterface
+    public function update(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         $id = $args['id'];
         $comment = $request->getParam('comment') ?? '';
@@ -177,7 +177,7 @@ final class TicketController extends BaseController
     /**
      * @throws Exception
      */
-    public function ticketView(ServerRequest $request, Response $response, array $args): ResponseInterface
+    public function detail(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
         if (! Setting::obtain('enable_ticket')) {
             return $response->withRedirect('/user');

+ 1 - 1
src/Middleware/AdminApiToken.php → src/Middleware/AdminApi.php

@@ -8,7 +8,7 @@ use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
-final class AdminApiToken
+final class AdminApi
 {
     /**
      * MID /admin/api/

+ 2 - 2
src/Middleware/Auth.php

@@ -30,9 +30,9 @@ final class Auth implements MiddlewareInterface
             return AppFactory::determineResponseFactory()->createResponse(302)->withHeader('Location', '/auth/login');
         }
 
-        $enablePages = ['/user/banned', '/user/logout'];
+        $bannedUserEnabledPages = ['/user/banned', '/user/logout'];
 
-        if ($user->is_banned && ! in_array($path, $enablePages)) {
+        if ($user->is_banned && ! in_array($path, $bannedUserEnabledPages)) {
             return AppFactory::determineResponseFactory()->createResponse(302)->withHeader('Location', '/user/banned');
         }
 

+ 1 - 1
src/Middleware/UserApiToken.php → src/Middleware/NodeApi.php

@@ -8,7 +8,7 @@ use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
 
-final class UserApiToken
+final class NodeApi
 {
     /**
      * MID /user/api

+ 25 - 0
src/Middleware/UserApi.php

@@ -0,0 +1,25 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Middleware;
+
+use Psr\Http\Message\ResponseInterface;
+use Slim\Http\Response;
+use Slim\Http\ServerRequest;
+
+final class UserApi
+{
+    /**
+     * MID /user/api
+     *
+     * @param ServerRequest $request
+     * @param Response $response
+     * @param callable $next
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke($request, $response, $next)
+    {
+    }
+}

+ 1 - 1
src/Models/DetectRule.php

@@ -17,6 +17,6 @@ final class DetectRule extends Model
      */
     public function type(): string
     {
-        return $this->type === 1 ? '数据包明文匹配' : '数据包十六进制匹配';
+        return $this->type === 1 ? '数据包明文匹配' : '数据包 hex 匹配';
     }
 }

+ 0 - 3
src/Services/Auth.php

@@ -15,9 +15,6 @@ final class Auth
         self::getDriver()->login($uid, $time);
     }
 
-    /**
-     * Get current user(cached)
-     */
     public static function getUser(): User
     {
         global $user;

+ 2 - 2
src/Services/Bot/Telegram/Callback.php

@@ -592,7 +592,7 @@ final class Callback
                 // 加密方式更改
                 $keyboard = $back;
                 if (isset($CallbackDataExplode[1])) {
-                    if (in_array($CallbackDataExplode[1], Config::getSupportParam('method'))) {
+                    if (in_array($CallbackDataExplode[1], Config::getSsMethod('method'))) {
                         $temp = $this->user->setMethod($CallbackDataExplode[1]);
                         if ($temp['ok']) {
                             $text = '你当前的加密方式为:' . $this->user->method . PHP_EOL . PHP_EOL . $temp['msg'];
@@ -605,7 +605,7 @@ final class Callback
                 } else {
                     $Encrypts = [];
 
-                    foreach (Config::getSupportParam('method') as $value) {
+                    foreach (Config::getSsMethod('method') as $value) {
                         $Encrypts[] = [
                             'text' => $value,
                             'callback_data' => 'user.edit.encrypt|' . $value,

+ 1 - 7
src/Services/Config.php

@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace App\Services;
 
-// Config is singleton instance store all config
 final class Config
 {
     public static function getViewConfig(): array
@@ -55,7 +54,7 @@ final class Config
         ];
     }
 
-    public static function getSupportParam($type): array
+    public static function getSsMethod($type): array
     {
         return match ($type) {
             'ss_obfs' => [
@@ -64,11 +63,6 @@ final class Config
                 'simple_obfs_tls',
                 'simple_obfs_tls_compatible',
             ],
-            'ss_2022' => [
-                '2022-blake3-aes-128-gcm',
-                '2022-blake3-aes-256-gcm',
-                '2022-blake3-chacha20-poly1305',
-            ],
             default => [
                 'aes-128-gcm',
                 'aes-192-gcm',

+ 4 - 4
src/Services/GeoIP2.php

@@ -29,8 +29,8 @@ final class GeoIP2
      */
     public function getCity(string $ip): ?string
     {
-        $record = $this->city_reader->city($ip);
-        return $record->city->names[$_ENV['geoip_locale']] ?? $record->city->name;
+        $record = $this?->city_reader?->city($ip);
+        return $record?->city?->names[$_ENV['geoip_locale']] ?? $record?->city?->name;
     }
 
     /**
@@ -39,7 +39,7 @@ final class GeoIP2
      */
     public function getCountry(string $ip): ?string
     {
-        $record = $this->country_reader->country($ip);
-        return $record->country->names[$_ENV['geoip_locale']] ?? $record->country->name;
+        $record = $this?->country_reader?->country($ip);
+        return $record?->country?->names[$_ENV['geoip_locale']] ?? $record?->country?->name;
     }
 }

+ 1 - 1
src/Utils/Tools.php

@@ -294,7 +294,7 @@ final class Tools
      */
     public static function isParamValidate($type, $str): bool
     {
-        $list = Config::getSupportParam($type);
+        $list = Config::getSsMethod($type);
 
         if (in_array($str, $list)) {
             return true;

+ 3 - 3
tests/App/Services/ConfigTest.php

@@ -132,11 +132,11 @@ class ConfigTest extends TestCase
     }
 
     /**
-     * @covers App\Services\Config::getSupportParam
+     * @covers App\Services\Config::getSsMethod
      */
-    public function testGetSupportParam(): void
+    public function testGetSsMethod(): void
     {
-        $params = Config::getSupportParam('ss_aead_method');
+        $params = Config::getSsMethod('ss_aead_method');
 
         $this->assertIsArray($params);
         $this->assertContains('aes-128-gcm', $params);