Browse Source

Merge pull request #2311 from sspanel-uim/dev

Dev 20231205
M1Screw 1 year ago
parent
commit
9584bde080

+ 2 - 7
.github/dependabot.yml

@@ -1,11 +1,6 @@
-# To get started with Dependabot version updates, you'll need to specify which
-# package ecosystems to update and where the package manifests are located.
-# Please see the documentation for all configuration options:
-# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
-
 version: 2
 updates:
-  - package-ecosystem: "composer" # See documentation for possible values
-    directory: "/" # Location of package manifests
+  - package-ecosystem: "composer"
+    directory: "/"
     schedule:
       interval: "monthly"

+ 0 - 4
.github/workflows/minify.yml

@@ -1,9 +1,5 @@
-# This is a basic workflow to help you get started with Actions
-
 name: Auto Minify CSS/JS file
 
-# Controls when the action will run. Triggers the workflow on push or pull request
-# events but only for the dev branch
 on:
   push:
     paths:

+ 0 - 24
.github/workflows/qodana_code_quality.yml

@@ -1,24 +0,0 @@
-name: Qodana
-on:
-  push:
-    branches: [ "dev" ]
-  pull_request:
-    branches: [ "dev" ]
-  workflow_dispatch:
-
-jobs:
-  qodana:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-        with:
-          fetch-depth: 0
-      - uses: shivammathur/setup-php@v2
-        with:
-          php-version: 8.2
-      - run: |
-          composer install --no-interaction --no-progress --no-suggest
-      - name: 'Qodana Scan'
-        uses: JetBrains/[email protected]
-        env:
-          QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

+ 1 - 1
.github/workflows/sonarcloud.yml

@@ -21,7 +21,7 @@ jobs:
       - name: Setup PHP with Xdebug
         uses: shivammathur/setup-php@v2
         with:
-          php-version: '8.2'
+          php-version: '8.3'
           coverage: xdebug
       - name: Install dependencies with composer
         run: composer update --no-ansi --no-interaction --no-progress

+ 0 - 5
.github/workflows/stale.yml

@@ -1,8 +1,3 @@
-# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
-#
-# You can adjust the behavior by modifying this file.
-# For more information, see:
-# https://github.com/actions/stale
 name: Mark stale issues and pull requests
 
 on:

+ 0 - 11
.github/workflows/unit.yaml

@@ -8,17 +8,6 @@ on:
   workflow_dispatch:
 
 jobs:
-  unit-test-php81:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - uses: shivammathur/setup-php@v2
-        with:
-          php-version: 8.1
-      - run: |
-          composer install --no-interaction --no-progress --no-suggest
-          php vendor/bin/phpunit
-
   unit-test-php82:
     runs-on: ubuntu-latest
     steps:

+ 7 - 13
README.md

@@ -23,18 +23,18 @@
 
 ## 简介
 
-SSPanel UIM 是一款专为 Shadowsocks / V2Ray / Trojan 协议设计的多用途代理服务销售管理系统。
+SSPanel UIM 是一款专为 Shadowsocks / V2Ray / Trojan / TUIC 协议设计的多用途代理服务销售管理系统。
 
 ## 特性
 
 - 集成 支付宝当面付,PayPal,Stripe 等多种支付系统
-- 支持多种邮件服务,内置队列功能,无需第三方组件即可使用
+- 支持多种邮件服务,内置邮件队列功能,无需第三方组件即可使用
 - 内置基于 Bootstrap 5 的 tabler 主题,模板引擎支持
 - 支持 Shadowsocks 2022,TUIC 等最新代理协议
 - 通用订阅接口,一键 json/clash/sip008/sing-box 格式订阅下发
-- 自定义节点配置,模块化订阅系统,支持多种传统订阅模
-- 重构的商店系统,支持多种计费模式,包括但不限于包年包月,按量计费,接入类型计费等
-- 重构的定时任务系统,再也不需要麻烦地配置 crontab,一个命令即可完成所有定时任务
+- 自定义节点配置,模块化订阅系统,支持多种客户端专用订阅格
+- 重构的商店系统,支持包括但不限于包年包月,按量计费,接入类型计费等计费模式
+- 重构的定时任务系统,一个命令即可自动完成所有定时任务
 
 ## 安装
 
@@ -42,8 +42,8 @@ SSPanel UIM 的需要以下程序才能正常的安装和运行:
 
 - Git
 - Nginx(必须使用 HTTPS/HTTPS is REQUIRED)
