QR enrollment: scan a TAK/ATAK enrollment QR (tak://...enroll)#101
Merged
Conversation
…..enroll) Onboard OmniTAK to a standard TAK Server (ArgusTAK / ATAK / TAK Server) by scanning its enrollment QR. Closes #100. The QR format is the de-facto ATAK enrollment deep link: tak://com.atakmap.app/enroll?host=<host>[:port]&username=<u>&token=<t> host is frequently URL-encoded (host=argustak.com%3A8089); username/token are one-time CSR-enrollment credentials. AndroidManifest: register the `tak` scheme (VIEW + BROWSABLE) alongside the existing atak/omnitak so a QR scanned with the OS camera app opens OmniTAK. DeepLinkImport: add isEnrollLink + parseEnrollLink, distinct from the existing connect form. Splits the URL-decoded host:port (connection port, default 8089), maps token -> the CSR Basic-auth secret, and derives a SEPARATE enrollment port (default 8446, overridable via enrollport=) since TAK Server enrolls on a different port than it streams on. A malformed port after the colon is stripped from the host rather than poisoning DNS. MainActivity: route enroll deep links to the existing CSR enrollment service (checked before the connect-form matcher so an atak://.../enroll link enrolls rather than being added cert-less), mirroring EnrollServerScreen's success path — add the TAKServer with the signed .p12 + pinned CA, auto-connect. ServersScreen: add a "Scan QR" action that opens a full-screen CameraX/MLKit scanner (the proven config-profile scanner pipeline, lifted into a reusable ServerQrScanScreen), decodes the enroll/connect link, and runs the same enroll/connect flow. CAMERA permission handled in-screen. Full-screen route, never a map-compressing panel. Tests: DeepLinkEnrollTest covers the host:port split (incl. IPv6, malformed ports) and the enroll-link detect/parse (Uri-based cases skip on the JVM stub, matching ConfigProfileTest's convention).
The tak://...enroll deep-link path built the TAKServer without caCertificateName, so the connection fell back to the system trust store and failed CertPathValidator against a private-CA server (ArgusTAK: 'Trust anchor for certification path not found'). Set caCertificateName from the enrollment result, matching EnrollServerScreen and ServerQrScanScreen. Verified on-device: now logs 'TLS trust: pinned CA(s)' and 'Connected to argustak.com:8089 (tls=true)'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #100.
Onboard OmniTAK to a standard TAK Server (ArgusTAK / ATAK / TAK Server) by scanning its enrollment QR. Before this, the deep-link handler only accepted
atak://…connect?host=/omnitak://server?…(and explicitly rejected other schemes), and the only in-app QR scanner was for config-profile sync — there was no path to enroll against a standard server QR.The QR format
The de-facto ATAK enrollment deep link:
hostis frequently URL-encoded (e.g.host=argustak.com%3A8089).username+tokenare one-time CSR-enrollment credentials.Changes per area
AndroidManifest.xml — register the
takURL scheme (VIEW + BROWSABLE) alongside the existingatak/omnitak, so a QR scanned with the OS camera app opens OmniTAK.data/DeepLinkImport.kt — added
isEnrollLink+parseEnrollLink, distinct from the existing connect-form parser:host:port→ connection host + connection port (default 8089),token→ the CSR Basic-auth secret (carried inImportedServerConfig.password, whichCSREnrollmentServicesends as HTTP Basic auth),enrollport=/enrollmentport=,splitHostPortstrips a malformed/out-of-range port from the host rather than poisoning DNS; handles IPv4 and bracketed IPv6.MainActivity.kt — route enroll deep links to the existing
CSREnrollmentService(checked before the connect-form matcher, so anatak://…/enrolllink enrolls instead of being added cert-less and rejected at the mTLS handshake). MirrorsEnrollServerScreen's success path: add theTAKServerwith the signed.p12+ pinned CA, auto-connect.ui/screens/ServerQrScanScreen.kt (new) — full-screen CameraX/MLKit scanner, lifting the proven config-profile scanner pipeline into a reusable, parameterized component (generic
acceptpredicate +onScanned).ServerEnrollScanRoutepairs it with the enroll/connect flow. Full-screen route, never a map-compressing panel; CAMERA permission handled in-screen.ui/screens/ServersScreen.kt + ui/navigation/AppNav.kt — add a "Scan QR" action (top bar) →
servers/scanroute →ServerEnrollScanRoute. This is the reliable on-ramp that does not depend on the OS camera app routing thetak://scheme back to us.test/…/DeepLinkEnrollTest.kt (new) — covers
splitHostPort(host:port, bare host, trailing colon, non-numeric / out-of-range port, IPv4, bracketed IPv6) and the enroll-link detect/parse. TheUri-based cases useassumeTrueto skip on the JVMUri.parsestub (no Robolectric on the classpath) — same convention asConfigProfileTest.Verify
./gradlew assembleDebug→ BUILD SUCCESSFUL.:app:testDebugUnitTest --tests DeepLinkEnrollTestgreen (host:port tests run; Uri tests skip on JVM stub).Assumptions to verify on device (ArgusTAK)
/Marti/api/tls/config+/Marti/api/tls/signClient/v2(existingCSREnrollmentService). ArgusTAK may colocate enrollment on the 8089 connection port or another port — if so, the QR needsenrollport=(now supported) or ArgusTAK's actual port confirmed.host/username/token(withpasswordtolerated as a token fallback). Confirm ArgusTAK's QR uses exactly these.trust=caon the link for strict validation.tak://OS-camera deep link depends on no other installed app claiming the scheme. Recommend leading with the in-app scanner in docs/onboarding.Note: a separate, unrelated in-progress "Import Data Package (.zip)" change exists in the working tree on another branch and is intentionally not part of this PR.