aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org')
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt98
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt152
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt99
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Tinc.kt4
-rw-r--r--app/src/main/java/org/pacien/tincapp/intent/Actions.kt19
-rw-r--r--app/src/main/java/org/pacien/tincapp/intent/SimpleBroadcastReceiver.kt19
-rw-r--r--app/src/main/java/org/pacien/tincapp/intent/action/Actions.kt14
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt113
-rw-r--r--app/src/main/java/org/pacien/tincapp/utils/TincKeyring.kt26
9 files changed, 314 insertions, 230 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt
deleted file mode 100644
index 0179040..0000000
--- a/app/src/main/java/org/pacien/tincapp/activities/LaunchActivity.kt
+++ /dev/null
@@ -1,98 +0,0 @@
1package org.pacien.tincapp.activities
2
3import android.annotation.SuppressLint
4import android.app.Activity
5import android.content.Intent
6import android.net.Uri
7import android.net.VpnService
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
14import org.pacien.tincapp.context.App
15import org.pacien.tincapp.intent.action.ACTION_CONNECT
16import org.pacien.tincapp.intent.action.ACTION_DISCONNECT
17import org.pacien.tincapp.intent.action.TINC_SCHEME
18import org.pacien.tincapp.service.TincVpnService
19import org.pacien.tincapp.utils.PemUtils
20import java.io.FileNotFoundException
21
22/**
23 * @author pacien
24 */
25class LaunchActivity : AppCompatActivity() {
26
27 override fun onCreate(savedInstanceState: Bundle?) {
28 super.onCreate(savedInstanceState)
29
30 when (intent.action) {
31 ACTION_CONNECT -> requestPerm()
32 ACTION_DISCONNECT -> disconnect()
33 }
34 }
35
36 override fun onActivityResult(request: Int, result: Int, data: Intent?) {
37 if (request == PERMISSION_REQUEST_CODE && result == Activity.RESULT_OK) askPassphrase()
38 }
39
40 private fun requestPerm() = VpnService.prepare(this).let {
41 if (it != null)
42 startActivityForResult(it, PERMISSION_REQUEST_CODE)
43 else
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
69 private fun connect(netName: String, passphrase: String? = null) {
70 TincVpnService.startVpn(netName, passphrase)
71 finish()
72 }
73
74 private fun disconnect() {
75 TincVpnService.stopVpn()
76 finish()
77 }
78
79 companion object {
80
81 private val PERMISSION_REQUEST_CODE = 0
82
83 fun connect(netName: String, passphrase: String? = null) {
84 App.getContext().startActivity(Intent(App.getContext(), LaunchActivity::class.java)
85 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
86 .setAction(ACTION_CONNECT)
87 .setData(Uri.Builder().scheme(TINC_SCHEME).opaquePart(netName).fragment(passphrase).build()))
88 }
89
90 fun disconnect() {
91 App.getContext().startActivity(Intent(App.getContext(), LaunchActivity::class.java)
92 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
93 .setAction(ACTION_DISCONNECT))
94 }
95
96 }
97
98}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
index 719bbc1..9fa5e44 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
@@ -1,8 +1,13 @@
1package org.pacien.tincapp.activities 1package org.pacien.tincapp.activities
2 2
3import android.app.Activity
4import android.app.ProgressDialog
3import android.content.Intent 5import android.content.Intent
6import android.content.IntentFilter
7import android.net.VpnService
4import android.os.Bundle 8import android.os.Bundle
5import android.support.v4.widget.SwipeRefreshLayout 9import android.support.v4.widget.SwipeRefreshLayout
10import android.support.v7.app.AlertDialog
6import android.view.Menu 11import android.view.Menu
7import android.view.MenuItem 12import android.view.MenuItem
8import android.view.View 13import android.view.View
@@ -10,29 +15,117 @@ import android.widget.AdapterView
10import android.widget.ArrayAdapter 15import android.widget.ArrayAdapter
11import android.widget.TextView 16import android.widget.TextView
12import kotlinx.android.synthetic.main.base.* 17import kotlinx.android.synthetic.main.base.*
18import kotlinx.android.synthetic.main.dialog_decrypt_keys.view.*
13import kotlinx.android.synthetic.main.fragment_list_view.* 19import kotlinx.android.synthetic.main.fragment_list_view.*
14import kotlinx.android.synthetic.main.fragment_network_list_header.* 20import kotlinx.android.synthetic.main.fragment_network_list_header.*
15import org.pacien.tincapp.R 21import org.pacien.tincapp.R
16import org.pacien.tincapp.context.AppPaths 22import org.pacien.tincapp.context.AppPaths
17import org.pacien.tincapp.extensions.Android.setElements 23import org.pacien.tincapp.extensions.Android.setElements
24import org.pacien.tincapp.intent.Actions
25import org.pacien.tincapp.intent.SimpleBroadcastReceiver
18import org.pacien.tincapp.service.TincVpnService 26import org.pacien.tincapp.service.TincVpnService
27import org.pacien.tincapp.utils.TincKeyring
19 28
20/** 29/**
21 * @author pacien 30 * @author pacien
22 */ 31 */
23class StartActivity : BaseActivity(), AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener { 32class StartActivity : BaseActivity() {
33 companion object {
34 private const val PERMISSION_REQUEST = 0
35 }
36
37 private val networkList = object : AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener {
38 private var networkListAdapter: ArrayAdapter<String>? = null
39
40 fun init() {
41 networkListAdapter = ArrayAdapter(this@StartActivity, R.layout.fragment_list_item)
42 layoutInflater.inflate(R.layout.fragment_list_view, main_content)
43 list_wrapper.setOnRefreshListener(this)
44 list.addHeaderView(layoutInflater.inflate(R.layout.fragment_network_list_header, list, false), null, false)
45 list.addFooterView(View(this@StartActivity), null, false)
46 list.adapter = networkListAdapter
47 list.onItemClickListener = this
48 }
49
50 fun destroy() {
51 networkListAdapter = null
52 }
53
54 override fun onRefresh() {
55 val networks = AppPaths.confDir()?.list()?.toList() ?: emptyList()
56 runOnUiThread {
57 networkListAdapter?.setElements(networks)
58 setPlaceholderVisibility()
59 list_wrapper.isRefreshing = false
60 }
61 }
62
63 override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
64 connectionStarter.tryStart(netName = (view as TextView).text.toString(), displayStatus = true)
65 }
66
67 private fun setPlaceholderVisibility() = if (networkListAdapter?.isEmpty != false) {
68 network_list_placeholder.text = getListPlaceholderText()
69 network_list_placeholder.visibility = View.VISIBLE
70 } else {
71 network_list_placeholder.visibility = View.GONE
72 }
73
74 private fun getListPlaceholderText() = if (!AppPaths.storageAvailable()) {
75 getText(R.string.message_storage_unavailable)
76 } else {
77 getText(R.string.message_no_network_configuration_found)
78 }
79 }
80
81 private val connectionStarter = object {
82 private var netName: String? = null
83 private var passphrase: String? = null