mirror of
https://github.com/cedar2025/Xboard.git
synced 2025-01-23 02:58:14 -05:00
Compare commits
1 Commits
b57b6f4ea6
...
6f971901a0
Author | SHA1 | Date | |
---|---|---|---|
|
6f971901a0 |
@ -17,7 +17,6 @@ directory=/www
|
|||||||
command=sh -c "chown -R www:www /www && chmod -R 775 /www"
|
command=sh -c "chown -R www:www /www && chmod -R 775 /www"
|
||||||
autostart=true
|
autostart=true
|
||||||
autorestart=false
|
autorestart=false
|
||||||
priority=1
|
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
@ -26,7 +25,6 @@ stderr_logfile_maxbytes=0
|
|||||||
[program:nginx]
|
[program:nginx]
|
||||||
command=nginx -g 'daemon off;'
|
command=nginx -g 'daemon off;'
|
||||||
user=root
|
user=root
|
||||||
priority=5
|
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
@ -38,7 +36,6 @@ startretries=10
|
|||||||
[program:cron]
|
[program:cron]
|
||||||
command=crond -f -l 8
|
command=crond -f -l 8
|
||||||
user=root
|
user=root
|
||||||
priority=4
|
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
@ -65,8 +62,6 @@ command=php -c php.ini webman.php start
|
|||||||
directory=/www
|
directory=/www
|
||||||
user=www
|
user=www
|
||||||
numprocs=1
|
numprocs=1
|
||||||
priority=2
|
|
||||||
startsecs=3
|
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
@ -79,7 +74,6 @@ startretries=10
|
|||||||
command=php artisan horizon
|
command=php artisan horizon
|
||||||
directory=/www
|
directory=/www
|
||||||
user=www
|
user=www
|
||||||
priority=3
|
|
||||||
stdout_logfile=/www/storage/logs/queue.log
|
stdout_logfile=/www/storage/logs/queue.log
|
||||||
stdout_logfile_maxbytes=0
|
stdout_logfile_maxbytes=0
|
||||||
stderr_logfile=/www/storage/logs/queue_error.log
|
stderr_logfile=/www/storage/logs/queue_error.log
|
||||||
|
0
.env.example
Normal file → Executable file
0
.env.example
Normal file → Executable file
@ -11,8 +11,7 @@ COPY .docker /
|
|||||||
COPY . /www
|
COPY . /www
|
||||||
RUN composer install --optimize-autoloader --no-cache --no-dev \
|
RUN composer install --optimize-autoloader --no-cache --no-dev \
|
||||||
&& php artisan storage:link \
|
&& php artisan storage:link \
|
||||||
&& cp /www/.env.example /www/.env \
|
|
||||||
&& chown -R www:www /www \
|
&& chown -R www:www /www \
|
||||||
&& chmod -R 775 /www
|
&& chmod -R 775 /www
|
||||||
|
|
||||||
CMD ["/usr/bin/supervisord", "--nodaemon", "-c", "/etc/supervisor/supervisord.conf"]
|
CMD /usr/bin/supervisord --nodaemon -c /etc/supervisor/supervisord.conf
|
@ -26,10 +26,9 @@ 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{
|
try{
|
||||||
if (config('database.default') === 'mysql'){
|
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");
|
$this->info("1️⃣:开始备份Mysql");
|
||||||
\Spatie\DbDumper\Databases\MySql::create()
|
\Spatie\DbDumper\Databases\MySql::create()
|
||||||
->setHost(config('database.connections.mysql.host'))
|
->setHost(config('database.connections.mysql.host'))
|
||||||
|
@ -76,13 +76,14 @@ class BTCPay
|
|||||||
//NOT BTCPay-Sig
|
//NOT BTCPay-Sig
|
||||||
//API doc is WRONG!
|
//API doc is WRONG!
|
||||||
$headerName = 'Btcpay-Sig';
|
$headerName = 'Btcpay-Sig';
|
||||||
$signatureHeader = isset($headers[$headerName]) ? $headers[$headerName] : '';
|
$signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : '';
|
||||||
$json_param = json_decode($payload, true);
|
$json_param = json_decode($payload, true);
|
||||||
|
|
||||||
$computedSignature = "sha256=" . \hash_hmac('sha256', $payload, $this->config['btcpay_webhook_key']);
|
$computedSignature = "sha256=" . \hash_hmac('sha256', $payload, $this->config['btcpay_webhook_key']);
|
||||||
|
|
||||||
if (!self::hashEqual($signatureHeader, $computedSignature)) {
|
if (!self::hashEqual($signraturHeader, $computedSignature)) {
|
||||||
throw new ApiException('HMAC signature does not match', 400);
|
throw new ApiException('HMAC signature does not match', 400);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get order id store in metadata
|
//get order id store in metadata
|
||||||
|
@ -1,210 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自己写别抄,抄NMB抄
|
|
||||||
*/
|
|
||||||
namespace App\Payments;
|
|
||||||
use App\Exceptions\ApiException;
|
|
||||||
|
|
||||||
class StripeALLInOne {
|
|
||||||
public function __construct($config)
|
|
||||||
{
|
|
||||||
$this->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];
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ use App\Plugins\Telegram\Telegram;
|
|||||||
|
|
||||||
class GetLatestUrl extends Telegram {
|
class GetLatestUrl extends Telegram {
|
||||||
public $command = '/getlatesturl';
|
public $command = '/getlatesturl';
|
||||||
public $description = '获取网站最新网址';
|
public $description = '将Telegram账号绑定到网站';
|
||||||
|
|
||||||
public function handle($message, $match = []) {
|
public function handle($message, $match = []) {
|
||||||
$telegramService = $this->telegramService;
|
$telegramService = $this->telegramService;
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Plugins\Telegram\Commands;
|
|
||||||
|
|
||||||
use App\Plugins\Telegram\Telegram;
|
|
||||||
|
|
||||||
class Start extends Telegram {
|
|
||||||
public $command = '/start';
|
|
||||||
public $description = 'telegram机器人初始化';
|
|
||||||
|
|
||||||
public function handle($message, $match = []) {
|
|
||||||
if (!$message->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');
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,9 +32,7 @@ class Surge
|
|||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'aes-192-gcm',
|
'aes-192-gcm',
|
||||||
'aes-256-gcm',
|
'aes-256-gcm',
|
||||||
'chacha20-ietf-poly1305',
|
'chacha20-ietf-poly1305'
|
||||||
'2022-blake3-aes-128-gcm',
|
|
||||||
'2022-blake3-aes-256-gcm',
|
|
||||||
])
|
])
|
||||||
) {
|
) {
|
||||||
// [Proxy]
|
// [Proxy]
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
"paragonie/sodium_compat": "^1.20",
|
"paragonie/sodium_compat": "^1.20",
|
||||||
"php-curl-class/php-curl-class": "^8.6",
|
"php-curl-class/php-curl-class": "^8.6",
|
||||||
"spatie/db-dumper": "^3.4",
|
"spatie/db-dumper": "^3.4",
|
||||||
"stripe/stripe-php": "^v14.9.0",
|
"stripe/stripe-php": "^7.36.1",
|
||||||
"symfony/http-client": "^6.4",
|
"symfony/http-client": "^6.4",
|
||||||
"symfony/mailgun-mailer": "^6.4",
|
"symfony/mailgun-mailer": "^6.4",
|
||||||
"symfony/yaml": "*",
|
"symfony/yaml": "*",
|
||||||
|
@ -83,8 +83,7 @@
|
|||||||
3. 在站点目录中执行以下命令从 Github 克隆到当前目录:
|
3. 在站点目录中执行以下命令从 Github 克隆到当前目录:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/cedar2025/Xboard ./
|
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard ./
|
||||||
cp docker-compose.sample.yaml docker-compose.yaml
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4. 执行以下命令安装 Xboard:
|
4. 执行以下命令安装 Xboard:
|
||||||
|
Loading…
Reference in New Issue
Block a user