From f4e1a75cfc9681e97e461f219d460fe87b26e9e0 Mon Sep 17 00:00:00 2001 From: Revertron <105154+Revertron@users.noreply.github.com> Date: Sat, 28 Oct 2023 23:31:32 +0200 Subject: [PATCH] Changes for updating to Yggdrasil 0.5. (#49) --- app/build.gradle | 23 +++++----- app/src/main/AndroidManifest.xml | 5 ++- .../yggdrasil/ConfigurationProxy.kt | 15 +++++-- .../yggdrasil/GlobalApplication.kt | 18 ++++++-- .../neilalexander/yggdrasil/MainActivity.kt | 16 +++---- .../yggdrasil/PacketTunnelProvider.kt | 45 ++++++++++++------- .../neilalexander/yggdrasil/PeersActivity.kt | 34 +++++++++++++- .../yggdrasil/SettingsActivity.kt | 39 ++++++++++++++-- app/src/main/res/layout/activity_main.xml | 6 +-- app/src/main/res/layout/activity_peers.xml | 31 +++++++++++++ app/src/main/res/layout/dialog_set_keys.xml | 9 ---- app/src/main/res/values-ru/strings.xml | 8 ++-- app/src/main/res/values/strings.xml | 8 ++-- build.gradle | 4 +- gradle/wrapper/gradle-wrapper.properties | 4 +- libs/yggdrasil-go | 2 +- 16 files changed, 189 insertions(+), 78 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 854ae6a..c4cccc3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,15 +4,14 @@ plugins { } android { - compileSdkVersion 29 - buildToolsVersion "30.0.3" + compileSdkVersion 33 defaultConfig { applicationId "eu.neilalexander.yggdrasil" minSdkVersion 21 - targetSdkVersion 29 - versionCode 13 - versionName "0.1-013" + targetSdkVersion 33 + versionCode 14 + versionName "0.1-014" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -51,12 +50,12 @@ android { dependencies { implementation fileTree(include: ['*.aar'], dir: 'libs') implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - 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' + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.preference:preference-ktx:1.2.1' testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e5231bb..a6e947e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,7 @@ + - - + + json.put("PrivateKey", newJson.getString("PrivateKey")) - json.put("PublicKey", newJson.getString("PublicKey")) } } - fun setKeys(privateKey: String, publicKey: String) { + fun setKeys(privateKey: String) { updateJSON { json -> json.put("PrivateKey", privateKey) - json.put("PublicKey", publicKey) } } @@ -62,7 +60,8 @@ object ConfigurationProxy { { "Regex": ".*", "Beacon": true, - "Listen": true + "Listen": true, + "Password": "" } """.trimIndent())) json.put("MulticastInterfaces", ar) @@ -94,4 +93,12 @@ object ConfigurationProxy { (json.getJSONArray("MulticastInterfaces").get(0) as JSONObject).put("Beacon", value) } } + + var multicastPassword: String + get() = (json.getJSONArray("MulticastInterfaces").get(0) as JSONObject).getString("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/GlobalApplication.kt b/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt index b2f02b4..85f9a09 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/GlobalApplication.kt @@ -47,8 +47,10 @@ class GlobalApplication: Application(), YggStateReceiver.StateReceiver { @RequiresApi(Build.VERSION_CODES.N) override fun onStateChange(state: State) { if (state != currentState) { - val componentName = ComponentName(this, YggTileService::class.java) - TileService.requestListeningState(this, componentName) + 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) @@ -68,7 +70,11 @@ fun createServiceNotification(context: Context, state: State): Notification { val intent = Intent(context, MainActivity::class.java).apply { this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } - val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + 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) @@ -91,7 +97,11 @@ fun createPermissionMissingNotification(context: Context): Notification { val intent = Intent(context, MainActivity::class.java).apply { this.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } - val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + 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) diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt index af70595..947dd07 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/MainActivity.kt @@ -24,7 +24,7 @@ class MainActivity : AppCompatActivity() { private lateinit var enabledLabel: TextView private lateinit var ipAddressLabel: TextView private lateinit var subnetLabel: TextView - private lateinit var coordinatesLabel: TextView + private lateinit var treeLengthLabel: TextView private lateinit var peersLabel: TextView private lateinit var peersRow: LinearLayoutCompat private lateinit var dnsLabel: TextView @@ -53,7 +53,7 @@ class MainActivity : AppCompatActivity() { enabledLabel = findViewById(R.id.yggdrasilStatusLabel) ipAddressLabel = findViewById(R.id.ipAddressValue) subnetLabel = findViewById(R.id.subnetValue) - coordinatesLabel = findViewById(R.id.coordinatesValue) + treeLengthLabel = findViewById(R.id.treeLengthValue) peersLabel = findViewById(R.id.peersValue) peersRow = findViewById(R.id.peersTableRow) dnsLabel = findViewById(R.id.dnsValue) @@ -155,11 +155,11 @@ class MainActivity : AppCompatActivity() { "state" -> { enabledLabel.text = if (intent.getBooleanExtra("started", false)) { var count = 0 - if (intent.hasExtra("dht")) { - val dht = intent.getStringExtra("dht") - if (dht != null && dht != "null") { - val dhtState = JSONArray(dht) - count = dhtState.length() + if (intent.hasExtra("tree")) { + val tree = intent.getStringExtra("tree") + if (tree != null && tree != "null") { + val treeState = JSONArray(tree) + count = treeState.length() } } if (count == 0) { @@ -175,7 +175,7 @@ class MainActivity : AppCompatActivity() { } ipAddressLabel.text = intent.getStringExtra("ip") ?: "N/A" subnetLabel.text = intent.getStringExtra("subnet") ?: "N/A" - coordinatesLabel.text = intent.getStringExtra("coords") ?: "[]" + treeLengthLabel.text = intent.getStringExtra("coords") ?: "0" if (intent.hasExtra("peers")) { val peerState = JSONArray(intent.getStringExtra("peers") ?: "[]") peersLabel.text = when (val count = peerState.length()) { diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt b/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt index 36d3b56..7259e80 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/PacketTunnelProvider.kt @@ -1,7 +1,8 @@ package eu.neilalexander.yggdrasil -import android.content.* +import android.content.Intent import android.net.VpnService +import android.net.wifi.WifiManager import android.os.Build import android.os.ParcelFileDescriptor import android.system.OsConstants @@ -42,6 +43,7 @@ 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() @@ -101,6 +103,13 @@ open class PacketTunnelProvider: VpnService() { 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()) @@ -163,16 +172,7 @@ open class PacketTunnelProvider: VpnService() { updater() } - var 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) - - intent = Intent(YGG_STATE_INTENT) + var intent = Intent(YGG_STATE_INTENT) intent.putExtra("state", STATE_ENABLED) LocalBroadcastManager.getInstance(this).sendBroadcast(intent) } @@ -221,6 +221,7 @@ open class PacketTunnelProvider: VpnService() { stopForeground(true) stopSelf() + multicastLock?.release() } private fun connect() { @@ -231,27 +232,37 @@ open class PacketTunnelProvider: VpnService() { } private fun updater() { + Thread.sleep(500) var lastStateUpdate = System.currentTimeMillis() updates@ while (started.get()) { + val treeJSON = yggdrasil.treeJSON + var treeLength = 0 + if (treeJSON != null && treeJSON != "null") { + val treeState = JSONArray(treeJSON) + treeLength = treeState.length() + } 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("coords", yggdrasil.coordsString) + intent.putExtra("pubkey", yggdrasil.publicKeyString) + intent.putExtra("coords", "$treeLength") intent.putExtra("peers", yggdrasil.peersJSON) - intent.putExtra("dht", yggdrasil.dhtjson) + intent.putExtra("tree", treeJSON) LocalBroadcastManager.getInstance(this).sendBroadcast(intent) } val curTime = System.currentTimeMillis() if (lastStateUpdate + 10000 < curTime) { val intent = Intent(YGG_STATE_INTENT) var state = STATE_ENABLED - val dht = yggdrasil.dhtjson - if (dht != null && dht != "null") { - val dhtState = JSONArray(dht) - val count = dhtState.length() + if (yggdrasil.routingEntries > 0) { + state = STATE_CONNECTED + } + if (treeJSON != null && treeJSON != "null") { + val treeState = JSONArray(treeJSON) + val count = treeState.length() if (count > 1) state = STATE_CONNECTED } diff --git a/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt b/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt index a3f4e08..8e67280 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/PeersActivity.kt @@ -7,10 +7,13 @@ 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.core.widget.doOnTextChanged import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.material.textfield.TextInputEditText import org.json.JSONArray @@ -27,6 +30,7 @@ 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?) { @@ -62,6 +66,30 @@ class PeersActivity : AppCompatActivity() { 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 { @@ -156,7 +184,7 @@ class PeersActivity : AppCompatActivity() { val view = inflater.inflate(R.layout.peers_connected, null) val ip = peer.getString("IP") view.findViewById(R.id.addressLabel).text = ip - view.findViewById(R.id.detailsLabel).text = peer.getString("Remote") + view.findViewById(R.id.detailsLabel).text = peer.getString("URI") connectedTableLayout.addView(view) } } @@ -168,7 +196,9 @@ class PeersActivity : AppCompatActivity() { when (intent.getStringExtra("type")) { "state" -> { if (intent.hasExtra("peers")) { - val peersArray = JSONArray(intent.getStringExtra("peers") ?: "[]") + val peers1 = intent.getStringExtra("peers") + //Log.i("PeersActivity", "Peers json: $peers1") + val peersArray = JSONArray(peers1 ?: "[]") 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 acb2b54..5831776 100644 --- a/app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt +++ b/app/src/main/java/eu/neilalexander/yggdrasil/SettingsActivity.kt @@ -1,8 +1,12 @@ 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 @@ -13,6 +17,7 @@ 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() { @@ -87,11 +92,10 @@ class SettingsActivity : AppCompatActivity() { val view = inflater.inflate(R.layout.dialog_set_keys, null) val builder: AlertDialog.Builder = AlertDialog.Builder(ContextThemeWrapper(this, R.style.Theme_MaterialComponents_DayNight_Dialog)) val privateKey = view.findViewById(R.id.private_key) - val publicKey = view.findViewById(R.id.public_key) builder.setTitle(getString(R.string.set_keys)) builder.setView(view) builder.setPositiveButton(getString(R.string.save)) { dialog, _ -> - config.setKeys(privateKey.text.toString(), publicKey.text.toString()) + config.setKeys(privateKey.text.toString()) updateView() dialog.dismiss() } @@ -113,13 +117,40 @@ class SettingsActivity : AppCompatActivity() { } private fun updateView() { - val nodeinfo = config.getJSON().optJSONObject("NodeInfo") + val json = config.getJSON() + val nodeinfo = json.optJSONObject("NodeInfo") if (nodeinfo != null) { deviceNameEntry.setText(nodeinfo.getString("name"), TextView.BufferType.EDITABLE) } else { deviceNameEntry.setText("", TextView.BufferType.EDITABLE) } - publicKeyLabel.text = config.getJSON().getString("PublicKey") + publicKeyLabel.text = json.optString("PublicKey") + } + + 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")) { + val tree = intent.getStringExtra("pubkey") + if (tree != null && tree != "null") { + publicKeyLabel.text = intent.getStringExtra("pubkey") + } + } + } } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index bf7028c..a974a99 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -210,11 +210,11 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="0" - android:text="@string/main_coordinates" + android:text="@string/main_tree_length" android:textColor="?attr/textDefault" /> diff --git a/app/src/main/res/layout/activity_peers.xml b/app/src/main/res/layout/activity_peers.xml index 88724c2..33269b8 100644 --- a/app/src/main/res/layout/activity_peers.xml +++ b/app/src/main/res/layout/activity_peers.xml @@ -217,6 +217,37 @@ + + + + + + + + - - - Н/Д Адрес Подсеть - Координаты + Высота дерева Конфигурация Пиры Серверы DNS @@ -58,7 +58,8 @@ Находимый через multicast Искать пиров через multicast Yggdrasil будет пытаться подключаться к этим пирам автоматически. Если вы добавите несколько пиров, ваше устройство может быть использовано для переноса данных между другими узлами сети. Чтобы этого избежать настройте только один пир. - Пиры могут быть найдены с помощью Multicast если они находятся в той же Wi-Fi сети, либо через USB. Трафик в мобильной сети может быть платным. Вы можете отключить мобильные данные в настройках устройства. + Пиры могут быть найдены с помощью Multicast если они находятся в той же Wi-Fi сети, либо через USB. У них должен быть одинаковый пароль. Трафик в мобильной сети может быть платным. Вы можете отключить мобильные данные в настройках устройства. + Пароль Об узле Название устройства Нажмите для изменения @@ -79,8 +80,7 @@ Главный канал нотификаций сервиса Нажмите здесь чтобы включить Yggdrasil. Введите полный URI пира для добавления. Yggdrasil будет автоматически подключаться к нему при запуске. - Публичный ключ: Приватный ключ: - Установить свои ключи + Установить свой ключ Сохранить \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 96e6545..7bf2dac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -46,7 +46,7 @@ N/A IP Subnet - Coordinates + Tree length Configuration Peers DNS servers @@ -58,7 +58,8 @@ 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. - 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. + 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 Node Info Device Name Tap to edit @@ -79,8 +80,7 @@ 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. - Public key: Private key: - Set your own keys + Set your own key Save \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0cf859d..67f7870 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.7.20' + ext.kotlin_version = '1.9.10' repositories { google() mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:4.2.2" + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e148f37..eb18bbf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 14 15:11:35 BST 2021 +#Sat Aug 26 21:38:34 CEST 2023 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/libs/yggdrasil-go b/libs/yggdrasil-go index 14f1cd4..7f9d4f3 160000 --- a/libs/yggdrasil-go +++ b/libs/yggdrasil-go @@ -1 +1 @@ -Subproject commit 14f1cd4696a37b0f7fdcb067fac337c46953f8af +Subproject commit 7f9d4f3f6d06262e212a8dd101d51fda134332da