Compare commits

..

31 Commits

Author SHA1 Message Date
Yaroslav Gurov ce41645f70 chore: bump awg-go to the latest version 2025-12-01 16:38:51 +01:00
albexk 24ef24e68b sdk 35 (#49) 2025-11-24 16:41:11 +03:00
NickVs2015 704964c22a Merge pull request for Add support awg2 fields
Fix: Add support awg2 fields
2025-11-21 00:14:54 +03:00
NickVs2015 7aea733671 Fix awg2 fields 2025-11-18 11:43:41 +03:00
Yaroslav Gurov ade016a11c fix: remove unused parse_uint32 2025-09-03 16:20:14 +02:00
Yaroslav Gurov c1af1fb8d6 feat: awg 2.0 2025-09-03 14:53:37 +02:00
albexk 2e9f9d3650 Release AmneziaWG V1.5 (#41) 2025-08-13 22:42:11 +03:00
Yaroslav Gurov f207d7bfd7 AmneziaWG V1.5 (#36) 2025-07-07 19:21:03 +02:00
pokamest e71423f46d Merge pull request #30 from amnezia-vpn/chore/update_go_1.24.2
Update go version to 1.24.2
2025-04-07 22:07:29 +01:00
pokamest 511397af2f Update go version to 1.24.2 2025-04-07 22:05:49 +01:00
albexk 6d654aff91 Add import disclaimer (#27) 2025-03-08 13:26:31 +03:00
albexk 5bffd56583 Fix typo and update icons (#9)
Fix typo and update icons
2024-06-17 18:17:08 +01:00
pokamest 6d295a9475 Merge pull request #7 from amnezia-vpn/bump-awg
Bump amneziawg-go to v0.2.11 and go to 1.22.3
2024-05-30 20:11:03 +01:00
albexk c906e7c1c7 Bump amneziawg-go to v0.2.11 and go to 1.22.3 2024-05-24 19:33:51 +03:00
pokamest bebf19aaf6 Merge pull request #5 from amnezia-vpn/fix/udpgso
Fix udpgso
2024-05-14 04:37:03 -07:00
albexk cef17bac38 Fix udpgso 2024-05-14 14:24:10 +03:00
albexk 1f748dc917 AmneziaWG release (#4) 2024-03-16 15:34:34 +00:00
pokamest d6f973d620 Merge pull request #1 from amnezia-vpn/fix/android
* Bump gradlew to 8.5
* Refactor gradle build scripts
* Rename wireguard-tools submodule to amneziawg-tools, fix submodule url
* Change package name
* Fix go modules naming
* Change JNI package name
* Change amneziawg android log tag
2024-02-12 07:11:53 -08:00
albexk 5c8f568453 Change amneziawg android log tag 2024-02-12 17:58:14 +03:00
albexk d771ee3fc6 Change JNI package name 2024-02-12 17:58:14 +03:00
albexk d52f8c4783 Fix go modules naming 2024-02-12 17:58:11 +03:00
albexk 3221335fd8 Change package name 2024-02-11 21:50:37 +03:00
albexk 8cb862d336 Rename wireguard-tools submodule to amneziawg-tools, fix submodule url 2024-02-11 21:45:34 +03:00
albexk adc770bb69 Refactor gradle build scripts 2024-02-11 21:41:11 +03:00
albexk 7921d15247 Bump gradlew to 8.5 2024-02-10 18:24:58 +03:00
Mykola Baibuz a96d4072bf Update AWG core 2024-01-14 14:19:40 -05:00
Mykola Baibuz 161d885ba8 Update AWG core 2023-11-30 14:20:56 -05:00
Mykola Baibuz f7dc83ae8e Update awg-go module 2023-10-09 09:48:37 -04:00
Mykola Baibuz 2f0782a967 Add submodules 2023-10-06 16:46:02 -04:00
Mykola Baibuz 8c8c640270 Change WG-go to AWG-go 2023-10-06 16:37:24 -04:00
Mykola Baibuz f9af162bed Upload default Android Wireguard 2023-10-06 16:23:04 -04:00
228 changed files with 3792 additions and 7576 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
[submodule "tunnel/tools/wireguard-tools"]
path = tunnel/tools/wireguard-tools
url = https://git.zx2c4.com/wireguard-tools
[submodule "tunnel/tools/amneziawg-tools"]
path = tunnel/tools/amneziawg-tools
url = https://github.com/amnezia-vpn/amneziawg-tools
[submodule "tunnel/tools/elf-cleaner"]
path = tunnel/tools/elf-cleaner
url = https://github.com/termux/termux-elf-cleaner
-474
View File
@@ -1,474 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="AUTODETECT_INDENTS" value="false" />
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<JavaCodeStyleSettings>
<option name="GENERATE_FINAL_LOCALS" value="true" />
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="10" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="10" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="METHOD_ANNOTATION_WRAP" value="0" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
<arrangement>
<groups />
<rules>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PUBLIC>true</PUBLIC>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PROTECTED>true</PROTECTED>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PRIVATE>true</PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PUBLIC>true</PUBLIC>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PROTECTED>true</PROTECTED>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>true</PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PUBLIC>true</PUBLIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PROTECTED>true</PROTECTED>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PRIVATE>true</PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PUBLIC>true</PUBLIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PROTECTED>true</PROTECTED>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>true</PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<FIELD>true</FIELD>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
</match>
</rule>
</section>
<section>
<rule>
<match>
<CONSTRUCTOR>true</CONSTRUCTOR>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<METHOD>true</METHOD>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<METHOD>true</METHOD>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<ENUM>true</ENUM>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<INTERFACE>true</INTERFACE>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<CLASS>true</CLASS>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<CLASS>true</CLASS>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="RIGHT_MARGIN" value="160" />
</codeStyleSettings>
</code_scheme>
</component>
-5
View File
@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
-6
View File
@@ -1,6 +0,0 @@
<component name="CopyrightManager">
<copyright>
<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>
-3
View File
@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="Default" />
</component>
-527
View File
@@ -1,527 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<option name="myName" value="Default" />
<inspection_tool class="AbstractClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="AbstractClassWithoutAbstractMethods" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="true" level="WARNING" enabled_by_default="true">
<option name="nonThreadSafeClasses">
<value />
</option>
<option name="nonThreadSafeTypes" value="" />
</inspection_tool>
<inspection_tool class="AndroidLintIconExpectedSize" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintNegativeMargin" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AndroidLintTypographyQuotes" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AnnotationNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="AnonymousClassVariableHidesContainingMethodVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AnonymousInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AnonymousInnerClassMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ApiName" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ApiNamespace" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ApiParameter" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ArrayEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ArrayIssues" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="AssignmentOrReturnOfFieldWithMutableTypeMerged" />
<inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToCollectionFieldFromParameter" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignorePrivateMethods" value="false" />
</inspection_tool>
<inspection_tool class="AssignmentToDateFieldFromParameter" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignorePrivateMethods" value="true" />
</inspection_tool>
<inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_checkForeachParameters" value="false" />
</inspection_tool>
<inspection_tool class="AssignmentToLambdaParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentToSuperclassField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.util.HashMap,put,java.util.Map,put" />
</inspection_tool>
<inspection_tool class="BadExceptionCaught" enabled="true" level="WARNING" enabled_by_default="true">
<option name="exceptionsString" value="" />
<option name="exceptions">
<value />
</option>
</inspection_tool>
<inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BooleanExpressionMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="BooleanParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="onlyReportMultiple" value="true" />
</inspection_tool>
<inspection_tool class="CallToSimpleGetterInClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreGetterCallsOnOtherObjects" value="false" />
<option name="onlyReportPrivateGetter" value="false" />
</inspection_tool>
<inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CannotResolve" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="CastConflictsWithInstanceof" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CatchMayIgnoreException" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreCatchBlocksWithComments" value="false" />
</inspection_tool>
<inspection_tool class="ChainedEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="ClassReferencesSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ClassWithOnlyPrivateConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConditionalExpression" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConditionalExpressionWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstExpressionRequired" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ConstantNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
<option name="onlyCheckImmutables" value="false" />
<option name="m_regex" value="[A-Z][A-Z_\d]*" />
<option name="m_minLength" value="0" />
<option name="m_maxLength" value="0" />
</inspection_tool>
<inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ConstructionIsNotAllowed" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="Constructor" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="Convert2streamapi" enabled="true" level="WARNING" enabled_by_default="true">
<option name="REPLACE_TRIVIAL_FOREACH" value="true" />
<option name="SUGGEST_FOREACH" value="true" />
</inspection_tool>
<inspection_tool class="ConvertAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DeclareCollectionAsInterface" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreLocalVariables" value="false" />
<option name="ignorePrivateMethodsAndFields" value="false" />
</inspection_tool>
<inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DerivedFunctionsReturnTypeMismatch" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="DeserializableClassInSecureContext" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DoubleBraceInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreOnVolatileVariables" value="false" />
</inspection_tool>
<inspection_tool class="DoubleLiteralMayBeFloatLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DuplicateAlternationBranch" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="DuplicateDeclarations" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="DynamicRegexReplaceableByCompiledPattern" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ElementOnlyUsedFromTestCode" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EmptyClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignorableAnnotations">
<value />
</option>
<option name="ignoreClassWithParameterization" value="true" />
<option name="ignoreThrowables" value="true" />
<option name="commentsAreContent" value="true" />
</inspection_tool>
<inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EnumSwitchStatementWhichMissesCases" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreSwitchStatementsWithDefault" value="false" />
</inspection_tool>
<inspection_tool class="EnumeratedClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="EnumeratedConstantNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Z_\d]*" />
<option name="m_minLength" value="5" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="EnumerationCanBeIteration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EqualityOperatorComparesObjects" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="EqualsAndHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EqualsCalledOnEnumConstant" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EqualsUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="EscapedMetaCharacter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreGetMessage" value="false" />
<option name="ignoreCantWrap" value="false" />
</inspection_tool>
<inspection_tool class="ExtendsThrowable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
<option name="countGettersAndSetters" value="false" />
</inspection_tool>
<inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FieldMustBeInitialized" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="FinalMethodInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreLoopsWithoutConditions" value="false" />
</inspection_tool>
<inspection_tool class="FrequentlyUsedInheritorInspection" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="FullJavaName" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="FullMethodName" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="FunctionParameterCountMismatch" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="FuseStreamOperations" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GrFieldAlreadyDefined" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="GroovyAnnotationNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="GroovyClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="GroovyEnumerationNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="GroovyInterfaceNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="HtmlTagCanBeJavadocTag" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IOResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredTypesString" value="java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringBufferInputStream,java.io.CharArrayWriter,java.io.CharArrayReader,java.io.StringWriter,java.io.StringReader" />
<option name="insideTryAllowed" value="false" />
</inspection_tool>
<inspection_tool class="IfMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IgnoreResultOfCall" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_reportAllNonLibraryCalls" value="false" />
<option name="callCheckString" value="java.io.File,.*,java.io.InputStream,read|skip|available|markSupported,java.io.Reader,read|skip|ready|markSupported,java.lang.Boolean,.*,java.lang.Byte,.*,java.lang.Character,.*,java.lang.Double,.*,java.lang.Float,.*,java.lang.Integer,.*,java.lang.Long,.*,java.lang.Math,.*,java.lang.Object,equals|hashCode|toString,java.lang.Short,.*,java.lang.StrictMath,.*,java.lang.String,.*,java.math.BigInteger,.*,java.math.BigDecimal,.*,java.net.InetAddress,.*,java.net.URI,.*,java.util.UUID,.*,java.util.regex.Matcher,pattern|toMatchResult|start|end|group|groupCount|matches|find|lookingAt|quoteReplacement|replaceAll|replaceFirst|regionStart|regionEnd|hasTransparantBounds|hasAnchoringBounds|hitEnd|requireEnd,java.util.regex.Pattern,.*,java.util.stream.BaseStream,.*" />
</inspection_tool>
<inspection_tool class="ImplicitSubclassInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="IncompatibleTypes" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="InitializerIssues" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="InnerClassReferencedViaSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInvisibleFields" value="true" />
</inspection_tool>
<inspection_tool class="InstanceMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="InstanceVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="m_[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="5" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="InstanceofCatchParameter" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="InstantiationOfUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IntLiteralMayBeLongLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="IntegerTypeRequired" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="InterfaceMayBeAnnotatedFunctional" enabled="true" level="INFORMATION" enabled_by_default="true" />
<inspection_tool class="InterfaceNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="InvalidParameterAnnotations" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="JUnit3MethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JUnit4MethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" />
<option name="m_minLength" value="12" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="JUnitTestClassNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*Test" />
<option name="m_minLength" value="8" />
<option name="m_maxLength" value="64" />
</inspection_tool>
<inspection_tool class="Java8ArraySetAll" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="Java9CollectionFactory" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavaRequiresAutoModule" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JavadocHtmlLint" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="KeySetIterationMayUseEntrySet" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LambdaCanBeMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LambdaParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LengthOneStringsInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LimitedScopeInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ListIndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LiteralAsArgToStringEquals" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
<option name="REPORT_VARIABLES" value="true" />
<option name="REPORT_PARAMETERS" value="true" />
</inspection_tool>
<inspection_tool class="LocalVariableHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreInvisibleFields" value="true" />
<option name="m_ignoreStaticMethods" value="true" />
</inspection_tool>
<inspection_tool class="LoopWithImplicitTerminationCondition" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MagicNumber" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInitialCapacity" value="true" />
</inspection_tool>
<inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MemberVisibility" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="MemberVisibilityCanPrivate" enabled="true" level="INFO" enabled_by_default="true" />
<inspection_tool class="MethodMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_onlyPrivateOrFinal" value="false" />
<option name="m_ignoreEmptyMethods" value="true" />
</inspection_tool>
<inspection_tool class="MethodMayBeSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodName" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="MethodOnlyUsedFromInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreMethodsAccessedFromAnonymousClass" value="false" />
<option name="ignoreStaticMethodsFromNonStaticInnerClass" value="false" />
<option name="onlyReportStaticMethods" value="false" />
</inspection_tool>
<inspection_tool class="MethodOverloadsParentMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="reportIncompatibleParameters" value="true" />
</inspection_tool>
<inspection_tool class="MethodOverridesInaccessibleMethodOfSuper" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodOverridesStaticMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodParameterType" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="MethodReturnType" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MissingOverrideAnnotation" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreObjectMethods" value="false" />
<option name="ignoreAnonymousClassMethods" value="false" />
</inspection_tool>
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_requireAnnotationsFirst" value="true" />
</inspection_tool>
<inspection_tool class="MoveFieldAssignmentToInitializer" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="MultipleDeclaration" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreForLoopDeclarations" value="true" />
</inspection_tool>
<inspection_tool class="MultipleTopLevelClassesInFile" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MultipleVariablesInDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NamedResource" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="NativeMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NegatedConditional" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreNegatedNullComparison" value="true" />
</inspection_tool>
<inspection_tool class="NegatedConditionalExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NegatedEqualityExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NegatedIfElse" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreNegatedNullComparison" value="true" />
<option name="m_ignoreNegatedZeroComparison" value="false" />
</inspection_tool>
<inspection_tool class="NegativelyNamedBooleanVariable" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NewClassNamingConventionMerged" />
<inspection_tool class="NewExceptionWithoutArguments" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NewGroovyClassNamingConventionMerged" />
<inspection_tool class="NewMethodNamingConventionMerged" />
<inspection_tool class="NoDefaultBaseConstructor" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="NonAsciiCharacters" enabled="true" level="WARNING" enabled_by_default="true">
<option name="CHECK_FOR_FILES_CONTAINING_BOM" value="true" />
</inspection_tool>
<inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalFieldInEnum" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonFinalUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreNonPublicClasses" value="false" />
</inspection_tool>
<inspection_tool class="NonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NoopMethodInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="NotAssignable" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="NullThrown" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObjectEquality" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_ignoreEnums" value="true" />
<option name="m_ignoreClassObjects" value="false" />
<option name="m_ignorePrivateConstructors" value="false" />
</inspection_tool>
<inspection_tool class="ObjectInstantiationInEqualsHashCode" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObjectToString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreRequiredObsoleteCollectionTypes" value="false" />
</inspection_tool>
<inspection_tool class="OctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OptionalContainsCollection" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInMatchingInstanceof" value="true" />
</inspection_tool>
<inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PackageInfoWithoutPackage" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PointerTypeRequired" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ProblematicVarargsMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProtectedField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ProtectedInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreEnums" value="false" />
<option name="ignoreInterfaces" value="false" />
</inspection_tool>
<inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PublicConstructorInNonPublicClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreEnums" value="false" />
<option name="ignorableAnnotations">
<value />
</option>
</inspection_tool>
<inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RandomDoubleForRandomInteger" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreSerializable" value="false" />
<option name="ignoreCloneable" value="false" />
</inspection_tool>
<inspection_tool class="RedundantMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RedundantThrowsDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="RepeatedSpace" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreLazyOperators" value="true" />
<option name="ignoreObscureOperators" value="false" />
</inspection_tool>
<inspection_tool class="ReplaceCallWithComparison" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="RequireNonNull" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="ResourceParameter" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="RestSignature" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ReturnOfCollectionField" enabled="false" level="WARNING" enabled_by_default="false">
<option name="ignorePrivateMethods" value="true" />
</inspection_tool>
<inspection_tool class="ReturnOfDateField" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ScalarTypeRequired" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SerializableClassInSecureContext" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SimplifiableAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SimplifiableEqualsExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SingleCharAlternation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticCallOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticFieldReferenceOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticImport" enabled="true" level="WARNING" enabled_by_default="true">
<option name="allowedClasses">
<set>
<option value="org.junit.Assert" />
</set>
</option>
</inspection_tool>
<inspection_tool class="StaticInheritance" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="4" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="StaticNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticVariableNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="checkMutableFinals" value="false" />
<option name="m_regex" value="s_[a-z][A-Za-z\d]*" />
<option name="m_minLength" value="5" />
<option name="m_maxLength" value="32" />
</inspection_tool>
<inspection_tool class="StaticnessMismatch" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConcatenationInFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringConcatenationMissingWhitespace" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringEqualsCharSequence" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StringReplaceableByStringBuffer" enabled="true" level="WARNING" enabled_by_default="true">
<option name="onlyWarnOnLoop" value="true" />
</inspection_tool>
<inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuperClassHasFrequentlyUsedInheritors" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SuspiciousArrayCast" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SwitchStatementWithConfusingDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SynchronizeOnThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_includeNativeMethods" value="true" />
<option name="ignoreSynchronizedSuperMethods" value="true" />
</inspection_tool>
<inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TemplateArgumentsIssues" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="TestMethodWithoutAssertion" enabled="false" level="WARNING" enabled_by_default="false">
<option name="assertionMethods" value="org.junit.Assert,assert.*|fail.*,junit.framework.Assert,assert.*|fail.*,org.junit.jupiter.api.Assertions,assert.*|fail.*,org.mockito.Mockito,verify.*,org.mockito.InOrder,verify,org.junit.rules.ExpectedException,expect.*,org.hamcrest.MatcherAssert,assertThat" />
</inspection_tool>
<inspection_tool class="TestNGMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ThisEscapedInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="ThrowCaughtLocally" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreRethrownExceptions" value="true" />
</inspection_tool>
<inspection_tool class="ThrowsRuntimeException" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TooBroadScope" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_allowConstructorAsInitializer" value="false" />
<option name="m_onlyLookAtBlocks" value="true" />
</inspection_tool>
<inspection_tool class="TrivialMethodReference" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TrivialStringConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TypeMayBeWeakened" enabled="true" level="WARNING" enabled_by_default="true">
<option name="useRighthandTypeAsWeakestTypeInAssignments" value="true" />
<option name="useParameterizedTypeForCollectionMethods" value="true" />
<option name="doNotWeakenToJavaLangObject" value="true" />
<option name="onlyWeakentoInterface" value="true" />
</inspection_tool>
<inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="TypeParameterNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
<option name="m_regex" value="[A-Z][A-Za-z\d]*" />
<option name="m_minLength" value="1" />
<option name="m_maxLength" value="1" />
</inspection_tool>
<inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessarilyQualifiedInnerClassAccess" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreReferencesNeedingImport" value="true" />
</inspection_tool>
<inspection_tool class="UnnecessaryBlockStatement" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreSwitchBranches" value="false" />
</inspection_tool>
<inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryExplicitNumericCast" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryFullyQualifiedName" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreJavadoc" value="false" />
<option name="ignoreInModuleStatements" value="true" />
</inspection_tool>
<inspection_tool class="UnnecessaryInheritDoc" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryJavaDocLink" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreInlineLinkToSuper" value="false" />
</inspection_tool>
<inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryThis" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryToStringCall" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnsecureRandomNumberGeneration" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnusedCatchParameter" enabled="true" level="WARNING" enabled_by_default="true">
<option name="m_ignoreCatchBlocksWithComments" value="false" />
<option name="m_ignoreTestCases" value="false" />
</inspection_tool>
<inspection_tool class="UnusedImport" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UpperCaseFieldNameNotConstant" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfClone" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UseOfObsoleteDateTimeApi" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignorableAnnotations">
<value />
</option>
<option name="ignoreClassesWithOnlyMain" value="false" />
</inspection_tool>
<inspection_tool class="WeakerAccess" enabled="true" level="WARNING" enabled_by_default="true">
<option name="SUGGEST_PACKAGE_LOCAL_FOR_MEMBERS" value="false" />
<option name="SUGGEST_PACKAGE_LOCAL_FOR_TOP_CLASSES" value="true" />
<option name="SUGGEST_PRIVATE_FOR_INNERS" value="false" />
</inspection_tool>
<inspection_tool class="WhileLoopSpinsOnField" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoreNonEmtpyLoops" value="false" />
</inspection_tool>
<inspection_tool class="ZeroLengthArrayInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="unused" enabled="true" level="WARNING" enabled_by_default="true" klass="packageLocal" inner_class="protected" field="protected" method="protected" parameter="protected">
<option name="LOCAL_VARIABLE" value="true" />
<option name="FIELD" value="true" />
<option name="METHOD" value="true" />
<option name="CLASS" value="true" />
<option name="PARAMETER" value="true" />
<option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="false" />
<option name="ADD_MAINS_TO_ENTRIES" value="true" />
<option name="ADD_APPLET_TO_ENTRIES" value="true" />
<option name="ADD_SERVLET_TO_ENTRIES" value="true" />
<option name="ADD_NONJAVA_TO_ENTRIES" value="true" />
</inspection_tool>
</profile>
</component>
-6
View File
@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Default" />
<version value="1.0" />
</settings>
</component>
+5 -30
View File
@@ -1,40 +1,15 @@
# Android GUI for [WireGuard](https://www.wireguard.com/)
# Android GUI for [AmneziaWG](https://amnezia.org/learn-more/31_amneziawg)
**[Download from the Play Store](https://play.google.com/store/apps/details?id=com.wireguard.android)**
**[Download from the Play Store](https://play.google.com/store/apps/details?id=org.amnezia.awg)**
This is an Android GUI for [WireGuard](https://www.wireguard.com/). It [opportunistically uses the kernel implementation](https://git.zx2c4.com/android_kernel_wireguard/about/), and falls back to using the non-root [userspace implementation](https://git.zx2c4.com/wireguard-go/about/).
This is an Android GUI for [AmneziaWG](https://amnezia.org/learn-more/31_amneziawg).
## Building
```
$ git clone --recurse-submodules https://git.zx2c4.com/wireguard-android
$ cd wireguard-android
$ git clone --recurse-submodules https://github.com/amnezia-vpn/amneziawg-android
$ cd amneziawg-android
$ ./gradlew assembleRelease
```
macOS users may need [flock(1)](https://github.com/discoteq/flock).
## Embedding
The tunnel library is [on Maven Central](https://search.maven.org/artifact/com.wireguard.android/tunnel), alongside [extensive class library documentation](https://javadoc.io/doc/com.wireguard.android/tunnel).
```
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](https://developer.android.com/studio/write/java8-support#library-desugaring):
```
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled = true
}
dependencies {
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.3"
}
```
## Translating
Please help us translate the app into several languages on [our translation platform](https://crowdin.com/project/WireGuard).
-7
View File
@@ -4,10 +4,3 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.kapt) apply false
}
tasks {
wrapper {
gradleVersion = "8.14"
distributionSha256Sum = "61ad310d3c7d3e5da131b76bbf22b5a4c0786e9d892dae8c1658d4b484de3caa"
}
}
+27 -3
View File
@@ -1,6 +1,6 @@
wireguardVersionCode=517
wireguardVersionName=1.0.20251231
wireguardPackageName=com.wireguard.android
amneziawgVersionCode=7
amneziawgVersionName=1.1.4
amneziawgPackageName=org.amnezia.awg
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
@@ -22,15 +22,38 @@ org.gradle.jvmargs=-Xmx1536m
# Turn off AP discovery in compile path to enable compile avoidance
kapt.include.compile.classpath=false
# 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.
android.nonTransitiveRClass=true
# Experimental AGP flags
# Generate compile-time only R class for app modules.
android.enableAppCompileTimeRClass=true
# Keep AAPT2 daemons alive between incremental builds.
android.keepWorkerActionServicesBetweenBuilds=true
# Make R fields non-final to improve build speeds.
# http://tools.android.com/tips/non-constant-fields
android.nonFinalResIds=true
# Enable the newly refactored resource shrinker.
android.experimental.enableNewResourceShrinker=true
# Enable precise shrinking in the new resource shrinker.
android.experimental.enableNewResourceShrinker.preciseShrinking=true
# Generate manifest class as a .class directly rather than a Java source file.
android.generateManifestClass=true
# Generate the text map of source sets and absolute paths to allow
# generating relative paths from absolute paths later in the build.
android.experimental.enableSourceSetPathsMap=true
# Use relative paths for better Gradle caching of library build tasks
android.experimental.cacheCompileLibResources=true
# Default Android build features
# Disable BuildConfig generation by default
android.defaults.buildfeatures.buildconfig=false
# Disable AIDL stub generation by default
android.defaults.buildfeatures.aidl=false
# Disable RenderScript compilation by default
android.defaults.buildfeatures.renderscript=false
# Disable resource values generation by default in libraries
android.defaults.buildfeatures.resvalues=false
# Disable shader compilation by default
@@ -40,6 +63,7 @@ android.library.defaults.buildfeatures.androidresources=false
# Suppress warnings for some features that aren't yet stabilized
android.suppressUnsupportedOptionWarnings=android.keepWorkerActionServicesBetweenBuilds,\
android.experimental.enableNewResourceShrinker.preciseShrinking,\
android.enableAppCompileTimeRClass,\
android.suppressUnsupportedOptionWarnings
+15 -15
View File
@@ -1,25 +1,25 @@
[versions]
agp = "8.13.2"
kotlin = "2.3.0"
agp = "8.3.0"
kotlin = "1.9.20"
[libraries]
androidx-activity-ktx = "androidx.activity:activity-ktx:1.12.2"
androidx-annotation = "androidx.annotation:annotation:1.9.1"
androidx-appcompat = "androidx.appcompat:appcompat:1.7.1"
androidx-activity-ktx = "androidx.activity:activity-ktx:1.8.2"
androidx-annotation = "androidx.annotation:annotation:1.7.1"
androidx-appcompat = "androidx.appcompat:appcompat:1.6.1"
androidx-biometric = "androidx.biometric:biometric:1.1.0"
androidx-collection = "androidx.collection:collection:1.5.0"
androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.2.1"
androidx-coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:1.3.0"
androidx-core-ktx = "androidx.core:core-ktx:1.17.0"
androidx-datastore-preferences = "androidx.datastore:datastore-preferences:1.2.0"
androidx-fragment-ktx = "androidx.fragment:fragment-ktx:1.8.9"
androidx-lifecycle-runtime-ktx = "androidx.lifecycle:lifecycle-runtime-ktx:2.10.0"
androidx-collection = "androidx.collection:collection:1.4.0"
androidx-constraintlayout = "androidx.constraintlayout:constraintlayout:2.1.4"
androidx-coordinatorlayout = "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
androidx-core-ktx = "androidx.core:core-ktx:1.12.0"
androidx-datastore-preferences = "androidx.datastore:datastore-preferences:1.0.0"
androidx-fragment-ktx = "androidx.fragment:fragment-ktx:1.6.2"
androidx-lifecycle-runtime-ktx = "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0"
androidx-preference-ktx = "androidx.preference:preference-ktx:1.2.1"
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.1.5"
google-material = "com.google.android.material:material:1.13.0"
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.0.4"
google-material = "com.google.android.material:material:1.11.0"
jsr305 = "com.google.code.findbugs:jsr305:3.0.2"
junit = "junit:junit:4.13.2"
kotlinx-coroutines-android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2"
kotlinx-coroutines-android = "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
zxing-android-embedded = "com.journeyapps:zxing-android-embedded:4.3.0"
[plugins]
Binary file not shown.
+1 -4
View File
@@ -1,8 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=a17ddd85a26b6a7f5ddb71ff8b05fc5104c0202c6e64782429790c933686c806
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+8 -7
View File
@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015 the original 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.
@@ -15,8 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -57,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# 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/.
@@ -86,7 +84,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -114,6 +112,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -171,6 +170,7 @@ fi
# 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" )
@@ -203,14 +203,15 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
+15 -3
View File
@@ -1,4 +1,4 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.api.dsl.SettingsExtension
pluginManagement {
repositories {
@@ -8,15 +8,27 @@ pluginManagement {
}
}
@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "wireguard-android"
plugins {
id("com.android.settings") version "8.3.0"
}
rootProject.name = "amneziawg-android"
include(":tunnel")
include(":ui")
configure<SettingsExtension> {
buildToolsVersion = "35.0.0"
compileSdk = 35
minSdk = 24
ndkVersion = "26.1.10909125"
}
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "Download https://crowdin.com/backend/download/project/wireguard.zip and provide path as argument"
exit 1
fi
set -ex
bsdtar -C ui/src/main/res -x -f "$1" --strip-components 5 wireguard-android
find ui/src/main/res -name strings.xml -exec bash -c '[[ $(xmllint --xpath "count(//resources/*)" {}) -ne 0 ]] || rm -rf "$(dirname {})"' \;
+4 -86
View File
@@ -1,26 +1,20 @@
@file:Suppress("UnstableApiUsage")
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.gradle.api.tasks.bundling.Zip
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
val pkg: String = providers.gradleProperty("amneziawgPackageName").get()
val cmakeAndroidPackageName: String = providers.environmentVariable("ANDROID_PACKAGE_NAME").getOrElse(pkg)
plugins {
alias(libs.plugins.android.library)
`maven-publish`
signing
}
android {
compileSdk = 36
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
namespace = "${pkg}.tunnel"
defaultConfig {
minSdk = 21
}
externalNativeBuild {
cmake {
path("tools/CMakeLists.txt")
@@ -35,21 +29,20 @@ android {
cmake {
targets("libwg-go.so", "libwg.so", "libwg-quick.so")
arguments("-DGRADLE_USER_HOME=${project.gradle.gradleUserHomeDir}")
arguments("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON")
}
}
}
release {
externalNativeBuild {
cmake {
arguments("-DANDROID_PACKAGE_NAME=${pkg}")
arguments("-DANDROID_PACKAGE_NAME=${cmakeAndroidPackageName}")
}
}
}
debug {
externalNativeBuild {
cmake {
arguments("-DANDROID_PACKAGE_NAME=${pkg}.debug")
arguments("-DANDROID_PACKAGE_NAME=${cmakeAndroidPackageName}.debug")
}
}
}
@@ -58,12 +51,6 @@ android {
disable += "LongLogTag"
disable += "NewApi"
}
publishing {
singleVariant("release") {
withJavadocJar()
withSourcesJar()
}
}
}
dependencies {
@@ -72,72 +59,3 @@ dependencies {
compileOnly(libs.jsr305)
testImplementation(libs.junit)
}
publishing {
publications {
register<MavenPublication>("release") {
groupId = pkg
artifactId = "tunnel"
version = providers.gradleProperty("wireguardVersionName").get()
afterEvaluate {
from(components["release"])
}
pom {
name = "WireGuard Tunnel Library"
description = "Embeddable tunnel library for WireGuard for Android"
url = "https://www.wireguard.com/"
licenses {
license {
name = "The Apache Software License, Version 2.0"
url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution = "repo"
}
}
scm {
connection = "scm:git:https://git.zx2c4.com/wireguard-android"
developerConnection = "scm:git:https://git.zx2c4.com/wireguard-android"
url = "https://git.zx2c4.com/wireguard-android"
}
developers {
organization {
name = "WireGuard"
url = "https://www.wireguard.com/"
}
developer {
name = "WireGuard"
email = "team@wireguard.com"
}
}
}
}
}
repositories {
maven {
name = "SonatypeUpload"
setUrl(layout.buildDirectory.dir("sonatype"))
}
}
}
val releasePublication = publishing.publications.named("release").get() as MavenPublication
val mavenGroupPath = releasePublication.groupId.replace('.', '/')
val mavenArtifactId = releasePublication.artifactId
val mavenVersion = releasePublication.version
tasks.register<Zip>("zipReleasePublication") {
dependsOn(tasks.named("publishReleasePublicationToSonatypeUploadRepository"))
group = "distribution"
description = "Zips the release publication in Maven repository layout."
val sourceDir = layout.buildDirectory.dir("sonatype/${mavenGroupPath}/${mavenArtifactId}/${mavenVersion}")
from(sourceDir)
archiveFileName.set("${mavenArtifactId}-${mavenVersion}-maven.zip")
destinationDirectory.set(layout.buildDirectory.dir("distributions"))
into("${mavenGroupPath}/${mavenArtifactId}/${mavenVersion}")
}
signing {
useGpgCmd()
sign(publishing.publications)
}
+2 -2
View File
@@ -1,5 +1,5 @@
<!--
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
@@ -7,7 +7,7 @@
<application>
<service
android:name="com.wireguard.android.backend.GoBackend$VpnService"
android:name="org.amnezia.awg.backend.GoBackend$VpnService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="false">
<intent-filter>
@@ -1,423 +0,0 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
import com.wireguard.config.BadConfigException.Location;
import com.wireguard.config.BadConfigException.Reason;
import com.wireguard.config.BadConfigException.Section;
import com.wireguard.crypto.Key;
import com.wireguard.crypto.KeyFormatException;
import com.wireguard.crypto.KeyPair;
import com.wireguard.util.NonNullForAll;
import java.net.InetAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import androidx.annotation.Nullable;
/**
* Represents the configuration for a WireGuard interface (an [Interface] block). Interfaces must
* have a private key (used to initialize a {@code KeyPair}), and may optionally have several other
* attributes.
* <p>
* Instances of this class are immutable.
*/
@NonNullForAll
public final class Interface {
private static final int MAX_UDP_PORT = 65535;
private static final int MIN_UDP_PORT = 0;
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;
private final Optional<Integer> listenPort;
private final Optional<Integer> mtu;
private Interface(final Builder builder) {
// 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");
listenPort = builder.listenPort;
mtu = builder.mtu;
}
/**
* Parses an series of "KEY = VALUE" lines into an {@code Interface}. Throws
* {@link ParseException} if the input is not well-formed or contains unknown attributes.
*
* @param lines An iterable sequence of lines, containing at least a private key attribute
* @return An {@code Interface} with all of the attributes from {@code lines} set
*/
public static Interface parse(final Iterable<? extends CharSequence> lines)
throws BadConfigException {
final Builder builder = new Builder();
for (final CharSequence line : lines) {
final Attribute attribute = Attribute.parse(line).orElseThrow(() ->
new BadConfigException(Section.INTERFACE, Location.TOP_LEVEL,
Reason.SYNTAX_ERROR, line));
switch (attribute.getKey().toLowerCase(Locale.ENGLISH)) {
case "address":
builder.parseAddresses(attribute.getValue());
break;
case "dns":
builder.parseDnsServers(attribute.getValue());
break;
case "excludedapplications":
builder.parseExcludedApplications(attribute.getValue());
break;
case "includedapplications":
builder.parseIncludedApplications(attribute.getValue());
break;
case "listenport":
builder.parseListenPort(attribute.getValue());
break;
case "mtu":
builder.parseMtu(attribute.getValue());
break;
case "privatekey":
builder.parsePrivateKey(attribute.getValue());
break;
default:
throw new BadConfigException(Section.INTERFACE, Location.TOP_LEVEL,
Reason.UNKNOWN_ATTRIBUTE, attribute.getKey());
}
}
return builder.build();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof Interface))
return false;
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)
&& listenPort.equals(other.listenPort)
&& mtu.equals(other.mtu);
}
/**
* Returns the set of IP addresses assigned to the interface.
*
* @return a set of {@link InetNetwork}s
*/
public Set<InetNetwork> getAddresses() {
// The collection is already immutable.
return addresses;
}
/**
* Returns the set of DNS servers associated with the interface.
*
* @return a set of {@link InetAddress}es
*/
public Set<InetAddress> getDnsServers() {
// The collection is already immutable.
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.
*
* @return a set of package names
*/
public Set<String> getExcludedApplications() {
// The collection is already immutable.
return excludedApplications;
}
/**
* Returns the set of applications included exclusively for using the interface.
*
* @return a set of package names
*/
public Set<String> getIncludedApplications() {
// The collection is already immutable.
return includedApplications;
}
/**
* Returns the public/private key pair used by the interface.
*
* @return a key pair
*/
public KeyPair getKeyPair() {
return keyPair;
}
/**
* Returns the UDP port number that the WireGuard interface will listen on.
*
* @return a UDP port number, or {@code Optional.empty()} if none is configured
*/
public Optional<Integer> getListenPort() {
return listenPort;
}
/**
* Returns the MTU used for the WireGuard interface.
*
* @return the MTU, or {@code Optional.empty()} if none is configured
*/
public Optional<Integer> getMtu() {
return mtu;
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + addresses.hashCode();
hash = 31 * hash + dnsServers.hashCode();
hash = 31 * hash + excludedApplications.hashCode();
hash = 31 * hash + includedApplications.hashCode();
hash = 31 * hash + keyPair.hashCode();
hash = 31 * hash + listenPort.hashCode();
hash = 31 * hash + mtu.hashCode();
return hash;
}
/**
* Converts the {@code Interface} into a string suitable for debugging purposes. The {@code
* Interface} is identified by its public key and (if set) the port used for its UDP socket.
*
* @return A concise single-line identifier for the {@code Interface}
*/
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("(Interface ");
sb.append(keyPair.getPublicKey().toBase64());
listenPort.ifPresent(lp -> sb.append(" @").append(lp));
sb.append(')');
return sb.toString();
}
/**
* Converts the {@code Interface} into a string suitable for inclusion in a {@code wg-quick}
* configuration file.
*
* @return The {@code Interface} represented as a series of "Key = Value" lines
*/
public String toWgQuickString() {
final StringBuilder sb = new StringBuilder();
if (!addresses.isEmpty())
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())
sb.append("ExcludedApplications = ").append(Attribute.join(excludedApplications)).append('\n');
if (!includedApplications.isEmpty())
sb.append("IncludedApplications = ").append(Attribute.join(includedApplications)).append('\n');
listenPort.ifPresent(lp -> sb.append("ListenPort = ").append(lp).append('\n'));
mtu.ifPresent(m -> sb.append("MTU = ").append(m).append('\n'));
sb.append("PrivateKey = ").append(keyPair.getPrivateKey().toBase64()).append('\n');
return sb.toString();
}
/**
* Serializes the {@code Interface} for use with the WireGuard cross-platform userspace API.
* Note that not all attributes are included in this representation.
*
* @return the {@code Interface} represented as a series of "KEY=VALUE" lines
*/
public String toWgUserspaceString() {
final StringBuilder sb = new StringBuilder();
sb.append("private_key=").append(keyPair.getPrivateKey().toHex()).append('\n');
listenPort.ifPresent(lp -> sb.append("listen_port=").append(lp).append('\n'));
return sb.toString();
}
@SuppressWarnings("UnusedReturnValue")
public static final class Builder {
// Defaults to an empty set.
private final Set<InetNetwork> addresses = new LinkedHashSet<>();
// 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<>();
// No default; must be provided before building.
@Nullable private KeyPair keyPair;
// Defaults to not present.
private Optional<Integer> listenPort = Optional.empty();
// Defaults to not present.
private Optional<Integer> mtu = Optional.empty();
public Builder addAddress(final InetNetwork address) {
addresses.add(address);
return this;
}
public Builder addAddresses(final Collection<InetNetwork> addresses) {
this.addresses.addAll(addresses);
return this;
}
public Builder addDnsServer(final InetAddress dnsServer) {
dnsServers.add(dnsServer);
return this;
}
public Builder addDnsServers(final Collection<? extends InetAddress> dnsServers) {
this.dnsServers.addAll(dnsServers);
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,
Reason.MISSING_ATTRIBUTE, null);
if (!includedApplications.isEmpty() && !excludedApplications.isEmpty())
throw new BadConfigException(Section.INTERFACE, Location.INCLUDED_APPLICATIONS,
Reason.INVALID_KEY, null);
return new Interface(this);
}
public Builder excludeApplication(final String application) {
excludedApplications.add(application);
return this;
}
public Builder excludeApplications(final Collection<String> applications) {
excludedApplications.addAll(applications);
return this;
}
public Builder includeApplication(final String application) {
includedApplications.add(application);
return this;
}
public Builder includeApplications(final Collection<String> applications) {
includedApplications.addAll(applications);
return this;
}
public Builder parseAddresses(final CharSequence addresses) throws BadConfigException {
try {
for (final String address : Attribute.split(addresses))
addAddress(InetNetwork.parse(address));
return this;
} catch (final ParseException e) {
throw new BadConfigException(Section.INTERFACE, Location.ADDRESS, e);
}
}
public Builder parseDnsServers(final CharSequence dnsServers) throws BadConfigException {
try {
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);
}
}
public Builder parseExcludedApplications(final CharSequence apps) {
return excludeApplications(List.of(Attribute.split(apps)));
}
public Builder parseIncludedApplications(final CharSequence apps) {
return includeApplications(List.of(Attribute.split(apps)));
}
public Builder parseListenPort(final String listenPort) throws BadConfigException {
try {
return setListenPort(Integer.parseInt(listenPort));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.LISTEN_PORT, listenPort, e);
}
}
public Builder parseMtu(final String mtu) throws BadConfigException {
try {
return setMtu(Integer.parseInt(mtu));
} catch (final NumberFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.MTU, mtu, e);
}
}
public Builder parsePrivateKey(final String privateKey) throws BadConfigException {
try {
return setKeyPair(new KeyPair(Key.fromBase64(privateKey)));
} catch (final KeyFormatException e) {
throw new BadConfigException(Section.INTERFACE, Location.PRIVATE_KEY, e);
}
}
public Builder setKeyPair(final KeyPair keyPair) {
this.keyPair = keyPair;
return this;
}
public Builder setListenPort(final int listenPort) throws BadConfigException {
if (listenPort < MIN_UDP_PORT || listenPort > MAX_UDP_PORT)
throw new BadConfigException(Section.INTERFACE, Location.LISTEN_PORT,
Reason.INVALID_VALUE, String.valueOf(listenPort));
this.listenPort = listenPort == 0 ? Optional.empty() : Optional.of(listenPort);
return this;
}
public Builder setMtu(final int mtu) throws BadConfigException {
if (mtu < 0)
throw new BadConfigException(Section.INTERFACE, Location.LISTEN_PORT,
Reason.INVALID_VALUE, String.valueOf(mtu));
this.mtu = mtu == 0 ? Optional.empty() : Optional.of(mtu);
return this;
}
}
}
@@ -0,0 +1,18 @@
package org.amnezia.awg;
import androidx.annotation.Nullable;
public class GoBackend {
@Nullable
public static native String awgGetConfig(int handle);
public static native int awgGetSocketV4(int handle);
public static native int awgGetSocketV6(int handle);
public static native void awgTurnOff(int handle);
public static native int awgTurnOn(String ifName, int tunFd, String settings);
public static native String awgVersion();
}
@@ -1,26 +1,25 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.backend;
package org.amnezia.awg.backend;
import android.content.Context;
import android.util.Log;
import android.util.Pair;
import com.wireguard.android.backend.BackendException.Reason;
import com.wireguard.android.backend.Tunnel.State;
import com.wireguard.android.util.RootShell;
import com.wireguard.android.util.ToolsInstaller;
import com.wireguard.config.Config;
import com.wireguard.crypto.Key;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.backend.BackendException.Reason;
import org.amnezia.awg.backend.Tunnel.State;
import org.amnezia.awg.util.RootShell;
import org.amnezia.awg.util.ToolsInstaller;
import org.amnezia.awg.config.Config;
import org.amnezia.awg.crypto.Key;
import org.amnezia.awg.util.NonNullForAll;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -35,27 +34,27 @@ import java.util.Set;
import androidx.annotation.Nullable;
/**
* Implementation of {@link Backend} that uses the kernel module and {@code wg-quick} to provide
* WireGuard tunnels.
* Implementation of {@link Backend} that uses the kernel module and {@code awg-quick} to provide
* AmneziaWG tunnels.
*/
@NonNullForAll
public final class WgQuickBackend implements Backend {
private static final String TAG = "WireGuard/WgQuickBackend";
public final class AwgQuickBackend implements Backend {
private static final String TAG = "AmneziaWG/AwgQuickBackend";
private final File localTemporaryDir;
private final RootShell rootShell;
private final Map<Tunnel, Config> runningConfigs = new HashMap<>();
private final ToolsInstaller toolsInstaller;
private boolean multipleTunnels;
public WgQuickBackend(final Context context, final RootShell rootShell, final ToolsInstaller toolsInstaller) {
public AwgQuickBackend(final Context context, final RootShell rootShell, final ToolsInstaller toolsInstaller) {
localTemporaryDir = new File(context.getCacheDir(), "tmp");
this.rootShell = rootShell;
this.toolsInstaller = toolsInstaller;
}
public static boolean hasKernelSupport() {
return new File("/sys/module/wireguard").exists();
return new File("/sys/module/amneziawg").exists();
}
@Override
@@ -64,13 +63,13 @@ public final class WgQuickBackend implements Backend {
// Don't throw an exception here or nothing will show up in the UI.
try {
toolsInstaller.ensureToolsAvailable();
if (rootShell.run(output, "wg show interfaces") != 0 || output.isEmpty())
if (rootShell.run(output, "awg show interfaces") != 0 || output.isEmpty())
return Collections.emptySet();
} catch (final Exception e) {
Log.w(TAG, "Unable to enumerate running tunnels", e);
return Collections.emptySet();
}
// wg puts all interface names on the same line. Split them into separate elements.
// awg puts all interface names on the same line. Split them into separate elements.
return Set.of(output.get(0).split(" "));
}
@@ -84,7 +83,7 @@ public final class WgQuickBackend implements Backend {
final Statistics stats = new Statistics();
final Collection<String> output = new ArrayList<>();
try {
if (rootShell.run(output, String.format("wg show '%s' dump", tunnel.getName())) != 0)
if (rootShell.run(output, String.format("awg show '%s' dump", tunnel.getName())) != 0)
return stats;
} catch (final Exception ignored) {
return stats;
@@ -104,21 +103,11 @@ public final class WgQuickBackend implements Backend {
@Override
public String getVersion() throws Exception {
final List<String> output = new ArrayList<>();
if (rootShell.run(output, "cat /sys/module/wireguard/version") != 0 || output.isEmpty())
if (rootShell.run(output, "cat /sys/module/amneziawg/version") != 0 || output.isEmpty())
throw new BackendException(Reason.UNKNOWN_KERNEL_MODULE_NAME);
return output.get(0);
}
@Override
public boolean isAlwaysOn() {
return false;
}
@Override
public boolean isLockdownEnabled() {
return false;
}
public void setMultipleTunnels(final boolean on) {
multipleTunnels = on;
}
@@ -184,17 +173,17 @@ public final class WgQuickBackend implements Backend {
final File tempFile = new File(localTemporaryDir, tunnel.getName() + ".conf");
try (final FileOutputStream stream = new FileOutputStream(tempFile, false)) {
stream.write(config.toWgQuickString().getBytes(StandardCharsets.UTF_8));
stream.write(config.toAwgQuickString().getBytes(StandardCharsets.UTF_8));
}
String command = String.format("wg-quick %s '%s'",
String command = String.format("awg-quick %s '%s'",
state.toString().toLowerCase(Locale.ENGLISH), tempFile.getAbsolutePath());
if (state == State.UP)
command = "cat /sys/module/wireguard/version && " + command;
command = "cat /sys/module/amneziawg/version && " + command;
final int result = rootShell.run(null, command);
// noinspection ResultOfMethodCallIgnored
tempFile.delete();
if (result != 0)
throw new BackendException(Reason.WG_QUICK_CONFIG_ERROR_CODE, result);
throw new BackendException(Reason.AWG_QUICK_CONFIG_ERROR_CODE, result);
if (state == State.UP)
runningConfigs.put(tunnel, config);
@@ -1,19 +1,19 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.backend;
package org.amnezia.awg.backend;
import com.wireguard.config.Config;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.config.Config;
import org.amnezia.awg.util.NonNullForAll;
import java.util.Set;
import androidx.annotation.Nullable;
/**
* Interface for implementations of the WireGuard secure network tunnel.
* Interface for implementations of the AmneziaWG secure network tunnel.
*/
@NonNullForAll
@@ -52,28 +52,6 @@ public interface Backend {
*/
String getVersion() throws Exception;
/**
* Determines whether the service is running in always-on VPN mode.
* In this mode the system ensures that the service is always running by restarting it when necessary,
* e.g. after reboot.
*
* @return A boolean indicating whether the service is running in always-on VPN mode.
* @throws Exception Exception raised while retrieving the always-on status.
*/
boolean isAlwaysOn() throws Exception;
/**
* Determines whether the service is running in always-on VPN lockdown mode.
* In this mode the system ensures that the service is always running and that the apps
* aren't allowed to bypass the VPN.
*
* @return A boolean indicating whether the service is running in always-on VPN lockdown mode.
* @throws Exception Exception raised while retrieving the lockdown status.
*/
boolean isLockdownEnabled() throws Exception;
/**
* Set the state of a tunnel, updating it's configuration. If the tunnel is already up, config
* may update the running configuration; config may be null when setting the tunnel down.
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.backend;
package org.amnezia.awg.backend;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
/**
* A subclass of {@link Exception} that encapsulates the reasons for a failure originating in
@@ -50,7 +50,7 @@ public final class BackendException extends Exception {
*/
public enum Reason {
UNKNOWN_KERNEL_MODULE_NAME,
WG_QUICK_CONFIG_ERROR_CODE,
AWG_QUICK_CONFIG_ERROR_CODE,
TUNNEL_MISSING_CONFIG,
VPN_NOT_AUTHORIZED,
UNABLE_TO_START_VPN,
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.backend;
package org.amnezia.awg.backend;
import android.content.Context;
import android.content.Intent;
@@ -12,38 +12,41 @@ import android.os.ParcelFileDescriptor;
import android.system.OsConstants;
import android.util.Log;
import com.wireguard.android.backend.BackendException.Reason;
import com.wireguard.android.backend.Tunnel.State;
import com.wireguard.android.util.SharedLibraryLoader;
import com.wireguard.config.Config;
import com.wireguard.config.InetEndpoint;
import com.wireguard.config.InetNetwork;
import com.wireguard.config.Peer;
import com.wireguard.crypto.Key;
import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.backend.BackendException.Reason;
import org.amnezia.awg.backend.Tunnel.State;
import org.amnezia.awg.util.SharedLibraryLoader;
import org.amnezia.awg.config.Config;
import org.amnezia.awg.config.InetEndpoint;
import org.amnezia.awg.config.InetNetwork;
import org.amnezia.awg.config.Peer;
import org.amnezia.awg.crypto.Key;
import org.amnezia.awg.crypto.KeyFormatException;
import org.amnezia.awg.util.NonNullForAll;
import java.net.InetAddress;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import androidx.annotation.Nullable;
import androidx.collection.ArraySet;
import static org.amnezia.awg.GoBackend.*;
/**
* Implementation of {@link Backend} that uses the wireguard-go userspace implementation to provide
* WireGuard tunnels.
* Implementation of {@link Backend} that uses the amneziawg-go userspace implementation to provide
* AmneziaWG tunnels.
*/
@NonNullForAll
public final class GoBackend implements Backend {
private static final int DNS_RESOLUTION_RETRIES = 10;
private static final String TAG = "WireGuard/GoBackend";
private static final String TAG = "AmneziaWG/GoBackend";
@Nullable private static AlwaysOnCallback alwaysOnCallback;
private static CompletableFuture<VpnService> vpnService = new CompletableFuture<>();
private static GhettoCompletableFuture<VpnService> vpnService = new GhettoCompletableFuture<>();
private final Context context;
@Nullable private Config currentConfig;
@Nullable private Tunnel currentTunnel;
@@ -69,17 +72,7 @@ public final class GoBackend implements Backend {
alwaysOnCallback = cb;
}
@Nullable private static native String wgGetConfig(int handle);
private static native int wgGetSocketV4(int handle);
private static native int wgGetSocketV6(int handle);
private static native void wgTurnOff(int handle);
private static native int wgTurnOn(String ifName, int tunFd, String settings);
private static native String wgVersion();
/**
* Method to get the names of running tunnels.
@@ -118,7 +111,7 @@ public final class GoBackend implements Backend {
final Statistics stats = new Statistics();
if (tunnel != currentTunnel || currentTunnelHandle == -1)
return stats;
final String config = wgGetConfig(currentTunnelHandle);
final String config = awgGetConfig(currentTunnelHandle);
if (config == null)
return stats;
Key key = null;
@@ -177,31 +170,13 @@ public final class GoBackend implements Backend {
}
/**
* Get the version of the underlying wireguard-go library.
* Get the version of the underlying amneziawg-go library.
*
* @return {@link String} value of the version of the wireguard-go library.
* @return {@link String} value of the version of the amneziawg-go library.
*/
@Override
public String getVersion() {
return wgVersion();
}
/**
* Determines if the service is running in always-on VPN mode.
* @return {@link boolean} whether the service is running in always-on VPN mode.
*/
@Override
public boolean isAlwaysOn() throws ExecutionException, InterruptedException, TimeoutException {
return vpnService.get(0, TimeUnit.NANOSECONDS).isAlwaysOn();
}
/**
* Determines if the service is running in always-on VPN lockdown mode.
* @return {@link boolean} whether the service is running in always-on VPN lockdown mode.
*/
@Override
public boolean isLockdownEnabled() throws ExecutionException, InterruptedException, TimeoutException {
return vpnService.get(0, TimeUnit.NANOSECONDS).isLockdownEnabled();
return awgVersion();
}
/**
@@ -291,7 +266,7 @@ public final class GoBackend implements Backend {
}
// Build config
final String goConfig = config.toWgUserspaceString();
final String goConfig = config.toAwgUserspaceString();
// Create the vpn tunnel with android API
final VpnService.Builder builder = service.getBuilder();
@@ -338,8 +313,8 @@ public final class GoBackend implements Backend {
try (final ParcelFileDescriptor tun = builder.establish()) {
if (tun == null)
throw new BackendException(Reason.TUN_CREATION_ERROR);
Log.d(TAG, "Go backend " + wgVersion());
currentTunnelHandle = wgTurnOn(tunnel.getName(), tun.detachFd(), goConfig);
Log.d(TAG, "Go backend " + awgVersion());
currentTunnelHandle = awgTurnOn(tunnel.getName(), tun.detachFd(), goConfig);
}
if (currentTunnelHandle < 0)
throw new BackendException(Reason.GO_ACTIVATION_ERROR_CODE, currentTunnelHandle);
@@ -347,8 +322,8 @@ public final class GoBackend implements Backend {
currentTunnel = tunnel;
currentConfig = config;
service.protect(wgGetSocketV4(currentTunnelHandle));
service.protect(wgGetSocketV6(currentTunnelHandle));
service.protect(awgGetSocketV4(currentTunnelHandle));
service.protect(awgGetSocketV6(currentTunnelHandle));
} else {
if (currentTunnelHandle == -1) {
Log.w(TAG, "Tunnel already down");
@@ -358,7 +333,7 @@ public final class GoBackend implements Backend {
currentTunnel = null;
currentTunnelHandle = -1;
currentConfig = null;
wgTurnOff(handleToClose);
awgTurnOff(handleToClose);
try {
vpnService.get(0, TimeUnit.NANOSECONDS).stopSelf();
} catch (final TimeoutException ignored) { }
@@ -375,6 +350,35 @@ public final class GoBackend implements Backend {
void alwaysOnTriggered();
}
// TODO: When we finally drop API 21 and move to API 24, delete this and replace with the ordinary CompletableFuture.
private static final class GhettoCompletableFuture<V> {
private final LinkedBlockingQueue<V> completion = new LinkedBlockingQueue<>(1);
private final FutureTask<V> result = new FutureTask<>(completion::peek);
public boolean complete(final V value) {
final boolean offered = completion.offer(value);
if (offered)
result.run();
return offered;
}
public V get() throws ExecutionException, InterruptedException {
return result.get();
}
public V get(final long timeout, final TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {
return result.get(timeout, unit);
}
public boolean isDone() {
return !completion.isEmpty();
}
public GhettoCompletableFuture<V> newIncompleteFuture() {
return new GhettoCompletableFuture<>();
}
}
/**
* {@link android.net.VpnService} implementation for {@link GoBackend}
*/
@@ -397,7 +401,7 @@ public final class GoBackend implements Backend {
final Tunnel tunnel = owner.currentTunnel;
if (tunnel != null) {
if (owner.currentTunnelHandle != -1)
wgTurnOff(owner.currentTunnelHandle);
awgTurnOff(owner.currentTunnelHandle);
owner.currentTunnel = null;
owner.currentTunnelHandle = -1;
owner.currentConfig = null;
@@ -1,18 +1,17 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.backend;
package org.amnezia.awg.backend;
import android.os.SystemClock;
import com.wireguard.crypto.Key;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.crypto.Key;
import org.amnezia.awg.util.NonNullForAll;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import androidx.annotation.Nullable;
@@ -31,12 +30,12 @@ public class Statistics {
/**
* Add a peer and its current stats to the internal map.
*
* @param key A WireGuard public key bound to a particular peer
* @param rxBytes The received traffic for the {@link com.wireguard.config.Peer} referenced by
* @param key An AmneziaWG public key bound to a particular peer
* @param rxBytes The received traffic for the {@link org.amnezia.config.Peer} referenced by
* the provided {@link Key}. This value is in bytes
* @param txBytes The transmitted traffic for the {@link com.wireguard.config.Peer} referenced by
* @param txBytes The transmitted traffic for the {@link org.amnezia.config.Peer} referenced by
* the provided {@link Key}. This value is in bytes.
* @param latestHandshake The timestamp of the latest handshake for the {@link com.wireguard.config.Peer}
* @param latestHandshake The timestamp of the latest handshake for the {@link org.amnezia.config.Peer}
* referenced by the provided {@link Key}. The value is in epoch milliseconds.
*/
void add(final Key key, final long rxBytes, final long txBytes, final long latestHandshake) {
@@ -54,9 +53,9 @@ public class Statistics {
}
/**
* Get the statistics for the {@link com.wireguard.config.Peer} referenced by the provided {@link Key}
* Get the statistics for the {@link org.amnezia.config.Peer} referenced by the provided {@link Key}
*
* @param peer A {@link Key} representing a {@link com.wireguard.config.Peer}.
* @param peer A {@link Key} representing a {@link org.amnezia.config.Peer}.
* @return a {@link PeerStats} representing various statistics about this peer.
*/
@Nullable
@@ -67,8 +66,8 @@ public class Statistics {
/**
* Get the list of peers being tracked by this instance.
*
* @return An array of {@link Key} instances representing WireGuard
* {@link com.wireguard.config.Peer}s
* @return An array of {@link Key} instances representing AmneziaWG
* {@link org.amnezia.config.Peer}s
*/
public Key[] peers() {
return stats.keySet().toArray(new Key[0]);
@@ -1,16 +1,16 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.backend;
package org.amnezia.awg.backend;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.util.regex.Pattern;
/**
* Represents a WireGuard tunnel.
* Represents an AmneziaWG tunnel.
*/
@NonNullForAll
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.util.Iterator;
import java.util.Optional;
@@ -1,12 +1,12 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.crypto.KeyFormatException;
import org.amnezia.awg.util.NonNullForAll;
import androidx.annotation.Nullable;
@@ -78,7 +78,23 @@ public class BadConfigException extends Exception {
PERSISTENT_KEEPALIVE("PersistentKeepalive"),
PRE_SHARED_KEY("PresharedKey"),
PRIVATE_KEY("PrivateKey"),
PUBLIC_KEY("PublicKey");
PUBLIC_KEY("PublicKey"),
JUNK_PACKET_COUNT("JunkPacketCount"),
JUNK_PACKET_MIN_SIZE("JunkPacketMinSize"),
JUNK_PACKET_MAX_SIZE("JunkPacketMaxSize"),
INIT_PACKET_JUNK_SIZE("InitPacketJunkSize"),
RESPONSE_PACKET_JUNK_SIZE("ResponsePacketJunkSize"),
COOKIE_REPLY_PACKET_JUNK_SIZE("CookieReplyPacketJunkSize"),
TRANSPORT_PACKET_JUNK_SIZE("TransportPacketJunkSize"),
INIT_PACKET_MAGIC_HEADER("InitPacketMagicHeader"),
RESPONSE_PACKET_MAGIC_HEADER("ResponsePacketMagicHeader"),
UNDERLOAD_PACKET_MAGIC_HEADER("UnderloadPacketMagicHeader"),
TRANSPORT_PACKET_MAGIC_HEADER("TransportPacketMagicHeader"),
SPECIAL_JUNK_I1("SpecialJunkI1"),
SPECIAL_JUNK_I2("SpecialJunkI2"),
SPECIAL_JUNK_I3("SpecialJunkI3"),
SPECIAL_JUNK_I4("SpecialJunkI4"),
SPECIAL_JUNK_I5("SpecialJunkI5");
private final String name;
@@ -1,14 +1,14 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.config.BadConfigException.Location;
import com.wireguard.config.BadConfigException.Reason;
import com.wireguard.config.BadConfigException.Section;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.config.BadConfigException.Location;
import org.amnezia.awg.config.BadConfigException.Reason;
import org.amnezia.awg.config.BadConfigException.Section;
import org.amnezia.awg.util.NonNullForAll;
import java.io.BufferedReader;
import java.io.IOException;
@@ -23,7 +23,7 @@ import java.util.Objects;
import androidx.annotation.Nullable;
/**
* Represents the contents of a wg-quick configuration file, made up of one or more "Interface"
* Represents the contents of a awg-quick configuration file, made up of one or more "Interface"
* sections (combined together), and zero or more "Peer" sections (treated individually).
* <p>
* Instances of this class are immutable.
@@ -44,7 +44,7 @@ public final class Config {
* {@link BadConfigException} if the input is not well-formed or contains data that cannot
* be parsed.
*
* @param stream a stream of UTF-8 text that is interpreted as a WireGuard configuration
* @param stream a stream of UTF-8 text that is interpreted as an AmneziaWG configuration
* @return a {@code Config} instance representing the supplied configuration
*/
public static Config parse(final InputStream stream)
@@ -57,7 +57,7 @@ public final class Config {
* {@link BadConfigException} if the input is not well-formed or contains data that cannot
* be parsed.
*
* @param reader a BufferedReader of UTF-8 text that is interpreted as a WireGuard configuration
* @param reader a BufferedReader of UTF-8 text that is interpreted as an AmneziaWG configuration
* @return a {@code Config} instance representing the supplied configuration
*/
public static Config parse(final BufferedReader reader)
@@ -155,30 +155,30 @@ public final class Config {
}
/**
* Converts the {@code Config} into a string suitable for use as a {@code wg-quick}
* Converts the {@code Config} into a string suitable for use as a {@code awg-quick}
* configuration file.
*
* @return the {@code Config} represented as one [Interface] and zero or more [Peer] sections
*/
public String toWgQuickString() {
public String toAwgQuickString() {
final StringBuilder sb = new StringBuilder();
sb.append("[Interface]\n").append(interfaze.toWgQuickString());
sb.append("[Interface]\n").append(interfaze.toAwgQuickString());
for (final Peer peer : peers)
sb.append("\n[Peer]\n").append(peer.toWgQuickString());
sb.append("\n[Peer]\n").append(peer.toAwgQuickString());
return sb.toString();
}
/**
* Serializes the {@code Config} for use with the WireGuard cross-platform userspace API.
* Serializes the {@code Config} for use with the AmneziaWG cross-platform userspace API.
*
* @return the {@code Config} represented as a series of "key=value" lines
*/
public String toWgUserspaceString() {
public String toAwgUserspaceString() {
final StringBuilder sb = new StringBuilder();
sb.append(interfaze.toWgUserspaceString());
sb.append(interfaze.toAwgUserspaceString());
sb.append("replace_peers=true\n");
for (final Peer peer : peers)
sb.append(peer.toWgUserspaceString());
sb.append(peer.toAwgUserspaceString());
return sb.toString();
}
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.lang.reflect.Method;
import java.net.Inet4Address;
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -21,7 +21,7 @@ import androidx.annotation.Nullable;
/**
* An external endpoint (host and port) used to connect to a WireGuard {@link Peer}.
* An external endpoint (host and port) used to connect to an AmneziaWG {@link Peer}.
* <p>
* Instances of this class are externally immutable.
*/
@@ -48,7 +48,7 @@ public final class InetEndpoint {
throw new ParseException(InetEndpoint.class, endpoint, "Forbidden characters");
final URI uri;
try {
uri = new URI("wg://" + endpoint);
uri = new URI("awg://" + endpoint);
} catch (final URISyntaxException e) {
throw new ParseException(InetEndpoint.class, endpoint, e);
}
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.net.Inet4Address;
import java.net.InetAddress;
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import androidx.annotation.Nullable;
@@ -1,16 +1,16 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.config.BadConfigException.Location;
import com.wireguard.config.BadConfigException.Reason;
import com.wireguard.config.BadConfigException.Section;
import com.wireguard.crypto.Key;
import com.wireguard.crypto.KeyFormatException;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.config.BadConfigException.Location;
import org.amnezia.awg.config.BadConfigException.Reason;
import org.amnezia.awg.config.BadConfigException.Section;
import org.amnezia.awg.crypto.Key;
import org.amnezia.awg.crypto.KeyFormatException;
import org.amnezia.awg.util.NonNullForAll;
import java.util.Collection;
import java.util.Collections;
@@ -23,7 +23,7 @@ import java.util.Set;
import androidx.annotation.Nullable;
/**
* Represents the configuration for a WireGuard peer (a [Peer] block). Peers must have a public key,
* Represents the configuration for an AmneziaWG peer (a [Peer] block). Peers must have a public key,
* and may optionally have several other attributes.
* <p>
* Instances of this class are immutable.
@@ -168,12 +168,12 @@ public final class Peer {
}
/**
* Converts the {@code Peer} into a string suitable for inclusion in a {@code wg-quick}
* Converts the {@code Peer} into a string suitable for inclusion in a {@code awg-quick}
* configuration file.
*
* @return the {@code Peer} represented as a series of "Key = Value" lines
*/
public String toWgQuickString() {
public String toAwgQuickString() {
final StringBuilder sb = new StringBuilder();
if (!allowedIps.isEmpty())
sb.append("AllowedIPs = ").append(Attribute.join(allowedIps)).append('\n');
@@ -185,12 +185,12 @@ public final class Peer {
}
/**
* Serializes the {@code Peer} for use with the WireGuard cross-platform userspace API. Note
* Serializes the {@code Peer} for use with the AmneziaWG cross-platform userspace API. Note
* that not all attributes are included in this representation.
*
* @return the {@code Peer} represented as a series of "key=value" lines
*/
public String toWgUserspaceString() {
public String toAwgUserspaceString() {
final StringBuilder sb = new StringBuilder();
// The order here is important: public_key signifies the beginning of a new peer.
sb.append("public_key=").append(publicKey.toHex()).append('\n');
@@ -204,7 +204,7 @@ public final class Peer {
@SuppressWarnings("UnusedReturnValue")
public static final class Builder {
// See wg(8)
// See awg(8)
private static final int MAX_PERSISTENT_KEEPALIVE = 65535;
// Defaults to an empty set.
@@ -1,12 +1,12 @@
/*
* Copyright © 2016 Southern Storm Software, Pty Ltd.
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.crypto;
package org.amnezia.awg.crypto;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.util.Arrays;
@@ -15,7 +15,7 @@ import androidx.annotation.Nullable;
/**
* Implementation of Curve25519 ECDH.
* <p>
* This implementation was imported to WireGuard from noise-java:
* This implementation was imported to AmneziaWG from noise-java:
* https://github.com/rweather/noise-java
* <p>
* This implementation is based on that from arduinolibs:
@@ -1,19 +1,19 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.crypto;
package org.amnezia.awg.crypto;
import com.wireguard.crypto.KeyFormatException.Type;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.crypto.KeyFormatException.Type;
import org.amnezia.awg.util.NonNullForAll;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
/**
* Represents a WireGuard public or private key. This class uses specialized constant-time base64
* Represents an AmneziaWG public or private key. This class uses specialized constant-time base64
* and hexadecimal codec implementations that resist side-channel attacks.
* <p>
* Instances of this class are immutable.
@@ -83,10 +83,10 @@ public final class Key {
}
/**
* Decodes a WireGuard public or private key from its base64 string representation. This
* Decodes an AmneziaWG public or private key from its base64 string representation. This
* function throws a {@link KeyFormatException} if the source string is not well-formed.
*
* @param str the base64 string representation of a WireGuard key
* @param str the base64 string representation of an AmneziaWG key
* @return the decoded key encapsulated in an immutable container
*/
public static Key fromBase64(final String str) throws KeyFormatException {
@@ -120,10 +120,10 @@ public final class Key {
}
/**
* Wraps a WireGuard public or private key in an immutable container. This function throws a
* Wraps an AmneziaWG public or private key in an immutable container. This function throws a
* {@link KeyFormatException} if the source data is not the correct length.
*
* @param bytes an array of bytes containing a WireGuard key in binary format
* @param bytes an array of bytes containing an AmneziaWG key in binary format
* @return the key encapsulated in an immutable container
*/
public static Key fromBytes(final byte[] bytes) throws KeyFormatException {
@@ -133,10 +133,10 @@ public final class Key {
}
/**
* Decodes a WireGuard public or private key from its hexadecimal string representation. This
* Decodes an AmneziaWG public or private key from its hexadecimal string representation. This
* function throws a {@link KeyFormatException} if the source string is not well-formed.
*
* @param str the hexadecimal string representation of a WireGuard key
* @param str the hexadecimal string representation of an AmneziaWG key
* @return the decoded key encapsulated in an immutable container
*/
public static Key fromHex(final String str) throws KeyFormatException {
@@ -269,7 +269,7 @@ public final class Key {
}
/**
* The supported formats for encoding a WireGuard key.
* The supported formats for encoding an AmneziaWG key.
*/
public enum Format {
BASE64(44),
@@ -1,11 +1,11 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.crypto;
package org.amnezia.awg.crypto;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
/**
* An exception thrown when attempting to parse an invalid key (too short, too long, or byte
@@ -1,14 +1,14 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.crypto;
package org.amnezia.awg.crypto;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
/**
* Represents a Curve25519 key pair as used by WireGuard.
* Represents a Curve25519 key pair as used by AmneziaWG.
* <p>
* Instances of this class are immutable.
*/
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.util;
package org.amnezia.awg.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -1,15 +1,15 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util;
package org.amnezia.awg.util;
import android.content.Context;
import android.util.Log;
import com.wireguard.android.util.RootShell.RootShellException.Reason;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.RootShell.RootShellException.Reason;
import org.amnezia.awg.util.NonNullForAll;
import java.io.BufferedReader;
import java.io.File;
@@ -29,7 +29,7 @@ import androidx.annotation.Nullable;
@NonNullForAll
public class RootShell {
private static final String SU = "su";
private static final String TAG = "WireGuard/RootShell";
private static final String TAG = "AmneziaWG/RootShell";
private final File localBinaryDir;
private final File localTemporaryDir;
@@ -1,15 +1,15 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util;
package org.amnezia.awg.util;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.NonNullForAll;
import java.io.File;
import java.io.FileOutputStream;
@@ -27,7 +27,7 @@ import androidx.annotation.RestrictTo.Scope;
@NonNullForAll
@RestrictTo(Scope.LIBRARY_GROUP)
public final class SharedLibraryLoader {
private static final String TAG = "WireGuard/SharedLibraryLoader";
private static final String TAG = "AmneziaWG/SharedLibraryLoader";
private SharedLibraryLoader() {
}
@@ -1,16 +1,16 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util;
package org.amnezia.awg.util;
import android.content.Context;
import android.system.OsConstants;
import android.util.Log;
import com.wireguard.android.util.RootShell.RootShellException;
import com.wireguard.util.NonNullForAll;
import org.amnezia.awg.util.RootShell.RootShellException;
import org.amnezia.awg.util.NonNullForAll;
import java.io.File;
import java.io.FileNotFoundException;
@@ -23,7 +23,7 @@ import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
/**
* Helper to install WireGuard tools to the system partition.
* Helper to install AmneziaWG tools to the system partition.
*/
@NonNullForAll
@@ -33,13 +33,13 @@ public final class ToolsInstaller {
public static final int NO = 0x2;
public static final int SYSTEM = 0x8;
public static final int YES = 0x1;
private static final String[] EXECUTABLES = {"wg", "wg-quick"};
private static final String[] EXECUTABLES = {"awg", "awg-quick"};
private static final File[] INSTALL_DIRS = {
new File("/system/xbin"),
new File("/system/bin"),
};
@Nullable private static final File INSTALL_DIR = getInstallDir();
private static final String TAG = "WireGuard/ToolsInstaller";
private static final String TAG = "AmneziaWG/ToolsInstaller";
private final Context context;
private final File localBinaryDir;
@@ -100,7 +100,7 @@ public final class ToolsInstaller {
"Tools were already extracted into our private binary dir");
areToolsAvailable = true;
} catch (final IOException e) {
Log.e(TAG, "The wg and wg-quick tools are not available", e);
Log.e(TAG, "The awg and awg-quick tools are not available", e);
areToolsAvailable = false;
}
}
@@ -134,8 +134,8 @@ public final class ToolsInstaller {
@RestrictTo(Scope.LIBRARY_GROUP)
public int install() throws RootShellException, IOException {
if (!context.getPackageName().startsWith("com.wireguard."))
throw new SecurityException("The tools may only be installed system-wide from the main WireGuard app.");
if (!context.getPackageName().startsWith("org.amnezia."))
throw new SecurityException("The tools may only be installed system-wide from the main AmneziaWG app.");
return willInstallAsMagiskModule() ? installMagisk() : installSystem();
}
@@ -143,12 +143,12 @@ public final class ToolsInstaller {
extract();
final StringBuilder script = new StringBuilder("set -ex; ");
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 '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; ");
script.append("trap 'rm -rf /data/adb/modules/amneziawg' INT TERM EXIT; ");
script.append(String.format("rm -rf /data/adb/modules/amneziawg/; mkdir -p /data/adb/modules/amneziawg%s; ", INSTALL_DIR));
script.append("printf 'id=amneziawg\nname=AmneziaWG Command Line Tools\nversion=1.0\nversionCode=1\nauthor=amnezia\ndescription=Command line tools for AmneziaWG\nminMagisk=1500\n' > /data/adb/modules/amneziawg/module.prop; ");
script.append("touch /data/adb/modules/amneziawg/auto_mount; ");
for (final String name : EXECUTABLES) {
final File destination = new File("/data/adb/modules/wireguard" + INSTALL_DIR, name);
final File destination = new File("/data/adb/modules/amneziawg" + INSTALL_DIR, name);
script.append(String.format("cp '%s' '%s'; chmod 755 '%s'; chcon 'u:object_r:system_file:s0' '%s' || true; ",
new File(localBinaryDir, name), destination, destination, destination));
}
@@ -1,13 +1,13 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import com.wireguard.config.BadConfigException.Location;
import com.wireguard.config.BadConfigException.Reason;
import com.wireguard.config.BadConfigException.Section;
import org.amnezia.awg.config.BadConfigException.Location;
import org.amnezia.awg.config.BadConfigException.Reason;
import org.amnezia.awg.config.BadConfigException.Section;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.config;
package org.amnezia.awg.config;
import org.junit.Test;
+7 -7
View File
@@ -1,23 +1,23 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
# Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
cmake_minimum_required(VERSION 3.4.1)
project("WireGuard")
project("AmneziaWG")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
add_link_options(LINKER:--build-id=none)
add_compile_options(-Wall -Werror)
add_executable(libwg-quick.so wireguard-tools/src/wg-quick/android.c ndk-compat/compat.c)
target_compile_options(libwg-quick.so PUBLIC -std=gnu11 -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\")
add_executable(libwg-quick.so amneziawg-tools/src/wg-quick/android.c ndk-compat/compat.c)
target_compile_options(libwg-quick.so PUBLIC -std=gnu11 -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -DAWG_PACKAGE_NAME=\"${ANDROID_PACKAGE_NAME}\")
target_link_libraries(libwg-quick.so -ldl)
file(GLOB WG_SOURCES wireguard-tools/src/*.c ndk-compat/compat.c)
file(GLOB WG_SOURCES amneziawg-tools/src/*.c ndk-compat/compat.c)
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_include_directories(libwg.so PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/amneziawg-tools/src/uapi/linux/" "${CMAKE_CURRENT_SOURCE_DIR}/amneziawg-tools/src/")
target_compile_options(libwg.so PUBLIC -std=gnu11 -include ${CMAKE_CURRENT_SOURCE_DIR}/ndk-compat/compat.h -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 "${ANDROID_HOST_PREBUILTS}/bin/make"
add_custom_target(libwg-go.so WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/libwg-go" COMMENT "Building amneziawg-go" VERBATIM COMMAND "${ANDROID_HOST_PREBUILTS}/bin/make"
ANDROID_ARCH_NAME=${ANDROID_ARCH_NAME}
ANDROID_PACKAGE_NAME=${ANDROID_PACKAGE_NAME}
GRADLE_USER_HOME=${GRADLE_USER_HOME}
+6 -6
View File
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
# Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
BUILDDIR ?= $(CURDIR)/build
DESTDIR ?= $(CURDIR)/out
@@ -20,12 +20,12 @@ export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME))
export GOOS := android
export CGO_ENABLED := 1
GO_VERSION := 1.24.3
GO_VERSION := 1.24.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 := 13e6fe3fcf65689d77d40e633de1e31c6febbdbcb846eb05fc2434ed2213e92b
GO_HASH_darwin-arm64 := 64a3fa22142f627e78fac3018ce3d4aeace68b743eff0afda8aae0411df5e4fb
GO_HASH_linux-amd64 := 3333f6ea53afa971e9078895eaa4ac7204a8c6b5c68c10e6bc9a33e8e391bdd8
GO_HASH_darwin-amd64 := 238d9c065d09ff6af229d2e3b8b5e85e688318d69f4006fb85a96e41c216ea83
GO_HASH_darwin-arm64 := b70f8b3c5b4ccb0ad4ffa5ee91cd38075df20fdbd953a1daedd47f50fbcff47a
GO_HASH_linux-amd64 := 68097bd680839cbc9d464a0edce4f7c333975e27a90246890e9f1078c7e702ad
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 -buildid=" -v -trimpath -buildvcs=false -o "$@" -buildmode c-shared
go build -tags linux -ldflags="-X github.com/amnezia-vpn/amneziawg-go/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/amneziawg -buildid=" -v -trimpath -buildvcs=false -o "$@" -buildmode c-shared
.DELETE_ON_ERROR:
+19 -19
View File
@@ -20,11 +20,11 @@ import (
"strings"
"unsafe"
"github.com/amnezia-vpn/amneziawg-go/conn"
"github.com/amnezia-vpn/amneziawg-go/device"
"github.com/amnezia-vpn/amneziawg-go/ipc"
"github.com/amnezia-vpn/amneziawg-go/tun"
"golang.org/x/sys/unix"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/ipc"
"golang.zx2c4.com/wireguard/tun"
)
type AndroidLogger struct {
@@ -66,15 +66,15 @@ func init() {
n--
}
buf[n] = 0
C.__android_log_write(C.ANDROID_LOG_ERROR, cstring("WireGuard/GoBackend/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0])))
C.__android_log_write(C.ANDROID_LOG_ERROR, cstring("AmneziaWG/Stacktrace"), (*C.char)(unsafe.Pointer(&buf[0])))
}
}
}()
}
//export wgTurnOn
func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 {
tag := cstring("WireGuard/GoBackend/" + interfaceName)
//export awgTurnOn
func awgTurnOn(interfaceName string, tunFd int32, settings string) int32 {
tag := cstring("AmneziaWG/" + interfaceName)
logger := &device.Logger{
Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf,
Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf,
@@ -146,8 +146,8 @@ func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 {
return i
}
//export wgTurnOff
func wgTurnOff(tunnelHandle int32) {
//export awgTurnOff
func awgTurnOff(tunnelHandle int32) {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return
@@ -159,8 +159,8 @@ func wgTurnOff(tunnelHandle int32) {
handle.device.Close()
}
//export wgGetSocketV4
func wgGetSocketV4(tunnelHandle int32) int32 {
//export awgGetSocketV4
func awgGetSocketV4(tunnelHandle int32) int32 {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return -1
@@ -176,8 +176,8 @@ func wgGetSocketV4(tunnelHandle int32) int32 {
return int32(fd)
}
//export wgGetSocketV6
func wgGetSocketV6(tunnelHandle int32) int32 {
//export awgGetSocketV6
func awgGetSocketV6(tunnelHandle int32) int32 {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return -1
@@ -193,8 +193,8 @@ func wgGetSocketV6(tunnelHandle int32) int32 {
return int32(fd)
}
//export wgGetConfig
func wgGetConfig(tunnelHandle int32) *C.char {
//export awgGetConfig
func awgGetConfig(tunnelHandle int32) *C.char {
handle, ok := tunnelHandles[tunnelHandle]
if !ok {
return nil
@@ -206,14 +206,14 @@ func wgGetConfig(tunnelHandle int32) *C.char {
return C.CString(settings)
}
//export wgVersion
func wgVersion() *C.char {
//export awgVersion
func awgVersion() *C.char {
info, ok := debug.ReadBuildInfo()
if !ok {
return C.CString("unknown")
}
for _, dep := range info.Deps {
if dep.Path == "golang.zx2c4.com/wireguard" {
if dep.Path == "github.com/amnezia-vpn/amneziawg-go" {
parts := strings.Split(dep.Version, "-")
if len(parts) == 3 && len(parts[2]) == 12 {
return C.CString(parts[2][:7])
+5 -5
View File
@@ -1,14 +1,14 @@
module golang.zx2c4.com/wireguard/android
module github.com/amnezia-vpn/amneziawg-android
go 1.23.1
go 1.24.4
require (
github.com/amnezia-vpn/amneziawg-go v0.2.16
golang.org/x/sys v0.33.0
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
)
require (
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
)
+14 -12
View File
@@ -1,16 +1,18 @@
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
github.com/amnezia-vpn/amneziawg-go v0.2.16 h1:XY6HOq/xtqH8ZXMncRWkjFs85EKdN10NLNnw23kTpE0=
github.com/amnezia-vpn/amneziawg-go v0.2.16/go.mod h1:nRkPpIzjCxMW8pZKXTRkpqAQVlmFJdVOGkeQSC7wbms=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
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-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+ZbWg+4sHnLp52d5yiIPUxMBSt4X9A=
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c h1:m/r7OM+Y2Ty1sgBQ7Qb27VgIMBW8ZZhT4gLnUyDIhzI=
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g=
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 h1:ze1vwAdliUAr68RQ5NtufWaXaOg8WUO2OACzEV+TNdE=
gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk=
+18 -18
View File
@@ -8,20 +8,20 @@
#include <string.h>
struct go_string { const char *str; long n; };
extern int wgTurnOn(struct go_string ifname, int tun_fd, struct go_string settings);
extern void wgTurnOff(int handle);
extern int wgGetSocketV4(int handle);
extern int wgGetSocketV6(int handle);
extern char *wgGetConfig(int handle);
extern char *wgVersion();
extern int awgTurnOn(struct go_string ifname, int tun_fd, struct go_string settings);
extern void awgTurnOff(int handle);
extern int awgGetSocketV4(int handle);
extern int awgGetSocketV6(int handle);
extern char *awgGetConfig(int handle);
extern char *awgVersion();
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings)
JNIEXPORT jint JNICALL Java_org_amnezia_awg_GoBackend_awgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings)
{
const char *ifname_str = (*env)->GetStringUTFChars(env, ifname, 0);
size_t ifname_len = (*env)->GetStringUTFLength(env, ifname);
const char *settings_str = (*env)->GetStringUTFChars(env, settings, 0);
size_t settings_len = (*env)->GetStringUTFLength(env, settings);
int ret = wgTurnOn((struct go_string){
int ret = awgTurnOn((struct go_string){
.str = ifname_str,
.n = ifname_len
}, tun_fd, (struct go_string){
@@ -33,25 +33,25 @@ JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNI
return ret;
}
JNIEXPORT void JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOff(JNIEnv *env, jclass c, jint handle)
JNIEXPORT void JNICALL Java_org_amnezia_awg_GoBackend_awgTurnOff(JNIEnv *env, jclass c, jint handle)
{
wgTurnOff(handle);
awgTurnOff(handle);
}
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV4(JNIEnv *env, jclass c, jint handle)
JNIEXPORT jint JNICALL Java_org_amnezia_awg_GoBackend_awgGetSocketV4(JNIEnv *env, jclass c, jint handle)
{
return wgGetSocketV4(handle);
return awgGetSocketV4(handle);
}
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetSocketV6(JNIEnv *env, jclass c, jint handle)
JNIEXPORT jint JNICALL Java_org_amnezia_awg_GoBackend_awgGetSocketV6(JNIEnv *env, jclass c, jint handle)
{
return wgGetSocketV6(handle);
return awgGetSocketV6(handle);
}
JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetConfig(JNIEnv *env, jclass c, jint handle)
JNIEXPORT jstring JNICALL Java_org_amnezia_awg_GoBackend_awgGetConfig(JNIEnv *env, jclass c, jint handle)
{
jstring ret;
char *config = wgGetConfig(handle);
char *config = awgGetConfig(handle);
if (!config)
return NULL;
ret = (*env)->NewStringUTF(env, config);
@@ -59,10 +59,10 @@ JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgGetConf
return ret;
}
JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgVersion(JNIEnv *env, jclass c)
JNIEXPORT jstring JNICALL Java_org_amnezia_awg_GoBackend_awgVersion(JNIEnv *env, jclass c)
{
jstring ret;
char *version = wgVersion();
char *version = awgVersion();
if (!version)
return NULL;
ret = (*env)->NewStringUTF(env, version);
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
*
*/
+1 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD
*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
*
*/
+5 -7
View File
@@ -3,7 +3,7 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val pkg: String = providers.gradleProperty("wireguardPackageName").get()
val pkg: String = providers.gradleProperty("amneziawgPackageName").get()
plugins {
alias(libs.plugins.android.application)
@@ -12,7 +12,6 @@ plugins {
}
android {
compileSdk = 36
buildFeatures {
buildConfig = true
dataBinding = true
@@ -21,10 +20,9 @@ android {
namespace = pkg
defaultConfig {
applicationId = pkg
minSdk = 24
targetSdk = 36
versionCode = providers.gradleProperty("wireguardVersionCode").get().toInt()
versionName = providers.gradleProperty("wireguardVersionName").get()
targetSdk = 35
versionCode = providers.gradleProperty("amneziawgVersionCode").get().toInt()
versionName = providers.gradleProperty("amneziawgVersionName").get()
buildConfigField("int", "MIN_SDK_VERSION", minSdk.toString())
}
compileOptions {
@@ -89,5 +87,5 @@ tasks.withType<JavaCompile>().configureEach {
}
tasks.withType<KotlinCompile>().configureEach {
compilerOptions.jvmTarget = JvmTarget.JVM_17
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
}
+12 -12
View File
@@ -3,18 +3,18 @@
"names": [
{
"names": [
{ "name": "wg0" },
{ "name": "wg1" },
{ "name": "wg2" },
{ "name": "wg3" },
{ "name": "wg4" },
{ "name": "wg5" },
{ "name": "wg6" },
{ "name": "wg7" },
{ "name": "wg8" },
{ "name": "wg9" },
{ "name": "wg10" },
{ "name": "wg11" }
{ "name": "awg0" },
{ "name": "awg1" },
{ "name": "awg2" },
{ "name": "awg3" },
{ "name": "awg4" },
{ "name": "awg5" },
{ "name": "awg6" },
{ "name": "awg7" },
{ "name": "awg8" },
{ "name": "awg9" },
{ "name": "awg10" },
{ "name": "awg11" }
],
"checked": [
{ "checked": true },
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">WireGuard β</string>
<string name="app_name" translatable="false">AmneziaWG β</string>
</resources>
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.REQUEST_INSTALL_PACKAGES"
tools:node="remove" />
</manifest>
+4 -16
View File
@@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
~ SPDX-License-Identifier: Apache-2.0
-->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
@@ -9,7 +6,6 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission
android:name="android.permission.SYSTEM_ALERT_WINDOW"
android:minSdkVersion="34" />
@@ -117,22 +113,14 @@
</intent-filter>
</receiver>
<receiver
android:name=".updater.Updater$AppUpdatedReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<receiver
android:name=".model.TunnelManager$IntentReceiver"
android:exported="true"
android:permission="${applicationId}.permission.CONTROL_TUNNELS">
<intent-filter>
<action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" />
<action android:name="com.wireguard.android.action.SET_TUNNEL_UP" />
<action android:name="com.wireguard.android.action.SET_TUNNEL_DOWN" />
<action android:name="org.amnezia.awg.action.REFRESH_TUNNEL_STATES" />
<action android:name="org.amnezia.awg.action.SET_TUNNEL_UP" />
<action android:name="org.amnezia.awg.action.SET_TUNNEL_DOWN" />
</intent-filter>
</receiver>
@@ -1,24 +0,0 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
import android.os.Bundle
import com.wireguard.android.R
import com.wireguard.android.model.ObservableTunnel
/**
* Standalone activity for creating tunnels.
*/
class TunnelCreatorActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.tunnel_creator_activity)
}
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?): Boolean {
finish()
return true
}
}
@@ -1,43 +0,0 @@
/*
* Copyright © 2017-2025 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.net.Uri
import android.util.AttributeSet
import android.widget.Toast
import androidx.preference.Preference
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.wireguard.android.R
import com.wireguard.android.updater.Updater
import com.wireguard.android.util.ErrorMessages
import androidx.core.net.toUri
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() {
/* Google Play Store forbids links to our donation page. */
if (Updater.installerIsGooglePlay(context)) {
MaterialAlertDialogBuilder(context)
.setTitle(R.string.donate_title)
.setMessage(R.string.donate_google_play_disappointment)
.show()
return
}
val intent = Intent(Intent.ACTION_VIEW)
intent.data = "https://www.wireguard.com/donations/".toUri()
try {
context.startActivity(intent)
} catch (e: Throwable) {
Toast.makeText(context, ErrorMessages[e], Toast.LENGTH_SHORT).show()
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,173 +0,0 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.updater
import android.content.Intent
import android.net.Uri
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import com.wireguard.android.R
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.QuantityFormatter
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.seconds
class SnackbarUpdateShower(private val fragment: Fragment) {
private var lastUserIntervention: Updater.Progress.NeedsUserIntervention? = null
private val intentLauncher = fragment.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
lastUserIntervention?.markAsDone()
}
private class SwapableSnackbar(fragment: Fragment, view: View, anchor: View?) {
private val actionSnackbar = makeSnackbar(fragment, view, anchor)
private val statusSnackbar = makeSnackbar(fragment, view, anchor)
private var showingAction: Boolean = false
private var showingStatus: Boolean = false
private fun makeSnackbar(fragment: Fragment, view: View, anchor: View?): Snackbar {
val snackbar = Snackbar.make(fragment.requireContext(), view, "", Snackbar.LENGTH_INDEFINITE)
if (anchor != null)
snackbar.anchorView = anchor
snackbar.setTextMaxLines(6)
snackbar.behavior = object : BaseTransientBottomBar.Behavior() {
override fun canSwipeDismissView(child: View): Boolean {
return false
}
}
snackbar.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
override fun onDismissed(snackbar: Snackbar?, @DismissEvent event: Int) {
super.onDismissed(snackbar, event)
if (event == DISMISS_EVENT_MANUAL || event == DISMISS_EVENT_ACTION ||
(snackbar == actionSnackbar && !showingAction) || (snackbar == statusSnackbar && !showingStatus)
)
return
fragment.lifecycleScope.launch {
delay(5.seconds)
snackbar?.show()
}
}
})
return snackbar
}
fun showAction(text: String, action: String, listener: View.OnClickListener) {
if (showingStatus) {
showingStatus = false
statusSnackbar.dismiss()
}
actionSnackbar.setText(text)
actionSnackbar.setAction(action, listener)
if (!showingAction) {
actionSnackbar.show()
showingAction = true
}
}
fun showText(text: String) {
if (showingAction) {
showingAction = false
actionSnackbar.dismiss()
}
statusSnackbar.setText(text)
if (!showingStatus) {
statusSnackbar.show()
showingStatus = true
}
}
fun dismiss() {
actionSnackbar.dismiss()
statusSnackbar.dismiss()
showingAction = false
showingStatus = false
}
}
fun attach(view: View, anchor: View?) {
val snackbar = SwapableSnackbar(fragment, view, anchor)
val context = fragment.requireContext()
Updater.state.onEach { progress ->
when (progress) {
is Updater.Progress.Complete ->
snackbar.dismiss()
is Updater.Progress.Available ->
snackbar.showAction(context.getString(R.string.updater_avalable), context.getString(R.string.updater_action)) {
progress.update()
}
is Updater.Progress.NeedsUserIntervention -> {
lastUserIntervention = progress
intentLauncher.launch(progress.intent)
}
is Updater.Progress.Installing ->
snackbar.showText(context.getString(R.string.updater_installing))
is Updater.Progress.Rechecking ->
snackbar.showText(context.getString(R.string.updater_rechecking))
is Updater.Progress.Downloading -> {
if (progress.bytesTotal != 0UL) {
snackbar.showText(
context.getString(
R.string.updater_download_progress,
QuantityFormatter.formatBytes(progress.bytesDownloaded.toLong()),
QuantityFormatter.formatBytes(progress.bytesTotal.toLong()),
progress.bytesDownloaded.toFloat() * 100.0 / progress.bytesTotal.toFloat()
)
)
} else {
snackbar.showText(
context.getString(
R.string.updater_download_progress_nototal,
QuantityFormatter.formatBytes(progress.bytesDownloaded.toLong())
)
)
}
}
is Updater.Progress.Failure -> {
snackbar.showText(context.getString(R.string.updater_failure, ErrorMessages[progress.error]))
delay(5.seconds)
progress.retry()
}
is Updater.Progress.Corrupt -> {
MaterialAlertDialogBuilder(context)
.setTitle(R.string.updater_corrupt_title)
.setMessage(R.string.updater_corrupt_message)
.setPositiveButton(R.string.updater_corrupt_navigate) { _, _ ->
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse(progress.downloadUrl)
try {
context.startActivity(intent)
} catch (e: Throwable) {
Toast.makeText(context, ErrorMessages[e], Toast.LENGTH_SHORT).show()
}
}.setCancelable(false).setOnDismissListener {
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_HOME)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
System.exit(0)
}.show()
}
}
}.launchIn(fragment.lifecycleScope)
}
}
@@ -1,460 +0,0 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.updater
import android.Manifest
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.os.Build
import android.util.Base64
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.core.content.IntentCompat
import com.wireguard.android.Application
import com.wireguard.android.BuildConfig
import com.wireguard.android.activity.MainActivity
import com.wireguard.android.util.UserKnobs
import com.wireguard.android.util.applicationScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import java.nio.charset.StandardCharsets
import java.security.InvalidKeyException
import java.security.InvalidParameterException
import java.security.MessageDigest
import java.util.UUID
import kotlin.math.max
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
object Updater {
private const val TAG = "WireGuard/Updater"
private const val UPDATE_URL_FMT = "https://download.wireguard.com/android-client/%s"
private const val APK_NAME_PREFIX = BuildConfig.APPLICATION_ID + "-"
private const val APK_NAME_SUFFIX = ".apk"
private const val LATEST_FILE = "latest.sig"
private const val RELEASE_PUBLIC_KEY_BASE64 = "RWTAzwGRYr3EC9px0Ia3fbttz8WcVN6wrOwWp2delz4el6SI8XmkKSMp"
private val CURRENT_VERSION by lazy { Version(BuildConfig.VERSION_NAME) }
private val updaterScope = CoroutineScope(Job() + Dispatchers.IO)
private fun installer(context: Context): String = try {
val packageName = context.packageName
val pm = context.packageManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
pm.getInstallSourceInfo(packageName).installingPackageName ?: ""
} else {
@Suppress("DEPRECATION")
pm.getInstallerPackageName(packageName) ?: ""
}
} catch (_: Throwable) {
""
}
fun installerIsGooglePlay(context: Context): Boolean = installer(context) == "com.android.vending"
sealed class Progress {
object Complete : Progress()
class Available(val version: String) : Progress() {
fun update() {
applicationScope.launch {
UserKnobs.setUpdaterNewerVersionConsented(version)
}
}
}
object Rechecking : Progress()
class Downloading(val bytesDownloaded: ULong, val bytesTotal: ULong) : Progress()
object Installing : Progress()
class NeedsUserIntervention(val intent: Intent, private val id: Int) : Progress() {
private suspend fun installerActive(): Boolean {
if (mutableState.firstOrNull() != this@NeedsUserIntervention)
return true
try {
if (Application.get().packageManager.packageInstaller.getSessionInfo(id)?.isActive == true)
return true
} catch (_: SecurityException) {
return true
}
return false
}
fun markAsDone() {
applicationScope.launch {
if (installerActive())
return@launch
delay(7.seconds)
if (installerActive())
return@launch
emitProgress(Failure(Exception("Ignored by user")))
}
}
}
class Failure(val error: Throwable) : Progress() {
fun retry() {
updaterScope.launch {
downloadAndUpdateWrapErrors()
}
}
}
class Corrupt(private val betterFile: String?) : Progress() {
val downloadUrl: String
get() = UPDATE_URL_FMT.format(betterFile ?: "")
}
}
private val mutableState = MutableStateFlow<Progress>(Progress.Complete)
val state = mutableState.asStateFlow()
private suspend fun emitProgress(progress: Progress, force: Boolean = false) {
if (force || mutableState.firstOrNull()?.javaClass != progress.javaClass)
mutableState.emit(progress)
}
private class Sha256Digest(hex: String) {
val bytes: ByteArray
init {
if (hex.length != 64)
throw InvalidParameterException("SHA256 hashes must be 32 bytes long")
bytes = hex.chunked(2).map { it.toInt(16).toByte() }.toByteArray()
}
}
@OptIn(ExperimentalUnsignedTypes::class)
private class Version(version: String) : Comparable<Version> {
val parts: ULongArray
init {
val strParts = version.split(".")
if (strParts.isEmpty())
throw InvalidParameterException("Version has no parts")
parts = ULongArray(strParts.size)
for (i in parts.indices) {
parts[i] = strParts[i].toULong()
}
}
override fun toString(): String {
return parts.joinToString(".")
}
override fun compareTo(other: Version): Int {
for (i in 0 until max(parts.size, other.parts.size)) {
val lhsPart = if (i < parts.size) parts[i] else 0UL
val rhsPart = if (i < other.parts.size) other.parts[i] else 0UL
if (lhsPart > rhsPart)
return 1
else if (lhsPart < rhsPart)
return -1
}
return 0
}
}
private class Update(val fileName: String, val version: Version, val hash: Sha256Digest)
private fun versionOfFile(name: String): Version? {
if (!name.startsWith(APK_NAME_PREFIX) || !name.endsWith(APK_NAME_SUFFIX))
return null
return try {
Version(name.substring(APK_NAME_PREFIX.length, name.length - APK_NAME_SUFFIX.length))
} catch (_: Throwable) {
null
}
}
private fun verifySignedFileList(signifyDigest: String): List<Update> {
val updates = ArrayList<Update>(1)
val publicKeyBytes = Base64.decode(RELEASE_PUBLIC_KEY_BASE64, Base64.DEFAULT)
if (publicKeyBytes == null || publicKeyBytes.size != 32 + 10 || publicKeyBytes[0] != 'E'.code.toByte() || publicKeyBytes[1] != 'd'.code.toByte())
throw InvalidKeyException("Invalid public key")
val lines = signifyDigest.split("\n", limit = 3)
if (lines.size != 3)
throw InvalidParameterException("Invalid signature format: too few lines")
if (!lines[0].startsWith("untrusted comment: "))
throw InvalidParameterException("Invalid signature format: missing comment")
val signatureBytes = Base64.decode(lines[1], Base64.DEFAULT)
if (signatureBytes == null || signatureBytes.size != 64 + 10)
throw InvalidParameterException("Invalid signature format: wrong sized or missing signature")
for (i in 0..9) {
if (signatureBytes[i] != publicKeyBytes[i])
throw InvalidParameterException("Invalid signature format: wrong signer")
}
if (!Ed25519.verify(
lines[2].toByteArray(StandardCharsets.UTF_8),
signatureBytes.sliceArray(10 until 10 + 64),
publicKeyBytes.sliceArray(10 until 10 + 32)
)
)
throw SecurityException("Invalid signature")
for (line in lines[2].split("\n").dropLastWhile { it.isEmpty() }) {
val components = line.split(" ", limit = 2)
if (components.size != 2)
throw InvalidParameterException("Invalid file list format: too few components")
/* If version is null, it's not a file we understand, but still a legitimate entry, so don't throw. */
val version = versionOfFile(components[1]) ?: continue
updates.add(Update(components[1], version, Sha256Digest(components[0])))
}
return updates
}
private fun checkForUpdates(): Update? {
val connection = URL(UPDATE_URL_FMT.format(LATEST_FILE)).openConnection() as HttpURLConnection
connection.setRequestProperty("User-Agent", Application.USER_AGENT)
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK)
throw IOException(connection.responseMessage)
var fileListBytes = ByteArray(1024 * 512 /* 512 KiB */)
connection.inputStream.use {
val len = it.read(fileListBytes)
if (len <= 0)
throw IOException("File list is empty")
fileListBytes = fileListBytes.sliceArray(0 until len)
}
return verifySignedFileList(fileListBytes.decodeToString()).maxByOrNull { it.version }
}
private suspend fun downloadAndUpdate() = withContext(Dispatchers.IO) {
val receiver = InstallReceiver()
val context = Application.get().applicationContext
val pendingIntent = withContext(Dispatchers.Main) {
ContextCompat.registerReceiver(context, receiver, IntentFilter(receiver.sessionId), ContextCompat.RECEIVER_NOT_EXPORTED)
PendingIntent.getBroadcast(
context,
0,
Intent(receiver.sessionId).setPackage(context.packageName),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
)
}
emitProgress(Progress.Rechecking)
val update = checkForUpdates()
if (update == null || update.version <= CURRENT_VERSION) {
emitProgress(Progress.Complete)
return@withContext
}
emitProgress(Progress.Downloading(0UL, 0UL), true)
val connection = URL(UPDATE_URL_FMT.format(update.fileName)).openConnection() as HttpURLConnection
connection.setRequestProperty("User-Agent", Application.USER_AGENT)
connection.connect()
if (connection.responseCode != HttpURLConnection.HTTP_OK)
throw IOException("Update could not be fetched: ${connection.responseCode}")
var downloadedByteLen: ULong = 0UL
val totalByteLen = connection.contentLengthLong.toULong()
val fileBytes = ByteArray(1024 * 32 /* 32 KiB */)
val digest = MessageDigest.getInstance("SHA-256")
emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true)
val installer = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)
params.setAppPackageName(context.packageName) /* Enforces updates; disallows new apps. */
val session = installer.openSession(installer.createSession(params))
var sessionFailure = true
try {
val installDest = session.openWrite(receiver.sessionId, 0, -1)
installDest.use { dest ->
connection.inputStream.use { src ->
while (true) {
val readLen = src.read(fileBytes)
if (readLen <= 0)
break
digest.update(fileBytes, 0, readLen)
dest.write(fileBytes, 0, readLen)
downloadedByteLen += readLen.toUInt()
emitProgress(Progress.Downloading(downloadedByteLen, totalByteLen), true)
if (downloadedByteLen >= 1024UL * 1024UL * 100UL /* 100 MiB */)
throw IOException("File too large")
}
}
}
emitProgress(Progress.Installing)
if (!digest.digest().contentEquals(update.hash.bytes))
throw SecurityException("Update has invalid hash")
sessionFailure = false
} finally {
if (sessionFailure) {
session.abandon()
session.close()
}
}
session.commit(pendingIntent.intentSender)
session.close()
}
private var updating = false
private suspend fun downloadAndUpdateWrapErrors() {
if (updating)
return
updating = true
try {
downloadAndUpdate()
} catch (e: Throwable) {
Log.e(TAG, "Update failure", e)
emitProgress(Progress.Failure(e))
}
updating = false
}
private class InstallReceiver : BroadcastReceiver() {
val sessionId = UUID.randomUUID().toString()
override fun onReceive(context: Context, intent: Intent) {
if (sessionId != intent.action)
return
when (val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE_INVALID)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val id = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, 0)
val userIntervention = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent::class.java)!!
applicationScope.launch {
emitProgress(Progress.NeedsUserIntervention(userIntervention, id))
}
}
PackageInstaller.STATUS_SUCCESS -> {
applicationScope.launch {
emitProgress(Progress.Complete)
}
context.applicationContext.unregisterReceiver(this)
}
else -> {
val id = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, 0)
try {
context.applicationContext.packageManager.packageInstaller.abandonSession(id)
} catch (_: SecurityException) {
}
val message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) ?: "Installation error $status"
applicationScope.launch {
val e = Exception(message)
Log.e(TAG, "Update failure", e)
emitProgress(Progress.Failure(e))
}
context.applicationContext.unregisterReceiver(this)
}
}
}
}
fun monitorForUpdates() {
if (BuildConfig.DEBUG)
return
val context = Application.get()
if (installerIsGooglePlay(context))
return
if (BuildConfig.BUILD_TYPE == "googleplay") {
if (installer(context).isNotEmpty()) {
applicationScope.launch {
emitProgress(Progress.Corrupt(null))
}
}
return
}
if (if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
} else {
context.packageManager.getPackageInfo(context.packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
}.requestedPermissions?.contains(Manifest.permission.REQUEST_INSTALL_PACKAGES) != true
) {
if (installer(context).isNotEmpty()) {
updaterScope.launch {
val update = try {
checkForUpdates()
} catch (_: Throwable) {
null
}
emitProgress(Progress.Corrupt(update?.fileName))
}
}
return
}
updaterScope.launch {
if (UserKnobs.updaterNewerVersionSeen.firstOrNull()?.let { Version(it) > CURRENT_VERSION } == true)
return@launch
var waitTime = 15
while (true) {
try {
val update = checkForUpdates() ?: continue
if (update.version > CURRENT_VERSION) {
Log.i(TAG, "Update available: ${update.version}")
UserKnobs.setUpdaterNewerVersionSeen(update.version.toString())
return@launch
}
} catch (_: Throwable) {
}
delay(waitTime.minutes)
waitTime = 45
}
}
UserKnobs.updaterNewerVersionSeen.onEach { ver ->
if (
ver != null &&
Version(ver) > CURRENT_VERSION &&
UserKnobs.updaterNewerVersionConsented.firstOrNull()?.let { Version(it) > CURRENT_VERSION } != true
)
emitProgress(Progress.Available(ver))
}.launchIn(applicationScope)
UserKnobs.updaterNewerVersionConsented.onEach { ver ->
if (ver != null && Version(ver) > CURRENT_VERSION)
updaterScope.launch {
downloadAndUpdateWrapErrors()
}
}.launchIn(applicationScope)
}
class AppUpdatedReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_MY_PACKAGE_REPLACED)
return
if (installer(context) != context.packageName)
return
/* TODO: does not work because of restrictions placed on broadcast receivers. */
val start = Intent(context, MainActivity::class.java)
start.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
start.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(start)
}
}
}
@@ -1,142 +0,0 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.viewmodel
import android.os.Parcel
import android.os.Parcelable
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import androidx.databinding.ObservableArrayList
import androidx.databinding.ObservableList
import com.wireguard.android.BR
import com.wireguard.config.Attribute
import com.wireguard.config.BadConfigException
import com.wireguard.config.Interface
import com.wireguard.crypto.Key
import com.wireguard.crypto.KeyFormatException
import com.wireguard.crypto.KeyPair
class InterfaceProxy : BaseObservable, Parcelable {
@get:Bindable
val excludedApplications: ObservableList<String> = ObservableArrayList()
@get:Bindable
val includedApplications: ObservableList<String> = ObservableArrayList()
@get:Bindable
var addresses: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.addresses)
}
@get:Bindable
var dnsServers: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.dnsServers)
}
@get:Bindable
var listenPort: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.listenPort)
}
@get:Bindable
var mtu: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.mtu)
}
@get:Bindable
var privateKey: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.privateKey)
notifyPropertyChanged(BR.publicKey)
}
@get:Bindable
val publicKey: String
get() = try {
KeyPair(Key.fromBase64(privateKey)).publicKey.toBase64()
} catch (ignored: KeyFormatException) {
""
}
private constructor(parcel: Parcel) {
addresses = parcel.readString() ?: ""
dnsServers = parcel.readString() ?: ""
parcel.readStringList(excludedApplications)
parcel.readStringList(includedApplications)
listenPort = parcel.readString() ?: ""
mtu = parcel.readString() ?: ""
privateKey = parcel.readString() ?: ""
}
constructor(other: Interface) {
addresses = Attribute.join(other.addresses)
val dnsServerStrings = other.dnsServers.map { it.hostAddress }.plus(other.dnsSearchDomains)
dnsServers = Attribute.join(dnsServerStrings)
excludedApplications.addAll(other.excludedApplications)
includedApplications.addAll(other.includedApplications)
listenPort = other.listenPort.map { it.toString() }.orElse("")
mtu = other.mtu.map { it.toString() }.orElse("")
val keyPair = other.keyPair
privateKey = keyPair.privateKey.toBase64()
}
constructor()
override fun describeContents() = 0
fun generateKeyPair() {
val keyPair = KeyPair()
privateKey = keyPair.privateKey.toBase64()
notifyPropertyChanged(BR.privateKey)
notifyPropertyChanged(BR.publicKey)
}
@Throws(BadConfigException::class)
fun resolve(): Interface {
val builder = Interface.Builder()
if (addresses.isNotEmpty()) builder.parseAddresses(addresses)
if (dnsServers.isNotEmpty()) builder.parseDnsServers(dnsServers)
if (excludedApplications.isNotEmpty()) builder.excludeApplications(excludedApplications)
if (includedApplications.isNotEmpty()) builder.includeApplications(includedApplications)
if (listenPort.isNotEmpty()) builder.parseListenPort(listenPort)
if (mtu.isNotEmpty()) builder.parseMtu(mtu)
if (privateKey.isNotEmpty()) builder.parsePrivateKey(privateKey)
return builder.build()
}
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeString(addresses)
dest.writeString(dnsServers)
dest.writeStringList(excludedApplications)
dest.writeStringList(includedApplications)
dest.writeString(listenPort)
dest.writeString(mtu)
dest.writeString(privateKey)
}
private class InterfaceProxyCreator : Parcelable.Creator<InterfaceProxy> {
override fun createFromParcel(parcel: Parcel): InterfaceProxy {
return InterfaceProxy(parcel)
}
override fun newArray(size: Int): Array<InterfaceProxy?> {
return arrayOfNulls(size)
}
}
companion object {
@JvmField
val CREATOR: Parcelable.Creator<InterfaceProxy> = InterfaceProxyCreator()
}
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
package org.amnezia.awg
import android.content.Context
import android.content.Intent
@@ -17,16 +17,15 @@ 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.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.updater.Updater
import com.wireguard.android.util.RootShell
import com.wireguard.android.util.ToolsInstaller
import com.wireguard.android.util.UserKnobs
import com.wireguard.android.util.applicationScope
import org.amnezia.awg.backend.Backend
import org.amnezia.awg.backend.GoBackend
import org.amnezia.awg.backend.AwgQuickBackend
import org.amnezia.awg.configStore.FileConfigStore
import org.amnezia.awg.model.TunnelManager
import org.amnezia.awg.util.RootShell
import org.amnezia.awg.util.ToolsInstaller
import org.amnezia.awg.util.UserKnobs
import org.amnezia.awg.util.applicationScope
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -63,14 +62,14 @@ class Application : android.app.Application() {
private suspend fun determineBackend(): Backend {
var backend: Backend? = null
if (UserKnobs.enableKernelModule.first() && WgQuickBackend.hasKernelSupport()) {
if (UserKnobs.enableKernelModule.first() && AwgQuickBackend.hasKernelSupport()) {
try {
rootShell.start()
val wgQuickBackend = WgQuickBackend(applicationContext, rootShell, toolsInstaller)
wgQuickBackend.setMultipleTunnels(UserKnobs.multipleTunnels.first())
backend = wgQuickBackend
val awgQuickBackend = AwgQuickBackend(applicationContext, rootShell, toolsInstaller)
awgQuickBackend.setMultipleTunnels(UserKnobs.multipleTunnels.first())
backend = awgQuickBackend
UserKnobs.multipleTunnels.onEach {
wgQuickBackend.setMultipleTunnels(it)
awgQuickBackend.setMultipleTunnels(it)
}.launchIn(coroutineScope)
} catch (ignored: Exception) {
}
@@ -116,7 +115,6 @@ class Application : android.app.Application() {
Log.e(TAG, Log.getStackTraceString(e))
}
}
Updater.monitorForUpdates()
if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(VmPolicy.Builder().detectAll().penaltyLog().build())
@@ -130,8 +128,8 @@ class Application : android.app.Application() {
}
companion object {
val USER_AGENT = String.format(Locale.ENGLISH, "WireGuard/%s (Android %d; %s; %s; %s %s; %s)", BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT, if (Build.SUPPORTED_ABIS.isNotEmpty()) Build.SUPPORTED_ABIS[0] else "unknown ABI", Build.BOARD, Build.MANUFACTURER, Build.MODEL, Build.FINGERPRINT)
private const val TAG = "WireGuard/Application"
val USER_AGENT = String.format(Locale.ENGLISH, "AmneziaWG/%s (Android %d; %s; %s; %s %s; %s)", BuildConfig.VERSION_NAME, Build.VERSION.SDK_INT, if (Build.SUPPORTED_ABIS.isNotEmpty()) Build.SUPPORTED_ABIS[0] else "unknown ABI", Build.BOARD, Build.MANUFACTURER, Build.MODEL, Build.FINGERPRINT)
private const val TAG = "AmneziaWG/Application"
private lateinit var weakSelf: WeakReference<Application>
fun get(): Application {
@@ -1,22 +1,22 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
package org.amnezia.awg
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.util.applicationScope
import org.amnezia.awg.backend.AwgQuickBackend
import org.amnezia.awg.util.applicationScope
import kotlinx.coroutines.launch
class BootShutdownReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action ?: return
applicationScope.launch {
if (Application.getBackend() !is WgQuickBackend) return@launch
if (Application.getBackend() !is AwgQuickBackend) return@launch
val tunnelManager = Application.getTunnelManager()
if (Intent.ACTION_BOOT_COMPLETED == action) {
Log.i(TAG, "Broadcast receiver restoring state (boot)")
@@ -29,6 +29,6 @@ class BootShutdownReceiver : BroadcastReceiver() {
}
companion object {
private const val TAG = "WireGuard/BootShutdownReceiver"
private const val TAG = "AmneziaWG/BootShutdownReceiver"
}
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android
package org.amnezia.awg
import android.app.PendingIntent
import android.content.Intent
@@ -19,12 +19,12 @@ import android.util.Log
import androidx.annotation.RequiresApi
import androidx.databinding.Observable
import androidx.databinding.Observable.OnPropertyChangedCallback
import com.wireguard.android.activity.MainActivity
import com.wireguard.android.activity.TunnelToggleActivity
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.applicationScope
import com.wireguard.android.widget.SlashDrawable
import org.amnezia.awg.activity.MainActivity
import org.amnezia.awg.activity.TunnelToggleActivity
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.model.ObservableTunnel
import org.amnezia.awg.util.applicationScope
import org.amnezia.awg.widget.SlashDrawable
import kotlinx.coroutines.launch
/**
@@ -32,6 +32,7 @@ import kotlinx.coroutines.launch
* system framework as necessary to update the appearance of the tile in the system UI, and to
* forward click events to the application.
*/
@RequiresApi(Build.VERSION_CODES.N)
class QuickTileService : TileService() {
private val onStateChangedCallback = OnStateChangedCallback()
private val onTunnelChangedCallback = OnTunnelChangedCallback()
@@ -51,50 +52,33 @@ class QuickTileService : TileService() {
}
override fun onClick() {
applicationScope.launch {
if (tunnel == null) {
Application.getTunnelManager().getTunnels()
updateTile()
}
when (val tunnel = tunnel) {
null -> {
Log.d(TAG, "No tunnel set, so launching main activity")
val intent = Intent(this@QuickTileService, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startActivityAndCollapse(PendingIntent.getActivity(this@QuickTileService, 0, intent, PendingIntent.FLAG_IMMUTABLE))
} else {
@Suppress("DEPRECATION")
startActivityAndCollapse(intent)
}
when (val tunnel = tunnel) {
null -> {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startActivityAndCollapse(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE))
} else {
@Suppress("DEPRECATION")
startActivityAndCollapse(intent)
}
else -> {
unlockAndRun {
applicationScope.launch {
try {
tunnel.setStateAsync(Tunnel.State.TOGGLE)
updateTile()
} catch (e: Throwable) {
Log.d(TAG, "Failed to set state, so falling back", e)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !Settings.canDrawOverlays(this@QuickTileService)) {
Log.d(TAG, "Need overlay permissions")
val permissionIntent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName"))
permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivityAndCollapse(
PendingIntent.getActivity(
this@QuickTileService,
0,
permissionIntent,
PendingIntent.FLAG_IMMUTABLE
)
)
return@launch
}
val toggleIntent = Intent(this@QuickTileService, TunnelToggleActivity::class.java)
toggleIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(toggleIntent)
}
else -> {
unlockAndRun {
applicationScope.launch {
try {
tunnel.setStateAsync(Tunnel.State.TOGGLE)
updateTile()
} catch (_: Throwable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && !Settings.canDrawOverlays(this@QuickTileService)) {
val permissionIntent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName"))
permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivityAndCollapse(PendingIntent.getActivity(this@QuickTileService, 0, permissionIntent, PendingIntent.FLAG_IMMUTABLE))
return@launch
}
val toggleIntent = Intent(this@QuickTileService, TunnelToggleActivity::class.java)
toggleIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(toggleIntent)
}
}
}
@@ -196,7 +180,7 @@ class QuickTileService : TileService() {
}
companion object {
private const val TAG = "WireGuard/QuickTileService"
private const val TAG = "AmneziaWG/QuickTileService"
var isAdded: Boolean = false
private set
}
@@ -1,16 +1,16 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
package org.amnezia.awg.activity
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.CallbackRegistry
import androidx.databinding.CallbackRegistry.NotifierCallback
import androidx.lifecycle.lifecycleScope
import com.wireguard.android.Application
import com.wireguard.android.model.ObservableTunnel
import org.amnezia.awg.Application
import org.amnezia.awg.model.ObservableTunnel
import kotlinx.coroutines.launch
/**
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
package org.amnezia.awg.activity
import android.content.ClipDescription.compareMimeTypes
import android.content.ContentProvider
@@ -36,13 +36,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textview.MaterialTextView
import com.wireguard.android.BuildConfig
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 org.amnezia.awg.BuildConfig
import org.amnezia.awg.R
import org.amnezia.awg.databinding.LogViewerActivityBinding
import org.amnezia.awg.util.DownloadsFileSaver
import org.amnezia.awg.util.ErrorMessages
import org.amnezia.awg.util.resolveAttribute
import org.amnezia.awg.crypto.KeyPair
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -171,7 +171,7 @@ class LogViewerActivity : AppCompatActivity() {
var outputFile: DownloadsFileSaver.DownloadsFile? = null
withContext(Dispatchers.IO) {
try {
outputFile = downloadsFileSaver.save("wireguard-log.txt", "text/plain", true)
outputFile = downloadsFileSaver.save("amneziawg-log.txt", "text/plain", true)
outputFile?.outputStream?.write(rawLogBytes())
} catch (e: Throwable) {
outputFile?.delete()
@@ -183,7 +183,7 @@ class LogViewerActivity : AppCompatActivity() {
return
Snackbar.make(
findViewById(android.R.id.content),
if (exception == null) getString(R.string.log_export_success, outputFile.fileName)
if (exception == null) getString(R.string.log_export_success, outputFile?.fileName)
else getString(R.string.log_export_error, ErrorMessages[exception]),
if (exception == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG
)
@@ -294,7 +294,7 @@ class LogViewerActivity : AppCompatActivity() {
private val THREADTIME_LINE: Pattern =
Pattern.compile("^(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d{3})(?:\\s+[0-9A-Za-z]+)?\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s+(.+?)\\s*: (.*)$")
private val LOGS: MutableMap<String, ByteArray> = ConcurrentHashMap()
private const val TAG = "WireGuard/LogViewerActivity"
private const val TAG = "AmneziaWG/LogViewerActivity"
}
private inner class LogEntryAdapter : RecyclerView.Adapter<LogEntryAdapter.ViewHolder>() {
@@ -353,7 +353,7 @@ class LogViewerActivity : AppCompatActivity() {
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? =
logForUri(uri)?.let {
val m = MatrixCursor(arrayOf(android.provider.OpenableColumns.DISPLAY_NAME, android.provider.OpenableColumns.SIZE), 1)
m.addRow(arrayOf<Any>("wireguard-log.txt", it.size.toLong()))
m.addRow(arrayOf("amneziawg-log.txt", it.size.toLong()))
m
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
package org.amnezia.awg.activity
import android.content.Intent
import android.os.Bundle
@@ -15,15 +15,15 @@ import androidx.appcompat.app.ActionBar
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.commit
import com.wireguard.android.R
import com.wireguard.android.fragment.TunnelDetailFragment
import com.wireguard.android.fragment.TunnelEditorFragment
import com.wireguard.android.model.ObservableTunnel
import org.amnezia.awg.R
import org.amnezia.awg.fragment.TunnelDetailFragment
import org.amnezia.awg.fragment.TunnelEditorFragment
import org.amnezia.awg.model.ObservableTunnel
/**
* CRUD interface for WireGuard tunnels. This activity serves as the main entry point to the
* WireGuard application, and contains several fragments for listing, viewing details of, and
* editing the configuration and interface state of WireGuard tunnels.
* CRUD interface for AmneziaWG tunnels. This activity serves as the main entry point to the
* AmneziaWG application, and contains several fragments for listing, viewing details of, and
* editing the configuration and interface state of AmneziaWG tunnels.
*/
class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener {
private var actionBar: ActionBar? = null
@@ -80,7 +80,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
R.id.menu_action_edit -> {
supportFragmentManager.commit {
replace(if (isTwoPaneLayout) R.id.detail_container else R.id.list_detail_container, TunnelEditorFragment())
replace(R.id.detail_container, TunnelEditorFragment())
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
addToBackStack(null)
}
@@ -119,7 +119,7 @@ class MainActivity : BaseActivity(), FragmentManager.OnBackStackChangedListener
} else if (backStackEntries == 0) {
// Create and show a new detail fragment.
fragmentManager.commit {
add(if (isTwoPaneLayout) R.id.detail_container else R.id.list_detail_container, TunnelDetailFragment())
add(R.id.detail_container, TunnelDetailFragment())
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
addToBackStack(null)
}
@@ -1,27 +1,24 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
package org.amnezia.awg.activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.wireguard.android.Application
import com.wireguard.android.QuickTileService
import com.wireguard.android.R
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.preference.PreferencesPreferenceDataStore
import com.wireguard.android.util.AdminKnobs
import org.amnezia.awg.Application
import org.amnezia.awg.QuickTileService
import org.amnezia.awg.R
import org.amnezia.awg.backend.AwgQuickBackend
import org.amnezia.awg.preference.PreferencesPreferenceDataStore
import org.amnezia.awg.util.AdminKnobs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -48,15 +45,6 @@ class SettingsActivity : AppCompatActivity() {
}
class SettingsFragment : PreferenceFragmentCompat() {
// Since this is pretty much abandoned by androidx, it never got updated for proper EdgeToEdge support,
// which is enabled everywhere for API 35. So handle the insets manually here.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = super.onCreateView(inflater, container, savedInstanceState)
view.fitsSystemWindows = true
return view
}
override fun onCreatePreferences(savedInstanceState: Bundle?, key: String?) {
preferenceManager.preferenceDataStore = PreferencesPreferenceDataStore(lifecycleScope, Application.getPreferencesDataStore())
addPreferencesFromResource(R.xml.preferences)
@@ -76,18 +64,18 @@ class SettingsActivity : AppCompatActivity() {
val zipExporter = preferenceManager.findPreference<Preference>("zip_exporter")
zipExporter?.parent?.removePreference(zipExporter)
}
val wgQuickOnlyPrefs = arrayOf(
val awgQuickOnlyPrefs = arrayOf(
preferenceManager.findPreference("tools_installer"),
preferenceManager.findPreference("restore_on_boot"),
preferenceManager.findPreference<Preference>("multiple_tunnels")
).filterNotNull()
wgQuickOnlyPrefs.forEach { it.isVisible = false }
awgQuickOnlyPrefs.forEach { it.isVisible = false }
lifecycleScope.launch {
if (Application.getBackend() is WgQuickBackend) {
if (Application.getBackend() is AwgQuickBackend) {
++preferenceScreen.initialExpandedChildrenCount
wgQuickOnlyPrefs.forEach { it.isVisible = true }
awgQuickOnlyPrefs.forEach { it.isVisible = true }
} else {
wgQuickOnlyPrefs.forEach { it.parent?.removePreference(it) }
awgQuickOnlyPrefs.forEach { it.parent?.removePreference(it) }
}
}
preferenceManager.findPreference<Preference>("log_viewer")?.setOnPreferenceClickListener {
@@ -95,9 +83,9 @@ class SettingsActivity : AppCompatActivity() {
true
}
val kernelModuleEnabler = preferenceManager.findPreference<Preference>("kernel_module_enabler")
if (WgQuickBackend.hasKernelSupport()) {
if (AwgQuickBackend.hasKernelSupport()) {
lifecycleScope.launch {
if (Application.getBackend() !is WgQuickBackend) {
if (Application.getBackend() !is AwgQuickBackend) {
try {
withContext(Dispatchers.IO) { Application.getRootShell().start() }
} catch (_: Throwable) {
@@ -0,0 +1,29 @@
/*
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package org.amnezia.awg.activity
import android.os.Bundle
import androidx.fragment.app.commit
import org.amnezia.awg.fragment.TunnelEditorFragment
import org.amnezia.awg.model.ObservableTunnel
/**
* Standalone activity for creating tunnels.
*/
class TunnelCreatorActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (supportFragmentManager.findFragmentById(android.R.id.content) == null) {
supportFragmentManager.commit {
add(android.R.id.content, TunnelEditorFragment())
}
}
}
override fun onSelectedTunnelChanged(oldTunnel: ObservableTunnel?, newTunnel: ObservableTunnel?): Boolean {
finish()
return true
}
}
@@ -1,25 +1,23 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
package org.amnezia.awg.activity
import android.content.ComponentName
import android.os.Build
import android.os.Bundle
import android.service.quicksettings.TileService
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.wireguard.android.Application
import com.wireguard.android.QuickTileService
import com.wireguard.android.R
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.util.ErrorMessages
import org.amnezia.awg.Application
import org.amnezia.awg.QuickTileService
import org.amnezia.awg.R
import org.amnezia.awg.backend.GoBackend
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.util.ErrorMessages
import kotlinx.coroutines.launch
class TunnelToggleActivity : AppCompatActivity() {
@@ -49,14 +47,10 @@ class TunnelToggleActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
if (Application.getBackend() is GoBackend) {
try {
val intent = GoBackend.VpnService.prepare(this@TunnelToggleActivity)
if (intent != null) {
permissionActivityResultLauncher.launch(intent)
return@launch
}
} catch (e: Exception) {
Toast.makeText(this@TunnelToggleActivity, ErrorMessages[e], Toast.LENGTH_LONG).show()
val intent = GoBackend.VpnService.prepare(this@TunnelToggleActivity)
if (intent != null) {
permissionActivityResultLauncher.launch(intent)
return@launch
}
}
toggleTunnelWithPermissionsResult()
@@ -64,6 +58,6 @@ class TunnelToggleActivity : AppCompatActivity() {
}
companion object {
private const val TAG = "WireGuard/TunnelToggleActivity"
private const val TAG = "AmneziaWG/TunnelToggleActivity"
}
}
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.activity
package org.amnezia.awg.activity
import android.Manifest
import android.content.ActivityNotFoundException
@@ -34,22 +34,22 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.databinding.Keyed
import com.wireguard.android.databinding.ObservableKeyedArrayList
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter
import com.wireguard.android.databinding.TvActivityBinding
import com.wireguard.android.databinding.TvFileListItemBinding
import com.wireguard.android.databinding.TvTunnelListItemBinding
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.QuantityFormatter
import com.wireguard.android.util.TunnelImporter
import com.wireguard.android.util.UserKnobs
import com.wireguard.android.util.applicationScope
import org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.backend.GoBackend
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.databinding.Keyed
import org.amnezia.awg.databinding.ObservableKeyedArrayList
import org.amnezia.awg.databinding.ObservableKeyedRecyclerViewAdapter
import org.amnezia.awg.databinding.TvActivityBinding
import org.amnezia.awg.databinding.TvFileListItemBinding
import org.amnezia.awg.databinding.TvTunnelListItemBinding
import org.amnezia.awg.model.ObservableTunnel
import org.amnezia.awg.util.ErrorMessages
import org.amnezia.awg.util.QuantityFormatter
import org.amnezia.awg.util.TunnelImporter
import org.amnezia.awg.util.UserKnobs
import org.amnezia.awg.util.applicationScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -57,8 +57,8 @@ import kotlinx.coroutines.withContext
import java.io.File
class TvMainActivity : AppCompatActivity() {
private val tunnelFileImportResultLauncher = registerForActivityResult(object : ActivityResultContracts.OpenDocument() {
override fun createIntent(context: Context, input: Array<String>): Intent {
private val tunnelFileImportResultLauncher = registerForActivityResult(object : ActivityResultContracts.GetContent() {
override fun createIntent(context: Context, input: String): Intent {
val intent = super.createIntent(context, input)
/* AndroidTV now comes with stubs that do nothing but display a Toast less helpful than
@@ -209,15 +209,12 @@ class TvMainActivity : AppCompatActivity() {
}
} else {
try {
tunnelFileImportResultLauncher.launch(arrayOf("*/*"))
tunnelFileImportResultLauncher.launch("*/*")
} catch (_: Throwable) {
MaterialAlertDialogBuilder(binding.root.context).setMessage(R.string.tv_no_file_picker).setCancelable(false)
.setPositiveButton(android.R.string.ok) { _, _ ->
try {
startActivity(Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.cxinventor.file.explorer")
setPackage("com.android.vending")
})
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://webstoreredirect")))
} catch (_: Throwable) {
}
}.show()
@@ -426,6 +423,6 @@ class TvMainActivity : AppCompatActivity() {
}
companion object {
private const val TAG = "WireGuard/TvMainActivity"
private const val TAG = "AmneziaWG/TvMainActivity"
}
}
@@ -1,13 +1,13 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.configStore
package org.amnezia.awg.configStore
import com.wireguard.config.Config
import org.amnezia.awg.config.Config
/**
* Interface for persistent storage providers for WireGuard configurations.
* Interface for persistent storage providers for AmneziaWG configurations.
*/
interface ConfigStore {
/**
@@ -1,14 +1,14 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.configStore
package org.amnezia.awg.configStore
import android.content.Context
import android.util.Log
import com.wireguard.android.R
import com.wireguard.config.BadConfigException
import com.wireguard.config.Config
import org.amnezia.awg.R
import org.amnezia.awg.config.BadConfigException
import org.amnezia.awg.config.Config
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException
@@ -17,7 +17,7 @@ import java.io.IOException
import java.nio.charset.StandardCharsets
/**
* Configuration store that uses a `wg-quick`-style file for each configured tunnel.
* Configuration store that uses a `awg-quick`-style file for each configured tunnel.
*/
class FileConfigStore(private val context: Context) : ConfigStore {
@Throws(IOException::class)
@@ -26,7 +26,7 @@ class FileConfigStore(private val context: Context) : ConfigStore {
val file = fileFor(name)
if (!file.createNewFile())
throw IOException(context.getString(R.string.config_file_exists_error, file.name))
FileOutputStream(file, false).use { it.write(config.toWgQuickString().toByteArray(StandardCharsets.UTF_8)) }
FileOutputStream(file, false).use { it.write(config.toAwgQuickString().toByteArray(StandardCharsets.UTF_8)) }
return config
}
@@ -72,11 +72,11 @@ class FileConfigStore(private val context: Context) : ConfigStore {
val file = fileFor(name)
if (!file.isFile)
throw FileNotFoundException(context.getString(R.string.config_not_found_error, file.name))
FileOutputStream(file, false).use { stream -> stream.write(config.toWgQuickString().toByteArray(StandardCharsets.UTF_8)) }
FileOutputStream(file, false).use { stream -> stream.write(config.toAwgQuickString().toByteArray(StandardCharsets.UTF_8)) }
return config
}
companion object {
private const val TAG = "WireGuard/FileConfigStore"
private const val TAG = "AmneziaWG/FileConfigStore"
}
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
package org.amnezia.awg.databinding
import android.text.InputFilter
import android.view.LayoutInflater
@@ -18,14 +18,14 @@ import androidx.databinding.adapters.ListenerUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.wireguard.android.BR
import com.wireguard.android.R
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
import com.wireguard.android.widget.ToggleSwitch
import com.wireguard.android.widget.ToggleSwitch.OnBeforeCheckedChangeListener
import com.wireguard.android.widget.TvCardView
import com.wireguard.config.Attribute
import com.wireguard.config.InetNetwork
import org.amnezia.awg.BR
import org.amnezia.awg.R
import org.amnezia.awg.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
import org.amnezia.awg.widget.ToggleSwitch
import org.amnezia.awg.widget.ToggleSwitch.OnBeforeCheckedChangeListener
import org.amnezia.awg.widget.TvCardView
import org.amnezia.awg.config.Attribute
import org.amnezia.awg.config.InetNetwork
import java.net.InetAddress
import java.util.Optional
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
package org.amnezia.awg.databinding
import android.view.LayoutInflater
import android.view.View
@@ -11,7 +11,7 @@ import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableList
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import com.wireguard.android.BR
import org.amnezia.awg.BR
import java.lang.ref.WeakReference
/**
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
package org.amnezia.awg.databinding
/**
* Interface for objects that have a identifying key of the given type.
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
package org.amnezia.awg.databinding
import androidx.databinding.ObservableArrayList
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
package org.amnezia.awg.databinding
import android.content.Context
import android.view.LayoutInflater
@@ -11,7 +11,7 @@ import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableList
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.wireguard.android.BR
import org.amnezia.awg.BR
import java.lang.ref.WeakReference
/**
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.databinding
package org.amnezia.awg.databinding
import java.util.AbstractList
import java.util.Collections
@@ -1,24 +1,26 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.content.pm.PackageManager
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.os.bundleOf
import androidx.fragment.app.setFragmentResult
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.wireguard.android.R
import com.wireguard.android.util.resolveAttribute
import org.amnezia.awg.R
import org.amnezia.awg.util.resolveAttribute
class AddTunnelsSheet : BottomSheetDialogFragment() {
@@ -42,6 +44,7 @@ class AddTunnelsSheet : BottomSheetDialogFragment() {
qrcode.isEnabled = false
qrcode.visibility = View.GONE
}
view.findViewById<TextView>(R.id.disclaimer)?.let { it.movementMethod = LinkMovementMethod.getInstance() }
return view
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.Manifest
import android.app.Dialog
@@ -21,12 +21,12 @@ 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
import com.wireguard.android.databinding.AppListDialogFragmentBinding
import com.wireguard.android.databinding.ObservableKeyedArrayList
import com.wireguard.android.model.ApplicationData
import com.wireguard.android.util.ErrorMessages
import org.amnezia.awg.BR
import org.amnezia.awg.R
import org.amnezia.awg.databinding.AppListDialogFragmentBinding
import org.amnezia.awg.databinding.ObservableKeyedArrayList
import org.amnezia.awg.model.ApplicationData
import org.amnezia.awg.util.ErrorMessages
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -48,9 +48,9 @@ class AppListDialogFragment : DialogFragment() {
val packageInfos = getPackagesHoldingPermissions(pm, arrayOf(Manifest.permission.INTERNET))
packageInfos.forEach {
val packageName = it.packageName
val appInfo = it.applicationInfo ?: return@forEach
val appInfo = it.applicationInfo
val appData =
ApplicationData(appInfo.loadIcon(pm), appInfo.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
ApplicationData(appInfo?.loadIcon(pm) ?: pm.defaultActivityIcon, appInfo?.loadLabel(pm)?.toString() ?: packageName, packageName, currentlySelectedApps.contains(packageName))
applicationData.add(appData)
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.content.Context
import android.util.Log
@@ -14,16 +14,16 @@ import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.activity.BaseActivity
import com.wireguard.android.activity.BaseActivity.OnSelectedTunnelChangedListener
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.databinding.TunnelDetailFragmentBinding
import com.wireguard.android.databinding.TunnelListItemBinding
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.ErrorMessages
import org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.activity.BaseActivity
import org.amnezia.awg.activity.BaseActivity.OnSelectedTunnelChangedListener
import org.amnezia.awg.backend.GoBackend
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.databinding.TunnelDetailFragmentBinding
import org.amnezia.awg.databinding.TunnelListItemBinding
import org.amnezia.awg.model.ObservableTunnel
import org.amnezia.awg.util.ErrorMessages
import kotlinx.coroutines.launch
/**
@@ -109,6 +109,6 @@ abstract class BaseFragment : Fragment(), OnSelectedTunnelChangedListener {
}
companion object {
private const val TAG = "WireGuard/BaseFragment"
private const val TAG = "AmneziaWG/BaseFragment"
}
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.app.Dialog
import android.os.Bundle
@@ -10,11 +10,11 @@ import android.view.WindowManager
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.databinding.ConfigNamingDialogFragmentBinding
import com.wireguard.config.BadConfigException
import com.wireguard.config.Config
import org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.databinding.ConfigNamingDialogFragmentBinding
import org.amnezia.awg.config.BadConfigException
import org.amnezia.awg.config.Config
import kotlinx.coroutines.launch
import java.io.ByteArrayInputStream
import java.io.IOException
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.os.Bundle
import android.view.LayoutInflater
@@ -15,12 +15,12 @@ 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
import com.wireguard.android.databinding.TunnelDetailFragmentBinding
import com.wireguard.android.databinding.TunnelDetailPeerBinding
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.QuantityFormatter
import org.amnezia.awg.R
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.databinding.TunnelDetailFragmentBinding
import org.amnezia.awg.databinding.TunnelDetailPeerBinding
import org.amnezia.awg.model.ObservableTunnel
import org.amnezia.awg.util.QuantityFormatter
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.content.Context
import android.os.Bundle
@@ -23,20 +23,20 @@ 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
import com.wireguard.android.R
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.databinding.TunnelEditorFragmentBinding
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.BiometricAuthenticator
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.viewmodel.ConfigProxy
import com.wireguard.config.Config
import org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.databinding.TunnelEditorFragmentBinding
import org.amnezia.awg.model.ObservableTunnel
import org.amnezia.awg.util.AdminKnobs
import org.amnezia.awg.util.BiometricAuthenticator
import org.amnezia.awg.util.ErrorMessages
import org.amnezia.awg.viewmodel.ConfigProxy
import org.amnezia.awg.config.Config
import kotlinx.coroutines.launch
/**
* Fragment for editing a WireGuard configuration.
* Fragment for editing an AmneziaWG configuration.
*/
class TunnelEditorFragment : BaseFragment(), MenuProvider {
private var haveShownKeys = false
@@ -328,6 +328,6 @@ class TunnelEditorFragment : BaseFragment(), MenuProvider {
companion object {
private const val KEY_LOCAL_CONFIG = "local_config"
private const val KEY_ORIGINAL_NAME = "original_name"
private const val TAG = "WireGuard/TunnelEditorFragment"
private const val TAG = "AmneziaWG/TunnelEditorFragment"
}
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.fragment
package org.amnezia.awg.fragment
import android.content.Intent
import android.content.res.Resources
@@ -26,25 +26,24 @@ import com.google.android.material.snackbar.Snackbar
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
import com.wireguard.android.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
import com.wireguard.android.databinding.TunnelListFragmentBinding
import com.wireguard.android.databinding.TunnelListItemBinding
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.updater.SnackbarUpdateShower
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 org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.activity.TunnelCreatorActivity
import org.amnezia.awg.databinding.ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler
import org.amnezia.awg.databinding.TunnelListFragmentBinding
import org.amnezia.awg.databinding.TunnelListItemBinding
import org.amnezia.awg.model.ObservableTunnel
import org.amnezia.awg.util.ErrorMessages
import org.amnezia.awg.util.QrCodeFromFileScanner
import org.amnezia.awg.util.TunnelImporter
import org.amnezia.awg.widget.MultiselectableRelativeLayout
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
/**
* Fragment containing a list of known WireGuard tunnels. It allows creating and deleting tunnels.
* Fragment containing a list of known AmneziaWG tunnels. It allows creating and deleting tunnels.
*/
class TunnelListFragment : BaseFragment() {
private val actionModeListener = ActionModeListener()
@@ -81,8 +80,6 @@ class TunnelListFragment : BaseFragment() {
}
}
private val snackbarUpdateShower = SnackbarUpdateShower(this)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (savedInstanceState != null) {
@@ -127,7 +124,6 @@ class TunnelListFragment : BaseFragment() {
bottomSheet.showNow(childFragmentManager, "BOTTOM_SHEET")
}
executePendingBindings()
snackbarUpdateShower.attach(mainContainer, createFab)
}
backPressedCallback = requireActivity().onBackPressedDispatcher.addCallback(this) { actionMode?.finish() }
backPressedCallback?.isEnabled = false
@@ -337,6 +333,6 @@ class TunnelListFragment : BaseFragment() {
companion object {
private const val CHECKED_ITEMS = "CHECKED_ITEMS"
private const val TAG = "WireGuard/TunnelListFragment"
private const val TAG = "AmneziaWG/TunnelListFragment"
}
}
@@ -1,14 +1,14 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
package org.amnezia.awg.model
import android.graphics.drawable.Drawable
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.wireguard.android.BR
import com.wireguard.android.databinding.Keyed
import org.amnezia.awg.BR
import org.amnezia.awg.databinding.Keyed
class ApplicationData(val icon: Drawable, val name: String, val packageName: String, isSelected: Boolean) : BaseObservable(), Keyed<String> {
override val key = name
@@ -1,24 +1,24 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
package org.amnezia.awg.model
import android.util.Log
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.wireguard.android.BR
import com.wireguard.android.backend.Statistics
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.databinding.Keyed
import com.wireguard.android.util.applicationScope
import com.wireguard.config.Config
import org.amnezia.awg.BR
import org.amnezia.awg.backend.Statistics
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.databinding.Keyed
import org.amnezia.awg.util.applicationScope
import org.amnezia.awg.config.Config
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
* Encapsulates the volatile and nonvolatile state of an AmneziaWG tunnel.
*/
class ObservableTunnel internal constructor(
private val manager: TunnelManager,
@@ -141,6 +141,6 @@ class ObservableTunnel internal constructor(
companion object {
private const val TAG = "WireGuard/ObservableTunnel"
private const val TAG = "AmneziaWG/ObservableTunnel"
}
}
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
package org.amnezia.awg.model
object TunnelComparator : Comparator<String> {
private class NaturalSortString(originalString: String) {
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.model
package org.amnezia.awg.model
import android.content.BroadcastReceiver
import android.content.Context
@@ -12,19 +12,19 @@ import android.util.Log
import android.widget.Toast
import androidx.databinding.BaseObservable
import androidx.databinding.Bindable
import com.wireguard.android.Application.Companion.get
import com.wireguard.android.Application.Companion.getBackend
import com.wireguard.android.Application.Companion.getTunnelManager
import com.wireguard.android.BR
import com.wireguard.android.R
import com.wireguard.android.backend.Statistics
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.configStore.ConfigStore
import com.wireguard.android.databinding.ObservableSortedKeyedArrayList
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.UserKnobs
import com.wireguard.android.util.applicationScope
import com.wireguard.config.Config
import org.amnezia.awg.Application.Companion.get
import org.amnezia.awg.Application.Companion.getBackend
import org.amnezia.awg.Application.Companion.getTunnelManager
import org.amnezia.awg.BR
import org.amnezia.awg.R
import org.amnezia.awg.backend.Statistics
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.configStore.ConfigStore
import org.amnezia.awg.databinding.ObservableSortedKeyedArrayList
import org.amnezia.awg.util.ErrorMessages
import org.amnezia.awg.util.UserKnobs
import org.amnezia.awg.util.applicationScope
import org.amnezia.awg.config.Config
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -35,7 +35,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* Maintains and mediates changes to the set of available WireGuard tunnels,
* Maintains and mediates changes to the set of available AmneziaWG tunnels,
*/
class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
private val tunnels = CompletableDeferred<ObservableSortedKeyedArrayList<String, ObservableTunnel>>()
@@ -217,15 +217,16 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
val manager = getTunnelManager()
if (intent == null) return@launch
val action = intent.action ?: return@launch
if ("com.wireguard.android.action.REFRESH_TUNNEL_STATES" == action) {
if ("org.amnezia.awg.action.REFRESH_TUNNEL_STATES" == action) {
manager.refreshTunnelStates()
return@launch
}
if (!UserKnobs.allowRemoteControlIntents.first())
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || !UserKnobs.allowRemoteControlIntents.first())
return@launch
val state = when (action) {
"com.wireguard.android.action.SET_TUNNEL_UP" -> Tunnel.State.UP
"com.wireguard.android.action.SET_TUNNEL_DOWN" -> Tunnel.State.DOWN
val state: Tunnel.State
state = when (action) {
"org.amnezia.awg.action.SET_TUNNEL_UP" -> Tunnel.State.UP
"org.amnezia.awg.action.SET_TUNNEL_DOWN" -> Tunnel.State.DOWN
else -> return@launch
}
val tunnelName = intent.getStringExtra("tunnel") ?: return@launch
@@ -249,6 +250,6 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
}
companion object {
private const val TAG = "WireGuard/TunnelManager"
private const val TAG = "AmneziaWG/TunnelManager"
}
}
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
package org.amnezia.awg.preference
import android.content.Context
import android.content.Intent
@@ -10,14 +10,14 @@ import android.util.AttributeSet
import android.util.Log
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.activity.SettingsActivity
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.util.UserKnobs
import com.wireguard.android.util.activity
import com.wireguard.android.util.lifecycleScope
import org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.activity.SettingsActivity
import org.amnezia.awg.backend.Tunnel
import org.amnezia.awg.backend.AwgQuickBackend
import org.amnezia.awg.util.UserKnobs
import org.amnezia.awg.util.activity
import org.amnezia.awg.util.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
@@ -32,7 +32,7 @@ class KernelModuleEnablerPreference(context: Context, attrs: AttributeSet?) : Pr
init {
isVisible = false
lifecycleScope.launch {
setState(if (Application.getBackend() is WgQuickBackend) State.ENABLED else State.DISABLED)
setState(if (Application.getBackend() is AwgQuickBackend) State.ENABLED else State.DISABLED)
}
}
@@ -83,6 +83,6 @@ class KernelModuleEnablerPreference(context: Context, attrs: AttributeSet?) : Pr
}
companion object {
private const val TAG = "WireGuard/KernelModuleEnablerPreference"
private const val TAG = "AmneziaWG/KernelModuleEnablerPreference"
}
}
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
package org.amnezia.awg.preference
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
@@ -1,9 +1,9 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
package org.amnezia.awg.preference
import android.app.StatusBarManager
import android.content.ComponentName
@@ -14,8 +14,8 @@ import android.util.AttributeSet
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.preference.Preference
import com.wireguard.android.QuickTileService
import com.wireguard.android.R
import org.amnezia.awg.QuickTileService
import org.amnezia.awg.R
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
class QuickTilePreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
@@ -1,16 +1,16 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
package org.amnezia.awg.preference
import android.content.Context
import android.util.AttributeSet
import androidx.preference.Preference
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.util.ToolsInstaller
import com.wireguard.android.util.lifecycleScope
import org.amnezia.awg.Application
import org.amnezia.awg.R
import org.amnezia.awg.util.ToolsInstaller
import org.amnezia.awg.util.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -1,8 +1,8 @@
/*
* Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* Copyright © 2017-2023 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.preference
package org.amnezia.awg.preference
import android.content.Context
import android.content.Intent
@@ -10,14 +10,14 @@ import android.net.Uri
import android.util.AttributeSet
import android.widget.Toast
import androidx.preference.Preference
import com.wireguard.android.Application
import com.wireguard.android.BuildConfig
import com.wireguard.android.R
import com.wireguard.android.backend.Backend
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.lifecycleScope
import org.amnezia.awg.Application
import org.amnezia.awg.BuildConfig
import org.amnezia.awg.R
import org.amnezia.awg.backend.Backend
import org.amnezia.awg.backend.GoBackend
import org.amnezia.awg.backend.AwgQuickBackend
import org.amnezia.awg.util.ErrorMessages
import org.amnezia.awg.util.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -31,7 +31,7 @@ class VersionPreference(context: Context, attrs: AttributeSet?) : Preference(con
override fun onClick() {
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("https://www.wireguard.com/")
intent.data = Uri.parse("https://amnezia.org/")
try {
context.startActivity(intent)
} catch (e: Throwable) {
@@ -41,7 +41,7 @@ class VersionPreference(context: Context, attrs: AttributeSet?) : Preference(con
companion object {
private fun getBackendPrettyName(context: Context, backend: Backend) = when (backend) {
is WgQuickBackend -> context.getString(R.string.type_name_kernel_module)
is AwgQuickBackend -> context.getString(R.string.type_name_kernel_module)
is GoBackend -> context.getString(R.string.type_name_go_userspace)
else -> ""
}

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