Addresses the errors seen in DefinedNet/mobile_nebula/actions/runs/11221064890/job/31190581077#step:13:1260
Locally I am able to perform most of a release build after removing these proguard rules which were previously added to avoid minification stripping out flutter code. That seems to no longer be required, though.
This updates kotlin, gson, AGP, and WorkManager to the latest versions.
It also updates the README to include the correct ndk version for our AGP, as specified here: developer.android.com/build/releases/gradle-plugin#compatibility
I ran the Gradle Upgrade Assistant to get us on the latest version of gradle, but two of our dependencies didn't support it.
- https://pub.dev/documentation/package_info/latest/
- https://github.com/AmolGangadhare/flutter_barcode_scanner
`pacakge_info` is officially deprecated and replaced by `package_info_plus`, which is what I've swapped to here.
A bigger change was switching to https://github.com/juliansteenbakker/mobile_scanner. It does seem to work a bit better than the other one, and does not throw an error now when cancelling the QR code collection, as it did before. I've tested on android in the simulator, and iOS with an actual device.
To test adding a cert:
1. Create a CA on your computer with `nebula-cert ca -name test-mobile`. This will create a `ca.crt` and `ca.key`
2. Tap the + button in the mobile app to add a site
3. Tap the "Certificate" row
4. Copy the public key to a file on your computer like `test.pub`
5. Create a signed cert with `nebula-cert sign -name test-mobile -ip 192.168.0.20/24 -in-pub test.pub`
6. Create a QR code for it: `nebula-cert print -out-qr "qr.png" -path ./test-mobile.crt`
7. In Android studio, in the "Running devices" tab, open the simulator's extended controls:
<img width="509" alt="Android Studio 2024-09-23 13 08 08" src="https://github.com/user-attachments/assets/c1f8288e-374c-457c-942a-4109240102ab">
8. Choose the Camera option, and add the qr code image to the wall of the virtual scene
<img width="679" alt="image" src="https://github.com/user-attachments/assets/bafaa9af-72e4-4444-9704-9876c53c883c">
9. Back in the app, when you choose QR Code and "Scan a QR code`, the virtual scene should open. Hold shift, then move your mouse to look around. Turn around 180 degrees, and walk forward into the other room (can go through the walls) using the `w` key. When you get the QR code into the white border, the scanner should close and apply the certificate settings. If you use a nonsense QR code, or a QR code with a non-matching key, or a CA QR code, you should get an error message when it scans.
The process for scanning a CA qr code is similar.
1. Run `nebula-cert print -out-qr "qr-ca.png" -path ./ca.crt`
2. Replace the QR in the extended controls
3. Tap CA when adding a site
4. The rest of the process is the same as above.
iOS is similar, except you'll need to use a real device, as the simulator does not include a virtual scene like Android does.
This updates flutter to 3.24.1, the latest stable version, and also updates our flutter dependencies to latest.
It targets the latest android sdk, 34, which is required if we want to publish a new version to the Google Play store.
I also needed to make a few adjustments to handle deprecations. The biggest change is that I needed to wrap the main widget in MaterialApp to avoid problems with AdaptiveSwitch in iOS.
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.
Previously VPN permissions were requested when the UI was loaded. If the
user denied the permissions it would have to be force stopped and
reopened to get another permission request grant.
Additionally, when requesting VPN permissions Android will kill any
other running VPN service. This avoids that behavior unless a site is
explicitly started.
Also disables the app from showing up in the "Always On" settings.
I think this closes the loop on DNS issues I was experiencing.
Previously, after starting Nebula, DNS would work until you switched
networks (e.g. from mobile to WiFi or vice-versa). This was fixed by
removing some explicit DNS server sets in commit
a283bf8010. This casued DNS to work in
`adb shell` even after toggling networks.
However, it did not actually fix the problem for Android applications.
The new behavior is that they would work while on WiFi, but fail on a
mobile network.
To quote Android docs:
> Allows traffic from the specified address family. By default, if no
> address, route or DNS server of a specific family (IPv4 or IPv6) is
> added to this VPN, then all outgoing traffic of that family is blocked.
> If any address, route or DNS server is added, that family is allowed.
> This method allows an address family to be unblocked even without adding
> an address, route or DNS server of that family. Traffic of that family
> will then typically fall-through to the underlying network if it's
> supported. family must be either AF_INET (for IPv4) or AF_INET6 (for
> IPv6). IllegalArgumentException is thrown if it's neither.
In my case, my home network supports only IPv4 while my mobile network
uses DNS over IPv6. Since my Nebula routes are IPv4-only, IPv6 traffic
stopped working, and DNS requests failed.
Previously when `stopVpn()` was called, it was possible for the network
change callback to fire while we were in the middle of shutting down.
This commit unregisters the network change callback before telling
Nebula to shutdown.
Fixes#15. When tapping the toggle in rapid succession,
`NebulaVpnService.onStartCommand` is called twice, in serial. This
method includes logic to show an error to the user if they somehow
attempt to connect to a service while already connected.
However, this method of showing an error message (calling
`announceExit`) sends a signal to `MainActivity` telling it the service
has exited, and that it should set the UI state to "Disconnected." It
does not actually disconnect the service at this point, resulting in a
state mismatch in which you cannot actually disconnect the service.
The solution in this commit is to remove this signalling and simply
return out of `onStartCommand` to avoid processing the start request
twice if the site is already running.
- Updated README with some maybe-helpful instructions for downgrading
flutter to a version that will build the project
- Added a step to create a missing directory to the Gradle build
(otherwise the build fails)
- Set `shrinkResources false` - otherwise you get an error that you
can't shrink resources unless you also enable minifying