From 33214dc83d56312ca79a37b2ec7f9f1d296b511c Mon Sep 17 00:00:00 2001 From: Pranavkumar Patel Date: Sat, 3 Oct 2026 09:55:34 -0400 Subject: [PATCH 1/2] Vouch for the app's signing keys, so its links open it The site now answers /.well-known/assetlinks.json with com.gridpointcode and the keys it may be signed with: the three Google holds for the app, as Play Console's Android developer verification lists them, the app signing key among them, and the upload key, so a release signed here and installed by hand verifies too. Until now the file was an empty list, and a link to gridpointcode.com/play opened in the browser. audit/assetlinks.py passes: the site vouches for com.gridpointcode signed with four keys, and the app's manifest asks it to. The README's note that verified links waited for the key moves out of Not here yet, and PLAY.md's checklist marks the step done. --- android/PLAY.md | 12 ++++---- android/README.md | 41 +++++++------------------- web/public/.well-known/assetlinks.json | 18 ++++++++++- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/android/PLAY.md b/android/PLAY.md index 422faa8..0368050 100644 --- a/android/PLAY.md +++ b/android/PLAY.md @@ -30,12 +30,14 @@ changes that page in the same pull request; it changes the - [ ] **Play App Signing.** Google keeps the key the app is signed with for readers; this repository's four upload values (see [A release](README.md#a-release)) only prove an upload came from its owner. -- [ ] **Verified links.** Copy the SHA-256 of the app signing key from Setup, - App signing, into +- [x] **Verified links.** [`web/public/.well-known/assetlinks.json`](../web/public/.well-known/assetlinks.json) - as [Not here yet](README.md#not-here-yet) shows, merge, and let the site - deploy before the first install anyone keeps: a device that checked before the - file was right keeps its answer until the app is installed again. + names the three keys Play Console's Android developer verification lists for + `com.gridpointcode`, and the upload key. The app signing key under Test and + release, App integrity, App signing must be one of the three; if Play ever + shows another, it goes in beside them. Let the site deploy before the first + install anyone keeps: a device that checked before the file was right keeps + its answer until the app is installed again. - [ ] **The bundles.** `./gradlew :app:bundleRelease :wear:bundleRelease :automotive:bundleRelease` with the four upload values set. All three share the application ID, so each upload needs its own version code; the ranges are diff --git a/android/README.md b/android/README.md index 27536da..bc3f417 100644 --- a/android/README.md +++ b/android/README.md @@ -519,12 +519,17 @@ kilobytes. **A link opens the app only when the site says so.** The filter for `https://gridpointcode.com/play` asks Android to verify it, and Android asks the site, which answers at `/.well-known/assetlinks.json` with the app's package -name and its signing key. Until that names the key, a link does what it does -today: from Android 12 it opens in the browser unless the reader turns on the -app's links in its settings, and before that it asks. Both ends are held together by -[`audit/assetlinks.py`](../audit/assetlinks.py) in CI, because either one wrong -fails without a sound: the link opens in the browser, and the device keeps that -answer until the app is installed again. +name and the keys it may be signed with. Those are the three Google holds for +the app, as Play Console's Android developer verification lists them, the app +signing key among them, and the upload key, so a release signed here and +installed by hand verifies too. A device that checked before the file named them +keeps its answer until the app is installed again; after that, `adb shell +pm get-app-links com.gridpointcode` says `verified` for `gridpointcode.com`. +Without it, from Android 12 a link opens in the browser unless the reader turns +on the app's links in its settings, and before that it asks. Both ends are held +together by [`audit/assetlinks.py`](../audit/assetlinks.py) in CI, because +either one wrong fails without a sound: the link opens in the browser, and the +device keeps that answer until the app is installed again. **What the app sends is on the site's privacy page.** Three hosts, the tile provider, this site's own files and GitHub's release downloads for a country's @@ -639,27 +644,3 @@ app's is 29, the oldest release the car's template host runs on. ## Not here yet The headset module, which waits for Jetpack XR to be stable. - -Verified links are built and wait only for the key: the app signing key Google -holds once the app is created in Play Console, under Setup, App signing. Its -SHA-256 fingerprint goes into -[`web/public/.well-known/assetlinks.json`](../web/public/.well-known/assetlinks.json), -which is an empty list until then: - -```json -[ - { - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "com.gridpointcode", - "sha256_cert_fingerprints": ["14:6D:E9:..."] - } - } -] -``` - -A release signed with the upload key and installed by hand verifies too if that -key's fingerprint is added beside it. Once the site has deployed, a fresh -install verifies, and `adb shell pm get-app-links com.gridpointcode` says -`verified` for `gridpointcode.com`. diff --git a/web/public/.well-known/assetlinks.json b/web/public/.well-known/assetlinks.json index fe51488..cc87b21 100644 --- a/web/public/.well-known/assetlinks.json +++ b/web/public/.well-known/assetlinks.json @@ -1 +1,17 @@ -[] +[ + { + "relation": [ + "delegate_permission/common.handle_all_urls" + ], + "target": { + "namespace": "android_app", + "package_name": "com.gridpointcode", + "sha256_cert_fingerprints": [ + "81:FA:A3:B1:0D:4E:5E:A4:19:AA:06:08:8A:FB:14:79:74:35:7C:85:99:46:E5:18:AC:4A:52:A2:84:E6:BD:A9", + "F5:DF:36:39:15:5D:99:AE:3C:0F:1F:7C:4C:D1:8A:02:10:A8:D9:F1:B4:27:82:0C:C4:F4:42:43:F9:C5:00:65", + "2B:FF:F9:E7:9C:B1:D7:33:D5:98:FC:F4:BA:DA:29:58:C5:37:C6:05:F5:EF:E7:5F:61:32:B6:38:7D:05:EE:A0", + "DB:42:9E:40:51:66:72:90:AC:56:BB:99:A9:A0:0B:61:0B:85:7C:A0:7A:FB:A9:E1:75:5C:4D:B0:B0:70:A8:C5" + ] + } + } +] From 39da2bd067ac5dd621a4b22eff7c013e1c34c7e0 Mon Sep 17 00:00:00 2001 From: Pranavkumar Patel Date: Sat, 3 Oct 2026 10:10:53 -0400 Subject: [PATCH 2/2] Say why the app has three signing keys Play signs a new app with quantum-ready hybrid signing: a classical key for devices before Android 17, and a classical and a post-quantum key together from Android 17. All three are app signing keys, which is why Android developer verification lists three, and Google's help asks for all three in assetlinks.json, as the file already has them. The README and PLAY.md now say so, and give the page Play Console shows them on. --- android/PLAY.md | 14 ++++++++------ android/README.md | 10 ++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/android/PLAY.md b/android/PLAY.md index 0368050..b6c9c84 100644 --- a/android/PLAY.md +++ b/android/PLAY.md @@ -32,12 +32,14 @@ changes that page in the same pull request; it changes the [A release](README.md#a-release)) only prove an upload came from its owner. - [x] **Verified links.** [`web/public/.well-known/assetlinks.json`](../web/public/.well-known/assetlinks.json) - names the three keys Play Console's Android developer verification lists for - `com.gridpointcode`, and the upload key. The app signing key under Test and - release, App integrity, App signing must be one of the three; if Play ever - shows another, it goes in beside them. Let the site deploy before the first - install anyone keeps: a device that checked before the file was right keeps - its answer until the app is installed again. + names the app's three app signing keys and the upload key. Play signs a new + app with quantum-ready hybrid signing: a classical key for devices before + Android 17, and a classical and a post-quantum key together from Android 17. + Play Console shows them under Protected with Play, Play Store distribution, + Play app signing, and Android developer verification lists the same three. + If Play ever adds a key, it goes in beside them. Let the site deploy before + the first install anyone keeps: a device that checked before the file was + right keeps its answer until the app is installed again. - [ ] **The bundles.** `./gradlew :app:bundleRelease :wear:bundleRelease :automotive:bundleRelease` with the four upload values set. All three share the application ID, so each upload needs its own version code; the ranges are diff --git a/android/README.md b/android/README.md index bc3f417..62d7d28 100644 --- a/android/README.md +++ b/android/README.md @@ -519,10 +519,12 @@ kilobytes. **A link opens the app only when the site says so.** The filter for `https://gridpointcode.com/play` asks Android to verify it, and Android asks the site, which answers at `/.well-known/assetlinks.json` with the app's package -name and the keys it may be signed with. Those are the three Google holds for -the app, as Play Console's Android developer verification lists them, the app -signing key among them, and the upload key, so a release signed here and -installed by hand verifies too. A device that checked before the file named them +name and the keys it may be signed with. Play signs a new app with +quantum-ready hybrid signing, so it has three app signing keys: a classical one +for devices before Android 17, and from Android 17 a classical and a +post-quantum one signing together. All three are listed, as Google's help asks, +and the upload key with them, so a release signed here and installed by hand +verifies too. A device that checked before the file named them keeps its answer until the app is installed again; after that, `adb shell pm get-app-links com.gridpointcode` says `verified` for `gridpointcode.com`. Without it, from Android 12 a link opens in the browser unless the reader turns