-- PHP 8.1+ (强烈推荐开启 OPcache /OPcache is highly recommended)
-- MariaDB 10.6+(关闭严格模式,不兼容 MySQL/Disable strict mode, DO NOT USE MySQL)
+- PHP 8.2+ (强烈推荐开启 OPcache /OPcache is highly recommended)
+- MariaDB 10.11+(关闭严格模式,不兼容 MySQL/Disable strict mode, DO NOT USE MySQL)
 - Redis 7.0+
 
 我们推荐用户在开始使用之前有一定程度的 PHP 和 Linux 使用知识,能够至少正确识别使用中所出现的问题并在 issue 中提供所需的信息。
@@ -62,12 +62,6 @@ SSPanel-UIM 不单单是一个面板,它还包括了一系列周边项目来
 
 你可以在 [SSPanel UIM 项目组](https://github.com/sspanel-uim) 的页面查看由我们的开发者维护的其他项目。
 
-## 贡献
-
-[功能请求 & 问题回报](https://github.com/Anankke/SSPanel-Uim/issues/new) | [Fork & Pull Request](https://github.com/Anankke/SSPanel-Uim/fork) | [文档 Repo](https://github.com/sspanel-uim/Wiki) | [贡献者列表](https://wiki.sspanel.org/#/contributors)
-
-SSPanel UIM 欢迎各种贡献,包括但不限于改进,新功能,文档和代码改进,问题和错误报告。
-
 ## 支持开发者
 
 ### M1Screw

+ 8 - 8
composer.json

@@ -1,6 +1,6 @@
 {
     "require": {
-        "php": "^8.1",
+        "php": "^8.2",
         "ext-bcmath": "*",
         "ext-curl": "*",
         "ext-fileinfo": "*",
@@ -15,30 +15,30 @@
         "ext-yaml": "*",
         "ext-zip": "*",
         "anankke/omnipay-alipay": "^3.1.3",
-        "aws/aws-sdk-php": "^3.289.0",
+        "aws/aws-sdk-php": "^3.293.2",
         "geoip2/geoip2": "^2.13",
         "guzzlehttp/guzzle": "^7.8",
         "guzzlehttp/psr7": "^2.6.1",
-        "illuminate/database": "^10.33.0",
-        "illuminate/pagination": "^10.33.0",
+        "illuminate/database": "^10.34.2",
+        "illuminate/pagination": "^10.34.2",
         "irazasyed/telegram-bot-sdk": "^3.13",
         "lcobucci/jwt": "^5.2",
         "league/omnipay": "^3.2.1",
-        "mailgun/mailgun-php": "^3.6.2",
+        "mailgun/mailgun-php": "^3.6.3",
         "nikolaposa/rate-limit": "^3.0",
         "openai-php/client": "^0.7.10",
         "ozdemir/datatables": "^2.3.7",
         "phpmailer/phpmailer": "^6.9.1",
         "postal/postal": "^2",
         "ramsey/uuid": "^4.7.5",
-        "sendgrid/sendgrid": "^8.0.1",
+        "sendgrid/sendgrid": "^8.1.0",
         "sentry/sdk": "^3.5",
         "slim/http": "^1.3",
         "slim/slim": "^4.12",
         "smarty/smarty": "^4.3.4",
         "srmklive/paypal": "^3.0.27",
         "stripe/stripe-php": "^12.8",
-        "symfony/translation": "^6.3.7",
+        "symfony/translation": "^6.4",
         "tronovav/geoip2-update": "^2.3.1",
         "twig/twig": "^3.8",
         "vectorface/googleauthenticator": "^3.0",
@@ -59,7 +59,7 @@
     },
     "require-dev": {
         "nunomaduro/phpinsights": "*",
-        "phpunit/phpunit": "^10.4.2"
+        "phpunit/phpunit": "^10.5.1"
     },
     "scripts": {
         "update-dev-windows": [

File diff suppressed because it is too large
+ 243 - 177
composer.lock


+ 1 - 1
db/migrations/2023020100-init.php

@@ -133,7 +133,7 @@ return new class() implements MigrationInterface {
             CREATE TABLE `node` (
                 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '节点ID',
                 `name` varchar(255) NOT NULL DEFAULT '' COMMENT '节点名称',
-                `type` tinyint(1) unsigned NOT NULL DEFAULT 1 COMMENT '节点显示',
+                `type` tinyint(1) unsigned NOT NULL DEFAULT 1 COMMENT '节点启用',
                 `server` varchar(255) NOT NULL DEFAULT '' COMMENT '节点地址',
                 `custom_config` longtext NOT NULL DEFAULT '{}' COMMENT '自定义配置' CHECK (json_valid(`custom_config`)),
                 `sort` tinyint(2) unsigned NOT NULL DEFAULT 14 COMMENT '节点类型',

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

@@ -186,7 +186,7 @@ final class UserController extends BaseController
             $money = (float) $request->getParam('money');
             $diff = $money - $user->money;
             $remark = ($diff > 0 ? '管理员添加余额' : '管理员扣除余额');
-            (new UserMoneyLog())->add($id, $user->money, $money, $diff, $remark);
+            (new UserMoneyLog())->add($id, (float) $user->money, $money, $diff, $remark);
             $user->money = $money;
         }
 

+ 32 - 2
src/Controllers/WebAPI/UserController.php

@@ -42,6 +42,13 @@ final class UserController extends BaseController
             ]);
         }
 
+        if ($node->type === 0) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => 'Node is not enabled.',
+            ]);
+        }
+
         $node->update(['node_heartbeat' => time()]);
 
         if ($node->node_bandwidth_limit !== 0 && $node->node_bandwidth_limit <= $node->node_bandwidth) {
@@ -160,6 +167,13 @@ final class UserController extends BaseController
             ]);
         }
 
