Compare commits

...

10 Commits

Author SHA1 Message Date
xboard
2c4a3b520f fix: handle null parameter in str_replace to resolve deprecation warning in ClientController
Some checks are pending
Docker Build and Publish / build (push) Waiting to run
2025-01-16 22:04:40 +08:00
xboard
94ecd10704 fix: correct know issues 2025-01-16 21:59:39 +08:00
xboard
78370717df update 2025_01_04_optimize_plan_table.php 2025-01-16 21:28:46 +08:00
xboard
abe93bf5ff fix: app getConfig api 2025-01-16 21:21:16 +08:00
Xboard
d7b88d7b5d
Merge pull request #323 from NekoCareLab/master
Fixed trojan and polished Vmess/VLESS for General.php and Clash/Meta.php
2025-01-16 18:48:15 +08:00
NekoCareLab
bc16656371
Fixed trojan and polished Vmess/VLESS for General.php and Clash/Meta.php 2025-01-16 15:26:19 +08:00
NekoCareLab
e0e76a22ea
Fixed General.php 2025-01-16 14:58:05 +08:00
xboard
7cf839488b fix(i18n): add missing language translations 2025-01-16 14:49:42 +08:00
xboard
c895de839a feat(database): add index to updated_at column in v2_order table for better query performance 2025-01-16 14:26:18 +08:00
xboard
296a72331e update XboardInstall.php 2025-01-16 14:12:14 +08:00
15 changed files with 174 additions and 86 deletions

View File

@ -145,7 +145,6 @@ class XboardInstall extends Command
}
}
$envConfig['APP_KEY'] = 'base64:' . base64_encode(Encrypter::generateKey('AES-256-CBC'));
$envConfig['INSTALLED'] = true;
$isReidsValid = false;
while (!$isReidsValid) {
// 判断是否为Docker环境
@ -212,6 +211,8 @@ class XboardInstall extends Command
$defaultSecurePath = hash('crc32b', config('app.key'));
$this->info("访问 http(s)://你的站点/{$defaultSecurePath} 进入管理面板,你可以在用户中心修改你的密码。");
$envConfig['INSTALLED'] = true;
$this->saveToEnv($envConfig);
} catch (\Exception $e) {
$this->error($e);
}

View File

