Compare commits

..

110 Commits

Author SHA1 Message Date
Jason A. Donenfeld 9e33d9e56b version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-04-04 15:31:52 +02:00
Jason A. Donenfeld 9fae327315 tools: pass -Wl,--build-id=none and -buildid= to toolchain
Unfortunately, we need to fix this up in both the Makefile and in CMake,
because add_link_options doesn't immediately reflect on the CMake
variables in scope.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-04-04 15:14:28 +02:00
Jason A. Donenfeld a6f5eb0dd2 build: exclude extra kotlin cruft from release build
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-04-04 15:14:28 +02:00
Jason A. Donenfeld c3c4cd05b1 ui: don't play with status and navigation colors on old APIs
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 16:05:41 +02:00
Jason A. Donenfeld 58c19385a3 ui: do not allow double clicking fab to show menu twice
Exception java.lang.IllegalStateException:
  at androidx.fragment.app.FragmentStore.addFragment (FragmentStore.java:92)
  at androidx.fragment.app.FragmentManager.addFragment (FragmentManager.java:1481)
  at androidx.fragment.app.BackStackRecord.executeOps (BackStackRecord.java:387)
  at androidx.fragment.app.FragmentManager.executeOps (FragmentManager.java:1965)
  at androidx.fragment.app.FragmentManager.executeOpsTogether (FragmentManager.java:1873)
  at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute (FragmentManager.java:1823)
  at androidx.fragment.app.FragmentManager.execPendingActions (FragmentManager.java:1760)
  at androidx.fragment.app.FragmentManager$5.run (FragmentManager.java:547)
  at android.os.Handler.handleCallback (Handler.java:938)
  at android.os.Handler.dispatchMessage (Handler.java:99)
  at android.os.Looper.loop (Looper.java:268)
  at android.app.ActivityThread.main (ActivityThread.java:8101)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:627)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:997)

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 15:15:39 +02:00
Jason A. Donenfeld 354e1c0ed9 ui: remove unneeded @JvmStatic annotations
These are only needed on methods called from databindings, since those
compile to java.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 15:07:45 +02:00
Jason A. Donenfeld 02b9677a9c ui: add list selection highlight color for tablet
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 14:53:28 +02:00
Jason A. Donenfeld 82d26e61da ui: the button is not always blue with Material You
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 14:23:10 +02:00
Jason A. Donenfeld a113770868 ui: use app resources instead of ctx for strings in callback
Exception java.lang.IllegalStateException:
  at androidx.fragment.app.Fragment.requireContext (Fragment.java:967)
  at com.wireguard.android.fragment.TunnelListFragment$tunnelFileImportResultLauncher$1$1.invokeSuspend (TunnelListFragment.kt:64)
  at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
  at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:104)
  at android.os.Handler.handleCallback (Handler.java:761)
  at android.os.Handler.dispatchMessage (Handler.java:98)
  at android.os.Looper.loop (Looper.java:156)
  at android.app.ActivityThread.main (ActivityThread.java:6617)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:942)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:832)

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 13:54:06 +02:00
Jason A. Donenfeld b734f44200 ui: use M3 theme for TV to prevent crash
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-30 13:40:05 +02:00
Jason A. Donenfeld ee16d1329b version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 18:32:34 +02:00
Jason A. Donenfeld 900654e6b1 tools: use NDK's make binary rather than system's
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 18:31:38 +02:00
Jason A. Donenfeld a0cba19645 strings: sync crowdin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 17:53:43 +02:00
Jason A. Donenfeld d7ccbd92e5 ui: add log items in buffered batches
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 17:47:36 +02:00
Jason A. Donenfeld 2da80e8dee ui: color verbose logs the same as debug logs
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 16:02:47 +02:00
Jason A. Donenfeld 450ef8ce1c ui: don't call getColor on already resolved attribute
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 16:02:47 +02:00
Jason A. Donenfeld 58e7b7a069 ui: bring back dark log viewer colors
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-28 16:02:47 +02:00
Harsh Shandilya d354831c6a ui: fix inconsistent style naming
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-28 17:42:35 +05:30
Harsh Shandilya fcb7caed23 gradle: opt into new publishing APIs
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-28 17:42:07 +05:30
Harsh Shandilya c7d1c4baba ui: adjust log viewer text sizes
10sp is below the minimum 11sp recommended for readability

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-28 00:53:18 +05:30
Harsh Shandilya 76423ce868 ui: use M3 styles everywhere
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-28 00:51:47 +05:30
Jason A. Donenfeld b37006ce2f ui: add possibility for themed icon
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-27 18:05:39 +02:00
Jason A. Donenfeld b072130e37 ui: add list selection backgrounds
Harsh - feel free to replace this commit with something better. I'm sure
it's the most terrible way to do it.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-27 18:00:00 +02:00
Jason A. Donenfeld 54dfa7bdd7 ui: cancel actionmode when pressing back button
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-27 17:59:00 +02:00
Jason A. Donenfeld e5a75307c2 ui: simplify actionmode cast
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-27 17:47:09 +02:00
Harsh Shandilya 4fcb8c4792 ui: introduce a fresh set of Material3 themes and migrate to them
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-27 16:10:24 +02:00
Harsh Shandilya fb05b358c0 ui: use AndroidX BundleCompat for extracting parcelable
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-27 16:11:30 +05:30
Jason A. Donenfeld f13624c58f ui: switch from SwitchMaterial to MaterialSwitch
This required some weird changes to prevent clipping on the top, because
apparently the new switch is a bit fatter.

I think this actually looks a bit uglier than before, but it seems like
that's what Material design wants. Maybe we can improve it?

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-25 23:58:06 +01:00
Jason A. Donenfeld 497a60cc90 ui: bring back donation button
For Google Play Store builds, we'll display an alert box. This was
inspired by the discussion around StreetComplete; hopefully we'll have a
similar okay outcome.

Link: https://github.com/streetcomplete/streetcomplete/issues/3768
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-24 14:16:08 +01:00
Jason A. Donenfeld 8139e60094 strings: update from crowdin
This is after doing a rebuild on the crowdin side.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-24 14:12:21 +01:00
Harsh Shandilya 9dab67f3f1 ui: fix inconsistent toolbar color
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-24 14:12:21 +01:00
Harsh Shandilya e342c9a28f ui: use Material switch component
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-24 14:12:21 +01:00
Jason A. Donenfeld cf943b7119 ui: migrate to OnBackPressedDispatcher
This is compatible with Android 13's prediction-based back gesture
animation.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-24 14:12:21 +01:00
Harsh Shandilya b7295cd56f build: raise target SDK to 33
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-24 14:12:21 +01:00
Jason A. Donenfeld 763d9a9f17 ui: set selected tunnel after creating fragments
I'm not sure why that comment (Samuel's) was there saying it was
necessary. Given it's been async for a long while, this wasn't
guaranteed anyway. So let's get rid of it and see what happens. Screen
rotation seems fine thus far.

Cc: Samuel Holland <samuel@sholland.org>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-24 14:12:21 +01:00
Jason A. Donenfeld f3107e349c ui: switch from using launchWhenCreated to using repeatOnLifecycle
Apparently the former is deprecated.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-24 14:12:21 +01:00
Jason A. Donenfeld caf2cded6e ui: simplify IME displaying in ConfigNamingDialogFragment
Also cleanup some event listener flow.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-24 14:12:21 +01:00
Harsh Shandilya b44380c81a ui: migrate to MenuProvider
AndroidX Activity 1.4.0 introduced the new lifecycle-dependent MenuProvider
APIs that supersede existing onCreateOptionsMenu-style menus.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-22 21:35:34 +05:30
Harsh Shandilya 35c8c10b7e ui: address Parcelable API deprecations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-22 21:35:34 +05:30
Harsh Shandilya 91227e445a ui: address PackageManager API deprecations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-22 21:35:34 +05:30
Harsh Shandilya 94e6d99dc7 gradle: upgrade AndroidX libraries
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-22 21:35:34 +05:30
Harsh Shandilya 052ff060b1 gradle: use idiomatic task handling
- The hand-rolled clean task is not required

- Tasks should use configureEach to prevent eager evaluation

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-22 21:35:34 +05:30
Harsh Shandilya e843fccbc6 gradle: bump wrapper version
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-03-22 21:35:34 +05:30
Jason A. Donenfeld 3ab1f94514 tools: compile with latest NDK
The -mthumb -> -marm hack is unfortunate.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-22 15:02:54 +01:00
Jason A. Donenfeld 4aa4843b74 tools: use __ANDROID_MIN_SDK_VERSION__ instead of __ANDROID_API__
The latter is deprecated.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-22 15:02:54 +01:00
Jason A. Donenfeld 4d00c334b1 ui: set button text after loading app list in AppListDialogFragment
Otherwise, for lots of apps, the dialog shows before they're enumerated,
and the button text never gets set.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-22 15:02:54 +01:00
Jason A. Donenfeld 62986b5cad version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:53:39 +01:00
L.W.Reek 296295ab8a gradle: use same NDK for tunnel and UI
Fixes: 4f261560 ("gradle: force the use of an older NDK version")
Signed-off-by: L.W.Reek <syphyr@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:53:39 +01:00
L.W.Reek d1237e2718 build: Google Play requires target API level 31 or higher
Fix build failure from lint check

Signed-off-by: L.W.Reek <syphyr@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:53:39 +01:00
Jason A. Donenfeld a26b7c594a strings: sync with crowdin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:47:26 +01:00
Jason A. Donenfeld 853e86e6d0 global: bump copyright date
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:41:11 +01:00
Jason A. Donenfeld a386e3a3d2 build: update to gradle 7.4.2 and restructure lint block
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:35:00 +01:00
Jason A. Donenfeld 560d9cf967 tools: bump deps
Notably, this isn't bumping to the latest wireguard-go master, which is
still in flux.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2023-03-21 15:35:00 +01:00
SlipkHunter 713947e432 gradle: adjust for and raise compileSdk to 33
Signed-off-by: SlipkHunter <abrito025@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-01-20 19:54:23 +05:30
Harsh Shandilya f8690ca215 gradle: migrate to namespace attribute
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-01-20 19:37:41 +05:30
SlipkHunter 4f26156030 gradle: force the use of an older NDK version
NDK 25.x removed the bundled ld.gold/ld.bfd linkers, replacing
them with the ld.ldd linker from LLVM. This causes the toolchains
to pick up the host OS' `ld.gold` instead, which does not
know how to link ARM(64) code and fails the build.

Fixes: f269fb175d ("gradle: update AndroidX and Kotlin")
Signed-off-by: SlipkHunter <abrito025@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-01-20 19:37:41 +05:30
Harsh Shandilya b353ed8ae9 gradle: update AGP and Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2023-01-20 19:37:41 +05:30
Harsh Shandilya f269fb175d gradle: update AndroidX and Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-12-01 00:15:39 +05:30
Harsh Shandilya 98fe4438d5 gradle: bump wrapper version
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-12-01 00:15:39 +05:30
Hwanseung Lee 0459d6d9f4 ui: un-export VpnService
There is no reason to expose this service to external apps.[1]

[1] https://developer.android.com/guide/topics/manifest/activity-element#exported

Signed-off-by: Hwanseung Lee <hwanseung@chromium.org>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-12-01 00:15:39 +05:30
Harsh Shandilya 4ff564521f gradle: upgrade plugins and runtime dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-08-04 02:12:38 +05:30
Harsh Shandilya 9f139134c2 gradle: bump wrapper version
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-08-04 02:12:37 +05:30
SlipkHunter 284ad03ebf ui: add barrier to fix detail fragment overlap
When listen port and MTU are hidden, we need a barrier here.

