From 261487437b10d648571ed4b91fafeaf8433234e5 Mon Sep 17 00:00:00 2001 From: LinusX Date: Wed, 5 Jun 2024 07:55:49 +0800 Subject: [PATCH 01/66] =?UTF-8?q?[update]=20=E6=96=B0=E5=A2=9Estripe?= =?UTF-8?q?=E8=81=9A=E5=90=88=E6=94=AF=E4=BB=98=E6=96=B9=E5=BC=8F=EF=BC=8C?= =?UTF-8?q?=E9=87=87=E7=94=A8=E5=85=A8=E6=96=B0=E7=9A=84paymentIntents=20A?= =?UTF-8?q?PI=20[fix]=20=E4=BF=AE=E6=94=B9=E6=94=AF=E4=BB=98=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=E4=B8=AD=E7=9A=84=E5=B0=8Fbug=20[update]=20=E5=B0=86s?= =?UTF-8?q?tripe-php=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7=E8=87=B3=E6=9C=80?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Payments/BTCPay.php | 5 +- app/Payments/StripeALLInOne.php | 173 ++++++++++++++++++++++++++++++++ composer.json | 2 +- 3 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 app/Payments/StripeALLInOne.php diff --git a/app/Payments/BTCPay.php b/app/Payments/BTCPay.php index f2db1d1..60ca039 100644 --- a/app/Payments/BTCPay.php +++ b/app/Payments/BTCPay.php @@ -76,14 +76,13 @@ class BTCPay //NOT BTCPay-Sig //API doc is WRONG! $headerName = 'Btcpay-Sig'; - $signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : ''; + $signatureHeader = isset($headers[$headerName]) ? $headers[$headerName] : ''; $json_param = json_decode($payload, true); $computedSignature = "sha256=" . \hash_hmac('sha256', $payload, $this->config['btcpay_webhook_key']); - if (!self::hashEqual($signraturHeader, $computedSignature)) { + if (!self::hashEqual($signatureHeader, $computedSignature)) { throw new ApiException('HMAC signature does not match', 400); - return false; } //get order id store in metadata diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php new file mode 100644 index 0000000..9543d51 --- /dev/null +++ b/app/Payments/StripeALLInOne.php @@ -0,0 +1,173 @@ +config = $config; + } + + public function form() + { + return [ + 'currency' => [ + 'label' => '货币单位', + 'description' => '请使用符合ISO 4217标准的三位字母,例如GBP', + 'type' => 'input', + ], + 'stripe_sk_live' => [ + 'label' => 'SK_LIVE', + 'description' => '', + 'type' => 'input', + ], + 'stripe_webhook_key' => [ + 'label' => 'WebHook密钥签名', + 'description' => 'whsec_....', + 'type' => 'input', + ], + 'description' => [ + 'label' => '自定义商品介绍', + 'description' => '', + 'type' => 'input', + ], + 'payment_method' => [ + 'label' => '支付方式', + 'description' => '请输入alipay或者wechat_pay', + 'type' => 'input', + ] + ]; + } + + public function pay($order) + { + $currency = $this->config['currency']; + $exchange = $this->exchange('CNY', strtoupper($currency)); + if (!$exchange) { + throw new ApiException(__('Currency conversion has timed out, please try again later')); + } + $stripe = new \Stripe\StripeClient($this->config['stripe_sk_live']); + + + $stripePaymentMethod = $stripe->paymentMethods->create([ + 'type' => $this->config['payment_method'], + ]); + // 准备支付意图的基础参数 + $params = [ + 'amount' => floor($order['total_amount'] * $exchange), + 'currency' => $currency, + 'confirm' => true, + 'payment_method' => $stripePaymentMethod->id, + 'automatic_payment_methods' => ['enabled' => true], + 'statement_descriptor' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), + 'description' => $this->config['description'], + 'metadata' => [ + 'user_id' => $order['user_id'], + 'out_trade_no' => $order['trade_no'], + 'identifier' => '' + ], + 'return_url' => $order['return_url'] + ]; + + // 如果支付方式为 wechat_pay,添加相应的支付方式选项 + if ($this->config['payment_method'] === 'wechat_pay') { + $params['payment_method_options'] = [ + 'wechat_pay' => [ + 'client' => 'web' + ], + ]; + } + //更新支持最新的paymentIntents方法,Sources API将在今年被彻底替 + $stripeIntents = $stripe->paymentIntents->create($params); + + $nextAction = null; + //jump url + $jumpUrl = null; + $actionType = 0; + if (!$stripeIntents['next_action']) { + throw new ApiException(__('Payment gateway request failed')); + }else { + $nextAction = $stripeIntents['next_action']; + } + + switch ($this->config['payment_method']){ + case "alipay": + if (isset($nextAction['alipay_handle_redirect'])){ + $jumpUrl = $nextAction['alipay_handle_redirect']['url']; + $actionType = 1; + }else { + throw new ApiException('unable get alipay redirect url', 500); + } + break; + case "wechat_pay": + if (isset($nextAction['wechat_pay_display_qr_code'])){ + $jumpUrl = $nextAction['wechat_pay_display_qr_code']['data']; + Log::info($jumpUrl); + }else { + throw new ApiException('unable get alipay redirect url', 500); + } + } + return [ + 'type' => $actionType, + 'data' => $jumpUrl + ]; + } + + public function notify($params) + { + try { + \Stripe\Stripe::setApiKey($this->config['stripe_sk_live']); + //Workerman不支持使用php://input, stripe同时要求验证签名的payload不能经过修改,所以使用这个方法 + $payload = $GLOBALS['HTTP_RAW_POST_DATA']; + $headers = getallheaders(); + $headerName = 'Stripe-Signature'; + $signatureHeader = $headers[$headerName] ?? ''; + $event = \Stripe\Webhook::constructEvent( + $payload, + $signatureHeader, + $this->config['stripe_webhook_key'] + ); + + } catch (\UnexpectedValueException $e){ + throw new ApiException('Error parsing payload', 400); + + } + catch (\Stripe\Exception\SignatureVerificationException $e) { + throw new ApiException('signature not match', 400); + } + switch ($event->type) { + case 'payment_intent.succeeded': + $object = $event->data->object; + if ($object->status === 'succeeded') { + if (!isset($object->metadata->out_trade_no)) { + return('order error'); + } + $metaData = $object->metadata; + $tradeNo = $metaData->out_trade_no; + return [ + 'trade_no' => $tradeNo, + 'callback_no' => $object->id + ]; + } + break; + default: + throw new ApiException('event is not support'); + } + return('success'); + } + + private function exchange($from, $to) + { + $from = strtolower($from); + $to = strtolower($to); + $result = file_get_contents("https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/" . $from . ".min.json"); + $result = json_decode($result, true); + return $result[$from][$to]; + } +} diff --git a/composer.json b/composer.json index bfccc63..70c2c94 100755 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "paragonie/sodium_compat": "^1.20", "php-curl-class/php-curl-class": "^8.6", "spatie/db-dumper": "^3.4", - "stripe/stripe-php": "^7.36.1", + "stripe/stripe-php": "^v14.9.0", "symfony/http-client": "^6.4", "symfony/mailgun-mailer": "^6.4", "symfony/yaml": "*", From 9270d94668ac9146ee9e26e0a2abd817c768d2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Thu, 13 Jun 2024 18:40:40 +0800 Subject: [PATCH 02/66] Update StripeALLInOne.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复部分报错语句不规范 --- app/Payments/StripeALLInOne.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php index 9543d51..d7aa413 100644 --- a/app/Payments/StripeALLInOne.php +++ b/app/Payments/StripeALLInOne.php @@ -102,7 +102,7 @@ class StripeALLInOne { $jumpUrl = $nextAction['alipay_handle_redirect']['url']; $actionType = 1; }else { - throw new ApiException('unable get alipay redirect url', 500); + throw new ApiException('unable get Alipay redirect url', 500); } break; case "wechat_pay": @@ -110,7 +110,7 @@ class StripeALLInOne { $jumpUrl = $nextAction['wechat_pay_display_qr_code']['data']; Log::info($jumpUrl); }else { - throw new ApiException('unable get alipay redirect url', 500); + throw new ApiException('unable get WeChat Pay redirect url', 500); } } return [ From fc283af60f526a8229e2c78b19f8814bc7f56d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Thu, 13 Jun 2024 18:47:04 +0800 Subject: [PATCH 03/66] Update StripeALLInOne.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除调试冗余代码 --- app/Payments/StripeALLInOne.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php index d7aa413..b997c81 100644 --- a/app/Payments/StripeALLInOne.php +++ b/app/Payments/StripeALLInOne.php @@ -4,9 +4,7 @@ * 自己写别抄,抄NMB抄 */ namespace App\Payments; - use App\Exceptions\ApiException; -use Illuminate\Support\Facades\Log; class StripeALLInOne { public function __construct($config) @@ -108,7 +106,6 @@ class StripeALLInOne { case "wechat_pay": if (isset($nextAction['wechat_pay_display_qr_code'])){ $jumpUrl = $nextAction['wechat_pay_display_qr_code']['data']; - Log::info($jumpUrl); }else { throw new ApiException('unable get WeChat Pay redirect url', 500); } From 338aad7f6cfa6d01a2d2bfd7f68e963455ba1a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Thu, 13 Jun 2024 23:25:23 +0800 Subject: [PATCH 04/66] Fix PaymentController.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复由Jun 8, 2024提交的2个commit产生的报错 --- app/Http/Controllers/V1/Guest/PaymentController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Controllers/V1/Guest/PaymentController.php b/app/Http/Controllers/V1/Guest/PaymentController.php index 07a8bb0..a917806 100644 --- a/app/Http/Controllers/V1/Guest/PaymentController.php +++ b/app/Http/Controllers/V1/Guest/PaymentController.php @@ -9,6 +9,7 @@ use App\Services\OrderService; use App\Services\PaymentService; use App\Services\TelegramService; use Illuminate\Http\Request; +use App\Models\Payment; class PaymentController extends Controller { From bab7ed8e97e78986989479c568244b08878bd6e7 Mon Sep 17 00:00:00 2001 From: LinusX Date: Sat, 15 Jun 2024 01:42:43 +0800 Subject: [PATCH 05/66] =?UTF-8?q?[fix]=20=E4=BF=AE=E5=A4=8Dcatch=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E5=80=99=E5=8F=98=E9=87=8F=E5=8F=AF=E8=83=BDundefined?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Console/Commands/BackupDatabase.php | 5 +++-- app/Payments/StripeALLInOne.php | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Console/Commands/BackupDatabase.php b/app/Console/Commands/BackupDatabase.php index 22a3c3c..377a6e6 100644 --- a/app/Console/Commands/BackupDatabase.php +++ b/app/Console/Commands/BackupDatabase.php @@ -26,9 +26,10 @@ class BackupDatabase extends Command } // 数据库备份逻辑 + $databaseBackupPath = storage_path('backup/' . now()->format('Y-m-d_H-i-s') . '_' . config('database.connections.mysql.database') . '_database_backup.sql'); + $compressedBackupPath = $databaseBackupPath . '.gz'; try{ if (config('database.default') === 'mysql'){ - $databaseBackupPath = storage_path('backup/' . now()->format('Y-m-d_H-i-s') . '_' . config('database.connections.mysql.database') . '_database_backup.sql'); $this->info("1️⃣:开始备份Mysql"); \Spatie\DbDumper\Databases\MySql::create() ->setHost(config('database.connections.mysql.host')) @@ -83,7 +84,7 @@ class BackupDatabase extends Command $bucket->upload(fopen($compressedBackupPath, 'r'), [ 'name' => $objectName, ]); - + // 输出文件链接 \Log::channel('backup')->info("🎉:数据库备份已上传到 Google Cloud Storage: $objectName"); $this->info("🎉:数据库备份已上传到 Google Cloud Storage: $objectName"); diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php index b997c81..2847beb 100644 --- a/app/Payments/StripeALLInOne.php +++ b/app/Payments/StripeALLInOne.php @@ -48,7 +48,7 @@ class StripeALLInOne { $currency = $this->config['currency']; $exchange = $this->exchange('CNY', strtoupper($currency)); if (!$exchange) { - throw new ApiException(__('Currency conversion has timed out, please try again later')); + throw new ApiException('Currency conversion has timed out, please try again later', 500); } $stripe = new \Stripe\StripeClient($this->config['stripe_sk_live']); From 8cc247b65354ea18947ebca01e192d0b6b58f634 Mon Sep 17 00:00:00 2001 From: LinusX Date: Sat, 15 Jun 2024 02:16:54 +0800 Subject: [PATCH 06/66] =?UTF-8?q?[feat]=20=E6=96=B0=E5=A2=9Etelegram?= =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA/start=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Plugins/Telegram/Commands/GetLatestUrl.php | 2 +- app/Plugins/Telegram/Commands/Start.php | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 app/Plugins/Telegram/Commands/Start.php diff --git a/app/Plugins/Telegram/Commands/GetLatestUrl.php b/app/Plugins/Telegram/Commands/GetLatestUrl.php index 0d34b77..44afdfb 100644 --- a/app/Plugins/Telegram/Commands/GetLatestUrl.php +++ b/app/Plugins/Telegram/Commands/GetLatestUrl.php @@ -7,7 +7,7 @@ use App\Plugins\Telegram\Telegram; class GetLatestUrl extends Telegram { public $command = '/getlatesturl'; - public $description = '将Telegram账号绑定到网站'; + public $description = '获取网站最新网址'; public function handle($message, $match = []) { $telegramService = $this->telegramService; diff --git a/app/Plugins/Telegram/Commands/Start.php b/app/Plugins/Telegram/Commands/Start.php new file mode 100644 index 0000000..add3db0 --- /dev/null +++ b/app/Plugins/Telegram/Commands/Start.php @@ -0,0 +1,17 @@ +is_private) return; + $telegramService = $this->telegramService; + $text = "/start 显示所有可用指令\n /bind+空格+订阅链接,将telegram绑定至账户\n /traffic 获取当前使用流量 \n /getlatesturl 获取网站最新网址 \n /unbind 解绑telegram账户"; + $telegramService->sendMessage($message->chat_id, $text, 'markdown'); + } +} From f0c620cbc219534f05a6e4dbc6967206cbcb7d09 Mon Sep 17 00:00:00 2001 From: LinusX Date: Mon, 17 Jun 2024 22:58:53 +0800 Subject: [PATCH 07/66] =?UTF-8?q?[fix]=20=E5=88=A0=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=8C=85=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/V1/Guest/PaymentController.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Http/Controllers/V1/Guest/PaymentController.php b/app/Http/Controllers/V1/Guest/PaymentController.php index 8ff1186..0f11867 100644 --- a/app/Http/Controllers/V1/Guest/PaymentController.php +++ b/app/Http/Controllers/V1/Guest/PaymentController.php @@ -10,7 +10,6 @@ use App\Services\OrderService; use App\Services\PaymentService; use App\Services\TelegramService; use Illuminate\Http\Request; -use App\Models\Payment; class PaymentController extends Controller { @@ -58,7 +57,7 @@ class PaymentController extends Controller $payment->name, $order->trade_no ); - + $telegramService->sendMessageWithAdmin($message); return true; } From acb40cc1f9de13d1816baa8bc034ba4e52068be7 Mon Sep 17 00:00:00 2001 From: LinusX Date: Tue, 2 Jul 2024 19:02:29 +0800 Subject: [PATCH 08/66] =?UTF-8?q?[update]=20=E6=96=B0=E5=A2=9Ecredit=20car?= =?UTF-8?q?d=E8=B7=B3=E8=BD=AC=E8=87=B3checkout=E9=A1=B5=E9=9D=A2=E4=BB=98?= =?UTF-8?q?=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Payments/StripeALLInOne.php | 154 ++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 57 deletions(-) diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php index 2847beb..9c7e003 100644 --- a/app/Payments/StripeALLInOne.php +++ b/app/Payments/StripeALLInOne.php @@ -37,7 +37,7 @@ class StripeALLInOne { ], 'payment_method' => [ 'label' => '支付方式', - 'description' => '请输入alipay或者wechat_pay', + 'description' => '请输入alipay, wechat_pay, cards', 'type' => 'input', ] ]; @@ -50,66 +50,91 @@ class StripeALLInOne { if (!$exchange) { throw new ApiException('Currency conversion has timed out, please try again later', 500); } - $stripe = new \Stripe\StripeClient($this->config['stripe_sk_live']); - - - $stripePaymentMethod = $stripe->paymentMethods->create([ - 'type' => $this->config['payment_method'], - ]); - // 准备支付意图的基础参数 - $params = [ - 'amount' => floor($order['total_amount'] * $exchange), - 'currency' => $currency, - 'confirm' => true, - 'payment_method' => $stripePaymentMethod->id, - 'automatic_payment_methods' => ['enabled' => true], - 'statement_descriptor' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), - 'description' => $this->config['description'], - 'metadata' => [ - 'user_id' => $order['user_id'], - 'out_trade_no' => $order['trade_no'], - 'identifier' => '' - ], - 'return_url' => $order['return_url'] - ]; - - // 如果支付方式为 wechat_pay,添加相应的支付方式选项 - if ($this->config['payment_method'] === 'wechat_pay') { - $params['payment_method_options'] = [ - 'wechat_pay' => [ - 'client' => 'web' - ], - ]; - } - //更新支持最新的paymentIntents方法,Sources API将在今年被彻底替 - $stripeIntents = $stripe->paymentIntents->create($params); - - $nextAction = null; //jump url $jumpUrl = null; $actionType = 0; - if (!$stripeIntents['next_action']) { - throw new ApiException(__('Payment gateway request failed')); - }else { - $nextAction = $stripeIntents['next_action']; + $stripe = new \Stripe\StripeClient($this->config['stripe_sk_live']); + + if ($this->config['payment_method'] != "cards"){ + $stripePaymentMethod = $stripe->paymentMethods->create([ + 'type' => $this->config['payment_method'], + ]); + // 准备支付意图的基础参数 + $params = [ + 'amount' => floor($order['total_amount'] * $exchange), + 'currency' => $currency, + 'confirm' => true, + 'payment_method' => $stripePaymentMethod->id, + 'automatic_payment_methods' => ['enabled' => true], + 'statement_descriptor' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), + 'description' => $this->config['description'], + 'metadata' => [ + 'user_id' => $order['user_id'], + 'out_trade_no' => $order['trade_no'], + 'identifier' => '' + ], + 'return_url' => $order['return_url'] + ]; + + // 如果支付方式为 wechat_pay,添加相应的支付方式选项 + if ($this->config['payment_method'] === 'wechat_pay') { + $params['payment_method_options'] = [ + 'wechat_pay' => [ + 'client' => 'web' + ], + ]; + } + //更新支持最新的paymentIntents方法,Sources API将在今年被彻底替 + $stripeIntents = $stripe->paymentIntents->create($params); + + $nextAction = null; + + if (!$stripeIntents['next_action']) { + throw new ApiException(__('Payment gateway request failed')); + }else { + $nextAction = $stripeIntents['next_action']; + } + + switch ($this->config['payment_method']){ + case "alipay": + if (isset($nextAction['alipay_handle_redirect'])){ + $jumpUrl = $nextAction['alipay_handle_redirect']['url']; + $actionType = 1; + }else { + throw new ApiException('unable get Alipay redirect url', 500); + } + break; + case "wechat_pay": + if (isset($nextAction['wechat_pay_display_qr_code'])){ + $jumpUrl = $nextAction['wechat_pay_display_qr_code']['data']; + }else { + throw new ApiException('unable get WeChat Pay redirect url', 500); + } + } + } else { + $creditCheckOut = $stripe->checkout->sessions->create([ + 'success_url' => $order['return_url'], + 'client_reference_id' => $order['trade_no'], + 'payment_method_types' => ['card'], + 'line_items' => [ + [ + 'price_data' => [ + 'currency' => $currency, + 'unit_amount' => floor($order['total_amount'] * $exchange), + 'product_data' => [ + 'name' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), + 'description' => $this->config['description'], + ] + ], + 'quantity' => 1, + ], + ], + 'mode' => 'payment', + ]); + $jumpUrl = $creditCheckOut['url']; + $actionType = 1; } - switch ($this->config['payment_method']){ - case "alipay": - if (isset($nextAction['alipay_handle_redirect'])){ - $jumpUrl = $nextAction['alipay_handle_redirect']['url']; - $actionType = 1; - }else { - throw new ApiException('unable get Alipay redirect url', 500); - } - break; - case "wechat_pay": - if (isset($nextAction['wechat_pay_display_qr_code'])){ - $jumpUrl = $nextAction['wechat_pay_display_qr_code']['data']; - }else { - throw new ApiException('unable get WeChat Pay redirect url', 500); - } - } return [ 'type' => $actionType, 'data' => $jumpUrl @@ -133,7 +158,6 @@ class StripeALLInOne { } catch (\UnexpectedValueException $e){ throw new ApiException('Error parsing payload', 400); - } catch (\Stripe\Exception\SignatureVerificationException $e) { throw new ApiException('signature not match', 400); @@ -153,6 +177,22 @@ class StripeALLInOne { ]; } break; + case 'checkout.session.completed': + $object = $event->data->object; + if ($object->payment_status === 'paid') { + return [ + 'trade_no' => $object->client_reference_id, + 'callback_no' => $object->payment_intent + ]; + } + break; + case 'checkout.session.async_payment_succeeded': + $object = $event->data->object; + return [ + 'trade_no' => $object->client_reference_id, + 'callback_no' => $object->payment_intent + ]; + break; default: throw new ApiException('event is not support'); } From 60ed240e6697e09171a4c047e6441e331309d0ce Mon Sep 17 00:00:00 2001 From: Yusum <47137031+yushum@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:16:56 +0800 Subject: [PATCH 09/66] Update ClashMeta.php --- app/Protocols/ClashMeta.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/Protocols/ClashMeta.php b/app/Protocols/ClashMeta.php index aff8982..845e052 100644 --- a/app/Protocols/ClashMeta.php +++ b/app/Protocols/ClashMeta.php @@ -194,8 +194,6 @@ class ClashMeta $array['server'] = $server['host']; $array['port'] = $server['port']; $array['uuid'] = $password; - $array['alterId'] = 0; - $array['cipher'] = 'auto'; $array['udp'] = true; // XTLS流控算法 @@ -242,10 +240,8 @@ class ClashMeta $array['ws-opts']['path'] = $wsSettings['path']; if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) $array['ws-opts']['headers'] = ['Host' => $wsSettings['headers']['Host']]; - if (isset($wsSettings['path']) && !empty($wsSettings['path'])) - $array['ws-path'] = $wsSettings['path']; - if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) - $array['ws-headers'] = ['Host' => $wsSettings['headers']['Host']]; + $array['ws-opts']['max-early-data'] = 2560; + $array['ws-opts']['early-data-header-name'] = 'Sec-WebSocket-Protocol'; } } if ($server['network'] === 'grpc') { From ab34ef327a788b2877a28e326299cc85d76ba3a3 Mon Sep 17 00:00:00 2001 From: Yusum <47137031+yushum@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:21:36 +0800 Subject: [PATCH 10/66] Update SingBox.php --- app/Protocols/SingBox.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Protocols/SingBox.php b/app/Protocols/SingBox.php index a0e1e18..5fd19c0 100644 --- a/app/Protocols/SingBox.php +++ b/app/Protocols/SingBox.php @@ -148,7 +148,7 @@ class SingBox $array['transport']['path'] = $wsSettings['path']; if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) $array['transport']['headers'] = ['Host' => array($wsSettings['headers']['Host'])]; - $array['transport']['max_early_data'] = 2048; + $array['transport']['max_early_data'] = 2560; $array['transport']['early_data_header_name'] = 'Sec-WebSocket-Protocol'; } } @@ -216,7 +216,7 @@ class SingBox $array['transport']['path'] = $wsSettings['path']; if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) $array['transport']['headers'] = ['Host' => array($wsSettings['headers']['Host'])]; - $array['transport']['max_early_data'] = 2048; + $array['transport']['max_early_data'] = 2560; $array['transport']['early_data_header_name'] = 'Sec-WebSocket-Protocol'; } } @@ -271,7 +271,7 @@ class SingBox if (isset($server['network_settings']['headers']['Host'])) { $array['transport']['headers'] = ['Host' => array($server['network_settings']['headers']['Host'])]; } - $array['transport']['max_early_data'] = 2048; + $array['transport']['max_early_data'] = 2560; $array['transport']['early_data_header_name'] = 'Sec-WebSocket-Protocol'; } } @@ -318,4 +318,4 @@ class SingBox return $array; } -} \ No newline at end of file +} From 42542725f7be8a130b820c90b9c094c1b6a20af4 Mon Sep 17 00:00:00 2001 From: Yusum <47137031+yushum@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:56:49 +0800 Subject: [PATCH 11/66] Update Shadowrocket.php --- app/Protocols/Shadowrocket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Protocols/Shadowrocket.php b/app/Protocols/Shadowrocket.php index c4cc8db..345783e 100644 --- a/app/Protocols/Shadowrocket.php +++ b/app/Protocols/Shadowrocket.php @@ -190,7 +190,7 @@ class Shadowrocket if ($server['network_settings']) { $wsSettings = $server['network_settings']; if (isset($wsSettings['path']) && !empty($wsSettings['path'])) - $config['path'] = $wsSettings['path']; + $config['path'] = $wsSettings['path'] . '?ed=2560'; if (isset($wsSettings['headers']['Host']) && !empty($wsSettings['headers']['Host'])) $config['obfsParam'] = $wsSettings['headers']['Host']; } From 0fb61ce30e9955b6784b8e59116151fe04b4ca7b Mon Sep 17 00:00:00 2001 From: greatbody Date: Fri, 6 Sep 2024 10:02:45 +0800 Subject: [PATCH 12/66] Support configure environment variable to skip interactive configuration, which is require when we want to setup by script. --- app/Console/Commands/XboardInstall.php | 9 ++++++--- docs/docker-compose安装指南.md | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/Console/Commands/XboardInstall.php b/app/Console/Commands/XboardInstall.php index e124736..434dd10 100644 --- a/app/Console/Commands/XboardInstall.php +++ b/app/Console/Commands/XboardInstall.php @@ -46,6 +46,9 @@ class XboardInstall extends Command { try { $isDocker = env('docker', false); + $enableSqlite = env('enable_sqlite', false); + $enableRedis = env('enable_redis', false); + $adminAccount = env('admin_account', ''); $this->info("__ __ ____ _ "); $this->info("\ \ / /| __ ) ___ __ _ _ __ __| | "); $this->info(" \ \/ / | __ \ / _ \ / _` | '__/ _` | "); @@ -67,7 +70,7 @@ class XboardInstall extends Command return; } // 选择是否使用Sqlite - if (confirm(label: '是否启用Sqlite(无需额外安装)代替Mysql', default: false, yes: '启用', no: '不启用')) { + if ($enableSqlite || confirm(label: '是否启用Sqlite(无需额外安装)代替Mysql', default: false, yes: '启用', no: '不启用')) { $sqliteFile = '.docker/.data/database.sqlite'; if (!file_exists(base_path($sqliteFile))) { // 创建空文件 @@ -142,7 +145,7 @@ class XboardInstall extends Command $isReidsValid = false; while (!$isReidsValid) { // 判断是否为Docker环境 - if ($isDocker == 'true' && (confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) { + if ($isDocker == 'true' && ($enableRedis || confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) { $envConfig['REDIS_HOST'] = '/run/redis-socket/redis.sock'; $envConfig['REDIS_PORT'] = 0; $envConfig['REDIS_PASSWORD'] = null; @@ -175,7 +178,7 @@ class XboardInstall extends Command abort(500, '复制环境文件失败,请检查目录权限'); } ; - $email = text( + $email = !empty($adminAccount) ? $adminAccount : text( label: '请输入管理员账号', default: 'admin@demo.com', required: true, diff --git a/docs/docker-compose安装指南.md b/docs/docker-compose安装指南.md index 4bc4c34..9d30b59 100644 --- a/docs/docker-compose安装指南.md +++ b/docs/docker-compose安装指南.md @@ -18,6 +18,10 @@ cd Xboard 3. 执行数据库安装命令 > 选择 **启用sqlite** 和 **Docker内置的Redis** ``` +docker compose run -it --rm -e enable_sqlite=true -e enable_redis=true -e admin_account=your_admin_email@example.com xboard php artisan xboard:install +``` +> 或者根据自己的需要在运行时选择 +``` docker compose run -it --rm xboard php artisan xboard:install ``` > 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来) @@ -67,4 +71,4 @@ docker compose up -d ``` ### 注意 -启用webman后做的任何代码修改都需要重启生效 \ No newline at end of file +启用webman后做的任何代码修改都需要重启生效 From 9517b0144fe88e0b3877c5ad249de33e36f37bb9 Mon Sep 17 00:00:00 2001 From: greatbody Date: Fri, 6 Sep 2024 10:08:17 +0800 Subject: [PATCH 13/66] Enable mannual trigger of pipeline. --- .github/workflows/docker-publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 6fe489e..00dd386 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -10,6 +10,7 @@ on: branches: [ "dev" ] # Publish semver tags as releases. tags: [ 'v*.*.*' ] + workflow_dispatch: # Enable manual trigger env: # Use docker.io for Docker Hub if empty @@ -60,7 +61,7 @@ jobs: uses: docker/metadata-action@v5.5.1 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - + - name: Get version id: get_version run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT From 0e2d961902b93c3a3fc483a505e7709df2f7b7c4 Mon Sep 17 00:00:00 2001 From: George Date: Sun, 29 Sep 2024 11:28:18 +0800 Subject: [PATCH 14/66] [fix]: Loon Hysteria2 node cannot get SNI --- app/Protocols/Loon.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Protocols/Loon.php b/app/Protocols/Loon.php index 570a380..56290ea 100644 --- a/app/Protocols/Loon.php +++ b/app/Protocols/Loon.php @@ -151,7 +151,7 @@ class Loon $server['host'], $server['port'], $password, - $server['server_name'] ? "tls={$server['server_name']}" : "(null)" + $server['server_name'] ? "sni={$server['server_name']}" : "(null)" ]; if ($server['insecure']) $config[] = "skip-cert-verify=true"; $config[] = "download-bandwidth=" . ($user->speed_limit ? min($server['down_mbps'], $user->speed_limit) : $server['down_mbps']); From a7f42a645970ec9aec1637c3e29f3500801ab1de Mon Sep 17 00:00:00 2001 From: xboard Date: Mon, 7 Oct 2024 00:27:11 +0800 Subject: [PATCH 15/66] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=AF=86=E9=92=A5=E6=9C=AA=E6=A0=A1=E9=AA=8C=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E4=B8=BA=E7=A9=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Middleware/Server.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Middleware/Server.php b/app/Http/Middleware/Server.php index 6feef83..3dcb858 100644 --- a/app/Http/Middleware/Server.php +++ b/app/Http/Middleware/Server.php @@ -26,6 +26,7 @@ class Server $request->validate([ 'token' => [ "string", + "required", function ($attribute, $value, $fail) { if ($value !== admin_setting('server_token')) { $fail('The ' . $attribute . ' is invalid.'); @@ -34,10 +35,11 @@ class Server ], 'node_id' => 'required', 'node_type' => [ + 'required', 'nullable', 'regex:/^(?i)(hysteria|hysteria2|vless|trojan|vmess|v2ray|tuic|shadowsocks|shadowsocks-plugin)$/', function ($attribute, $value, $fail) use ($aliasTypes, $request) { - $request->merge([$attribute => strtolower(isset ($aliasTypes[$value]) ? $aliasTypes[$value] : $value)]); + $request->merge([$attribute => strtolower(isset($aliasTypes[$value]) ? $aliasTypes[$value] : $value)]); }, ] ], [ From 47b0646811f1c89da3057f65c1c762dd050ceced Mon Sep 17 00:00:00 2001 From: xboard Date: Mon, 7 Oct 2024 02:47:54 +0800 Subject: [PATCH 16/66] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dvless=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E7=9A=84tls=5Finsecure=E5=9C=A8meta=E4=B8=AD=E4=B8=8B?= =?UTF-8?q?=E5=8F=91=E7=94=9F=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Protocols/ClashMeta.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Protocols/ClashMeta.php b/app/Protocols/ClashMeta.php index aff8982..7b9fa1c 100644 --- a/app/Protocols/ClashMeta.php +++ b/app/Protocols/ClashMeta.php @@ -207,8 +207,8 @@ class ClashMeta $array['tls'] = true; if ($server['tls_settings']) { $tlsSettings = $server['tls_settings']; - if (isset($tlsSettings['allowInsecure']) && !empty($tlsSettings['allowInsecure'])) - $array['skip-cert-verify'] = ($tlsSettings['allowInsecure'] ? true : false); + if (isset($tlsSettings['allow_insecure']) && !empty($tlsSettings['allow_insecure'])) + $array['skip-cert-verify'] = ($tlsSettings['allow_insecure'] ? true : false); if (isset($tlsSettings['server_name']) && !empty($tlsSettings['server_name'])) $array['servername'] = $tlsSettings['server_name']; } From af1f1e9fdf39af6355b2b1647fd49c12685de649 Mon Sep 17 00:00:00 2001 From: xboard Date: Mon, 7 Oct 2024 09:55:19 +0800 Subject: [PATCH 17/66] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=B5=81?= =?UTF-8?q?=E9=87=8F=E6=98=8E=E7=BB=86=E6=98=BE=E7=A4=BA=E6=89=80=E6=9C=89?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=9A=84BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/V1/User/StatController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/V1/User/StatController.php b/app/Http/Controllers/V1/User/StatController.php index a7845d4..f93bab5 100644 --- a/app/Http/Controllers/V1/User/StatController.php +++ b/app/Http/Controllers/V1/User/StatController.php @@ -13,7 +13,7 @@ class StatController extends Controller { public function getTrafficLog(Request $request) { - $startDate = now()->startOfMonth(); + $startDate = now()->startOfMonth()->timestamp; $records = StatUser::query() ->where('user_id', $request->user['id']) ->where('record_at', '>=', $startDate) From 0873ce591fca5801d56c2da0228da195e345269c Mon Sep 17 00:00:00 2001 From: George Date: Wed, 9 Oct 2024 15:17:45 +0800 Subject: [PATCH 18/66] [feat]: add v2rayNG hysteria2 support --- app/Protocols/V2rayNG.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/app/Protocols/V2rayNG.php b/app/Protocols/V2rayNG.php index 7b1ba53..21f0554 100644 --- a/app/Protocols/V2rayNG.php +++ b/app/Protocols/V2rayNG.php @@ -34,6 +34,9 @@ class V2rayNG if ($item['type'] === 'vless') { $uri .= self::buildVless($user['uuid'], $item); } + if ($item['type'] === 'hysteria') { + $uri .= self::buildHysteria($user['uuid'], $item); + } } return base64_encode($uri); } @@ -190,5 +193,34 @@ class V2rayNG return $uri; } + public static function buildHysteria($password, $server) + { + $params = []; + // Return empty if version is not 2 + if ($server['version'] !== 2) { + return ''; + } + + if ($server['server_name']) { + $params['sni'] = $server['server_name']; + $params['security'] = 'tls'; + } + + if ($server['is_obfs']) { + $params['obfs'] = 'salamander'; + $params['obfs-password'] = $server['server_key']; + } + + $params['insecure'] = $server['insecure'] ? 1 : 0; + + $query = http_build_query($params); + $name = rawurlencode($server['name']); + + $uri = "hysteria2://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}"; + $uri .= "\r\n"; + + return $uri; + } + } From f5746423bf496cac556b14c809f98f9f98be1bed Mon Sep 17 00:00:00 2001 From: Linux Date: Wed, 9 Oct 2024 22:55:26 +0800 Subject: [PATCH 19/66] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E4=B8=8D=E6=98=BE=E7=A4=BA=E5=BD=93=E6=97=A5?= =?UTF-8?q?=E6=B5=81=E9=87=8F=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Services/StatisticalService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Services/StatisticalService.php b/app/Services/StatisticalService.php index 3ec016e..3a727f0 100644 --- a/app/Services/StatisticalService.php +++ b/app/Services/StatisticalService.php @@ -108,14 +108,14 @@ class StatisticalService /** * 获取指定用户的流量使用情况 */ - public function getStatUserByUserID($userId): array + public function getStatUserByUserID(int|string $userId): array { $stats = []; $statsUser = $this->redis->zrange($this->statUserKey, 0, -1, true); foreach ($statsUser as $member => $value) { list($rate, $uid, $type) = explode('_', $member); - if ($uid !== $userId) + if (intval($uid) !== intval($userId)) continue; $key = "{$rate}_{$uid}"; $stats[$key] = $stats[$key] ?? [ From 6cfdd1c9b1b0ef0b0ce3264d99cd046e04f3eca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Fri, 18 Oct 2024 12:42:51 -0400 Subject: [PATCH 20/66] Update Surge.php support surge ss2022 --- app/Protocols/Surge.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Protocols/Surge.php b/app/Protocols/Surge.php index 4e09b82..ab2dc54 100644 --- a/app/Protocols/Surge.php +++ b/app/Protocols/Surge.php @@ -32,7 +32,9 @@ class Surge 'aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm', - 'chacha20-ietf-poly1305' + 'chacha20-ietf-poly1305', + '2022-blake3-aes-128-gcm', + '2022-blake3-aes-256-gcm', ]) ) { // [Proxy] From c7ea56bb7e72d05e826b345a0c9da09a4c9afa92 Mon Sep 17 00:00:00 2001 From: Linux Date: Sat, 19 Oct 2024 23:17:22 +0800 Subject: [PATCH 21/66] docs: update --- docs/1panel安装指南.md | 2 ++ docs/aapanel+docker安装指南.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index 4a37cb6..74ae6de 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -106,6 +106,8 @@ docker compose up -d 🎉: 到这里,你已经可以通过域名访问你的站点了。 +⚠️: 请务必开启防火墙防止7001端口暴露到公网当中。 + ## 更新 1. 通过 SSH 登录到服务器后,访问站点路径如:`/opt/1panel/apps/openresty/openresty/www/sites/xboard/index`,然后在站点目录中执行以下命令: diff --git a/docs/aapanel+docker安装指南.md b/docs/aapanel+docker安装指南.md index 3a7513c..37b3ba9 100644 --- a/docs/aapanel+docker安装指南.md +++ b/docs/aapanel+docker安装指南.md @@ -79,7 +79,9 @@ location ^~ / { } ``` -🎉: 到这里,你可以已经可以通过域名访问你的站点了 +🎉: 到这里,你可以已经可以通过域名访问你的站点了 + +⚠️: 请务必开启防火墙防止7001端口暴露到公网当中。 ### 更新 1. 更新代码 From 4d4adc4facfa9a4031d42ec86ade75f21dad22c5 Mon Sep 17 00:00:00 2001 From: Linux Date: Sun, 20 Oct 2024 12:03:21 +0800 Subject: [PATCH 22/66] fix: Hide online user count display for child nodes without independent online users --- app/Services/ServerService.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Services/ServerService.php b/app/Services/ServerService.php index 8da9a3f..391157a 100644 --- a/app/Services/ServerService.php +++ b/app/Services/ServerService.php @@ -314,9 +314,11 @@ class ServerService $servers[$k]['online'] = Cache::get(CacheKey::get("SERVER_{$serverType}_ONLINE_USER", $v['parent_id'] ?? $v['id'])) ?? 0; // 如果是子节点,先尝试从缓存中获取 if($pid = $v['parent_id']){ - // 获取缓存 - $onlineUsers = Cache::get(CacheKey::get('MULTI_SERVER_' . $serverType . '_ONLINE_USER', $pid)) ?? []; - $servers[$k]['online'] = (collect($onlineUsers)->whereIn('ip', $v['ips'])->sum('online_user')) . "|{$servers[$k]['online']}"; + $cacheKey = CacheKey::get('MULTI_SERVER_' . $serverType . '_ONLINE_USER', $pid); + $onlineUsers = Cache::get($cacheKey) ?? []; + $onlineUserSum = collect($onlineUsers)->whereIn('ip', $v['ips'])->sum('online_user'); + $online = ($onlineUserSum > 0 ? $onlineUserSum . "|" : "") . $servers[$k]['online']; + $servers[$k]['online'] = $online; } $servers[$k]['last_check_at'] = Cache::get(CacheKey::get("SERVER_{$serverType}_LAST_CHECK_AT", $v['parent_id'] ?? $v['id'])); $servers[$k]['last_push_at'] = Cache::get(CacheKey::get("SERVER_{$serverType}_LAST_PUSH_AT", $v['parent_id'] ?? $v['id'])); From f25696f22b5b69553b7762030c9be3535c4ddb90 Mon Sep 17 00:00:00 2001 From: Linux Date: Sun, 20 Oct 2024 12:37:16 +0800 Subject: [PATCH 23/66] Payment: add type configuration to Epay payment --- app/Payments/EPay.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/Payments/EPay.php b/app/Payments/EPay.php index cf60128..2835c3f 100644 --- a/app/Payments/EPay.php +++ b/app/Payments/EPay.php @@ -27,7 +27,12 @@ class EPay 'label' => 'KEY', 'description' => '', 'type' => 'input', - ] + ], + 'type' => [ + 'label' => 'TYPE', + 'description' => 'alipay / qqpay / wxpay', + 'type' => 'input', + ], ]; } @@ -41,6 +46,9 @@ class EPay 'out_trade_no' => $order['trade_no'], 'pid' => $this->config['pid'] ]; + if(optional($this->config)['type']){ + $params['type'] = $this->config['type']; + } ksort($params); reset($params); $str = stripslashes(urldecode(http_build_query($params))) . $this->config['key']; From dd246b2c169c45a8348d801f11ec6cea5d40e6c9 Mon Sep 17 00:00:00 2001 From: xboard Date: Tue, 5 Nov 2024 11:56:02 +0800 Subject: [PATCH 24/66] chore: update composer.json --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index bfccc63..c99645b 100755 --- a/composer.json +++ b/composer.json @@ -12,7 +12,6 @@ "license": "MIT", "require": { "php": "^8.1", - "cedar2025/http-foundation": "6.4.x-dev", "cweagans/composer-patches": "^1.7", "doctrine/dbal": "^3.7", "firebase/php-jwt": "^6.3", From 2251f218d80e56a8ce76e9511b2259d0a1fd267e Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Fri, 8 Nov 2024 06:32:48 +0800 Subject: [PATCH 25/66] chore: add persistence configuration to redis --- .docker/services/redis/redis.conf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.docker/services/redis/redis.conf b/.docker/services/redis/redis.conf index c7115b6..b067b4c 100644 --- a/.docker/services/redis/redis.conf +++ b/.docker/services/redis/redis.conf @@ -1,3 +1,7 @@ unixsocket /run/redis-socket/redis.sock unixsocketperm 777 -port 0 \ No newline at end of file +port 0 + +save 900 1 +save 300 10 +save 60 10000 From fd372917169b98627870797b27a72bbf3fe444c1 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:26:31 +0800 Subject: [PATCH 26/66] feat: add appname display in hiddify add profile-title header to sing-box subscribe --- app/Protocols/SingBox.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Protocols/SingBox.php b/app/Protocols/SingBox.php index a0e1e18..3c79a01 100644 --- a/app/Protocols/SingBox.php +++ b/app/Protocols/SingBox.php @@ -26,6 +26,7 @@ class SingBox return response() ->json($this->config) + ->header('profile-title', 'base64:'. base64_encode($appName)) ->header('subscription-userinfo', "upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}") ->header('profile-update-interval', '24'); } @@ -318,4 +319,4 @@ class SingBox return $array; } -} \ No newline at end of file +} From b5ea28cd27bc7a93ef39faec62884e259bb3cac7 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Sat, 9 Nov 2024 04:01:39 +0800 Subject: [PATCH 27/66] =?UTF-8?q?Update=20docker-compose=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docker-compose安装指南.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/docker-compose安装指南.md b/docs/docker-compose安装指南.md index 9d30b59..ac25f8b 100644 --- a/docs/docker-compose安装指南.md +++ b/docs/docker-compose安装指南.md @@ -7,6 +7,9 @@ 1. 安装docker ``` curl -sSL https://get.docker.com | bash +``` +Centos系统可能需要执行下面命令来启动Docker。 +``` systemctl enable docker systemctl start docker ``` From 73b25d2eec578ac11d0910dd9dd19744042ced6b Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Sat, 9 Nov 2024 04:13:45 +0800 Subject: [PATCH 28/66] =?UTF-8?q?Update=20aapanel+docker=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/aapanel+docker安装指南.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/aapanel+docker安装指南.md b/docs/aapanel+docker安装指南.md index 37b3ba9..5094da8 100644 --- a/docs/aapanel+docker安装指南.md +++ b/docs/aapanel+docker安装指南.md @@ -6,6 +6,7 @@ ``` # 安装Docker curl -sSL https://get.docker.com | bash +# Centos系统可能还需要执行下面命令来启动Docker systemctl enable docker systemctl start docker ``` From ab52e61ed19278f5b243cb6b028a633c15815f05 Mon Sep 17 00:00:00 2001 From: xboard Date: Sat, 9 Nov 2024 06:34:30 +0800 Subject: [PATCH 29/66] refactor: subscription URL retrieval logic --- app/Http/Controllers/V1/Admin/UserController.php | 6 +++--- .../Controllers/V1/User/KnowledgeController.php | 2 +- app/Http/Controllers/V1/User/UserController.php | 4 ++-- app/Http/Routes/V1/ClientRoute.php | 2 +- app/Protocols/Surfboard.php | 2 +- app/Protocols/Surge.php | 3 +-- app/Utils/Helper.php | 14 ++++++++------ 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/V1/Admin/UserController.php b/app/Http/Controllers/V1/Admin/UserController.php index c3ed2bc..8117aa1 100644 --- a/app/Http/Controllers/V1/Admin/UserController.php +++ b/app/Http/Controllers/V1/Admin/UserController.php @@ -73,7 +73,7 @@ class UserController extends Controller $res[$i]['plan_name'] = $plan[$k]['name']; } } - $res[$i]['subscribe_url'] = Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $res[$i]['token']); + $res[$i]['subscribe_url'] = Helper::getSubscribeUrl( $res[$i]['token']); } return response([ 'data' => $res, @@ -162,7 +162,7 @@ class UserController extends Controller $transferEnable = $user['transfer_enable'] ? $user['transfer_enable'] / 1073741824 : 0; $notUseFlow = (($user['transfer_enable'] - ($user['u'] + $user['d'])) / 1073741824) ?? 0; $planName = $user['plan_name'] ?? '无订阅'; - $subscribeUrl = Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $user['token']); + $subscribeUrl = Helper::getSubscribeUrl($user['token']); $data .= "{$user['email']},{$balance},{$commissionBalance},{$transferEnable},{$notUseFlow},{$expireDate},{$planName},{$subscribeUrl}\r\n"; } echo "\xEF\xBB\xBF" . $data; @@ -240,7 +240,7 @@ class UserController extends Controller $expireDate = $user['expired_at'] === NULL ? '长期有效' : date('Y-m-d H:i:s', $user['expired_at']); $createDate = date('Y-m-d H:i:s', $user['created_at']); $password = $request->input('password') ?? $user['email']; - $subscribeUrl = Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $user['token']); + $subscribeUrl = Helper::getSubscribeUrl($user['token']); $data .= "{$user['email']},{$password},{$expireDate},{$user['uuid']},{$createDate},{$subscribeUrl}\r\n"; } echo $data; diff --git a/app/Http/Controllers/V1/User/KnowledgeController.php b/app/Http/Controllers/V1/User/KnowledgeController.php index ac412aa..6861e81 100644 --- a/app/Http/Controllers/V1/User/KnowledgeController.php +++ b/app/Http/Controllers/V1/User/KnowledgeController.php @@ -25,7 +25,7 @@ class KnowledgeController extends Controller if (!$userService->isAvailable($user)) { $this->formatAccessData($knowledge['body']); } - $subscribeUrl = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}"); + $subscribeUrl = Helper::getSubscribeUrl($user['token']); $knowledge['body'] = str_replace('{{siteName}}', admin_setting('app_name', 'XBoard'), $knowledge['body']); $knowledge['body'] = str_replace('{{subscribeUrl}}', $subscribeUrl, $knowledge['body']); $knowledge['body'] = str_replace('{{urlEncodeSubscribeUrl}}', urlencode($subscribeUrl), $knowledge['body']); diff --git a/app/Http/Controllers/V1/User/UserController.php b/app/Http/Controllers/V1/User/UserController.php index 0dbe572..abb97bf 100755 --- a/app/Http/Controllers/V1/User/UserController.php +++ b/app/Http/Controllers/V1/User/UserController.php @@ -140,7 +140,7 @@ class UserController extends Controller return $this->fail([400, __('Subscription plan does not exist')]); } } - $user['subscribe_url'] = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}"); + $user['subscribe_url'] = Helper::getSubscribeUrl($user['token']); $userService = new UserService(); $user['reset_day'] = $userService->getResetDay($user); return $this->success($user); @@ -157,7 +157,7 @@ class UserController extends Controller if (!$user->save()) { return $this->fail([400, __('Reset failed')]); } - return $this->success(Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $user->token)); + return $this->success(Helper::getSubscribeUrl($user->token)); } public function update(UserUpdate $request) diff --git a/app/Http/Routes/V1/ClientRoute.php b/app/Http/Routes/V1/ClientRoute.php index 81644ac..ef5e4d1 100644 --- a/app/Http/Routes/V1/ClientRoute.php +++ b/app/Http/Routes/V1/ClientRoute.php @@ -12,7 +12,7 @@ class ClientRoute 'middleware' => 'client' ], function ($router) { // Client - $router->get('/subscribe', 'V1\\Client\\ClientController@subscribe'); + $router->get('/subscribe', 'V1\\Client\\ClientController@subscribe')->name('client.subscribe'); // App $router->get('/app/getConfig', 'V1\\Client\\AppController@getConfig'); $router->get('/app/getVersion', 'V1\\Client\\AppController@getVersion'); diff --git a/app/Protocols/Surfboard.php b/app/Protocols/Surfboard.php index 007e3eb..be44640 100644 --- a/app/Protocols/Surfboard.php +++ b/app/Protocols/Surfboard.php @@ -63,7 +63,7 @@ class Surfboard } // Subscription link - $subsURL = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}"); + $subsURL = Helper::getSubscribeUrl($user['token']); $subsDomain = request()->header('Host'); $config = str_replace('$subs_link', $subsURL, $config); diff --git a/app/Protocols/Surge.php b/app/Protocols/Surge.php index 4e09b82..c89f2ef 100644 --- a/app/Protocols/Surge.php +++ b/app/Protocols/Surge.php @@ -69,9 +69,8 @@ class Surge } // Subscription link - $subsURL = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}"); $subsDomain = request()->header('Host'); - $subsURL = 'https://' . $subsDomain . '/api/v1/client/subscribe?token=' . $user['token']; + $subsURL = Helper::getSubscribeUrl($user['token'], $subsDomain ? 'https://' . $subsDomain : null); $config = str_replace('$subs_link', $subsURL, $config); $config = str_replace('$subs_domain', $subsDomain, $config); diff --git a/app/Utils/Helper.php b/app/Utils/Helper.php index 6844327..341df4e 100644 --- a/app/Utils/Helper.php +++ b/app/Utils/Helper.php @@ -108,13 +108,15 @@ class Helper } } - public static function getSubscribeUrl($path) + public static function getSubscribeUrl(string $token, $subscribeUrl = null) { - $subscribeUrls = explode(',', admin_setting('subscribe_url')); - $subscribeUrl = $subscribeUrls[array_rand($subscribeUrls)]; - $subscribeUrl = self::replaceByPattern($subscribeUrl); - if ($subscribeUrl) return $subscribeUrl . $path; - return url($path); + $path = route('client.subscribe', ['token' => $token], false); + if(!$subscribeUrl){ + $subscribeUrls = explode(',', admin_setting('subscribe_url')); + $subscribeUrl = \Arr::random($subscribeUrls); + $subscribeUrl = self::replaceByPattern($subscribeUrl); + } + return $subscribeUrl ? rtrim($subscribeUrl, '/') . $path : url($path); } public static function randomPort($range) { From e79465c90d9fe8185fdf75fcf9ae0218c1c60053 Mon Sep 17 00:00:00 2001 From: xboard Date: Sat, 9 Nov 2024 21:37:15 +0800 Subject: [PATCH 30/66] feat: add support for hysteria2 in Passwall and SSRPLUS --- app/Protocols/General.php | 32 ++++++++++++++++++++++++++++++++ app/Protocols/Passwall.php | 3 +++ app/Protocols/SSRPlus.php | 3 +++ app/Protocols/V2rayN.php | 22 +--------------------- app/Protocols/V2rayNG.php | 32 +------------------------------- 5 files changed, 40 insertions(+), 52 deletions(-) diff --git a/app/Protocols/General.php b/app/Protocols/General.php index 7de9186..0a3f2a5 100644 --- a/app/Protocols/General.php +++ b/app/Protocols/General.php @@ -36,6 +36,9 @@ class General if ($item['type'] === 'trojan') { $uri .= self::buildTrojan($user['uuid'], $item); } + if ($item['type'] === 'hysteria') { + $uri .= self::buildHysteria($user['uuid'], $item); + } } return base64_encode($uri); } @@ -170,4 +173,33 @@ class General return $uri; } + public static function buildHysteria($password, $server) + { + $params = []; + // Return empty if version is not 2 + if ($server['version'] !== 2) { + return ''; + } + + if ($server['server_name']) { + $params['sni'] = $server['server_name']; + $params['security'] = 'tls'; + } + + if ($server['is_obfs']) { + $params['obfs'] = 'salamander'; + $params['obfs-password'] = $server['server_key']; + } + + $params['insecure'] = $server['insecure'] ? 1 : 0; + + $query = http_build_query($params); + $name = rawurlencode($server['name']); + + $uri = "hysteria2://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}"; + $uri .= "\r\n"; + + return $uri; + } + } diff --git a/app/Protocols/Passwall.php b/app/Protocols/Passwall.php index 66efd33..2799a61 100644 --- a/app/Protocols/Passwall.php +++ b/app/Protocols/Passwall.php @@ -34,6 +34,9 @@ class Passwall if ($item['type'] === 'trojan') { $uri .= self::buildTrojan($user['uuid'], $item); } + if ($item['type'] === 'hysteria') { + $uri .= General::buildHysteria($user['uuid'], $item); + } } return base64_encode($uri); } diff --git a/app/Protocols/SSRPlus.php b/app/Protocols/SSRPlus.php index 1d32a61..e2e25b6 100644 --- a/app/Protocols/SSRPlus.php +++ b/app/Protocols/SSRPlus.php @@ -34,6 +34,9 @@ class SSRPlus if ($item['type'] === 'trojan') { $uri .= self::buildTrojan($user['uuid'], $item); } + if ($item['type'] === 'hysteria') { + $uri .= General::buildHysteria($user['uuid'], $item); + } } return base64_encode($uri); } diff --git a/app/Protocols/V2rayN.php b/app/Protocols/V2rayN.php index cb353f4..9d2ae6c 100644 --- a/app/Protocols/V2rayN.php +++ b/app/Protocols/V2rayN.php @@ -37,7 +37,7 @@ class V2rayN $uri .= self::buildTrojan($user['uuid'], $item); } if ($item['type'] === 'hysteria') { - $uri .= self::buildHysteria($user['uuid'], $item); + $uri .= General::buildHysteria($user['uuid'], $item); } } @@ -192,25 +192,5 @@ class V2rayN return $uri; } - public static function buildHysteria($password, $server) - { - $name = rawurlencode($server['name']); - $params = []; - if ($server['server_name']) $params['sni'] = $server['server_name']; - $params['insecure'] = $server['insecure'] ? 1 : 0; - if($server['is_obfs']) { - $params['obfs'] = 'salamander'; - $params['obfs-password'] = $server['server_key']; - } - $query = http_build_query($params); - if ($server['version'] == 2) { - $uri = "hysteria2://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}"; - $uri .= "\r\n"; - } else { - // V2rayN似乎不支持v1, 返回空 - $uri = ""; - } - return $uri; - } } diff --git a/app/Protocols/V2rayNG.php b/app/Protocols/V2rayNG.php index 21f0554..7d16c95 100644 --- a/app/Protocols/V2rayNG.php +++ b/app/Protocols/V2rayNG.php @@ -35,7 +35,7 @@ class V2rayNG $uri .= self::buildVless($user['uuid'], $item); } if ($item['type'] === 'hysteria') { - $uri .= self::buildHysteria($user['uuid'], $item); + $uri .= General::buildHysteria($user['uuid'], $item); } } return base64_encode($uri); @@ -193,34 +193,4 @@ class V2rayNG return $uri; } - public static function buildHysteria($password, $server) - { - $params = []; - // Return empty if version is not 2 - if ($server['version'] !== 2) { - return ''; - } - - if ($server['server_name']) { - $params['sni'] = $server['server_name']; - $params['security'] = 'tls'; - } - - if ($server['is_obfs']) { - $params['obfs'] = 'salamander'; - $params['obfs-password'] = $server['server_key']; - } - - $params['insecure'] = $server['insecure'] ? 1 : 0; - - $query = http_build_query($params); - $name = rawurlencode($server['name']); - - $uri = "hysteria2://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}"; - $uri .= "\r\n"; - - return $uri; - } - - } From 090781db0c0cf7e29cd171ae04c33d1440378d0b Mon Sep 17 00:00:00 2001 From: xboard Date: Sat, 9 Nov 2024 22:16:05 +0800 Subject: [PATCH 31/66] feat: add support for hysteria2 in V2rayNG --- app/Http/Controllers/V1/Client/ClientController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Controllers/V1/Client/ClientController.php b/app/Http/Controllers/V1/Client/ClientController.php index 913e4d6..903490f 100644 --- a/app/Http/Controllers/V1/Client/ClientController.php +++ b/app/Http/Controllers/V1/Client/ClientController.php @@ -24,6 +24,7 @@ class ClientController extends Controller 'ClashX Meta' => '1.3.5', 'Hiddify' => '0.1.0', 'loon' => '637', + 'v2rayng' => '1.9.5', 'v2rayN' => '6.31', 'surge' => '2398' ]; From db6a36185781c7fa3bd776e425b3b3b45d892606 Mon Sep 17 00:00:00 2001 From: xboard Date: Fri, 15 Nov 2024 15:10:05 +0800 Subject: [PATCH 32/66] Revert "chore: update composer.json" This reverts commit dd246b2c169c45a8348d801f11ec6cea5d40e6c9. --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index c99645b..bfccc63 100755 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "license": "MIT", "require": { "php": "^8.1", + "cedar2025/http-foundation": "6.4.x-dev", "cweagans/composer-patches": "^1.7", "doctrine/dbal": "^3.7", "firebase/php-jwt": "^6.3", From 0e9739af0be22d13944df7568d5d4639d82b689b Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Sun, 17 Nov 2024 17:02:07 +0800 Subject: [PATCH 33/66] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bfccc63..e83ffd7 100755 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "guzzlehttp/guzzle": "^7.4.3", "hhxsv5/laravel-s": "~3.7.0", "joanhey/adapterman": "^0.6.1", - "laravel/framework": "^10.0", + "laravel/framework": "10.48.22", "laravel/horizon": "^5.9.6", "laravel/tinker": "^2.5", "linfo/linfo": "^4.0", From ddac216e2d49b9a678b690f501895d84ee9de8dc Mon Sep 17 00:00:00 2001 From: longdoer <346048058@qq.com> Date: Tue, 19 Nov 2024 16:45:52 +0800 Subject: [PATCH 34/66] Update ClashMeta.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加ClashMeta首页链接 --- app/Protocols/ClashMeta.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Protocols/ClashMeta.php b/app/Protocols/ClashMeta.php index 7b9fa1c..77a98ee 100644 --- a/app/Protocols/ClashMeta.php +++ b/app/Protocols/ClashMeta.php @@ -88,7 +88,8 @@ class ClashMeta return response($yaml, 200) ->header('subscription-userinfo', "upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}") ->header('profile-update-interval', '24') - ->header('content-disposition', 'attachment;filename*=UTF-8\'\'' . rawurlencode($appName)); + ->header('content-disposition', 'attachment;filename*=UTF-8\'\'' . rawurlencode($appName)) + ->header('profile-web-page-url', admin_setting('app_url')); } /** From f86ccae28cd6003f386cb7db548a2053c4504ebc Mon Sep 17 00:00:00 2001 From: xboard Date: Fri, 29 Nov 2024 19:22:12 +0800 Subject: [PATCH 35/66] pref: Enhance TrafficFetch Performance and Optimize Code Structure --- app/Jobs/BatchTrafficFetchJob.php | 37 +++++++++---------------------- app/Services/ServerService.php | 2 +- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/app/Jobs/BatchTrafficFetchJob.php b/app/Jobs/BatchTrafficFetchJob.php index 0cf8599..18a456f 100644 --- a/app/Jobs/BatchTrafficFetchJob.php +++ b/app/Jobs/BatchTrafficFetchJob.php @@ -2,6 +2,7 @@ namespace App\Jobs; +use App\Models\User; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; @@ -17,7 +18,7 @@ class BatchTrafficFetchJob implements ShouldQueue protected $protocol; protected $timestamp; public $tries = 1; - public $timeout = 10; + public $timeout = 20; /** * Create a new job instance. @@ -36,34 +37,16 @@ class BatchTrafficFetchJob implements ShouldQueue public function handle(): void { - // 获取子节点 $targetServer = $this->childServer ?? $this->server; foreach ($this->data as $uid => $v) { - $u = $v[0]; - $d = $v[1]; - $result = \DB::transaction(function () use ($uid, $u, $d, $targetServer) { - $user = \DB::table('v2_user')->lockForUpdate()->where('id', $uid)->first(); - if (!$user) { - return true; - } - $newTime = time(); - $newU = $user->u + ($u * $targetServer['rate']); - $newD = $user->d + ($d * $targetServer['rate']); - $rows = \DB::table('v2_user') - ->where('id', $uid) - ->update([ - 't' => $newTime, - 'u' => $newU, - 'd' => $newD, - ]); - if ($rows === 0) { - return false; - } - return true; - }, 3); - if (!$result) { - TrafficFetchJob::dispatch($u, $d, $uid, $targetServer, $this->protocol); - } + User::where('id', $uid) + ->incrementEach( + [ + 'u' => $v[0] * $targetServer['rate'], + 'd' => $v[1] * $targetServer['rate'], + ], + ['t' => time()] + ); } } } diff --git a/app/Services/ServerService.php b/app/Services/ServerService.php index 391157a..60bcefa 100644 --- a/app/Services/ServerService.php +++ b/app/Services/ServerService.php @@ -196,7 +196,7 @@ class ServerService // 获取可用的用户列表 public static function getAvailableUsers($groupId): Collection { - return \DB::table('v2_user') + return User::toBase() ->whereIn('group_id', $groupId) ->whereRaw('u + d < transfer_enable') ->where(function ($query) { From c4595bc6652d9f05543fa1f00149b24a60e86df7 Mon Sep 17 00:00:00 2001 From: Linus Xiong Date: Sun, 8 Dec 2024 00:53:43 -0500 Subject: [PATCH 36/66] use docker env on .env file --- .env.example | 69 +++++++++++++++++++++++++--------------------------- Dockerfile | 27 +++++++++++++------- 2 files changed, 51 insertions(+), 45 deletions(-) mode change 100755 => 100644 .env.example diff --git a/.env.example b/.env.example old mode 100755 new mode 100644 index 2bffe56..6211636 --- a/.env.example +++ b/.env.example @@ -1,43 +1,40 @@ -APP_NAME=XBoard -APP_ENV=local -APP_KEY=base64:PZXk5vTuTinfeEVG5FpYv2l6WEhLsyvGpiWK7IgJJ60= -APP_DEBUG=false -APP_URL=http://localhost +APP_NAME=${APP_NAME:-XBoard} +APP_ENV=${APP_ENV:-local} +APP_KEY=${APP_KEY:-base64:PZXk5vTuTinfeEVG5FpYv2l6WEhLsyvGpiWK7IgJJ60=} +APP_DEBUG=${APP_DEBUG:-false} +APP_URL=${APP_URL:-http://localhost} +ADMIN_SETTING_CACHE=${ADMIN_SETTING_CACHE:-60} +LOG_CHANNEL=${LOG_CHANNEL:-stack} -ADMIN_SETTING_CACHE=60 #设置缓存时间(单位秒) -LOG_CHANNEL=stack +DB_CONNECTION=${DB_CONNECTION:-mysql} +DB_HOST=${DB_HOST:-127.0.0.1} +DB_PORT=${DB_PORT:-3306} +DB_DATABASE=${DB_DATABASE:-xboard} +DB_USERNAME=${DB_USERNAME:-root} +DB_PASSWORD=${DB_PASSWORD:-} -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=xboard -DB_USERNAME=root -DB_PASSWORD= +REDIS_HOST=${REDIS_HOST:-127.0.0.1} +REDIS_PASSWORD=${REDIS_PASSWORD:-null} +REDIS_PORT=${REDIS_PORT:-6379} -REDIS_HOST=127.0.0.1 -REDIS_PASSWORD=null -REDIS_PORT=6379 +BROADCAST_DRIVER=${BROADCAST_DRIVER:-log} +CACHE_DRIVER=${CACHE_DRIVER:-redis} +QUEUE_CONNECTION=${QUEUE_CONNECTION:-redis} -#默认将队列驱动和缓存驱动都修改为了redis,请务必安装redis -BROADCAST_DRIVER=log -CACHE_DRIVER=redis -QUEUE_CONNECTION=redis +MAIL_DRIVER=${MAIL_DRIVER:-smtp} +MAIL_HOST=${MAIL_HOST:-smtp.mailtrap.io} +MAIL_PORT=${MAIL_PORT:-2525} +MAIL_USERNAME=${MAIL_USERNAME:-null} +MAIL_PASSWORD=${MAIL_PASSWORD:-null} +MAIL_ENCRYPTION=${MAIL_ENCRYPTION:-null} +MAIL_FROM_ADDRESS=${MAIL_FROM_ADDRESS:-null} +MAIL_FROM_NAME=${MAIL_FROM_NAME:-null} -MAIL_DRIVER=smtp -MAIL_HOST=smtp.mailtrap.io -MAIL_PORT=2525 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS=null -MAIL_FROM_NAME=null -MAILGUN_DOMAIN= -MAILGUN_SECRET= +MAILGUN_DOMAIN=${MAILGUN_DOMAIN:-} +MAILGUN_SECRET=${MAILGUN_SECRET:-} -# google cloud stoage -ENABLE_AUTO_BACKUP_AND_UPDATE=false -GOOGLE_CLOUD_KEY_FILE=config/googleCloudStorageKey.json -GOOGLE_CLOUD_STORAGE_BUCKET= +ENABLE_AUTO_BACKUP_AND_UPDATE=${ENABLE_AUTO_BACKUP_AND_UPDATE:-false} +GOOGLE_CLOUD_KEY_FILE=${GOOGLE_CLOUD_KEY_FILE:-config/googleCloudStorageKey.json} +GOOGLE_CLOUD_STORAGE_BUCKET=${GOOGLE_CLOUD_STORAGE_BUCKET:-} -# 用于阻止重复安装 -INSTALLED=false \ No newline at end of file +INSTALLED=${INSTALLED:-false} diff --git a/Dockerfile b/Dockerfile index 3ce274a..17c777f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,16 +2,25 @@ FROM phpswoole/swoole:php8.1-alpine COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ -RUN install-php-extensions pcntl bcmath inotify \ -&& apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch \ -&& addgroup -S -g 1000 www && adduser -S -G www -u 1000 www -#复制项目文件以及配置文件 +# 安装基础软件包,包括 gettext (提供 envsubst) +RUN install-php-extensions pcntl bcmath inotify \ + && apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch gettext \ + && addgroup -S -g 1000 www && adduser -S -G www -u 1000 www + +# 设置工作目录 WORKDIR /www + +# 复制项目文件和配置文件 COPY .docker / COPY . /www -RUN composer install --optimize-autoloader --no-cache --no-dev \ -&& php artisan storage:link \ -&& chown -R www:www /www \ -&& chmod -R 775 /www +COPY .env.example /www/.env.example -CMD /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf \ No newline at end of file +# 生成环境变量文件并安装依赖 +RUN envsubst < /www/.env.template > /www/.env \ + && composer install --optimize-autoloader --no-cache --no-dev \ + && php artisan storage:link \ + && chown -R www:www /www \ + && chmod -R 775 /www + +# 启动 supervisor +CMD /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf From 1378fdb45bfcbd1d6fd14f06c2bbbe7237e834df Mon Sep 17 00:00:00 2001 From: Linus Xiong Date: Sun, 8 Dec 2024 00:58:58 -0500 Subject: [PATCH 37/66] fix bugs --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 17c777f..0e88d06 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ COPY . /www COPY .env.example /www/.env.example # 生成环境变量文件并安装依赖 -RUN envsubst < /www/.env.template > /www/.env \ +RUN envsubst < /www/.env.example > /www/.env \ && composer install --optimize-autoloader --no-cache --no-dev \ && php artisan storage:link \ && chown -R www:www /www \ From cfc8a05cbae238cd509efa644c9fd73acd8df3f5 Mon Sep 17 00:00:00 2001 From: Linus Xiong Date: Sun, 8 Dec 2024 01:05:38 -0500 Subject: [PATCH 38/66] fix bugs --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0e88d06..a09f9d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,6 @@ WORKDIR /www # 复制项目文件和配置文件 COPY .docker / COPY . /www -COPY .env.example /www/.env.example # 生成环境变量文件并安装依赖 RUN envsubst < /www/.env.example > /www/.env \ From dee7525bb42fea0ec16b794720094feea9cbafff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Sun, 8 Dec 2024 01:10:00 -0500 Subject: [PATCH 39/66] Update Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index a09f9d4..d520265 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,6 @@ FROM phpswoole/swoole:php8.1-alpine COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ -# 安装基础软件包,包括 gettext (提供 envsubst) RUN install-php-extensions pcntl bcmath inotify \ && apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch gettext \ && addgroup -S -g 1000 www && adduser -S -G www -u 1000 www @@ -12,6 +11,7 @@ WORKDIR /www # 复制项目文件和配置文件 COPY .docker / +COPY .env.example /www/.env.example COPY . /www # 生成环境变量文件并安装依赖 From 22ffe0dacef22adf70dc61b73f7a2f8fcd70d2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Sun, 8 Dec 2024 01:38:27 -0500 Subject: [PATCH 40/66] Update Dockerfile --- Dockerfile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index d520265..ea86f2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM phpswoole/swoole:php8.1-alpine COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ RUN install-php-extensions pcntl bcmath inotify \ - && apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch gettext \ + && apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch \ && addgroup -S -g 1000 www && adduser -S -G www -u 1000 www # 设置工作目录 @@ -11,15 +11,14 @@ WORKDIR /www # 复制项目文件和配置文件 COPY .docker / -COPY .env.example /www/.env.example COPY . /www # 生成环境变量文件并安装依赖 -RUN envsubst < /www/.env.example > /www/.env \ +RUN cp /www/.env.example /www/.env \ && composer install --optimize-autoloader --no-cache --no-dev \ && php artisan storage:link \ && chown -R www:www /www \ && chmod -R 775 /www # 启动 supervisor -CMD /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf +CMD ["/usr/bin/supervisord", "--nodaemon", "-c", "/etc/supervisor/supervisord.conf"] From aa3ff5cb663e9400a3952adee120370293eaffee Mon Sep 17 00:00:00 2001 From: Linus Xiong Date: Sun, 8 Dec 2024 01:48:49 -0500 Subject: [PATCH 41/66] fix bug --- .env.example | 69 +++++++++++++++++++++++++++------------------------- Dockerfile | 24 +++++++----------- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/.env.example b/.env.example index 6211636..93f2d35 100644 --- a/.env.example +++ b/.env.example @@ -1,40 +1,43 @@ -APP_NAME=${APP_NAME:-XBoard} -APP_ENV=${APP_ENV:-local} -APP_KEY=${APP_KEY:-base64:PZXk5vTuTinfeEVG5FpYv2l6WEhLsyvGpiWK7IgJJ60=} -APP_DEBUG=${APP_DEBUG:-false} -APP_URL=${APP_URL:-http://localhost} -ADMIN_SETTING_CACHE=${ADMIN_SETTING_CACHE:-60} -LOG_CHANNEL=${LOG_CHANNEL:-stack} +APP_NAME=XBoard +APP_ENV=local +APP_KEY=base64:PZXk5vTuTinfeEVG5FpYv2l6WEhLsyvGpiWK7IgJJ60= +APP_DEBUG=false +APP_URL=http://localhost -DB_CONNECTION=${DB_CONNECTION:-mysql} -DB_HOST=${DB_HOST:-127.0.0.1} -DB_PORT=${DB_PORT:-3306} -DB_DATABASE=${DB_DATABASE:-xboard} -DB_USERNAME=${DB_USERNAME:-root} -DB_PASSWORD=${DB_PASSWORD:-} +ADMIN_SETTING_CACHE=60 #设置缓存时间(单位秒) +LOG_CHANNEL=stack -REDIS_HOST=${REDIS_HOST:-127.0.0.1} -REDIS_PASSWORD=${REDIS_PASSWORD:-null} -REDIS_PORT=${REDIS_PORT:-6379} +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=xboard +DB_USERNAME=root +DB_PASSWORD= -BROADCAST_DRIVER=${BROADCAST_DRIVER:-log} -CACHE_DRIVER=${CACHE_DRIVER:-redis} -QUEUE_CONNECTION=${QUEUE_CONNECTION:-redis} +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 -MAIL_DRIVER=${MAIL_DRIVER:-smtp} -MAIL_HOST=${MAIL_HOST:-smtp.mailtrap.io} -MAIL_PORT=${MAIL_PORT:-2525} -MAIL_USERNAME=${MAIL_USERNAME:-null} -MAIL_PASSWORD=${MAIL_PASSWORD:-null} -MAIL_ENCRYPTION=${MAIL_ENCRYPTION:-null} -MAIL_FROM_ADDRESS=${MAIL_FROM_ADDRESS:-null} -MAIL_FROM_NAME=${MAIL_FROM_NAME:-null} +#默认将队列驱动和缓存驱动都修改为了redis,请务必安装redis +BROADCAST_DRIVER=log +CACHE_DRIVER=redis +QUEUE_CONNECTION=redis -MAILGUN_DOMAIN=${MAILGUN_DOMAIN:-} -MAILGUN_SECRET=${MAILGUN_SECRET:-} +MAIL_DRIVER=smtp +MAIL_HOST=smtp.mailtrap.io +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS=null +MAIL_FROM_NAME=null +MAILGUN_DOMAIN= +MAILGUN_SECRET= -ENABLE_AUTO_BACKUP_AND_UPDATE=${ENABLE_AUTO_BACKUP_AND_UPDATE:-false} -GOOGLE_CLOUD_KEY_FILE=${GOOGLE_CLOUD_KEY_FILE:-config/googleCloudStorageKey.json} -GOOGLE_CLOUD_STORAGE_BUCKET=${GOOGLE_CLOUD_STORAGE_BUCKET:-} +# google cloud stoage +ENABLE_AUTO_BACKUP_AND_UPDATE=false +GOOGLE_CLOUD_KEY_FILE=config/googleCloudStorageKey.json +GOOGLE_CLOUD_STORAGE_BUCKET= -INSTALLED=${INSTALLED:-false} +# 用于阻止重复安装 +INSTALLED=false diff --git a/Dockerfile b/Dockerfile index ea86f2b..f0102c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,23 +2,17 @@ FROM phpswoole/swoole:php8.1-alpine COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/ -RUN install-php-extensions pcntl bcmath inotify \ - && apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch \ - && addgroup -S -g 1000 www && adduser -S -G www -u 1000 www - -# 设置工作目录 +RUN install-php-extensions pcntl bcmath inotify \ +&& apk --no-cache add shadow supervisor nginx sqlite nginx-mod-http-brotli mysql-client git patch \ +&& addgroup -S -g 1000 www && adduser -S -G www -u 1000 www +#复制项目文件以及配置文件 WORKDIR /www - -# 复制项目文件和配置文件 COPY .docker / COPY . /www +RUN composer install --optimize-autoloader --no-cache --no-dev \ +&& php artisan storage:link \ +&& cp /www/.env.example /www/.env \ +&& chown -R www:www /www \ +&& chmod -R 775 /www -# 生成环境变量文件并安装依赖 -RUN cp /www/.env.example /www/.env \ - && composer install --optimize-autoloader --no-cache --no-dev \ - && php artisan storage:link \ - && chown -R www:www /www \ - && chmod -R 775 /www - -# 启动 supervisor CMD ["/usr/bin/supervisord", "--nodaemon", "-c", "/etc/supervisor/supervisord.conf"] From 654f1f84fb455b12700885058fa11afd222e6515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Sun, 8 Dec 2024 04:58:38 -0500 Subject: [PATCH 42/66] Update supervisord.conf --- .docker/etc/supervisor/supervisord.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.docker/etc/supervisor/supervisord.conf b/.docker/etc/supervisor/supervisord.conf index 018e54b..8919bd4 100644 --- a/.docker/etc/supervisor/supervisord.conf +++ b/.docker/etc/supervisor/supervisord.conf @@ -17,6 +17,7 @@ directory=/www command=sh -c "chown -R www:www /www && chmod -R 775 /www" autostart=true autorestart=false +priority=1 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr @@ -25,6 +26,7 @@ stderr_logfile_maxbytes=0 [program:nginx] command=nginx -g 'daemon off;' user=root +priority=5 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr @@ -36,6 +38,7 @@ startretries=10 [program:cron] command=crond -f -l 8 user=root +priority=4 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr @@ -62,6 +65,8 @@ command=php -c php.ini webman.php start directory=/www user=www numprocs=1 +priority=2 +startsecs=3 stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr @@ -74,6 +79,7 @@ startretries=10 command=php artisan horizon directory=/www user=www +priority=3 stdout_logfile=/www/storage/logs/queue.log stdout_logfile_maxbytes=0 stderr_logfile=/www/storage/logs/queue_error.log From de18cfe596ae3371d2591d7e874c495a32eec76a Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Mon, 9 Dec 2024 18:45:12 +0800 Subject: [PATCH 43/66] fix: resolve hy2 speed limit dispatch issue in Singbox client --- app/Protocols/SingBox.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Protocols/SingBox.php b/app/Protocols/SingBox.php index 3c79a01..1db6d8c 100644 --- a/app/Protocols/SingBox.php +++ b/app/Protocols/SingBox.php @@ -310,6 +310,8 @@ class SingBox $array['tag'] = $server['name']; $array['type'] = 'hysteria2'; $array['password'] = $password; + $array['up_mbps'] = $user->speed_limit ? min($server['down_mbps'], $user->speed_limit) : $server['down_mbps']; + $array['down_mbps'] = $user->speed_limit ? min($server['up_mbps'], $user->speed_limit) : $server['up_mbps']; if ($server['is_obfs']) { $array['obfs']['type'] = 'salamander'; From d6b7ae64040ed7646217b61202317d02f6d2e6b3 Mon Sep 17 00:00:00 2001 From: seck Date: Thu, 19 Dec 2024 15:34:58 +0800 Subject: [PATCH 44/66] Update default.sing-box.json The inet4_address and inet6_address types have been consolidated into a unified address type, in alignment with the official documentation. --- resources/rules/default.sing-box.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/rules/default.sing-box.json b/resources/rules/default.sing-box.json index 1cf83a8..b762ef6 100644 --- a/resources/rules/default.sing-box.json +++ b/resources/rules/default.sing-box.json @@ -49,8 +49,10 @@ "auto_route": true, "domain_strategy": "prefer_ipv4", "endpoint_independent_nat": true, - "inet4_address": "172.19.0.1/30", - "inet6_address": "2001:0470:f9da:fdfa::1/64", + "address": [ + "172.19.0.1/30", + "2001:0470:f9da:fdfa::1/64" + ], "mtu": 9000, "sniff": true, "sniff_override_destination": true, From ae249f8e96925c9af10b85a66442c9bdc8484e70 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:14:07 -0500 Subject: [PATCH 45/66] =?UTF-8?q?Update=201panel=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/1panel安装指南.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index 74ae6de..e90abfc 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -83,7 +83,8 @@ 3. 在站点目录中执行以下命令从 Github 克隆到当前目录: ``` - git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard ./ + git clone https://github.com/cedar2025/Xboard ./ + cp docker-compose.sample.yaml docker-compose.yaml ``` 4. 执行以下命令安装 Xboard: From cddcb144ef8068d397014e6203b9493fecb288b3 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:14:46 -0500 Subject: [PATCH 46/66] =?UTF-8?q?Update=201panel=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/1panel安装指南.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index e90abfc..161242d 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -90,7 +90,8 @@ 4. 执行以下命令安装 Xboard: ``` - docker compose run -it --rm xboard php artisan xboard:install + + docker compose run -it --rm xboard sh init.sh ``` 5. 根据提示输入上述创建的数据库账号密码,选择使用内置 redis 完成安装。 From dde41da139fa00b0bc71811d49bae6df6f1be552 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:43:06 -0500 Subject: [PATCH 47/66] =?UTF-8?q?update=20docker-compose=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/docker-compose安装指南.md | 105 +++++++++++++++------------------ 1 file changed, 47 insertions(+), 58 deletions(-) diff --git a/docs/docker-compose安装指南.md b/docs/docker-compose安装指南.md index ac25f8b..38f9745 100644 --- a/docs/docker-compose安装指南.md +++ b/docs/docker-compose安装指南.md @@ -1,77 +1,66 @@ -## Docker-Compose 部署教程 -本文教你如何在命令行使用docker-compose + sqlite来快速部署Xboard -如果你需要使用Mysql,你需要自行处理好Mysql的安装。 -### 部署 (使用docker-compose 2分钟部署) -> 在此提供Xboard安装、快速体验Xboard的步骤。 -使用docker compose + sqlite 快速部署站点(**无需安装Mysql以及redis**) -1. 安装docker -``` +## Docker Compose 快速部署指南 + +本指南介绍如何使用 Docker Compose 快速部署 Xboard。默认使用 SQLite 数据库,无需额外安装 MySQL。 + +### 1. 环境准备 + +安装 Docker: +```bash curl -sSL https://get.docker.com | bash -``` -Centos系统可能需要执行下面命令来启动Docker。 -``` + +# CentOS 系统需要执行: systemctl enable docker systemctl start docker ``` -2. 获取Docker compose 文件 -``` -git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard + +### 2. 部署步骤 + +1. 获取项目文件: +```bash +git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard cd Xboard ``` -3. 执行数据库安装命令 -> 选择 **启用sqlite** 和 **Docker内置的Redis** -``` -docker compose run -it --rm -e enable_sqlite=true -e enable_redis=true -e admin_account=your_admin_email@example.com xboard php artisan xboard:install -``` -> 或者根据自己的需要在运行时选择 -``` -docker compose run -it --rm xboard php artisan xboard:install -``` -> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来) -> 你需要执行下面的 **启动xborad** 步骤之后才能访问后台 -4. 启动Xboard +2. 安装数据库: +```bash +# 快速安装(推荐新手使用) +docker compose run -it --rm \ + -e enable_sqlite=true \ + -e enable_redis=true \ + -e admin_account=admin@demo.com \ + web php artisan xboard:install + +# 自定义配置安装(高级用户) +docker compose run -it --rm web php artisan xboard:install ``` +> 安装完成后请保存返回的后台地址和管理员账号密码 + +3. 启动服务: +```bash docker compose up -d ``` -> 安装完成之后即可访问你的站点 -5. 访问站点 -> 启动之后网站端口默认为7001, 你可以配置nginx反向代理使用80端口 -网站地址: http://你的IP:7001/ -在此你已经成功部署了, 你可以访问网址体验Xboard的完整功能, +4. 访问站点: +- 默认端口:7001 +- 网站地址:http://服务器IP:7001 -> 如果你需要使用mysql,请自行安装Mysql后重新部署 +### 3. 版本更新 -### **更新** -1. 修改版本 -``` +```bash cd Xboard -vi docker-compose.yaml -``` -> 修改docker-compose.yaml 当中image后面的版本号为你需要的版本 -> 如果为版本为latest 则可以忽略这一步,直接进行第二步 - -2. 更新数据库(可以执行多次都是安全的) -``` docker compose pull docker compose down -docker compose run -it --rm xboard php artisan xboard:update -docker compose up -d -``` -> 即可更新成功 - -### **回滚** -> 此回滚不回滚数据库,是否回滚数据库请查看相关文档 -1. 回退版本 -``` -vi docker-compose.yaml -``` -> 修改docker-compose.yaml 当中image后面的版本号为更新前的版本号 -2. 启动 -``` +docker compose run -it --rm web php artisan xboard:update docker compose up -d ``` -### 注意 -启用webman后做的任何代码修改都需要重启生效 +### 4. 版本回滚 + +1. 修改 `docker-compose.yaml` 中的版本号为需要回滚的版本 +2. 执行:`docker compose up -d` + +### 注意事项 + +- 如需使用 MySQL,请自行安装并重新部署 +- 代码修改后需要重启服务才能生效 +- 可以配置 Nginx 反向代理使用 80 端口 From 5b3474a06d6061dc28caf75c15e22af49a5af4f2 Mon Sep 17 00:00:00 2001 From: xboard Date: Thu, 9 Jan 2025 10:15:21 +0800 Subject: [PATCH 48/66] =?UTF-8?q?Revert=20"update=20docker-compose?= =?UTF-8?q?=E5=AE=89=E8=A3=85=E6=8C=87=E5=8D=97.md"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit dde41da139fa00b0bc71811d49bae6df6f1be552. --- docs/docker-compose安装指南.md | 105 ++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/docs/docker-compose安装指南.md b/docs/docker-compose安装指南.md index 38f9745..ac25f8b 100644 --- a/docs/docker-compose安装指南.md +++ b/docs/docker-compose安装指南.md @@ -1,66 +1,77 @@ -## Docker Compose 快速部署指南 - -本指南介绍如何使用 Docker Compose 快速部署 Xboard。默认使用 SQLite 数据库,无需额外安装 MySQL。 - -### 1. 环境准备 - -安装 Docker: -```bash +## Docker-Compose 部署教程 +本文教你如何在命令行使用docker-compose + sqlite来快速部署Xboard +如果你需要使用Mysql,你需要自行处理好Mysql的安装。 +### 部署 (使用docker-compose 2分钟部署) +> 在此提供Xboard安装、快速体验Xboard的步骤。 +使用docker compose + sqlite 快速部署站点(**无需安装Mysql以及redis**) +1. 安装docker +``` curl -sSL https://get.docker.com | bash - -# CentOS 系统需要执行: +``` +Centos系统可能需要执行下面命令来启动Docker。 +``` systemctl enable docker systemctl start docker ``` - -### 2. 部署步骤 - -1. 获取项目文件: -```bash -git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard +2. 获取Docker compose 文件 +``` +git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard cd Xboard ``` - -2. 安装数据库: -```bash -# 快速安装(推荐新手使用) -docker compose run -it --rm \ - -e enable_sqlite=true \ - -e enable_redis=true \ - -e admin_account=admin@demo.com \ - web php artisan xboard:install - -# 自定义配置安装(高级用户) -docker compose run -it --rm web php artisan xboard:install +3. 执行数据库安装命令 +> 选择 **启用sqlite** 和 **Docker内置的Redis** ``` -> 安装完成后请保存返回的后台地址和管理员账号密码 +docker compose run -it --rm -e enable_sqlite=true -e enable_redis=true -e admin_account=your_admin_email@example.com xboard php artisan xboard:install +``` +> 或者根据自己的需要在运行时选择 +``` +docker compose run -it --rm xboard php artisan xboard:install +``` +> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来) +> 你需要执行下面的 **启动xborad** 步骤之后才能访问后台 -3. 启动服务: -```bash +4. 启动Xboard +``` docker compose up -d ``` +> 安装完成之后即可访问你的站点 +5. 访问站点 +> 启动之后网站端口默认为7001, 你可以配置nginx反向代理使用80端口 -4. 访问站点: -- 默认端口:7001 -- 网站地址:http://服务器IP:7001 +网站地址: http://你的IP:7001/ +在此你已经成功部署了, 你可以访问网址体验Xboard的完整功能, -### 3. 版本更新 +> 如果你需要使用mysql,请自行安装Mysql后重新部署 -```bash +### **更新** +1. 修改版本 +``` cd Xboard +vi docker-compose.yaml +``` +> 修改docker-compose.yaml 当中image后面的版本号为你需要的版本 +> 如果为版本为latest 则可以忽略这一步,直接进行第二步 + +2. 更新数据库(可以执行多次都是安全的) +``` docker compose pull docker compose down -docker compose run -it --rm web php artisan xboard:update +docker compose run -it --rm xboard php artisan xboard:update +docker compose up -d +``` +> 即可更新成功 + +### **回滚** +> 此回滚不回滚数据库,是否回滚数据库请查看相关文档 +1. 回退版本 +``` +vi docker-compose.yaml +``` +> 修改docker-compose.yaml 当中image后面的版本号为更新前的版本号 +2. 启动 +``` docker compose up -d ``` -### 4. 版本回滚 - -1. 修改 `docker-compose.yaml` 中的版本号为需要回滚的版本 -2. 执行:`docker compose up -d` - -### 注意事项 - -- 如需使用 MySQL,请自行安装并重新部署 -- 代码修改后需要重启服务才能生效 -- 可以配置 Nginx 反向代理使用 80 端口 +### 注意 +启用webman后做的任何代码修改都需要重启生效 From cf44a62db7ae2e72092bf2aa1a9e7620ad9478f1 Mon Sep 17 00:00:00 2001 From: xboard Date: Thu, 9 Jan 2025 10:15:24 +0800 Subject: [PATCH 49/66] =?UTF-8?q?Revert=20"Update=201panel=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E6=8C=87=E5=8D=97.md"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cddcb144ef8068d397014e6203b9493fecb288b3. --- docs/1panel安装指南.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index 161242d..e90abfc 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -90,8 +90,7 @@ 4. 执行以下命令安装 Xboard: ``` - - docker compose run -it --rm xboard sh init.sh + docker compose run -it --rm xboard php artisan xboard:install ``` 5. 根据提示输入上述创建的数据库账号密码,选择使用内置 redis 完成安装。 From 89d2aed46d9df460322ec20148db0561aead983e Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Thu, 9 Jan 2025 23:57:38 +0000 Subject: [PATCH 50/66] =?UTF-8?q?Revert=20"Update=201panel=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E6=8C=87=E5=8D=97.md"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ae249f8e96925c9af10b85a66442c9bdc8484e70. --- docs/1panel安装指南.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index e90abfc..74ae6de 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -83,8 +83,7 @@ 3. 在站点目录中执行以下命令从 Github 克隆到当前目录: ``` - git clone https://github.com/cedar2025/Xboard ./ - cp docker-compose.sample.yaml docker-compose.yaml + git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard ./ ``` 4. 执行以下命令安装 Xboard: From e2262f14355c7d0f15f9b2d9a82265eeb83801d2 Mon Sep 17 00:00:00 2001 From: Elysia <118418714+elysias123@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:31:51 +0800 Subject: [PATCH 51/66] feat: allow admin/staff unbind a user --- app/Plugins/Telegram/Commands/UnBind.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/app/Plugins/Telegram/Commands/UnBind.php b/app/Plugins/Telegram/Commands/UnBind.php index ebd9325..67fd022 100644 --- a/app/Plugins/Telegram/Commands/UnBind.php +++ b/app/Plugins/Telegram/Commands/UnBind.php @@ -12,11 +12,17 @@ class UnBind extends Telegram { public function handle($message, $match = []) { if (!$message->is_private) return; - $user = User::where('telegram_id', $message->chat_id)->first(); - $telegramService = $this->telegramService; - if (!$user) { - $telegramService->sendMessage($message->chat_id, '没有查询到您的用户信息,请先绑定账号', 'markdown'); - return; + if (!isset($message->args[0])) { + $user = User::where('telegram_id', $message->chat_id)->first(); + } else { + $chat = User::where('telegram_id', $message->chat_id)->first(); + if (!$chat) return; + if (!($chat->is_admin || $chat->is_staff)) return; + if (strpos($message->args[0], '@') !== true) { + $user = User::where('email', $message->args[0])->first(); + } else { + $user = User::where('telegram_id', $message->args[0])->first(); + } } $user->telegram_id = NULL; if (!$user->save()) { From 558834b15493a9270bc2b0ddde34c547b2c2c7c4 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Mon, 13 Jan 2025 07:55:19 +0800 Subject: [PATCH 52/66] update docs --- docs/1panel安装指南.md | 1 + docs/aapanel+docker安装指南.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index 74ae6de..fdab87e 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -115,6 +115,7 @@ docker compose up -d ``` docker compose down xboard docker compose pull + docker compose run -it --rm web php artisan xboard:update docker compose up -d ``` diff --git a/docs/aapanel+docker安装指南.md b/docs/aapanel+docker安装指南.md index 5094da8..080b5fd 100644 --- a/docs/aapanel+docker安装指南.md +++ b/docs/aapanel+docker安装指南.md @@ -94,7 +94,7 @@ docker compose run -it --rm xboard sh update.sh ``` 2. 重启Xboard ``` -docker compose restart +docker compose up -d ``` 🎉: 在此你已完成Xboard的更新 From d57c3ca60d94b9fc2c072c2103423359fc0c7dd5 Mon Sep 17 00:00:00 2001 From: xboard Date: Mon, 13 Jan 2025 07:57:07 +0800 Subject: [PATCH 53/66] Revert "update docs" This reverts commit 558834b15493a9270bc2b0ddde34c547b2c2c7c4. --- docs/1panel安装指南.md | 1 - docs/aapanel+docker安装指南.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/1panel安装指南.md b/docs/1panel安装指南.md index fdab87e..74ae6de 100644 --- a/docs/1panel安装指南.md +++ b/docs/1panel安装指南.md @@ -115,7 +115,6 @@ docker compose up -d ``` docker compose down xboard docker compose pull - docker compose run -it --rm web php artisan xboard:update docker compose up -d ``` diff --git a/docs/aapanel+docker安装指南.md b/docs/aapanel+docker安装指南.md index 080b5fd..5094da8 100644 --- a/docs/aapanel+docker安装指南.md +++ b/docs/aapanel+docker安装指南.md @@ -94,7 +94,7 @@ docker compose run -it --rm xboard sh update.sh ``` 2. 重启Xboard ``` -docker compose up -d +docker compose restart ``` 🎉: 在此你已完成Xboard的更新 From a550fd1436e5213c792fd69f97420bb4f6446ec1 Mon Sep 17 00:00:00 2001 From: Elysia Date: Tue, 14 Jan 2025 13:54:26 +0800 Subject: [PATCH 54/66] feat: Replace with a random string when the subscription domain contains *&Replace with the user uuid when the subscription domain contains {uuid} --- app/Utils/Helper.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/Utils/Helper.php b/app/Utils/Helper.php index 341df4e..c88272a 100644 --- a/app/Utils/Helper.php +++ b/app/Utils/Helper.php @@ -110,11 +110,20 @@ class Helper public static function getSubscribeUrl(string $token, $subscribeUrl = null) { + $strs = 'QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm'; + $randstr = substr(str_shuffle($strs), 0, rand(4,8)); + $path = route('client.subscribe', ['token' => $token], false); if(!$subscribeUrl){ $subscribeUrls = explode(',', admin_setting('subscribe_url')); $subscribeUrl = \Arr::random($subscribeUrls); $subscribeUrl = self::replaceByPattern($subscribeUrl); + if (strpos($subscribeUrl, "*") !== false) { + $subscribeUrl = str_replace("*", $randstr, $subscribeUrl); + } elseif (strpos($subscribeUrl, '{uuid}') !== false) { + $user = User::where('token', $token)->first(); + $subscribeUrl = str_replace('{uuid}', $user->uuid, $subscribeUrl); + } } return $subscribeUrl ? rtrim($subscribeUrl, '/') . $path : url($path); } From 4d2b442885287c5c11e8340e94d6f1bcac183ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E5=A4=A7=E7=99=BD?= Date: Tue, 14 Jan 2025 14:43:52 -0500 Subject: [PATCH 55/66] Update StripeALLInOne.php fix a bug that causes 400: https://support.stripe.com/questions/use-of-the-statement-descriptor-parameter-on-paymentintents-for-card-charges --- app/Payments/StripeALLInOne.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Payments/StripeALLInOne.php b/app/Payments/StripeALLInOne.php index 9c7e003..70e5b5b 100644 --- a/app/Payments/StripeALLInOne.php +++ b/app/Payments/StripeALLInOne.php @@ -66,7 +66,7 @@ class StripeALLInOne { 'confirm' => true, 'payment_method' => $stripePaymentMethod->id, 'automatic_payment_methods' => ['enabled' => true], - 'statement_descriptor' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), + 'statement_descriptor_suffix' => 'sub-' . $order['user_id'] . '-' . substr($order['trade_no'], -8), 'description' => $this->config['description'], 'metadata' => [ 'user_id' => $order['user_id'], From 18c90a0aee49d7efaca1f168850bffc763a995bf Mon Sep 17 00:00:00 2001 From: xboard Date: Thu, 16 Jan 2025 09:50:45 +0800 Subject: [PATCH 56/66] update docker-publish.yml --- .github/workflows/docker-publish.yml | 126 ++++++++++++++------------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 00dd386..8320ef7 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,89 +1,91 @@ -name: Docker - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. +name: Docker Build and Publish on: push: - branches: [ "dev" ] - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] - workflow_dispatch: # Enable manual trigger + branches: ["legacy"] + workflow_dispatch: env: - # Use docker.io for Docker Hub if empty REGISTRY: ghcr.io - # github.repository as / IMAGE_NAME: ${{ github.repository }} - jobs: build: - runs-on: ubuntu-latest permissions: contents: read packages: write - # This is used to complete the identity challenge - # with sigstore/fulcio when running outside of PRs. id-token: write steps: - - name: Checkout repository - uses: actions/checkout@v3 - - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up QEMU uses: docker/setup-qemu-action@v3 + with: + platforms: 'arm64,amd64' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + platforms: linux/amd64,linux/arm64 + driver-opts: | + image=moby/buildkit:latest + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=sha,format=long + type=raw,value=new + + - name: Get version + id: get_version + run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT + + - name: Update version in app.php + run: | + VERSION=$(date '+%Y%m%d')-$(git rev-parse --short HEAD) + sed -i "s/'version' => '.*'/'version' => '$VERSION'/g" config/app.php + echo "Updated version to: $VERSION" + + - name: Build and push + id: build-and-push + uses: docker/build-push-action@v5 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + tags: | + ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:legacy + ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:${{ steps.get_version.outputs.version }} + build-args: | + BUILDKIT_INLINE_CACHE=1 + provenance: false - name: Install cosign uses: sigstore/cosign-installer@v3.4.0 with: cosign-release: 'v2.2.2' - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3.2.0 - - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - uses: docker/login-action@v3.1.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v5.5.1 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - - name: Get version - id: get_version - run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT - - - name: Build and push Docker image - id: build-and-push - uses: docker/build-push-action@v5.3.0 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:latest,${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard,${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:${{ steps.get_version.outputs.version }} - # Sign the resulting Docker image digest except on PRs. - # This will only write to the public Rekor transparency log when the Docker - # repository is public to avoid leaking data. If you would like to publish - # transparency data even for private images, pass --force to cosign below. - # https://github.com/sigstore/cosign - - name: Sign the published Docker image + - name: Sign image + if: steps.build-and-push.outputs.digest != '' env: - # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable - TAGS: ${{ steps.meta.outputs.tags }} - DIGEST: ${{ steps.build-and-push.outputs.digest }} - # This step uses the identity token to provision an ephemeral certificate - # against the sigstore community Fulcio instance. - run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} + COSIGN_EXPERIMENTAL: 1 + run: | + echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes "{}@${{ steps.build-and-push.outputs.digest }}" \ No newline at end of file From 4877866fe8aa696823c58e9bc65202a2889168fc Mon Sep 17 00:00:00 2001 From: xboard Date: Thu, 16 Jan 2025 09:58:04 +0800 Subject: [PATCH 57/66] update docs --- docker-compose.sample.yaml | 2 +- docs/aapanel+docker安装指南.md | 2 +- docs/aapanel安装指南.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.sample.yaml b/docker-compose.sample.yaml index 87960b5..e16db3a 100644 --- a/docker-compose.sample.yaml +++ b/docker-compose.sample.yaml @@ -3,7 +3,7 @@ services: xboard: # build: # context: . - image: ghcr.io/cedar2025/xboard:latest + image: ghcr.io/cedar2025/xboard:legacy volumes: - ./:/www/ # - ./.env:/www/.env diff --git a/docs/aapanel+docker安装指南.md b/docs/aapanel+docker安装指南.md index 5094da8..0ba7653 100644 --- a/docs/aapanel+docker安装指南.md +++ b/docs/aapanel+docker安装指南.md @@ -39,7 +39,7 @@ rm -rf .htaccess 404.html 502.html index.html .user.ini ``` > 执行命令从 Github 克隆到当前目录。 ``` -git clone https://github.com/cedar2025/Xboard.git ./ +git clone -b legacy https://github.com/cedar2025/Xboard.git ./ ``` > 复制一份docker-compose.yaml文件 ``` diff --git a/docs/aapanel安装指南.md b/docs/aapanel安装指南.md index 430e054..164085f 100644 --- a/docs/aapanel安装指南.md +++ b/docs/aapanel安装指南.md @@ -48,7 +48,7 @@ rm -rf .htaccess 404.html 502.html index.html .user.ini ``` > 执行命令从 Github 克隆到当前目录。 ``` -git clone https://github.com/cedar2025/Xboard.git ./ +git clone -b legacy https://github.com/cedar2025/Xboard.git ./ ``` > 执行命令安装依赖包以及V2board ``` From f6af7313d09fc7946e70ec994a86000e2d3c5e76 Mon Sep 17 00:00:00 2001 From: xboard Date: Thu, 16 Jan 2025 10:13:53 +0800 Subject: [PATCH 58/66] update docs --- docs/docker-compose安装指南.md | 142 +++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 50 deletions(-) diff --git a/docs/docker-compose安装指南.md b/docs/docker-compose安装指南.md index ac25f8b..d7c3a1f 100644 --- a/docs/docker-compose安装指南.md +++ b/docs/docker-compose安装指南.md @@ -1,77 +1,119 @@ -## Docker-Compose 部署教程 -本文教你如何在命令行使用docker-compose + sqlite来快速部署Xboard -如果你需要使用Mysql,你需要自行处理好Mysql的安装。 -### 部署 (使用docker-compose 2分钟部署) -> 在此提供Xboard安装、快速体验Xboard的步骤。 -使用docker compose + sqlite 快速部署站点(**无需安装Mysql以及redis**) -1. 安装docker -``` +## Docker-Compose 快速部署指南 + +### 环境要求 +- Docker (最新稳定版) +- 至少 1GB 可用内存 +- 至少 10GB 可用磁盘空间 +- 系统支持: Linux/macOS/Windows +- 开放端口: 7001 (默认) + +### 部署步骤 + +#### 1. 安装 Docker +```bash +# 安装 Docker curl -sSL https://get.docker.com | bash -``` -Centos系统可能需要执行下面命令来启动Docker。 -``` + +# CentOS 系统需要执行以下命令启动 Docker systemctl enable docker systemctl start docker ``` -2. 获取Docker compose 文件 -``` -git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard + +#### 2. 获取部署文件 +```bash +git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard cd Xboard ``` -3. 执行数据库安装命令 -> 选择 **启用sqlite** 和 **Docker内置的Redis** -``` -docker compose run -it --rm -e enable_sqlite=true -e enable_redis=true -e admin_account=your_admin_email@example.com xboard php artisan xboard:install -``` -> 或者根据自己的需要在运行时选择 + +#### 3. 初始化安装 +> 提供两种安装方式,选择其一即可: + +**方式一:快速安装** (推荐) +```bash +# 使用 SQLite + Docker内置Redis +docker compose run -it --rm \ + -e enable_sqlite=true \ + -e enable_redis=true \ + -e admin_account=admin@demo.com \ + xboard php artisan xboard:install ``` + +**方式二:自定义安装** +```bash +# 根据提示自定义配置 docker compose run -it --rm xboard php artisan xboard:install ``` -> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来) -> 你需要执行下面的 **启动xborad** 步骤之后才能访问后台 -4. 启动Xboard -``` +> **重要提示:** +> - 安装完成后会显示后台地址和管理员账号密码,请务必保存 +> - 如需使用 MySQL,请先自行安装并配置 MySQL 后再部署 + +#### 4. 启动服务 +```bash docker compose up -d ``` -> 安装完成之后即可访问你的站点 -5. 访问站点 -> 启动之后网站端口默认为7001, 你可以配置nginx反向代理使用80端口 -网站地址: http://你的IP:7001/ -在此你已经成功部署了, 你可以访问网址体验Xboard的完整功能, +#### 5. 访问站点 +- 网站地址:`http://服务器IP:7001` +- 后台地址:安装时提供的地址 -> 如果你需要使用mysql,请自行安装Mysql后重新部署 +### 更新指南 -### **更新** -1. 修改版本 -``` +#### 方式一:快速更新(保持最新版本) +```bash cd Xboard -vi docker-compose.yaml -``` -> 修改docker-compose.yaml 当中image后面的版本号为你需要的版本 -> 如果为版本为latest 则可以忽略这一步,直接进行第二步 - -2. 更新数据库(可以执行多次都是安全的) -``` docker compose pull docker compose down docker compose run -it --rm xboard php artisan xboard:update docker compose up -d ``` -> 即可更新成功 -### **回滚** -> 此回滚不回滚数据库,是否回滚数据库请查看相关文档 -1. 回退版本 -``` +#### 方式二:更新至指定版本 +1. 修改版本号 +```bash +# 编辑 docker-compose.yaml,修改 image 的版本号 vi docker-compose.yaml ``` -> 修改docker-compose.yaml 当中image后面的版本号为更新前的版本号 -2. 启动 -``` + +2. 执行更新 +```bash +docker compose pull +docker compose down +docker compose run -it --rm xboard php artisan xboard:update docker compose up -d ``` -### 注意 -启用webman后做的任何代码修改都需要重启生效 +### 版本回滚 +```bash +# 1. 修改 docker-compose.yaml 中的版本号为目标版本 +vi docker-compose.yaml + +# 2. 重启服务 +docker compose up -d +``` + +### 常见问题 + +1. **端口配置** +- 默认端口为 7001 +- 可通过 Nginx 反向代理使用 80/443 端口 +- 如需修改端口,请编辑 docker-compose.yaml + +2. **数据持久化** +- 数据默认存储在 ./data 目录 +- 建议定期备份 data 目录 + +3. **性能优化** +- 启用 webman 后的代码修改需要重启服务才能生效 +- 可根据实际需求调整容器资源限制 + +### 安全建议 +1. 及时更新到最新版本 +2. 修改默认管理员账号 +3. 使用强密码 +4. 建议配置 SSL 证书 +5. 定期备份数据 + +### 技术支持 +- GitHub Issues: https://github.com/cedar2025/Xboard/issues +- 官方文档:[文档链接] From 024a9dfb543e73f76e26cc1afce17b03e5d1b4c6 Mon Sep 17 00:00:00 2001 From: rebecca554owen Date: Thu, 16 Jan 2025 22:44:10 +0800 Subject: [PATCH 59/66] fix update.sh --- update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update.sh b/update.sh index 02e7769..ae37c6e 100755 --- a/update.sh +++ b/update.sh @@ -11,7 +11,7 @@ if ! command -v git &> /dev/null; then fi git config --global --add safe.directory $(pwd) -git fetch --all && git reset --hard origin/dev && git pull origin dev +git fetch --all && git reset --hard origin/legacy && git pull origin legacy rm -rf composer.lock composer.phar wget https://github.com/composer/composer/releases/latest/download/composer.phar -O composer.phar php composer.phar update -vvv From 3a05281a9f146747672d12c9cb69487a1ef3ed75 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Sat, 18 Jan 2025 21:57:33 +0800 Subject: [PATCH 60/66] Update MigrateFromV2b.php --- app/Console/Commands/MigrateFromV2b.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/Console/Commands/MigrateFromV2b.php b/app/Console/Commands/MigrateFromV2b.php index 2209282..0fca35e 100644 --- a/app/Console/Commands/MigrateFromV2b.php +++ b/app/Console/Commands/MigrateFromV2b.php @@ -51,15 +51,16 @@ class MigrateFromV2b extends Command ], '1.7.3' => [ 'ALTER TABLE `v2_stat_order` RENAME TO `v2_stat`;', - "ALTER TABLE `v2_stat` CHANGE COLUMN order_amount order_total INT COMMENT '订单合计';", + "ALTER TABLE `v2_stat` CHANGE COLUMN order_amount paid_total INT COMMENT '订单合计';", + "ALTER TABLE `v2_stat` CHANGE COLUMN order_count paid_count INT COMMENT '邀请佣金';", "ALTER TABLE `v2_stat` CHANGE COLUMN commission_amount commission_total INT COMMENT '佣金合计';", "ALTER TABLE `v2_stat` - ADD COLUMN paid_count INT NULL, - ADD COLUMN paid_total INT NULL, + ADD COLUMN order_count INT NULL, + ADD COLUMN order_total INT NULL, ADD COLUMN register_count INT NULL, ADD COLUMN invite_count INT NULL, ADD COLUMN transfer_used_total VARCHAR(32) NULL; - ", + ", "CREATE TABLE `v2_log` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `title` TEXT NOT NULL, From dff2e721cb75ca8fddedb007cfdd9298ce69a5ca Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Tue, 21 Jan 2025 22:05:56 +0800 Subject: [PATCH 61/66] Update docker-publish.yml --- .github/workflows/docker-publish.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 8320ef7..c20bb7f 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -2,7 +2,7 @@ name: Docker Build and Publish on: push: - branches: ["legacy"] + branches: ["legacy", "dev"] workflow_dispatch: env: @@ -73,6 +73,7 @@ jobs: cache-to: type=gha,mode=max tags: | ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:legacy + ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:dev ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:${{ steps.get_version.outputs.version }} build-args: | BUILDKIT_INLINE_CACHE=1 @@ -88,4 +89,4 @@ jobs: env: COSIGN_EXPERIMENTAL: 1 run: | - echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes "{}@${{ steps.build-and-push.outputs.digest }}" \ No newline at end of file + echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign --yes "{}@${{ steps.build-and-push.outputs.digest }}" From 7acae3dcc42a6d94fb1ebd3bdd7e472f4c5fa6b5 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Tue, 21 Jan 2025 22:14:01 +0800 Subject: [PATCH 62/66] Update docker-publish.yml --- .github/workflows/docker-publish.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index c20bb7f..f6c2443 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -74,6 +74,8 @@ jobs: tags: | ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:legacy ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:dev + ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard + ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:latest ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:${{ steps.get_version.outputs.version }} build-args: | BUILDKIT_INLINE_CACHE=1 From 6c67cbf85ad21bc927d44f85c7bcb96957243f85 Mon Sep 17 00:00:00 2001 From: xboard Date: Wed, 22 Jan 2025 21:16:51 +0800 Subject: [PATCH 63/66] update docs --- README.md | 92 +++++++++++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 740050d..5561913 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@ -# 关于Xboard -Xboard是基于V2board二次开发,在性能上和功能上都有大部分增强的**面板 +# About Xboard +Xboard is a panel based on V2board's secondary development, with significant enhancements in both performance and functionality. -# 免责声明 -本项目只是本人个人学习开发并维护,本人不保证任何可用性,也不对使用本软件造成的任何后果负责。 +# Disclaimer +This project is personally developed and maintained by me for learning purposes. I do not guarantee any availability and am not responsible for any consequences resulting from the use of this software. -# Xboard 特点 -基于V2board 二次开发,增加了以下特性 -- 升级Laravel10 -- 适配Laravels (提升至10+倍并发) -- 适配Webman (比laravels快50%左右) -- 修改配置从数据库中获取 -- 支持Docker部署、分布式部署 -- 支持根据用户IP归属地来下发订阅 -- 增加Hy2支持 -- 增加sing-box下发 -- 支持直接从cloudflare获取访问者真实IP -- 支持根据客户端版本自动下发新协议 -- 支持线路筛选(订阅地址后面增加 &filter=香港|美国) -- 支持Sqlite安装(代替Mysql,自用用户福音) -- 使用Vue3 + TypeScript + NaiveUI + Unocss + Pinia重构用户前端 -- 修复大量BUG +# Xboard Features +Based on V2board's secondary development, with the following added features: +- Upgraded to Laravel 10 +- Adapted to Laravels (10+ times concurrent improvement) +- Adapted to Webman (about 50% faster than laravels) +- Modified configuration retrieval from database +- Support for Docker deployment and distributed deployment +- Support for subscription distribution based on user IP location +- Added Hy2 support +- Added sing-box distribution +- Support for obtaining real visitor IP directly from Cloudflare +- Support for automatic new protocol distribution based on client version +- Support for route filtering (add &filter=HongKong|USA after subscription URL) +- Support for Sqlite installation (alternative to MySQL, great for personal use) +- User frontend rebuilt using Vue3 + TypeScript + NaiveUI + Unocss + Pinia +- Fixed numerous bugs -# **系统架构** +# **System Architecture** - PHP8.1+ - Composer @@ -29,36 +29,36 @@ Xboard是基于V2board二次开发,在性能上和功能上都有大部分增 - Redis - Laravel -## 性能对比 [查看详情](./docs/性能对比.md) -> xboard 无论前端还是后端性能都有巨大的提升 +## Performance Comparison [View Details](./docs/性能对比.md) +> xboard shows tremendous performance improvements in both frontend and backend -|场景 | php-fpm(传统) | php-fpm(传统开启opcache) | laravels | webman(docker)| -|---- | ---- |---- |----| ---| -|首页 | 6请求/秒 | 157请求/秒 | 477请求/秒 | 803请求/秒 | -|用户订阅 | 6请求/秒 | 196请求/秒 | 586请求/秒 | 1064请求/秒 | -|用户首页延迟| 308ms | 110ms | 101ms | 98ms | +|Scenario | php-fpm(traditional) | php-fpm(traditional with opcache) | laravels | webman(docker)| +|---- | ---- |---- |---- | ---| +|Homepage | 6 req/s | 157 req/s | 477 req/s| 803 req/s| +|User Subscription| 6 req/s | 196 req/s | 586 req/s| 1064 req/s| +|User Homepage Latency| 308ms | 110ms | 101ms | 98ms| -## 页面展示 -![示例图片](./docs/images/dashboard.png) +## Page Display +![Example Image](./docs/images/dashboard.png) -## 安装 / 更新 / 回滚 -你可以点击查看下列方式的**安装、更新**步骤 -- [1panel 部署](./docs/1panel安装指南.md) -- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md) -- [aapanel + Docker Compose (推荐)](./docs/aapanel+docker安装指南.md) -- [aapanel 部署](./docs/aapanel安装指南.md) -### 从其他版本迁移 -#### 数据库迁移 -**根据你的版本查看对应的迁移指南进行迁移** -- v2board dev 23/10/27的版本 [点击跳转迁移指南](./docs/v2b_dev迁移指南.md) -- v2board 1.7.4 [点击跳转迁移指南](./docs/v2b_1.7.4迁移指南.md) -- v2board 1.7.3 [点击跳转迁移指南](./docs/v2b_1.7.3迁移指南.md) -- v2board wyx2685 [点击跳转迁移指南](./docs/v2b_wyx2685迁移指南.md) +## Installation / Update / Rollback +You can click to view the **installation and update** steps for the following methods: +- [1panel Deployment](./docs/1panel安装指南.md) +- [Docker Compose Command-line Quick Deployment](./docs/docker-compose安装指南.md) +- [aapanel + Docker Compose (Recommended)](./docs/aapanel+docker安装指南.md) +- [aapanel Deployment](./docs/aapanel安装指南.md) +### Migrating from Other Versions +#### Database Migration +**Check the corresponding migration guide according to your version** +- v2board dev version 23/10/27 [Jump to Migration Guide](./docs/v2b_dev迁移指南.md) +- v2board 1.7.4 [Jump to Migration Guide](./docs/v2b_1.7.4迁移指南.md) +- v2board 1.7.3 [Jump to Migration Guide](./docs/v2b_1.7.3迁移指南.md) +- v2board wyx2685 [Jump to Migration Guide](./docs/v2b_wyx2685迁移指南.md) -### 注意 -> 修改后台路径需要重启才能生效 +### Note +> Modifying the admin path requires a restart to take effect ``` docker compose restart ``` -> 如果是是aapanel安装则需要重启 webman守护进程 +> If using aapanel installation, you need to restart the webman daemon process From d231b6ebcd49beb59cb0f53bd39e92551b5345f3 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Sat, 25 Jan 2025 17:07:31 +0800 Subject: [PATCH 64/66] =?UTF-8?q?Update=20aapanel+docker=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/aapanel+docker安装指南.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/aapanel+docker安装指南.md b/docs/aapanel+docker安装指南.md index 0ba7653..b835760 100644 --- a/docs/aapanel+docker安装指南.md +++ b/docs/aapanel+docker安装指南.md @@ -39,7 +39,7 @@ rm -rf .htaccess 404.html 502.html index.html .user.ini ``` > 执行命令从 Github 克隆到当前目录。 ``` -git clone -b legacy https://github.com/cedar2025/Xboard.git ./ +git clone -b dev https://github.com/cedar2025/Xboard.git ./ ``` > 复制一份docker-compose.yaml文件 ``` From 99413c5962b6fae27d621cd592518679bac59075 Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:04:37 +0800 Subject: [PATCH 65/66] =?UTF-8?q?Update=20aapanel=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=8C=87=E5=8D=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/aapanel安装指南.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/aapanel安装指南.md b/docs/aapanel安装指南.md index 164085f..c9bf194 100644 --- a/docs/aapanel安装指南.md +++ b/docs/aapanel安装指南.md @@ -48,7 +48,7 @@ rm -rf .htaccess 404.html 502.html index.html .user.ini ``` > 执行命令从 Github 克隆到当前目录。 ``` -git clone -b legacy https://github.com/cedar2025/Xboard.git ./ +git clone -b dev https://github.com/cedar2025/Xboard.git ./ ``` > 执行命令安装依赖包以及V2board ``` From cab76f1cf3a3b66305668e8c579c6f435222681f Mon Sep 17 00:00:00 2001 From: Xboard <147830212+cedar2025@users.noreply.github.com> Date: Thu, 10 Jul 2025 19:05:29 +0800 Subject: [PATCH 66/66] Update default.conf --- .docker/etc/nginx/http.d/default.conf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.docker/etc/nginx/http.d/default.conf b/.docker/etc/nginx/http.d/default.conf index 5c0acb1..9b1d49d 100644 --- a/.docker/etc/nginx/http.d/default.conf +++ b/.docker/etc/nginx/http.d/default.conf @@ -38,4 +38,7 @@ server { location ~ /\.ht { deny all; } -} \ No newline at end of file + + access_log off; + error_log /dev/null crit; +}