aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorpacien2017-09-07 14:27:37 +0200
committerpacien2017-09-07 14:27:37 +0200
commit4989dad67b68b38e75416916df406dcec908b399 (patch)
tree1857d313393788234ffa75b9203122d3ae822d3f /app/src/main/java
parent9e5aa1a9f95a3b5541aba7e511e13ae51b614416 (diff)
downloadtincapp-4989dad67b68b38e75416916df406dcec908b399.tar.gz
Implement encrypted private keys support
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt38
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt50
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/TincApp.kt24
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Tincd.kt6
-rw-r--r--app/src/main/java/org/pacien/tincapp/context/AppPaths.kt7
-rw-r--r--app/src/main/java/org/pacien/tincapp/data/TincConfiguration.kt26
-rw-r--r--app/src/main/java/org/pacien/tincapp/extensions/ApacheConfiguration.kt4
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt41
-rw-r--r--app/src/main/java/org/pacien/tincapp/utils/PemUtils.kt62
9 files changed, 234 insertions, 24 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt
index 9027b14..6c29a53 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/ConfigureActivity.kt
@@ -10,6 +10,7 @@ import android.support.v7.app.AlertDialog
10import android.view.View 10import android.view.View
11import java8.util.concurrent.CompletableFuture 11import java8.util.concurrent.CompletableFuture
12import kotlinx.android.synthetic.main.base.* 12import kotlinx.android.synthetic.main.base.*
13import kotlinx.android.synthetic.main.dialog_encrypt_decrypt_keys.view.*
13import kotlinx.android.synthetic.main.dialog_network_generate.view.* 14import kotlinx.android.synthetic.main.dialog_network_generate.view.*
14import kotlinx.android.synthetic.main.dialog_network_join.view.* 15import kotlinx.android.synthetic.main.dialog_network_join.view.*
15import kotlinx.android.synthetic.main.page_configure.* 16import kotlinx.android.synthetic.main.page_configure.*
@@ -62,7 +63,10 @@ class ConfigureActivity : BaseActivity() {
62 val genDialog = layoutInflater.inflate(R.layout.dialog_network_generate, main_content, false) 63 val genDialog = layoutInflater.inflate(R.layout.dialog_network_generate, main_content, false)
63 AlertDialog.Builder(this).setTitle(R.string.title_new_network).setView(genDialog) 64 AlertDialog.Builder(this).setTitle(R.string.title_new_network).setView(genDialog)
64 .setPositiveButton(R.string.action_create) { _, _ -> 65 .setPositiveButton(R.string.action_create) { _, _ ->
65 generateConf(genDialog.new_net_name.text.toString(), genDialog.new_node_name.text.toString()) 66 generateConf(
67 genDialog.new_net_name.text.toString(),
68 genDialog.new_node_name.text.toString(),
69 genDialog.new_passphrase.text.toString())
66 }.setNegativeButton(R.string.action_cancel, App.dismissAction).show() 70 }.setNegativeButton(R.string.action_cancel, App.dismissAction).show()
67 } 71 }
68 72
@@ -70,7 +74,21 @@ class ConfigureActivity : BaseActivity() {
70 joinDialog = layoutInflater.inflate(R.layout.dialog_network_join, main_content, false) 74 joinDialog = layoutInflater.inflate(R.layout.dialog_network_join, main_content, false)
71 AlertDialog.Builder(this).setTitle(R.string.title_join_network).setView(joinDialog) 75 AlertDialog.Builder(this).setTitle(R.string.title_join_network).setView(joinDialog)
72 .setPositiveButton(R.string.action_join) { _, _ -> 76 .setPositiveButton(R.string.action_join) { _, _ ->
73 joinNetwork(joinDialog!!.net_name.text.toString(), joinDialog!!.invitation_url.text.toString()) 77 joinNetwork(
78 joinDialog!!.net_name.text.toString(),
79 joinDialog!!.invitation_url.text.toString(),
80 joinDialog!!.join_passphrase.text.toString())
81 }.setNegativeButton(R.string.action_cancel, App.dismissAction).show()
82 }
83
84 fun openEncryptDecryptPrivateKeyDialog(@Suppress("UNUSED_PARAMETER") v: View) {
85 val encryptDecryptDialog = layoutInflater.inflate(R.layout.dialog_encrypt_decrypt_keys, main_content, false)
86 AlertDialog.Builder(this).setTitle(R.string.title_private_keys_encryption).setView(encryptDecryptDialog)
87 .setPositiveButton(R.string.action_apply) { _, _ ->
88 encryptDecryptPrivateKeys(
89 encryptDecryptDialog!!.enc_dec_net_name.text.toString(),
90 encryptDecryptDialog.enc_dec_current_passphrase.text.toString(),
91 encryptDecryptDialog.enc_dec_new_passphrase.text.toString())
74 }.setNegativeButton(R.string.action_cancel, App.dismissAction).show() 92 }.setNegativeButton(R.string.action_cancel, App.dismissAction).show()
75 } 93 }
76 94
@@ -80,22 +98,28 @@ class ConfigureActivity : BaseActivity() {
80 text_tinc_binary.text = AppPaths.tinc().absolutePath 98 text_tinc_binary.text = AppPaths.tinc().absolutePath
81 } 99 }
82 100
83 private fun generateConf(netName: String, nodeName: String) = execAction( 101 private fun generateConf(netName: String, nodeName: String, passphrase: String? = null) = execAction(
84 R.string.message_generating_configuration, 102 R.string.message_generating_configuration,
85 Tinc.init(netName, nodeName) 103 Tinc.init(netName, nodeName)
86 .thenCompose { TincApp.removeScripts(netName) }) 104 .thenCompose { TincApp.removeScripts(netName) }
105 .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) })
87 106
88 private fun joinNetwork(netName: String, url: String) = execAction( 107 private fun joinNetwork(netName: String, url: String, passphrase: String? = null) = execAction(
89 R.string.message_joining_network, 108 R.string.message_joining_network,
90 Tinc.join(netName, url) 109 Tinc.join(netName, url)
91 .thenCompose { TincApp.removeScripts(netName) } 110 .thenCompose { TincApp.removeScripts(netName) }
92 .thenCompose { TincApp.generateIfaceCfg(netName) }) 111 .thenCompose { TincApp.generateIfaceCfg(netName) }
112 .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) })
113
114 private fun encryptDecryptPrivateKeys(netName: String, currentPassphrase: String, newPassphrase: String) = execAction(
115 R.string.message_encrypting_decrypting_private_keys,
116 TincApp.setPassphrase(netName, currentPassphrase, newPassphrase))
93 117
94 private fun execAction(@StringRes label: Int, action: CompletableFuture<Void>) { 118 private fun execAction(@StringRes label: Int, action: CompletableFuture<Void>) {
95 showProgressDialog(label).let { progressDialog -> 119 showProgressDialog(label).let { progressDialog ->
96 action 120 action
97 .whenComplete { _, _ -> progressDialog.dismiss() } 121 .whenComplete { _, _ -> progressDialog.dismiss() }
98 .thenAccept { notify(R.string.message_network_configuration_created) } 122 .thenAccept { notify(R.string.message_network_configuration_written) }
99 .exceptionallyAccept { runOnUiThread { showErrorDialog(it.cause!!.localizedMessage) } } 123 .exceptionallyAccept { runOnUiThread { showErrorDialog(it.cause!!.localizedMessage) } }
100 } 124 }
101 } 125 }
diff --git a/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt
index 6eb630d..74a059b 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt
@@ -1,20 +1,28 @@
1package org.pacien.tincapp.activities 1package org.pacien.tincapp.activities
2 2
3import android.annotation.SuppressLint
3import android.app.Activity 4import android.app.Activity
4import android.content.Intent 5import android.content.Intent
5import android.net.Uri 6import android.net.Uri
6import android.net.VpnService 7import android.net.VpnService
7import android.os.Bundle 8import android.os.Bundle
9import android.support.v7.app.AlertDialog
10import android.support.v7.app.AppCompatActivity
11import kotlinx.android.synthetic.main.dialog_decrypt_keys.view.*
12import org.pacien.tincapp.R
13import org.pacien.tincapp.commands.TincApp
8import org.pacien.tincapp.context.App 14import org.pacien.tincapp.context.App
9import org.pacien.tincapp.intent.action.ACTION_CONNECT 15import org.pacien.tincapp.intent.action.ACTION_CONNECT
10import org.pacien.tincapp.intent.action.ACTION_DISCONNECT 16import org.pacien.tincapp.intent.action.ACTION_DISCONNECT
11import org.pacien.tincapp.intent.action.TINC_SCHEME 17import org.pacien.tincapp.intent.action.TINC_SCHEME
12import org.pacien.tincapp.service.TincVpnService 18import org.pacien.tincapp.service.TincVpnService
19import org.pacien.tincapp.utils.PemUtils
20import java.io.FileNotFoundException
13 21
14/** 22/**
15 * @author pacien 23 * @author pacien
16 */ 24 */
17class LaunchActivity : Activity() { 25class LaunchActivity : AppCompatActivity() {
18 26
19 override fun onCreate(savedInstanceState: Bundle?) { 27 override fun onCreate(savedInstanceState: Bundle?) {
20 super.onCreate(savedInstanceState) 28 super.onCreate(savedInstanceState)
@@ -26,15 +34,41 @@ class LaunchActivity : Activity() {
26 } 34 }
27 35
28 override fun onActivityResult(request: Int, result: Int, data: Intent?) { 36 override fun onActivityResult(request: Int, result: Int, data: Intent?) {
29 if (result == Activity.RESULT_OK) TincVpnService.startVpn(intent.data.schemeSpecificPart) 37 if (request == PERMISSION_REQUEST_CODE && result == Activity.RESULT_OK) askPassphrase()
30 finish()
31 } 38 }
32 39
33 private fun requestPerm() = VpnService.prepare(this).let { 40 private fun requestPerm() = VpnService.prepare(this).let {
34 if (it != null) 41 if (it != null)
35 startActivityForResult(it, 0) 42 startActivityForResult(it, PERMISSION_REQUEST_CODE)
36 else 43 else
37 onActivityResult(0, Activity.RESULT_OK, null) 44 onActivityResult(PERMISSION_REQUEST_CODE, Activity.RESULT_OK, null)
45 }
46
47 @SuppressLint("InflateParams")
48 private fun askPassphrase() {
49 val netName = intent.data.schemeSpecificPart
50
51 if (needPassphrase(netName) && intent.data.fragment == null) {
52 val dialog = layoutInflater.inflate(R.layout.dialog_decrypt_keys, null, false)
53 AlertDialog.Builder(this)
54 .setTitle(R.string.title_unlock_private_keys).setView(dialog)
55 .setPositiveButton(R.string.action_unlock) { _, _ -> connect(netName, dialog.passphrase.text.toString()) }
56 .setNegativeButton(R.string.action_cancel, { _, _ -> finish() })
57 .show()
58 } else {
59 connect(netName, intent.data.fragment)
60 }
61 }
62
63 private fun needPassphrase(netName: String) = try {
64 TincApp.listPrivateKeys(netName).filter { it.exists() }.any { PemUtils.isEncrypted(PemUtils.read(it)) }
65 } catch (e: FileNotFoundException) {
66 false
67 }
68