From b8d2a80eef5cbcbf5c2fe276c8a20ca5aa0bdd60 Mon Sep 17 00:00:00 2001 From: "yuanxue.yang" Date: Sat, 24 Nov 2018 18:06:21 +0800 Subject: [PATCH] share qrcode --- Podfile | 2 +- Podfile.lock | 14 +- V2rayU.xcodeproj/project.pbxproj | 14 +- .../xcschemes/xcschememanagement.plist | 16 +- .../xcdebugger/Breakpoints_v2.xcbkptlist | 18 +++ V2rayU/ConfigWindow.swift | 37 +++-- V2rayU/MainMenu.swift | 78 +++++++--- V2rayU/QrcodeWindow.swift | 29 ++++ V2rayU/QrcodeWindow.xib | 45 ++++++ V2rayU/Scanner.swift | 138 ++++++++++++++++++ 10 files changed, 333 insertions(+), 58 deletions(-) create mode 100644 V2rayU/QrcodeWindow.swift create mode 100644 V2rayU/QrcodeWindow.xib diff --git a/Podfile b/Podfile index a10e4b2..fc9cfd5 100644 --- a/Podfile +++ b/Podfile @@ -12,6 +12,6 @@ target 'V2rayU' do pod 'SwiftyJSON' pod 'Preferences' pod 'Sparkle' - pod 'EFQRCode' + pod 'QRCoder' end diff --git a/Podfile.lock b/Podfile.lock index 07dc11c..702d06b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,36 +1,32 @@ PODS: - Alamofire (4.7.3) - - EFQRCode (4.4.2): - - swift_qrcodejs (~> 1.0.1) - Preferences (0.2.0) + - QRCoder (1.0.0) - Sparkle (1.20.0) - - swift_qrcodejs (1.0.1) - SwiftyJSON (4.2.0) DEPENDENCIES: - Alamofire - - EFQRCode - Preferences + - QRCoder - Sparkle - SwiftyJSON SPEC REPOS: https://github.com/cocoapods/specs.git: - Alamofire - - EFQRCode - Preferences + - QRCoder - Sparkle - - swift_qrcodejs - SwiftyJSON SPEC CHECKSUMS: Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568 - EFQRCode: e65a9eb6c7137ed6db4cfce37f0cee47938e44f0 Preferences: ebc036a176a298cde835155c73251173768a2f8d + QRCoder: 488f6869fb89ffcc3de3b4de2dabd200a6573f3c Sparkle: 48999e7ee032f05ca05e28451eadf4af8ede6b44 - swift_qrcodejs: c181fe5c849d30c699546a23762d7e3dd143ab37 SwiftyJSON: c4bcba26dd9ec7a027fc8eade48e2c911f229e96 -PODFILE CHECKSUM: fde745e82410567a545d4aa0c3f453959d468f5b +PODFILE CHECKSUM: c8bfc44adeae40100cae3f20ce703eaa6666d947 COCOAPODS: 1.6.0.beta.1 diff --git a/V2rayU.xcodeproj/project.pbxproj b/V2rayU.xcodeproj/project.pbxproj index 82aa767..71c4150 100644 --- a/V2rayU.xcodeproj/project.pbxproj +++ b/V2rayU.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 6608D9E22182C9C100A0E0DD /* v2rayStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6608D9E12182C9C100A0E0DD /* v2rayStream.swift */; }; 660C8CA22181CBAA00896361 /* V2rayUTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660C8CA12181CBAA00896361 /* V2rayUTests.swift */; }; 660D0E5A216E0158000C2922 /* V2rayServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660D0E59216E0158000C2922 /* V2rayServer.swift */; }; + 660F9A7521A94C7600AEB4F7 /* QrcodeWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 660F9A7421A94C7600AEB4F7 /* QrcodeWindow.xib */; }; 6610ECB721742AFD008FC401 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 664EB378216C9A5F00B6AE0D /* MainMenu.xib */; }; 66406AF42183320000B56041 /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66406AF32183320000B56041 /* Sample.swift */; }; 664EB375216C9A5E00B6AE0D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB374216C9A5E00B6AE0D /* AppDelegate.swift */; }; @@ -30,6 +31,7 @@ 66FEAD432179A969009DECF9 /* PreferenceGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66FEAD422179A969009DECF9 /* PreferenceGeneral.swift */; }; 66FEAD53217EE14C009DECF9 /* ConfigWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 66FEAD4E217EE14C009DECF9 /* ConfigWindow.xib */; }; 66FEAD54217EE14C009DECF9 /* PreferenceGeneral.xib in Resources */ = {isa = PBXBuildFile; fileRef = 66FEAD50217EE14C009DECF9 /* PreferenceGeneral.xib */; }; + 6D6DF2CF13D9FD3C7C6492A4 /* QrcodeWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF12EA09D2D80788666D0 /* QrcodeWindow.swift */; }; 6D6DF4711EE7CB7CA552CC89 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF04B14482D1536ADDA7D /* Test.swift */; }; 6D6DF6AEAA13C0DB0065BE3B /* Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF821D34F8B06A62F1936 /* Authorization.swift */; }; 6D6DF6F065067CD879201FF9 /* Scanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF87840CDA04AF0E9D36E /* Scanner.swift */; }; @@ -74,6 +76,7 @@ 660C8CA12181CBAA00896361 /* V2rayUTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = V2rayUTests.swift; sourceTree = ""; }; 660C8CA32181CBAA00896361 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 660D0E59216E0158000C2922 /* V2rayServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = V2rayServer.swift; sourceTree = ""; usesTabs = 0; wrapsLines = 0; }; + 660F9A7421A94C7600AEB4F7 /* QrcodeWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = QrcodeWindow.xib; sourceTree = ""; }; 66406AF32183320000B56041 /* Sample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sample.swift; sourceTree = ""; }; 664B95DD217062A500DBC941 /* Alamofire */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Alamofire; path = Pods/Alamofire; sourceTree = ""; }; 664EB371216C9A5E00B6AE0D /* V2rayU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = V2rayU.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -96,6 +99,7 @@ 66FEAD4F217EE14C009DECF9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ConfigWindow.xib; sourceTree = ""; }; 66FEAD51217EE14C009DECF9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferenceGeneral.xib; sourceTree = ""; }; 6D6DF04B14482D1536ADDA7D /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; + 6D6DF12EA09D2D80788666D0 /* QrcodeWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QrcodeWindow.swift; sourceTree = ""; }; 6D6DF821D34F8B06A62F1936 /* Authorization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Authorization.swift; sourceTree = ""; }; 6D6DF87840CDA04AF0E9D36E /* Scanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scanner.swift; sourceTree = ""; }; 6D6DFD9F5991B38B128888D6 /* V2rayConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = V2rayConfig.swift; sourceTree = ""; }; @@ -208,6 +212,8 @@ 6D6DF821D34F8B06A62F1936 /* Authorization.swift */, 6D6DF87840CDA04AF0E9D36E /* Scanner.swift */, 664EB37B216C9A5F00B6AE0D /* Info.plist */, + 660F9A7421A94C7600AEB4F7 /* QrcodeWindow.xib */, + 6D6DF12EA09D2D80788666D0 /* QrcodeWindow.swift */, ); path = V2rayU; sourceTree = ""; @@ -373,6 +379,7 @@ 66FEAD54217EE14C009DECF9 /* PreferenceGeneral.xib in Resources */, 664EB377216C9A5F00B6AE0D /* Assets.xcassets in Resources */, 66FEAD53217EE14C009DECF9 /* ConfigWindow.xib in Resources */, + 660F9A7521A94C7600AEB4F7 /* QrcodeWindow.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -389,22 +396,20 @@ inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-V2rayU/Pods-V2rayU-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", - "${BUILT_PRODUCTS_DIR}/EFQRCode/EFQRCode.framework", "${BUILT_PRODUCTS_DIR}/Preferences/Preferences.framework", + "${BUILT_PRODUCTS_DIR}/QRCoder/QRCoder.framework", "${PODS_ROOT}/Sparkle/Sparkle.framework", "${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework", - "${BUILT_PRODUCTS_DIR}/swift_qrcodejs/swift_qrcodejs.framework", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( ); outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/EFQRCode.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Preferences.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/QRCoder.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sparkle.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/swift_qrcodejs.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -473,6 +478,7 @@ 6D6DF6AEAA13C0DB0065BE3B /* Authorization.swift in Sources */, 6D6DF6F065067CD879201FF9 /* Scanner.swift in Sources */, 6D6DF4711EE7CB7CA552CC89 /* Test.swift in Sources */, + 6D6DF2CF13D9FD3C7C6492A4 /* QrcodeWindow.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/V2rayU.xcodeproj/xcuserdata/yanue.xcuserdatad/xcschemes/xcschememanagement.plist b/V2rayU.xcodeproj/xcuserdata/yanue.xcuserdatad/xcschemes/xcschememanagement.plist index 5eb6c9b..218b5f2 100644 --- a/V2rayU.xcodeproj/xcuserdata/yanue.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/V2rayU.xcodeproj/xcuserdata/yanue.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ Launcher.xcscheme orderHint - 8 + 11 V2rayU.xcscheme @@ -17,17 +17,17 @@ V2rayUHelper.xcscheme orderHint - 13 + 17 V2rayULauncher.xcscheme orderHint - 20 + 21 V2rayULauncher.xcscheme_^#shared#^_ orderHint - 17 + 18 V2rayUTests.test.xcscheme @@ -39,7 +39,7 @@ isShown orderHint - 12 + 13 V2rayUTests.testDecodeVmess.xcscheme @@ -60,17 +60,17 @@ isShown orderHint - 5 + 7 V2rayuHelper.xcscheme orderHint - 18 + 19 proxyHelper.xcscheme_^#shared#^_ orderHint - 19 + 20 diff --git a/V2rayU.xcworkspace/xcuserdata/yanue.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/V2rayU.xcworkspace/xcuserdata/yanue.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index ed9a9b4..d121c01 100644 --- a/V2rayU.xcworkspace/xcuserdata/yanue.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/V2rayU.xcworkspace/xcuserdata/yanue.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,4 +2,22 @@ + + + + + + diff --git a/V2rayU/ConfigWindow.swift b/V2rayU/ConfigWindow.swift index c6bc200..4591c60 100644 --- a/V2rayU/ConfigWindow.swift +++ b/V2rayU/ConfigWindow.swift @@ -7,7 +7,6 @@ // import Cocoa -import WebKit import Alamofire class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDelegate { @@ -430,16 +429,20 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel let errMsg = V2rayServer.save(idx: self.serversTableView.selectedRow, isValid: self.v2rayConfig.isValid, jsonData: text) self.errTip.stringValue = errMsg + self.refreshServerList(ok: errMsg.count > 0) + } + + func refreshServerList(ok: Bool = true) { // refresh menu menuController.showServers() // if server is current if let curName = UserDefaults.get(forKey: .v2rayCurrentServerName) { let v2rayItemList = V2rayServer.list() if curName == v2rayItemList[self.serversTableView.selectedRow].name { - if errMsg != "" { - menuController.stopV2rayCore() - } else { + if ok { menuController.startV2rayCore() + } else { + menuController.stopV2rayCore() } } } @@ -481,6 +484,20 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel self.importJson() } + func saveImport(importUri: ImportUri) { + if importUri.isValid { + self.configText.string = importUri.json + if importUri.remark.count > 0 { + V2rayServer.edit(rowIndex: self.serversTableView.selectedRow, remark: importUri.remark) + } + + // refresh + self.refreshServerList(ok: true) + } else { + self.errTip.stringValue = importUri.error + } + } + func importJson() { let text = self.configText.string let uri = jsonUrl.stringValue.trimmingCharacters(in: .whitespaces) @@ -489,19 +506,11 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel if uri.contains("vmess://") { let importUri = ImportUri() importUri.importVmessUri(uri: uri) - if importUri.isValid { - self.configText.string = importUri.json - } else { - self.errTip.stringValue = importUri.error - } + self.saveImport(importUri: importUri) } else if uri.contains("ss://") { let importUri = ImportUri() importUri.importSSUri(uri: uri) - if importUri.isValid { - self.configText.string = importUri.json - } else { - self.errTip.stringValue = importUri.error - } + self.saveImport(importUri: importUri) } else { // download json file Alamofire.request(jsonUrl.stringValue).responseString { DataResponse in diff --git a/V2rayU/MainMenu.swift b/V2rayU/MainMenu.swift index d6f90cb..c49b3cb 100644 --- a/V2rayU/MainMenu.swift +++ b/V2rayU/MainMenu.swift @@ -56,6 +56,7 @@ class MenuController: NSObject, NSMenuDelegate { statusItem.menu = statusMenu configWindow = ConfigWindowController() + if UserDefaults.getBool(forKey: .v2rayTurnOn) { // start // on status @@ -291,13 +292,33 @@ class MenuController: NSObject, NSMenuDelegate { V2rayLaunch.setSystemProxy(enabled: true, httpPort: httpPort, sockPort: sockPort) } + @IBAction func generateQrcode(_ sender: NSMenuItem) { + guard let v2ray = V2rayServer.loadSelectedItem() else { + NSLog("v2ray config not found") + self.notice(title: "generate Qrcode fail", subtitle: "", informativeText: "no available servers") + return + } + + let share = ShareUri() + share.qrcode(item: v2ray) + if share.error.count > 0 { + self.notice(title: "generate Qrcode fail", subtitle: "", informativeText: share.error) + return + } + + let qrcodeWindow = QrcodeWindowController() + qrcodeWindow.showWindow(nil) + qrcodeWindow.setShareUri(uri: share.uri) + // bring to front + NSApp.activate(ignoringOtherApps: true) + } + @IBAction func scanQrcode(_ sender: NSMenuItem) { let uri: String = Scanner.scanQRCodeFromScreen() - print("scanQrcode", uri) if uri.count > 0 { self.importUri(url: uri) } else { - print("not found") + self.notice(title: "import server fail", subtitle: "", informativeText: "no found qrcode") } } @@ -305,44 +326,57 @@ class MenuController: NSObject, NSMenuDelegate { if let uri = NSPasteboard.general.string(forType: .string), uri.count > 0 { self.importUri(url: uri) } else { - print("not found") + self.notice(title: "import server fail", subtitle: "", informativeText: "no found ss:// or vmess:// from Pasteboard") } } - @IBAction func generateQrcode(_ sender: NSMenuItem) { - print("generateQrcode") - } - func importUri(url: String) { let uri = url.trimmingCharacters(in: .whitespaces) if uri.count == 0 { - print("import error: uri not found") + self.notice(title: "import server fail", subtitle: "", informativeText: "import error: uri not found") return } if uri.contains("ss://") && URL(string: uri) != nil { let importUri = ImportUri() importUri.importSSUri(uri: uri) - if importUri.isValid { - V2rayServer.add(remark: importUri.remark, json: importUri.json, isValid: true, url: uri) - // todo tip - // todo refresh server list - } else { - print("import error", importUri.error) - } + self.saveServer(importUri: importUri) + return } if uri.contains("vmess://") && URL(string: uri) != nil { let importUri = ImportUri() importUri.importVmessUri(uri: uri) - if importUri.isValid { - V2rayServer.add(remark: importUri.remark, json: importUri.json, isValid: true, url: uri) - // todo tip - // todo refresh server list - } else { - print("import error", importUri.error) - } + self.saveServer(importUri: importUri) + return + } + + self.notice(title: "import server fail", subtitle: "", informativeText: "no found ss:// or vmess://") + } + + func notice(title: String = "", subtitle: String = "", informativeText: String = "") { + // 定义NSUserNotification + let userNotification = NSUserNotification() + userNotification.title = title + userNotification.subtitle = subtitle + userNotification.informativeText = informativeText + // 使用NSUserNotificationCenter发送NSUserNotification + let userNotificationCenter = NSUserNotificationCenter.default + userNotificationCenter.scheduleNotification(userNotification) + } + + func saveServer(importUri: ImportUri) { + if importUri.isValid { + // add server + V2rayServer.add(remark: importUri.remark, json: importUri.json, isValid: true, url: importUri.uri) + // refresh server + self.showServers() + + self.notice(title: "import server success", subtitle: "", informativeText: importUri.remark) + } else { + self.notice(title: "import server fail", subtitle: "", informativeText: importUri.error) } } + } diff --git a/V2rayU/QrcodeWindow.swift b/V2rayU/QrcodeWindow.swift new file mode 100644 index 0000000..59de2a8 --- /dev/null +++ b/V2rayU/QrcodeWindow.swift @@ -0,0 +1,29 @@ +// +// Created by yanue on 2018/11/24. +// Copyright (c) 2018 yanue. All rights reserved. +// + +import Foundation +import Cocoa +import QRCoder + +class QrcodeWindowController: NSWindowController { + override var windowNibName: String? { + return "QrcodeWindow" // no extension .xib here + } + @IBOutlet weak var shareUri: NSTextField! + @IBOutlet weak var shareQrcode: NSImageView! + + override func awakeFromNib() { + } + + override func windowDidLoad() { + super.windowDidLoad() + } + + func setShareUri(uri: String) { + self.shareUri.stringValue = uri + let generator = QRCodeGenerator() + shareQrcode.image = generator.createImage(value: uri, size: CGSize(width: 256, height: 256)) + } +} diff --git a/V2rayU/QrcodeWindow.xib b/V2rayU/QrcodeWindow.xib new file mode 100644 index 0000000..feac95e --- /dev/null +++ b/V2rayU/QrcodeWindow.xib @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/V2rayU/Scanner.swift b/V2rayU/Scanner.swift index ec88f99..3863e43 100644 --- a/V2rayU/Scanner.swift +++ b/V2rayU/Scanner.swift @@ -8,13 +8,133 @@ import CoreGraphics import CoreImage import SwiftyJSON +struct VmessShare: Codable { + var v: String = "2" + var ps: String = "" + var add: String = "" + var port: String = "" + var id: String = "" + var aid: String = "" + var net: String = "" + var type: String = "none" + var host: String = "" + var path: String = "" + var tls: String = "none" +} + +class ShareUri { + var error = "" + var remark = "" + var uri: String = "" + var v2ray = V2rayConfig() + var share = VmessShare() + + func qrcode(item: V2rayItem) { + v2ray.parseJson(jsonText: item.json) + if !v2ray.isValid { + self.error = v2ray.errors[0] + return + } + + self.remark = item.remark + + if v2ray.serverProtocol == V2rayProtocolOutbound.vmess.rawValue { + self.genVmessUri() + + let encoder = JSONEncoder() + if let data = try? encoder.encode(self.share) { + let uri = String(data: data, encoding: .utf8)! + self.uri = "vmess://" + uri.base64Encoded()! + print("vmess", self.uri) + } else { + self.error = "encode uri error" + } + return + } + + if v2ray.serverProtocol == V2rayProtocolOutbound.shadowsocks.rawValue { + print("share shadowsocks") + self.genShadowsocksUri() + return + } + + self.error = "not support" + } + + /**s + 分享的链接(二维码)格式:vmess://(Base64编码的json格式服务器数据 + json数据如下 + { + "v": "2", + "ps": "备注别名", + "add": "111.111.111.111", + "port": "32000", + "id": "1386f85e-657b-4d6e-9d56-78badb75e1fd", + "aid": "100", + "net": "tcp", + "type": "none", + "host": "www.bbb.com", + "path": "/", + "tls": "tls" + } + v:配置文件版本号,主要用来识别当前配置 + net :传输协议(tcp\kcp\ws\h2) + type:伪装类型(none\http\srtp\utp\wechat-video) + host:伪装的域名 + 1)http host中间逗号(,)隔开 + 2)ws host + 3)h2 host + path:path(ws/h2) + tls:底层传输安全(tls) + */ + private func genVmessUri() { + self.share.add = self.v2ray.serverVmess.address + self.share.ps = self.remark + self.share.port = String(self.v2ray.serverVmess.port) + self.share.id = self.v2ray.serverVmess.users[0].id + self.share.aid = String(self.v2ray.serverVmess.users[0].alterId) + self.share.net = self.v2ray.streamNetwork + + if self.v2ray.streamNetwork == "h2" { + self.share.host = self.v2ray.streamH2.host[0] + self.share.path = self.v2ray.streamH2.path + } + + if self.v2ray.streamNetwork == "ws" { + self.share.host = self.v2ray.streamWs.headers.host + self.share.path = self.v2ray.streamWs.path + } + + self.share.tls = self.v2ray.streamTlsSecurity + } + + // Shadowsocks + func genShadowsocksUri() { + var ss = ShadowsockUri() + ss.host = self.v2ray.serverShadowsocks.address + ss.port = self.v2ray.serverShadowsocks.port + ss.password = self.v2ray.serverShadowsocks.password + ss.method = self.v2ray.serverShadowsocks.method + ss.remark = self.remark + self.uri = ss.encode() + self.error = ss.error + } +} + class ImportUri { var isValid: Bool = false var json: String = "" var remark: String = "" var error: String = "" + var uri: String = "" func importSSUri(uri: String) { + if URL(string: uri) == nil { + self.error = "invail ss url" + return + } + self.uri = uri + let ss = ShadowsockUri() ss.Init(url: URL(string: uri)!) if ss.error.count > 0 { @@ -44,6 +164,12 @@ class ImportUri { } func importVmessUri(uri: String) { + if URL(string: uri) == nil { + self.error = "invail vmess url" + return + } + self.uri = uri + var vmess = VmessUri() vmess.parseType2(url: URL(string: uri)!) if vmess.error.count > 0 { @@ -290,6 +416,7 @@ class VmessUri { self.tls = json["tls"].stringValue // type:伪装类型(none\http\srtp\utp\wechat-video) self.type = json["type"].stringValue + print("json", json) } } @@ -304,6 +431,17 @@ class ShadowsockUri { var error: String = "" + // ss://bf-cfb:test@192.168.100.1:8888#remark + func encode() -> String { + let base64 = self.method + ":" + self.password + "@" + self.host + ":" + String(self.port) + var ss = base64.base64Encoded() + if ss != nil { + return "ss://" + ss! + "#" + self.remark + } + self.error = "encode base64 fail" + return "" + } + func Init(url: URL) { let (_decodedUrl, _tag) = self.decodeUrl(url: url) guard let decodedUrl = _decodedUrl else {