ViewController.swift 6.6 KB

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