mirror of
https://github.com/bolucat/Archive.git
synced 2025-12-24 13:28:37 +08:00
Update On Sat Jun 7 20:34:20 CEST 2025
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
// params的obfs=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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user