@ -30,8 +30,9 @@ class AppController extends Controller
$proxies = [];
foreach ($servers as $item) {
$protocol_settings = $item['protocol_settings'];
if ($item['type'] === 'shadowsocks'
&& in_array($item['cipher'], [
&& in_array(data_get($protocol_settings, 'cipher'), [
'aes-128-gcm',
'aes-192-gcm',
'aes-256-gcm',

View File

@ -166,7 +166,10 @@ class ClientController extends Controller
private function getFilterArray(?string $filter): ?array
{
return mb_strlen((string) $filter) > 20 ? null :
if ($filter === null) {
return null;
}
return mb_strlen($filter) > 20 ? null :
explode('|', str_replace(['|', '', ','], '|', $filter));
}

View File

@ -170,16 +170,17 @@ class Clash implements ProtocolInterface
break;
case 'ws':
$array['network'] = 'ws';
$array['ws-opts']['path'] = data_get($protocol_settings, 'network_settings.path', '/');
if ($host = data_get($protocol_settings, 'network_settings.headers.Host')) {
if ($path = data_get($protocol_settings, 'network_settings.path'))
$array['ws-opts']['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$array['ws-opts']['headers'] = ['Host' => $host];
}
break;
case 'grpc':
$array['network'] = 'grpc';
$array['grpc-opts'] = [
'grpc-service-name' => data_get($protocol_settings, 'network_settings.serviceName')
];
if ($serviceName = data_get($protocol_settings, 'network_settings.serviceName'))
$array['grpc-opts']['grpc-service-name'] = $serviceName;
break;
default:
break;
}
return $array;
@ -206,16 +207,15 @@ class Clash implements ProtocolInterface
break;
case 'ws':
$array['network'] = 'ws';
$array['ws-opts']['path'] = data_get($protocol_settings, 'network_settings.path', '/');
if ($host = data_get($protocol_settings, 'network_settings.headers.Host')) {
if ($path = data_get($protocol_settings, 'network_settings.path'))
$array['ws-opts']['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$array['ws-opts']['headers'] = ['Host' => $host];
}
break;
case 'grpc':
$array['network'] = 'grpc';
$array['grpc-opts'] = [
'grpc-service-name' => data_get($protocol_settings, 'network_settings.serviceName')
];
if ($serviceName = data_get($protocol_settings, 'network_settings.serviceName'))
$array['grpc-opts']['grpc-service-name'] = $serviceName;
break;
default:
$array['network'] = 'tcp';
@ -234,6 +234,6 @@ class Clash implements ProtocolInterface
if (empty($exp)) {
return false;
}
return @preg_match((string)$exp, '') !== false;
return @preg_match((string) $exp, '') !== false;
}
}

View File

@ -43,6 +43,7 @@ class ClashMeta implements ProtocolInterface
$proxies = [];
foreach ($servers as $item) {
$protocol_settings = $item['protocol_settings'];
if ($item['type'] === 'shadowsocks') {
array_push($proxy, self::buildShadowsocks($item['password'], $item));
array_push($proxies, $item['name']);
@ -55,7 +56,10 @@ class ClashMeta implements ProtocolInterface
array_push($proxy, self::buildTrojan($user['uuid'], $item));
array_push($proxies, $item['name']);
}
if ($item['type'] === 'vless') {
if (
$item['type'] === 'vless'
&& in_array(data_get($protocol_settings, 'network'), ['tcp', 'ws', 'grpc', 'http', 'h2'])
) {
array_push($proxy, self::buildVless($user['uuid'], $item));
array_push($proxies, $item['name']);
}
@ -167,16 +171,15 @@ class ClashMeta implements ProtocolInterface
break;
case 'ws':
$array['network'] = 'ws';
$array['ws-opts'] = [
'path' => data_get($protocol_settings, 'network_settings.path'),
'headers' => ['Host' => data_get($protocol_settings, 'network_settings.headers.Host', $server['host'])]
];
if ($path = data_get($protocol_settings, 'network_settings.path'))
$array['ws-opts']['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$array['ws-opts']['headers'] = ['Host' => $host];
break;
case 'grpc':
$array['network'] = 'grpc';
$array['grpc-opts'] = [
'grpc-service-name' => data_get($protocol_settings, 'network_settings.serviceName')
];
if ($serviceName = data_get($protocol_settings, 'network_settings.serviceName'))
$array['grpc-opts']['grpc-service-name'] = $serviceName;
break;
default:
break;
@ -226,23 +229,15 @@ class ClashMeta implements ProtocolInterface
switch (data_get($protocol_settings, 'network')) {
case 'ws':
$array['network'] = 'ws';
$array['ws-opts']['path'] = data_get($protocol_settings, 'network_settings.path', '/');
if ($host = data_get($protocol_settings, 'network_settings.headers.Host')) {
if ($path = data_get($protocol_settings, 'network_settings.path'))
$array['ws-opts']['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$array['ws-opts']['headers'] = ['Host' => $host];
}
break;
case 'grpc':
$array['network'] = 'grpc';
$array['grpc-opts'] = [
'grpc-service-name' => data_get($protocol_settings, 'network_settings.serviceName')
];
break;
case 'h2':
$array['network'] = 'h2';
$array['h2-opts'] = [
'path' => data_get($protocol_settings, 'network_settings.path', '/'),
'host' => data_get($protocol_settings, 'network_settings.host')
];
if ($serviceName = data_get($protocol_settings, 'network_settings.serviceName'))
$array['grpc-opts']['grpc-service-name'] = $serviceName;
break;
default:
break;
@ -268,20 +263,23 @@ class ClashMeta implements ProtocolInterface
}
switch (data_get($protocol_settings, 'network')) {
case 'grpc':
$array['network'] = 'grpc';
$array['grpc-opts'] = [
'grpc-service-name' => data_get($protocol_settings, 'network_settings.serviceName')
];
case 'tcp':
$array['network'] = 'tcp';
break;
case 'ws':
$array['network'] = 'ws';
$array['ws-opts']['path'] = data_get($protocol_settings, 'network_settings.path', '/');
if ($host = data_get($protocol_settings, 'network_settings.headers.Host')) {
if ($path = data_get($protocol_settings, 'network_settings.path'))
$array['ws-opts']['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$array['ws-opts']['headers'] = ['Host' => $host];
}
break;
case 'grpc':
$array['network'] = 'grpc';
if ($serviceName = data_get($protocol_settings, 'network_settings.serviceName'))
$array['grpc-opts']['grpc-service-name'] = $serviceName;
break;
default:
$array['network'] = 'tcp';
break;
}

View File

@ -92,14 +92,15 @@ class General implements ProtocolInterface
break;
case 'ws':
$config['type'] = 'ws';
$config['path'] = data_get($protocol_settings, 'network_settings.path');
if ($host = data_get($protocol_settings, 'network_settings.headers.Host')) {
if ($path = data_get($protocol_settings, 'network_settings.path'))
$config['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$config['host'] = $host;
}
break;
case 'grpc':
$config['type'] = 'grpc';
$config['path'] = data_get($protocol_settings, 'network_settings.serviceName');
if ($path = data_get($protocol_settings, 'network_settings.serviceName'))
$config['path'] = $path;
break;
default:
break;
@ -144,20 +145,23 @@ class General implements ProtocolInterface
// 处理传输协议
switch ($server['protocol_settings']['network']) {
case 'ws':
$config['path'] = data_get($protocol_settings, 'network_settings.path');
if ($host = data_get($protocol_settings, 'network_settings.headers.Host')) {
if ($path = data_get($protocol_settings, 'network_settings.path'))
$config['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$config['host'] = $host;
}
break;
case 'grpc':
$config['serviceName'] = data_get($protocol_settings, 'network_settings.serviceName');
if ($path = data_get($protocol_settings, 'network_settings.serviceName'))
$config['path'] = $path;
break;
case 'kcp':
$config['path'] = data_get($protocol_settings, 'network_settings.seed');
if ($path = data_get($protocol_settings, 'network_settings.seed'))
$config['path'] = $path;
$config['type'] = data_get($protocol_settings, 'network_settings.header.type', 'none');
break;
case 'httpupgrade':
$config['path'] = data_get($protocol_settings, 'network_settings.path');
if ($path = data_get($protocol_settings, 'network_settings.path'))
$config['path'] = $path;
$config['host'] = data_get($protocol_settings, 'network_settings.host', $server['host']);
break;
case 'xhttp':
@ -185,6 +189,23 @@ class General implements ProtocolInterface
$array['peer'] = $serverName;
$array['sni'] = $serverName;
}
switch ($server['protocol_settings']['network']) {
case 'ws':
$array['type'] = 'ws';
if ($path = data_get($protocol_settings, 'network_settings.path'))
$array['path'] = $path;
if ($host = data_get($protocol_settings, 'network_settings.headers.Host'))
$array['host'] = $host;
break;
case 'grpc':
// Follow V2rayN family standards
$array['type'] = 'grpc';
if ($serviceName = data_get($protocol_settings, 'network_settings.serviceName'))
$array['serviceName'] = $serviceName;
break;
default:
break;
}
$query = http_build_query($array);
$uri = "trojan://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
$uri .= "\r\n";
@ -209,7 +230,7 @@ class General implements ProtocolInterface
$params['obfs'] = 'salamander';
$params['obfs-password'] = data_get($protocol_settings, 'obfs.password');
}
if(isset($server['ports'])){
if (isset($server['ports'])) {
$params['mport'] = $server['ports'];
}

View File

@ -51,6 +51,7 @@ class SingBox implements ProtocolInterface
$outbounds = $this->config['outbounds'];
$proxies = [];
foreach ($this->servers as $item) {
$protocol_settings = $item['protocol_settings'];
if ($item['type'] === 'shadowsocks') {
$ssConfig = $this->buildShadowsocks($item['password'], $item);
$proxies[] = $ssConfig;
@ -63,7 +64,9 @@ class SingBox implements ProtocolInterface
$vmessConfig = $this->buildVmess($this->user['uuid'], $item);
$proxies[] = $vmessConfig;
}
if ($item['type'] === 'vless') {
if ($item['type'] === 'vless'
&& in_array(data_get($protocol_settings, 'network'), ['tcp', 'ws', 'grpc', 'http', 'quic', 'httpupgrade'])
) {
$vlessConfig = $this->buildVless($this->user['uuid'], $item);
$proxies[] = $vlessConfig;
}
@ -213,13 +216,13 @@ class SingBox implements ProtocolInterface
],
'h2' => [
'type' => 'http',
'host' => data_get($protocol_settings, 'network_settings.host') ? [data_get($protocol_settings, 'network_settings.host')] : null,
'host' => data_get($protocol_settings, 'network_settings.host'),
'path' => data_get($protocol_settings, 'network_settings.path')
],
'httpupgrade' => [
'type' => 'httpupgrade',
'path' => data_get($protocol_settings, 'network_settings.path'),
'host' => data_get($protocol_settings, 'network_settings.headers.Host', $server['host']),
'host' => data_get($protocol_settings, 'network_settings.host', $server['host']),
'headers' => data_get($protocol_settings, 'network_settings.headers')
],
default => null

View File

@ -59,10 +59,15 @@ class Stash implements ProtocolInterface
array_push($proxy, self::buildVmess($user['uuid'], $item));
array_push($proxies, $item['name']);
}
// if ($item['type'] === 'vless') {
// array_push($proxy, self::buildVless($user['uuid'], $item));
// array_push($proxies, $item['name']);
// }
if (
$item['type'] === 'vless'
&& in_array(data_get($item['protocol_settings'], 'network'), ['tcp', 'ws', 'grpc', 'http', 'h2'])
&& in_array(data_get($item['protocol_settings'], 'tls'), [1, 0])
&& in_array(data_get($item['protocol_settings'], 'flow'), ['xtls-rprx-origin', 'xtls-rprx-direct', 'xtls-rprx-splice'])
) {
array_push($proxy, self::buildVless($user['uuid'], $item));
array_push($proxies, $item['name']);
}
if ($item['type'] === 'hysteria') {
array_push($proxy, self::buildHysteria($user['uuid'], $item));
array_push($proxies, $item['name']);
@ -192,15 +197,6 @@ class Stash implements ProtocolInterface
$array['servername'] = $serverName;
}
break;
case 2:
$array['tls'] = true;
$array['skip-cert-verify'] = data_get($protocol_settings, 'reality_settings.allow_insecure');
$array['servername'] = data_get($protocol_settings, 'reality_settings.server_name');
$array['reality-opts'] = [
'public-key' => data_get($protocol_settings, 'reality_settings.public_key'),
'short-id' => data_get($protocol_settings, 'reality_settings.short_id')
];
break;
}
switch (data_get($protocol_settings, 'network')) {
@ -219,6 +215,11 @@ class Stash implements ProtocolInterface
$array['network'] = 'grpc';
$array['grpc-opts']['grpc-service-name'] = data_get($protocol_settings, 'network_settings.serviceName');
break;
// case 'h2':
// $array['network'] = 'h2';
// $array['h2-opts']['host'] = data_get($protocol_settings, 'network_settings.host');
// $array['h2-opts']['path'] = data_get($protocol_settings, 'network_settings.path');
// break;
}
return $array;

View File

@ -42,27 +42,19 @@ class Surge implements ProtocolInterface
'chacha20-ietf-poly1305'
])
) {
// [Proxy]
$proxies .= self::buildShadowsocks($item['password'], $item);
// [Proxy Group]
$proxyGroup .= $item['name'] . ', ';
}
if ($item['type'] === 'vmess') {
// [Proxy]
$proxies .= self::buildVmess($user['uuid'], $item);
// [Proxy Group]
$proxyGroup .= $item['name'] . ', ';
}
if ($item['type'] === 'trojan') {
// [Proxy]
$proxies .= self::buildTrojan($user['uuid'], $item);
// [Proxy Group]
$proxyGroup .= $item['name'] . ', ';
}
if ($item['type'] === 'hysteria') {
// [Proxy]
$proxies .= self::buildHysteria($user['uuid'], $item);
// [Proxy Group]
$proxyGroup .= $item['name'] . ', ';
}
}

View File

@ -38,6 +38,7 @@ return new class extends Migration {
->where('id', $plan->id)
->update([
'prices' => json_encode($prices),
'sell' => $plan->show
]);
}
});

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('v2_order', function (Blueprint $table) {
$table->index('updated_at');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('v2_order', function (Blueprint $table) {
$table->dropIndex(['updated_at']);
});
}
};

File diff suppressed because one or more lines are too long

View File

@ -780,6 +780,19 @@ window.XBOARD_TRANSLATIONS['en-US'] = {
"success": "Copied successfully",
"error": "Copy failed",
"errorLog": "Error copying to clipboard"
},
"table": {
"noData": "No data available",
"pagination": {
"selected": "{{selected}} of {{total}} items selected",
"itemsPerPage": "Per page",
"page": "Page",
"pageOf": "of {{total}} pages",
"firstPage": "Go to first page",
"previousPage": "Previous page",
"nextPage": "Next page",
"lastPage": "Go to last page"
}
}
},
"dashboard": {

View File

@ -481,7 +481,7 @@ window.XBOARD_TRANSLATIONS['ko-KR'] = {
"delete": "삭제",
"edit": "편집",
"view": "보기",
"toggleNavigation": "비게이션 전환",
"toggleNavigation": "비게이션 전환",
"toggleSidebar": "사이드바 전환",
"search": "검색...",
"theme": {
@ -497,6 +497,19 @@ window.XBOARD_TRANSLATIONS['ko-KR'] = {
"success": "복사 성공",
"error": "복사 실패",
"errorLog": "클립보드에 복사하는 중 오류 발생"
},
"table": {
"noData": "데이터가 없습니다",
"pagination": {
"selected": "{{selected}}개 선택됨, 총 {{total}}개",
"itemsPerPage": "페이지당 표시",
"page": "페이지",
"pageOf": "/ {{total}} 페이지",
"firstPage": "첫 페이지로 이동",
"previousPage": "이전 페이지",
"nextPage": "다음 페이지",
"lastPage": "마지막 페이지로 이동"
}
}
},
"dashboard": {

View File

@ -784,6 +784,19 @@ window.XBOARD_TRANSLATIONS['zh-CN'] = {
"success": "复制成功",
"error": "复制失败",
"errorLog": "复制到剪贴板时出错"
},
"table": {
"noData": "暂无数据",
"pagination": {
"selected": "已选择 {{selected}} 项,共 {{total}} 项",
"itemsPerPage": "每页显示",
"page": "第",
"pageOf": "页,共 {{total}} 页",
"firstPage": "跳转到第一页",
"previousPage": "上一页",
"nextPage": "下一页",
"lastPage": "跳转到最后一页"
}
}
},
"dashboard": {