已修复,insecure: true✅ Hysteria - 新增支持✅ Hysteria2 - 已修复,insecure: true (cherry picked from commit 7fae8a6f4d569a30c5a3606949154a57e5a597d6)
362 lines
12 KiB
Dart
Executable File
362 lines
12 KiB
Dart
Executable File
import 'dart:convert';
|
||
import 'package:get/get.dart';
|
||
|
||
import '../response/kr_node_list.dart';
|
||
|
||
/// 表示出站项的模型类
|
||
class KROutboundItem {
|
||
int selected = 0; // 是否选中(0=未选中,1=选中)
|
||
String id = ""; // 标签
|
||
String tag = ""; // 标签
|
||
String serverAddr = ""; // 服务器地址
|
||
|
||
/// 初始化配置
|
||
Map<String, dynamic> config = {}; // 配置项
|
||
|
||
String city = ""; // 城市
|
||
String country = ""; // 国家
|
||
|
||
double latitude = 0.0; // 节点纬度
|
||
double latitudeCountry = 0.0; // 国家中心纬度
|
||
double longitude = 0.0; // 节点经度
|
||
double longitudeCountry = 0.0; // 国家中心经度
|
||
String protocol = "";
|
||
|
||
/// 延迟
|
||
RxInt urlTestDelay = 0.obs;
|
||
|
||
/// URL
|
||
String url = "";
|
||
|
||
/// 服务器类型
|
||
|
||
/// 构造函数,接受 KrNodeListItem 对象并初始化 KROutboundItem
|
||
KROutboundItem(KrNodeListItem nodeListItem) {
|
||
id = nodeListItem.id.toString();
|
||
protocol = nodeListItem.protocol;
|
||
latitude = nodeListItem.latitude;
|
||
latitudeCountry = nodeListItem.latitudeCountry;
|
||
longitude = nodeListItem.longitude;
|
||
longitudeCountry = nodeListItem.longitudeCountry;
|
||
|
||
tag = nodeListItem.name; // 设置标签
|
||
serverAddr = nodeListItem.serverAddr; // 设置服务器地址
|
||
city = nodeListItem.city; // 设置城市
|
||
country = nodeListItem.country; // 设置国家
|
||
|
||
// 🔧 优先使用直接字段构建配置(新API格式)
|
||
// 判断条件:如果有 port 和 serverAddr,说明是新格式
|
||
if (nodeListItem.port > 0 && nodeListItem.serverAddr.isNotEmpty) {
|
||
print('ℹ️ 节点 ${nodeListItem.name} 使用直接字段构建配置');
|
||
_buildConfigFromFields(nodeListItem);
|
||
return;
|
||
}
|
||
|
||
// 兜底:尝试解析 config 字段(旧API格式)
|
||
if (nodeListItem.config.isEmpty) {
|
||
print('❌ 节点 ${nodeListItem.name} 缺少配置信息(无port或config)');
|
||
config = {};
|
||
return;
|
||
}
|
||
|
||
late Map<String, dynamic> json;
|
||
try {
|
||
json = jsonDecode(nodeListItem.config) as Map<String, dynamic>;
|
||
} catch (e) {
|
||
print('❌ 节点 ${nodeListItem.name} 的 config 解析失败: $e,尝试使用直接字段');
|
||
print('📄 Config 内容: ${nodeListItem.config}');
|
||
_buildConfigFromFields(nodeListItem);
|
||
return;
|
||
}
|
||
switch (nodeListItem.protocol) {
|
||
case "vless":
|
||
final securityConfig =
|
||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||
|
||
// 智能设置 server_name
|
||
String serverName = securityConfig["sni"] ?? "";
|
||
if (serverName.isEmpty) {
|
||
serverName = nodeListItem.serverAddr;
|
||
}
|
||
|
||
config = {
|
||
"type": "vless",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": json["port"],
|
||
"uuid": nodeListItem.uuid,
|
||
if (json["flow"] != null && json["flow"] != "none")
|
||
"flow": json["flow"],
|
||
if (json["transport"] != null && json["transport"] != "tcp")
|
||
"transport": _buildTransport(json),
|
||
"tls": {
|
||
"enabled": json["security"] == "tls",
|
||
"server_name": serverName,
|
||
"insecure": securityConfig["allow_insecure"] ?? true,
|
||
"utls": {
|
||
"enabled": true,
|
||
"fingerprint": securityConfig["fingerprint"] ?? "chrome"
|
||
}
|
||
}
|
||
};
|
||
break;
|
||
case "vmess":
|
||
final securityConfig =
|
||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||
|
||
// 智能设置 server_name
|
||
String serverName = securityConfig["sni"] ?? "";
|
||
if (serverName.isEmpty) {
|
||
serverName = nodeListItem.serverAddr;
|
||
}
|
||
|
||
config = {
|
||
"type": "vmess",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": json["port"],
|
||
"uuid": nodeListItem.uuid,
|
||
"alter_id": 0,
|
||
"security": "auto",
|
||
if (json["transport"] != null && json["transport"] != "tcp")
|
||
"transport": _buildTransport(json),
|
||
"tls": {
|
||
"enabled": json["security"] == "tls",
|
||
"server_name": serverName,
|
||
"insecure": securityConfig["allow_insecure"] ?? true,
|
||
"utls": {"enabled": true, "fingerprint": "chrome"}
|
||
}
|
||
};
|
||
break;
|
||
case "shadowsocks":
|
||
config = {
|
||
"type": "shadowsocks",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": json["port"],
|
||
"method": json["method"],
|
||
"password": nodeListItem.uuid
|
||
};
|
||
break;
|
||
case "hysteria2":
|
||
final securityConfig =
|
||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||
config = {
|
||
"type": "hysteria2",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": json["port"],
|
||
"password": nodeListItem.uuid,
|
||
"up_mbps": 100,
|
||
"down_mbps": 100,
|
||
"obfs": {
|
||
"type": "salamander",
|
||
"password": json["obfs_password"] ?? nodeListItem.uuid
|
||
},
|
||
"tls": {
|
||
"enabled": true,
|
||
"server_name": securityConfig["sni"] ?? "",
|
||
"insecure": securityConfig["allow_insecure"] ?? true,
|
||
"alpn": ["h3"]
|
||
}
|
||
};
|
||
break;
|
||
case "trojan":
|
||
final securityConfig =
|
||
json["security_config"] as Map<String, dynamic>? ?? {};
|
||
|
||
// 智能设置 server_name
|
||
String serverName = securityConfig["sni"] ?? "";
|
||
if (serverName.isEmpty) {
|
||
// 如果没有配置 SNI,使用服务器地址
|
||
serverName = nodeListItem.serverAddr;
|
||
}
|
||
|
||
config = {
|
||
"type": "trojan",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": json["port"],
|
||
"password": nodeListItem.uuid,
|
||
"tls": {
|
||
"enabled": json["security"] == "tls",
|
||
"server_name": serverName,
|
||
"insecure": securityConfig["allow_insecure"] ?? true,
|
||
"utls": {"enabled": true, "fingerprint": "chrome"}
|
||
}
|
||
};
|
||
break;
|
||
}
|
||
|
||
// 检查 relayNode 是否为 JSON 字符串并解析
|
||
if (nodeListItem.relayNode.isNotEmpty && nodeListItem.relayMode != "none") {
|
||
final relayNodeJson = jsonDecode(nodeListItem.relayNode);
|
||
if (relayNodeJson is List && nodeListItem.relayMode != "none") {
|
||
// 随机选择一个元素
|
||
final randomNode = (relayNodeJson..shuffle()).first;
|
||
config["server"] = randomNode["host"]; // 提取 host
|
||
config["server_port"] = randomNode["port"]; // 提取 port
|
||
}
|
||
}
|
||
// 解析配置
|
||
}
|
||
|
||
/// 构建传输配置
|
||
Map<String, dynamic> _buildTransport(Map<String, dynamic> json) {
|
||
final transportType = json["transport"] as String?;
|
||
final transportConfig =
|
||
json["transport_config"] as Map<String, dynamic>? ?? {};
|
||
|
||
switch (transportType) {
|
||
case "ws":
|
||
return {
|
||
"type": "ws",
|
||
"path": transportConfig["path"] ?? "/",
|
||
if (transportConfig["host"] != null)
|
||
"headers": {"Host": transportConfig["host"]}
|
||
};
|
||
case "grpc":
|
||
return {
|
||
"type": "grpc",
|
||
"service_name": transportConfig["service_name"] ?? ""
|
||
};
|
||
case "http":
|
||
return {
|
||
"type": "http",
|
||
"host": [transportConfig["host"] ?? ""],
|
||
"path": transportConfig["path"] ?? "/"
|
||
};
|
||
default:
|
||
return {};
|
||
}
|
||
}
|
||
|
||
/// 直接从节点字段构建配置(新API格式)
|
||
void _buildConfigFromFields(KrNodeListItem nodeListItem) {
|
||
print('🔧 开始构建节点配置 - 协议: ${nodeListItem.protocol}, 名称: ${nodeListItem.name}');
|
||
print('📋 节点详细信息:');
|
||
print(' - serverAddr: ${nodeListItem.serverAddr}');
|
||
print(' - port: ${nodeListItem.port}');
|
||
print(' - uuid: ${nodeListItem.uuid}');
|
||
print(' - method: ${nodeListItem.method}');
|
||
|
||
switch (nodeListItem.protocol) {
|
||
case "shadowsocks":
|
||
// 优先使用 protocols 解析出来的 cipher,其次是 method 字段,最后才是默认值
|
||
String finalMethod = nodeListItem.method.isNotEmpty
|
||
? nodeListItem.method
|
||
: "2022-blake3-aes-256-gcm";
|
||
|
||
config = {
|
||
"type": "shadowsocks",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": nodeListItem.port,
|
||
"method": finalMethod,
|
||
"password": nodeListItem.uuid
|
||
};
|
||
print('✅ Shadowsocks 节点配置构建成功: ${nodeListItem.name}');
|
||
print('📄 使用加密方法: $finalMethod');
|
||
print('📄 完整配置: $config');
|
||
break;
|
||
case "vless":
|
||
config = {
|
||
"type": "vless",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": nodeListItem.port,
|
||
"uuid": nodeListItem.uuid,
|
||
"tls": {
|
||
"enabled": true,
|
||
"server_name": nodeListItem.serverAddr,
|
||
"insecure": true,
|
||
"utls": {
|
||
"enabled": true,
|
||
"fingerprint": "chrome"
|
||
}
|
||
}
|
||
};
|
||
print('✅ VLESS 节点配置构建成功: ${nodeListItem.name}');
|
||
print('📄 完整配置: $config');
|
||
break;
|
||
case "vmess":
|
||
config = {
|
||
"type": "vmess",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": nodeListItem.port,
|
||
"uuid": nodeListItem.uuid,
|
||
"alter_id": 0,
|
||
"security": "auto",
|
||
"tls": {
|
||
"enabled": true,
|
||
"server_name": nodeListItem.serverAddr,
|
||
"insecure": true,
|
||
"utls": {"enabled": true, "fingerprint": "chrome"}
|
||
}
|
||
};
|
||
print('✅ VMess 节点配置构建成功: ${nodeListItem.name}');
|
||
print('📄 完整配置: $config');
|
||
break;
|
||
case "trojan":
|
||
config = {
|
||
"type": "trojan",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": nodeListItem.port,
|
||
"password": nodeListItem.uuid,
|
||
"tls": {
|
||
"enabled": true,
|
||
"server_name": nodeListItem.serverAddr,
|
||
"insecure": true,
|
||
"utls": {"enabled": true, "fingerprint": "chrome"}
|
||
}
|
||
};
|
||
print('✅ Trojan 节点配置构建成功: ${nodeListItem.name}');
|
||
print('📄 完整配置: $config');
|
||
break;
|
||
case "hysteria":
|
||
config = {
|
||
"type": "hysteria",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": nodeListItem.port,
|
||
"up_mbps": 100,
|
||
"down_mbps": 100,
|
||
"auth_str": nodeListItem.uuid,
|
||
"tls": {
|
||
"enabled": true,
|
||
"server_name": nodeListItem.serverAddr,
|
||
"insecure": true,
|
||
"alpn": ["h3"]
|
||
}
|
||
};
|
||
print('✅ Hysteria 节点配置构建成功: ${nodeListItem.name}');
|
||
print('📄 完整配置: $config');
|
||
break;
|
||
case "hysteria2":
|
||
config = {
|
||
"type": "hysteria2",
|
||
"tag": nodeListItem.name,
|
||
"server": nodeListItem.serverAddr,
|
||
"server_port": nodeListItem.port,
|
||
"password": nodeListItem.uuid,
|
||
"up_mbps": 100,
|
||
"down_mbps": 100,
|
||
"tls": {
|
||
"enabled": true,
|
||
"server_name": nodeListItem.serverAddr,
|
||
"insecure": true,
|
||
"alpn": ["h3"]
|
||
}
|
||
};
|
||
print('✅ Hysteria2 节点配置构建成功: ${nodeListItem.name}');
|
||
print('📄 完整配置: $config');
|
||
break;
|
||
default:
|
||
print('⚠️ 不支持的协议类型: ${nodeListItem.protocol}');
|
||
config = {};
|
||
}
|
||
}
|
||
}
|