Bläddra i källkod

feat: json sub v4

M1Screw 1 år sedan
förälder
incheckning
b7f9e14d82

+ 1 - 1
app/routes.php

@@ -23,7 +23,7 @@ return static function (Slim\App $app): void {
     $app->post('/oauth/{type}', App\Controllers\OAuthController::class . ':index');
     $app->get('/oauth/{type}', App\Controllers\OAuthController::class . ':index');
     // 通用订阅
-    $app->get('/sub/{token}/{subtype}', App\Controllers\SubController::class . ':getUniversalSubContent');
+    $app->get('/sub/{token}/{subtype}', App\Controllers\SubController::class . ':index');
 
     // User
     $app->group('/user', static function (RouteCollectorProxy $group): void {

+ 7 - 6
composer.json

@@ -16,9 +16,9 @@
         "ext-zip": "*",
         "anankke/omnipay-alipay": "^3.1.3",
         "aws/aws-sdk-php": "^3.293.2",
-        "geoip2/geoip2": "^2.13",
-        "guzzlehttp/guzzle": "^7.8",
-        "guzzlehttp/psr7": "^2.6.1",
+        "geoip2/geoip2": "^3",
+        "guzzlehttp/guzzle": "^7.8.1",
+        "guzzlehttp/psr7": "^2.6.2",
         "illuminate/database": "^10.34.2",
         "illuminate/pagination": "^10.34.2",
         "irazasyed/telegram-bot-sdk": "^3.13",
@@ -26,18 +26,19 @@
         "league/omnipay": "^3.2.1",
         "mailgun/mailgun-php": "^3.6.3",
         "nikolaposa/rate-limit": "^3.0",
-        "openai-php/client": "^0.7.10",
+        "openai-php/client": "^0",
         "ozdemir/datatables": "^2.3.7",
         "phpmailer/phpmailer": "^6.9.1",
         "postal/postal": "^2",
         "ramsey/uuid": "^4.7.5",
         "sendgrid/sendgrid": "^8.1.0",
-        "sentry/sdk": "^3.5",
+        "sentry/sdk": "^4",
         "slim/http": "^1.3",
         "slim/slim": "^4.12",
         "smarty/smarty": "^4.3.4",
         "srmklive/paypal": "^3.0.27",
-        "stripe/stripe-php": "^12.8",
+        "stripe/stripe-php": "^13",
+        "symfony/http-client": "^7.0",
         "symfony/translation": "^6.4",
         "tronovav/geoip2-update": "^2.3.1",
         "twig/twig": "^3.8",

+ 58 - 129
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "2ef8e259b1374393f8cbb0e2f5ab87e6",
+    "content-hash": "9da81b5aa6d2908d2c465e277de35f2d",
     "packages": [
         {
             "name": "anankke/omnipay-alipay",
@@ -123,16 +123,16 @@
         },
         {
             "name": "aws/aws-sdk-php",
-            "version": "3.293.2",
+            "version": "3.293.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/aws/aws-sdk-php.git",
-                "reference": "1d3e952ea2f45bb0d42d7f873d1b4957bb6362c4"
+                "reference": "a4b5523d5bde20fbaa35f439f8ca57ab2b4a753d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1d3e952ea2f45bb0d42d7f873d1b4957bb6362c4",
-                "reference": "1d3e952ea2f45bb0d42d7f873d1b4957bb6362c4",
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/a4b5523d5bde20fbaa35f439f8ca57ab2b4a753d",
+                "reference": "a4b5523d5bde20fbaa35f439f8ca57ab2b4a753d",
                 "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.293.2"
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.293.3"
             },
-            "time": "2023-12-01T19:06:15+00:00"
+            "time": "2023-12-04T19:09:01+00:00"
         },
         {
             "name": "bacon/bacon-qr-code",
@@ -821,28 +821,28 @@
         },
         {
             "name": "geoip2/geoip2",
-            "version": "v2.13.0",
+            "version": "v3.0.0",
             "source": {
                 "type": "git",
                 "url": "[email protected]:maxmind/GeoIP2-php.git",
-                "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23"
+                "reference": "1a802ce9356cdd1c6b681c030fd9563750e11e6a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
-                "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
+                "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/1a802ce9356cdd1c6b681c030fd9563750e11e6a",
+                "reference": "1a802ce9356cdd1c6b681c030fd9563750e11e6a",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "maxmind-db/reader": "~1.8",
+                "maxmind-db/reader": "^1.11.1",
                 "maxmind/web-service-common": "~0.8",
-                "php": ">=7.2"
+                "php": ">=8.1"
             },
             "require-dev": {
                 "friendsofphp/php-cs-fixer": "3.*",
                 "phpstan/phpstan": "*",
-                "phpunit/phpunit": "^8.0 || ^9.0",
+                "phpunit/phpunit": "^10.0",
                 "squizlabs/php_codesniffer": "3.*"
             },
             "type": "library",
@@ -871,7 +871,7 @@
                 "geolocation",
                 "maxmind"
             ],
-            "time": "2022-08-05T20:32:58+00:00"
+            "time": "2023-12-04T17:16:34+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",
@@ -1198,64 +1198,6 @@
             ],
             "time": "2023-12-03T20:05:35+00:00"
         },
-        {
-            "name": "http-interop/http-factory-guzzle",
-            "version": "1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/http-interop/http-factory-guzzle.git",
-                "reference": "8f06e92b95405216b237521cc64c804dd44c4a81"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/http-interop/http-factory-guzzle/zipball/8f06e92b95405216b237521cc64c804dd44c4a81",
-                "reference": "8f06e92b95405216b237521cc64c804dd44c4a81",
-                "shasum": ""
-            },
-            "require": {
-                "guzzlehttp/psr7": "^1.7||^2.0",
-                "php": ">=7.3",
-                "psr/http-factory": "^1.0"
-            },
-            "provide": {
-                "psr/http-factory-implementation": "^1.0"
-            },
-            "require-dev": {
-                "http-interop/http-factory-tests": "^0.9",
-                "phpunit/phpunit": "^9.5"
-            },
-            "suggest": {
-                "guzzlehttp/psr7": "Includes an HTTP factory starting in version 2.0"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Http\\Factory\\Guzzle\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "An HTTP Factory using Guzzle PSR7",
-            "keywords": [
-                "factory",
-                "http",
-                "psr-17",
-                "psr-7"
-            ],
-            "support": {
-                "issues": "https://github.com/http-interop/http-factory-guzzle/issues",
-                "source": "https://github.com/http-interop/http-factory-guzzle/tree/1.2.0"
-            },
-            "time": "2021-07-21T13:50:14+00:00"
-        },
         {
             "name": "illuminate/collections",
             "version": "v10.34.2",
@@ -2675,16 +2617,16 @@
         },
         {
             "name": "openai-php/client",
-            "version": "v0.7.10",
+            "version": "v0.8.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/openai-php/client.git",
-                "reference": "f9af25d7d7bd8e58f60ada6c30f1c93d65c73833"
+                "reference": "d0e4996f6446ced6ad35ec0ea6af20e3596c648f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/openai-php/client/zipball/f9af25d7d7bd8e58f60ada6c30f1c93d65c73833",
-                "reference": "f9af25d7d7bd8e58f60ada6c30f1c93d65c73833",
+                "url": "https://api.github.com/repos/openai-php/client/zipball/d0e4996f6446ced6ad35ec0ea6af20e3596c648f",
+                "reference": "d0e4996f6446ced6ad35ec0ea6af20e3596c648f",
                 "shasum": ""
             },
             "require": {
@@ -2699,15 +2641,15 @@
             "require-dev": {
                 "guzzlehttp/guzzle": "^7.8.0",
                 "guzzlehttp/psr7": "^2.6.1",
-                "laravel/pint": "^1.13.2",
-                "nunomaduro/collision": "^7.9.0",
-                "pestphp/pest": "^2.19.2",
-                "pestphp/pest-plugin-arch": "^2.3.3",
-                "pestphp/pest-plugin-mock": "^2.0.0",
-                "pestphp/pest-plugin-type-coverage": "^2.2.0",
-                "phpstan/phpstan": "^1.10.35",
+                "laravel/pint": "^1.13.6",
+                "mockery/mockery": "^1.6.6",
+                "nunomaduro/collision": "^7.10.0",
+                "pestphp/pest": "^2.25.0",
+                "pestphp/pest-plugin-arch": "^2.4.1",
+                "pestphp/pest-plugin-type-coverage": "^2.5.0",
+                "phpstan/phpstan": "^1.10.44",
                 "rector/rector": "^0.16.0",
-                "symfony/var-dumper": "^6.3.4"
+                "symfony/var-dumper": "^6.3.8"
             },
             "type": "library",
             "autoload": {
@@ -2747,7 +2689,7 @@
             ],
             "support": {
                 "issues": "https://github.com/openai-php/client/issues",
-                "source": "https://github.com/openai-php/client/tree/v0.7.10"
+                "source": "https://github.com/openai-php/client/tree/v0.8.0"
             },
             "funding": [
                 {
@@ -2763,7 +2705,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-11-14T13:39:26+00:00"
+            "time": "2023-11-23T14:04:47+00:00"
         },
         {
             "name": "ozdemir/datatables",
@@ -4327,22 +4269,20 @@
         },
         {
             "name": "sentry/sdk",
-            "version": "3.6.0",
+            "version": "4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/getsentry/sentry-php-sdk.git",
-                "reference": "24c235ff2027401cbea099bf88689e1a1f197c7a"
+                "reference": "fcbca864e8d1dc712f3ecfaa95ea89d024fb2e53"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/getsentry/sentry-php-sdk/zipball/24c235ff2027401cbea099bf88689e1a1f197c7a",
-                "reference": "24c235ff2027401cbea099bf88689e1a1f197c7a",
+                "url": "https://api.github.com/repos/getsentry/sentry-php-sdk/zipball/fcbca864e8d1dc712f3ecfaa95ea89d024fb2e53",
+                "reference": "fcbca864e8d1dc712f3ecfaa95ea89d024fb2e53",
                 "shasum": ""
             },
             "require": {
-                "http-interop/http-factory-guzzle": "^1.0",
-                "sentry/sentry": "^3.22",
-                "symfony/http-client": "^4.3|^5.0|^6.0|^7.0"
+                "sentry/sentry": "^4.0"
             },
             "type": "metapackage",
             "notification-url": "https://packagist.org/downloads/",
@@ -4355,7 +4295,7 @@
                     "email": "[email protected]"
                 }
             ],
-            "description": "This is a metapackage shipping sentry/sentry with a recommended HTTP client.",
+            "description": "This is a meta package of sentry/sentry. We recommend using sentry/sentry directly.",
             "homepage": "http://sentry.io",
             "keywords": [
                 "crash-reporting",
@@ -4368,7 +4308,7 @@
             ],
             "support": {
                 "issues": "https://github.com/getsentry/sentry-php-sdk/issues",
-                "source": "https://github.com/getsentry/sentry-php-sdk/tree/3.6.0"
+                "source": "https://github.com/getsentry/sentry-php-sdk/tree/4.0.0"
             },
             "funding": [
                 {
@@ -4380,55 +4320,42 @@
                     "type": "custom"
                 }
             ],
-            "time": "2023-12-04T10:49:33+00:00"
+            "time": "2023-11-06T10:23:19+00:00"
         },
         {
             "name": "sentry/sentry",
-            "version": "3.22.1",
+            "version": "4.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/getsentry/sentry-php.git",
-                "reference": "8859631ba5ab15bc1af420b0eeed19ecc6c9d81d"
+                "reference": "89666f297891ff937fceb2f3d1fb967a6848cf37"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/8859631ba5ab15bc1af420b0eeed19ecc6c9d81d",
-                "reference": "8859631ba5ab15bc1af420b0eeed19ecc6c9d81d",
+                "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/89666f297891ff937fceb2f3d1fb967a6848cf37",
+                "reference": "89666f297891ff937fceb2f3d1fb967a6848cf37",
                 "shasum": ""
             },
             "require": {
+                "ext-curl": "*",
                 "ext-json": "*",
                 "ext-mbstring": "*",
-                "guzzlehttp/promises": "^1.5.3|^2.0",
+                "guzzlehttp/psr7": "^1.8.4|^2.1.1",
                 "jean85/pretty-package-versions": "^1.5|^2.0.4",
                 "php": "^7.2|^8.0",
-                "php-http/async-client-implementation": "^1.0",
-                "php-http/client-common": "^1.5|^2.0",
-                "php-http/discovery": "^1.15",
-                "php-http/httplug": "^1.1|^2.0",
-                "php-http/message": "^1.5",
-                "php-http/message-factory": "^1.1",
-                "psr/http-factory": "^1.0",
-                "psr/http-factory-implementation": "^1.0",
                 "psr/log": "^1.0|^2.0|^3.0",
-                "symfony/options-resolver": "^3.4.43|^4.4.30|^5.0.11|^6.0|^7.0",
-                "symfony/polyfill-php80": "^1.17"
+                "symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0"
             },
             "conflict": {
-                "php-http/client-common": "1.8.0",
                 "raven/raven": "*"
             },
             "require-dev": {
-                "friendsofphp/php-cs-fixer": "^2.19|3.4.*",
+                "friendsofphp/php-cs-fixer": "^3.4",
+                "guzzlehttp/promises": "^1.0|^2.0",
                 "guzzlehttp/psr7": "^1.8.4|^2.1.1",
-                "http-interop/http-factory-guzzle": "^1.0",
                 "monolog/monolog": "^1.6|^2.0|^3.0",
-                "nikic/php-parser": "^4.10.3",
-                "php-http/mock-client": "^1.3",
                 "phpbench/phpbench": "^1.0",
-                "phpstan/extension-installer": "^1.0",
                 "phpstan/phpstan": "^1.3",
-                "phpstan/phpstan-phpunit": "^1.0",
                 "phpunit/phpunit": "^8.5.14|^9.4",
                 "symfony/phpunit-bridge": "^5.2|^6.0",
                 "vimeo/psalm": "^4.17"
@@ -4455,7 +4382,7 @@
                     "email": "[email protected]"
                 }
             ],
