Update On Sat Jun 7 20:34:20 CEST 2025

This commit is contained in:
github-action[bot]
2025-06-07 20:34:21 +02:00
parent ea0afe0bab
commit 0b80ee18cf
181 changed files with 2047 additions and 4156 deletions

View File

@@ -121,6 +121,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if UserDefaults.get(forKey: .runMode) == nil {
UserDefaults.set(forKey: .runMode, value: RunMode.global.rawValue)
}
if UserDefaults.get(forKey: .autoClearLog) == nil {
UserDefaults.setBool(forKey: .autoClearLog, value: true)
}
//
V2rayLaunch.clearLogFile()
V2rayServer.loadConfig()
V2rayRoutings.loadConfig()
V2raySubscription.loadConfig()
@@ -155,6 +161,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if UserDefaults.getBool(forKey: .autoUpdateServers) {
V2raySubSync.shared.sync()
}
// auto clear log
if UserDefaults.getBool(forKey: .autoClearLog) {
V2rayLaunch.truncateLogFile()
}
// ping
ping.pingAll()
}

View File

@@ -181,7 +181,39 @@ class ShareUri {
ss.port = self.v2ray.serverTrojan.port
ss.password = self.v2ray.serverTrojan.password
ss.remark = self.remark
ss.security = "tls"
ss.security = self.v2ray.streamSecurity
ss.network = self.v2ray.streamNetwork
if self.v2ray.streamNetwork == "tcp" {
ss.headerType = self.v2ray.streamTcp.header.type
if self.v2ray.streamTcp.header.type == "http" {
if let req = self.v2ray.streamTcp.header.request {
if req.path.count > 0 {
ss.path = req.path[0]
}
if req.headers.host.count>0 {
ss.host = req.headers.host[0]
}
}
}
} else if self.v2ray.streamNetwork == "kcp" {
ss.headerType = self.v2ray.streamKcp.header.type
ss.netPath = self.v2ray.streamKcp.seed
} else if self.v2ray.streamNetwork == "quic" {
ss.headerType = self.v2ray.streamQuic.header.type
ss.netPath = self.v2ray.streamQuic.key
} else if self.v2ray.streamNetwork == "domainsocket" {
ss.netPath = self.v2ray.streamDs.path
} else if self.v2ray.streamNetwork == "h2" {
if self.v2ray.streamH2.host.count > 0 {
ss.netHost = self.v2ray.streamH2.host[0]
}
ss.netPath = self.v2ray.streamH2.path
} else if self.v2ray.streamNetwork == "ws" {
ss.netHost = self.v2ray.streamWs.headers.host
ss.netPath = self.v2ray.streamWs.path
} else if self.v2ray.streamNetwork == "grpc" {
ss.netPath = self.v2ray.streamGrpc.serviceName
}
ss.fp = self.v2ray.securityTls.fingerprint
ss.flow = self.v2ray.serverTrojan.flow
ss.sni = self.v2ray.securityTls.serverName

View File

@@ -152,8 +152,64 @@ class VmessUri {
break
case "mode":
self.grpcMode = param[1]
break
case "seed":
self.kcpSeed = param[1]
break
// shadowrocket :
// remarks=vmess_ws&obfsParam=ws.host.domain&path=/vmwss&obfs=websocket&tls=1&peer=ws.sni.domain&alterId=64
case "obfs":
// ws
if param[1] == "websocket" || param[1] == "ws" {
self.network = "ws"
} else if param[1] == "h2" {
self.network = "h2"
} else if param[1] == "http" {
self.network = "tcp" //
self.type = "http" // headerType
} else if param[1] == "grpc" {
self.network = "grpc"
} else if param[1] == "domainsocket" {
self.network = "domainsocket"
} else if param[1] == "quic" {
self.network = "quic"
} else if param[1] == "kcp" || param[1] == "mkcp" {
self.network = "kcp"
} else {
self.network = "tcp"
self.type = param[1]
}
break
case "alterId":
// alterId
self.alterId = Int(param[1]) ?? 0
break
case "obfsParam":
// ws,h2 host
self.netHost = param[1]
// paramsobfs=mkcp, kcp seed: obfsParam=%7B%22seed%22:%22111%22,%22Host%22:%22xxx.xx%22%7D
if paramsStr.contains("obfs=mkcp") || paramsStr.contains("obfs=kcp") || paramsStr.contains("obfs=grpc") {
// urldecode, kcp seed: {"seed":"111","Host":""}
if let decodedParam = param[1].removingPercentEncoding, let data = decodedParam.data(using: .utf8) {
if let json = try? JSON(data: data) {
self.kcpSeed = json["seed"].stringValue
self.netHost = json["Host"].stringValue
}
}
}
break
case "path":
// ws,h2 path, tcp header path
self.netPath = param[1]
break
case "remarks":
//
self.remark = param[1].urlDecoded()
break
case "peer":
// sni
self.sni = param[1]
break
default:
break
}
@@ -436,7 +492,7 @@ class TrojanUri {
func encode() -> String {
var uri = URLComponents()
uri.scheme = "trojan"
uri.password = self.password
uri.user = self.password // user password, :
uri.host = self.host
uri.port = self.port
uri.queryItems = [
@@ -462,10 +518,15 @@ class TrojanUri {
self.error = "error:missing port"
return
}
guard let password = url.user else {
guard var password = url.user else {
self.error = "error:missing password"
return
}
// shadowrocket trojan url: trojan://%3Apassword@host:port?query#remark
if url.absoluteString.contains("trojan://%3A") {
// %3A,:
password = password.replacingOccurrences(of: "%3A", with: "").replacingOccurrences(of: ":", with: "")
}
self.host = host
self.port = Int(port)
self.password = password
@@ -499,6 +560,69 @@ class TrojanUri {
case "headerType":
self.headerType = item.value as! String
break
// shadowrocket :
// peer=sni.xx.xx&obfs=grpc&obfsParam=hjfjkdkdi&path=tekdjjd#yanue-trojan1
// ?peer=sni.xx.xx&plugin=obfs-local;obfs=websocket;obfs-host=%7B%22Host%22:%22hjfjkdkdi%22%7D;obfs-uri=tekdjjd#trojan3
case "plugin":
// obfs-local : obfs-local;obfs=websocket;obfs-host={"Host":"hjfjkdkdi"};obfs-uri=tekdjjd
let value = item.value as! String
print("trojan plugin:", value)
// ;
let plugins = value.components(separatedBy: ";")
for plugin in plugins {
let pluginParts = plugin.components(separatedBy: "=")
if pluginParts.count < 2 {
continue
}
switch pluginParts[0] {
case "obfs":
// ws
if pluginParts[1] == "websocket" || pluginParts[1] == "ws" {
self.network = "ws"
} else if pluginParts[1] == "h2" {
self.network = "h2"
} else if pluginParts[1] == "grpc" {
self.network = "grpc"
} else {
self.network = "tcp"
}
case "obfs-host":
// ws,h2 host: {"Host":"hjfjkdkdi"}
if let hostValue = pluginParts[1].removingPercentEncoding,let data = hostValue.data(using: .utf8) {
if let json = try? JSON(data: data) {
self.netHost = json["Host"].stringValue
}
}
case "obfs-uri":
// ws,h2 path
self.netPath = pluginParts[1]
default:
break
}
}
break
case "obfs":
let value = item.value as! String
print("trojan obfs:", value)
// ws
if value == "websocket" || value == "ws" {
self.network = "ws"
} else if value == "h2" {
self.network = "h2"
} else if value == "grpc" {
self.network = "grpc"
} else {
self.network = "tcp"
}
break
case "obfsParam":
// ws,h2 host
self.netHost = item.value as! String
break
case "peer":
// sni
self.sni = item.value as! String
break
default:
break
}

View File

@@ -444,4 +444,44 @@ class V2rayLaunch: NSObject {
NSLog("save json file fail: \(error)")
}
}
// clear v2ray-core.log file
static func clearLogFile() {
let logFile = URL(fileURLWithPath: logFilePath)
do {
if FileManager.default.fileExists(atPath: logFilePath) {
try FileManager.default.removeItem(at: logFile)
}
// create new file
FileManager.default.createFile(atPath: logFilePath, contents: nil, attributes: nil)
} catch let error {
NSLog("clear log file fail: \(error)")
var title = "Clear log file failed"
var toast = "Error: \(error)"
if isMainland {
title = "清除日志文件失败"
toast = "错误: \(error)"
}
alertDialog(title: title, message: toast)
}
}
static func truncateLogFile() {
let logFile = URL(fileURLWithPath: logFilePath)
do {
if FileManager.default.fileExists(atPath: logFilePath) {
// truncate log file, write empty string
try "".write(to: logFile, atomically: true, encoding: String.Encoding.utf8)
}
} catch let error {
NSLog("truncate log file fail: \(error)")
var title = "Truncate log file failed"
var toast = "Error: \(error)"
if isMainland {
title = "清除日志文件失败"
toast = "错误: \(error)"
}
alertDialog(title: title, message: toast)
}
}
}