+        if ($node->type === 0) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => 'Node is not enabled.',
+            ]);
+        }
+
         $pdo = DB::getPdo();
         $stat = $pdo->prepare('
                 UPDATE user SET last_use_time = UNIX_TIMESTAMP(),
@@ -228,14 +242,22 @@ final class UserController extends BaseController
 
         $data = $data->data;
         $node_id = $request->getQueryParam('node_id');
+        $node = (new Node())->find($node_id);
 
-        if ($node_id === null || ! (new Node())->where('id', $node_id)->exists()) {
+        if ($node === null) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => 'Node not found.',
             ]);
         }
 
+        if ($node->type === 0) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => 'Node is not enabled.',
+            ]);
+        }
+
         $stat = DB::getPdo()->prepare('
             INSERT INTO online_log (user_id, ip, node_id, first_time, last_time)
                 VALUES (?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())
@@ -285,14 +307,22 @@ final class UserController extends BaseController
 
         $data = $data->data;
         $node_id = $request->getQueryParam('node_id');
+        $node = (new Node())->find($node_id);
 
-        if ($node_id === null || ! (new Node())->where('id', $node_id)->exists()) {
+        if ($node === null) {
             return $response->withJson([
                 'ret' => 0,
                 'msg' => 'Node not found.',
             ]);
         }
 
+        if ($node->type === 0) {
+            return $response->withJson([
+                'ret' => 0,
+                'msg' => 'Node is not enabled.',
+            ]);
+        }
+
         foreach ($data as $log) {
             $list_id = (int) $log?->list_id;
             $user_id = (int) $log?->user_id;

+ 1 - 1
src/Models/Node.php

@@ -15,7 +15,7 @@ use const DNS_AAAA;
 /**
  * @property int    $id                      节点ID
  * @property string $name                    节点名称
- * @property int    $type                    节点显示
+ * @property int    $type                    节点启用
  * @property string $server                  节点地址
  * @property string $custom_config           自定义配置
  * @property int    $sort                    节点类型

+ 1 - 0
src/Models/User.php

@@ -93,6 +93,7 @@ final class User extends Model
      * @var array
      */
     protected $casts = [
+        'money' => 'float',
         'port' => 'int',
         'node_speedlimit' => 'float',
         'daily_mail_enable' => 'int',

+ 7 - 4
src/Services/Gateway/AopF2F.php

@@ -19,6 +19,11 @@ use voku\helper\AntiXSS;
 
 final class AopF2F extends Base
 {
+    public function __construct()
+    {
+        $this->antiXss = new AntiXSS();
+    }
+
     public static function _name(): string
     {
         return 'f2f';
@@ -36,10 +41,8 @@ final class AopF2F extends Base
 
     public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $antiXss = new AntiXSS();
-
-        $price = $antiXss->xss_clean($request->getParam('amount'));
-        $invoice_id = $antiXss->xss_clean($request->getParam('invoice_id'));
+        $price = $this->antiXss->xss_clean($request->getParam('amount'));
+        $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
         $trade_no = self::generateGuid();
 
         if ($price <= 0) {

+ 3 - 0
src/Services/Gateway/Base.php

@@ -13,6 +13,7 @@ use App\Utils\Tools;
 use Psr\Http\Message\ResponseInterface;
 use Slim\Http\Response;
 use Slim\Http\ServerRequest;
+use voku\helper\AntiXSS;
 use function get_called_class;
 use function in_array;
 use function json_decode;
@@ -20,6 +21,8 @@ use function time;
 
 abstract class Base
 {
+    protected AntiXSS $antiXss;
+
     abstract public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface;
 
     abstract public function notify(ServerRequest $request, Response $response, array $args): ResponseInterface;

+ 4 - 5
src/Services/Gateway/Epay.php

@@ -28,6 +28,7 @@ final class Epay extends Base
 
     public function __construct()
     {
+        $this->antiXss = new AntiXSS();
         $this->epay['apiurl'] = Config::obtain('epay_url');//易支付API地址
         $this->epay['partner'] = Config::obtain('epay_pid');//易支付商户pid
         $this->epay['key'] = Config::obtain('epay_key');//易支付商户Key
@@ -53,12 +54,10 @@ final class Epay extends Base
 
     public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $antiXss = new AntiXSS();
-
-        $price = $antiXss->xss_clean($request->getParam('price'));
-        $invoice_id = $antiXss->xss_clean($request->getParam('invoice_id'));
+        $price = $this->antiXss->xss_clean($request->getParam('price'));
+        $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
         // EPay 特定参数
-        $type = $antiXss->xss_clean($request->getParam('type'));
+        $type = $this->antiXss->xss_clean($request->getParam('type'));
 
         if ($price <= 0) {
             return $response->withJson([

+ 5 - 8
src/Services/Gateway/PayPal.php

@@ -21,10 +21,11 @@ use voku\helper\AntiXSS;
 
 final class PayPal extends Base
 {
-    private array $gateway_config;
+    protected array $gateway_config;
 
     public function __construct()
     {
+        $this->antiXss = new AntiXSS();
         $configs = Config::getClass('billing');
 
         $this->gateway_config = [
@@ -69,10 +70,8 @@ final class PayPal extends Base
      */
     public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $antiXss = new AntiXSS();
-
-        $price = $antiXss->xss_clean($request->getParam('price'));
-        $invoice_id = $antiXss->xss_clean($request->getParam('invoice_id'));
+        $price = $this->antiXss->xss_clean($request->getParam('price'));
+        $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
         $trade_no = self::generateGuid();
 
         if ($price <= 0) {
@@ -121,9 +120,7 @@ final class PayPal extends Base
      */
     public function notify($request, $response, $args): ResponseInterface
     {
-        $antiXss = new AntiXSS();
-
-        $order_id = $antiXss->xss_clean($request->getParam('order_id'));
+        $order_id = $this->antiXss->xss_clean($request->getParam('order_id'));
 
         $pp = new PayPalClient($this->gateway_config);
         $pp->getAccessToken();

+ 8 - 7
src/Services/Gateway/StripeCard.php

@@ -23,6 +23,11 @@ use voku\helper\AntiXSS;
 
 final class StripeCard extends Base
 {
+    public function __construct()
+    {
+        $this->antiXss = new AntiXSS();
+    }
+
     public static function _name(): string
     {
         return 'stripe';
@@ -44,10 +49,8 @@ final class StripeCard extends Base
      */
     public function purchase(ServerRequest $request, Response $response, array $args): ResponseInterface
     {
-        $antiXss = new AntiXSS();
-
-        $price = $antiXss->xss_clean($request->getParam('price'));
-        $invoice_id = $antiXss->xss_clean($request->getParam('invoice_id'));
+        $price = $this->antiXss->xss_clean($request->getParam('price'));
+        $invoice_id = $this->antiXss->xss_clean($request->getParam('invoice_id'));
         $trade_no = self::generateGuid();
 
         if ($price < Config::obtain('stripe_min_recharge') ||
@@ -118,9 +121,7 @@ final class StripeCard extends Base
 
     public function getReturnHTML($request, $response, $args): ResponseInterface
     {
-        $antiXss = new AntiXSS();
-
-        $session_id = $antiXss->xss_clean($request->getParam('session_id'));
+        $session_id = $this->antiXss->xss_clean($request->getParam('session_id'));
 
         $stripe = new StripeClient(Config::obtain('stripe_sk'));
         $session = null;

Some files were not shown because too many files changed in this diff