ViewController.swift 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. //
  2. // ViewController.swift
  3. // TunneledWebView
  4. //
  5. import UIKit
  6. import PsiphonTunnel
  7. class ViewController: UIViewController {
  8. var webView: UIWebView!
  9. // The instance of PsiphonTunnel we'll use for connecting.
  10. var psiphonTunnel: PsiphonTunnel?
  11. // This are the ports that we can proxy through.
  12. var socksProxyPort = -1
  13. var httpProxyPort = -1
  14. override func loadView() {
  15. // Make our whole view the webview.
  16. webView = UIWebView()
  17. view = webView
  18. self.psiphonTunnel = PsiphonTunnel.newPsiphonTunnel(self)
  19. }
  20. override func viewDidLoad() {
  21. super.viewDidLoad()
  22. // Do any additional setup after loading the view, typically from a nib.
  23. // Start up the tunnel and begin connecting.
  24. // This could be started elsewhere or earlier.
  25. NSLog("Starting tunnel")
  26. let embeddedServerEntries = ""
  27. guard let success = self.psiphonTunnel?.start(embeddedServerEntries), success else {
  28. NSLog("psiphonTunnel.start returned false")
  29. return
  30. }
  31. }
  32. override func didReceiveMemoryWarning() {
  33. super.didReceiveMemoryWarning()
  34. // Dispose of any resources that can be recreated.
  35. }
  36. }
  37. // MARK: TunneledAppDelegate implementation
  38. // See the protocol definition for details about the methods.
  39. // Note that we're excluding all the optional methods that we aren't using,
  40. // however your needs may be different.
  41. extension ViewController: TunneledAppDelegate {
  42. func getPsiphonConfig() -> String? {
  43. // In this example, we're going to retrieve our Psiphon config from a file in the app bundle.
  44. // Alternatively, it could be a string literal in the code, or whatever makes sense.
  45. guard let psiphonConfigUrl = Bundle.main.url(forResource: "psiphon-config", withExtension: "json") else {
  46. NSLog("Error getting Psiphon config resource file URL!")
  47. return nil
  48. }
  49. do {
  50. return try String.init(contentsOf: psiphonConfigUrl)
  51. } catch {
  52. NSLog("Error getting Psiphon config resource file URL!")
  53. return nil
  54. }
  55. }
  56. func onDiagnosticMessage(_ message: String) {
  57. NSLog("onDiagnosticMessage: %@", message)
  58. }
  59. func onConnected() {
  60. NSLog("onConnected")
  61. // After we're connected, make a tunneled request and populate the webview.
  62. DispatchQueue.main.async {
  63. assert(self.httpProxyPort > 0)
  64. // We'll check out IP to make sure we're tunneled.
  65. let urlPath: String = "https://freegeoip.net/csv/"
  66. let url = URL(string: urlPath)!
  67. let request = URLRequest(url: url)
  68. let config = URLSessionConfiguration.ephemeral
  69. config.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
  70. config.connectionProxyDictionary = [AnyHashable: Any]()
  71. // Enable and set the SOCKS proxy values.
  72. config.connectionProxyDictionary?[kCFStreamPropertySOCKSProxy as String] = 1
  73. config.connectionProxyDictionary?[kCFStreamPropertySOCKSProxyHost as String] = "127.0.0.1"
  74. config.connectionProxyDictionary?[kCFStreamPropertySOCKSProxyPort as String] = self.socksProxyPort
  75. // Alternatively, the HTTP proxy can be used. Below are the settings for that.
  76. // The HTTPS key constants are mismatched and Xcode gives deprecation warnings, but they seem to be necessary to proxy HTTPS requests. This is probably a bug on Apple's side; see: https://forums.developer.apple.com/thread/19356#131446
  77. // config.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] = 1
  78. // config.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] = "127.0.0.1"
  79. // config.connectionProxyDictionary?[kCFNetworkProxiesHTTPPort as String] = self.httpProxyPort
  80. // config.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyHost as String] = "127.0.0.1"
  81. // config.connectionProxyDictionary?[kCFStreamPropertyHTTPSProxyPort as String] = self.httpProxyPort
  82. let session = URLSession.init(configuration: config, delegate: nil, delegateQueue: OperationQueue.current)
  83. // Create the URLSession task that will make the request via the tunnel proxy.
  84. let task = session.dataTask(with: request) {
  85. (data: Data?, response: URLResponse?, error: Error?) in
  86. if error != nil {
  87. NSLog("Client-side error in request to \(urlPath): \(error)")
  88. return
  89. }
  90. let httpResponse = response as? HTTPURLResponse
  91. if httpResponse?.statusCode != 200 {
  92. NSLog("Server-side error in request to \(urlPath): \(httpResponse)")
  93. return
  94. }
  95. let encodingName = response?.textEncodingName != nil ? response?.textEncodingName : "utf-8"
  96. let encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName as CFString!))
  97. var stringData = String(data: data!, encoding: String.Encoding(rawValue: UInt(encoding)))
  98. stringData = stringData?.replacingOccurrences(of: ",", with: "\n")
  99. // Load the IP info result into the web view.
  100. self.webView.loadHTMLString("<br><pre>\(stringData!)</pre>", baseURL: url)
  101. // Make sure the session is cleaned up.
  102. session.invalidateAndCancel()
  103. // We're done with the Psiphon tunnel, so stop it.
  104. // In a real app, we would keep this alive for as long as we need it.
  105. self.psiphonTunnel?.stop()
  106. }
  107. // Start the request task.
  108. task.resume()
  109. }
  110. }
  111. func onListeningSocksProxyPort(_ port: Int) {
  112. NSLog("onListeningSocksProxyPort: %d", port)
  113. // Record the port being used so that we can proxy through it later.
  114. DispatchQueue.main.async {
  115. self.socksProxyPort = port
  116. }
  117. }
  118. func onListeningHttpProxyPort(_ port: Int) {
  119. NSLog("onListeningHttpProxyPort: %d", port)
  120. // Record the port being used so that we can proxy through it later.
  121. DispatchQueue.main.async {
  122. self.httpProxyPort = port
  123. }
  124. }
  125. }