-            "description": "A PHP SDK for Sentry (http://sentry.io)",
+            "description": "PHP SDK for Sentry (http://sentry.io)",
             "homepage": "http://sentry.io",
             "keywords": [
                 "crash-reporting",
@@ -4464,11 +4391,13 @@
                 "error-monitoring",
                 "log",
                 "logging",
-                "sentry"
+                "profiling",
+                "sentry",
+                "tracing"
             ],
             "support": {
                 "issues": "https://github.com/getsentry/sentry-php/issues",
-                "source": "https://github.com/getsentry/sentry-php/tree/3.22.1"
+                "source": "https://github.com/getsentry/sentry-php/tree/4.1.0"
             },
             "funding": [
                 {
@@ -4480,7 +4409,7 @@
                     "type": "custom"
                 }
             ],
-            "time": "2023-11-13T11:47:28+00:00"
+            "time": "2023-12-04T12:41:21+00:00"
         },
         {
             "name": "slim/http",
@@ -4851,16 +4780,16 @@
         },
         {
             "name": "stripe/stripe-php",
-            "version": "v12.8.0",
+            "version": "v13.5.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/stripe/stripe-php.git",
-                "reference": "6b6f4a775ad46fee4b1df2df4fdfa574365b1621"
+                "reference": "a688c0ee7c0a2d162dee5c80b85d017cdd8d5e37"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/6b6f4a775ad46fee4b1df2df4fdfa574365b1621",
-                "reference": "6b6f4a775ad46fee4b1df2df4fdfa574365b1621",
+                "url": "https://api.github.com/repos/stripe/stripe-php/zipball/a688c0ee7c0a2d162dee5c80b85d017cdd8d5e37",
+                "reference": "a688c0ee7c0a2d162dee5c80b85d017cdd8d5e37",
                 "shasum": ""
             },
             "require": {
@@ -4904,9 +4833,9 @@
             ],
             "support": {
                 "issues": "https://github.com/stripe/stripe-php/issues",
-                "source": "https://github.com/stripe/stripe-php/tree/v12.8.0"
+                "source": "https://github.com/stripe/stripe-php/tree/v13.5.0"
             },
