Android: old host name out of the pinned-root config and the S-1 fixture

- Pinned-root network security config (D-082) is now a template in
  app/src/releasePinnedRoot/; with kvitt.tls.pinnedRoot=true the task
  generatePinnedRootNetworkSecurityConfig writes it into the release
  resources with the domain kvitt.publicHost (D-121), and stops with a
  clear message while the root src/release/res/raw/kvitt_root_ca.crt is
  not committed (fallback unprepared, SPEC 10.5.3). Comment: pinned NPM
  root (D-120).
- Port 443 (D-124): RELEASE_SERVER_URL is https://<kvitt.publicHost>
  without a port (RELEASE_SERVER_PORT removed); the AC-2.6 intent filter
  has no android:port; InviteLink drops an explicit default port.
- S-1 fixture GOLDEN_SERVER https://kvitt.example.org; 28 S-1 goldens
  re-recorded (only the server row changed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-19 20:27:29 +02:00
parent 4852803cdb
commit 038c6036fe
40 changed files with 97 additions and 44 deletions
@@ -23,10 +23,11 @@ class AppLinksTest {
private val host = BuildConfig.PUBLIC_HOST
@Test
fun theReleaseServerIsHttpsOnPort8443OfThePublicHost() {
assertEquals("https://$host:8443", RELEASE_SERVER_URL)
fun theReleaseServerIsHttpsOnTheDefaultPortOfThePublicHost() {
// D-124: port 443, written without a port.
assertEquals("https://$host", RELEASE_SERVER_URL)
// Without kvitt.publicHost the build uses the placeholder, which never resolves (RFC 2606).
assertEquals("https://kvitt.example.invalid:8443", releaseServerUrl("kvitt.example.invalid"))
assertEquals("https://kvitt.example.invalid", releaseServerUrl("kvitt.example.invalid"))
}
@Test
@@ -37,8 +38,13 @@ class AppLinksTest {
0,
).any { it.activityInfo.name == "se.hagstedt.kvitt.MainActivity" }
assertTrue(opens("$RELEASE_SERVER_URL/i/ABCDEFGHJKMN"))
assertFalse(opens("https://other.example.org:8443/i/ABCDEFGHJKMN"))
assertFalse(opens("https://$host/i/ABCDEFGHJKMN"))
assertTrue(opens("https://$host/i/ABCDEFGHJKMN?from=Jacob"))
assertFalse(opens("https://other.example.org/i/ABCDEFGHJKMN"))
assertFalse(opens("http://$host/i/ABCDEFGHJKMN"))
assertFalse(opens("https://$host/apk/latest"))
// A filter without a port matches every port of the host (android:port="443" would match no link without an
// explicit port), so an old :8443 link still opens S-1, with the server the link names (AC-2.6).
assertTrue(opens("https://$host:8443/i/ABCDEFGHJKMN"))
}
@Test
@@ -50,13 +56,15 @@ class AppLinksTest {
@Test
fun appLinkNormalisesTheCode() {
// §8.3: lowercase, O -> 0, I and L -> 1.
assertEquals("ABCD0113EFGH", AppLinks.parseUri("kvitt://invite?server=https%3A%2F%2F$host%3A8443&code=abcdo1l3efgh")?.code)
assertEquals("ABCD0113EFGH", AppLinks.parseUri("kvitt://invite?server=https%3A%2F%2F$host&code=abcdo1l3efgh")?.code)
}
@Test
fun landingLinkFillsTheServerFromTheLink() {
val link = AppLinks.parseUri("$RELEASE_SERVER_URL/i/ABCDEFGHJKMN")
assertEquals(AppLink.Invite(RELEASE_SERVER_URL, "ABCDEFGHJKMN"), link)
// An explicit default port names the same server.
assertEquals(AppLink.Invite(RELEASE_SERVER_URL, "ABCDEFGHJKMN"), AppLinks.parseUri("https://$host:443/i/ABCDEFGHJKMN"))
}
@Test
@@ -67,7 +75,7 @@ class AppLinksTest {
)
assertEquals(
AppLink.Invite(RELEASE_SERVER_URL, "ABCDEFGHJKMN", "Jacob"),
AppLinks.parseUri("kvitt://invite?server=https%3A%2F%2F${host.replace(".", "%2E")}%3A8443&code=ABCDEFGHJKMN&from=Jacob"),
AppLinks.parseUri("kvitt://invite?server=https%3A%2F%2F${host.replace(".", "%2E")}&code=ABCDEFGHJKMN&from=Jacob"),
)
assertNull(AppLinks.parseUri("$RELEASE_SERVER_URL/i/ABCDEFGHJKMN")?.adminName)
}