Skip to content

Make the update check immune to GitHub rate limiting, refresh the About icons - #203

Merged
Renakoni merged 3 commits into
mainfrom
fix/about-update-polish
Aug 8, 2026
Merged

Make the update check immune to GitHub rate limiting, refresh the About icons#203
Renakoni merged 3 commits into
mainfrom
fix/about-update-polish

Conversation

@Renakoni

@Renakoni Renakoni commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Findings from the owner's post-release phone test of v0.2.0, on the About page.

1. "Could not check updates (403)" — diagnosed, then solved outright

Diagnosis — environmental, not a client bug. The checker called GitHub's releases/latest API unauthenticated, which is limited to 60 requests/hour per source IP. The phone was on a VPN: the shared exit IP's pool was exhausted by other clients on that node, and GitHub answers 403. Evidence: the identical request from this machine returns 200 with X-RateLimit-Limit: 60, and the same build returned "latest version" on the emulator over a different egress. A public client cannot ship a token, so the API quota itself cannot be raised.

The complete fix — stop depending on the API at all. On Android the check now asks the native layer first: AppUpdateChecker (pure JVM over the existing HttpTransport seam, which already surfaces redirects unfollowed) issues one GET to github.com/…/releases/latest and reads the release tag from the Location header of the redirect. The web endpoint is not behind the API quota, so the check works on shared-egress networks where the API refuses. Hardening: refuses non-redirects, locationless responses, and any target outside this repository's tag page (the URL is later opened in a browser and must never be attacker-shaped); strips query/fragment, URL-decodes the tag, bounds the probe body at 64 KB.

Defense in depth kept. The API fetch remains the browser-shell path and the fallback for any native failure; there, 403/429 now maps to a localized rate-limit explanation (×10 locales) instead of a bare status code, and the releases-page link row appears after any failed check as the manual path.

Plumbing: UrlConnectionTransport moves out of CloudDocumentsPlugin into a shared package-private class; AndroidAppInfo gains getLatestRelease on a single-thread executor; the web wrapper (src/lib/androidAppInfo.ts) becomes the plugin's single registration point (Capacitor rejects duplicate names), and advancedDiagnostics reuses it.

2. About icons

  • External-link glyph: the old geometry ran the arrow strokes within ~1 SVG unit of the box outline; at 24 px with a 2.1 stroke the sub-stroke gaps fused into the smudge visible in the report. Redrawn with the conventional layout (box bottom-left, arrow exiting the open corner) — no stroke pair closer than 3 units.
  • GitHub row: the code-brackets glyph read as "source code", not GitHub; the row now carries the Octicons mark-github Octocat (MIT-licensed glyph; GitHub permits the mark as a link to a repository). Filled shape, so it opts out of the shared stroke styling at a balanced 24 px.

Verification

  • JVM: 121 green (+5 AppUpdateCheckerTest: redirect parse, relative-Location + query/fragment/URL-decode handling, refusal of the no-releases redirect and foreign hosts, refusal of non-redirect/locationless responses, bounded probe + Accept header).
  • Web: 684 tests green (+1 rate-limit mapping), vue-tsc -b + Vite build green, focused lint clean, locale contract satisfied.
  • e2e mobile-home-navigation 2/2 (browser shell keeps the fetch path: link hidden before a check, shown with the right href after a mocked available result).
  • Emulator (API 35, debug build): About → Check updates → "You are on the latest version" with logcat showing the AndroidAppInfo.getLatestRelease native call and zero api.github.com traffic — the tag came from the redirect. Screenshot-verified the Octocat row and the redrawn external-link glyph.

Notes

  • Current installs (v0.1.0/v0.2.0) still use the API path; their 403 clears when the VPN exit rotates or the hour window resets. From the next release on, the check no longer touches the API on devices.

- The About update check surfaced a bare "(403)" when GitHub rate limited
  the request. The unauthenticated API allows 60 requests/hour per IP, so
  a shared egress (VPN, CGNAT) exhausts the pool through no fault of the
  app; 403/429 now maps to a localized explanation, and the releases-page
  link shows after any failed check as the manual path — the web page is
  not behind the API rate limit.
- Redraw the external-link glyph on the About rows: the old geometry ran
  the arrow strokes within a sub-stroke distance of the box outline, so
  they fused at render size. The box now sits bottom-left with the arrow
  leaving through the open corner.
- The complete fix for the 403: on Android the update check now asks the
  native layer first, which reads the release tag from the Location
  header of the github.com releases/latest redirect. The web endpoint is
  not behind the GitHub API 60-requests/hour-per-IP quota, so the check
  keeps working on shared-egress networks where the unauthenticated API
  answers 403. The API fetch remains the browser-shell path and the
  fallback for any native failure, keeping the rate-limit message and
  the manual releases link as the last line.
- AppUpdateChecker is pure JVM over the HttpTransport seam (redirects
  already surface as-is): refuses non-redirects, locationless responses,
  and any target outside this repository tag page (the URL is opened in
  a browser and must never be attacker-shaped); strips query/fragment,
  decodes the tag, bounds the probe body. Five JVM tests.
- UrlConnectionTransport moves out of CloudDocumentsPlugin into a shared
  package-private class; AndroidAppInfo gains the getLatestRelease
  method on a single-thread executor, and the web wrapper becomes the
  single registration point for the plugin.
The code-brackets glyph read as "source code", not GitHub. The row now
carries the Octicons mark-github glyph (MIT; GitHub permits the mark as
a link to a repository). It is a filled shape, so it opts out of the
shared stroke styling and sits at 24px to balance the visual weight.
@Renakoni Renakoni changed the title Handle GitHub rate limiting in the update check, fix the link icon Make the update check immune to GitHub rate limiting, refresh the About icons Aug 8, 2026
@Renakoni
Renakoni merged commit ac8a936 into main Aug 8, 2026
7 checks passed
@Renakoni
Renakoni deleted the fix/about-update-polish branch August 8, 2026 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant