android: Full Compose rewrite + two-mode RU split with userspace routing
Android / pre-check (push) Failing after 5s
Android / android (push) Skipped
CIFuzz / pre-check (push) Failing after 3s
CIFuzz / fuzzing (address) (push) Skipped
CIFuzz / fuzzing (undefined) (push) Skipped
CodeQL / pre-check (push) Failing after 3s
CodeQL / analyze (python) (push) Skipped
CodeQL / analyze (ruby) (push) Skipped
CodeQL / analyze-cpp (push) Skipped
FreeBSD / pre-check (push) Failing after 3s
FreeBSD / freebsd (14.4) (push) Skipped
FreeBSD / freebsd (15.0) (push) Skipped
Linux / pre-check (push) Failing after 3s
Linux / latest (apidoc) (push) Skipped
Linux / latest (clang, no, all) (push) Skipped
Linux / latest (clang, no, default) (push) Skipped
Linux / latest (clang, no, printf-builtin) (push) Skipped
Linux / latest (clang, no-dbg) (push) Skipped
Linux / latest (clang, no-testable-ke) (push) Skipped
Linux / latest (clang, yes, all) (push) Skipped
Linux / latest (clang, yes, default) (push) Skipped
Linux / latest (clang, yes, fuzzing) (push) Skipped
Linux / latest (coverage) (push) Skipped
Linux / latest (dist) (push) Skipped
Linux / latest (gcc, no, all) (push) Skipped
Linux / latest (gcc, no, default) (push) Skipped
Linux / latest (gcc, no, printf-builtin) (push) Skipped
Linux / latest (gcc, yes, all) (push) Skipped
Linux / latest (gcc, yes, default) (push) Skipped
Linux / latest (nm) (push) Skipped
Linux / latest (no-dbg) (push) Skipped
Linux / latest (no-testable-ke) (push) Skipped
Linux / latest (yes, ld) (push) Skipped
Linux / crypto (ubuntu-22.04, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, botan) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-3) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-4) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-awslc) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, wolfssl) (push) Skipped
Linux / older (clang, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, nm) (push) Skipped
Linux / alpine (push) Skipped
macOS / pre-check (push) Failing after 3s
macOS / macos (macos-14) (push) Skipped
macOS / macos (macos-latest) (push) Skipped
SonarCloud / pre-check (push) Failing after 4s
SonarCloud / sonarcloud (push) Skipped
TKM / pre-check (push) Failing after 3s
TKM / tkm (push) Skipped
Windows / pre-check (push) Failing after 4s
Windows / cross-compile (win32) (push) Skipped
Windows / cross-compile (win64) (push) Skipped
Windows / native (i686, mingw32, win32) (push) Skipped
Windows / native (x86_64, mingw64, win64) (push) Skipped
Android / pre-check (push) Failing after 5s
Android / android (push) Skipped
CIFuzz / pre-check (push) Failing after 3s
CIFuzz / fuzzing (address) (push) Skipped
CIFuzz / fuzzing (undefined) (push) Skipped
CodeQL / pre-check (push) Failing after 3s
CodeQL / analyze (python) (push) Skipped
CodeQL / analyze (ruby) (push) Skipped
CodeQL / analyze-cpp (push) Skipped
FreeBSD / pre-check (push) Failing after 3s
FreeBSD / freebsd (14.4) (push) Skipped
FreeBSD / freebsd (15.0) (push) Skipped
Linux / pre-check (push) Failing after 3s
Linux / latest (apidoc) (push) Skipped
Linux / latest (clang, no, all) (push) Skipped
Linux / latest (clang, no, default) (push) Skipped
Linux / latest (clang, no, printf-builtin) (push) Skipped
Linux / latest (clang, no-dbg) (push) Skipped
Linux / latest (clang, no-testable-ke) (push) Skipped
Linux / latest (clang, yes, all) (push) Skipped
Linux / latest (clang, yes, default) (push) Skipped
Linux / latest (clang, yes, fuzzing) (push) Skipped
Linux / latest (coverage) (push) Skipped
Linux / latest (dist) (push) Skipped
Linux / latest (gcc, no, all) (push) Skipped
Linux / latest (gcc, no, default) (push) Skipped
Linux / latest (gcc, no, printf-builtin) (push) Skipped
Linux / latest (gcc, yes, all) (push) Skipped
Linux / latest (gcc, yes, default) (push) Skipped
Linux / latest (nm) (push) Skipped
Linux / latest (no-dbg) (push) Skipped
Linux / latest (no-testable-ke) (push) Skipped
Linux / latest (yes, ld) (push) Skipped
Linux / crypto (ubuntu-22.04, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, botan) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-3) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-4) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-awslc) (push) Skipped
Linux / crypto (ubuntu-latest, openssl-sys) (push) Skipped
Linux / crypto (ubuntu-latest, wolfssl) (push) Skipped
Linux / older (clang, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, all) (push) Skipped
Linux / older (gcc, ubuntu-22.04, nm) (push) Skipped
Linux / alpine (push) Skipped
macOS / pre-check (push) Failing after 3s
macOS / macos (macos-14) (push) Skipped
macOS / macos (macos-latest) (push) Skipped
SonarCloud / pre-check (push) Failing after 4s
SonarCloud / sonarcloud (push) Skipped
TKM / pre-check (push) Failing after 3s
TKM / tkm (push) Skipped
Windows / pre-check (push) Failing after 4s
Windows / cross-compile (win32) (push) Skipped
Windows / cross-compile (win64) (push) Skipped
Windows / native (i686, mingw32, win32) (push) Skipped
Windows / native (x86_64, mingw64, win64) (push) Skipped
Replaces the fragment-based UI with a full Jetpack Compose app (HOME/profiles/routing/settings/trusted networks in Compose, adaptive brand theming, notification/vector drawables), adds the SHX release pipeline (build-local.sh, UpdateManager self-update from the S3 bucket, DiagLog diagnostics rotated into diag.log with crash capture) and the watchdog/auto-connect/reconnect hardening series. RU-GeoIP split now has two modes (Routing screen): - OS routes (default): coarsened complement of the RU list installed as system routes, bounded by the binder budget (2.12.x behavior) - Userspace routing (beta): only the default routes point into the TUN; every packet is classified natively against the exact RU list (ring-buffer queue, fixed flow tables - allocation-free hot path) and RU TCP/UDP leaves through protected sockets. TCP is terminated by a vendored lwIP 2.2.0 (tun2socks model, err_t renamed to avoid the strongSwan typedef clash, wildcard-port listener patch, asserts into diag.log). IPv4 addresses are compared in Java's numeric byte order and ranges sorted natively; direct flows re-protect on roam; relay errors log errno. Route diagnostics block 12s after connect. Also: SIM2-crash hardening, connectivity watchdog with wakeup alarm, profile export, connectivity self-check screen, tests. Published as 2.13.9 (versionCode 146).
This commit is contained in:
1 parent
9dcc56c821
commit
d12fb96dc2
494 files changed
+156372
-5520
No files matched your search
@@ -0,0 +1,174 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
||||
|
||||
/* Optional .env next to this project: S3/update settings and signing (see .env.example).
|
||||
Environment variables take precedence over .env values. */
|
||||
def dotenv = [:]
|
||||
def envFile = rootProject.file('.env')
|
||||
if (envFile.exists()) {
|
||||
envFile.eachLine { line ->
|
||||
def trimmed = line.trim()
|
||||
if (trimmed && !trimmed.startsWith('#') && trimmed.contains('=')) {
|
||||
def idx = trimmed.indexOf('=')
|
||||
dotenv[trimmed.substring(0, idx).trim()] = trimmed.substring(idx + 1).trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
def envOr = { String key, String defaultValue ->
|
||||
(System.getenv(key) ?: dotenv[key] ?: defaultValue)
|
||||
}
|
||||
|
||||
def updateBaseUrl = envOr('S3_PUBLIC_BASE_URL', '').replace('\\', '\\\\').replace('"', '\\"')
|
||||
|
||||
def keystoreFile = envOr('KEYSTORE_FILE', '')
|
||||
def keystorePassword = envOr('KEYSTORE_PASSWORD', '')
|
||||
/* note: locals must not be named keyAlias/keyPassword - those names would
|
||||
shadow the signingConfig methods inside the signingConfigs block */
|
||||
def keystoreKeyAlias = envOr('KEY_ALIAS', '')
|
||||
def keystoreKeyPassword = envOr('KEY_PASSWORD', '')
|
||||
|
||||
android {
|
||||
namespace = 'org.strongswan.android'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "one.shx.strongswan.ext"
|
||||
compileSdk = 36
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 36
|
||||
|
||||
versionCode 146
|
||||
versionName "2.13.9"
|
||||
|
||||
/* Base URL of the update storage, trailing slash included */
|
||||
buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\""
|
||||
|
||||
/* S3 credentials used by the app for authenticated update downloads
|
||||
(same keys as the publish script). They are obfuscated with XOR +
|
||||
Base64 at build time to hinder trivial string extraction.
|
||||
Note: obfuscation is not real protection - an APK can always be
|
||||
reverse engineered, so rotate these keys if they leak. */
|
||||
def updateS3Access = envOr('S3_ACCESS_KEY', '')
|
||||
def updateS3Secret = envOr('S3_SECRET_KEY', '')
|
||||
def updateXorKey = new byte[16]
|
||||
System.arraycopy(java.security.MessageDigest.getInstance('SHA-256')
|
||||
.digest('shx-update-credentials'.getBytes('UTF-8')), 0, updateXorKey, 0, 16)
|
||||
def xorB64 = { String value ->
|
||||
if (!value) { return '' }
|
||||
def bytes = value.getBytes('UTF-8')
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = (byte)(bytes[i] ^ updateXorKey[i % updateXorKey.length])
|
||||
}
|
||||
java.util.Base64.getEncoder().encodeToString(bytes)
|
||||
}
|
||||
buildConfigField "String", "UPDATE_S3_ACCESS_KEY", "\"${xorB64(updateS3Access)}\""
|
||||
buildConfigField "String", "UPDATE_S3_SECRET_KEY", "\"${xorB64(updateS3Secret)}\""
|
||||
buildConfigField "String", "UPDATE_S3_KEY_XOR", "\"${java.util.Base64.getEncoder().encodeToString(updateXorKey)}\""
|
||||
buildConfigField "String", "UPDATE_S3_REGION", "\"${envOr('S3_REGION', 'us-east-1')}\""
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments '-j' + Runtime.runtime.availableProcessors()
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ndkVersion = "27.3.13750724"
|
||||
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
path 'src/main/jni/Android.mk'
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
compileTask ->
|
||||
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
if (keystoreFile) {
|
||||
storeFile rootProject.file(keystoreFile)
|
||||
storePassword keystorePassword
|
||||
keyAlias keystoreKeyAlias
|
||||
keyPassword keystoreKeyPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
/* R8 shrinking + resource shrinking: strips dead code/resources and
|
||||
obfuscates. The JNI surface is kept via proguard-rules.txt.
|
||||
Smoke-test a release build on a device before publishing. */
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
if (keystoreFile) {
|
||||
signingConfig signingConfigs.release
|
||||
} else {
|
||||
/* fall back to the debug key so that release APKs update debug-signed
|
||||
installations in place (no uninstall, data is preserved) */
|
||||
def debugKeystore = new File(System.getProperty('user.home'), '.android/debug.keystore')
|
||||
if (debugKeystore.exists()) {
|
||||
signingConfig signingConfigs.debug
|
||||
println "WARNING: KEYSTORE_FILE not set (see .env.example) - signing the release APK with the debug key (${debugKeystore})"
|
||||
} else {
|
||||
println "WARNING: no signing configuration - the release APK will be UNSIGNED (set KEYSTORE_FILE in .env or run a debug build once)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
targetCompatibility 1.8
|
||||
sourceCompatibility 1.8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
buildConfig true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.7.1'
|
||||
implementation 'androidx.core:core:1.17.0'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-process:2.9.4'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.9.4'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.10.1'
|
||||
implementation 'com.google.android.material:material:1.13.0'
|
||||
|
||||
/* BOM 2025.12.01 (compose 1.10) требует minSdk 23 — приложение поддерживает API 21.
|
||||
2025.09.01 = первый BOM с material3 1.4.0 (Expressive) на compose 1.9 (minSdk 21). */
|
||||
def composeBom = platform('androidx.compose:compose-bom:2025.09.01')
|
||||
implementation composeBom
|
||||
implementation 'androidx.compose.ui:ui'
|
||||
implementation 'androidx.compose.material3:material3'
|
||||
implementation 'androidx.compose.material3:material3-window-size-class'
|
||||
/* adaptive-navigation-suite требует minSdk 23 (adaptive:1.2.0) — подключить на этапе 3
|
||||
вместе с решением о minSdk; сейчас приложение поддерживает API 21 */
|
||||
implementation 'androidx.compose.material:material-icons-extended'
|
||||
implementation 'androidx.activity:activity-compose:1.11.0'
|
||||
implementation 'androidx.navigation:navigation-compose:2.9.4'
|
||||
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'org.assertj:assertj-core:3.27.6'
|
||||
testImplementation 'org.mockito:mockito-core:5.20.0'
|
||||
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.7.0'
|
||||
androidTestImplementation 'org.assertj:assertj-core:3.27.6'
|
||||
androidTestImplementation composeBom
|
||||
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||
}
|
||||
Reference in new issue
Block a user