-            "time": "2023-10-16T18:04:12+00:00"
+            "time": "2023-11-30T18:11:45+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",

+ 1 - 18
src/Controllers/SubController.php

@@ -10,7 +10,6 @@ use App\Models\SubscribeLog;
 use App\Services\RateLimit;
 use App\Services\Subscribe;
 use App\Utils\ResponseHelper;
-use App\Utils\Tools;
 use GuzzleHttp\Exception\GuzzleException;
 use Psr\Http\Client\ClientExceptionInterface;
 use Psr\Http\Message\ResponseInterface;
@@ -33,10 +32,9 @@ final class SubController extends BaseController
      * @throws RedisException
      * @throws TelegramSDKException
      */
-    public function getUniversalSubContent($request, $response, $args): ResponseInterface
+    public function index($request, $response, $args): ResponseInterface
     {
         $err_msg = '订阅链接无效';
-
         $subtype = $args['subtype'];
         $subtype_list = ['json', 'clash', 'sip008', 'singbox', 'sip002', 'ss', 'v2ray', 'trojan'];
 
@@ -84,19 +82,4 @@ final class SubController extends BaseController
             ->withHeader('Content-Type', $content_type)
             ->write($sub_info);
     }
-
-    public static function getUniversalSubLink($user): string
-    {
-        $userid = $user->id;
-        $token = (new Link())->where('userid', $userid)->first();
-
-        if ($token === null) {
-            $token = new Link();
-            $token->userid = $userid;
-            $token->token = Tools::genSubToken();
-            $token->save();
-        }
-
-        return $_ENV['subUrl'] . '/sub/' . $token->token;
-    }
 }

+ 2 - 1
src/Controllers/UserController.php

@@ -13,6 +13,7 @@ use App\Models\OnlineLog;
 use App\Models\Payback;
 use App\Services\Auth;
 use App\Services\Captcha;
+use App\Services\Subscribe;
 use App\Utils\ResponseHelper;
 use App\Utils\Tools;
 use Exception;
@@ -43,7 +44,7 @@ final class UserController extends BaseController
                 ->assign('ann', (new Ann())->orderBy('date', 'desc')->first())
                 ->assign('captcha', $captcha)
                 ->assign('class_expire_days', $class_expire_days)
-                ->assign('UniversalSub', SubController::getUniversalSubLink($this->user))
+                ->assign('UniversalSub', Subscribe::getUniversalSubLink($this->user))
                 ->fetch('user/index.tpl')
         );
     }

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

@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace App\Services\Bot\Telegram;
 
-use App\Controllers\SubController;
 use App\Models\Config;
 use App\Models\InviteCode;
 use App\Models\LoginIp;
@@ -12,6 +11,7 @@ use App\Models\OnlineLog;
 use App\Models\Payback;
 use App\Models\SubscribeLog;
 use App\Models\User;
+use App\Services\Subscribe;
 use App\Utils\Tools;
 use GuzzleHttp\Exception\GuzzleException;
 use Illuminate\Database\Eloquent\Model;