Signed-off-by: SlipkHunter <abrito025@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-07-07 15:35:10 +02:00
Harsh Shandilya c3693b3e66 gradle: remove crowdin kludge
This never ended up being used over the shell script

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-06-15 12:51:37 +05:30
Harsh Shandilya 960bc99f5e gradle: update AndroidX and Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-06-15 12:51:37 +05:30
Lucas Lee Jing Yi 8d33b648cc gradle: remove duplicate useAndroidX entry
Signed-off-by: Lucas Lee Jing Yi <lucasleeeeeeeee@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-06-15 12:51:31 +05:30
Harsh Shandilya 38cb184cf8 ui: reorder constraints to fix detail fragment overlap
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:50:00 +05:30
Harsh Shandilya 5d14caf3b2 ui: move default style to Material3 with Dynamic Colors
The TV theme has been kept as-is since Material You guidance around this
is a bit scarce at the moment.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:49:22 +05:30
Harsh Shandilya 81c571f0c7 ui: normalise icon tints and remove unused drawable
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:01:03 +05:30
Harsh Shandilya 50b21e95c3 gradle: bump ConstraintLayout and MDC
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:01:03 +05:30
Harsh Shandilya 059bf88141 gradle: bump AGP and Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:01:02 +05:30
Harsh Shandilya b3112ab0bd gradle: bump to 7.4.2
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:01:02 +05:30
Harsh Shandilya 1bb8a10633 ui: remove unnecessary boolean check
This check was added in 3c31c340d8 when the kernel module loader was
introduced into the app lifecycle, to avoid attempting to start a root shell
twice. When the module loader was removed in a03ad51622, this flag
was accidentally left in when it should have been deleted.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:01:02 +05:30
Harsh Shandilya f3230fc8f9 idea: squelch XML codestyle warning
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-05-26 06:01:02 +05:30
Jason A. Donenfeld c762bc3120 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2022-05-16 19:17:40 +02:00
Jason A. Donenfeld aeb8903ba2 tools: bump deps
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2022-05-16 19:15:07 +02:00
Shahzain Ali 2f244771a2 ui: move target SDK to 31
Signed-off-by: Shahzain Ali <shahzainali93@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-04-26 01:27:41 +05:30
Harsh Shandilya 5ffb1d0c36 gradle: bump AGP and Kotlin
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-04-08 03:08:22 +05:30
Jason A. Donenfeld 62910caae1 tools: bump wireguard-go and go 1.18
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2022-03-20 22:31:57 -06:00
Vlad Loktionov 866fd35df5 ui: word wrap settings headers
Apparently some translations make this wrap, which is bad.

Signed-off-by: Vlad Loktionov <yobabay23@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2022-03-20 22:28:14 -06:00
Rin Patch 32a2ebb66f ui: exclude TunnelToggleActivity from recents
Fixes annoying behavior in quick settings widget, when you enable
the tunnel, try to switch to last used app, but instead it switches to
the toggle activity and turns the tunnel off.

Signed-off-by: Rin Patch <rin@patch.cx>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-03-20 22:28:07 -06:00
Harsh Shandilya 70d9a87d0d ui: make validity check from QR code image scanner static
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-03-06 10:48:15 -07:00
Nikita Pustovoi 0bd39309c8 ui: allow importing tunnel from an QR image stored on the device
Add a new feature to import a tunnel from a saved QR image, this feature
integrates into 'import from file' flow, however adds a condition, if
file is an image, attempt to parse it as QR image file.

My use case for this feature, is to allow easier sharing of tunnels to
family.  Scanning QR code is ok when you have an external display to
show it, but if you sent QR code to someone, there is no way to import
it in the app.  If you share a config file, that becomes way harder for
a non-technical person to import as now they need to find a file with
that name in the file picker etc etc, Where the images are very visible
in the file picker, and user can easily recognize it for import.

Testing:
- Click "+" blue button, try to import a valid `.conf` file - the
  'original' file flow should not be affected
- Click "+" blue button, try to import a valid QR code image - if QR
  code was parsed, then a new tunnel will be added.
- Click "+" blue button, try to import an invalid QR code image - Error
  message will be shown

Signed-off-by: Nikita Pustovoi <deishelon@gmail.com>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-03-06 10:48:15 -07:00
Harsh Shandilya 751ce54fa5 build: upgrade dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-03-03 11:53:18 +05:30
Michal Murin 72dc677819 tunnel: fix BadConfigExceptionTest
Fix the test by changing the DNS to a string with an invalid char in the
`invalid-value.conf` test configuration file.

Signed-off-by: Michal Murin <michal.murin@jamf.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2022-02-09 12:01:56 +01:00
Harsh Shandilya 7002367e4f gradle: update AndroidX dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-01-28 22:08:34 +05:30
Jason A. Donenfeld 5339e48251 ToolsInstaller: set id=wireguard magisk module param
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2022-01-21 17:10:28 +01:00
Marcel Joss d626e23210 ui: add margin on empty list text
Signed-off-by: Marcel Joss <marceljoss@hotmail.ch>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-01-17 11:51:27 +05:30
Harsh Shandilya 342ed5e259 ui: make when statements exhaustive everywhere
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-01-08 15:30:12 +05:30
Harsh Shandilya 2bf09f8e2d gradle: bump AGP, Kotlin and AGP
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-01-08 15:30:11 +05:30
Harsh Shandilya 36d93a8e1b gradle: bump wrapper to 7.3.3
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2022-01-08 15:30:11 +05:30
Jason A. Donenfeld 1d7d306950 version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-10-29 17:21:43 +02:00
Jason A. Donenfeld 06306c669d README: re-add desugaring block
People are never gonna figure it out otherwise.

This reverts commit 1701e4fde4.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-10-29 17:19:00 +02:00
Jason A. Donenfeld d19e126e2e tools: bump libwg-go
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-10-29 16:58:28 +02:00
Jason A. Donenfeld bf84e26a86 global: bump copyright year
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-10-29 16:47:12 +02:00
Jason A. Donenfeld a03ad51622 tunnel: remove kernel module downloader
Nathan Chance dropped the ball repeatedly and never maintained this in a
consistent way that anybody could use. With Android 12 out now, just
drop it all together. A bummer, but I don't see much of a choice.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-10-29 16:42:36 +02:00
Harsh Shandilya 447b06ec2c ui: fix and silence lint errors
- The `copied_to_clipboard` translation for Farsi does not include
the placeholder, so it has been removed.

- A couple lints that are errors but we cannot particularly do anything about
were downgraded to warnings.

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-28 03:19:56 +05:30
Harsh Shandilya 6da1d5ed01 tunnel: make JSR305 annotations a compileOnly dependency
These have no business being part of the runtime classpath of this library

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-28 03:19:55 +05:30
Harsh Shandilya 836c367499 gradle: upgrade AndroidX dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-28 03:19:55 +05:30
Harsh Shandilya 15cb99a41f strings: sync translations
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-27 18:56:52 +05:30
Harsh Shandilya fae74dd3ca ui: upgrade zxing-android-embedded
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-25 22:42:39 +05:30
Harsh Shandilya e462ae270d gradle: bump wrapper to 7.2
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-25 22:38:00 +05:30
Harsh Shandilya 24d5a28a4a gradle: bump AGP
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-25 22:27:34 +05:30
Harsh Shandilya 3df42898ae gradle: upgrade AndroidX dependencies
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-10-10 18:23:51 +05:30
Harsh Shandilya 1701e4fde4 README: link to Android desugaring docs
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
2021-09-27 08:45:46 +05:30
Jason A. Donenfeld f6d175b774 strings: sync with crowdin
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-09-26 20:05:35 -06:00
Jason A. Donenfeld 878c450563 README: bump desugar version
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-09-26 18:40:30 -06:00
Jason A. Donenfeld b444ea064e version: bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-09-26 17:38:31 -06:00
Jason A. Donenfeld 4eb90266a2 tunnel: bump to work on x86_64 architecture
Bionic bans poll, so switch to ppoll. Folks were experiencing crashes on
ChromeOS.

We're waiting for https://go-review.googlesource.com/c/sys/+/352310 to
be merged, but for now we rely on
https://git.zx2c4.com/wireguard-go/commit/?id=fcc601dbf0f6b626ec1d47a880cbe64f9c8fe385

Reported-by: Rodrigo Alexandre <rdrslv00@gmail.com>
Reported-by: Mace Moneta <moneta.mace@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-09-26 17:35:57 -06:00
Jason A. Donenfeld 3935a369b8 ui,tunnel: support DNS search domains
wg-quick has supported this for a while, but not the config layer, and
not the Go backend, so wire this all up.

Requested-by: Alexis Geoffrey <alexis.geoffrey97@gmail.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-09-25 22:22:09 -06:00
189 changed files with 3232 additions and 3757 deletions
-3
View File
@@ -66,9 +66,6 @@
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="10" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA">
<option name="METHOD_ANNOTATION_WRAP" value="0" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
+1 -1
View File
@@ -1,6 +1,6 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright © &amp;#36;today.year WireGuard LLC. All Rights Reserved.&#10;SPDX-License-Identifier: Apache-2.0" />
<option name="notice" value="Copyright © 2017-&amp;#36;today.year WireGuard LLC. All Rights Reserved.&#10;SPDX-License-Identifier: Apache-2.0" />
<option name="myName" value="Default" />
</copyright>
</component>
+2 -2
View File
@@ -22,7 +22,7 @@ The tunnel library is [on Maven Central](https://search.maven.org/artifact/com.w
implementation 'com.wireguard.android:tunnel:$wireguardTunnelVersion'
```
The library makes use of Java 8 features, so be sure to support those in your gradle configuration with desugaring:
The library makes use of Java 8 features, so be sure to support those in your gradle configuration with [desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring):
```
compileOptions {
@@ -31,7 +31,7 @@ compileOptions {
coreLibraryDesugaringEnabled = true
}
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.0.10"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
}
```
+15 -52
View File
@@ -1,69 +1,32 @@
buildscript {
ext {
activityVersion = '1.3.1'
annotationsVersion = '1.2.0'
appcompatVersion = '1.3.1'
activityVersion = '1.6.1'
annotationsVersion = '1.6.0'
appcompatVersion = '1.6.1'
biometricVersion = '1.1.0'
collectionVersion = '1.1.0'
constraintLayoutVersion = '2.1.0'
coordinatorLayoutVersion = '1.1.0'
coreKtxVersion = '1.6.0'
coroutinesVersion = '1.5.2'
collectionVersion = '1.2.0'
constraintLayoutVersion = '2.1.4'
coordinatorLayoutVersion = '1.2.0'
coreKtxVersion = '1.10.0-rc01'
coroutinesVersion = '1.6.4'
datastoreVersion = '1.0.0'
desugarVersion = '1.1.5'
fragmentVersion = '1.3.6'
fragmentVersion = '1.5.5'
jsr305Version = '3.0.2'
junitVersion = '4.13.2'
lifecycleRuntimeKtxVersion = '2.3.1'
materialComponentsVersion = '1.4.0'
preferenceVersion = '1.1.1'
zxingEmbeddedVersion = '4.2.0'
lifecycleRuntimeKtxVersion = '2.6.0'
materialComponentsVersion = '1.8.0'
preferenceVersion = '1.2.0'
zxingEmbeddedVersion = '4.3.0'
groupName = 'com.wireguard.android'
}
}
plugins {
id "de.undercouch.download" version "4.1.2"
}
task downloadCrowdin(type: Download) {
src 'https://crowdin.com/backend/download/project/wireguard.zip'
dest file('build/translations.zip')
overwrite true
}
task cleanCrowdin(type: Delete) {
delete 'ui/src/main/res/values-*/strings.xml'
}
task extractCrowdin(type: Copy, dependsOn: ['downloadCrowdin', 'cleanCrowdin']) {
mustRunAfter 'downloadCrowdin'
from zipTree(file('build/translations.zip'))
into file('build/translations')
doFirst {
delete 'build/translations'
}
}
task crowdin(type: Copy, dependsOn: ['extractCrowdin']) {
mustRunAfter 'extractCrowdin'
from 'build/translations/wireguard-android/ui/src/main/res'
into 'ui/src/main/res/'
doLast {
delete 'build/translations'
delete 'build/translations.zip'
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
tasks {
wrapper {
gradleVersion = "7.1.1"
distributionSha256Sum = "bf8b869948901d422e9bb7d1fa61da6a6e19411baa7ad6ee929073df85d6365d"
gradleVersion = "8.0.2"
distributionSha256Sum = "ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7"
}
}
+2 -3
View File
@@ -18,9 +18,6 @@ org.gradle.jvmargs=-Xmx1536m
# Turn off AP discovery in compile path to enable compile avoidance
kapt.include.compile.classpath=false
# Enable AndroidX
android.useAndroidX=true
# Enable non-transitive R class namespacing where each library only contains
# references to the resources it declares instead of declarations plus all
# transitive dependency references.
@@ -45,6 +42,8 @@ android.generateManifestClass=true
android.experimental.enableSourceSetPathsMap=true
# Use relative paths for better Gradle caching of library build tasks
android.experimental.cacheCompileLibResources=true
# Disable automatic creation of publishing components
android.disableAutomaticComponentCreation=true
# Default Android build features
# Disable BuildConfig generation by default
Binary file not shown.
+3 -2
View File
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=bf8b869948901d422e9bb7d1fa61da6a6e19411baa7ad6ee929073df85d6365d
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
distributionSha256Sum=ff7bf6a86f09b9b2c40bb8f48b25fc19cf2b2664fd1d220cd7ab833ec758d0d7
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+172 -113
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
+2 -2
View File
@@ -1,6 +1,6 @@
pluginManagement {
def agpVersion = "7.0.2"
def kotlinVersion = "1.5.31"
def agpVersion = '7.4.2'
def kotlinVersion = "1.8.0"
repositories {
gradlePluginPortal()
google()
+11 -6
View File
@@ -6,14 +6,15 @@ version wireguardVersionName
group groupName
android {
compileSdkVersion 30
compileSdk 33
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'com.wireguard.android.tunnel'
defaultConfig {
minSdkVersion 21
targetSdkVersion 30
targetSdkVersion 33
versionCode wireguardVersionCode
versionName wireguardVersionName
}
@@ -43,16 +44,20 @@ android {
}
}
}
lintOptions {
disable('LongLogTag')
disable('NewApi') // Desugaring!
lint {
disable 'LongLogTag', 'NewApi'
}
publishing {
multipleVariants("release") {
allVariants()
}
}
}
dependencies {
implementation "androidx.annotation:annotation:$annotationsVersion"
implementation "androidx.collection:collection:$collectionVersion"
implementation "com.google.code.findbugs:jsr305:$jsr305Version"
compileOnly "com.google.code.findbugs:jsr305:$jsr305Version"
testImplementation "junit:junit:$junitVersion"
}
+4 -4
View File
@@ -1,15 +1,15 @@
<!--
~ Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wireguard.android.tunnel">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service
android:name="com.wireguard.android.backend.GoBackend$VpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -274,6 +274,9 @@ public final class GoBackend implements Backend {
for (final InetAddress addr : config.getInterface().getDnsServers())
builder.addDnsServer(addr.getHostAddress());
for (final String dnsSearchDomain : config.getInterface().getDnsSearchDomains())
builder.addSearchDomain(dnsSearchDomain);
boolean sawDefaultRoute = false;
for (final Peer peer : config.getPeers()) {
for (final InetNetwork addr : peer.getAllowedIps()) {
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -53,6 +53,10 @@ public final class WgQuickBackend implements Backend {
this.toolsInstaller = toolsInstaller;
}
public static boolean hasKernelSupport() {
return new File("/sys/module/wireguard").exists();
}
@Override
public Set<String> getRunningTunnelNames() {
final List<String> output = new ArrayList<>();
@@ -1,215 +0,0 @@
/*
* Copyright © 2019-2020 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util;
import android.content.Context;
import android.system.OsConstants;
import android.util.Base64;
import com.wireguard.android.util.RootShell.RootShellException;
import com.wireguard.crypto.Ed25519;
import com.wireguard.util.NonNullForAll;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidParameterException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import androidx.annotation.Nullable;
/**
* Class that implements the logic for downloading and loading signed, prebuilt modules for
* WireGuard into the running kernel.
*/
@NonNullForAll
@SuppressWarnings("MagicNumber")
public class ModuleLoader {
private static final String MODULE_LIST_URL = "https://download.wireguard.com/android-module/modules.txt.sig";
private static final String MODULE_NAME = "wireguard-%s.ko";
private static final String MODULE_PUBLIC_KEY_BASE64 = "RWRmHuT9PSqtwfsLtEx+QS06BJtLgFYteL9WCNjH7yuyu5Y1DieSN7If";
private static final String MODULE_URL = "https://download.wireguard.com/android-module/%s";
private final File moduleDir;
private final RootShell rootShell;
private final File tmpDir;
private final String userAgent;
/**
* Public constructor for ModuleLoader
*
* @param context A {@link Context} instance.
* @param rootShell A {@link RootShell} instance used to run elevated commands required for module
* loading.
* @param userAgent A {@link String} that represents the User-Agent string used for connections
* to the upstream server.
*/
public ModuleLoader(final Context context, final RootShell rootShell, final String userAgent) {
moduleDir = new File(context.getCacheDir(), "kmod");
tmpDir = new File(context.getCacheDir(), "tmp");
this.rootShell = rootShell;
this.userAgent = userAgent;
}
/**
* Check whether a WireGuard module is already loaded into the kernel.
*
* @return boolean indicating if WireGuard is already enabled in the kernel.
*/
public static boolean isModuleLoaded() {
return new File("/sys/module/wireguard").exists();
}
/**
* Download the correct WireGuard module for the device
*
* @return {@link OsConstants}.EXIT_SUCCESS if everything succeeds, ENOENT otherwise.
* @throws IOException if the remote hash list was not found or empty.
* @throws RootShellException if {@link RootShell} has a failure executing elevated commands.
* @throws NoSuchAlgorithmException if SHA256 algorithm is not available in device JDK.
*/
public Integer download() throws IOException, RootShellException, NoSuchAlgorithmException {
final List<String> output = new ArrayList<>();
rootShell.run(output, "sha256sum /proc/version|cut -d ' ' -f 1");
if (output.size() != 1 || output.get(0).length() != 64)
throw new InvalidParameterException("Invalid sha256 of /proc/version");
final String moduleName = String.format(MODULE_NAME, output.get(0));
HttpURLConnection connection = (HttpURLConnection) new URL(MODULE_LIST_URL).openConnection();
connection.setRequestProperty("User-Agent", userAgent);
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
throw new IOException("Hash list could not be found");
final byte[] input = new byte[1024 * 1024 * 3 /* 3MiB */];
int len;
try (final InputStream inputStream = connection.getInputStream()) {
int offset = 0;
while (input.length - offset > 0 && (len = inputStream.read(input, offset, input.length - offset)) > 0) {
offset += len;
}
len = offset;
}
if (len <= 0)
throw new IOException("Hash list was empty");
final Map<String, Sha256Digest> modules = verifySignedHashes(new String(input, 0, len, StandardCharsets.UTF_8));
if (modules == null)
throw new InvalidParameterException("The signature did not verify or invalid hash list format");
if (!modules.containsKey(moduleName))
return OsConstants.ENOENT;
connection = (HttpURLConnection) new URL(String.format(MODULE_URL, moduleName)).openConnection();
connection.setRequestProperty("User-Agent", userAgent);
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
throw new IOException("Module file could not be found, despite being on hash list");
tmpDir.mkdirs();
moduleDir.mkdir();
File tempFile = null;
try {
tempFile = File.createTempFile("UNVERIFIED-", null, tmpDir);
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (final InputStream inputStream = connection.getInputStream();
final FileOutputStream outputStream = new FileOutputStream(tempFile)) {
int total = 0;
while ((len = inputStream.read(input)) > 0) {
total += len;
if (total > 1024 * 1024 * 15 /* 15 MiB */)
throw new IOException("File too big");
outputStream.write(input, 0, len);
digest.update(input, 0, len);
}
outputStream.getFD().sync();
}
if (!Arrays.equals(digest.digest(), modules.get(moduleName).bytes))
throw new IOException("Incorrect file hash");
if (!tempFile.renameTo(new File(moduleDir, moduleName)))
throw new IOException("Unable to rename to final destination");
} finally {
if (tempFile != null)
tempFile.delete();
}
return OsConstants.EXIT_SUCCESS;
}
/**
* Load the downloaded module. ModuleLoader#download must be called before this.
*
* @throws IOException if {@link RootShell} has a failure executing elevated commands.
* @throws RootShellException if {@link RootShell} has a failure executing elevated commands.
*/
public void loadModule() throws IOException, RootShellException {
rootShell.run(null, String.format("insmod \"%s/wireguard-$(sha256sum /proc/version|cut -d ' ' -f 1).ko\"", moduleDir.getAbsolutePath()));
}
/**
* Check if the module might already exist in the app's data.
*
* @return boolean indicating whether downloadable module might exist already.
*/
public boolean moduleMightExist() {
return moduleDir.exists() && moduleDir.isDirectory();
}
@Nullable
private Map<String, Sha256Digest> verifySignedHashes(final String signifyDigest) {
byte[] publicKeyBytes = Base64.decode(MODULE_PUBLIC_KEY_BASE64, Base64.DEFAULT);
if (publicKeyBytes == null || publicKeyBytes.length != 32 + 10 || publicKeyBytes[0] != 'E' || publicKeyBytes[1] != 'd')
return null;
final String[] lines = signifyDigest.split("\n", 3);
if (lines.length != 3)
return null;
if (!lines[0].startsWith("untrusted comment: "))
return null;
byte[] signatureBytes = Base64.decode(lines[1], Base64.DEFAULT);
if (signatureBytes == null || signatureBytes.length != 64 + 10)
return null;
for (int i = 0; i < 10; ++i) {
if (signatureBytes[i] != publicKeyBytes[i])
return null;
}
publicKeyBytes = Arrays.copyOfRange(publicKeyBytes, 10, 10 + 32);
signatureBytes = Arrays.copyOfRange(signatureBytes, 10, 10 + 64);
if (!Ed25519.verify(lines[2].getBytes(StandardCharsets.UTF_8), signatureBytes, publicKeyBytes))
return null;
final Map<String, Sha256Digest> hashes = new HashMap<>();
for (final String line : lines[2].split("\n")) {
final String[] components = line.split(" {2}", 2);
if (components.length != 2)
return null;
try {
hashes.put(components[1], new Sha256Digest(components[0]));
} catch (final Exception ignored) {
return null;
}
}
return hashes;
}
private static final class Sha256Digest {
private final byte[] bytes;
private Sha256Digest(final String hex) {
if (hex.length() != 64)
throw new InvalidParameterException("SHA256 hashes must be 32 bytes long");
bytes = new byte[32];
for (int i = 0; i < 32; ++i)
bytes[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -145,7 +145,7 @@ public final class ToolsInstaller {
script.append("trap 'rm -rf /data/adb/modules/wireguard' INT TERM EXIT; ");
script.append(String.format("rm -rf /data/adb/modules/wireguard/; mkdir -p /data/adb/modules/wireguard%s; ", INSTALL_DIR));
script.append("printf 'name=WireGuard Command Line Tools\nversion=1.0\nversionCode=1\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /data/adb/modules/wireguard/module.prop; ");
script.append("printf 'id=wireguard\nname=WireGuard Command Line Tools\nversion=1.0\nversionCode=1\nauthor=zx2c4\ndescription=Command line tools for WireGuard\nminMagisk=1500\n' > /data/adb/modules/wireguard/module.prop; ");
script.append("touch /data/adb/modules/wireguard/auto_mount; ");
for (final String name : EXECUTABLES) {
final File destination = new File("/data/adb/modules/wireguard" + INSTALL_DIR, name);
@@ -1,5 +1,5 @@
/*
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
public final class InetAddresses {
@Nullable private static final Method PARSER_METHOD;
private static final Pattern WONT_TOUCH_RESOLVER = Pattern.compile("^(((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?)|((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$");
private static final Pattern VALID_HOSTNAME = Pattern.compile("^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\\.?$");
static {
Method m = null;
@@ -38,6 +39,16 @@ public final class InetAddresses {
private InetAddresses() {
}
/**
* Determines whether input is a valid DNS hostname.
*
* @param maybeHostname a string that is possibly a DNS hostname
* @return whether or not maybeHostname is a valid DNS hostname
*/
public static boolean isHostname(final CharSequence maybeHostname) {
return VALID_HOSTNAME.matcher(maybeHostname).matches();
}
/**
* Parses a numeric IPv4 or IPv6 address without performing any DNS lookups.
*
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -40,6 +40,7 @@ public final class Interface {
private final Set<InetNetwork> addresses;
private final Set<InetAddress> dnsServers;
private final Set<String> dnsSearchDomains;
private final Set<String> excludedApplications;
private final Set<String> includedApplications;
private final KeyPair keyPair;
@@ -50,6 +51,7 @@ public final class Interface {
// Defensively copy to ensure immutability even if the Builder is reused.
addresses = Collections.unmodifiableSet(new LinkedHashSet<>(builder.addresses));
dnsServers = Collections.unmodifiableSet(new LinkedHashSet<>(builder.dnsServers));
dnsSearchDomains = Collections.unmodifiableSet(new LinkedHashSet<>(builder.dnsSearchDomains));
excludedApplications = Collections.unmodifiableSet(new LinkedHashSet<>(builder.excludedApplications));
includedApplications = Collections.unmodifiableSet(new LinkedHashSet<>(builder.includedApplications));
keyPair = Objects.requireNonNull(builder.keyPair, "Interfaces must have a private key");
@@ -108,6 +110,7 @@ public final class Interface {
final Interface other = (Interface) obj;
return addresses.equals(other.addresses)
&& dnsServers.equals(other.dnsServers)
&& dnsSearchDomains.equals(other.dnsSearchDomains)
&& excludedApplications.equals(other.excludedApplications)
&& includedApplications.equals(other.includedApplications)
&& keyPair.equals(other.keyPair)
@@ -135,6 +138,16 @@ public final class Interface {
return dnsServers;
}
/**
* Returns the set of DNS search domains associated with the interface.
*
* @return a set of strings
*/
public Set<String> getDnsSearchDomains() {
// The collection is already immutable.
return dnsSearchDomains;
}
/**
* Returns the set of applications excluded from using the interface.
*
@@ -222,6 +235,7 @@ public final class Interface {
sb.append("Address = ").append(Attribute.join(addresses)).append('\n');
if (!dnsServers.isEmpty()) {
final List<String> dnsServerStrings = dnsServers.stream().map(InetAddress::getHostAddress).collect(Collectors.toList());
dnsServerStrings.addAll(dnsSearchDomains);
sb.append("DNS = ").append(Attribute.join(dnsServerStrings)).append('\n');
}
if (!excludedApplications.isEmpty())
@@ -254,6 +268,8 @@ public final class Interface {
// Defaults to an empty set.
private final Set<InetAddress> dnsServers = new LinkedHashSet<>();
// Defaults to an empty set.
private final Set<String> dnsSearchDomains = new LinkedHashSet<>();
// Defaults to an empty set.
private final Set<String> excludedApplications = new LinkedHashSet<>();
// Defaults to an empty set.
private final Set<String> includedApplications = new LinkedHashSet<>();
@@ -284,6 +300,16 @@ public final class Interface {
return this;
}
public Builder addDnsSearchDomain(final String dnsSearchDomain) {
dnsSearchDomains.add(dnsSearchDomain);
return this;
}
public Builder addDnsSearchDomains(final Collection<String> dnsSearchDomains) {
this.dnsSearchDomains.addAll(dnsSearchDomains);
return this;
}
public Interface build() throws BadConfigException {
if (keyPair == null)
throw new BadConfigException(Section.INTERFACE, Location.PRIVATE_KEY,
@@ -326,8 +352,15 @@ public final class Interface {
public Builder parseDnsServers(final CharSequence dnsServers) throws BadConfigException {
try {
for (final String dnsServer : Attribute.split(dnsServers))
addDnsServer(InetAddresses.parse(dnsServer));
for (final String dnsServer : Attribute.split(dnsServers)) {
try {
addDnsServer(InetAddresses.parse(dnsServer));
} catch (final ParseException e) {
if (e.getParsingClass() != InetAddress.class || !InetAddresses.isHostname(dnsServer))
throw e;
addDnsSearchDomain(dnsServer);
}
}
return this;
} catch (final ParseException e) {
throw new BadConfigException(Section.INTERFACE, Location.DNS, e);
@@ -1,5 +1,5 @@
/*
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,6 +1,6 @@
/*
* Copyright © 2016 Southern Storm Software, Pty Ltd.
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
+1 -1
View File
@@ -1,6 +1,6 @@
[Interface]
Address = 192.0.2.2/32,2001:db8:ffff:ffff:ffff:ffff:ffff:ffff/128
DNS = 192.0.2.0,yes
DNS = 192.0.2.0,invalid_value
PrivateKey = TFlmmEUC7V7VtiDYLKsbP5rySTKLIZq1yn8lMqK83wo=
[Peer]
AllowedIPs = 0.0.0.0/0, ::0/0
+8 -11
View File
@@ -1,13 +1,11 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
# Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
cmake_minimum_required(VERSION 3.4.1)
project("WireGuard")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
# Work around https://github.com/android-ndk/ndk/issues/602
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
add_link_options(LINKER:--build-id=none)
add_executable(libwg-quick.so wireguard-tools/src/wg-quick/android.c ndk-compat/compat.c)
target_compile_options(libwg-quick.so PUBLIC -O3 -std=gnu11 -Wall -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\")
@@ -18,16 +16,15 @@ add_executable(libwg.so ${WG_SOURCES})
target_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/uapi/linux/" "${CMAKE_CURRENT_SOURCE_DIR}/wireguard-tools/src/")
target_compile_options(libwg.so PUBLIC -O3 -std=gnu11 -D_GNU_SOURCE -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DHAVE_VISIBILITY_HIDDEN -DRUNSTATEDIR=\"/data/data/${ANDROID_PACKAGE_NAME}/cache\")
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go" VERBATIM COMMAND make
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building wireguard-go" VERBATIM COMMAND "${ANDROID_HOST_PREBUILTS}/bin/make"
ANDROID_ARCH_NAME=${ANDROID_ARCH_NAME}
ANDROID_C_COMPILER=${ANDROID_C_COMPILER}
ANDROID_TOOLCHAIN_ROOT=${ANDROID_TOOLCHAIN_ROOT}
ANDROID_LLVM_TRIPLE=${ANDROID_LLVM_TRIPLE}
ANDROID_SYSROOT=${ANDROID_SYSROOT}
ANDROID_PACKAGE_NAME=${ANDROID_PACKAGE_NAME}
GRADLE_USER_HOME=${GRADLE_USER_HOME}
CFLAGS=${CMAKE_C_FLAGS}\ -Wno-unused-command-line-argument
LDFLAGS=${CMAKE_SHARED_LINKER_FLAGS}\ -fuse-ld=gold
CC=${CMAKE_C_COMPILER}
CFLAGS=${CMAKE_C_FLAGS}
LDFLAGS=${CMAKE_SHARED_LINKER_FLAGS}
SYSROOT=${CMAKE_SYSROOT}
TARGET=${CMAKE_C_COMPILER_TARGET}
DESTDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
BUILDDIR=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/../generated-src
)
+10 -10
View File
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
# Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
BUILDDIR ?= $(CURDIR)/build
DESTDIR ?= $(CURDIR)/out
@@ -12,20 +12,20 @@ NDK_GO_ARCH_MAP_arm64 := arm64
NDK_GO_ARCH_MAP_mips := mipsx
NDK_GO_ARCH_MAP_mips64 := mips64x
CLANG_FLAGS := --target=$(ANDROID_LLVM_TRIPLE) --gcc-toolchain=$(ANDROID_TOOLCHAIN_ROOT) --sysroot=$(ANDROID_SYSROOT)
export CGO_CFLAGS := $(CLANG_FLAGS) $(CFLAGS)
export CGO_LDFLAGS := $(CLANG_FLAGS) $(LDFLAGS) -Wl,-soname=libwg-go.so
export CC := $(ANDROID_C_COMPILER)
comma := ,
CLANG_FLAGS := --target=$(TARGET) --sysroot=$(SYSROOT)
export CGO_CFLAGS := $(CLANG_FLAGS) $(subst -mthumb,-marm,$(CFLAGS))
export CGO_LDFLAGS := $(CLANG_FLAGS) $(patsubst -Wl$(comma)--build-id=%,-Wl$(comma)--build-id=none,$(LDFLAGS)) -Wl,-soname=libwg-go.so
export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
GO_VERSION := 1.17.1
GO_VERSION := 1.20.2
GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m))
GO_TARBALL := go$(GO_VERSION).$(GO_PLATFORM).tar.gz
GO_HASH_darwin-amd64 := 3c452046b1dfa27b70d3217c9fe6de266f9fd74d83aad81382fead70efcdffca
GO_HASH_darwin-arm64 := 48f48a3cfe49b7bb448510ec9bf1682439e4e95fa6888580914a3115fe853d8c
GO_HASH_linux-amd64 := dab7d9c34361dc21ec237d584590d72500652e7c909bf082758fb63064fca0ef
GO_HASH_darwin-amd64 := c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19aded08764c
GO_HASH_darwin-arm64 := 7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885
GO_HASH_linux-amd64 := 4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768
default: $(DESTDIR)/libwg-go.so
@@ -47,6 +47,6 @@ $(BUILDDIR)/go-$(GO_VERSION)/.prepared: $(GRADLE_USER_HOME)/caches/golang/$(GO_T
$(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH)
$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod
go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -trimpath -o "$@" -buildmode c-shared
go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard -buildid=" -v -trimpath -o "$@" -buildmode c-shared
.DELETE_ON_ERROR:
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: Apache-2.0
*
* Copyright (C) 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright © 2017-2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
package main
+9 -5
View File
@@ -1,10 +1,14 @@
module golang.zx2c4.com/wireguard/android
go 1.16
go 1.20
require (
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 // indirect
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7
golang.zx2c4.com/wireguard v0.0.0-20210923155401-217ac1016bc5
golang.org/x/sys v0.6.0
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675
)
require (
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
)
+10 -24
View File
@@ -1,24 +1,10 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 h1:c20P3CcPbopVp2f7099WLOqSNKURf30Z0uq66HpijZY=
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.0-20210923155401-217ac1016bc5 h1:iXtWdri0M6DdLa0wsT6zVSXqlyFBJAoEQPGMGmsYh4E=
golang.zx2c4.com/wireguard v0.0.0-20210923155401-217ac1016bc5/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 h1:/J/RVnr7ng4fWPRH3xa4WtBJ1Jp+Auu4YNLmGiPv5QU=
golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675/go.mod h1:whfbyDBt09xhCYQWtO2+3UVjlaq6/9hDZrjg2ZE6SyA=
@@ -1,7 +1,8 @@
From b83553d9f260ba20c6faaa52e6fe6f74309eb41a Mon Sep 17 00:00:00 2001
From 729c58cb1c0496497dac6de3d0bf540f6149618f Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Mon, 22 Feb 2021 02:36:03 +0100
Subject: [PATCH] runtime: use CLOCK_BOOTTIME in nanotime on Linux
Date: Tue, 21 Mar 2023 15:33:56 +0100
Subject: [PATCH] [release-branch.go1.20] runtime: use CLOCK_BOOTTIME in
nanotime on Linux
This makes timers account for having expired while a computer was
asleep, which is quite common on mobile devices. Note that BOOTTIME is
@@ -28,10 +29,10 @@ Change-Id: I7b2a6ca0c5bc5fce57ec0eeafe7b68270b429321
8 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 1e3a834812..78b6021fc7 100644
index 12a294153d..17e3524b40 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -337,13 +337,13 @@ noswitch:
@@ -352,13 +352,13 @@ noswitch:
LEAL 8(SP), BX // &ts (struct timespec)
MOVL BX, 4(SP)
@@ -48,10 +49,10 @@ index 1e3a834812..78b6021fc7 100644
INVOKE_SYSCALL
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 37cb8dad03..e8b730bcaa 100644
index c7a89ba536..01f0a6a26e 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -302,7 +302,7 @@ noswitch:
@@ -255,7 +255,7 @@ noswitch:
SUBQ $16, SP // Space for results
ANDQ $~15, SP // Align for C code
@@ -61,7 +62,7 @@ index 37cb8dad03..e8b730bcaa 100644
MOVQ runtime·vdsoClockgettimeSym(SB), AX
CMPQ AX, $0
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 475f52344c..bb567abcf4 100644
index 7b8c4f0e04..9798a1334e 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -11,7 +11,7 @@
@@ -73,20 +74,20 @@ index 475f52344c..bb567abcf4 100644
// for EABI, as we don't support OABI
#define SYS_BASE 0x0
@@ -366,7 +366,7 @@ noswitch:
SUB $24, R13 // Space for results
BIC $0x7, R13 // Align for C code
@@ -374,7 +374,7 @@ finish:
// func nanotime1() int64
TEXT runtime·nanotime1(SB),NOSPLIT,$12-8
- MOVW $CLOCK_MONOTONIC, R0
+ MOVW $CLOCK_BOOTTIME, R0
MOVW $8(R13), R1 // timespec
MOVW runtime·vdsoClockgettimeSym(SB), R2
CMP $0, R2
MOVW $spec-12(SP), R1 // timespec
MOVW runtime·vdsoClockgettimeSym(SB), R4
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 198a5bacef..9715387f36 100644
index 38ff6ac330..6b819c5441 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -13,7 +13,7 @@
@@ -14,7 +14,7 @@
#define AT_FDCWD -100
#define CLOCK_REALTIME 0
@@ -95,7 +96,7 @@ index 198a5bacef..9715387f36 100644
#define SYS_exit 93
#define SYS_read 63
@@ -319,7 +319,7 @@ noswitch:
@@ -338,7 +338,7 @@ noswitch:
BIC $15, R1
MOVD R1, RSP
@@ -105,10 +106,10 @@ index 198a5bacef..9715387f36 100644
CBZ R2, fallback
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index c3e9f37694..e3879acd38 100644
index 47f2da524d..6c1a9a2801 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -312,7 +312,7 @@ noswitch:
@@ -326,7 +326,7 @@ noswitch:
AND $~15, R1 // Align for C code
MOVV R1, R29
@@ -118,10 +119,10 @@ index c3e9f37694..e3879acd38 100644
MOVV runtime·vdsoClockgettimeSym(SB), R25
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
index fab2ab3892..f9af103594 100644
index 5e6b6c1504..7f5fd2a80e 100644
--- a/src/runtime/sys_linux_mipsx.s
+++ b/src/runtime/sys_linux_mipsx.s
@@ -238,7 +238,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$8-12
@@ -243,7 +243,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
RET
TEXT runtime·nanotime1(SB),NOSPLIT,$8-8
@@ -131,11 +132,11 @@ index fab2ab3892..f9af103594 100644
MOVW $SYS_clock_gettime, R2
SYSCALL
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index fd69ee70a5..ff6bc8355b 100644
index d0427a4807..05ee9fede9 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -249,7 +249,7 @@ fallback:
JMP finish
@@ -298,7 +298,7 @@ fallback:
JMP return
TEXT runtime·nanotime1(SB),NOSPLIT,$16-8
- MOVD $1, R3 // CLOCK_MONOTONIC
@@ -144,18 +145,18 @@ index fd69ee70a5..ff6bc8355b 100644
MOVD R1, R15 // R15 is unchanged by C code
MOVD g_m(g), R21 // R21 = m
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index c15a1d5364..f52c4d5098 100644
index 1448670b91..7d2ee3231c 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -207,7 +207,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$16
@@ -296,7 +296,7 @@ fallback:
RET
TEXT runtime·nanotime1(SB),NOSPLIT,$16
- MOVW $1, R2 // CLOCK_MONOTONIC
+ MOVW $7, R2 // CLOCK_BOOTTIME
MOVD $tp-16(SP), R3
MOVW $SYS_clock_gettime, R1
SYSCALL
TEXT runtime·nanotime1(SB),NOSPLIT,$32-8
- MOVW $1, R2 // CLOCK_MONOTONIC
+ MOVW $7, R2 // CLOCK_BOOTTIME
MOVD R15, R7 // Backup stack pointer
--
2.30.1
2.40.0
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: Apache-2.0
*
* Copyright © 2017-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
* Copyright © 2017-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#include <jni.h>
+3 -3
View File
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
*
*/
#define FILE_IS_EMPTY
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 18
#undef FILE_IS_EMPTY
#include <stdio.h>
#include <stdlib.h>
@@ -58,7 +58,7 @@ ssize_t getline(char **buf, size_t *bufsiz, FILE *fp)
}
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 24
#undef FILE_IS_EMPTY
#include <string.h>
+3 -3
View File
@@ -1,16 +1,16 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
*
*/
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 18
#include <stdio.h>
ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp);
ssize_t getline(char **buf, size_t *bufsiz, FILE *fp);
#endif
#if defined(__ANDROID_API__) && __ANDROID_API__ < 24
#if defined(__ANDROID_MIN_SDK_VERSION__) && __ANDROID_MIN_SDK_VERSION__ < 24
char *strchrnul(const char *s, int c);
#endif
+18 -10
View File
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
@@ -12,16 +14,17 @@ group groupName
final def keystorePropertiesFile = rootProject.file("keystore.properties")
android {
compileSdkVersion 30
compileSdk 33
buildFeatures {
buildConfig = true
dataBinding = true
viewBinding = true
}
namespace = 'com.wireguard.android'
defaultConfig {
applicationId 'com.wireguard.android'
minSdkVersion 21
targetSdkVersion 30
targetSdkVersion 33
versionCode wireguardVersionCode
versionName wireguardVersionName
buildConfigField 'int', 'MIN_SDK_VERSION', "$minSdkVersion.apiLevel"
@@ -45,18 +48,26 @@ android {
}
}
buildTypes {
all {
buildConfigField('boolean', 'IS_GOOGLE_PLAY', (findProperty('build.google_play') == 'true').toString())
}
release {
if (keystorePropertiesFile.exists()) signingConfig signingConfigs.release
minifyEnabled true
proguardFiles "proguard-android-optimize.txt", "proguard-rules.pro"
packagingOptions {
exclude "DebugProbesKt.bin"
exclude "kotlin-tooling-metadata.json"
}
}
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}
}
lintOptions {
disable('LongLogTag')
lint {
disable 'LongLogTag'
warning 'MissingTranslation', 'ImpliedQuantity'
}
}
@@ -80,14 +91,11 @@ dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugarVersion"
}
tasks.withType(JavaCompile) {
tasks.withType(JavaCompile).configureEach {
options.compilerArgs << '-Xlint:unchecked'
options.deprecation = true
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
useIR = true
}
tasks.withType(KotlinCompile).configureEach {
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8
}
+16 -11
View File
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.wireguard.android"
android:installLocation="internalOnly">
<uses-permission android:name="android.permission.CAMERA" />
@@ -21,6 +20,9 @@
<uses-feature
android:name="android.hardware.camera.any"
android:required="false" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<permission
android:name="${applicationId}.permission.CONTROL_TUNNELS"
@@ -29,13 +31,11 @@
android:label="@string/permission_label"
android:protectionLevel="dangerous" />
<!-- This is safe to override, the APIs we use work perfectly fine on Android 6 -->
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
<application
android:name=".Application"
android:allowBackup="false"
android:banner="@mipmap/banner"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
@@ -44,9 +44,10 @@
<activity
android:name=".activity.TunnelToggleActivity"
android:theme="@style/NoBackgroundTheme" />
android:theme="@style/NoBackgroundTheme"
android:excludeFromRecents="true"/>
<activity android:name=".activity.MainActivity">
<activity android:name=".activity.MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -60,7 +61,8 @@
<activity
android:name=".activity.TvMainActivity"
android:theme="@style/TvTheme">
android:theme="@style/TvTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
@@ -84,7 +86,8 @@
<activity
android:name=".activity.LogViewerActivity"
android:label="@string/log_viewer_title">
android:label="@string/log_viewer_title"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
@@ -96,7 +99,7 @@
android:exported="false"
android:grantUriPermissions="true" />
<receiver android:name=".BootShutdownReceiver">
<receiver android:name=".BootShutdownReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
@@ -105,7 +108,8 @@
<receiver
android:name=".model.TunnelManager$IntentReceiver"
android:permission="${applicationId}.permission.CONTROL_TUNNELS">
android:permission="${applicationId}.permission.CONTROL_TUNNELS"
android:exported="true">
<intent-filter>
<action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" />
<action android:name="com.wireguard.android.action.SET_TUNNEL_UP" />
@@ -116,7 +120,8 @@
<service
android:name=".QuickTileService"
android:icon="@drawable/ic_tile"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
@@ -16,12 +16,14 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import com.wireguard.android.activity.TvMainActivity
import com.wireguard.android.backend.Backend
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.configStore.FileConfigStore
import com.wireguard.android.model.TunnelManager
import com.wireguard.android.util.ModuleLoader
import com.wireguard.android.util.RootShell
import com.wireguard.android.util.ToolsInstaller
import com.wireguard.android.util.UserKnobs
@@ -42,7 +44,6 @@ class Application : android.app.Application() {
private val futureBackend = CompletableDeferred<Backend>()
private val coroutineScope = CoroutineScope(Job() + Dispatchers.Main.immediate)
private var backend: Backend? = null
private lateinit var moduleLoader: ModuleLoader
private lateinit var rootShell: RootShell
private lateinit var preferencesDataStore: DataStore<Preferences>
private lateinit var toolsInstaller: ToolsInstaller
@@ -66,19 +67,9 @@ class Application : android.app.Application() {
private suspend fun determineBackend(): Backend {
var backend: Backend? = null
var didStartRootShell = false
if (!ModuleLoader.isModuleLoaded() && moduleLoader.moduleMightExist()) {
if (UserKnobs.enableKernelModule.first() && WgQuickBackend.hasKernelSupport()) {
try {
rootShell.start()
didStartRootShell = true
moduleLoader.loadModule()
} catch (ignored: Exception) {
}
}
if (!UserKnobs.disableKernelModule.first() && ModuleLoader.isModuleLoaded()) {
try {
if (!didStartRootShell)
rootShell.start()
val wgQuickBackend = WgQuickBackend(applicationContext, rootShell, toolsInstaller)
wgQuickBackend.setMultipleTunnels(UserKnobs.multipleTunnels.first())
backend = wgQuickBackend
@@ -98,9 +89,11 @@ class Application : android.app.Application() {
override fun onCreate() {
Log.i(TAG, USER_AGENT)
super.onCreate()
DynamicColors.applyToActivitiesIfAvailable(this,
// TODO: Remove this second argument once the TV theme has a proper M3 color palette.
DynamicColorsOptions.Builder().setPrecondition { activity, _ -> activity !is TvMainActivity }.build())
rootShell = RootShell(applicationContext)
toolsInstaller = ToolsInstaller(applicationContext, rootShell)
moduleLoader = ModuleLoader(applicationContext, rootShell, USER_AGENT)
preferencesDataStore = PreferenceDataStoreFactory.create { applicationContext.preferencesDataStoreFile("settings") }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
coroutineScope.launch {
@@ -132,30 +125,20 @@ class Application : android.app.Application() {
private const val TAG = "WireGuard/Application"
private lateinit var weakSelf: WeakReference<Application>
@JvmStatic
fun get(): Application {
return weakSelf.get()!!
}
@JvmStatic
suspend fun getBackend() = get().futureBackend.await()
@JvmStatic
fun getModuleLoader() = get().moduleLoader
@JvmStatic
fun getRootShell() = get().rootShell
@JvmStatic
fun getPreferencesDataStore() = get().preferencesDataStore
@JvmStatic
fun getToolsInstaller() = get().toolsInstaller
@JvmStatic
fun getTunnelManager() = get().tunnelManager
@JvmStatic
fun getCoroutineScope() = get().coroutineScope
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -10,6 +10,7 @@ import androidx.databinding.CallbackRegistry.NotifierCallback
import androidx.lifecycle.lifecycleScope
import com.wireguard.android.Application
import com.wireguard.android.model.ObservableTunnel
import kotlinx.coroutines.launch
/**
* Base class for activities that need to remember the currently-selected tunnel.
@@ -30,6 +31,8 @@ abstract class BaseActivity : ThemeChangeAwareActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Restore the saved tunnel if there is one; otherwise grab it from the arguments.
val savedTunnelName = when {
savedInstanceState != null -> savedInstanceState.getString(KEY_SELECTED_TUNNEL)
@@ -37,10 +40,9 @@ abstract class BaseActivity : ThemeChangeAwareActivity() {
else -> null
}
if (savedTunnelName != null)
lifecycleScope.launchWhenCreated { selectedTunnel = Application.getTunnelManager().getTunnels()[savedTunnelName] }
// The selected tunnel must be set before the superclass method recreates fragments.
super.onCreate(savedInstanceState)
lifecycleScope.launch {
selectedTunnel = Application.getTunnelManager().getTunnels()[savedTunnelName]
}
}
override fun onSaveInstanceState(outState: Bundle) {
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -40,6 +40,7 @@ import com.wireguard.android.R
import com.wireguard.android.databinding.LogViewerActivityBinding
import com.wireguard.android.util.DownloadsFileSaver
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.resolveAttribute
import com.wireguard.crypto.KeyPair
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -70,7 +71,7 @@ class LogViewerActivity : AppCompatActivity() {
yearFormatter.format(Date())
}
private val defaultColor by lazy { ResourcesCompat.getColor(resources, R.color.primary_text_color, theme) }
private val defaultColor by lazy { resolveAttribute(com.google.android.material.R.attr.colorOnSurface) }
private val debugColor by lazy { ResourcesCompat.getColor(resources, R.color.debug_tag_color, theme) }
@@ -126,9 +127,9 @@ class LogViewerActivity : AppCompatActivity() {
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.log_viewer, menu)
saveButton = menu?.findItem(R.id.save_log)
saveButton = menu.findItem(R.id.save_log)
return true
}
@@ -184,36 +185,47 @@ class LogViewerActivity : AppCompatActivity() {
return@withContext
}
val stdout = BufferedReader(InputStreamReader(process!!.inputStream, StandardCharsets.UTF_8))
var haveScrolled = false
val start = System.nanoTime()
var startPeriod = start
var posStart = 0
var timeLastNotify = System.nanoTime()
var priorModified = false
val bufferedLogLines = arrayListOf<LogLine>()
var timeout = 1000000000L / 2 // The timeout is initially small so that the view gets populated immediately.
while (true) {
val line = stdout.readLine() ?: break
rawLogLines.append(line)
rawLogLines.append('\n')
val logLine = parseLine(line)
withContext(Dispatchers.Main.immediate) {
if (logLine != null) {
recyclerView?.let {
val shouldScroll = haveScrolled && !it.canScrollVertically(1)
logLines.add(logLine)
if (haveScrolled) logAdapter.notifyDataSetChanged()
if (shouldScroll)
it.scrollToPosition(logLines.size - 1)
}
} else {
logLines.lastOrNull()?.msg += "\n$line"
if (haveScrolled) logAdapter.notifyDataSetChanged()
if (logLine != null) {
bufferedLogLines.add(logLine)
} else {
if (bufferedLogLines.isNotEmpty()) {
bufferedLogLines.last().msg += "\n$line"
} else if (logLines.isNotEmpty()) {
logLines.last().msg += "\n$line"
priorModified = true
}
if (!haveScrolled) {
val end = System.nanoTime()
val scroll = (end - start) > 1000000000L * 2.5 || !stdout.ready()
if (logLines.isNotEmpty() && (scroll || (end - startPeriod) > 1000000000L / 4)) {
logAdapter.notifyDataSetChanged()
recyclerView?.scrollToPosition(logLines.size - 1)
startPeriod = end
}
if (scroll) haveScrolled = true
}
val timeNow = System.nanoTime()
if ((timeNow - timeLastNotify) < timeout && stdout.ready())
continue
timeout = 1000000000L * 5 / 2 // Increase the timeout after the initial view has something in it.
timeLastNotify = timeNow
withContext(Dispatchers.Main.immediate) {
val isScrolledToBottomAlready = recyclerView?.canScrollVertically(1) == false
if (priorModified) {
logAdapter.notifyItemChanged(posStart - 1)
priorModified = false
}
logLines.addAll(bufferedLogLines)
bufferedLogLines.clear()
logAdapter.notifyItemRangeInserted(posStart, logLines.size - posStart)
posStart = logLines.size
if (isScrolledToBottomAlready) {
recyclerView?.scrollToPosition(logLines.size - 1)
}
}
}
@@ -259,7 +271,7 @@ class LogViewerActivity : AppCompatActivity() {
private fun levelToColor(level: String): Int {
return when (level) {
"D" -> debugColor
"V", "D" -> debugColor
"E" -> errorColor
"I" -> infoColor
"W" -> warningColor
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -9,6 +9,8 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.appcompat.app.ActionBar
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
@@ -26,27 +28,29 @@ import com.wireguard.android.model.ObservableTunnel
class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener {
private var actionBar: ActionBar? = null
private var isTwoPaneLayout = false
private var backPressedCallback: OnBackPressedCallback? = null
override fun onBackPressed() {
private fun handleBackPressed() {
val backStackEntries = supportFragmentManager.backStackEntryCount
// If the two-pane layout does not have an editor open, going back should exit the app.
if (isTwoPaneLayout && backStackEntries <= 1) {
finish()
return
}
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
if (!isTwoPaneLayout && backStackEntries == 1) {
if (backStackEntries >= 1)
supportFragmentManager.popBackStack()
// Deselect the current tunnel on navigating back from the detail pane to the one-pane list.
if (backStackEntries == 1)
selectedTunnel = null
return
}
super.onBackPressed()
}
override fun onBackStackChanged() {
val backStackEntries = supportFragmentManager.backStackEntryCount
backPressedCallback?.isEnabled = backStackEntries >= 1
if (actionBar == null) return
// Do not show the home menu when the two-pane layout is at the detail view (see above).
val backStackEntries = supportFragmentManager.backStackEntryCount
val minBackStackEntries = if (isTwoPaneLayout) 2 else 1
actionBar!!.setDisplayHomeAsUpEnabled(backStackEntries >= minBackStackEntries)
}
@@ -57,6 +61,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
actionBar = supportActionBar
isTwoPaneLayout = findViewById<View?>(R.id.master_detail_wrapper) != null
supportFragmentManager.addOnBackStackChangedListener(this)
backPressedCallback = onBackPressedDispatcher.addCallback(this) { handleBackPressed() }
onBackStackChanged()
}
@@ -69,7 +74,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
return when (item.itemId) {
android.R.id.home -> {
// The back arrow in the action bar should act the same as the back button.
onBackPressed()
onBackPressedDispatcher.onBackPressed()
true
}
R.id.menu_action_edit -> {
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -17,7 +17,6 @@ import com.wireguard.android.R
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.preference.PreferencesPreferenceDataStore
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.ModuleLoader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -79,30 +78,19 @@ class SettingsActivity : ThemeChangeAwareActivity() {
startActivity(Intent(requireContext(), LogViewerActivity::class.java))
true
}
val moduleInstaller = preferenceManager.findPreference<Preference>("module_downloader")
val kernelModuleDisabler = preferenceManager.findPreference<Preference>("kernel_module_disabler")
moduleInstaller?.isVisible = false
if (ModuleLoader.isModuleLoaded()) {
moduleInstaller?.parent?.removePreference(moduleInstaller)
val kernelModuleEnabler = preferenceManager.findPreference<Preference>("kernel_module_enabler")
if (WgQuickBackend.hasKernelSupport()) {
lifecycleScope.launch {
if (Application.getBackend() !is WgQuickBackend) {
try {
withContext(Dispatchers.IO) { Application.getRootShell().start() }
} catch (_: Throwable) {
kernelModuleDisabler?.parent?.removePreference(kernelModuleDisabler)
kernelModuleEnabler?.parent?.removePreference(kernelModuleEnabler)
}
}
}
} else {
kernelModuleDisabler?.parent?.removePreference(kernelModuleDisabler)
lifecycleScope.launch {
try {
withContext(Dispatchers.IO) { Application.getRootShell().start() }
moduleInstaller?.isVisible = true
} catch (_: Throwable) {
moduleInstaller?.parent?.removePreference(moduleInstaller)
}
}
kernelModuleEnabler?.parent?.removePreference(kernelModuleEnabler)
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,12 +16,14 @@ import android.os.storage.StorageVolume
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.view.forEach
import androidx.databinding.DataBindingUtil
import androidx.databinding.Observable
import androidx.databinding.ObservableBoolean
import androidx.databinding.ObservableField
import androidx.lifecycle.lifecycleScope
@@ -185,6 +187,17 @@ class TvMainActivity : AppCompatActivity() {
binding.tunnelList.requestFocus()
}
}
val backPressedCallback = onBackPressedDispatcher.addCallback(this) { handleBackPressed() }
val updateBackPressedCallback = object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
backPressedCallback.isEnabled = isDeleting.get() || filesRoot.get()?.isNotEmpty() == true
}
}
isDeleting.addOnPropertyChangedCallback(updateBackPressedCallback)
filesRoot.addOnPropertyChangedCallback(updateBackPressedCallback)
backPressedCallback.isEnabled = false
binding.executePendingBindings()
setContentView(binding.root)
@@ -298,7 +311,7 @@ class TvMainActivity : AppCompatActivity() {
}
}
override fun onBackPressed() {
private fun handleBackPressed() {
when {
isDeleting.get() -> {
isDeleting.set(false)
@@ -313,7 +326,6 @@ class TvMainActivity : AppCompatActivity() {
binding.tunnelList.requestFocus()
}
}
else -> super.onBackPressed()
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.configStore
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.configStore
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -152,6 +152,12 @@ object BindingAdapters {
view.text = if (addresses != null) Attribute.join(addresses.map { it?.hostAddress }) else ""
}
@JvmStatic
@BindingAdapter("android:text")
fun setStringSetText(view: TextView, strings: Iterable<String?>?) {
view.text = if (strings != null) Attribute.join(strings) else ""
}
@JvmStatic
fun tryParseInt(s: String?): Int {
if (s == null)
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -34,10 +34,6 @@ class AddTunnelsSheet : BottomSheetDialogFragment() {
}
}
override fun getTheme(): Int {
return R.style.BottomSheetDialogTheme
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (savedInstanceState != null) dismiss()
val view = inflater.inflate(R.layout.add_tunnels_bottom_sheet, container, false)
@@ -76,7 +72,7 @@ class AddTunnelsSheet : BottomSheetDialogFragment() {
}
})
val gradientDrawable = GradientDrawable().apply {
setColor(requireContext().resolveAttribute(R.attr.colorBackground))
setColor(requireContext().resolveAttribute(com.google.android.material.R.attr.colorSurface))
}
view.background = gradientDrawable
}
@@ -1,11 +1,15 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
import android.Manifest
import android.app.Dialog
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PackageInfoFlags
import android.os.Build
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
@@ -15,6 +19,7 @@ import androidx.databinding.Observable
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.tabs.TabLayout
import com.wireguard.android.BR
import com.wireguard.android.R
@@ -40,7 +45,7 @@ class AppListDialogFragment : DialogFragment() {
try {
val applicationData: MutableList<ApplicationData> = ArrayList()
withContext(Dispatchers.IO) {
val packageInfos = pm.getPackagesHoldingPermissions(arrayOf(Manifest.permission.INTERNET), 0)
val packageInfos = getPackagesHoldingPermissions(pm, arrayOf(Manifest.permission.INTERNET))
packageInfos.forEach {
val packageName = it.packageName
val appInfo = it.applicationInfo
@@ -59,6 +64,7 @@ class AppListDialogFragment : DialogFragment() {
appData.clear()
appData.addAll(applicationData)
}
setButtonText()
} catch (e: Throwable) {
withContext(Dispatchers.Main.immediate) {
val error = ErrorMessages[e]
@@ -76,6 +82,15 @@ class AppListDialogFragment : DialogFragment() {
initiallyExcluded = arguments?.getBoolean(KEY_IS_EXCLUDED) ?: true
}
private fun getPackagesHoldingPermissions(pm: PackageManager, permissions: Array<String>): List<PackageInfo> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
pm.getPackagesHoldingPermissions(permissions, PackageInfoFlags.of(0L))
} else {
@Suppress("DEPRECATION")
pm.getPackagesHoldingPermissions(permissions, 0)
}
}
private fun setButtonText() {
val numSelected = appData.count { it.isSelected }
button?.text = if (numSelected == 0)
@@ -88,7 +103,7 @@ class AppListDialogFragment : DialogFragment() {
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val alertDialogBuilder = AlertDialog.Builder(requireActivity())
val alertDialogBuilder = MaterialAlertDialogBuilder(requireActivity())
val binding = AppListDialogFragmentBinding.inflate(requireActivity().layoutInflater, null, false)
binding.executePendingBindings()
alertDialogBuilder.setView(binding.root)
@@ -139,6 +154,7 @@ class AppListDialogFragment : DialogFragment() {
const val KEY_SELECTED_APPS = "selected_apps"
const val KEY_IS_EXCLUDED = "is_excluded"
const val REQUEST_SELECTION = "request_selection"
fun newInstance(selectedApps: ArrayList<String?>?, isExcluded: Boolean): AppListDialogFragment {
val extras = Bundle()
extras.putStringArrayList(KEY_SELECTED_APPS, selectedApps)
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -1,18 +1,15 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AlertDialog
import androidx.core.content.getSystemService
import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.databinding.ConfigNamingDialogFragmentBinding
@@ -26,7 +23,6 @@ import java.nio.charset.StandardCharsets
class ConfigNamingDialogFragment : DialogFragment() {
private var binding: ConfigNamingDialogFragmentBinding? = null
private var config: Config? = null
private var imm: InputMethodManager? = null
private fun createTunnelAndDismiss() {
val binding = binding ?: return
@@ -41,12 +37,6 @@ class ConfigNamingDialogFragment : DialogFragment() {
}
}
}
override fun dismiss() {
setKeyboardVisible(false)
super.dismiss()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val configText = requireArguments().getString(KEY_CONFIG_TEXT)
@@ -63,51 +53,23 @@ class ConfigNamingDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val activity = requireActivity()
imm = activity.getSystemService()
val alertDialogBuilder = AlertDialog.Builder(activity)
val alertDialogBuilder = MaterialAlertDialogBuilder(activity)
alertDialogBuilder.setTitle(R.string.import_from_qr_code)
binding = ConfigNamingDialogFragmentBinding.inflate(activity.layoutInflater, null, false)
binding?.apply {
executePendingBindings()
alertDialogBuilder.setView(root)
}
alertDialogBuilder.setPositiveButton(R.string.create_tunnel, null)
alertDialogBuilder.setPositiveButton(R.string.create_tunnel) { _, _ -> createTunnelAndDismiss() }
alertDialogBuilder.setNegativeButton(R.string.cancel) { _, _ -> dismiss() }
return alertDialogBuilder.create().apply {
setOnShowListener {
findViewById<TextInputEditText>(R.id.tunnel_name_text)?.apply {
setOnFocusChangeListener { v, _ ->
v.post {
imm?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT)
}
}
requestFocus()
}
}
}
}
override fun onResume() {
super.onResume()
val dialog = dialog as AlertDialog?
if (dialog != null) {
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener { createTunnelAndDismiss() }
setKeyboardVisible(true)
}
}
private fun setKeyboardVisible(visible: Boolean) {
if (visible) {
imm!!.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
} else if (binding != null) {
imm!!.hideSoftInputFromWindow(binding!!.tunnelNameText.windowToken, 0)
}
val dialog = alertDialogBuilder.create()
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
return dialog
}
companion object {
private const val KEY_CONFIG_TEXT = "config_text"
@JvmStatic
fun newInstance(configText: String?): ConfigNamingDialogFragment {
val extras = Bundle()
extras.putString(KEY_CONFIG_TEXT, configText)
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -8,9 +8,12 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.MenuProvider
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import com.wireguard.android.R
import com.wireguard.android.backend.Tunnel
@@ -24,18 +27,17 @@ import kotlinx.coroutines.launch
/**
* Fragment that shows details about a specific tunnel.
*/
class TunnelDetailFragment : BaseFragment() {
class TunnelDetailFragment : BaseFragment(), MenuProvider {
private var binding: TunnelDetailFragmentBinding? = null
private var lastState = Tunnel.State.TOGGLE
private var timerActive = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return false
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.tunnel_detail, menu)
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.tunnel_detail, menu)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@@ -46,6 +48,11 @@ class TunnelDetailFragment : BaseFragment() {
return binding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
override fun onDestroyView() {
binding = null
super.onDestroyView()
@@ -1,10 +1,11 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.text.InputType
import android.util.Log
@@ -18,6 +19,9 @@ import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import androidx.core.os.BundleCompat
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.wireguard.android.Application
@@ -35,7 +39,7 @@ import kotlinx.coroutines.launch
/**
* Fragment for editing a WireGuard configuration.
*/
class TunnelEditorFragment : BaseFragment() {
class TunnelEditorFragment : BaseFragment(), MenuProvider {
private var haveShownKeys = false
private var binding: TunnelEditorFragmentBinding? = null
private var tunnel: ObservableTunnel? = null
@@ -65,11 +69,10 @@ class TunnelEditorFragment : BaseFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.config_editor, menu)
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.config_editor, menu)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@@ -83,6 +86,11 @@ class TunnelEditorFragment : BaseFragment() {
return binding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
}
override fun onDestroyView() {
activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
binding = null
@@ -105,8 +113,8 @@ class TunnelEditorFragment : BaseFragment() {
selectedTunnel = tunnel
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_action_save) {
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
if (menuItem.itemId == R.id.menu_action_save) {
binding ?: return false
val newConfig = try {
binding!!.config!!.resolve()
@@ -152,7 +160,7 @@ class TunnelEditorFragment : BaseFragment() {
}
return true
}
return super.onOptionsItemSelected(item)
return false
}
@Suppress("UNUSED_PARAMETER")
@@ -265,7 +273,7 @@ class TunnelEditorFragment : BaseFragment() {
onSelectedTunnelChanged(null, selectedTunnel)
} else {
tunnel = selectedTunnel
val config: ConfigProxy = savedInstanceState.getParcelable(KEY_LOCAL_CONFIG)!!
val config = BundleCompat.getParcelable(savedInstanceState, KEY_LOCAL_CONFIG, ConfigProxy::class.java)!!
val originalName = savedInstanceState.getString(KEY_ORIGINAL_NAME)
if (tunnel != null && tunnel!!.name != originalName) onSelectedTunnelChanged(null, tunnel) else binding!!.config = config
}
@@ -297,6 +305,7 @@ class TunnelEditorFragment : BaseFragment() {
Snackbar.LENGTH_SHORT
).show()
}
is BiometricAuthenticator.Result.Cancelled -> {}
}
}
} else {
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
@@ -16,12 +16,16 @@ import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.google.zxing.integration.android.IntentIntegrator
import com.google.zxing.qrcode.QRCodeReader
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.activity.TunnelCreatorActivity
@@ -30,14 +34,13 @@ import com.wireguard.android.databinding.TunnelListFragmentBinding
import com.wireguard.android.databinding.TunnelListItemBinding
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.QrCodeFromFileScanner
import com.wireguard.android.util.TunnelImporter
import com.wireguard.android.widget.MultiselectableRelativeLayout
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
import java.util.ArrayList
import java.util.HashSet
/**
* Fragment containing a list of known WireGuard tunnels. It allows creating and deleting tunnels.
@@ -45,22 +48,36 @@ import java.util.HashSet
class TunnelListFragment : BaseFragment() {
private val actionModeListener = ActionModeListener()
private var actionMode: ActionMode? = null
private var backPressedCallback: OnBackPressedCallback? = null
private var binding: TunnelListFragmentBinding? = null
private val tunnelFileImportResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { data ->
if (data == null) return@registerForActivityResult
val activity = activity ?: return@registerForActivityResult
val contentResolver = activity.contentResolver ?: return@registerForActivityResult
activity.lifecycleScope.launch {
TunnelImporter.importTunnel(contentResolver, data) { showSnackbar(it) }
if (QrCodeFromFileScanner.validContentType(contentResolver, data)) {
try {
val qrCodeFromFileScanner = QrCodeFromFileScanner(contentResolver, QRCodeReader())
val result = qrCodeFromFileScanner.scan(data)
TunnelImporter.importTunnel(parentFragmentManager, result.text) { showSnackbar(it) }
} catch (e: Exception) {
val error = ErrorMessages[e]
val message = Application.get().resources.getString(R.string.import_error, error)
Log.e(TAG, message, e)
showSnackbar(message)
}
} else {
TunnelImporter.importTunnel(contentResolver, data) { showSnackbar(it) }
}
}
}
private val qrImportResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val qrCode = IntentIntegrator.parseActivityResult(result.resultCode, result.data)?.contents
?: return@registerForActivityResult
val activity = activity ?: return@registerForActivityResult
val fragManager = parentFragmentManager
activity.lifecycleScope.launch { TunnelImporter.importTunnel(fragManager, qrCode) { showSnackbar(it) } }
private val qrImportResultLauncher = registerForActivityResult(ScanContract()) { result ->
val qrCode = result.contents
val activity = activity
if (qrCode != null && activity != null) {
activity.lifecycleScope.launch { TunnelImporter.importTunnel(parentFragmentManager, qrCode) { showSnackbar(it) } }
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -80,6 +97,8 @@ class TunnelListFragment : BaseFragment() {
val bottomSheet = AddTunnelsSheet()
binding?.apply {
createFab.setOnClickListener {
if (childFragmentManager.findFragmentByTag("BOTTOM_SHEET") != null)
return@setOnClickListener
childFragmentManager.setFragmentResultListener(AddTunnelsSheet.REQUEST_KEY_NEW_TUNNEL, viewLifecycleOwner) { _, bundle ->
when (bundle.getString(AddTunnelsSheet.REQUEST_METHOD)) {
AddTunnelsSheet.REQUEST_CREATE -> {
@@ -89,11 +108,10 @@ class TunnelListFragment : BaseFragment() {
tunnelFileImportResultLauncher.launch("*/*")
}
AddTunnelsSheet.REQUEST_SCAN -> {
qrImportResultLauncher.launch(IntentIntegrator(requireActivity())
qrImportResultLauncher.launch(ScanOptions()
.setOrientationLocked(false)
.setBeepEnabled(false)
.setPrompt(getString(R.string.qr_code_hint))
.createScanIntent())
.setPrompt(getString(R.string.qr_code_hint)))
}
}
}
@@ -101,6 +119,9 @@ class TunnelListFragment : BaseFragment() {
}
executePendingBindings()
}
backPressedCallback = requireActivity().onBackPressedDispatcher.addCallback(this) { actionMode?.finish() }
backPressedCallback?.isEnabled = false
return binding?.root
}
@@ -225,6 +246,7 @@ class TunnelListFragment : BaseFragment() {
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
actionMode = mode
backPressedCallback?.isEnabled = true
if (activity != null) {
resources = activity!!.resources
}
@@ -236,6 +258,7 @@ class TunnelListFragment : BaseFragment() {
override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
backPressedCallback?.isEnabled = false
resources = null
animateFab(binding?.createFab, true)
checkedItems.clear()
@@ -255,7 +278,7 @@ class TunnelListFragment : BaseFragment() {
}
val adapter = if (binding == null) null else binding!!.tunnelList.adapter
if (actionMode == null && !checkedItems.isEmpty() && activity != null) {
(activity as AppCompatActivity?)!!.startSupportActionMode(this)
(activity as AppCompatActivity).startSupportActionMode(this)
} else if (actionMode != null && checkedItems.isEmpty()) {
actionMode!!.finish()
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
@@ -0,0 +1,38 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
import android.app.AlertDialog
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.AttributeSet
import androidx.preference.Preference
import com.wireguard.android.BuildConfig
import com.wireguard.android.R
class DonatePreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
override fun getSummary() = context.getString(R.string.donate_summary)
override fun getTitle() = context.getString(R.string.donate_title)
override fun onClick() {
if (BuildConfig.IS_GOOGLE_PLAY) {
AlertDialog.Builder(context)
.setTitle(R.string.donate_title)
.setMessage(R.string.donate_google_play_disappointment)
.show()
return
}
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.wireguard.com/donations/")
try {
context.startActivity(intent)
} catch (ignored: ActivityNotFoundException) {
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -26,7 +26,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.system.exitProcess
class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
class KernelModuleEnablerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var state = State.UNKNOWN
init {
@@ -44,10 +44,10 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
activity.lifecycleScope.launch {
if (state == State.DISABLED) {
setState(State.ENABLING)
UserKnobs.setDisableKernelModule(false)
UserKnobs.setEnableKernelModule(true)
} else if (state == State.ENABLED) {
setState(State.DISABLING)
UserKnobs.setDisableKernelModule(true)
UserKnobs.setEnableKernelModule(false)
}
val observableTunnels = Application.getTunnelManager().getTunnels()
val downings = observableTunnels.map { async(SupervisorJob()) { it.setStateAsync(Tunnel.State.DOWN) } }
@@ -76,13 +76,13 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
private enum class State(val titleResourceId: Int, val summaryResourceId: Int, val shouldEnableView: Boolean, val visible: Boolean) {
UNKNOWN(0, 0, false, false),
ENABLED(R.string.module_disabler_enabled_title, R.string.module_disabler_enabled_summary, true, true),
DISABLED(R.string.module_disabler_disabled_title, R.string.module_disabler_disabled_summary, true, true),
ENABLING(R.string.module_disabler_disabled_title, R.string.success_application_will_restart, false, true),
DISABLING(R.string.module_disabler_enabled_title, R.string.success_application_will_restart, false, true);
ENABLED(R.string.module_enabler_enabled_title, R.string.module_enabler_enabled_summary, true, true),
DISABLED(R.string.module_enabler_disabled_title, R.string.module_enabler_disabled_summary, true, true),
ENABLING(R.string.module_enabler_disabled_title, R.string.success_application_will_restart, false, true),
DISABLING(R.string.module_enabler_enabled_title, R.string.success_application_will_restart, false, true);
}
companion object {
private const val TAG = "WireGuard/KernelModuleDisablerPreference"
private const val TAG = "WireGuard/KernelModuleEnablerPreference"
}
}
@@ -1,70 +0,0 @@
/*
* Copyright © 2019 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
import android.content.Context
import android.content.Intent
import android.system.OsConstants
import android.util.AttributeSet
import android.widget.Toast
import androidx.preference.Preference
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.activity.SettingsActivity
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.UserKnobs
import com.wireguard.android.util.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.system.exitProcess
class ModuleDownloaderPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var state = State.INITIAL
override fun getSummary() = context.getString(state.messageResourceId)
override fun getTitle() = context.getString(R.string.module_installer_title)
override fun onClick() {
setState(State.WORKING)
lifecycleScope.launch {
try {
when (withContext(Dispatchers.IO) { Application.getModuleLoader().download() }) {
OsConstants.ENOENT -> setState(State.NOTFOUND)
OsConstants.EXIT_SUCCESS -> {
setState(State.SUCCESS)
UserKnobs.setDisableKernelModule(null)
withContext(Dispatchers.IO) {
val restartIntent = Intent(context, SettingsActivity::class.java)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Application.get().startActivity(restartIntent)
exitProcess(0)
}
}
else -> setState(State.FAILURE)
}
} catch (e: Throwable) {
setState(State.FAILURE)
Toast.makeText(context, ErrorMessages[e], Toast.LENGTH_LONG).show()
}
}
}
private fun setState(state: State) {
if (this.state == state) return
this.state = state
if (isEnabled != state.shouldEnableView) isEnabled = state.shouldEnableView
notifyChanged()
}
private enum class State(val messageResourceId: Int, val shouldEnableView: Boolean) {
INITIAL(R.string.module_installer_initial, true),
FAILURE(R.string.module_installer_error, true),
WORKING(R.string.module_installer_working, false),
SUCCESS(R.string.success_application_will_restart, false),
NOTFOUND(R.string.module_installer_not_found, false);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
@@ -98,6 +98,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
Snackbar.LENGTH_SHORT
).show()
}
is BiometricAuthenticator.Result.Cancelled -> {}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
@@ -1,5 +1,5 @@
/*
* Copyright © 2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
@@ -1,11 +1,13 @@
/*
* Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
import android.content.res.Resources
import android.os.RemoteException
import com.google.zxing.ChecksumException
import com.google.zxing.NotFoundException
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.backend.BackendException
@@ -84,6 +86,12 @@ object ErrorMessages {
rootCause is RootShellException -> {
resources.getString(RSE_REASON_MAP.getValue(rootCause.reason), *rootCause.format)
}
rootCause is NotFoundException -> {
resources.getString(R.string.error_no_qr_found)
}
rootCause is ChecksumException -> {
resources.getString(R.string.error_qr_checksum)
}
rootCause.message != null -> {
rootCause.message!!
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -0,0 +1,110 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
import android.content.ContentResolver
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Log
import com.google.zxing.BinaryBitmap
import com.google.zxing.DecodeHintType
import com.google.zxing.NotFoundException
import com.google.zxing.RGBLuminanceSource
import com.google.zxing.Reader
import com.google.zxing.Result
import com.google.zxing.common.HybridBinarizer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
/**
* Encapsulates the logic of scanning a barcode from a file,
* @property contentResolver - Resolver to read the incoming data
* @property reader - An instance of zxing's [Reader] class to parse the image
*/
class QrCodeFromFileScanner(
private val contentResolver: ContentResolver,
private val reader: Reader,
) {
private fun scanBitmapForResult(source: Bitmap): Result {
val width = source.width
val height = source.height
val pixels = IntArray(width * height)
source.getPixels(pixels, 0, width, 0, 0, width, height)
val bBitmap = BinaryBitmap(HybridBinarizer(RGBLuminanceSource(width, height, pixels)))
return reader.decode(bBitmap, mapOf(DecodeHintType.TRY_HARDER to true))
}
private fun downscaleBitmap(source: Bitmap, scaledSize: Int): Bitmap {
val originalWidth = source.width
val originalHeight = source.height
var newWidth = -1
var newHeight = -1
val multFactor: Float
when {
originalHeight > originalWidth -> {
newHeight = scaledSize
multFactor = originalWidth.toFloat() / originalHeight.toFloat()
newWidth = (newHeight * multFactor).toInt()
}
originalWidth > originalHeight -> {
newWidth = scaledSize
multFactor = originalHeight.toFloat() / originalWidth.toFloat()
newHeight = (newWidth * multFactor).toInt()
}
originalHeight == originalWidth -> {
newHeight = scaledSize
newWidth = scaledSize
}
}
return Bitmap.createScaledBitmap(source, newWidth, newHeight, false)
}
private fun doScan(data: Uri): Result {
Log.d(TAG, "Starting to scan an image: $data")
contentResolver.openInputStream(data).use { inputStream ->
val originalBitmap = BitmapFactory.decodeStream(inputStream)
?: throw IllegalArgumentException("Can't decode stream to Bitmap")
return try {
scanBitmapForResult(originalBitmap).also {
Log.d(TAG, "Found result in original image")
}
} catch (e: Exception) {
Log.e(TAG, "Original image scan finished with error: $e, will try downscaled image")
val scaleBitmap = downscaleBitmap(originalBitmap, 500)
scanBitmapForResult(originalBitmap).also { scaleBitmap.recycle() }
} finally {
originalBitmap.recycle()
}
}
}
/**
* Attempts to parse incoming data
* @return result of the decoding operation
* @throws NotFoundException when parser didn't find QR code in the image
*/
suspend fun scan(data: Uri) = withContext(Dispatchers.Default) { doScan(data) }
companion object {
private const val TAG = "QrCodeFromFileScanner"
/**
* Given a reference to a file, check if this file could be parsed by this class
* @return true if the file can be parsed, false if not
*/
fun validContentType(contentResolver: ContentResolver, data: Uri): Boolean {
return contentResolver.getType(data)?.startsWith("image/") == true
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright © 2020 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
@@ -14,18 +14,18 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
object UserKnobs {
private val DISABLE_KERNEL_MODULE = booleanPreferencesKey("disable_kernel_module")
val disableKernelModule: Flow<Boolean>
private val ENABLE_KERNEL_MODULE = booleanPreferencesKey("enable_kernel_module")
val enableKernelModule: Flow<Boolean>
get() = Application.getPreferencesDataStore().data.map {
it[DISABLE_KERNEL_MODULE] ?: false
it[ENABLE_KERNEL_MODULE] ?: false
}
suspend fun setDisableKernelModule(disable: Boolean?) {
suspend fun setEnableKernelModule(enable: Boolean?) {
Application.getPreferencesDataStore().edit {
if (disable == null)
it.remove(DISABLE_KERNEL_MODULE)
if (enable == null)
it.remove(ENABLE_KERNEL_MODULE)
else
it[DISABLE_KERNEL_MODULE] = disable
it[ENABLE_KERNEL_MODULE] = enable
}
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.viewmodel
@@ -18,7 +18,7 @@ class ConfigProxy : Parcelable {
val peers: ObservableList<PeerProxy> = ObservableArrayList()
private constructor(parcel: Parcel) {
`interface` = parcel.readParcelable(InterfaceProxy::class.java.classLoader)!!
`interface` = InterfaceProxy.CREATOR.createFromParcel(parcel)
parcel.readTypedList(peers, PeerProxy.CREATOR)
peers.forEach { it.bind(this) }
}
@@ -1,5 +1,5 @@
/*
* Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.viewmodel
@@ -81,7 +81,7 @@ class InterfaceProxy : BaseObservable, Parcelable {
constructor(other: Interface) {
addresses = Attribute.join(other.addresses)
val dnsServerStrings = other.dnsServers.map { it.hostAddress }
val dnsServerStrings = other.dnsServers.map { it.hostAddress }.plus(other.dnsSearchDomains)
dnsServers = Attribute.join(dnsServerStrings)
excludedApplications.addAll(other.excludedApplications)
includedApplications.addAll(other.includedApplications)

Some files were not shown because too many files have changed in this diff Show More