feat: add AnyTLS support and improve system functionality

- Add AnyTLS protocol support
- Add system logs viewing in admin panel
- Refactor client subscription delivery code
- Refactor hook mechanism
- Add plugin support for Shadowsocks protocol
- Add CSV export option for batch user creation
- Fix mobile admin login page width display issue
This commit is contained in:
xboard
2025-05-22 17:58:22 +08:00
parent 2580475f78
commit fc5a957ddd
35 changed files with 1586 additions and 640 deletions
+93 -29
View File
@@ -2,36 +2,62 @@
namespace App\Protocols;
use App\Contracts\ProtocolInterface;
use App\Models\ServerHysteria;
use App\Utils\Helper;
use Illuminate\Support\Facades\File;
use Symfony\Component\Yaml\Yaml;
use App\Support\AbstractProtocol;
class ClashMeta implements ProtocolInterface
class ClashMeta extends AbstractProtocol
{
public $flags = ['meta', 'verge', 'flclash'];
private $servers;
private $user;
public $flags = ['meta', 'verge', 'flclash', 'nekobox', 'clashmetaforandroid'];
const CUSTOM_TEMPLATE_FILE = 'resources/rules/custom.clashmeta.yaml';
const CUSTOM_CLASH_TEMPLATE_FILE = 'resources/rules/custom.clash.yaml';
const DEFAULT_TEMPLATE_FILE = 'resources/rules/default.clash.yaml';
/**
* @param mixed $user 用户实例
* @param array $servers 服务器列表
*/
public function __construct($user, $servers)
{
$this->user = $user;
$this->servers = $servers;
}
public function getFlags(): array
{
return $this->flags;
}
protected $protocolRequirements = [
'nekobox' => [
'hysteria' => [
'protocol_settings.version' => [
'2' => '1.2.7'
],
],
],
'clashmetaforandroid' => [
'hysteria' => [
'protocol_settings.version' => [
'2' => '2.9.0'
],
],
],
'nekoray' => [
'hysteria' => [
'protocol_settings.version' => [
'2' => '3.24'
],
],
],
'verge' => [
'hysteria' => [
'protocol_settings.version' => [
'2' => '1.3.8'
],
],
],
'ClashX Meta' => [
'hysteria' => [
'protocol_settings.version' => [
'2' => '1.3.5'
],
],
],
'flclash' => [
'hysteria' => [
'protocol_settings.version' => [
'2' => '0.8.0'
],
],
],
];
public function handle()
{
@@ -80,7 +106,7 @@ class ClashMeta implements ProtocolInterface
array_push($proxy, self::buildTuic($user['uuid'], $item));
array_push($proxies, $item['name']);
}
if ($item['type'] === 'anytls'){
if ($item['type'] === 'anytls') {
array_push($proxy, self::buildAnyTLS($user['uuid'], $item));
array_push($proxies, $item['name']);
}
@@ -166,12 +192,50 @@ class ClashMeta implements ProtocolInterface
$array['cipher'] = data_get($server['protocol_settings'], 'cipher');
$array['password'] = data_get($server, 'password', $password);
$array['udp'] = true;
if (data_get($protocol_settings, 'obfs') == 'http') {
$array['plugin'] = 'obfs';
$array['plugin-opts'] = [
'mode' => 'http',
'host' => data_get($protocol_settings, 'obfs_settings.host'),
];
if (data_get($protocol_settings, 'plugin') && data_get($protocol_settings, 'plugin_opts')) {
$plugin = data_get($protocol_settings, 'plugin');
$pluginOpts = data_get($protocol_settings, 'plugin_opts', '');
$array['plugin'] = $plugin;
// 解析插件选项
$parsedOpts = collect(explode(';', $pluginOpts))
->filter()
->mapWithKeys(function ($pair) {
if (!str_contains($pair, '=')) {
return [];
}
[$key, $value] = explode('=', $pair, 2);
return [trim($key) => trim($value)];
})
->all();
// 根据插件类型进行字段映射
switch ($plugin) {
case 'obfs':
$array['plugin-opts'] = [
'mode' => $parsedOpts['obfs'],
'host' => $parsedOpts['obfs-host'],
];
// 可选path参数
if (isset($parsedOpts['path'])) {
$array['plugin-opts']['path'] = $parsedOpts['path'];
}
break;
case 'v2ray-plugin':
$array['plugin-opts'] = [
'mode' => $parsedOpts['mode'] ?? 'websocket',
'tls' => isset($parsedOpts['tls']) && $parsedOpts['tls'] == 'true',
'host' => $parsedOpts['host'] ?? '',
'path' => $parsedOpts['path'] ?? '/',
];
break;
default:
// 对于其他插件,直接使用解析出的键值对
$array['plugin-opts'] = $parsedOpts;
}
}
return $array;
}
@@ -408,7 +472,7 @@ class ClashMeta implements ProtocolInterface
'udp' => true,
];
$array['skip-cert-verify'] = (bool) data_get($protocol_settings, 'tls.allow_insecure', false);
return $array;
}