@@ -816,7 +816,7 @@ final class Callback
 
             $sendMessage = [];
 
-            $UniversalSub_Url = SubController::getUniversalSubLink($this->user);
+            $UniversalSub_Url = Subscribe::getUniversalSubLink($this->user);
 
             $text = match ($CallbackDataExplode[1]) {
                 'json' => 'Json 通用订阅地址:' . PHP_EOL . PHP_EOL .

+ 22 - 5
src/Services/Subscribe.php

@@ -4,6 +4,7 @@ declare(strict_types=1);
 
 namespace App\Services;
 
+use App\Models\Link;
 use App\Models\Node;
 use App\Services\Subscribe\Clash;
 use App\Services\Subscribe\Json;
@@ -13,10 +14,26 @@ use App\Services\Subscribe\SIP008;
 use App\Services\Subscribe\SS;
 use App\Services\Subscribe\Trojan;
 use App\Services\Subscribe\V2Ray;
+use App\Utils\Tools;
 use Illuminate\Support\Collection;
 
 final class Subscribe
 {
+    public static function getUniversalSubLink($user): string
+    {
+        $userid = $user->id;
+        $token = (new Link())->where('userid', $userid)->first();
+
+        if ($token === null) {
+            $token = new Link();
+            $token->userid = $userid;
+            $token->token = Tools::genSubToken();
+            $token->save();
+        }
+
+        return $_ENV['subUrl'] . '/sub/' . $token->token;
+    }
+
     /**
      * @param $user
      *
@@ -39,6 +56,11 @@ final class Subscribe
             ->get();
     }
 
+    public static function getContent($user, $type): string
+    {
+        return self::getClient($type)->getContent($user);
+    }
+
     public static function getClient($type): Json|SS|SIP002|V2Ray|Trojan|Clash|SIP008|SingBox
     {
         return match ($type) {
@@ -52,9 +74,4 @@ final class Subscribe
             default => new Json(),
         };
     }
-
-    public static function getContent($user, $type): string
-    {
-        return self::getClient($type)->getContent($user);
-    }
 }

+ 12 - 104
src/Services/Subscribe/Json.php

@@ -5,119 +5,27 @@ declare(strict_types=1);
 namespace App\Services\Subscribe;
 
 use App\Services\Subscribe;
-use function json_decode;
 
 final class Json extends Base
 {
     public function getContent($user): string
     {
-        $nodes = [];
-        $nodes_raw = Subscribe::getUserSubNodes($user);
-
-        foreach ($nodes_raw as $node_raw) {
-            $node_custom_config = json_decode($node_raw->custom_config, true);
-
-            switch ((int) $node_raw->sort) {
-                case 0:
-                    $plugin = $node_custom_config['plugin'] ?? '';
-                    $plugin_option = $node_custom_config['plugin_option'] ?? '';
-                    $node = [
-                        'name' => $node_raw->name,
-                        'id' => $node_raw->id,
-                        'type' => 'ss',
-                        'address' => $node_raw->server,
-                        'port' => (int) $user->port,
-                        'password' => $user->passwd,
-                        'encryption' => $user->method,
-                        'plugin' => $plugin,
-                        'plugin_option' => $plugin_option,
-                        'remark' => $node_raw->info,
-                    ];
-                    break;
-                case 11:
-                    $v2_port = $node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443);
-                    $security = $node_custom_config['security'] ?? 'none';
-                    $flow = $node_custom_config['flow'] ?? '';
-                    $encryption = $node_custom_config['encryption'] ?? '';
-                    $network = $node_custom_config['network'] ?? '';
-                    $header = $node_custom_config['header'] ?? ['type' => 'none'];
-                    $header_type = $header['type'] ?? '';
-                    $host = $node_custom_config['header']['request']['headers']['Host'][0] ??
-                        $node_custom_config['host'] ?? '';
-                    $servicename = $node_custom_config['servicename'] ?? '';
-                    $path = $node_custom_config['header']['request']['path'][0] ?? $node_custom_config['path'] ?? '/';
-                    $tls = $security === 'tls' ? '1' : '0';
-                    $node = [
-                        'name' => $node_raw->name,
-                        'id' => $node_raw->id,
-                        'type' => 'vmess',
-                        'address' => $node_raw->server,
-                        'port' => (int) $v2_port,
-                        'uuid' => $user->uuid,
-                        'alterid' => 0,
-                        'security' => $security,
-                        'flow' => $flow,
-                        'encryption' => $encryption,
-                        'network' => $network,
-                        'header' => $header,
-                        'header_type' => $header_type,
-                        'host' => $host,
-                        'path' => $path,
-                        'servicename' => $servicename,
-                        'tls' => (int) $tls,
-                        'remark' => $node_raw->info,
-                    ];
-                    break;
-                case 14:
-                    $trojan_port = $node_custom_config['offset_port_user'] ?? ($node_custom_config['offset_port_node'] ?? 443);
-                    $host = $node_custom_config['host'] ?? '';
-                    $allow_insecure = $node_custom_config['allow_insecure'] ?? '0';
-                    $mux = $node_custom_config['mux'] ?? '';
-                    $network = $node_custom_config['network'] ?? 'tcp';
-                    $transport_plugin = $node_custom_config['transport_plugin'] ?? '';
-                    $transport_method = $node_custom_config['transport_method'] ?? '';
-                    $servicename = $node_custom_config['servicename'] ?? '';
-                    $path = $node_custom_config['path'] ?? '';
-                    $node = [
-                        'name' => $node_raw->name,
-                        'id' => $node_raw->id,
-                        'type' => 'trojan',
-                        'address' => $node_raw->server,
-                        'host' => $host,
-                        'port' => (int) $trojan_port,
-                        'uuid' => $user->uuid,
-                        'mux' => $mux,
-                        'transport' => $network,
-                        'transport_plugin' => $transport_plugin,
-                        'transport_method' => $transport_method,
-                        'allow_insecure' => (int) $allow_insecure,
-                        'servicename' => $servicename,
-                        'path' => $path,
-                        'remark' => $node_raw->info,
-                    ];
-                    break;
-                default:
-                    $node = [];
-                    break;
-            }
-
-            if ($node === []) {
-                continue;
-            }
-
-            $nodes[] = $node;
-        }
+        $sub_url = Subscribe::getUniversalSubLink($user);
 
         return json_encode([
-            'version' => 3,
+            'version' => 4,
             'sub_name' => $_ENV['appName'],
-            'user_email' => $user->email,
+            'email' => $user->email,
             'user_name' => $user->user_name,
-            'user_class' => $user->class,
-            'user_class_expire_date' => $user->class_expire,
-            'user_total_traffic' => $user->transfer_enable,
-            'user_used_traffic' => $user->u + $user->d,
-            'nodes' => $nodes,
+            'class' => $user->class,
+            'class_expire_date' => $user->class_expire,
+            'total_traffic' => $user->transfer_enable,
+            'used_upload_traffic' => $user->u,
+            'used_download_traffic' => $user->d,
+            'sub_url' => [
+                'sing-box' => $sub_url . '/singbox',
+                'clash' => $sub_url . '/clash',
+            ],
         ]);
     }
 }