Implement a Ouinet proxy with its own Trust Manager
This commit is contained in:
parent
246e675fd6
commit
a782b65fbc
|
@ -1,14 +1,44 @@
|
|||
package ie.equalit.ouinet_examples.android_kotlin
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import ie.equalit.ouinet.Config
|
||||
import ie.equalit.ouinet.Ouinet
|
||||
import okhttp3.*
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
import java.security.*
|
||||
import java.security.cert.Certificate
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.CertificateFactory
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.concurrent.Executors
|
||||
import javax.net.ssl.*
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var ouinet: Ouinet
|
||||
lateinit var ouinetDir: String
|
||||
private val TAG = "OuinetTester"
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
val get = findViewById<Button>(R.id.get)
|
||||
get.setOnClickListener{ getURL(get) }
|
||||
|
||||
var config = Config.ConfigBuilder(this)
|
||||
.setCacheType("bep5-http")
|
||||
.setTlsCaCertStorePath("file:///android_asset/cacert.pem")
|
||||
|
@ -16,5 +46,170 @@ class MainActivity : AppCompatActivity() {
|
|||
.setInjectorCredentials(BuildConfig.INJECTOR_CREDENTIALS)
|
||||
.setInjectorTlsCert(BuildConfig.INJECTOR_TLS_CERT)
|
||||
.build()
|
||||
ouinetDir = config.ouinetDirectory
|
||||
|
||||
ouinet = Ouinet(this, config)
|
||||
ouinet.start()
|
||||
|
||||
Executors.newFixedThreadPool(1).execute(Runnable { this.updateOuinetState() })
|
||||
}
|
||||
|
||||
private fun updateOuinetState() {
|
||||
val ouinetState = findViewById<View>(R.id.status) as TextView
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(1000)
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
val state = ouinet.state.toString()
|
||||
runOnUiThread { ouinetState.text = "State: $state" }
|
||||
}
|
||||
}
|
||||
|
||||
fun getURL(view: View?) {
|
||||
val editText = findViewById<View>(R.id.url) as EditText
|
||||
val logViewer = findViewById<View>(R.id.log_viewer) as TextView
|
||||
val url = editText.text.toString()
|
||||
val toast = Toast.makeText(this, "Loading: $url", Toast.LENGTH_SHORT)
|
||||
toast.show()
|
||||
|
||||
val client: OkHttpClient = getOuinetHttpClient()
|
||||
val request: Request = Request.Builder()
|
||||
.url(url)
|
||||
.header("X-Ouinet-Group", getDhtGroup(url))
|
||||
.build()
|
||||
|
||||
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
e.printStackTrace()
|
||||
runOnUiThread { logViewer.text = e.toString() }
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
response.body.use { _ ->
|
||||
val responseHeaders = response.headers
|
||||
var i = 0
|
||||
val size = responseHeaders.size
|
||||
while (i < size) {
|
||||
println(responseHeaders.name(i) + ": " + responseHeaders.value(i))
|
||||
i++
|
||||
}
|
||||
runOnUiThread { logViewer.text = responseHeaders.toString() }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun getDhtGroup(url: String): String {
|
||||
var domain: String = ""
|
||||
try {
|
||||
domain = URI(url).schemeSpecificPart
|
||||
domain = domain.replace("^//".toRegex(), "")
|
||||
} catch (e: URISyntaxException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return domain
|
||||
}
|
||||
|
||||
private fun getOuinetHttpClient(): OkHttpClient {
|
||||
return try {
|
||||
val trustManagers: Array<TrustManager> = getOuinetTrustManager()
|
||||
|
||||
val builder = OkHttpClient.Builder()
|
||||
builder.sslSocketFactory(
|
||||
getSSLSocketFactory(trustManagers),
|
||||
(trustManagers[0] as X509TrustManager)
|
||||
)
|
||||
|
||||
// Proxy to ouinet service
|
||||
val ouinetService = Proxy(Proxy.Type.HTTP, InetSocketAddress("127.0.0.1", 8077))
|
||||
builder.proxy(ouinetService)
|
||||
return builder.build()
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(NoSuchAlgorithmException::class, KeyManagementException::class)
|
||||
private fun getSSLSocketFactory(trustManagers: Array<TrustManager>): SSLSocketFactory {
|
||||
val sslContext = SSLContext.getInstance("TLS")
|
||||
sslContext.init(null, trustManagers, SecureRandom())
|
||||
return sslContext.socketFactory
|
||||
}
|
||||
|
||||
@Throws(
|
||||
NoSuchAlgorithmException::class,
|
||||
KeyStoreException::class,
|
||||
CertificateException::class,
|
||||
IOException::class
|
||||
)
|
||||
private fun getOuinetTrustManager(): Array<TrustManager> {
|
||||
return arrayOf(OuinetTrustManager())
|
||||
}
|
||||
|
||||
inner private class OuinetTrustManager : X509TrustManager {
|
||||
private var trustManager: X509TrustManager? = null
|
||||
private var ca: Certificate? = null
|
||||
|
||||
init {
|
||||
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
tmf.init(keyStore)
|
||||
for (tm in tmf.trustManagers) {
|
||||
if (tm is X509TrustManager) {
|
||||
trustManager = tm
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@get:Throws(
|
||||
KeyStoreException::class,
|
||||
CertificateException::class,
|
||||
NoSuchAlgorithmException::class,
|
||||
IOException::class
|
||||
)
|
||||
private val keyStore: KeyStore
|
||||
private get() {
|
||||
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
|
||||
keyStore.load(null, null)
|
||||
keyStore.setCertificateEntry("ca", certificateAuthority)
|
||||
return keyStore
|
||||
}
|
||||
|
||||
@get:Throws(CertificateException::class)
|
||||
private val certificateAuthority: Certificate?
|
||||
private get() {
|
||||
var caInput: InputStream? = null
|
||||
try {
|
||||
caInput = FileInputStream(ouinetDir + "/ssl-ca-cert.pem")
|
||||
} catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
val cf = CertificateFactory.getInstance("X.509")
|
||||
ca = cf.generateCertificate(caInput)
|
||||
return ca
|
||||
}
|
||||
|
||||
@Throws(CertificateException::class)
|
||||
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
|
||||
}
|
||||
|
||||
@Throws(CertificateException::class)
|
||||
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
|
||||
for (cert in chain) {
|
||||
Log.d(TAG, "Server Cert Issuer: " + cert.issuerDN.name + " " + cert.subjectDN.name)
|
||||
}
|
||||
for (cert in trustManager!!.acceptedIssuers) {
|
||||
Log.d(TAG, "Client Trusted Issuer: " + cert.issuerDN.name)
|
||||
}
|
||||
trustManager!!.checkServerTrusted(chain, authType)
|
||||
}
|
||||
|
||||
override fun getAcceptedIssuers(): Array<X509Certificate> {
|
||||
return arrayOf(ca as X509Certificate)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user