SHA256
fix(android): retain HTTPS sessions with upstream default cookie flags
Reproduce browser-success/native-401 with unmodified upstream SESSION_SECURE=false behind HTTPS. Keep cookies in the existing HTTPS-only origin-bound encrypted jar regardless of the server Secure attribute; preserve TLS, redirect, expiry and origin protections. Distinguish credential/2FA rejection from missing/rejected session handoff and clear stale login errors on retry. Verify 13 JVM tests plus the 7-test real-server suite in both Secure/default-cookie modes, including bad-password then successful native login. Bump Android preview to 0.2.1/code 3; extend CI and document the defect without claiming access to the user's production server.
This commit is contained in:
1 parent
129eac675c
commit
4b483c20e3
16 files changed
+220
-22
No files matched your search
@@ -8,7 +8,7 @@ window around that website. Both shipping entry points now render native views:
|
||||
| Screens and navigation | Jetpack Compose / Material 3 primitives, Yuvomi tokens | SwiftUI, Yuvomi tokens |
|
||||
| Application state | AndroidViewModel + Compose state | MainActor ObservableObject |
|
||||
| JSON API | HttpsURLConnection, serialized worker | URLSession actor, bounded streaming delegate |
|
||||
| Session ownership | Explicit origin-bound secure-cookie jar | Private ephemeral URLSession cookie storage |
|
||||
| Session ownership | Explicit origin-bound HTTPS-only cookie jar | Private ephemeral URLSession cookie storage |
|
||||
| Persistent cookies | AES-GCM, AndroidKeyStore key, origin as authenticated data | Keychain, WhenUnlockedThisDeviceOnly, origin-scoped account |
|
||||
| Server logic | Existing unmodified Yuvomi API | Existing unmodified Yuvomi API |
|
||||
|
||||
@@ -34,6 +34,11 @@ navigation destinations. The other modules remain unfinished.
|
||||
Session-only cookies are not converted to long-lived cookies.
|
||||
- Native UI mutations wait for the server result. Permissions remain enforced
|
||||
server-side; sparse module/widget permissions also control native affordances.
|
||||
- Android's native jar enforces HTTPS itself rather than rejecting a valid server
|
||||
cookie solely because its `Secure` attribute is absent. This supports upstream's
|
||||
default session settings behind HTTPS proxies without permitting HTTP or
|
||||
cross-origin cookie replay. Browser cookie configuration remains the server
|
||||
operator's responsibility; `SESSION_SECURE=true` is recommended for HTTPS sites.
|
||||
- Local removal clears the native cookie vault and in-memory records. It is not
|
||||
remote revocation. Logout attempts server revocation and still erases the local
|
||||
session if the server cannot be reached.
|
||||
|
||||
@@ -62,6 +62,7 @@ git clone --filter=blob:none https://github.com/ulsklyc/yuvomi.git /path/to/upst
|
||||
git -C /path/to/upstream checkout 10bfef7686ed7303b4c74c7fcc55a5eb16356c9d
|
||||
npm ci --omit=dev --prefix /path/to/upstream
|
||||
python3 scripts/test-integration.py /path/to/upstream --android
|
||||
python3 scripts/test-integration.py /path/to/upstream --android --cookie-without-secure
|
||||
```
|
||||
|
||||
Requires Node 22.14+ and a running emulator. The harness creates and removes its
|
||||
@@ -71,6 +72,11 @@ Keep test reports private if you customize the harness with real data (not advis
|
||||
The native test calls the real API through native controls and saves a synthetic
|
||||
dashboard screenshot under `app/build/outputs/native-screenshots/`. It does not
|
||||
demonstrate native SSO merely because the protocol fixture also tests OIDC.
|
||||
Both commands retain HTTPS and system/test-CA validation; the second reproduces
|
||||
upstream's default `SESSION_SECURE=false` cookie attributes behind an HTTPS proxy.
|
||||
The native jar must retain that session while continuing to forbid HTTP and
|
||||
cross-origin replay. The scenario also rejects a wrong password, then retries
|
||||
successfully without retaining the old error.
|
||||
The test writes through `PlatformTestStorageRegistry`; AGP collects the file in
|
||||
`outputs/connected_android_test_additional_output/integrationAndroidTest/` before
|
||||
uninstalling the fixture. The harness rejects missing/ambiguous output and removes
|
||||
|
||||
+13
-1
@@ -13,6 +13,18 @@ Read [native parity](native-parity.md), [architecture](architecture.md), and
|
||||
shopping slices exist, but **no module has accepted full visual/functional parity**.
|
||||
The remaining pages/settings/auth/file/offline/notification work is explicit.
|
||||
|
||||
### Android login follow-up: 0.2.1 native preview / code 3
|
||||
|
||||
A user reported immediate HTTP-401 login failure although the same direct password
|
||||
login works in the browser. Reproduced against unmodified upstream by setting its
|
||||
existing `SESSION_SECURE=false` default behind the HTTPS fixture: the old Android
|
||||
jar discarded the cookie and the next authenticated request failed. The fix keeps
|
||||
all native cookies HTTPS/origin-bound independent of that server attribute;
|
||||
certificate checks, redirect refusal, encryption and expiry are unchanged. Login
|
||||
errors now distinguish credential/code rejection from session-cookie problems and
|
||||
a successful retry clears the old error. Both secure/default-cookie test modes
|
||||
are in CI; see `login-troubleshooting.md` and the latest validation section.
|
||||
|
||||
The owner-authorized signing key and four Gitea secrets were created before this
|
||||
correction. Their private backup is `/home/neste/yuvomi-signing/initial-20261021`.
|
||||
Do not print its contents. Uncommitted signing changes are preserved in Git stash
|
||||
@@ -34,7 +46,7 @@ is not typechecked by Linux. Gitea's Mac job now bootstraps pinned Node before
|
||||
checkout, but actual Xcode results still need inspection. Ubuntu emulator jobs
|
||||
continue requiring accessible KVM; do not weaken or fake that evidence.
|
||||
|
||||
Latest local native evidence: 10 JVM tests, 6 API-35 Compose tests, 7 real-server
|
||||
Initial 0.2.0 local native evidence: 10 JVM tests, 6 API-35 Compose tests, 7 real-server
|
||||
instrumentation tests (including those same 6), both lint variants and native
|
||||
debug/unsigned release APK/AAB builds pass. Sixteen portable Swift tests and strict
|
||||
format/parsing pass. Screenshot export now uses AndroidX test storage/AGP output
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# Android native login: 0.2.1 preview fix
|
||||
|
||||
## Reproduced compatibility defect
|
||||
|
||||
The Android 0.2.0 native preview could show “Anmeldung oder Sitzung ist nicht mehr
|
||||
gültig” even when the identical direct username/password login worked in the PWA.
|
||||
Upstream defaults to `SESSION_SECURE=false`; an HTTPS reverse proxy does not by
|
||||
itself change this cookie attribute. The old native jar rejected the session
|
||||
cookie without `Secure`, so the successful login was followed by an unauthenticated
|
||||
API request. This was an app compatibility defect, not evidence of a bad password.
|
||||
|
||||
Android 0.2.1 native preview (version code 3) keeps the cookie in its existing
|
||||
HTTPS-only, origin/port-bound jar. It still never makes HTTP requests, follows
|
||||
redirects or shares cookies with another server. System TLS validation,
|
||||
AndroidKeyStore encryption and absolute expiry remain unchanged. The native client
|
||||
does not depend on weakening the server or changing its configuration. For browser
|
||||
security, server operators should still use `SESSION_SECURE=true` on HTTPS sites.
|
||||
|
||||
## Error distinctions
|
||||
|
||||
- Rejected username/password: the server rejected `/auth/login` with HTTP 401.
|
||||
- Invalid/expired second-factor step: the verification endpoint rejected the code
|
||||
or its pending session. Restart login if necessary.
|
||||
- Login confirmed but no usable cookie: inspect server/reverse-proxy cookie
|
||||
configuration; no password-reset claim is made.
|
||||
- Login confirmed but session rejected: inspect server/proxy session handling.
|
||||
|
||||
The app never displays raw cookie values, credentials or arbitrary server response
|
||||
bodies as diagnostics. A failed attempt's message is cleared after successful retry.
|
||||
If the updated app still fails, report the exact new message, app/server version,
|
||||
whether the direct browser password login works and whether 2FA is enabled.
|
||||
**Do not send passwords, session cookies, recovery codes or authentication tokens.**
|
||||
|
||||
## Reproduction and regression evidence
|
||||
|
||||
```sh
|
||||
python3 scripts/test-integration.py /path/to/pinned-upstream --android --cookie-without-secure
|
||||
python3 scripts/test-integration.py /path/to/pinned-upstream --android
|
||||
```
|
||||
|
||||
The first mode fails with the old native jar despite successful protocol-level
|
||||
browser login. After the fix, it passes native login, a wrong-password/correct-retry
|
||||
sequence, dashboard/recreation, task/note/shopping operations and logout. The normal
|
||||
Secure-cookie mode remains required too. These use synthetic temporary records and
|
||||
the unmodified pinned upstream, not the user's server or credentials.
|
||||
|
||||
Development APKs from different CI jobs can have different debug signing keys.
|
||||
If Android rejects an update as signature-incompatible, uninstall the old preview
|
||||
before installing the new one. This clears local app/session data and requires a
|
||||
fresh login; server household records are not deleted. Production signing remains
|
||||
paused and full native PWA parity is not implied by this fix.
|
||||
@@ -4,6 +4,11 @@
|
||||
This report closes the initial native rebuild slice, not the requested complete
|
||||
1:1 replacement. No module has accepted functional and visual parity.
|
||||
|
||||
**Follow-up:** Android 0.2.1 native preview (code 3) fixes a reproduced session-cookie
|
||||
login compatibility defect. See [login troubleshooting](login-troubleshooting.md)
|
||||
and the newer [validation evidence](validation.md); the original 0.2.0 results
|
||||
below remain historical evidence, not a replacement for the fixed APK.
|
||||
|
||||
## 1. Outcome
|
||||
|
||||
The rejected embedded-browser application has been replaced by genuine native
|
||||
|
||||
+27
-1
@@ -8,7 +8,33 @@ tests are in `androidTestNative` / `androidTestNativeIntegration`, JVM native po
|
||||
tests, and Swift production contracts/transport tests. Archived WebView tests are
|
||||
not included in the native suites or counted toward native completion.
|
||||
|
||||
## Executed locally — 2026-10-21
|
||||
## Android 0.2.1 / code 3: reproduced login regression
|
||||
|
||||
The user reported immediate login failure despite a working direct browser login.
|
||||
The root cause was reproduced using upstream's `SESSION_SECURE=false` default over
|
||||
HTTPS: browser/protocol login succeeded, but the old Android jar discarded the
|
||||
session cookie and its next authenticated API request failed. The fixed jar binds
|
||||
all cookies to HTTPS itself instead of requiring this optional server attribute.
|
||||
HTTP, cross-origin requests/redirects, invalid certificates, plaintext persistence
|
||||
and session-only cookie persistence remain disallowed.
|
||||
|
||||
- Before-fix failure retained in `/home/neste/yuvomi-login-cookie-before.log` and
|
||||
`/home/neste/yuvomi-login-cookie-before.xml` (synthetic fixture only).
|
||||
- After-fix upstream-default cookie mode: 7 instrumentation tests passed,
|
||||
zero failures/skips; complete harness exited successfully.
|
||||
- Secure-cookie mode: the same 7 tests passed, zero failures/skips.
|
||||
- Both modes test a rejected password followed by successful retry with no stale
|
||||
error, native dashboard/recreation, task/note/shopping calls and logout.
|
||||
- 13 JVM tests passed, including default-cookie persistence/deletion, expired/empty
|
||||
session detection and separate credential/2FA/session-handoff error messages.
|
||||
- Logs: `/home/neste/yuvomi-login-cookie-after.log`,
|
||||
`/home/neste/yuvomi-login-secure-after.log`, `/home/neste/yuvomi-login-unit.log`.
|
||||
|
||||
See [login troubleshooting](login-troubleshooting.md). This reproduces a matching
|
||||
compatibility defect without accessing the user's server or credentials; it does
|
||||
not claim inspection of that particular server's configuration.
|
||||
|
||||
## Initial 0.2.0 preview evidence — 2026-10-21
|
||||
|
||||
| Check | Observed result |
|
||||
| --- | --- |
|
||||
|
||||
Reference in new issue
Block a user