mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-03 18:40:52 +08:00
refactor: refactor subscription delivery logic, change payment return_url to origin_url concatenation
- Unify protocol filter configuration to client.type.field (dot-path, three-segment) format, support strict whitelist mode - Refactor AbstractProtocol and all protocol classes for more flexible and maintainable subscription delivery - Change payment callback logic: use origin_url concatenation instead of return_url for more accurate redirects
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
use App\Support\Setting;
|
use App\Support\Setting;
|
||||||
use Illuminate\Support\Facades\App;
|
use Illuminate\Support\Facades\App;
|
||||||
|
|
||||||
if (! function_exists('admin_setting')) {
|
if (!function_exists('admin_setting')) {
|
||||||
/**
|
/**
|
||||||
* 获取或保存配置参数.
|
* 获取或保存配置参数.
|
||||||
*
|
*
|
||||||
@@ -23,12 +23,12 @@ if (! function_exists('admin_setting')) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$default = config('v2board.'. $key) ?? $default;
|
$default = config('v2board.' . $key) ?? $default;
|
||||||
return $setting->get($key) ?? $default;
|
return $setting->get($key) ?? $default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! function_exists('admin_settings_batch')) {
|
if (!function_exists('admin_settings_batch')) {
|
||||||
/**
|
/**
|
||||||
* 批量获取配置参数,性能优化版本
|
* 批量获取配置参数,性能优化版本
|
||||||
*
|
*
|
||||||
@@ -40,3 +40,18 @@ if (! function_exists('admin_settings_batch')) {
|
|||||||
return app(Setting::class)->getBatch($keys);
|
return app(Setting::class)->getBatch($keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!function_exists('origin_url')) {
|
||||||
|
/**
|
||||||
|
* 根据 HTTP_ORIGIN 拼接完整 URL
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function origin_url(string $path = ''): string
|
||||||
|
{
|
||||||
|
$origin = request()->getSchemeAndHttpHost(); // 自动带端口
|
||||||
|
$origin = rtrim($origin, '/');
|
||||||
|
$path = ltrim($path, '/');
|
||||||
|
return $origin . '/' . $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Protocols;
|
namespace App\Protocols;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
@@ -12,6 +13,13 @@ class Clash extends AbstractProtocol
|
|||||||
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.clash.yaml';
|
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.clash.yaml';
|
||||||
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.clash.yaml';
|
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.clash.yaml';
|
||||||
|
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_SOCKS,
|
||||||
|
Server::TYPE_HTTP,
|
||||||
|
];
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$servers = $this->servers;
|
$servers = $this->servers;
|
||||||
@@ -30,7 +38,7 @@ class Clash extends AbstractProtocol
|
|||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$item['type'] === 'shadowsocks'
|
$item['type'] === Server::TYPE_SHADOWSOCKS
|
||||||
&& in_array(data_get($item['protocol_settings'], 'cipher'), [
|
&& in_array(data_get($item['protocol_settings'], 'cipher'), [
|
||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'aes-192-gcm',
|
'aes-192-gcm',
|
||||||
@@ -41,19 +49,19 @@ class Clash extends AbstractProtocol
|
|||||||
array_push($proxy, self::buildShadowsocks($item['password'], $item));
|
array_push($proxy, self::buildShadowsocks($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
array_push($proxy, self::buildVmess($item['password'], $item));
|
array_push($proxy, self::buildVmess($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
array_push($proxy, self::buildTrojan($item['password'], $item));
|
array_push($proxy, self::buildTrojan($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'socks') {
|
if ($item['type'] === Server::TYPE_SOCKS) {
|
||||||
array_push($proxy, self::buildSocks5($item['password'], $item));
|
array_push($proxy, self::buildSocks5($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'http') {
|
if ($item['type'] === Server::TYPE_HTTP) {
|
||||||
array_push($proxy, self::buildHttp($item['password'], $item));
|
array_push($proxy, self::buildHttp($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Protocols;
|
namespace App\Protocols;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
@@ -13,49 +14,48 @@ class ClashMeta extends AbstractProtocol
|
|||||||
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.clashmeta.yaml';
|
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.clashmeta.yaml';
|
||||||
const CUSTOM_CLASH_TEMPLATE_FILE = 'resources/rules/custom.clash.yaml';
|
const CUSTOM_CLASH_TEMPLATE_FILE = 'resources/rules/custom.clash.yaml';
|
||||||
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.clash.yaml';
|
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.clash.yaml';
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_VLESS,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
Server::TYPE_TUIC,
|
||||||
|
Server::TYPE_ANYTLS,
|
||||||
|
Server::TYPE_SOCKS,
|
||||||
|
Server::TYPE_HTTP,
|
||||||
|
Server::TYPE_MIERU,
|
||||||
|
];
|
||||||
|
|
||||||
protected $protocolRequirements = [
|
protected $protocolRequirements = [
|
||||||
'nekobox' => [
|
'*.vless.protocol_settings.network' => [
|
||||||
'hysteria' => [
|
'whitelist' => [
|
||||||
'protocol_settings.version' => [
|
'tcp' => '0.0.0',
|
||||||
'2' => '1.2.7'
|
'ws' => '0.0.0',
|
||||||
],
|
'grpc' => '0.0.0',
|
||||||
|
'http' => '0.0.0',
|
||||||
|
'h2' => '0.0.0',
|
||||||
],
|
],
|
||||||
|
'strict' => true,
|
||||||
],
|
],
|
||||||
'clashmetaforandroid' => [
|
'nekobox.hysteria.protocol_settings.version' => [
|
||||||
'hysteria' => [
|
1 => '0.0.0',
|
||||||
'protocol_settings.version' => [
|
2 => '1.2.7',
|
||||||
'2' => '2.9.0'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'nekoray' => [
|
'clashmetaforandroid.hysteria.protocol_settings.version' => [
|
||||||
'hysteria' => [
|
2 => '2.9.0',
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '3.24'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'verge' => [
|
'nekoray.hysteria.protocol_settings.version' => [
|
||||||
'hysteria' => [
|
2 => '3.24',
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '1.3.8'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'ClashX Meta' => [
|
'verge.hysteria.protocol_settings.version' => [
|
||||||
'hysteria' => [
|
2 => '1.3.8',
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '1.3.5'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'flclash' => [
|
'ClashX Meta.hysteria.protocol_settings.version' => [
|
||||||
'hysteria' => [
|
2 => '1.3.5',
|
||||||
'protocol_settings.version' => [
|
],
|
||||||
'2' => '0.8.0'
|
'flclash.hysteria.protocol_settings.version' => [
|
||||||
],
|
2 => '0.8.0',
|
||||||
],
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -78,47 +78,43 @@ class ClashMeta extends AbstractProtocol
|
|||||||
$proxies = [];
|
$proxies = [];
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
$protocol_settings = $item['protocol_settings'];
|
if ($item['type'] === Server::TYPE_SHADOWSOCKS) {
|
||||||
if ($item['type'] === 'shadowsocks') {
|
|
||||||
array_push($proxy, self::buildShadowsocks($item['password'], $item));
|
array_push($proxy, self::buildShadowsocks($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
array_push($proxy, self::buildVmess($item['password'], $item));
|
array_push($proxy, self::buildVmess($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
array_push($proxy, self::buildTrojan($item['password'], $item));
|
array_push($proxy, self::buildTrojan($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if (
|
if ($item['type'] === Server::TYPE_VLESS) {
|
||||||
$item['type'] === 'vless'
|
|
||||||
&& in_array(data_get($protocol_settings, 'network'), ['tcp', 'ws', 'grpc', 'http', 'h2'])
|
|
||||||
) {
|
|
||||||
array_push($proxy, self::buildVless($item['password'], $item));
|
array_push($proxy, self::buildVless($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === Server::TYPE_HYSTERIA) {
|
||||||
array_push($proxy, self::buildHysteria($item['password'], $item, $user));
|
array_push($proxy, self::buildHysteria($item['password'], $item, $user));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'tuic') {
|
if ($item['type'] === Server::TYPE_TUIC) {
|
||||||
array_push($proxy, self::buildTuic($item['password'], $item));
|
array_push($proxy, self::buildTuic($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'anytls') {
|
if ($item['type'] === Server::TYPE_ANYTLS) {
|
||||||
array_push($proxy, self::buildAnyTLS($item['password'], $item));
|
array_push($proxy, self::buildAnyTLS($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'socks') {
|
if ($item['type'] === Server::TYPE_SOCKS) {
|
||||||
array_push($proxy, self::buildSocks5($item['password'], $item));
|
array_push($proxy, self::buildSocks5($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'http') {
|
if ($item['type'] === Server::TYPE_HTTP) {
|
||||||
array_push($proxy, self::buildHttp($item['password'], $item));
|
array_push($proxy, self::buildHttp($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'mieru') {
|
if ($item['type'] === Server::TYPE_MIERU) {
|
||||||
array_push($proxy, self::buildMieru($item['password'], $item));
|
array_push($proxy, self::buildMieru($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Protocols;
|
namespace App\Protocols;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
@@ -10,21 +11,18 @@ class General extends AbstractProtocol
|
|||||||
{
|
{
|
||||||
public $flags = ['general', 'v2rayn', 'v2rayng', 'passwall', 'ssrplus', 'sagernet'];
|
public $flags = ['general', 'v2rayn', 'v2rayng', 'passwall', 'ssrplus', 'sagernet'];
|
||||||
|
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_VLESS,
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
Server::TYPE_SOCKS,
|
||||||
|
];
|
||||||
|
|
||||||
protected $protocolRequirements = [
|
protected $protocolRequirements = [
|
||||||
'v2rayng' => [
|
'v2rayng.hysteria.protocol_settings.version' => [2 => '1.9.5'],
|
||||||
'hysteria' => [
|
'v2rayn.hysteria.protocol_settings.version' => [2 => '6.31'],
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '1.9.5'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'v2rayN' => [
|
|
||||||
'hysteria' => [
|
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '6.31'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
@@ -34,24 +32,15 @@ class General extends AbstractProtocol
|
|||||||
$uri = '';
|
$uri = '';
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if ($item['type'] === 'vmess') {
|
$uri .= match ($item['type']) {
|
||||||
$uri .= self::buildVmess($item['password'], $item);
|
Server::TYPE_VMESS => self::buildVmess($item['password'], $item),
|
||||||
}
|
Server::TYPE_VLESS => self::buildVless($item['password'], $item),
|
||||||
if ($item['type'] === 'vless') {
|
Server::TYPE_SHADOWSOCKS => self::buildShadowsocks($item['password'], $item),
|
||||||
$uri .= self::buildVless($item['password'], $item);
|
Server::TYPE_TROJAN => self::buildTrojan($item['password'], $item),
|
||||||
}
|
Server::TYPE_HYSTERIA => self::buildHysteria($item['password'], $item),
|
||||||
if ($item['type'] === 'shadowsocks') {
|
Server::TYPE_SOCKS => self::buildSocks($item['password'], $item),
|
||||||
$uri .= self::buildShadowsocks($item['password'], $item);
|
default => '',
|
||||||
}
|
};
|
||||||
if ($item['type'] === 'trojan') {
|
|
||||||
$uri .= self::buildTrojan($item['password'], $item);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'hysteria') {
|
|
||||||
$uri .= self::buildHysteria($item['password'], $item);
|
|
||||||
}
|
|
||||||
if ($item['type'] === 'socks') {
|
|
||||||
$uri .= self::buildSocks($item['password'], $item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return response(base64_encode($uri))->header('content-type', 'text/plain');
|
return response(base64_encode($uri))->header('content-type', 'text/plain');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,21 @@
|
|||||||
namespace App\Protocols;
|
namespace App\Protocols;
|
||||||
|
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class Loon extends AbstractProtocol
|
class Loon extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['loon'];
|
public $flags = ['loon'];
|
||||||
|
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
];
|
||||||
|
|
||||||
protected $protocolRequirements = [
|
protected $protocolRequirements = [
|
||||||
'loon' => [
|
'loon.hysteria.protocol_settings.version' => [2 => '637'],
|
||||||
'hysteria' => [
|
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '637'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
@@ -27,17 +29,17 @@ class Loon extends AbstractProtocol
|
|||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if (
|
if (
|
||||||
$item['type'] === 'shadowsocks'
|
$item['type'] === Server::TYPE_SHADOWSOCKS
|
||||||
) {
|
) {
|
||||||
$uri .= self::buildShadowsocks($item['password'], $item);
|
$uri .= self::buildShadowsocks($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
$uri .= self::buildVmess($item['password'], $item);
|
$uri .= self::buildVmess($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
$uri .= self::buildTrojan($item['password'], $item);
|
$uri .= self::buildTrojan($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === Server::TYPE_HYSTERIA) {
|
||||||
$uri .= self::buildHysteria($item['password'], $item, $user);
|
$uri .= self::buildHysteria($item['password'], $item, $user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,16 @@
|
|||||||
namespace App\Protocols;
|
namespace App\Protocols;
|
||||||
|
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class QuantumultX extends AbstractProtocol
|
class QuantumultX extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['quantumult%20x', 'quantumult-x'];
|
public $flags = ['quantumult%20x', 'quantumult-x'];
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
];
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
@@ -14,13 +20,13 @@ class QuantumultX extends AbstractProtocol
|
|||||||
$user = $this->user;
|
$user = $this->user;
|
||||||
$uri = '';
|
$uri = '';
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if ($item['type'] === 'shadowsocks') {
|
if ($item['type'] === Server::TYPE_SHADOWSOCKS) {
|
||||||
$uri .= self::buildShadowsocks($item['password'], $item);
|
$uri .= self::buildShadowsocks($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
$uri .= self::buildVmess($item['password'], $item);
|
$uri .= self::buildVmess($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
$uri .= self::buildTrojan($item['password'], $item);
|
$uri .= self::buildTrojan($item['password'], $item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,25 @@ namespace App\Protocols;
|
|||||||
|
|
||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class Shadowrocket extends AbstractProtocol
|
class Shadowrocket extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['shadowrocket'];
|
public $flags = ['shadowrocket'];
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_VLESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
Server::TYPE_TUIC,
|
||||||
|
Server::TYPE_ANYTLS,
|
||||||
|
Server::TYPE_SOCKS,
|
||||||
|
];
|
||||||
|
|
||||||
protected $protocolRequirements = [
|
protected $protocolRequirements = [
|
||||||
'shadowrocket' => [
|
'shadowrocket.hysteria.protocol_settings.version' => [2 => '1993'],
|
||||||
'hysteria' => [
|
'shadowrocket.anytls.base_version' => '2592',
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '1993'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'anytls' => [
|
|
||||||
'base_version' => '2592'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
@@ -35,28 +38,28 @@ class Shadowrocket extends AbstractProtocol
|
|||||||
$expiredDate = date('Y-m-d', $user['expired_at']);
|
$expiredDate = date('Y-m-d', $user['expired_at']);
|
||||||
$uri .= "STATUS=🚀↑:{$upload}GB,↓:{$download}GB,TOT:{$totalTraffic}GB💡Expires:{$expiredDate}\r\n";
|
$uri .= "STATUS=🚀↑:{$upload}GB,↓:{$download}GB,TOT:{$totalTraffic}GB💡Expires:{$expiredDate}\r\n";
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if ($item['type'] === 'shadowsocks') {
|
if ($item['type'] === Server::TYPE_SHADOWSOCKS) {
|
||||||
$uri .= self::buildShadowsocks($item['password'], $item);
|
$uri .= self::buildShadowsocks($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
$uri .= self::buildVmess($item['password'], $item);
|
$uri .= self::buildVmess($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vless') {
|
if ($item['type'] === Server::TYPE_VLESS) {
|
||||||
$uri .= self::buildVless($item['password'], $item);
|
$uri .= self::buildVless($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
$uri .= self::buildTrojan($item['password'], $item);
|
$uri .= self::buildTrojan($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === Server::TYPE_HYSTERIA) {
|
||||||
$uri .= self::buildHysteria($item['password'], $item);
|
$uri .= self::buildHysteria($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'tuic') {
|
if ($item['type'] === Server::TYPE_TUIC) {
|
||||||
$uri .= self::buildTuic($item['password'], $item);
|
$uri .= self::buildTuic($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'anytls') {
|
if ($item['type'] === Server::TYPE_ANYTLS) {
|
||||||
$uri .= self::buildAnyTLS($item['password'], $item);
|
$uri .= self::buildAnyTLS($item['password'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'socks') {
|
if ($item['type'] === Server::TYPE_SOCKS) {
|
||||||
$uri .= self::buildSocks($item['password'], $item);
|
$uri .= self::buildSocks($item['password'], $item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,16 @@
|
|||||||
namespace App\Protocols;
|
namespace App\Protocols;
|
||||||
|
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class Shadowsocks extends AbstractProtocol
|
class Shadowsocks extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['shadowsocks'];
|
public $flags = ['shadowsocks'];
|
||||||
|
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
];
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$servers = $this->servers;
|
$servers = $this->servers;
|
||||||
|
|||||||
@@ -4,12 +4,23 @@ namespace App\Protocols;
|
|||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class SingBox extends AbstractProtocol
|
class SingBox extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['sing-box', 'hiddify', 'sfm'];
|
public $flags = ['sing-box', 'hiddify', 'sfm'];
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_VLESS,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
Server::TYPE_TUIC,
|
||||||
|
Server::TYPE_ANYTLS,
|
||||||
|
Server::TYPE_SOCKS,
|
||||||
|
Server::TYPE_HTTP,
|
||||||
|
];
|
||||||
private $config;
|
private $config;
|
||||||
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.sing-box.json';
|
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.sing-box.json';
|
||||||
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.sing-box.json';
|
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.sing-box.json';
|
||||||
@@ -85,42 +96,42 @@ class SingBox extends AbstractProtocol
|
|||||||
$proxies = [];
|
$proxies = [];
|
||||||
foreach ($this->servers as $item) {
|
foreach ($this->servers as $item) {
|
||||||
$protocol_settings = $item['protocol_settings'];
|
$protocol_settings = $item['protocol_settings'];
|
||||||
if ($item['type'] === 'shadowsocks') {
|
if ($item['type'] === Server::TYPE_SHADOWSOCKS) {
|
||||||
$ssConfig = $this->buildShadowsocks($item['password'], $item);
|
$ssConfig = $this->buildShadowsocks($item['password'], $item);
|
||||||
$proxies[] = $ssConfig;
|
$proxies[] = $ssConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
$trojanConfig = $this->buildTrojan($this->user['uuid'], $item);
|
$trojanConfig = $this->buildTrojan($this->user['uuid'], $item);
|
||||||
$proxies[] = $trojanConfig;
|
$proxies[] = $trojanConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
$vmessConfig = $this->buildVmess($this->user['uuid'], $item);
|
$vmessConfig = $this->buildVmess($this->user['uuid'], $item);
|
||||||
$proxies[] = $vmessConfig;
|
$proxies[] = $vmessConfig;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
$item['type'] === 'vless'
|
$item['type'] === Server::TYPE_VLESS
|
||||||
&& in_array(data_get($protocol_settings, 'network'), ['tcp', 'ws', 'grpc', 'http', 'quic', 'httpupgrade'])
|
&& in_array(data_get($protocol_settings, 'network'), ['tcp', 'ws', 'grpc', 'http', 'quic', 'httpupgrade'])
|
||||||
) {
|
) {
|
||||||
$vlessConfig = $this->buildVless($this->user['uuid'], $item);
|
$vlessConfig = $this->buildVless($this->user['uuid'], $item);
|
||||||
$proxies[] = $vlessConfig;
|
$proxies[] = $vlessConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === Server::TYPE_HYSTERIA) {
|
||||||
$hysteriaConfig = $this->buildHysteria($this->user['uuid'], $item);
|
$hysteriaConfig = $this->buildHysteria($this->user['uuid'], $item);
|
||||||
$proxies[] = $hysteriaConfig;
|
$proxies[] = $hysteriaConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'tuic') {
|
if ($item['type'] === Server::TYPE_TUIC) {
|
||||||
$tuicConfig = $this->buildTuic($this->user['uuid'], $item);
|
$tuicConfig = $this->buildTuic($this->user['uuid'], $item);
|
||||||
$proxies[] = $tuicConfig;
|
$proxies[] = $tuicConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'anytls') {
|
if ($item['type'] === Server::TYPE_ANYTLS) {
|
||||||
$anytlsConfig = $this->buildAnyTLS($this->user['uuid'], $item);
|
$anytlsConfig = $this->buildAnyTLS($this->user['uuid'], $item);
|
||||||
$proxies[] = $anytlsConfig;
|
$proxies[] = $anytlsConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'socks') {
|
if ($item['type'] === Server::TYPE_SOCKS) {
|
||||||
$socksConfig = $this->buildSocks($this->user['uuid'], $item);
|
$socksConfig = $this->buildSocks($this->user['uuid'], $item);
|
||||||
$proxies[] = $socksConfig;
|
$proxies[] = $socksConfig;
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'http') {
|
if ($item['type'] === Server::TYPE_HTTP) {
|
||||||
$httpConfig = $this->buildHttp($this->user['uuid'], $item);
|
$httpConfig = $this->buildHttp($this->user['uuid'], $item);
|
||||||
$proxies[] = $httpConfig;
|
$proxies[] = $httpConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,22 @@ use Symfony\Component\Yaml\Yaml;
|
|||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class Stash extends AbstractProtocol
|
class Stash extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['stash'];
|
public $flags = ['stash'];
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_VLESS,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_TUIC,
|
||||||
|
// Server::TYPE_ANYTLS,
|
||||||
|
Server::TYPE_SOCKS,
|
||||||
|
Server::TYPE_HTTP,
|
||||||
|
];
|
||||||
protected $protocolRequirements = [
|
protected $protocolRequirements = [
|
||||||
'stash' => [
|
'stash' => [
|
||||||
'anytls' => [
|
'anytls' => [
|
||||||
@@ -80,27 +92,27 @@ class Stash extends AbstractProtocol
|
|||||||
$proxies = [];
|
$proxies = [];
|
||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if ($item['type'] === 'shadowsocks') {
|
if ($item['type'] === Server::TYPE_SHADOWSOCKS) {
|
||||||
array_push($proxy, self::buildShadowsocks($item['password'], $item));
|
array_push($proxy, self::buildShadowsocks($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
array_push($proxy, self::buildVmess($item['password'], $item));
|
array_push($proxy, self::buildVmess($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vless') {
|
if ($item['type'] === Server::TYPE_VLESS) {
|
||||||
array_push($proxy, $this->buildVless($item['password'], $item));
|
array_push($proxy, $this->buildVless($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === Server::TYPE_HYSTERIA) {
|
||||||
array_push($proxy, self::buildHysteria($item['password'], $item));
|
array_push($proxy, self::buildHysteria($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
array_push($proxy, self::buildTrojan($item['password'], $item));
|
array_push($proxy, self::buildTrojan($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'tuic') {
|
if ($item['type'] === Server::TYPE_TUIC) {
|
||||||
array_push($proxy, self::buildTuic($item['password'], $item));
|
array_push($proxy, self::buildTuic($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
@@ -108,11 +120,11 @@ class Stash extends AbstractProtocol
|
|||||||
// array_push($proxy, self::buildAnyTLS($item['password'], $item));
|
// array_push($proxy, self::buildAnyTLS($item['password'], $item));
|
||||||
// array_push($proxies, $item['name']);
|
// array_push($proxies, $item['name']);
|
||||||
// }
|
// }
|
||||||
if ($item['type'] === 'socks') {
|
if ($item['type'] === Server::TYPE_SOCKS) {
|
||||||
array_push($proxy, self::buildSocks5($item['password'], $item));
|
array_push($proxy, self::buildSocks5($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'http') {
|
if ($item['type'] === Server::TYPE_HTTP) {
|
||||||
array_push($proxy, self::buildHttp($item['password'], $item));
|
array_push($proxy, self::buildHttp($item['password'], $item));
|
||||||
array_push($proxies, $item['name']);
|
array_push($proxies, $item['name']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,16 @@ namespace App\Protocols;
|
|||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class Surfboard extends AbstractProtocol
|
class Surfboard extends AbstractProtocol
|
||||||
{
|
{
|
||||||
public $flags = ['surfboard'];
|
public $flags = ['surfboard'];
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
];
|
||||||
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.surfboard.conf';
|
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.surfboard.conf';
|
||||||
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.surfboard.conf';
|
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.surfboard.conf';
|
||||||
|
|
||||||
@@ -25,7 +31,7 @@ class Surfboard extends AbstractProtocol
|
|||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if (
|
if (
|
||||||
$item['type'] === 'shadowsocks'
|
$item['type'] === Server::TYPE_SHADOWSOCKS
|
||||||
&& in_array(data_get($item, 'protocol_settings.cipher'), [
|
&& in_array(data_get($item, 'protocol_settings.cipher'), [
|
||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'aes-192-gcm',
|
'aes-192-gcm',
|
||||||
@@ -38,13 +44,13 @@ class Surfboard extends AbstractProtocol
|
|||||||
// [Proxy Group]
|
// [Proxy Group]
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
// [Proxy]
|
// [Proxy]
|
||||||
$proxies .= self::buildVmess($item['password'], $item);
|
$proxies .= self::buildVmess($item['password'], $item);
|
||||||
// [Proxy Group]
|
// [Proxy Group]
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
// [Proxy]
|
// [Proxy]
|
||||||
$proxies .= self::buildTrojan($item['password'], $item);
|
$proxies .= self::buildTrojan($item['password'], $item);
|
||||||
// [Proxy Group]
|
// [Proxy Group]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Protocols;
|
|||||||
use App\Utils\Helper;
|
use App\Utils\Helper;
|
||||||
use Illuminate\Support\Facades\File;
|
use Illuminate\Support\Facades\File;
|
||||||
use App\Support\AbstractProtocol;
|
use App\Support\AbstractProtocol;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
class Surge extends AbstractProtocol
|
class Surge extends AbstractProtocol
|
||||||
{
|
{
|
||||||
@@ -12,14 +13,14 @@ class Surge extends AbstractProtocol
|
|||||||
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.surge.conf';
|
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.surge.conf';
|
||||||
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.surge.conf';
|
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.surge.conf';
|
||||||
|
|
||||||
|
public $allowedProtocols = [
|
||||||
|
Server::TYPE_SHADOWSOCKS,
|
||||||
|
Server::TYPE_VMESS,
|
||||||
|
Server::TYPE_TROJAN,
|
||||||
|
Server::TYPE_HYSTERIA,
|
||||||
|
];
|
||||||
protected $protocolRequirements = [
|
protected $protocolRequirements = [
|
||||||
'surge' => [
|
'surge.hysteria.protocol_settings.version' => [2 => '2398'],
|
||||||
'hysteria' => [
|
|
||||||
'protocol_settings.version' => [
|
|
||||||
'2' => '2398'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
@@ -34,7 +35,7 @@ class Surge extends AbstractProtocol
|
|||||||
|
|
||||||
foreach ($servers as $item) {
|
foreach ($servers as $item) {
|
||||||
if (
|
if (
|
||||||
$item['type'] === 'shadowsocks'
|
$item['type'] === Server::TYPE_SHADOWSOCKS
|
||||||
&& in_array(data_get($item, 'protocol_settings.cipher'), [
|
&& in_array(data_get($item, 'protocol_settings.cipher'), [
|
||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'aes-192-gcm',
|
'aes-192-gcm',
|
||||||
@@ -45,15 +46,15 @@ class Surge extends AbstractProtocol
|
|||||||
$proxies .= self::buildShadowsocks($item['password'], $item);
|
$proxies .= self::buildShadowsocks($item['password'], $item);
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'vmess') {
|
if ($item['type'] === Server::TYPE_VMESS) {
|
||||||
$proxies .= self::buildVmess($item['password'], $item);
|
$proxies .= self::buildVmess($item['password'], $item);
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === Server::TYPE_TROJAN) {
|
||||||
$proxies .= self::buildTrojan($item['password'], $item);
|
$proxies .= self::buildTrojan($item['password'], $item);
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === Server::TYPE_HYSTERIA) {
|
||||||
$proxies .= self::buildHysteria($item['password'], $item);
|
$proxies .= self::buildHysteria($item['password'], $item);
|
||||||
$proxyGroup .= $item['name'] . ', ';
|
$proxyGroup .= $item['name'] . ', ';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,12 @@ class PaymentService
|
|||||||
{
|
{
|
||||||
$this->method = $method;
|
$this->method = $method;
|
||||||
$this->class = '\\App\\Payments\\' . $this->method;
|
$this->class = '\\App\\Payments\\' . $this->method;
|
||||||
if (!class_exists($this->class)) throw new ApiException('gate is not found');
|
if (!class_exists($this->class))
|
||||||
if ($id) $payment = Payment::find($id)->toArray();
|
throw new ApiException('gate is not found');
|
||||||
if ($uuid) $payment = Payment::where('uuid', $uuid)->first()->toArray();
|
if ($id)
|
||||||
|
$payment = Payment::find($id)->toArray();
|
||||||
|
if ($uuid)
|
||||||
|
$payment = Payment::where('uuid', $uuid)->first()->toArray();
|
||||||
$this->config = [];
|
$this->config = [];
|
||||||
if (isset($payment)) {
|
if (isset($payment)) {
|
||||||
$this->config = $payment['config'];
|
$this->config = $payment['config'];
|
||||||
@@ -27,13 +30,15 @@ class PaymentService
|
|||||||
$this->config['id'] = $payment['id'];
|
$this->config['id'] = $payment['id'];
|
||||||
$this->config['uuid'] = $payment['uuid'];
|
$this->config['uuid'] = $payment['uuid'];
|
||||||
$this->config['notify_domain'] = $payment['notify_domain'];
|
$this->config['notify_domain'] = $payment['notify_domain'];
|
||||||
};
|
}
|
||||||
|
;
|
||||||
$this->payment = new $this->class($this->config);
|
$this->payment = new $this->class($this->config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notify($params)
|
public function notify($params)
|
||||||
{
|
{
|
||||||
if (!$this->config['enable']) throw new ApiException('gate is not enable');
|
if (!$this->config['enable'])
|
||||||
|
throw new ApiException('gate is not enable');
|
||||||
return $this->payment->notify($params);
|
return $this->payment->notify($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +53,7 @@ class PaymentService
|
|||||||
|
|
||||||
return $this->payment->pay([
|
return $this->payment->pay([
|
||||||
'notify_url' => $notifyUrl,
|
'notify_url' => $notifyUrl,
|
||||||
'return_url' => url('/#/order/' . $order['trade_no']),
|
'return_url' => origin_url('/#/order/' . $order['trade_no']),
|
||||||
'trade_no' => $order['trade_no'],
|
'trade_no' => $order['trade_no'],
|
||||||
'total_amount' => $order['total_amount'],
|
'total_amount' => $order['total_amount'],
|
||||||
'user_id' => $order['user_id'],
|
'user_id' => $order['user_id'],
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ abstract class AbstractProtocol
|
|||||||
*/
|
*/
|
||||||
protected $protocolRequirements = [];
|
protected $protocolRequirements = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array 允许的协议类型(白名单) 为空则不进行过滤
|
||||||
|
*/
|
||||||
|
protected $allowedProtocols = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
*
|
*
|
||||||
@@ -50,6 +55,7 @@ abstract class AbstractProtocol
|
|||||||
$this->servers = $servers;
|
$this->servers = $servers;
|
||||||
$this->clientName = $clientName;
|
$this->clientName = $clientName;
|
||||||
$this->clientVersion = $clientVersion;
|
$this->clientVersion = $clientVersion;
|
||||||
|
$this->protocolRequirements = $this->normalizeProtocolRequirements($this->protocolRequirements);
|
||||||
$this->servers = HookManager::filter('protocol.servers.filtered', $this->filterServersByVersion());
|
$this->servers = HookManager::filter('protocol.servers.filtered', $this->filterServersByVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,19 +83,22 @@ abstract class AbstractProtocol
|
|||||||
*/
|
*/
|
||||||
protected function filterServersByVersion()
|
protected function filterServersByVersion()
|
||||||
{
|
{
|
||||||
// 如果没有客户端信息,直接返回所有服务器
|
$this->filterByAllowedProtocols();
|
||||||
if (empty($this->clientName) || empty($this->clientVersion)) {
|
$hasGlobalConfig = isset($this->protocolRequirements['*']);
|
||||||
|
$hasClientConfig = isset($this->protocolRequirements[$this->clientName]);
|
||||||
|
|
||||||
|
if ((blank($this->clientName) || blank($this->clientVersion)) && !$hasGlobalConfig) {
|
||||||
return $this->servers;
|
return $this->servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查当前客户端是否有特殊配置
|
if (!$hasGlobalConfig && !$hasClientConfig) {
|
||||||
if (!isset($this->protocolRequirements[$this->clientName])) {
|
|
||||||
return $this->servers;
|
return $this->servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
return collect($this->servers)->filter(function ($server) {
|
return collect($this->servers)
|
||||||
return $this->isCompatible($server);
|
->filter(fn($server) => $this->isCompatible($server))
|
||||||
})->values()->all();
|
->values()
|
||||||
|
->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,30 +110,73 @@ abstract class AbstractProtocol
|
|||||||
protected function isCompatible($server)
|
protected function isCompatible($server)
|
||||||
{
|
{
|
||||||
$serverType = $server['type'] ?? null;
|
$serverType = $server['type'] ?? null;
|
||||||
// 如果该协议没有特定要求,则认为兼容
|
if (isset($this->protocolRequirements['*'][$serverType])) {
|
||||||
|
$globalRequirements = $this->protocolRequirements['*'][$serverType];
|
||||||
|
if (!$this->checkRequirements($globalRequirements, $server)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isset($this->protocolRequirements[$this->clientName][$serverType])) {
|
if (!isset($this->protocolRequirements[$this->clientName][$serverType])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$requirements = $this->protocolRequirements[$this->clientName][$serverType];
|
$requirements = $this->protocolRequirements[$this->clientName][$serverType];
|
||||||
|
return $this->checkRequirements($requirements, $server);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($requirements['base_version']) && version_compare($this->clientVersion, $requirements['base_version'], '<')) {
|
/**
|
||||||
return false;
|
* 检查版本要求
|
||||||
}
|
*
|
||||||
|
* @param array $requirements 要求配置
|
||||||
|
* @param array $server 服务器信息
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function checkRequirements(array $requirements, array $server): bool
|
||||||
|
{
|
||||||
|
foreach ($requirements as $field => $filterRule) {
|
||||||
|
if (in_array($field, ['base_version', 'incompatible'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 检查每个路径的版本要求
|
$actualValue = data_get($server, $field);
|
||||||
foreach ($requirements as $path => $valueRequirements) {
|
|
||||||
$actualValue = data_get($server, $path);
|
if (is_array($filterRule) && isset($filterRule['whitelist'])) {
|
||||||
|
$allowedValues = $filterRule['whitelist'];
|
||||||
|
$strict = $filterRule['strict'] ?? false;
|
||||||
|
if ($strict) {
|
||||||
|
if ($actualValue === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!is_string($actualValue) && !is_int($actualValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isset($allowedValues[$actualValue])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$requiredVersion = $allowedValues[$actualValue];
|
||||||
|
if ($requiredVersion !== '0.0.0' && version_compare($this->clientVersion, $requiredVersion, '<')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$allowedValues = $filterRule;
|
||||||
|
$strict = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ($actualValue === null) {
|
if ($actualValue === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!is_string($actualValue) && !is_int($actualValue)) {
|
||||||
if (isset($valueRequirements[$actualValue])) {
|
continue;
|
||||||
$requiredVersion = $valueRequirements[$actualValue];
|
}
|
||||||
if (version_compare($this->clientVersion, $requiredVersion, '<')) {
|
if (!isset($allowedValues[$actualValue])) {
|
||||||
return false;
|
continue;
|
||||||
}
|
}
|
||||||
|
$requiredVersion = $allowedValues[$actualValue];
|
||||||
|
if ($requiredVersion !== '0.0.0' && version_compare($this->clientVersion, $requiredVersion, '<')) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,4 +212,44 @@ abstract class AbstractProtocol
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据白名单过滤服务器
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function filterByAllowedProtocols(): void
|
||||||
|
{
|
||||||
|
if (!empty($this->allowedProtocols)) {
|
||||||
|
$this->servers = collect($this->servers)
|
||||||
|
->filter(fn($server) => in_array($server['type'], $this->allowedProtocols))
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将平铺的协议需求转换为树形结构
|
||||||
|
*
|
||||||
|
* @param array $flat 平铺的协议需求
|
||||||
|
* @return array 树形结构的协议需求
|
||||||
|
*/
|
||||||
|
protected function normalizeProtocolRequirements(array $flat): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach ($flat as $key => $value) {
|
||||||
|
if (!str_contains($key, '.')) {
|
||||||
|
$result[$key] = $value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$segments = explode('.', $key, 3);
|
||||||
|
if (count($segments) < 3) {
|
||||||
|
$result[$segments[0]][$segments[1] ?? '*'][''] = $value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
[$client, $type, $field] = $segments;
|
||||||
|
$result[$client][$type][$field] = $value;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user