[stealth 03/11] Stealth Lantern: randomize Android build identity#8781
[stealth 03/11] Stealth Lantern: randomize Android build identity#8781reflog wants to merge 15 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds build-time “identity profiles” for Stealth Android builds so each artifact can have a distinct install identity (applicationId, labels, scheme, icons, and various user-visible strings), while keeping normal builds on the existing Lantern identity.
Changes:
- Introduces a Python generator + unit tests to produce deterministic (seeded) or random Android identity
.propertiesprofiles. - Wires Android Gradle/manifest placeholders + BuildConfig fields to consume identity profile values (applicationId, labels, auth scheme, metadata, notification/tile strings, icons).
- Adds Make/CI/docs plumbing and neutral icon resources to support reproducible Stealth builds.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/stealth/generate_android_identity.py | Generates Android identity profiles (applicationId, labels, metadata, icons, strings). |
| scripts/stealth/generate_android_identity_test.py | Unit tests for deterministic/random generation and properties output. |
| Makefile | Adds identity profile generation and injects ANDROID_IDENTITY_PROFILE into Flutter Android builds. |
| docs/stealth-android-identity.md | Documents how to generate/use identity profiles and schema. |
| android/app/src/main/res/values/string.xml | Removes static app_name so Gradle resValue can control it per build. |
| android/app/src/main/res/drawable/neutral_notification_icon.xml | Adds neutral notification small icon vector. |
| android/app/src/main/res/drawable/neutral_app_icon.xml | Adds neutral app icon vector. |
| android/app/src/main/kotlin/org/getlantern/lantern/service/QuickTileService.kt | Uses BuildConfig-provided quick settings tile labels. |
| android/app/src/main/kotlin/org/getlantern/lantern/service/LanternVpnService.kt | Uses BuildConfig-provided VPN session name. |
| android/app/src/main/kotlin/org/getlantern/lantern/notification/NotificationManager.kt | Uses BuildConfig-provided notification strings + resolves small icon from BuildConfig. |
| android/app/src/main/AndroidManifest.xml | Switches app labels/icons/schemes to manifest placeholders; adds identity meta-data placeholders. |
| android/app/build.gradle | Loads identity profile, validates applicationId, sets manifest placeholders, resValue app_name, and BuildConfig fields. |
| .github/workflows/build-android.yml | Adds optional android_identity_seed input passed through to builds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
lib/lantern_app.dart:199
_buildPrivateServerAccessKey()now accepts anyAppBuildInfo.appAuthSchemeURI, but still normalizes the returned access key to a hardcodedlantern//...prefix and the comment/example also hardcodelantern://.... If the intention is to preserve the randomized scheme end-to-end (or to avoid leaking "lantern" into a user-visible access key), update the normalization and comment to useAppBuildInfo.appAuthScheme(or add an explicit comment explaining why thelantern//prefix must remain constant).
if (AppBuildInfo.isAppAuthUri(uri)) {
// lantern://private-server?key=value → lantern//private-server?key=value
var accessKey = 'lantern//${uri.host}';
if (uri.hasQuery) {
accessKey += '?${uri.query}';
}
return accessKey;
|
@copilot review |
Ran a fresh review pass on commit |
Adds scripts/stealth/generate_profile.py for private stealth-vpn/stealth-novpn
build profiles and wires profile values through Make targets, Flutter dart
defines, Android Gradle, manifest app label, session name, and Go build tags.
Key additions:
- generate_profile.py: validates/generates stealth profile JSON, emits
dart-defines and artifact metadata (seed redacted to hash only)
- Makefile: STEALTH_PROFILE_TOOL/ENV/DART_DEFINES/GO_TAGS variables, stealth-
profile target with incremental caching, wired into all platform build targets
- android/app/build.gradle: loadStealthProfile() with strict validation for
mode/packageName/appName/sessionName/denylistVersion; STEALTH_* BuildConfig
fields; dynamic applicationId from profile
- AndroidManifest.xml: ${appName} placeholder for manifest label
- LanternVpnService.kt: uses BuildConfig.STEALTH_SESSION_NAME
- app_build_info.dart: STEALTH_MODE/ENABLED/PACKAGE_NAME/APP_NAME/SESSION_NAME
compile-time constants; isStealthBuild helper
- docs/stealth-build-profile.md: profile generation guide
Conflict resolution notes (rebased onto main's arm64-only + sideload changes):
- Android build targets now have BOTH stealth wiring (STEALTH_PROFILE_ENV,
MAYBE_STEALTH_PROFILE, STEALTH_DART_DEFINES) AND main's -Plantern.sideloadUpdates=true
+ ANDROID_APK/AAB_TARGET_PLATFORMS variables
- build.gradle has BOTH sideload cert verification AND stealth profile loading
- abiFilters: arm64-v8a only (aligning with main's arm64-only direction)
Closes getlantern/engineering#3571
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Manifest: remove app.identity.{label,profile_id,metadata} meta-data tags
— these embedded identityMetadata (containing "android-identity-v1",
"source":"stealth-profile", profileMode, seedFingerprint) directly in
the shipped artifact, readable via aapt2 without decompilation. Traceability
belongs in the private support profile, keyed by build ID (QA policy #3576).
Generator: strip "generator"/"source"/"profileMode"/"seedFingerprint" from
identityMetadata output in both identity_from_profile() and generate_identity()
so no stealth-identifying strings land in BuildConfig.ANDROID_IDENTITY_METADATA.
The fallback scheme in generate_identity now uses "id" prefix instead of "stealth".
Normal builds unaffected: identity meta-data defaults were inert (Lantern/standard/{}).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ad2f3e4 to
72c39f0
Compare
Integration Notes for #8781 → Integration PR #8794These items require attention when integrating this branch: 1.
|
reflog
left a comment
There was a problem hiding this comment.
Addressing remaining review comments.
|
Superseded — the 11 per-issue stealth PRs were consolidated into a 6-PR stack for epic getlantern/engineering#3569. This work now lives in #8860. |
Summary
Dependency / non-goals
This closes getlantern/engineering#3566 for per-build install identity and native Android identity surfaces. Static inspection can still find source namespace/class/action strings such as org.getlantern and LanternVpnService until the manifest/source minimization work lands; this PR intentionally depends on getlantern/engineering#3571 for that broader minimization instead of expanding this branch.
Verification
Closes getlantern/engineering#3566