diff --git a/.circleci/config.yml b/.circleci/config.yml index f29b502..0d833b7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,7 @@ jobs: - run: name: Run Build - command: ./gradlew clean assembleRelease + command: ./gradlew clean assembleDebug - save_cache: key: gradle-v1-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} @@ -31,15 +31,15 @@ jobs: - /usr/local/android-sdk - store_artifacts: - path: app/build/outputs/apk/release/app-release-unsigned.apk - destination: AeroVPN-release.apk + path: app/build/outputs/apk/debug/app-debug.apk + destination: AeroVPN-debug.apk - store_artifacts: - path: app/build/outputs/apk/release/ - destination: apk-release + path: app/build/outputs/apk/debug/ + destination: apk-debug - persist_to_workspace: - root: app/build/outputs/apk/release/ + root: app/build/outputs/apk/debug/ paths: - "*.apk" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d46753 --- /dev/null +++ b/.gitignore @@ -0,0 +1,144 @@ +# ============================================================ +# Android .gitignore for AeroVPN +# ============================================================ + +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/ +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches +# Android Studio 3 in .idea has some non-Gradle configuration files. +# Uncomment those lines managing them at your own risk. +.idea/compiler.xml +.idea/jarRepositories.xml +.idea/modules.xml +.idea/*.ipr +.idea/*.iws + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +*.jks +*.keystore +keystore.properties +signing.properties +release.properties + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +google-services.json +GoogleService-Info.plist +google-play-services.json + +# Secrets and sensitive configuration +# Never commit API keys, tokens, or passwords +secrets.properties +api_keys.properties +*.env +.env +.env.* +local.env + +# Fabric API Key +fabric.properties + +# Version control +vcs.xml + +# Lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling +*.hprof + +# Kotlin +*.kotlin_module +kotlin-compiler-embeddable*.jar + +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* +.Spotlight-V100 +.Trashes + +# Windows +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db +Desktop.ini +$RECYCLE.BIN/ + +# Linux +*~ +.directory +.Trash-* +.nfs* + +# VS Code +.vscode/ +*.code-workspace + +# Node (if using any JS tooling) +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# CI/CD sensitive files +.circleci/config.local.yml +.github/secrets/ + +# Test results +test-results/ diff --git a/.gradle/8.14/checksums/checksums.lock b/.gradle/8.14/checksums/checksums.lock new file mode 100644 index 0000000..39c723b Binary files /dev/null and b/.gradle/8.14/checksums/checksums.lock differ diff --git a/.gradle/8.14/checksums/md5-checksums.bin b/.gradle/8.14/checksums/md5-checksums.bin new file mode 100644 index 0000000..c3f1c98 Binary files /dev/null and b/.gradle/8.14/checksums/md5-checksums.bin differ diff --git a/.gradle/8.14/checksums/sha1-checksums.bin b/.gradle/8.14/checksums/sha1-checksums.bin new file mode 100644 index 0000000..c28648c Binary files /dev/null and b/.gradle/8.14/checksums/sha1-checksums.bin differ diff --git a/.gradle/8.14/executionHistory/executionHistory.bin b/.gradle/8.14/executionHistory/executionHistory.bin new file mode 100644 index 0000000..68a47e1 Binary files /dev/null and b/.gradle/8.14/executionHistory/executionHistory.bin differ diff --git a/.gradle/8.14/executionHistory/executionHistory.lock b/.gradle/8.14/executionHistory/executionHistory.lock new file mode 100644 index 0000000..1cbf1d7 Binary files /dev/null and b/.gradle/8.14/executionHistory/executionHistory.lock differ diff --git a/.gradle/8.14/fileChanges/last-build.bin b/.gradle/8.14/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle/8.14/fileChanges/last-build.bin differ diff --git a/.gradle/8.14/fileHashes/fileHashes.bin b/.gradle/8.14/fileHashes/fileHashes.bin new file mode 100644 index 0000000..be45379 Binary files /dev/null and b/.gradle/8.14/fileHashes/fileHashes.bin differ diff --git a/.gradle/8.14/fileHashes/fileHashes.lock b/.gradle/8.14/fileHashes/fileHashes.lock new file mode 100644 index 0000000..274b5fd Binary files /dev/null and b/.gradle/8.14/fileHashes/fileHashes.lock differ diff --git a/.gradle/8.14/gc.properties b/.gradle/8.14/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..c841dff Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..08d453d --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Thu Apr 09 17:57:39 UTC 2026 +gradle.version=8.14 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..cd7c360 Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 0000000..985b285 Binary files /dev/null and b/.gradle/file-system.probe differ diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..cd02e86 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,632 @@ +# Contributing to AeroVPN + +Thank you for your interest in contributing to AeroVPN! This document provides guidelines and instructions for contributing to the project. We welcome all forms of contribution — code, documentation, bug reports, feature requests, and translations. + +--- + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [Getting Started](#getting-started) +- [How to Contribute](#how-to-contribute) +- [Development Setup](#development-setup) +- [Project Structure](#project-structure) +- [Coding Standards](#coding-standards) +- [Commit Guidelines](#commit-guidelines) +- [Pull Request Process](#pull-request-process) +- [Reporting Bugs](#reporting-bugs) +- [Requesting Features](#requesting-features) +- [Security Vulnerabilities](#security-vulnerabilities) +- [Translations](#translations) + +--- + +## Code of Conduct + +By participating in this project, you agree to maintain a respectful and constructive environment. We expect all contributors to: + +- Be respectful and considerate in all interactions +- Accept constructive feedback gracefully +- Focus on what is best for the community and project +- Show empathy towards other community members +- Refrain from harassment, discrimination, or offensive language + +Violations of these standards may result in removal from the project. + +--- + +## Getting Started + +### Prerequisites + +Before contributing, ensure you have the following installed: + +| Tool | Version | Purpose | +|------|---------|---------| +| Android Studio | Hedgehog (2023.1.1)+ | IDE | +| JDK | 17+ | Build toolchain | +| Android SDK | API 34 | Target platform | +| Git | 2.30+ | Version control | +| Kotlin | 1.9.22+ | Primary language | + +### Fork and Clone + +1. **Fork** the repository by clicking the Fork button on GitHub +2. **Clone** your fork locally: + ```bash + git clone https://github.com/YOUR_USERNAME/AeroVPN.git + cd AeroVPN + ``` +3. **Add the upstream remote** to keep your fork in sync: + ```bash + git remote add upstream https://github.com/0xgetz/AeroVPN.git + ``` +4. **Verify remotes**: + ```bash + git remote -v + # origin https://github.com/YOUR_USERNAME/AeroVPN.git (fetch) + # origin https://github.com/YOUR_USERNAME/AeroVPN.git (push) + # upstream https://github.com/0xgetz/AeroVPN.git (fetch) + # upstream https://github.com/0xgetz/AeroVPN.git (push) + ``` + +--- + +## How to Contribute + +### Types of Contributions + +| Type | Description | Skill Level | +|------|-------------|-------------| +| Bug fixes | Fix reported issues | Beginner+ | +| Documentation | Improve README, comments, wiki | Beginner | +| Translations | Localize the app to new languages | Beginner | +| UI improvements | Polish the Jetpack Compose UI | Intermediate | +| New protocol support | Add new VPN/tunneling protocols | Advanced | +| Performance | Optimize speed, battery, memory | Advanced | +| Security | Harden encryption, fix vulnerabilities | Expert | +| Tests | Add unit/integration tests | Intermediate | + +### Finding Issues to Work On + +- Browse [open issues](https://github.com/0xgetz/AeroVPN/issues) on GitHub +- Look for issues labeled `good first issue` for beginner-friendly tasks +- Issues labeled `help wanted` are prioritized for community contributions +- Check the [project board](https://github.com/0xgetz/AeroVPN/projects) for planned work + +**Before starting work**, comment on the issue to let maintainers know you're working on it. This avoids duplicate effort. + +--- + +## Development Setup + +### 1. Open the Project + +1. Launch Android Studio +2. Select **File** → **Open** +3. Navigate to the cloned `AeroVPN` directory +4. Click **OK** and wait for Gradle sync + +### 2. Create a Feature Branch + +Always branch off `main` for new work: + +```bash +# Sync your fork with upstream +git fetch upstream +git checkout main +git merge upstream/main + +# Create your feature branch +git checkout -b feature/your-feature-name +# or for bug fixes: +git checkout -b fix/issue-description +# or for documentation: +git checkout -b docs/what-you-changed +``` + +**Branch naming conventions:** + +| Prefix | Use for | +|--------|---------| +| `feature/` | New features | +| `fix/` | Bug fixes | +| `docs/` | Documentation only | +| `refactor/` | Code restructuring | +| `perf/` | Performance improvements | +| `test/` | Adding or fixing tests | +| `chore/` | Build/config changes | + +### 3. Run the App + +```bash +# Build debug APK +./gradlew assembleDebug + +# Install on connected device +./gradlew installDebug + +# Run all checks +./gradlew check + +# Run lint +./gradlew lint +``` + +### 4. Verify Your Changes + +Before submitting, ensure: +- [ ] App builds successfully (`./gradlew assembleDebug`) +- [ ] No new lint warnings (`./gradlew lint`) +- [ ] App tested on a physical device or emulator +- [ ] No sensitive data (API keys, passwords) hardcoded in code +- [ ] New features have appropriate comments + +--- + +## Project Structure + +``` +AeroVPN/ +├── app/ +│ └── src/ +│ └── main/ +│ ├── java/com/aerovpn/ +│ │ ├── AeroVPNApplication.kt # Application class +│ │ ├── config/ +│ │ │ └── VpnConfig.kt # VPN configuration models +│ │ ├── receiver/ +│ │ │ ├── BootReceiver.kt # Auto-start on boot +│ │ │ ├── NetworkStateReceiver.kt # Network change detection +│ │ │ ├── PackageUpdateReceiver.kt# App install/uninstall events +│ │ │ └── PowerStateReceiver.kt # Power state events +│ │ ├── service/ +│ │ │ ├── AeroVpnService.kt # Core VPN service +│ │ │ └── protocol/ +│ │ │ ├── ProtocolHandler.kt # Protocol abstraction +│ │ │ ├── SSHProtocol.kt # SSH tunneling +│ │ │ ├── ShadowsocksProtocol.kt +│ │ │ ├── UdpTunnelProtocol.kt +│ │ │ ├── V2RayProtocol.kt # V2Ray/Xray +│ │ │ └── WireGuardProtocol.kt +│ │ ├── tools/ +│ │ │ ├── AppsFilterTool.kt # Split tunneling +│ │ │ ├── CustomDnsTool.kt # DNS configuration +│ │ │ ├── ExportImportTool.kt # Config backup/restore +│ │ │ ├── HostCheckerTool.kt # Host connectivity test +│ │ │ ├── IpHunterTool.kt # Public IP lookup +│ │ │ ├── PayloadGeneratorTool.kt# HTTP payload for tunnels +│ │ │ ├── PingTool.kt # Latency test +│ │ │ ├── ShareConnectionTool.kt # Hotspot/tethering +│ │ │ ├── SlowDnsCheckerTool.kt # DNS tunnel test +│ │ │ └── TcpNoDelayTool.kt # TCP optimization +│ │ └── ui/ +│ │ ├── MainActivity.kt # Entry point activity +│ │ ├── navigation/ # Navigation graph +│ │ ├── screens/ # Compose screens +│ │ │ ├── HomeScreen.kt +│ │ │ ├── ServerListScreen.kt +│ │ │ ├── ToolsScreen.kt +│ │ │ ├── ConfigScreen.kt +│ │ │ └── SettingsScreen.kt +│ │ └── theme/ # Material 3 theming +│ └── res/ +│ ├── drawable/ # Icons and graphics +│ ├── values/ # Strings, colors, themes +│ └── xml/ # Network security config +├── gradle/ # Gradle wrapper +├── .github/ # CI/CD workflows +├── LICENSE +├── README.md +├── CONTRIBUTING.md +├── .gitignore +├── build.gradle +├── settings.gradle +└── gradle.properties +``` + +### Architecture Overview + +AeroVPN follows **MVVM (Model-View-ViewModel)** architecture: + +``` +UI Layer (Compose Screens) + ↕ +ViewModel Layer (State management) + ↕ +Domain Layer (Business logic, Protocol handlers) + ↕ +Data Layer (VpnConfig, DataStore, Room) + ↕ +System Layer (Android VpnService, Network APIs) +``` + +Key architectural decisions: +- **Jetpack Compose** for all UI — no XML layouts +- **Kotlin Coroutines** for async operations +- **Android VpnService** as the foundation for all protocols +- **DataStore** for preferences over SharedPreferences +- **BuildConfig** fields for any environment-specific values (never hardcoded) + +--- + +## Coding Standards + +### Kotlin Style + +Follow the [official Kotlin coding conventions](https://kotlinlang.org/docs/coding-conventions.html). Key rules: + +```kotlin +// Good: descriptive names, single responsibility +fun connectToServer(config: VpnConfig): Result { + // ... +} + +// Bad: cryptic names, multiple responsibilities +fun doStuff(c: Any): Boolean { + // ... +} +``` + +**Formatting:** +- 4-space indentation (no tabs) +- Max line length: 120 characters +- Opening braces on the same line +- Trailing commas in multi-line expressions + +**Naming conventions:** + +| Element | Convention | Example | +|---------|------------|---------| +| Classes | PascalCase | `VpnConfig`, `AeroVpnService` | +| Functions | camelCase | `connectToServer()` | +| Properties | camelCase | `isConnected`, `serverAddress` | +| Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` | +| Private fields | camelCase (no underscore prefix) | `connectionState` | + +### Compose UI Guidelines + +```kotlin +// Good: stateless composable with hoisted state +@Composable +fun ConnectButton( + isConnected: Boolean, + onConnectClick: () -> Unit, + modifier: Modifier = Modifier +) { + Button( + onClick = onConnectClick, + modifier = modifier + ) { + Text(if (isConnected) "Disconnect" else "Connect") + } +} + +// Bad: state inside composable (hard to test/preview) +@Composable +fun ConnectButton() { + var isConnected by remember { mutableStateOf(false) } + Button(onClick = { isConnected = !isConnected }) { + Text(if (isConnected) "Disconnect" else "Connect") + } +} +``` + +**Compose best practices:** +- Keep composables small and focused on a single responsibility +- Hoist state as high as necessary, no higher +- Use `modifier` parameter in every composable for flexibility +- Preview composables with `@Preview` annotations +- Avoid side effects in composable bodies — use `LaunchedEffect`, `SideEffect`, etc. + +### Protocol Handler Guidelines + +When adding a new protocol or modifying an existing one: + +1. Implement the `ProtocolHandler` interface +2. Handle all connection lifecycle events: `connect()`, `disconnect()`, `reconnect()` +3. Properly release all resources in `disconnect()` +4. Never store credentials beyond the active session +5. Log connection events at appropriate levels (INFO for state changes, DEBUG for internals) +6. Return descriptive error messages in `Result.failure()` + +```kotlin +// Template for a new protocol +class MyProtocol : ProtocolHandler { + override suspend fun connect(config: VpnConfig): Result { + return try { + // Implementation + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) + } + } + + override suspend fun disconnect(): Result { + // Always clean up resources + return Result.success(Unit) + } +} +``` + +### Security Guidelines + +**Never hardcode sensitive values:** +```kotlin +// BAD - never do this +val apiKey = "sk-abc123xyz" +val serverPassword = "mypassword123" + +// GOOD - use BuildConfig or runtime input +val apiKey = BuildConfig.API_KEY // set via gradle, not in code +// Or better: receive from user input at runtime, never store in source +``` + +**Handle user credentials safely:** +- Never log passwords, keys, or tokens +- Clear sensitive data from memory when no longer needed +- Use Android Keystore for storing cryptographic keys +- Validate all imported configuration files before use + +--- + +## Commit Guidelines + +We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. + +### Format + +``` +(): + +[optional body] + +[optional footer(s)] +``` + +### Types + +| Type | Description | +|------|-------------| +| `feat` | New feature | +| `fix` | Bug fix | +| `docs` | Documentation changes only | +| `style` | Code style changes (formatting, no logic change) | +| `refactor` | Code change that neither fixes a bug nor adds a feature | +| `perf` | Performance improvement | +| `test` | Adding or updating tests | +| `chore` | Build process, dependency updates, tooling | +| `ci` | CI/CD configuration changes | +| `revert` | Reverts a previous commit | + +### Scope (optional) + +Use the affected component: `service`, `ui`, `protocol`, `tools`, `config`, `build` + +### Examples + +```bash +feat(protocol): add VLESS protocol support with XTLS + +fix(service): resolve crash when switching protocols during active connection + +docs(readme): add VLESS configuration example and URI format + +perf(wireguard): reduce CPU usage by batching keepalive packets + +refactor(tools): extract IP geolocation logic into dedicated class + +chore(deps): bump OkHttp from 4.11.0 to 4.12.0 + +fix(ui): correct dark theme colors on ServerListScreen + +feat(tools): add QR code scanner for config import +``` + +### Short Description Rules + +- Use imperative mood: "add" not "added" or "adds" +- No capital letter at start +- No period at the end +- Maximum 72 characters +- Be specific: "fix WireGuard reconnect on network switch" not "fix bug" + +--- + +## Pull Request Process + +### Before Opening a PR + +1. **Sync with upstream** to avoid conflicts: + ```bash + git fetch upstream + git rebase upstream/main + ``` + +2. **Test your changes** thoroughly on a real device if possible + +3. **Run the full check suite:** + ```bash + ./gradlew check lint assembleDebug + ``` + +4. **Self-review** your diff before submitting — check for debug code, TODOs, or accidental changes + +### PR Title and Description + +Use the same format as commit messages for the PR title. + +The PR description should include: + +```markdown +## Summary +Brief explanation of what this PR does and why. + +## Changes +- List of specific changes made +- ... + +## Testing +- [ ] Tested on physical device (Android X.X) +- [ ] Tested on emulator (API XX) +- [ ] Existing features not broken +- [ ] New feature works as expected + +## Screenshots (if UI changes) +Before | After +-------|------ +[img] | [img] + +## Related Issues +Fixes #123 +Closes #456 +``` + +### Review Process + +1. A maintainer will review your PR within a few days +2. Address any requested changes promptly +3. Keep the PR focused — one feature/fix per PR +4. Don't force-push after review has started (use new commits instead) +5. PRs are merged with squash-merge to keep history clean + +### Checklist Before Submitting + +- [ ] Branch is up to date with `main` +- [ ] Code follows the project's style guidelines +- [ ] No hardcoded secrets, API keys, or passwords +- [ ] New features are documented +- [ ] Existing README sections updated if behavior changed +- [ ] Build passes (`./gradlew assembleDebug`) +- [ ] Lint passes (`./gradlew lint`) +- [ ] App tested on device/emulator +- [ ] Commit messages follow the convention +- [ ] PR description is complete + +--- + +## Reporting Bugs + +Use the [GitHub Issues](https://github.com/0xgetz/AeroVPN/issues) page to report bugs. Before opening a new issue: + +1. **Search existing issues** to avoid duplicates +2. **Try the latest version** — the bug may already be fixed +3. **Reproduce the bug** consistently + +### Bug Report Template + +```markdown +**Bug Description** +A clear and concise description of what the bug is. + +**Steps to Reproduce** +1. Go to '...' +2. Tap on '...' +3. See error + +**Expected Behavior** +What you expected to happen. + +**Actual Behavior** +What actually happened. + +**Environment** +- AeroVPN version: [e.g., 1.0.0] +- Android version: [e.g., Android 13] +- Device model: [e.g., Samsung Galaxy S21] +- Protocol used: [e.g., WireGuard] + +**Logs** +If applicable, export logs from Settings → Export Logs and attach here +(redact any personal information first). + +**Screenshots** +If applicable, add screenshots to help explain the problem. +``` + +--- + +## Requesting Features + +Feature requests are welcome! Use [GitHub Issues](https://github.com/0xgetz/AeroVPN/issues) with the `enhancement` label. + +### Feature Request Template + +```markdown +**Feature Description** +A clear description of the feature you'd like to see. + +**Problem it Solves** +What problem does this feature address? Who would benefit? + +**Proposed Solution** +If you have ideas about implementation, describe them here. + +**Alternatives Considered** +Any alternative approaches you've considered. + +**Additional Context** +Screenshots, mockups, or references to similar features in other apps. +``` + +--- + +## Security Vulnerabilities + +**Do not open a public GitHub issue for security vulnerabilities.** + +If you discover a security vulnerability in AeroVPN, please report it responsibly: + +1. Go to the repository's **Security** tab on GitHub +2. Click **Report a vulnerability** +3. Fill in the details of the vulnerability + +Or contact the maintainers directly through the contact information in the repository. + +**What to include:** +- Description of the vulnerability +- Steps to reproduce +- Potential impact +- Suggested fix (if you have one) + +We aim to respond to security reports within 48 hours and will credit reporters in our security advisories (unless you prefer to remain anonymous). + +--- + +## Translations + +AeroVPN aims to support multiple languages. To add or improve a translation: + +1. Navigate to `app/src/main/res/` +2. Create a new values directory for your language: + - `values-id/` for Indonesian (Bahasa Indonesia) + - `values-de/` for German + - `values-fr/` for French + - `values-ja/` for Japanese + - etc. (use [BCP 47 language tags](https://tools.ietf.org/html/bcp47)) +3. Copy `values/strings.xml` into the new directory +4. Translate the string values (keep the string names unchanged) +5. Submit a PR with the new translation file + +**Translation guidelines:** +- Translate the values, not the keys +- Keep format specifiers (`%1$s`, `%d`) in the correct position +- Maintain the same tone (concise, technical but accessible) +- If unsure about a term, keep the English term with a local transliteration +- Mark any strings you're unsure about with `` + +--- + +## Questions? + +If you have questions not covered in this guide: + +- Check the [README](README.md) for project overview and documentation +- Open a [GitHub Discussion](https://github.com/0xgetz/AeroVPN/discussions) for general questions +- Browse [closed issues](https://github.com/0xgetz/AeroVPN/issues?q=is%3Aissue+is%3Aclosed) for past answers + +--- + +**Thank you for contributing to AeroVPN!** + +Every contribution, no matter how small, helps make privacy and internet freedom more accessible to everyone. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8b942c7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 AeroVPN Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/app/build.gradle b/app/build.gradle index 834ff94..e7eda7a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,7 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' - id 'org.jetbrains.kotlin.plugin.compose' + id 'com.google.devtools.ksp' // Fix #14: KSP for Room annotation processing } android { @@ -40,12 +40,13 @@ android { compileOptions { // Use Java 17 for better performance - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + coreLibraryDesugaringEnabled true // Fix #15: enables Java 8+ APIs on older Android versions + sourceCompatibility JavaVersion.VERSION_1_8 // Fix #15: lowered for coreLibraryDesugaring compatibility + targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = '17' + jvmTarget = '1.8' // Fix #15: match sourceCompatibility // Enable compose compiler options freeCompilerArgs += [ '-opt-in=androidx.compose.material3.ExperimentalMaterial3Api', @@ -129,29 +130,36 @@ dependencies { // Room Database (if local storage needed) implementation 'androidx.room:room-runtime:2.6.1' implementation 'androidx.room:room-ktx:2.6.1' - annotationProcessor 'androidx.room:room-compiler:2.6.1' + ksp 'androidx.room:room-compiler:2.6.1' // Fix #14: replaced annotationProcessor with ksp // VPN Libraries - // WireGuard - implementation 'com.wireguard:wireguard:0.0.10' + // WireGuard - Fix #19: official WireGuard Android tunnel library + implementation 'com.wireguard.android:tunnel:1.0.20230705' - // JSCH for SSH - implementation 'com.jcraft:jsch:0.1.55' + // JSCH for SSH - Fix #16: upgraded from 0.1.55 to mwiede fork with security fixes + implementation 'com.github.mwiede:jsch:0.2.16' - // V2Ray core (via local AAR or build from source) - // implementation files('libs/v2ray-core.aar') + // V2Ray core - Fix #18: use tun2socks + v2ray-core via JitPack + implementation 'com.github.2dust:v2rayNG:1.8.19' + // Fallback: implementation files('libs/v2ray-core.aar') // Shadowsocks library - implementation 'com.github.shadowsocks:shadowsocks-libev:3.3.5' + // implementation 'com.github.shadowsocks:shadowsocks-libev:3.3.5' // not available on jitpack // Image Loading - Coil implementation 'io.coil-kt:coil-compose:2.5.0' // Utility libraries implementation 'androidx.preference:preference-ktx:1.2.1' - implementation 'com.google.accompanist:accompanist-systemuicontroller:0.33.2-alpha' + // Fix #17: removed accompanist-systemuicontroller — use WindowInsetsController native API instead implementation 'com.google.accompanist:accompanist-permissions:0.33.2-alpha' + // Fix #22: MultiDex support + implementation 'androidx.multidex:multidex:2.0.1' + + // Fix #15: required for coreLibraryDesugaringEnabled + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' + // Testing testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f55a68..a8d5fe8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,8 +17,6 @@ - - @@ -93,7 +91,6 @@ android:description="@string/app_description" android:usesCleartextTraffic="false" android:networkSecurityConfig="@xml/network_security_config" - android:enableOnBackInvokedCallback="true" tools:targetApi="34"> diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml index a709f1d..0bc821b 100644 --- a/app/src/main/res/xml/data_extraction_rules.xml +++ b/app/src/main/res/xml/data_extraction_rules.xml @@ -1,25 +1,38 @@ + - + - + - - + + + + - + + + + diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index f1bfff2..74ef964 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -1,32 +1,19 @@ + - + - + - - - - + + + - - localhost - 127.0.0.1 - 10.0.2.2 - - - - - - - - - diff --git a/build.gradle b/build.gradle index fb32f14..7f1fcc1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,10 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - ext.kotlin_version = '1.9.22' - repositories { - google() - mavenCentral() - maven { url 'https://jitpack.io' } - } - dependencies { - classpath 'com.android.tools.build:gradle:8.2.2' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} plugins { id 'com.android.application' version '8.2.2' apply false id 'com.android.library' version '8.2.2' apply false id 'org.jetbrains.kotlin.android' version '1.9.22' apply false - id 'org.jetbrains.kotlin.plugin.compose' version '2.0.0' apply false + id 'com.google.devtools.ksp' version '1.9.22-1.0.17' apply false // Fix #14: KSP plugin for Room } tasks.register('clean', Delete) { diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html new file mode 100644 index 0000000..28d346b --- /dev/null +++ b/build/reports/problems/problems-report.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..82cf835 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..486dc59 --- /dev/null +++ b/gradlew @@ -0,0 +1,190 @@ +#!/bin/sh +# +# 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. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# Gradle startup script for UN*X +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( absolute + *) app_path=$APP_HOME$link ;; #( relative + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + ;; + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # temporary variables we created. + # zsh is a bit stricter about the length of this arrangement. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-evaluated before use., and +# * put everything else in single quotes, so that it's not re-evaluated. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# temporary variable we created earlier: +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^a-zA-Z0-9/=@._-]~\\&~g; ' | + tr '\n' ' ' + ) $@" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9dccd53 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@ +@rem Gradle startup script for Windows +@ +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this process. +set DEFAULT_JVM_OPTS="--add-opens=java.base/java.util=ALL-UNNAMED" "--add-opens=java.base/java.lang=ALL-UNNAMED" "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED" "--add-opens=java.prefs/java.util.prefs=ALL-UNNAMED" "--add-opens=java.base/java.nio.charset=ALL-UNNAMED" "--add-opens=java.base/java.net=ALL-UNNAMED" "--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED" "-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega