diff --git a/app/Http/Controllers/SakaiFnController.php b/app/Http/Controllers/SakaiFnController.php new file mode 100755 index 00000000..813bbf74 --- /dev/null +++ b/app/Http/Controllers/SakaiFnController.php @@ -0,0 +1,59 @@ +first()?->content; + $aContent = json_decode($sContent, true); + + $cClientContent = $aContent[$sClient]; + + $aNode = []; + + if ($sClient == "singbox") { + foreach ($cClientContent as $sMd5 => $aClientContent) { + + $sContentXieyi = $aClientContent["protocolType"] ?? ''; + + if ($sXieyi != "all" && $sContentXieyi != $sXieyi) { + continue; + } + + $sNodeName = $aClientContent["country"]; + + if ($sLike) { + if (!Str::contains($sNodeName, $sLike, true)) { + continue; + } + } + + $aNode[] = $aClientContent; + } + } + + + + + tt($aNode); +// tt($aContent[$sClient]); + } + +} diff --git a/app/Services/ServiceFnPoolV2rayTo.php b/app/Services/ServiceFnPoolV2rayTo.php index 02900f81..c287aa44 100644 --- a/app/Services/ServiceFnPoolV2rayTo.php +++ b/app/Services/ServiceFnPoolV2rayTo.php @@ -86,7 +86,7 @@ class ServiceFnPoolV2rayTo return $aV2ray; } - private function mod_to_trojan($aV2ray) + private function mod_to_trojan__($aV2ray) { $sConfig = $aV2ray["config"] ?? ''; @@ -177,7 +177,7 @@ class ServiceFnPoolV2rayTo return $aV2ray; } - private function mod_to_hysteria2($aV2ray) + private function mod_to_hysteria2__($aV2ray) { $sConfig = $aV2ray["config"] ?? ''; @@ -237,7 +237,7 @@ class ServiceFnPoolV2rayTo return $aV2ray; } - private function mod_to_ss($aV2ray) + private function mod_to_ss__($aV2ray) { $sConfig = $aV2ray["config"] ?? ''; @@ -285,55 +285,138 @@ class ServiceFnPoolV2rayTo return $aV2ray; } - private function mod_to_vmess($aV2ray) + private function mod_to_vmess(array $aV2ray): array { - $aNode = []; - $aConfig = $aV2ray["config"]; - - $aNode["type"] = "vmess"; - $aNode["tag"] = $aV2ray['country'] ?? ''; - $aNode["server"] = $aConfig["add"] ?? ''; - $aNode["server_port"] = $aConfig["port"] ?? ''; // Cannot access offset of type string on string - $aNode["server_port"] = (int) $aNode["server_port"]; - $aNode["uuid"] = $aConfig["id"] ?? ''; - $aNode["security"] = $aConfig["scy"] ?? 'auto'; - $aNode["alter_id"] = $aConfig["aid"] ?? 0; // 猜的 - $aNode["alter_id"] = (int) $aNode["alter_id"]; - + // 1. 类型安全防御:确保 $aConfig 一定是数组 + $aConfig = $aV2ray['config'] ?? []; + if (is_string($aConfig)) { + $aConfig = json_decode($aConfig, true) ?? []; + } + if (!is_array($aConfig)) { + $aConfig = []; + } + + // 2. 基础节点属性映射 + $aNode = [ + 'type' => 'vmess', + 'tag' => (string) ($aV2ray['country'] ?? ''), + 'server' => (string) ($aConfig['add'] ?? ''), + 'server_port' => (int) ($aConfig['port'] ?? 0), + 'uuid' => (string) ($aConfig['id'] ?? ''), + 'security' => !empty($aConfig['scy']) ? (string) $aConfig['scy'] : 'auto', + 'alter_id' => (int) ($aConfig['aid'] ?? 0), + ]; + + // 3. 传输层 (Transport) 映射逻辑 + $sV2rayNet = strtolower((string) ($aConfig['net'] ?? 'tcp')); + $sV2rayType = strtolower((string) ($aConfig['type'] ?? 'none')); + $sRawPath = (string) ($aConfig['path'] ?? ''); + $sPath = !empty($sRawPath) ? rawurldecode($sRawPath) : '/'; + $sHost = (string) ($aConfig['host'] ?? ''); + $aTransport = []; - if (isset($aConfig["net"]) && $aConfig["net"] != "none" && $aConfig["net"] != "raw") { - $aTransport["type"] = $aConfig["net"]; + + // 分支 A:TCP + HTTP 伪装 + if ($sV2rayNet === 'tcp' && $sV2rayType === 'http') { + $aTransport['type'] = 'http'; + $aTransport['path'] = $sPath; + if (!empty($sHost)) { + $aTransport['host'] = array_map('trim', explode(',', $sHost)); + } } - if (isset($aConfig["path"])) { - $aTransport["path"] = rawurldecode($aConfig["path"]); + // 分支 B:WebSocket 传输 + elseif ($sV2rayNet === 'ws') { + $aTransport['type'] = 'ws'; + $aTransport['path'] = $sPath; + if (!empty($sHost)) { + $aTransport['headers'] = ['Host' => $sHost]; + } } - if (isset($aConfig["host"])) { - $aTransport["headers"]["Host"] = $aConfig["host"]; + // 分支 C:gRPC 传输 + elseif ($sV2rayNet === 'grpc') { + $aTransport['type'] = 'grpc'; + $aTransport['service_name'] = $sRawPath; } + // 分支 D:其他非 TCP 传输(如 mkcp, quic) + elseif (!in_array($sV2rayNet, ['tcp', 'none', 'raw', ''], true)) { + $aTransport['type'] = $sV2rayNet; + } + if (!empty($aTransport)) { - if (empty($aTransport["type"])) { - $aTransport["type"] = "tcp"; + $aNode['transport'] = $aTransport; + } + + // 4. TLS 配置映射 + $sTlsType = strtolower((string) ($aConfig['tls'] ?? '')); + if ($sTlsType === 'tls') { + $sServerName = !empty($sHost) ? $sHost : $aNode['server']; + + // 兼容类内 parseServerName 方法 + if (method_exists($this, 'parseServerName')) { + $sServerName = $this->parseServerName($sServerName, $sServerName); } - $aNode["transport"] = $aTransport; + + $aNode['tls'] = [ + 'enabled' => true, + 'server_name' => $sServerName, + ]; } - - $aTls = []; - if (isset($aConfig["tls"])) { - if ($aConfig["tls"] == "tls") { - $aTls["server_name"] = !empty($aConfig['host']) ? $aConfig['host'] : $aConfig['add']; - $aTls["server_name"] = $this->parseServerName($aTls["server_name"], $aTls["server_name"]); - } - } - if (!empty($aTls)) { - $aTls["enabled"] = true; - $aNode["tls"] = $aTls; - } - - $aV2ray["config"] = $aNode; - + + // 5. 替换配置并输出同等结构 + $aV2ray['config'] = $aNode; + return $aV2ray; } +// private function mod_to_vmess($aV2ray) +// { +// $aNode = []; +// $aConfig = $aV2ray["config"]; +// +// $aNode["type"] = "vmess"; +// $aNode["tag"] = $aV2ray['country'] ?? ''; +// $aNode["server"] = $aConfig["add"] ?? ''; +// $aNode["server_port"] = $aConfig["port"] ?? ''; // Cannot access offset of type string on string +// $aNode["server_port"] = (int) $aNode["server_port"]; +// $aNode["uuid"] = $aConfig["id"] ?? ''; +// $aNode["security"] = $aConfig["scy"] ?? 'auto'; +// $aNode["alter_id"] = $aConfig["aid"] ?? 0; // 猜的 +// $aNode["alter_id"] = (int) $aNode["alter_id"]; +// +// $aTransport = []; +// if (isset($aConfig["net"]) && $aConfig["net"] != "none" && $aConfig["net"] != "raw") { +// $aTransport["type"] = $aConfig["net"]; +// } +// if (isset($aConfig["path"])) { +// $aTransport["path"] = rawurldecode($aConfig["path"]); +// } +// if (isset($aConfig["host"])) { +// $aTransport["headers"]["Host"] = $aConfig["host"]; +// } +// if (!empty($aTransport)) { +// if (empty($aTransport["type"])) { +// $aTransport["type"] = "tcp"; +// } +// $aNode["transport"] = $aTransport; +// } +// +// $aTls = []; +// if (isset($aConfig["tls"])) { +// if ($aConfig["tls"] == "tls") { +// $aTls["server_name"] = !empty($aConfig['host']) ? $aConfig['host'] : $aConfig['add']; +// $aTls["server_name"] = $this->parseServerName($aTls["server_name"], $aTls["server_name"]); +// } +// } +// if (!empty($aTls)) { +// $aTls["enabled"] = true; +// $aNode["tls"] = $aTls; +// } +// +// $aV2ray["config"] = $aNode; +// +// return $aV2ray; +// } // 这是原版代码,不行。你给我重写。传入和返回值一致即可 + private function mod_to_vless__($aV2ray) { $sConfig = $aV2ray['config'] ?? ''; diff --git a/app/Services/Tg/Hook/Mod/Blade.php b/app/Services/Tg/Hook/Mod/Blade.php index 0aa9905f..47d8eaac 100755 --- a/app/Services/Tg/Hook/Mod/Blade.php +++ b/app/Services/Tg/Hook/Mod/Blade.php @@ -4,7 +4,7 @@ namespace App\Services\Tg\Hook\Mod; use App\Models\Blade as ModelBlade; use App\Services\Tg\Hook\Dog; - +use Illuminate\Support\Str; class Blade extends Base { diff --git a/app/Services/Tg/Hook/Mod/FnLook.php b/app/Services/Tg/Hook/Mod/FnLook.php new file mode 100755 index 00000000..92689d34 --- /dev/null +++ b/app/Services/Tg/Hook/Mod/FnLook.php @@ -0,0 +1,149 @@ +oDog = new Dog(new FreenodePool()); + $this->oDog->_setDogName("fnLook"); // 必须,me用,正常就是类名,只不过后期没准改名,所以就这里写死 +// $this->oDog->_setPrimaryKey("code"); // 可选,默认id +// $this->oDog->_setStrField(["content"]); // 可选,指定长文本字段 + + } + + public function __call($sName, $aArg) + { + + return $this->oDog->$sName($aArg[0]); + + } + + // 筛选生成订阅,比如只生成vmess协议的 + // 暂时只支持v2ray + public function tichun($aParam) + { + $sClient = $aParam["aOption"][1] ?? "v2ray"; + $sXieyi = $aParam["aOption"][2] ?? "all"; + $aLike = $aParam["aArg"] ?? []; + $sLike = implode("", $aLike); + + if ($sLike == "?") { + return "#tichun__[client]__[xieyi,可用all]__[like,可空]"; + } + + $sDate = date("Y-m-d"); + $sContent = FreenodePool::whereDate("date", $sDate)->first()?->content; + $aContent = json_decode($sContent, true); + + $cClientContent = $aContent[$sClient]; + + $cNode = []; + $sMerge = ''; + if ($sClient == "v2ray") { + + foreach ($cClientContent as $aClientContent) { + $sContentXieyi = $aClientContent["protocolType"] ?? ''; + + if ($sXieyi != "all" && $sContentXieyi != $sXieyi) { + continue; + } + + $sNodeName = $aClientContent["country"]; + + if ($sLike) { + if (!Str::contains($sNodeName, $sLike, true)) { + continue; + } + } + + $sConfig = $aClientContent["config"]; + + if (is_array($sConfig)) { + $sConfig["ps"] = "xx".rand(1, 999); + $sConfig = json_encode($sConfig); + } + +// $sNodeName = preg_replace('/ :\[.*?\]:/su', '', $sNodeName); +// +// tt($sNodeName); + $sConfig = base64_encode($sConfig); + $sNodeTmp = $sContentXieyi."://".$sConfig; + $cNode[] = $sNodeTmp; + } + +// tt($cNode); + $sMerge = implode("\n", $cNode); + $sMerge = base64_encode($sMerge); + + } + + return $sMerge; +// tt($sMerge); +// exit; +// tt($cClientContent); + } + + + // 比较节点数据。目前用于singbox比较原v2ray + public function duibi($aParam) + { + $sClient = $aParam["aOption"][1] ?? "singbox"; + $sXieyi = $aParam["aOption"][2] ?? "all"; + $aLike = $aParam["aArg"] ?? []; + $sLike = implode(" ", $aLike); + + if ($sLike == "?") { + return "#duibi__[client]__[xieyi,可用all]__[like,可空]"; + } + + $sDate = date("Y-m-d"); + $sContent = FreenodePool::whereDate("date", $sDate)->first()?->content; + $aContent = json_decode($sContent, true); + + $cClientContent = $aContent[$sClient]; + + $sNode = ""; + + if ($sClient == "singbox") { + foreach ($cClientContent as $sMd5 => $aClientContent) { + + $sContentXieyi = $aClientContent["protocolType"] ?? ''; + + if ($sXieyi != "all" && $sContentXieyi != $sXieyi) { + continue; + } + + $sNodeName = $aClientContent["country"]; + + if ($sLike) { + if (!Str::contains($sNodeName, $sLike, true)) { + continue; + } + } + + $sClientContent = json_encode($aClientContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + + $cV2rayContent = $aContent["v2ray"] ?? []; + + $aV2rayContent = $cV2rayContent[$sMd5] ?? ''; + $sV2rayContent = json_encode($aV2rayContent, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + + $sNode .= "\n\n"."v2ray:\n".$sV2rayContent; + $sNode .= "\n\n".$sClient.":\n".$sClientContent; + $sNode .= "\n\n========================================================================================="; + } + } + + return $sNode; + } + +} diff --git a/routes/web.php b/routes/web.php index 88832e78..2b7b1b73 100755 --- a/routes/web.php +++ b/routes/web.php @@ -50,6 +50,11 @@ use App\Http\Controllers\Web\Nasa\V1\ResourceArticleBaseController as NasaResour use App\Http\Controllers\Web\Nasa\V1\ResourceUploadimagesBaseController as NasaResourceUploadimagesBaseController; use App\Http\Controllers\Web\Nasa\V1\ActionsController as NasaActionsController; use App\Http\Controllers\Web\Nasa\V1\GithubArticleGithubController as NasaGithubArticleGithubController; +use App\Http\Controllers\SakaiFnController; + +Route::prefix('sakai')->group(function() { + Route::get('fn/looktrans/{client}/{xieyi}/{like?}', [SakaiFnController::class, 'looktrans']); // like可以空怎么表示 +}); Route::get('/birds/create', [BirdController::class, 'create'])->name('birds.create'); // 录入界面 Route::get('/birds/{id}', [BirdController::class, 'show'])->name('birds.show'); // 详情展示界面