diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index a929523..d80c32f 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -23,7 +23,7 @@ jobs: with: repository: yggdrasil-network/yggdrasil-go path: yggdrasil-go - ref: master + ref: develop fetch-depth: 0 - name: Setup Go environment @@ -34,10 +34,10 @@ jobs: go install golang.org/x/mobile/cmd/gomobile@latest ~/go/bin/gomobile init - - name: Set up JDK 17 + - name: Set up JDK 11 uses: actions/setup-java@v3 with: - java-version: '17' + java-version: '11' distribution: 'temurin' cache: gradle diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 3340ab4..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "libs/yggdrasil-go"] - path = libs/yggdrasil-go - url = https://github.com/yggdrasil-network/yggdrasil-go diff --git a/app/build.gradle b/app/build.gradle index 1a38c8d..3107ca2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,14 +4,15 @@ plugins { } android { - compileSdkVersion 34 + compileSdkVersion 29 + buildToolsVersion "30.0.3" defaultConfig { applicationId "eu.neilalexander.yggdrasil" minSdkVersion 21 - targetSdkVersion 34 - versionCode 20 - versionName "0.1-020" + targetSdkVersion 29 + versionCode 10 + versionName "0.1-010" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -45,18 +46,17 @@ android { kotlinOptions { jvmTarget = '1.8' } - namespace 'eu.neilalexander.yggdrasil' } dependencies { implementation fileTree(include: ['*.aar'], dir: 'libs') implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.13.1' - implementation 'androidx.appcompat:appcompat:1.7.0' - implementation 'com.google.android.material:material:1.12.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.preference:preference-ktx:1.2.1' - testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.2.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' + implementation 'androidx.core:core-ktx:1.5.0' + implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.preference:preference-ktx:1.1.0' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ebf9dd1..edec37d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,12 +1,9 @@ - + - - - - + android:theme="@style/Theme.Yggdrasil"> + + @@ -24,49 +24,16 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/BootUpReceiver.kt b/app/src/main/java/eu/neilalexander/yggdrasil/BootUpReceiver.kt deleted file mode 100644 index 2ca3629..0000000 --- a/app/src/main/java/eu/neilalexander/yggdrasil/BootUpReceiver.kt +++ /dev/null @@ -1,40 +0,0 @@ -package eu.neilalexander.yggdrasil - -import android.app.NotificationManager -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.net.VpnService -import android.util.Log -import androidx.preference.PreferenceManager - -class BootUpReceiver : BroadcastReceiver() { - - companion object { - const val TAG = "BootUpReceiver" - } - - override fun onReceive(context: Context, intent: Intent) { - if (intent.action != Intent.ACTION_BOOT_COMPLETED) { - Log.w(TAG, "Wrong action: ${intent.action}") - } - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - if (!preferences.getBoolean(PREF_KEY_ENABLED, false)) { - Log.i(TAG, "Yggdrasil disabled, not starting service") - return - } - Log.i(TAG, "Yggdrasil enabled, starting service") - val serviceIntent = Intent(context, PacketTunnelProvider::class.java) - serviceIntent.action = PacketTunnelProvider.ACTION_START - - val vpnIntent = VpnService.prepare(context) - if (vpnIntent != null) { - Log.i(TAG, "Need to ask for VPN permission") - val notification = createPermissionMissingNotification(context) - val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - manager.notify(444, notification) - } else { - context.startService(serviceIntent) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/ConfigurationProxy.kt b/app/src/main/java/eu/neilalexander/yggdrasil/ConfigurationProxy.kt index 2eca90a..4af8b3b 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/ConfigurationProxy.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/ConfigurationProxy.kt @@ -1,6 +1,7 @@ package eu.neilalexander.yggdrasil import android.content.Context +import android.provider.Settings import mobile.Mobile import org.json.JSONArray import org.json.JSONObject @@ -28,19 +29,6 @@ object ConfigurationProxy { fix() } - fun resetKeys() { - val newJson = JSONObject(String(Mobile.generateConfigJSON())) - updateJSON { json -> - json.put("PrivateKey", newJson.getString("PrivateKey")) - } - } - - fun setKeys(privateKey: String) { - updateJSON { json -> - json.put("PrivateKey", privateKey) - } - } - fun updateJSON(fn: (JSONObject) -> Unit) { json = JSONObject(file.readText(Charsets.UTF_8)) fn(json) @@ -55,13 +43,12 @@ object ConfigurationProxy { json.put("IfMTU", 65535) if (json.getJSONArray("MulticastInterfaces").get(0) is String) { - val ar = JSONArray() + var ar = JSONArray() ar.put(0, JSONObject(""" { "Regex": ".*", "Beacon": true, - "Listen": true, - "Password": "" + "Listen": true } """.trimIndent())) json.put("MulticastInterfaces", ar) @@ -93,12 +80,4 @@ object ConfigurationProxy { (json.getJSONArray("MulticastInterfaces").get(0) as JSONObject).put("Beacon", value) } } - - var multicastPassword: String - get() = (json.getJSONArray("MulticastInterfaces").get(0) as JSONObject).optString("Password") - set(value) { - updateJSON { json -> - (json.getJSONArray("MulticastInterfaces").get(0) as JSONObject).put("Password", value) - } - } } \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt index bd50644..8b2b5e7 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/DnsActivity.kt @@ -9,12 +9,11 @@ import android.view.ContextThemeWrapper import android.view.LayoutInflater import android.view.View import android.widget.* -import androidx.preference.PreferenceManager import com.google.android.material.textfield.TextInputEditText const val KEY_DNS_SERVERS = "dns_servers" -const val KEY_DNS_VERSION = "dns_version" const val KEY_ENABLE_CHROME_FIX = "enable_chrome_fix" +const val DEFAULT_DNS_SERVERS = "302:7991::53,302:db60::53,300:6223::53,301:1088::53" class DnsActivity : AppCompatActivity() { private lateinit var config: ConfigurationProxy @@ -29,8 +28,6 @@ class DnsActivity : AppCompatActivity() { private lateinit var servers: MutableList private lateinit var preferences: SharedPreferences - private lateinit var defaultDnsServers: HashMap> - @SuppressLint("ApplySharedPref") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -39,15 +36,6 @@ class DnsActivity : AppCompatActivity() { config = ConfigurationProxy(applicationContext) inflater = LayoutInflater.from(this) - val descriptionRevertron = getString(R.string.dns_server_info_revertron) - // Here we can add some other DNS servers in a future - defaultDnsServers = hashMapOf( - "308:62:45:62::" to Pair(getString(R.string.location_amsterdam), descriptionRevertron), - "308:84:68:55::" to Pair(getString(R.string.location_frankfurt), descriptionRevertron), - "308:25:40:bd::" to Pair(getString(R.string.location_bratislava), descriptionRevertron), - "308:c8:48:45::" to Pair(getString(R.string.location_buffalo), descriptionRevertron), - ) - serversTableLayout = findViewById(R.id.configuredDnsTableLayout) serversTableLabel = findViewById(R.id.configuredDnsLabel) serversTableHint = findViewById(R.id.configuredDnsHint) @@ -57,21 +45,17 @@ class DnsActivity : AppCompatActivity() { addServerButton.setOnClickListener { val view = inflater.inflate(R.layout.dialog_add_dns_server, null) val input = view.findViewById(R.id.addDnsInput) - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) + val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog)) builder.setTitle(getString(R.string.dns_add_server_dialog_title)) builder.setView(view) - builder.setPositiveButton(getString(R.string.add)) { _, _ -> - val server = input.text.toString() - if (!servers.contains(server)) { - servers.add(server) - preferences.edit().apply { - putString(KEY_DNS_SERVERS, servers.joinToString(",")) - commit() - } - updateConfiguredServers() - } else { - Toast.makeText(this, R.string.dns_already_added_server, Toast.LENGTH_SHORT).show() + builder.setPositiveButton(getString(R.string.add)) { dialog, _ -> + servers.add(input.text.toString()) + preferences.edit().apply { + putString(KEY_DNS_SERVERS, servers.joinToString(",")) + commit() } + dialog.dismiss() + updateConfiguredServers() } builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ -> dialog.cancel() @@ -86,12 +70,7 @@ class DnsActivity : AppCompatActivity() { } } - val enableChromeFixPanel = findViewById(R.id.enableChromeFixPanel) - enableChromeFixPanel.setOnClickListener { - enableChromeFix.toggle() - } - - preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) + preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext) val serverString = preferences.getString(KEY_DNS_SERVERS, "") servers = if (serverString!!.isNotEmpty()) { serverString.split(",").toMutableList() @@ -128,7 +107,7 @@ class DnsActivity : AppCompatActivity() { view.findViewById(R.id.deletePeerButton).tag = i view.findViewById(R.id.deletePeerButton).setOnClickListener { button -> - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) + val builder: AlertDialog.Builder = AlertDialog.Builder(this) builder.setTitle(getString(R.string.dns_remove_title, server)) builder.setPositiveButton(getString(R.string.remove)) { dialog, _ -> servers.removeAt(button.tag as Int) @@ -153,32 +132,27 @@ class DnsActivity : AppCompatActivity() { @SuppressLint("ApplySharedPref") private fun updateUsableServers() { val usableTableLayout: TableLayout = findViewById(R.id.usableDnsTableLayout) + val defaultServers = DEFAULT_DNS_SERVERS.split(",") - defaultDnsServers.forEach { - val server = it.key - val infoPair = it.value + defaultServers.forEach { + val server = it val view = inflater.inflate(R.layout.dns_server_usable, null) view.findViewById(R.id.serverValue).text = server val addButton = view.findViewById(R.id.addButton) addButton.tag = server addButton.setOnClickListener { button -> - val serverString = button.tag as String - if (!servers.contains(serverString)) { - servers.add(serverString) - preferences.edit().apply { - this.putString(KEY_DNS_SERVERS, servers.joinToString(",")) - this.commit() - } - updateConfiguredServers() - } else { - Toast.makeText(this, R.string.dns_already_added_server, Toast.LENGTH_SHORT).show() + servers.add(button.tag as String) + preferences.edit().apply { + this.putString(KEY_DNS_SERVERS, servers.joinToString(",")) + this.commit() } + updateConfiguredServers() } view.setOnLongClickListener { - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) + val builder: AlertDialog.Builder = AlertDialog.Builder(this) builder.setTitle(getString(R.string.dns_server_info_dialog_title)) - builder.setMessage("${infoPair.first}\n\n${infoPair.second}") + builder.setMessage(getText(R.string.dns_server_info_revertron)) builder.setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.dismiss() } diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt b/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt index 0431d12..58cda01 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt @@ -1,32 +1,15 @@ package eu.neilalexander.yggdrasil -import android.app.* -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.os.Build -import android.service.quicksettings.TileService -import androidx.annotation.RequiresApi -import androidx.core.app.NotificationCompat -import androidx.preference.PreferenceManager +import android.app.Application -const val PREF_KEY_ENABLED = "enabled" -const val PREF_KEY_PEERS_NOTE = "peers_note" -const val MAIN_CHANNEL_ID = "Yggdrasil Service" - -class GlobalApplication: Application(), YggStateReceiver.StateReceiver { +class GlobalApplication: Application() { private lateinit var config: ConfigurationProxy - private var currentState: State = State.Disabled - private var updaterConnections: Int = 0 + var updaterConnections: Int = 0 override fun onCreate() { super.onCreate() config = ConfigurationProxy(applicationContext) val callback = NetworkStateCallback(this) - callback.register() - val receiver = YggStateReceiver(this) - receiver.register(this) - migrateDnsServers(this) } fun subscribe() { @@ -42,116 +25,4 @@ class GlobalApplication: Application(), YggStateReceiver.StateReceiver { fun needUiUpdates(): Boolean { return updaterConnections > 0 } - - fun getCurrentState(): State { - return currentState - } - - @RequiresApi(Build.VERSION_CODES.N) - override fun onStateChange(state: State) { - if (state != currentState) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - val componentName = ComponentName(this, YggTileService::class.java) - TileService.requestListeningState(this, componentName) - } - - if (state != State.Disabled) { - val notification = createServiceNotification(this, state) - val notificationManager: NotificationManager = - this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.notify(SERVICE_NOTIFICATION_ID, notification) - } - - currentState = state - } - } -} - -fun migrateDnsServers(context: Context) { - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - if (preferences.getInt(KEY_DNS_VERSION, 0) >= 1) { - return - } - val serverString = preferences.getString(KEY_DNS_SERVERS, "") - if (serverString!!.isNotEmpty()) { - // Replacing old Revertron's servers by new ones - val newServers = serverString - .replace("300:6223::53", "308:25:40:bd::") - .replace("302:7991::53", "308:62:45:62::") - .replace("302:db60::53", "308:84:68:55::") - .replace("301:1088::53", "308:c8:48:45::") - val editor = preferences.edit() - editor.putInt(KEY_DNS_VERSION, 1) - if (newServers != serverString) { - editor.putString(KEY_DNS_SERVERS, newServers) - } - editor.apply() - } -} - -fun createServiceNotification(context: Context, state: State): Notification { - createNotificationChannels(context) - - val intent = Intent(context, MainActivity::class.java).apply { - this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - } - var flags = PendingIntent.FLAG_UPDATE_CURRENT - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - } - val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, flags) - - val text = when (state) { - State.Disabled -> context.getText(R.string.tile_disabled) - State.Enabled -> context.getText(R.string.tile_enabled) - State.Connected -> context.getText(R.string.tile_connected) - else -> context.getText(R.string.tile_disabled) - } - - return NotificationCompat.Builder(context, MAIN_CHANNEL_ID) - .setShowWhen(false) - .setContentTitle(text) - .setSmallIcon(R.drawable.ic_tile_icon) - .setContentIntent(pendingIntent) - .setPriority(NotificationCompat.PRIORITY_MIN) - .build() -} - -fun createPermissionMissingNotification(context: Context): Notification { - createNotificationChannels(context) - val intent = Intent(context, MainActivity::class.java).apply { - this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - } - var flags = PendingIntent.FLAG_UPDATE_CURRENT - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - } - val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, flags) - - return NotificationCompat.Builder(context, MAIN_CHANNEL_ID) - .setShowWhen(false) - .setContentTitle(context.getText(R.string.app_name)) - .setContentText(context.getText(R.string.permission_notification_text)) - .setSmallIcon(R.drawable.ic_tile_icon) - .setContentIntent(pendingIntent) - .setAutoCancel(true) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .build() -} - -private fun createNotificationChannels(context: Context) { - // Create the NotificationChannel, but only on API 26+ because - // the NotificationChannel class is new and not in the support library - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val name = context.getString(R.string.channel_name) - val descriptionText = context.getString(R.string.channel_description) - val importance = NotificationManager.IMPORTANCE_MIN - val channel = NotificationChannel(MAIN_CHANNEL_ID, name, importance).apply { - description = descriptionText - } - // Register the channel with the system - val notificationManager: NotificationManager = - context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.createNotificationChannel(channel) - } } \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt index befdbe3..d33d4ac 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt @@ -1,39 +1,33 @@ package eu.neilalexander.yggdrasil import android.app.Activity -import android.app.AlertDialog import android.content.* import android.graphics.Color -import android.net.Uri import android.net.VpnService import android.os.Bundle -import android.view.ContextThemeWrapper import android.widget.Switch +import android.widget.TableRow import android.widget.TextView import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.LinearLayoutCompat -import androidx.core.content.edit import androidx.localbroadcastmanager.content.LocalBroadcastManager -import androidx.preference.PreferenceManager import eu.neilalexander.yggdrasil.PacketTunnelProvider.Companion.STATE_INTENT import mobile.Mobile import org.json.JSONArray -const val APP_WEB_URL = "https://github.com/yggdrasil-network/yggdrasil-android" class MainActivity : AppCompatActivity() { private lateinit var enabledSwitch: Switch private lateinit var enabledLabel: TextView private lateinit var ipAddressLabel: TextView private lateinit var subnetLabel: TextView + private lateinit var coordinatesLabel: TextView private lateinit var peersLabel: TextView - private lateinit var peersRow: LinearLayoutCompat + private lateinit var peersRow: TableRow private lateinit var dnsLabel: TextView - private lateinit var dnsRow: LinearLayoutCompat - private lateinit var settingsRow: LinearLayoutCompat - private lateinit var versionRow: LinearLayoutCompat + private lateinit var dnsRow: TableRow + private lateinit var settingsRow: TableRow private fun start() { val intent = Intent(this, PacketTunnelProvider::class.java) @@ -57,12 +51,12 @@ class MainActivity : AppCompatActivity() { enabledLabel = findViewById(R.id.yggdrasilStatusLabel) ipAddressLabel = findViewById(R.id.ipAddressValue) subnetLabel = findViewById(R.id.subnetValue) + coordinatesLabel = findViewById(R.id.coordinatesValue) peersLabel = findViewById(R.id.peersValue) peersRow = findViewById(R.id.peersTableRow) dnsLabel = findViewById(R.id.dnsValue) dnsRow = findViewById(R.id.dnsTableRow) settingsRow = findViewById(R.id.settingsTableRow) - versionRow = findViewById(R.id.versionTableRow) enabledLabel.setTextColor(Color.GRAY) @@ -74,7 +68,6 @@ class MainActivity : AppCompatActivity() { startVpnActivity.launch(vpnIntent) } else { start() - enabledSwitch.isEnabled = false } } false -> { @@ -83,13 +76,6 @@ class MainActivity : AppCompatActivity() { startService(intent) } } - val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) - preferences.edit(commit = true) { putBoolean(PREF_KEY_ENABLED, isChecked) } - } - - val enableYggdrasilPanel = findViewById(R.id.enableYggdrasilPanel) - enableYggdrasilPanel.setOnClickListener { - enabledSwitch.toggle() } peersRow.isClickable = true @@ -110,11 +96,6 @@ class MainActivity : AppCompatActivity() { startActivity(intent) } - versionRow.isClickable = true - versionRow.setOnClickListener { - openUrlInBrowser(APP_WEB_URL) - } - ipAddressLabel.setOnLongClickListener { val clipboard: ClipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("ip", ipAddressLabel.text) @@ -137,8 +118,7 @@ class MainActivity : AppCompatActivity() { LocalBroadcastManager.getInstance(this).registerReceiver( receiver, IntentFilter(STATE_INTENT) ) - val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) - enabledSwitch.isChecked = preferences.getBoolean(PREF_KEY_ENABLED, false) + val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext) val serverString = preferences.getString(KEY_DNS_SERVERS, "") if (serverString!!.isNotEmpty()) { val servers = serverString.split(",") @@ -163,16 +143,16 @@ class MainActivity : AppCompatActivity() { override fun onReceive(context: Context?, intent: Intent) { when (intent.getStringExtra("type")) { "state" -> { - val peerState = JSONArray(intent.getStringExtra("peers") ?: "[]") - var count = 0 - for (i in 0.. getString(R.string.main_no_peers) 1 -> getString(R.string.main_one_peer) else -> getString(R.string.main_many_peers, count) } } - if (!enabledSwitch.isEnabled) { - enabledSwitch.isEnabled = true - } } } } } - - private fun showPeersNoteIfNeeded(peerCount: Int) { - if (peerCount > 0) return - val preferences = PreferenceManager.getDefaultSharedPreferences(this@MainActivity.baseContext) - if (!preferences.getBoolean(PREF_KEY_PEERS_NOTE, false)) { - this@MainActivity.runOnUiThread { - val builder: AlertDialog.Builder = - AlertDialog.Builder(ContextThemeWrapper(this@MainActivity, R.style.YggdrasilDialogs)) - builder.setTitle(getString(R.string.main_add_some_peers_title)) - builder.setMessage(getString(R.string.main_add_some_peers_message)) - builder.setPositiveButton(getString(R.string.ok)) { dialog, _ -> - dialog.dismiss() - } - builder.show() - } - // Mark this note as shown - preferences.edit().apply { - putBoolean(PREF_KEY_PEERS_NOTE, true) - commit() - } - } - } - - fun openUrlInBrowser(url: String) { - val intent = Intent(Intent.ACTION_VIEW).apply { - data = Uri.parse(url) - } - try { - startActivity(intent) - } catch (e: ActivityNotFoundException) { - // Handle the exception if no browser is found - Toast.makeText(this, getText(R.string.no_browser_found_toast), Toast.LENGTH_SHORT).show() - } - } } diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/NetworkStateCallback.kt b/app/src/main/java/eu/neilalexander/yggdrasil/NetworkStateCallback.kt index 7775308..404fd23 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/NetworkStateCallback.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/NetworkStateCallback.kt @@ -3,43 +3,14 @@ package eu.neilalexander.yggdrasil import android.content.Context import android.content.Intent import android.net.* -import android.os.Build import android.util.Log -import androidx.preference.PreferenceManager private const val TAG = "Network" class NetworkStateCallback(val context: Context) : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - super.onAvailable(network) - Log.d(TAG, "onAvailable") - - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - if (preferences.getBoolean(PREF_KEY_ENABLED, false)) { - Thread { - // The message often arrives before the connection is fully established - Thread.sleep(1000) - val intent = Intent(context, PacketTunnelProvider::class.java) - intent.action = PacketTunnelProvider.ACTION_CONNECT - try { - context.startService(intent) - } catch (e: IllegalStateException) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } - } - }.start() - } - } - - override fun onLost(network: Network) { - super.onLost(network) - Log.d(TAG, "onLost") - } - - fun register() { + init { val request = NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) @@ -49,4 +20,22 @@ class NetworkStateCallback(val context: Context) : ConnectivityManager.NetworkCa val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager manager.registerNetworkCallback(request, this) } + + override fun onAvailable(network: Network) { + super.onAvailable(network) + Log.d(TAG, "onAvailable") + + Thread { + // The message often arrives before the connection is fully established + Thread.sleep(1000) + val intent = Intent(context, PacketTunnelProvider::class.java) + intent.action = PacketTunnelProvider.ACTION_CONNECT + context.startService(intent) + }.start() + } + + override fun onLost(network: Network) { + super.onLost(network) + Log.d(TAG, "onLost") + } } \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt b/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt index aa84803..b761efc 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt @@ -1,17 +1,12 @@ package eu.neilalexander.yggdrasil -import android.content.Intent +import android.content.* import android.net.VpnService -import android.net.wifi.WifiManager -import android.os.Build import android.os.ParcelFileDescriptor import android.system.OsConstants import android.util.Log import androidx.localbroadcastmanager.content.LocalBroadcastManager -import androidx.preference.PreferenceManager -import eu.neilalexander.yggdrasil.YggStateReceiver.Companion.YGG_STATE_INTENT import mobile.Yggdrasil -import org.json.JSONArray import java.io.FileInputStream import java.io.FileOutputStream import java.util.concurrent.atomic.AtomicBoolean @@ -19,15 +14,13 @@ import kotlin.concurrent.thread private const val TAG = "PacketTunnelProvider" -const val SERVICE_NOTIFICATION_ID = 1000 -open class PacketTunnelProvider: VpnService() { +class PacketTunnelProvider: VpnService() { companion object { const val STATE_INTENT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STATE_MESSAGE" const val ACTION_START = "eu.neilalexander.yggdrasil.PacketTunnelProvider.START" const val ACTION_STOP = "eu.neilalexander.yggdrasil.PacketTunnelProvider.STOP" - const val ACTION_TOGGLE = "eu.neilalexander.yggdrasil.PacketTunnelProvider.TOGGLE" const val ACTION_CONNECT = "eu.neilalexander.yggdrasil.PacketTunnelProvider.CONNECT" } @@ -43,7 +36,6 @@ open class PacketTunnelProvider: VpnService() { private var parcel: ParcelFileDescriptor? = null private var readerStream: FileInputStream? = null private var writerStream: FileOutputStream? = null - private var multicastLock: WifiManager.MulticastLock? = null override fun onCreate() { super.onCreate() @@ -60,8 +52,6 @@ open class PacketTunnelProvider: VpnService() { Log.d(TAG, "Intent is null") return START_NOT_STICKY } - val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) - val enabled = preferences.getBoolean(PREF_KEY_ENABLED, false) return when (intent.action ?: ACTION_STOP) { ACTION_STOP -> { Log.d(TAG, "Stopping...") @@ -69,26 +59,9 @@ open class PacketTunnelProvider: VpnService() { } ACTION_CONNECT -> { Log.d(TAG, "Connecting...") - if (started.get()) { - connect() - } else { - start() - } - START_STICKY - } - ACTION_TOGGLE -> { - Log.d(TAG, "Toggling...") - if (started.get()) { - stop(); START_NOT_STICKY - } else { - start(); START_STICKY - } + connect(); START_STICKY } else -> { - if (!enabled) { - Log.d(TAG, "Service is disabled") - return START_NOT_STICKY - } Log.d(TAG, "Starting...") start(); START_STICKY } @@ -100,16 +73,6 @@ open class PacketTunnelProvider: VpnService() { return } - val notification = createServiceNotification(this, State.Enabled) - startForeground(SERVICE_NOTIFICATION_ID, notification) - - // Acquire multicast lock - val wifi = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager - multicastLock = wifi.createMulticastLock("Yggdrasil").apply { - setReferenceCounted(false) - acquire() - } - Log.d(TAG, config.getJSON().toString()) yggdrasil.startJSON(config.getJSONByteArray()) @@ -133,11 +96,11 @@ open class PacketTunnelProvider: VpnService() { // If we don't set metered status of VPN it is considered as metered. // If we set it to false, then it will inherit this status from underlying network. // See: https://developer.android.com/reference/android/net/VpnService.Builder#setMetered(boolean) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { builder.setMetered(false) } - val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) + val preferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this.baseContext) val serverString = preferences.getString(KEY_DNS_SERVERS, "") if (serverString!!.isNotEmpty()) { val servers = serverString.split(",") @@ -172,8 +135,13 @@ open class PacketTunnelProvider: VpnService() { updater() } - var intent = Intent(YGG_STATE_INTENT) - intent.putExtra("state", STATE_ENABLED) + val intent = Intent(STATE_INTENT) + intent.putExtra("type", "state") + intent.putExtra("started", true) + intent.putExtra("ip", yggdrasil.addressString) + intent.putExtra("subnet", yggdrasil.subnetString) + intent.putExtra("coords", yggdrasil.coordsString) + intent.putExtra("peers", yggdrasil.peersJSON) LocalBroadcastManager.getInstance(this).sendBroadcast(intent) } @@ -210,18 +178,12 @@ open class PacketTunnelProvider: VpnService() { updateThread = null } - var intent = Intent(STATE_INTENT) + val intent = Intent(STATE_INTENT) intent.putExtra("type", "state") intent.putExtra("started", false) LocalBroadcastManager.getInstance(this).sendBroadcast(intent) - intent = Intent(YGG_STATE_INTENT) - intent.putExtra("state", STATE_DISABLED) - LocalBroadcastManager.getInstance(this).sendBroadcast(intent) - - stopForeground(true) stopSelf() - multicastLock?.release() } private fun connect() { @@ -232,69 +194,44 @@ open class PacketTunnelProvider: VpnService() { } private fun updater() { - try { - Thread.sleep(500) - } catch (_: InterruptedException) { - return - } - var lastStateUpdate = System.currentTimeMillis() updates@ while (started.get()) { - val treeJSON = yggdrasil.treeJSON if ((application as GlobalApplication).needUiUpdates()) { val intent = Intent(STATE_INTENT) intent.putExtra("type", "state") intent.putExtra("started", true) intent.putExtra("ip", yggdrasil.addressString) intent.putExtra("subnet", yggdrasil.subnetString) - intent.putExtra("pubkey", yggdrasil.publicKeyString) + intent.putExtra("coords", yggdrasil.coordsString) intent.putExtra("peers", yggdrasil.peersJSON) + intent.putExtra("dht", yggdrasil.dhtjson) LocalBroadcastManager.getInstance(this).sendBroadcast(intent) - } - val curTime = System.currentTimeMillis() - if (lastStateUpdate + 10000 < curTime) { - val intent = Intent(YGG_STATE_INTENT) - var state = STATE_ENABLED - if (yggdrasil.routingEntries > 0) { - state = STATE_CONNECTED + } else { + try { + Thread.sleep(1000) + } catch (e: InterruptedException) { + return } - if (treeJSON != null && treeJSON != "null") { - val treeState = JSONArray(treeJSON) - val count = treeState.length() - if (count > 1) - state = STATE_CONNECTED - } - intent.putExtra("state", state) - LocalBroadcastManager.getInstance(this).sendBroadcast(intent) - lastStateUpdate = curTime } - if (Thread.currentThread().isInterrupted) { break@updates } - if (sleep()) return + try { + Thread.sleep(1000) + } catch (e: InterruptedException) { + return + } } } - private fun sleep(): Boolean { - try { - Thread.sleep(1000) - } catch (e: InterruptedException) { - return true - } - return false - } - private fun writer() { val buf = ByteArray(65535) writes@ while (started.get()) { val writerStream = writerStream val writerThread = writerThread if (writerThread == null || writerStream == null) { - Log.i(TAG, "Write thread or stream is null") break@writes } if (Thread.currentThread().isInterrupted || !writerStream.fd.valid()) { - Log.i(TAG, "Write thread interrupted or file descriptor is invalid") break@writes } try { @@ -303,12 +240,6 @@ open class PacketTunnelProvider: VpnService() { writerStream.write(buf, 0, len.toInt()) } } catch (e: Exception) { - Log.i(TAG, "Error in write: $e") - if (e.toString().contains("ENOBUFS")) { - //TODO Check this by some error code - //More info about this: https://github.com/AdguardTeam/AdguardForAndroid/issues/724 - continue - } break@writes } } @@ -324,18 +255,15 @@ open class PacketTunnelProvider: VpnService() { val readerStream = readerStream val readerThread = readerThread if (readerThread == null || readerStream == null) { - Log.i(TAG, "Read thread or stream is null") break@reads } if (Thread.currentThread().isInterrupted ||!readerStream.fd.valid()) { - Log.i(TAG, "Read thread interrupted or file descriptor is invalid") break@reads } try { val n = readerStream.read(b) yggdrasil.sendBuffer(b, n.toLong()) } catch (e: Exception) { - Log.i(TAG, "Error in sendBuffer: $e") break@reads } } diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt index 55e2817..5664fdc 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt @@ -5,27 +5,17 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter +import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.text.method.LinkMovementMethod -import android.util.Log import android.view.ContextThemeWrapper -import android.view.KeyEvent import android.view.LayoutInflater import android.view.View -import android.widget.EditText -import android.widget.ImageButton -import android.widget.Switch -import android.widget.TableLayout -import android.widget.TableRow -import android.widget.TextView -import androidx.appcompat.app.AppCompatActivity -import androidx.core.widget.doOnTextChanged +import android.widget.* import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.material.textfield.TextInputEditText import org.json.JSONArray import org.json.JSONObject - class PeersActivity : AppCompatActivity() { private lateinit var config: ConfigurationProxy private lateinit var inflater: LayoutInflater @@ -37,7 +27,6 @@ class PeersActivity : AppCompatActivity() { private lateinit var configuredTableLabel: TextView private lateinit var multicastListenSwitch: Switch private lateinit var multicastBeaconSwitch: Switch - private lateinit var passwordEdit: EditText private lateinit var addPeerButton: ImageButton override fun onCreate(savedInstanceState: Bundle?) { @@ -54,9 +43,6 @@ class PeersActivity : AppCompatActivity() { configuredTableLayout = findViewById(R.id.configuredPeersTableLayout) configuredTableLabel = findViewById(R.id.configuredPeersLabel) - val discoveryLink = findViewById(R.id.peers_discovery_link) - discoveryLink.movementMethod = LinkMovementMethod.getInstance() - multicastListenSwitch = findViewById(R.id.enableMulticastListen) multicastListenSwitch.setOnCheckedChangeListener { button, _ -> config.multicastListen = button.isChecked @@ -68,44 +54,11 @@ class PeersActivity : AppCompatActivity() { multicastListenSwitch.isChecked = config.multicastListen multicastBeaconSwitch.isChecked = config.multicastBeacon - val multicastBeaconPanel = findViewById(R.id.enableMulticastBeaconPanel) - multicastBeaconPanel.setOnClickListener { - multicastBeaconSwitch.toggle() - } - val multicastListenPanel = findViewById(R.id.enableMulticastListenPanel) - multicastListenPanel.setOnClickListener { - multicastListenSwitch.toggle() - } - passwordEdit = findViewById(R.id.passwordEdit) - passwordEdit.setText(config.multicastPassword) - - passwordEdit.doOnTextChanged { text, _, _, _ -> - config.multicastPassword = text.toString() - } - - passwordEdit.setOnKeyListener { _, keyCode, _ -> - (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) - } - - findViewById(R.id.passwordTableRow).setOnKeyListener { _, keyCode, event -> - Log.i("Key", keyCode.toString()) - if (event.action == KeyEvent.ACTION_DOWN) { - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { - passwordEdit.requestFocus() - true - } else { - false - } - } else { - false - } - } - addPeerButton = findViewById(R.id.addPeerButton) addPeerButton.setOnClickListener { val view = inflater.inflate(R.layout.dialog_addpeer, null) val input = view.findViewById(R.id.addPeerInput) - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) + val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog)) builder.setTitle(getString(R.string.peers_add_peer)) builder.setView(view) builder.setPositiveButton(getString(R.string.peers_add)) { dialog, _ -> @@ -159,7 +112,7 @@ class PeersActivity : AppCompatActivity() { view.findViewById(R.id.deletePeerButton).tag = i view.findViewById(R.id.deletePeerButton).setOnClickListener { button -> - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) + val builder: AlertDialog.Builder = AlertDialog.Builder(this) builder.setTitle(getString(R.string.peers_remove_title, peer)) builder.setPositiveButton(getString(R.string.peers_remove)) { dialog, _ -> config.updateJSON { json -> @@ -186,25 +139,16 @@ class PeersActivity : AppCompatActivity() { connectedTableLabel.text = getString(R.string.peers_no_connected_title) } else -> { - var connected = false + connectedTableLayout.visibility = View.VISIBLE + connectedTableLabel.text = getString(R.string.peers_connected_title) + connectedTableLayout.removeAllViewsInLayout() for (peer in peers) { val view = inflater.inflate(R.layout.peers_connected, null) val ip = peer.getString("IP") - // Only connected peers have IPs - if (ip.isNotEmpty()) { - view.findViewById(R.id.addressLabel).text = ip - view.findViewById(R.id.detailsLabel).text = peer.getString("URI") - connectedTableLayout.addView(view) - connected = true - } - } - if (connected) { - connectedTableLayout.visibility = View.VISIBLE - connectedTableLabel.text = getString(R.string.peers_connected_title) - } else { - connectedTableLayout.visibility = View.GONE - connectedTableLabel.text = getString(R.string.peers_no_connected_title) + view.findViewById(R.id.addressLabel).text = ip + view.findViewById(R.id.detailsLabel).text = peer.getString("Remote") + connectedTableLayout.addView(view) } } } @@ -215,9 +159,7 @@ class PeersActivity : AppCompatActivity() { when (intent.getStringExtra("type")) { "state" -> { if (intent.hasExtra("peers")) { - val peers1 = intent.getStringExtra("peers") - //Log.i("PeersActivity", "Peers json: $peers1") - val peersArray = JSONArray(peers1 ?: "[]") + val peersArray = JSONArray(intent.getStringExtra("peers") ?: "[]") val array = Array(peersArray.length()) { i -> peersArray.getJSONObject(i) } diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt index 8e2e3d2..11f9b32 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt @@ -1,23 +1,14 @@ package eu.neilalexander.yggdrasil import android.app.AlertDialog -import android.content.BroadcastReceiver import android.content.ClipData import android.content.ClipboardManager -import android.content.Context -import android.content.Intent -import android.content.IntentFilter import androidx.appcompat.app.AppCompatActivity import android.os.Bundle -import android.util.Log import android.view.ContextThemeWrapper -import android.view.KeyEvent import android.view.LayoutInflater -import android.view.View import android.widget.* -import androidx.appcompat.widget.LinearLayoutCompat import androidx.core.widget.doOnTextChanged -import androidx.localbroadcastmanager.content.LocalBroadcastManager import org.json.JSONObject class SettingsActivity : AppCompatActivity() { @@ -26,8 +17,7 @@ class SettingsActivity : AppCompatActivity() { private lateinit var deviceNameEntry: EditText private lateinit var publicKeyLabel: TextView - private lateinit var resetConfigurationRow: LinearLayoutCompat - private var publicKeyReset = false + private lateinit var resetConfigurationRow: TableRow override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -42,35 +32,17 @@ class SettingsActivity : AppCompatActivity() { deviceNameEntry.doOnTextChanged { text, _, _, _ -> config.updateJSON { cfg -> - val nodeInfo = cfg.optJSONObject("NodeInfo") - if (nodeInfo == null) { + val nodeinfo = cfg.optJSONObject("NodeInfo") + if (nodeinfo == null) { cfg.put("NodeInfo", JSONObject("{}")) } cfg.getJSONObject("NodeInfo").put("name", text) } } - deviceNameEntry.setOnKeyListener { view, keyCode, event -> - (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) - } - - findViewById(R.id.deviceNameTableRow).setOnKeyListener { view, keyCode, event -> - Log.i("Key", keyCode.toString()) - if (event.action == KeyEvent.ACTION_DOWN) { - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) { - deviceNameEntry.requestFocus() - true - } else { - false - } - } else { - false - } - } - resetConfigurationRow.setOnClickListener { val view = inflater.inflate(R.layout.dialog_resetconfig, null) - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) + val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog)) builder.setTitle(getString(R.string.settings_warning_title)) builder.setView(view) builder.setPositiveButton(getString(R.string.settings_reset)) { dialog, _ -> @@ -84,29 +56,6 @@ class SettingsActivity : AppCompatActivity() { builder.show() } - findViewById(R.id.resetKeysRow).setOnClickListener { - config.resetKeys() - publicKeyReset = true - updateView() - } - - findViewById(R.id.setKeysRow).setOnClickListener { - val view = inflater.inflate(R.layout.dialog_set_keys, null) - val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.YggdrasilDialogs)) - val privateKey = view.findViewById(R.id.private_key) - builder.setTitle(getString(R.string.set_keys)) - builder.setView(view) - builder.setPositiveButton(getString(R.string.save)) { dialog, _ -> - config.setKeys(privateKey.text.toString()) - updateView() - dialog.dismiss() - } - builder.setNegativeButton(getString(R.string.cancel)) { dialog, _ -> - dialog.cancel() - } - builder.show() - } - publicKeyLabel.setOnLongClickListener { val clipboard: ClipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("public key", publicKeyLabel.text) @@ -119,44 +68,13 @@ class SettingsActivity : AppCompatActivity() { } private fun updateView() { - val json = config.getJSON() - val nodeinfo = json.optJSONObject("NodeInfo") + val nodeinfo = config.getJSON().optJSONObject("NodeInfo") if (nodeinfo != null) { deviceNameEntry.setText(nodeinfo.getString("name"), TextView.BufferType.EDITABLE) } else { deviceNameEntry.setText("", TextView.BufferType.EDITABLE) } - var key = json.optString("PrivateKey") - if (key.isNotEmpty()) { - key = key.substring(key.length / 2) - } - publicKeyLabel.text = key - } - - override fun onResume() { - super.onResume() - LocalBroadcastManager.getInstance(this).registerReceiver( - receiver, IntentFilter(PacketTunnelProvider.STATE_INTENT) - ) - (application as GlobalApplication).subscribe() - } - - override fun onPause() { - super.onPause() - (application as GlobalApplication).unsubscribe() - LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver) - } - - // To be able to get public key from running Yggdrasil we use this receiver, as we don't have this field in config - private val receiver: BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent) { - if (intent.hasExtra("pubkey") && !publicKeyReset) { - val tree = intent.getStringExtra("pubkey") - if (tree != null && tree != "null") { - publicKeyLabel.text = intent.getStringExtra("pubkey") - } - } - } + publicKeyLabel.text = config.getJSON().getString("PublicKey") } } diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/TileServiceActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/TileServiceActivity.kt deleted file mode 100644 index a4f71cc..0000000 --- a/app/src/main/java/eu/neilalexander/yggdrasil/TileServiceActivity.kt +++ /dev/null @@ -1,17 +0,0 @@ -package eu.neilalexander.yggdrasil - -import android.app.Activity -import android.content.Intent -import android.os.Bundle - -class TileServiceActivity : Activity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - // Just starting MainActivity - val intent = Intent(this, MainActivity::class.java) - startService(intent) - finish() - } -} \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/YggStateReceiver.kt b/app/src/main/java/eu/neilalexander/yggdrasil/YggStateReceiver.kt deleted file mode 100644 index f6745f8..0000000 --- a/app/src/main/java/eu/neilalexander/yggdrasil/YggStateReceiver.kt +++ /dev/null @@ -1,53 +0,0 @@ -package eu.neilalexander.yggdrasil - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import androidx.localbroadcastmanager.content.LocalBroadcastManager - -const val STATE_ENABLED = "enabled" -const val STATE_DISABLED = "disabled" -const val STATE_CONNECTED = "connected" -const val STATE_RECONNECTING = "reconnecting" - -class YggStateReceiver(var receiver: StateReceiver): BroadcastReceiver() { - - companion object { - const val YGG_STATE_INTENT = "eu.neilalexander.yggdrasil.YggStateReceiver.STATE" - } - - override fun onReceive(context: Context?, intent: Intent?) { - if (context == null) return - - val state = when (intent?.getStringExtra("state")) { - STATE_ENABLED -> State.Enabled - STATE_DISABLED -> State.Disabled - STATE_CONNECTED -> State.Connected - STATE_RECONNECTING -> State.Reconnecting - else -> State.Unknown - } - receiver.onStateChange(state) - } - - fun register(context: Context) { - LocalBroadcastManager.getInstance(context).registerReceiver( - this, IntentFilter(YGG_STATE_INTENT) - ) - } - - fun unregister(context: Context) { - LocalBroadcastManager.getInstance(context).unregisterReceiver(this) - } - - interface StateReceiver { - fun onStateChange(state: State) - } -} - -/** - * A class-supporter with an Yggdrasil state - */ -enum class State { - Unknown, Disabled, Enabled, Connected, Reconnecting; -} \ No newline at end of file diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/YggTileService.kt b/app/src/main/java/eu/neilalexander/yggdrasil/YggTileService.kt deleted file mode 100644 index 4725bd4..0000000 --- a/app/src/main/java/eu/neilalexander/yggdrasil/YggTileService.kt +++ /dev/null @@ -1,113 +0,0 @@ -package eu.neilalexander.yggdrasil - -import android.content.Intent -import android.graphics.drawable.Icon -import android.os.Build -import android.os.IBinder -import android.service.quicksettings.Tile -import android.service.quicksettings.TileService -import android.util.Log -import androidx.annotation.RequiresApi -import androidx.core.content.edit -import androidx.preference.PreferenceManager - -private const val TAG = "TileService" - -@RequiresApi(Build.VERSION_CODES.N) -class YggTileService: TileService(), YggStateReceiver.StateReceiver { - - private lateinit var receiver: YggStateReceiver - - override fun onCreate() { - super.onCreate() - receiver = YggStateReceiver(this) - } - - /** - * We need to override the method onBind to avoid crashes that were detected on Android 8 - * - * The possible reason of crashes is described here: - * https://github.com/aosp-mirror/platform_frameworks_base/commit/ee68fd889c2dfcd895b8e73fc39d7b97826dc3d8 - */ - override fun onBind(intent: Intent?): IBinder? { - return try { - super.onBind(intent) - } catch (th: Throwable) { - null - } - } - - override fun onTileAdded() { - super.onTileAdded() - updateTileState((application as GlobalApplication).getCurrentState()) - } - - override fun onTileRemoved() { - super.onTileRemoved() - updateTileState((application as GlobalApplication).getCurrentState()) - } - - override fun onStartListening() { - super.onStartListening() - receiver.register(this) - updateTileState((application as GlobalApplication).getCurrentState()) - } - - override fun onStopListening() { - super.onStopListening() - receiver.unregister(this) - } - - override fun onDestroy() { - super.onDestroy() - receiver.unregister(this) - } - - override fun onClick() { - super.onClick() - // Saving new state - val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) - val enabled = preferences.getBoolean(PREF_KEY_ENABLED, false) - preferences.edit(commit = true) { putBoolean(PREF_KEY_ENABLED, !enabled) } - // Starting or stopping VPN service - val intent = Intent(this, PacketTunnelProvider::class.java) - intent.action = PacketTunnelProvider.ACTION_TOGGLE - startService(intent) - } - - private fun updateTileState(state: State) { - val tile = qsTile ?: return - val oldState = tile.state - val preferences = PreferenceManager.getDefaultSharedPreferences(this.baseContext) - val enabled = preferences.getBoolean(PREF_KEY_ENABLED, false) - tile.state = when (enabled) { - false -> Tile.STATE_INACTIVE - true -> Tile.STATE_ACTIVE - } - var changed = oldState != tile.state - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - val oldText = tile.subtitle - tile.subtitle = when (state) { - State.Enabled -> getText(R.string.tile_enabled) - State.Connected -> getText(R.string.tile_connected) - else -> getText(R.string.tile_disabled) - } - changed = changed || (oldText != tile.subtitle) - } - - // Update tile if changed state - if (changed) { - Log.i(TAG, "Updating tile, old state: $oldState, new state: ${tile.state}") - /* - Force set the icon in the tile, because there is a problem on icon tint in the Android Oreo. - Issue: https://github.com/AdguardTeam/AdguardForAndroid/issues/1996 - */ - tile.icon = Icon.createWithResource(applicationContext, R.drawable.ic_tile_icon) - tile.updateTile() - } - } - - override fun onStateChange(state: State) { - updateTileState(state) - } -} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_tile_icon.xml b/app/src/main/res/drawable/ic_tile_icon.xml deleted file mode 100644 index fae8232..0000000 --- a/app/src/main/res/drawable/ic_tile_icon.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - diff --git a/app/src/main/res/layout/activity_dns.xml b/app/src/main/res/layout/activity_dns.xml index d0061e8..132f2a0 100644 --- a/app/src/main/res/layout/activity_dns.xml +++ b/app/src/main/res/layout/activity_dns.xml @@ -194,8 +194,13 @@ android:showDividers="middle"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clickable="true" + android:paddingStart="4pt" + android:paddingTop="2pt" + android:paddingEnd="4pt" + android:paddingBottom="4pt"> - - + - + - + - + - + - - + - + - + - + - + + + + + + + + - - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + android:paddingStart="4pt" + android:paddingTop="6pt" + android:paddingEnd="4pt" + android:paddingBottom="6pt"> - + - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + android:paddingStart="4pt" + android:paddingTop="6pt" + android:paddingEnd="4pt" + android:paddingBottom="6pt"> - + - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:paddingStart="4pt" + android:paddingTop="6pt" + android:paddingEnd="4pt" + android:paddingBottom="6pt"> - + - + - + - + - - @@ -182,6 +167,7 @@ android:layout_marginEnd="8pt" android:layout_marginRight="8pt" android:background="@drawable/rounded" + android:clickable="true" android:divider="#46878787" android:dividerPadding="4pt" android:paddingLeft="4pt" @@ -191,8 +177,13 @@ android:showDividers="middle"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clickable="true" + android:paddingStart="4pt" + android:paddingTop="2pt" + android:paddingEnd="4pt" + android:paddingBottom="4pt"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clickable="true" + android:paddingStart="4pt" + android:paddingTop="4pt" + android:paddingEnd="4pt" + android:paddingBottom="2pt"> - - - - - - - - - + @@ -212,14 +217,13 @@ android:layout_marginBottom="2pt" android:alpha="0.7" android:paddingRight="8pt" - android:text="@string/settings_config" + android:text="@string/settings_reset" android:textAllCaps="true" android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textSize="12sp" /> - - - - - - - - - - - - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + android:padding="4pt"> - - + + + android:text="Enter the full URI of the peer to add. Yggdrasil will automatically connect to this peer when started." /> - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/dns_server_usable.xml b/app/src/main/res/layout/dns_server_usable.xml index 9ca6628..d26e788 100644 --- a/app/src/main/res/layout/dns_server_usable.xml +++ b/app/src/main/res/layout/dns_server_usable.xml @@ -10,11 +10,10 @@ android:id="@+id/serverValue" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="12dp" + android:layout_marginStart="18dp" android:layout_marginTop="4dp" - android:layout_marginEnd="16dp" - android:layout_marginBottom="4dp" - android:gravity="center_vertical" + android:layout_marginEnd="18dp" + android:layout_marginBottom="12dp" android:ellipsize="end" android:singleLine="true" android:text="" @@ -22,16 +21,24 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/addButton" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="@+id/space" /> + + - + app:layout_constraintTop_toTopOf="@+id/space" /> + + 1 сервер %d сервера/серверов Убрать %s? - Этот сервер уже добавлен. - Включено (Нет подключения) - Подключено + Нет подключения + Включено Выключено Нет пиров 1 пир %d пира/пиров - Внимание - Не настроено ни одного пира. Если не будет обнаруживаемых пиров в этой сети, то вам надо будет добавить пир вручную, чтобы подключение к Yggdrasil работало как положено. Добавить пира в конфиг Добавить Убрать %s? @@ -40,14 +37,14 @@ Нет подключенных пиров Подключенные пиры Внимание - Конфигурация Сброс Состояние Включить Yggdrasil - Адрес и сеть + Статистика Н/Д Адрес Подсеть + Координаты Конфигурация Пиры Серверы DNS @@ -59,31 +56,13 @@ Находимый через multicast Искать пиров через multicast Yggdrasil будет пытаться подключаться к этим пирам автоматически. Если вы добавите несколько пиров, ваше устройство может быть использовано для переноса данных между другими узлами сети. Чтобы этого избежать настройте только один пир. - Вы можете найти публичные пиры по этой ссылке. - Пиры могут быть найдены с помощью Multicast если они находятся в той же Wi-Fi сети, либо через USB. У них должен быть одинаковый пароль. Трафик в мобильной сети может быть платным. Вы можете отключить мобильные данные в настройках устройства. - Пароль + Пиры могут быть найдены с помощью Multicast если они находятся в той же Wi-Fi сети, либо через USB. Трафик в мобильной сети может быть платным. Вы можете отключить мобильные данные в настройках устройства. Об узле Название устройства Нажмите для изменения Эта информация публична и может появиться на картах сети. Публичный ключ Ваш публичный ключ идентифицирует вас в сети. Его распространение безопасно. - Сбросить ключи (и адрес IPv6) Сбросить настройки Сброс создаст полностью новые настройки. Это изменит ваш публичный ключ и адрес IP. - Выключено - Включено (Нет подключения) - Подключено - Амстердам, Нидерланды - Франкфурт, Германия - Братислава, Словакия - Буффало, США - Сервис VPN - Главный канал нотификаций сервиса - Нажмите здесь чтобы включить Yggdrasil. - Введите полный URI пира для добавления. Yggdrasil будет автоматически подключаться к нему при запуске. - Приватный ключ: - Установить свой ключ - Сохранить - Не найден браузер для открытия ссылки! \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2c8e64a..4f74376 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -5,7 +5,6 @@ #FF3700B3 #FF03DAC5 #FF018786 - #5FBF9F #FF000000 #FFFFFFFF #F2F1F5 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 61c8633..4b169d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,17 +20,14 @@ DNS fixes No servers 1 server - %d servers + %d server Remove %s? - This server is already added. - Enabled (No connectivity) - Connected + No connectivity + Enabled Not enabled No peers 1 peer %d peers - Note - No peers are configured. If there are no multicast peers nearby, you will need to manually configure peers in order for Yggdrasil to connect and work properly. Add Configured Peer Add Remove %s? @@ -40,14 +37,14 @@ No peers currently connected Connected Peers Warning - Config Reset Status Enable Yggdrasil - Network info + Statistics N/A IP Subnet + Coordinates Configuration Peers DNS servers @@ -59,31 +56,13 @@ Discoverable over multicast Search for multicast peers Yggdrasil will automatically attempt to connect to configured peers when started. If you configure more than one peer, your device may carry traffic on behalf of other network nodes. Avoid this by configuring only a single peer. - You can find public peers by opening this link. - Multicast peers will be discovered on the same Wi-Fi network or via USB. They must have the same password. Data charges may apply when using mobile data. You can prevent data usage in the device settings. - Password + Multicast peers will be discovered on the same Wi-Fi network or via USB. Data charges may apply when using mobile data. You can prevent data usage in the device settings. Node Info Device Name Tap to edit Information entered here is public and may be shown on network maps. Public Key Your public key forms your identity on the network. It is safe to be shared. - Regenerate keys (and IPv6-address) Reset configuration Resetting will overwrite with newly generated configuration. Your public keys and IP address on the network will change. - Disabled - Enabled (No connectivity) - Connected - Amsterdam, NL - Frankfurt, DE - Bratislava, SK - Buffalo, US - VPN Service - Main channel for foreground notification - Tap here to enable Yggdrasil. - Enter the full URI of the peer to add. Yggdrasil will automatically connect to this peer when started. - Private key: - Set your own key - Save - No browser found to open the URL! \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml deleted file mode 100644 index a5123f8..0000000 --- a/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index e48c592..ece6c2c 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -18,8 +18,4 @@ @color/white @color/black - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 2f8ae41..0cf859d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.9.20' + ext.kotlin_version = '1.7.20' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.1.4' + classpath "com.android.tools.build:gradle:4.2.2" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt deleted file mode 100644 index eeabdf8..0000000 --- a/fastlane/metadata/android/en-US/changelogs/11.txt +++ /dev/null @@ -1,4 +0,0 @@ -* Added quick-settings tile for fast on/off switching -* Added notification with the connection status (it is needed for quick-settings tile) -* Fixed small UI bugs -* Updated Yggdrasil library to 0.4.7 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/15.txt b/fastlane/metadata/android/en-US/changelogs/15.txt deleted file mode 100644 index 859f418..0000000 --- a/fastlane/metadata/android/en-US/changelogs/15.txt +++ /dev/null @@ -1,3 +0,0 @@ -* Updated core Yggdrasil library to 0.5.1 -* Updated UI to reflect changes in new version -* Fixed small bugs in UI \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/16.txt b/fastlane/metadata/android/en-US/changelogs/16.txt deleted file mode 100644 index 2bf6005..0000000 --- a/fastlane/metadata/android/en-US/changelogs/16.txt +++ /dev/null @@ -1 +0,0 @@ -* Updated core Yggdrasil library to 0.5.4 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/17.txt b/fastlane/metadata/android/en-US/changelogs/17.txt deleted file mode 100644 index 6e775f8..0000000 --- a/fastlane/metadata/android/en-US/changelogs/17.txt +++ /dev/null @@ -1 +0,0 @@ -* Updated core Yggdrasil library to 0.5.6 diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt deleted file mode 100644 index 7c13f7b..0000000 --- a/fastlane/metadata/android/en-US/changelogs/18.txt +++ /dev/null @@ -1,14 +0,0 @@ -Updated core library to 0.5.7, presenting these changes: - -Added -WebSocket support for peerings, by using the new ws:// scheme in Listen and Peers -Additionally, the wss:// scheme can be used to connect to a WebSocket peer behind a HTTPS reverse proxy - -Changed -On Linux, the TUN adapter now uses vectorised reads/writes where possible, which should reduce the amount of CPU time spent on syscalls and potentially improve throughput -Link error handling has been improved and various link error messages have been rewritten to be clearer -Upgrade dependencies - -Fixed -Multiple multicast connections to the same remote machine should now work correctly -You may get two connections in some cases, one inbound and one outbound, this is known and will not cause problems diff --git a/fastlane/metadata/android/en-US/changelogs/19.txt b/fastlane/metadata/android/en-US/changelogs/19.txt deleted file mode 100644 index da2178d..0000000 --- a/fastlane/metadata/android/en-US/changelogs/19.txt +++ /dev/null @@ -1,23 +0,0 @@ -Updated core library to 0.5.9, presenting these changes: - -Changed -The routing algorithm has been updated with RTT-aware link costing, which should prefer lower latency links over higher latency links where possible -The calculated cost is an average of the link RTT, but newly established links are costed higher to begin with, such that unstable peerings can be avoided -Link costs are only used where multiple next-hops are available and will be ignored if there is only one loop-free path to the destination -This is protocol-compatible with existing v0.5.x nodes but will have the best results when peering with nodes that are also running the latest version -The getPeers endpoint will now report the calculated link cost for each given peer -Upgrade dependencies - -Fixed -Multicast discovery should now work again when building Yggdrasil as an Android framework -Multicast discovery will now correctly ignore interfaces that are not marked as running -Ephemeral links, such as those added by multicast, will no longer try to reconnect in a fast loop, fixing a high CPU issue -The TUN interface will no longer stop working when hitting a segment read error from vectorised reads -The AllowedPublicKeys option will once again no longer apply to multicast peerings, as was originally intended -A potential panic when shutting down peering links has been fixed -A redundant system call for setting MTU on OpenBSD has been removed - -Fixes in Android app -Fixed occasional crash on start/stop -Updated some dependencies -Updated Android API to 34 \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/20.txt b/fastlane/metadata/android/en-US/changelogs/20.txt deleted file mode 100644 index 8641cf5..0000000 --- a/fastlane/metadata/android/en-US/changelogs/20.txt +++ /dev/null @@ -1,19 +0,0 @@ -Updated core library to 0.5.12, presenting these changes: - -Fixed -A timing regression which causes a higher level of idle protocol traffic on each peering has been fixed - -Fixes in Android app -Some UI fixes and improvements -Updated some dependencies - -Updates from previous versions: - -Changed -The parent selection algorithm now only chooses a new parent if there is a larger cost benefit to doing so, which should help to stabilise the tree -The bloom filters are now repropagated periodically, to avoid nodes getting stuck with bad state - -Fixed -A memory leak caused by missed cleanup of the peer response map has been fixed -Other bug fixes with bloom filter propagation for off-tree filters and zero vs one bits -TLS-based peering connections now support TLS 1.2 again diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt deleted file mode 100644 index 13f6a6a..0000000 --- a/fastlane/metadata/android/en-US/full_description.txt +++ /dev/null @@ -1,9 +0,0 @@ -Yggdrasil is an early-stage implementation of a fully end-to-end encrypted IPv6 network. -It is lightweight, self-arranging, supported on multiple platforms and allows pretty much any IPv6-capable application to communicate securely with other Yggdrasil nodes. -Yggdrasil does not require you to have IPv6 Internet connectivity - it also works over IPv4. - -This app allows you to connect to Yggdrasil Network and use any service located in this network. It works as VPN service, but all your usual traffic will go trough your provider, not through Yggdrasil Network. - -Also, it is not a goal of the Yggdrasil project to provide anonymity. Direct peers over the Internet will be able to see your IP address and may be able to use this information to determine your location or identity. Multicast-discovered peerings on the same network will typically expose your device MAC address. Other nodes on the network may be able to discern some information about which nodes you are peered with. - -All traffic sent across the Yggdrasil network is encrypted end-to-end. Assuming that our crypto is solid, it cannot be decrypted or read by any intermediate nodes, and can only be decrypted by the recipient for which it was intended. However, please note that Yggdrasil has not been officially externally audited. \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png deleted file mode 100644 index 322635d..0000000 Binary files a/fastlane/metadata/android/en-US/images/featureGraphic.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png deleted file mode 100644 index 124727e..0000000 Binary files a/fastlane/metadata/android/en-US/images/icon.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png deleted file mode 100644 index fbc6f8b..0000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png deleted file mode 100644 index 07e366e..0000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt deleted file mode 100644 index f580d9c..0000000 --- a/fastlane/metadata/android/en-US/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Official implementation for connecting to the Yggdrasil Network from Android \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt deleted file mode 100644 index f8c32ce..0000000 --- a/fastlane/metadata/android/en-US/title.txt +++ /dev/null @@ -1 +0,0 @@ -Yggdrasil \ No newline at end of file diff --git a/fastlane/metadata/android/ru/changelogs/11.txt b/fastlane/metadata/android/ru/changelogs/11.txt deleted file mode 100644 index 54138a2..0000000 --- a/fastlane/metadata/android/ru/changelogs/11.txt +++ /dev/null @@ -1,4 +0,0 @@ -* Добавлена кнопка в шторку для быстрого включения/выключения -* Добавлена компактная нотификация со статусом подключения (требуется для работы кнопки в шторке) -* Исправлены некоторые баги в интерфейсе -* Обновлена библиотека Yggdrasil до 0.4.7 \ No newline at end of file diff --git a/fastlane/metadata/android/ru/changelogs/15.txt b/fastlane/metadata/android/ru/changelogs/15.txt deleted file mode 100644 index 8aaecd6..0000000 --- a/fastlane/metadata/android/ru/changelogs/15.txt +++ /dev/null @@ -1,3 +0,0 @@ -* Обновлена библиотека Yggdrasil до 0.5.1 -* Обновлен интерфейс в соответствии с новой версией библиотеки -* Сделаны небольшие исправления в интерфейсе \ No newline at end of file diff --git a/fastlane/metadata/android/ru/changelogs/16.txt b/fastlane/metadata/android/ru/changelogs/16.txt deleted file mode 100644 index 66c5dba..0000000 --- a/fastlane/metadata/android/ru/changelogs/16.txt +++ /dev/null @@ -1 +0,0 @@ -* Обновлена библиотека Yggdrasil до 0.5.4 \ No newline at end of file diff --git a/fastlane/metadata/android/ru/changelogs/17.txt b/fastlane/metadata/android/ru/changelogs/17.txt deleted file mode 100644 index eb0d4a3..0000000 --- a/fastlane/metadata/android/ru/changelogs/17.txt +++ /dev/null @@ -1 +0,0 @@ -* Обновлена библиотека Yggdrasil до 0.5.6 diff --git a/fastlane/metadata/android/ru/changelogs/18.txt b/fastlane/metadata/android/ru/changelogs/18.txt deleted file mode 100644 index fe1c795..0000000 --- a/fastlane/metadata/android/ru/changelogs/18.txt +++ /dev/null @@ -1,14 +0,0 @@ -Обновлена основная библиотека до версии 0.5.7, в которой представлены следующие изменения: - -Добавлено -Поддержка WebSocket для пиринга с использованием новой схемы ws:// в Listen и Peers -Кроме того, схему wss:// можно использовать для подключения к узлам WebSocket за обратным прокси-сервером HTTPS вроде Nginx - -Изменено -В Linux адаптер TUN теперь использует векторизованную чтение/запись, где это возможно, что должно сократить количество времени ЦП, затрачиваемого на системные вызовы, и потенциально повысить пропускную способность -Улучшена обработка ошибок соединения, а различные сообщения об ошибках соединения были переписаны для большей ясности -Обновление зависимостей - -Исправлено -Несколько мультикаст подключений к одной и той же удаленной машине теперь должны работать правильно -В некоторых случаях вы можете получить два подключения, одно входящее и одно исходящее, это известное поведение и не вызовет проблем \ No newline at end of file diff --git a/fastlane/metadata/android/ru/changelogs/19.txt b/fastlane/metadata/android/ru/changelogs/19.txt deleted file mode 100644 index 4bbe5b8..0000000 --- a/fastlane/metadata/android/ru/changelogs/19.txt +++ /dev/null @@ -1,23 +0,0 @@ -Обновлена основная библиотека до версии 0.5.9, в которой представлены следующие изменения: - -Изменено -Алгоритм маршрутизации был обновлен с учетом стоимости соединения с RTT, что должно отдавать предпочтения соединениям с меньшей задержкой соединениям с большей задержкой, когда это возможно -Расчетная стоимость представляет собой среднее значение RTT соединения, но новые соединения изначально оцениваются выше, так что можно избежать проблем с нестабильными узлами -Стоимость соединения используется только при наличии нескольких следующих переходов и будет игнорироваться, если есть только один путь без петель к месту назначения -Эта версия совместима с существующими узлами v0.5.x, но будет иметь наилучшие результаты при пиринге с узлами, которые также работают под управлением последней версии -Команда getPeers теперь будет сообщать рассчитанную стоимость соединения для каждого заданного пира -Обновлены зависимости - -Исправлено -Обнаружение локальных пиров теперь должно снова работать при сборке Yggdrasil как фреймворка Android -Обнаружение локальных пиров теперь будет правильно игнорировать интерфейсы, которые не помечены как работающие -Эфемерные соединения, такие как добавленные мультикастом, больше не будут пытаться быстро переподключаться в цикле, устранена проблема высокой загрузки ЦП -Интерфейс TUN больше не будет прекращать работу при срабатывании ошибки чтения пакета с помощью векторизованного чтения -Опция AllowedPublicKeys снова больше не будет применяться к локальным пирам, как изначально предполагалось -Потенциальный краш при отключении пиринговых соединений был исправлен -Избыточный системный вызов для установки MTU в OpenBSD был удален - -Исправления в приложении для Android -Исправлен случайный сбой при запуске/остановке -Обновлены некоторые зависимости -Обновлен Android API до 34 \ No newline at end of file diff --git a/fastlane/metadata/android/ru/changelogs/20.txt b/fastlane/metadata/android/ru/changelogs/20.txt deleted file mode 100644 index ef12299..0000000 --- a/fastlane/metadata/android/ru/changelogs/20.txt +++ /dev/null @@ -1,19 +0,0 @@ -Обновлена основная библиотека до версии 0.5.12, в которой представлены следующие изменения: - -Исправлено -Исправлена регрессия синхронизации, которая приводит к более высокому уровню служебного трафика в простое - -Исправления в приложении Android -Исправления и улучшения пользовательского интерфейса -Обновлены некоторые зависимости - -Обновления с предыдущих версий: - -Изменено -Алгоритм выбора родителя теперь выбирает нового родителя только в том случае, если это дает большую экономическую выгоду, что должно помочь стабилизировать дерево -Фильтры Блума теперь периодически распространяются повторно, чтобы избежать застревания узлов в плохом состоянии - -Исправлено -Утечка памяти, вызванная пропущенной очисткой карты ответов пиров -Другие исправления ошибок с распространением фильтра Блума для фильтров вне дерева -Пиринг с использованием TLS теперь снова поддерживают TLS 1.2 \ No newline at end of file diff --git a/fastlane/metadata/android/ru/full_description.txt b/fastlane/metadata/android/ru/full_description.txt deleted file mode 100644 index 1b4f408..0000000 --- a/fastlane/metadata/android/ru/full_description.txt +++ /dev/null @@ -1,9 +0,0 @@ -Yggdrasil это рабочая реализация полностью зашифрованной сети IPv6. -Она лёгкая, само-организующаяся, поддерживающая множество платформ, и позволяющая любому ПО, способному работать с IPv6, свободно коммуницировать с другими узлами сети Yggdrasil. -Yggdrasil не требует Интернет-подключения по IPv6 - она работает и поверх IPv4. - -Это приложение позволяет вам подключиться к Yggdrasil Network и пользоваться любыми сервисами, расположенными в этой сети. Оно работает как сервис VPN, но весь ваш обычный Интернет-трафик будет идти через вашего провайдера, не через сеть Yggdrasil. - -Заметьте, что анонимность не является целью Yggdrasil. Прямые пиры через Интернет смогут видеть ваш настоящий адрес IP и смогут использовать эту информацию для определения вашего местоположения или идентификации. Пиры, подключающиеся с помощью multicast, скорее всего смогут узнать ваш MAC-адрес. Некоторые узлы в сети могут вычислить через какие узлы вы входите в сеть Yggdrasil. - -Весь трафик, пересылаемый через сеть Yggdrasil зашифрован от точки к точке. Предполагая, что наше шифрование реализовано правильно, трафик не может быть расшифрован или прочитан промежуточными узлами, иможет быть расшифрован только адресатом. Однако, просим заметить, что Yggdrasil не подвергался официальному внешнему аудиту. \ No newline at end of file diff --git a/fastlane/metadata/android/ru/images/featureGraphic.png b/fastlane/metadata/android/ru/images/featureGraphic.png deleted file mode 100644 index 322635d..0000000 Binary files a/fastlane/metadata/android/ru/images/featureGraphic.png and /dev/null differ diff --git a/fastlane/metadata/android/ru/images/phoneScreenshots/1.png b/fastlane/metadata/android/ru/images/phoneScreenshots/1.png deleted file mode 100644 index 8447368..0000000 Binary files a/fastlane/metadata/android/ru/images/phoneScreenshots/1.png and /dev/null differ diff --git a/fastlane/metadata/android/ru/images/phoneScreenshots/2.png b/fastlane/metadata/android/ru/images/phoneScreenshots/2.png deleted file mode 100644 index 04ec129..0000000 Binary files a/fastlane/metadata/android/ru/images/phoneScreenshots/2.png and /dev/null differ diff --git a/fastlane/metadata/android/ru/short_description.txt b/fastlane/metadata/android/ru/short_description.txt deleted file mode 100644 index a1078ae..0000000 --- a/fastlane/metadata/android/ru/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Официальный клиент для подключения к Yggdrasil Network с устройств Android \ No newline at end of file diff --git a/fastlane/metadata/android/ru/title.txt b/fastlane/metadata/android/ru/title.txt deleted file mode 100644 index f8c32ce..0000000 --- a/fastlane/metadata/android/ru/title.txt +++ /dev/null @@ -1 +0,0 @@ -Yggdrasil \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3feb240..2521752 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,8 +16,4 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official -#android.enableR8.fullMode=false -android.defaults.buildfeatures.buildconfig=true -android.nonTransitiveRClass=false -android.nonFinalResIds=false \ No newline at end of file +kotlin.code.style=official \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7f3c09a..e148f37 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Nov 27 01:27:23 CET 2023 +#Mon Jun 14 15:11:35 BST 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/libs/yggdrasil-go b/libs/yggdrasil-go deleted file mode 160000 index 213f72b..0000000 --- a/libs/yggdrasil-go +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 213f72b8403ff55a5e38a0fa7d1cd0a093ac4666 diff --git a/readme.md b/readme.md index 98e1bc2..69fe52e 100644 --- a/readme.md +++ b/readme.md @@ -1,23 +1,4 @@ -Yggdrasil Android ------------------ - -Yggdrasil is an early-stage implementation of a fully end-to-end encrypted IPv6 network. It is lightweight, self-arranging, supported on multiple platforms and allows pretty much any IPv6-capable application to communicate securely with other Yggdrasil nodes. Yggdrasil does not require you to have IPv6 Internet connectivity - it also works over IPv4. - -This app allows you to connect to Yggdrasil Network and use any service located in this network. It works as VPN service, but all your usual traffic will go trough your provider, not through Yggdrasil Network. - -Also, it is not a goal of the Yggdrasil project to provide anonymity. Direct peers over the Internet will be able to see your IP address and may be able to use this information to determine your location or identity. Multicast-discovered peerings on the same network will typically expose your device MAC address. Other nodes on the network may be able to discern some information about which nodes you are peered with. - -All traffic sent across the Yggdrasil network is encrypted end-to-end. Assuming that our crypto is solid, it cannot be decrypted or read by any intermediate nodes, and can only be decrypted by the recipient for which it was intended. However, please note that Yggdrasil has not been officially externally audited. - -## Download - -[Get it on F-Droid](https://f-droid.org/packages/eu.neilalexander.yggdrasil/) - -Or get the APK from the [Releases Section](https://github.com/yggdrasil-network/yggdrasil-android/releases/latest). - -## Build Instructions +## build instructions * install gomobile