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 diff --git a/.env.example b/.env.example old mode 100755 new mode 100644 index 2bffe56..93f2d35 --- a/.env.example +++ b/.env.example @@ -40,4 +40,4 @@ GOOGLE_CLOUD_KEY_FILE=config/googleCloudStorageKey.json GOOGLE_CLOUD_STORAGE_BUCKET= # 用于阻止重复安装 -INSTALLED=false \ No newline at end of file +INSTALLED=false diff --git a/Dockerfile b/Dockerfile index 3ce274a..f0102c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,8 @@ 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 -CMD /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf \ No newline at end of file +CMD ["/usr/bin/supervisord", "--nodaemon", "-c", "/etc/supervisor/supervisord.conf"] 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/Http/Controllers/V1/Guest/PaymentController.php b/app/Http/Controllers/V1/Guest/PaymentController.php index b7cf604..0f11867 100644 --- a/app/Http/Controllers/V1/Guest/PaymentController.php +++ b/app/Http/Controllers/V1/Guest/PaymentController.php @@ -57,7 +57,7 @@ class PaymentController extends Controller $payment->name, $order->trade_no ); - + $telegramService->sendMessageWithAdmin($message); return true; } 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..9c7e003 --- /dev/null +++ b/app/Payments/StripeALLInOne.php @@ -0,0 +1,210 @@ +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, cards', + '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', 500); + } + //jump url + $jumpUrl = null; + $actionType = 0; + $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; + } + + 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; + 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'); + } + 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/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'); + } +} diff --git a/app/Protocols/Surge.php b/app/Protocols/Surge.php index c89f2ef..12e2f26 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] diff --git a/composer.json b/composer.json index e83ffd7..8dad9fe 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": "*",