diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index ca5782e..54cbbdf 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -25,6 +25,8 @@ + - when(call.method) { - "android.requestPermissions" -> androidPermissions(result) "android.registerActiveSite" -> registerActiveSite(result) "nebula.parseCerts" -> nebulaParseCerts(call, result) @@ -242,25 +244,16 @@ class MainActivity: FlutterActivity() { return result.error("required_argument", "id is a required argument", null) } - val siteContainer: SiteContainer = sites!!.getSite(id!!) ?: return result.error("unknown_site", "No site with that id exists", null) + startingSiteContainer = sites!!.getSite(id!!) ?: return result.error("unknown_site", "No site with that id exists", null) + startingSiteContainer!!.updater.setState(true, "Initializing...") - siteContainer.updater.setState(true, "Initializing...") - - var intent = VpnService.prepare(this) + startResult = result + val intent = VpnService.prepare(this) if (intent != null) { - //TODO: ensure this boots the correct bit, I bet it doesn't and we need to go back to the active symlink - intent.putExtra("path", siteContainer.site.path) - intent.putExtra("id", siteContainer.site.id) startActivityForResult(intent, VPN_START_CODE) - } else { - intent = Intent(this, NebulaVpnService::class.java) - intent.putExtra("path", siteContainer.site.path) - intent.putExtra("id", siteContainer.site.id) - onActivityResult(VPN_START_CODE, Activity.RESULT_OK, intent) + onActivityResult(VPN_START_CODE, Activity.RESULT_OK, null) } - - result.success(null) } private fun stopSite() { @@ -400,45 +393,38 @@ class MainActivity: FlutterActivity() { outMessenger?.send(msg) } - private fun androidPermissions(result: MethodChannel.Result) { - val intent = VpnService.prepare(this) - if (intent != null) { - permResult = result - return startActivityForResult(intent, VPN_PERMISSIONS_CODE) - } - - // We already have the permission - result.success(null) - } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { // This is where activity results come back to us (startActivityForResult) - if (requestCode == VPN_PERMISSIONS_CODE && permResult != null) { - // We are processing a response for vpn permissions and the UI is waiting for feedback - //TODO: unlikely we ever register multiple attempts but this could be a trouble spot if we did - val result = permResult!! - permResult = null - if (resultCode == Activity.RESULT_OK) { - return result.success(null) + if (requestCode == VPN_START_CODE) { + // If we are processing a result for VPN permissions and don't get them, let the UI know + val result = startResult!! + val siteContainer = startingSiteContainer!! + startResult = null + startingSiteContainer = null + if (resultCode != Activity.RESULT_OK) { + // The user did not grant permissions + siteContainer.updater.setState(false, "Disconnected") + return result.error("permissions", "Please grant VPN permissions to the app when requested", null) } - //NOTE: flutter side doesn't care about the message currently, only the code - return result.error("PERMISSIONS", "User did not grant permission", null) - - } else if (requestCode == VPN_START_CODE) { - // We are processing a response for permissions while starting the VPN - // (or reusing code in the event we already have perms) - startService(data) + // Start the VPN service + val intent = Intent(this, NebulaVpnService::class.java).apply { + putExtra("path", siteContainer.site.path) + putExtra("id", siteContainer.site.id) + } + startService(intent) if (outMessenger == null) { - bindService(data, connection, 0) + bindService(intent, connection, 0) } - return + + return result.success(null) } // The file picker needs us to super super.onActivityResult(requestCode, resultCode, data) } + /** Defines callbacks for service binding, passed to bindService() */ private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { diff --git a/lib/screens/MainScreen.dart b/lib/screens/MainScreen.dart index 9dfb02b..06a9cc8 100644 --- a/lib/screens/MainScreen.dart +++ b/lib/screens/MainScreen.dart @@ -284,43 +284,6 @@ class _MainScreenState extends State { } _loadSites() async { - if (Platform.isAndroid) { - try { - await platform.invokeMethod("android.requestPermissions"); - } on PlatformException catch (err) { - if (err.code == "PERMISSIONS") { - setState(() { - error = [ - Text("Permissions Required", style: TextStyle(fontWeight: FontWeight.bold)), - Text( - "VPN permissions are required for nebula to run, click the button below request and accept the appropriate permissions.", - textAlign: TextAlign.center), - ElevatedButton( - onPressed: () { - error = null; - _loadSites(); - }, - child: Text("Request Permissions")), - ]; - }); - } else { - setState(() { - error = [ - Text("Unknown Error", style: TextStyle(fontWeight: FontWeight.bold)), - Text(err.message ?? 'An unknown error occurred', textAlign: TextAlign.center) - ]; - }); - } - } catch (err) { - setState(() { - error = [ - Text("Unknown Error", style: TextStyle(fontWeight: FontWeight.bold)), - Text(err.toString(), textAlign: TextAlign.center) - ]; - }); - } - } - //TODO: This can throw, we need to show an error dialog Map rawSites = jsonDecode(await platform.invokeMethod('listSites')); bool hasErrors = false; diff --git a/nebula/go.mod b/nebula/go.mod index e2061c7..0b18d44 100644 --- a/nebula/go.mod +++ b/nebula/go.mod @@ -34,8 +34,10 @@ 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.1 // indirect + golang.org/x/mobile v0.0.0-20221110043201-43a038452099 // indirect golang.org/x/mod v0.7.0 // indirect golang.org/x/net v0.2.0 // indirect + golang.org/x/sync v0.1.0 // indirect golang.org/x/sys v0.2.0 // indirect golang.org/x/term v0.2.0 // indirect golang.org/x/tools v0.3.0 // indirect diff --git a/nebula/go.sum b/nebula/go.sum index 7ab9647..319d941 100644 --- a/nebula/go.sum +++ b/nebula/go.sum @@ -275,6 +275,8 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20221110043201-43a038452099 h1:aIu0lKmfdgtn2uTj7JI2oN4TUrQvgB+wzTPO23bCKt8= +golang.org/x/mobile v0.0.0-20221110043201-43a038452099/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -340,6 +342,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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=