From ec1af2974a424bcb53743b6172838e737e074565 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Fri, 1 Dec 2023 15:26:21 -0500 Subject: [PATCH] Fix encryption errors after restoring to a new phone (#143) When a user restores to a new phone, their TPM will no longer be able to decrypt the encrypted credentials. We have code already in place to delete "invalid" sites, which cleans these up by removing them. However, when trying to save a new site, Android continues to try to use the old keys which are no longer decryptable. So, when saving new encrypted files, simply reset the crypto keys if we are unable to encrypt. --- .../net/defined/mobile_nebula/EncFile.kt | 45 ++++++++-- .../net/defined/mobile_nebula/MainActivity.kt | 4 + android/build.gradle | 2 +- lib/screens/MainScreen.dart | 13 +-- nebula/go.mod | 14 ++-- nebula/go.sum | 28 +++++++ pubspec.lock | 84 ++++++++----------- 7 files changed, 123 insertions(+), 67 deletions(-) diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/EncFile.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/EncFile.kt index 5cbc2be..e9a641d 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/EncFile.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/EncFile.kt @@ -1,22 +1,57 @@ package net.defined.mobile_nebula import android.content.Context +import android.util.Log import androidx.security.crypto.EncryptedFile import androidx.security.crypto.MasterKeys import java.io.* +import java.security.KeyStore class EncFile(private val context: Context) { + companion object { + // Borrowed from androidx.security.crypto.MasterKeys + private const val ANDROID_KEYSTORE = "AndroidKeyStore" + + // Borrowed from androidx.security.crypto.EncryptedFile + private const val KEYSET_PREF_NAME = "__androidx_security_crypto_encrypted_file_pref__" + } + private val scheme = EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB - private val master: String = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC) + private val spec = MasterKeys.AES256_GCM_SPEC + private var master: String = MasterKeys.getOrCreate(spec) fun openRead(file: File): BufferedReader { - val eFile = EncryptedFile.Builder(file, context, master, scheme).build() - return eFile.openFileInput().bufferedReader() + // We may fail to decrypt the file, in which case we'll raise an exception. + // Callers should handle this exception by deleting the invalid file. + return build(file).openFileInput().bufferedReader() } fun openWrite(file: File): BufferedWriter { - val eFile = EncryptedFile.Builder(file, context, master, scheme).build() - return eFile.openFileOutput().bufferedWriter() + return try { + build(file).openFileOutput().bufferedWriter() + } catch (e: Exception) { + // If we fail to open the file, it's likely because the master key no longer works. + // We'll try to reset the master key and try again. + resetMasterKey() + + build(file).openFileOutput().bufferedWriter() + } } + private fun build(file: File): EncryptedFile { + return EncryptedFile.Builder(file, context, master, scheme).build() + } + + fun resetMasterKey() { + // Reset the master key + KeyStore.getInstance(ANDROID_KEYSTORE).apply { + load(null) + deleteEntry(master) + } + // And reset the shared preference containing the file encryption key + context.deleteSharedPreferences(KEYSET_PREF_NAME) + + // Re-create the master key now so future calls don't fail + master = MasterKeys.getOrCreate(spec) + } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt b/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt index 90c7b9b..dd83799 100644 --- a/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt +++ b/android/app/src/main/kotlin/net/defined/mobile_nebula/MainActivity.kt @@ -84,6 +84,10 @@ class MainActivity: FlutterActivity() { "active.setRemoteForTunnel" -> activeSetRemoteForTunnel(call, result) "active.closeTunnel" -> activeCloseTunnel(call, result) + "debug.clearKeys" -> { + EncFile(context).resetMasterKey() + } + else -> result.notImplemented() } } diff --git a/android/build.gradle b/android/build.gradle index 3c12826..9444e0b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -30,6 +30,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/screens/MainScreen.dart b/lib/screens/MainScreen.dart index 7712d9a..337d0b1 100644 --- a/lib/screens/MainScreen.dart +++ b/lib/screens/MainScreen.dart @@ -119,7 +119,7 @@ class _MainScreenState extends State { children: [ _debugSave(badDebugSave), _debugSave(goodDebugSave), - _debugDNEnroll(), + _debugClearKeys(), ], mainAxisAlignment: MainAxisAlignment.center, ); @@ -289,15 +289,16 @@ class _MainScreenState extends State { ); } - Widget _debugDNEnroll() { + Widget _debugClearKeys() { return CupertinoButton( - child: Text('DN Enroll'), - onPressed: () => Utils.openPage(context, (context) { - return EnrollmentScreen(allowCodeEntry: true); - }), + child: Text("Clear Keys"), + onPressed: () async { + await platform.invokeMethod("debug.clearKeys", null); + }, ); } + _loadSites() async { //TODO: This can throw, we need to show an error dialog Map rawSites = jsonDecode(await platform.invokeMethod('listSites')); diff --git a/nebula/go.mod b/nebula/go.mod index 3122f02..902c105 100644 --- a/nebula/go.mod +++ b/nebula/go.mod @@ -8,7 +8,7 @@ require ( github.com/DefinedNet/dnapi v0.0.0-20221117210952-6f56f055f991 github.com/sirupsen/logrus v1.9.2 github.com/slackhq/nebula v1.7.2 - golang.org/x/crypto v0.9.0 + golang.org/x/crypto v0.16.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -34,11 +34,13 @@ require ( github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect github.com/vishvananda/netlink v1.1.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect - golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/tools v0.16.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/nebula/go.sum b/nebula/go.sum index 9107c5c..af7b1ea 100644 --- a/nebula/go.sum +++ b/nebula/go.sum @@ -148,12 +148,22 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da h1:gS9sVMAeHM+gVBmM9bTM6vUi/NHv58O3QzJ3vjjN84M= +golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da/go.mod h1:IEceR0jfVklLJXrbUe90rfdAFAYDW0SQwKl4qvO1GBQ= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a h1:sYbmY3FwUWCBTodZL1S3JUuOvaW6kM2o+clDzzDNBWg= +golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a/go.mod h1:Ede7gF0KGoHlj822RtphAHK1jLdrcuRBZg0sF1Q+SPc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -166,6 +176,10 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -174,6 +188,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -191,9 +207,17 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -204,6 +228,10 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pubspec.lock b/pubspec.lock index 0be5c11..df2e762 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,21 +42,21 @@ packages: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.3+2" + version: "0.3.3+4" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" fake_async: dependency: transitive description: @@ -70,21 +70,21 @@ packages: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.1.2" + version: "6.1.4" file_picker: dependency: "direct main" description: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "5.2.2" + version: "5.2.10" flutter: dependency: "direct main" description: flutter @@ -103,21 +103,21 @@ packages: name: flutter_platform_widgets url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.2.6" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.0.15" flutter_svg: dependency: "direct main" description: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "1.1.5" + version: "1.1.6" flutter_test: dependency: "direct dev" description: flutter @@ -169,7 +169,7 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.4" package_info: dependency: "direct main" description: @@ -204,77 +204,63 @@ packages: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.1.0" path_provider_android: dependency: transitive description: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" - path_provider_ios: + version: "2.1.0" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios + name: path_provider_foundation url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.3.0" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.4" + version: "2.2.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.2.0" petitparser: dependency: transitive description: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "5.1.0" platform: dependency: transitive description: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.4" + version: "2.1.5" pull_to_refresh: dependency: "direct main" description: @@ -288,14 +274,14 @@ packages: name: share_plus url: "https://pub.dartlang.org" source: hosted - version: "6.3.0" + version: "6.3.4" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "3.3.1" sky_engine: dependency: transitive description: flutter @@ -349,63 +335,63 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.2" url_launcher: dependency: "direct main" description: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.1.6" + version: "6.1.11" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.13" + version: "6.0.38" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.13" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.7" uuid: dependency: "direct main" description: @@ -426,14 +412,14 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "3.1.1" + version: "3.1.4" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "1.0.2" xml: dependency: transitive description: @@ -443,4 +429,4 @@ packages: version: "6.1.0" sdks: dart: ">=2.18.1 <3.0.0" - flutter: ">=3.0.0" + flutter: ">=3.3.0"