diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..93453c0 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +## [Unreleased] + +- Native Android HTTPS onboarding, origin-bound browsing, session persistence, + recovery, server erasure, camera/document selection, downloads and blob exports. +- SwiftUI/WKWebView iOS implementation, isolated web sign-in, native settings, + recovery, file export, and strict URL/metadata policies; Xcode validation pending. +- JVM, Android emulator, portable Swift, and real pinned-upstream HTTPS tests. +- Reproducible build configuration, CI and maintainer-controlled signing workflow. +- MIT licensing, upstream audit, security model and release documentation. + +No stable release has been published. No native push or browser-to-app session +handoff is claimed. See validation records for what has actually been executed. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4a370c1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing + +This is an independent mobile repository, not the upstream Yuvomi project. +Discuss substantial changes with the community maintainer before submitting a PR. +Do not open upstream issues or submit upstream patches on somebody else's behalf. + +Use `feat/`, `fix/`, or `docs/` branches and Conventional Commits. Keep commits +reviewable and scoped. Preserve existing work. Run the relevant tests, lint, +`python3 scripts/check-repository.py`, and `git diff --check` before committing. +Add regression tests with security fixes, and demonstrate that the test fails +without the fix. Do not commit build outputs, credentials, private signing keys, +local servers, generated fixture certificates, or production household data. + +Keep platform integrations native and dependencies minimal. The server owns +business logic, authentication, CSRF, and authorization. Never solve compatibility +by disabling TLS, accepting every origin, or copying a browser's session cookies. +Upstream prohibits frontend frameworks, bundlers, and transpilers in its own +codebase; we make no changes to it. Read its CONTRIBUTING, SECURITY, and DESIGN +before proposing an upstream integration. + +This code was drafted with OpenAI through OpenCode. Disclose AI assistance in PRs +(one sentence is sufficient), as upstream requests. Generated code and automated +reviews do not replace human review. No merge, release, public issue, or store +publication happens automatically. Security-sensitive code needs human review. + +See `docs/build-android.md`, `docs/build-ios.md`, and `docs/validation.md`. +The portable Swift package checks shared production policy, not the iOS app. diff --git a/README.md b/README.md index 020e353..c7d5aa2 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ reconnect or erase local browsing data and switch installations. - [Android build](docs/build-android.md) / [iOS build](docs/build-ios.md) - [Compatibility and authentication](docs/server-compatibility.md) - [Release process](docs/release-process.md) +- [Maintainer continuation](docs/continuation.md) MIT licensed. Upstream notices are preserved in `THIRD_PARTY_NOTICES.md`. This implementation is AI-assisted (OpenAI via OpenCode) and requires human security diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..590df6f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,69 @@ +# Security policy + +**Development software: no production-readiness claim.** Only the current +development branch is maintained; no stable mobile release exists yet. + +Do not post vulnerabilities, cookies, private URLs, household records or keys in a +public issue. Contact the community repository's owner through an established +private channel or enable the host's private vulnerability-reporting mechanism +before public distribution. No private reporting mailbox has been supplied; we +will not invent one. If none is available, request a private contact without +including exploit details. Upstream Yuvomi vulnerabilities belong in +[upstream's private reporting channel](https://github.com/ulsklyc/yuvomi/security/advisories/new), +not its public issue tracker. This project cannot promise upstream response times. + +Include affected app/OS/WebView/server versions, reproduction steps, impact, +and a minimal sanitized demonstration. Never include real credentials. + +## Security model + +- The user selects one HTTPS origin, including its port. A valid TLS chain is + required. No certificate-error bypass, HTTP production mode, or custom scheme + handler exists. Use a VPN for private-network access. +- Main application navigation is origin-bound. Android also blocks cross-origin + subresource and POST requests before the network. External links need a native + choice; dangerous URI schemes are rejected. No exported deep-link receiver exists. +- No `addJavascriptInterface` bridge or native credential store. Android blob + exports capture at most 25 MB / eight same-origin Blob references using an + origin-restricted document-start script, then pull bounded chunks with + `evaluateJavascript` only after a user chooses a destination. Every pull + rechecks origin and lifecycle. No blob fetch or CSP relaxation is used. +- WebView/WKWebView owns persistent HttpOnly session cookies. Native code neither + handles passwords nor bypasses the server's CSRF rules. Native Android download + code obtains a cookie snapshot only for the configured origin and refuses redirects. +- Live microphone, geolocation and media-capture requests are denied. The trusted + app's file input uses explicit system pickers; Android image capture delegates + to the camera app with a narrowly scoped content URI and no broad storage access. +- External SSO uses a separate capability-restricted web view and the same OS + website cookie store. It does not gain app navigation/file handlers. iOS 18.4+ + is required so uploads can be explicitly denied in that untrusted auth window. +- Android backups/device transfer are excluded and screenshots are blocked. + iOS hides content when inactive and excludes temporary exports from backups. + OS-managed WKWebView storage remains governed by iOS device/backup protection; + do not assume the app can exclude every WebKit-managed cookie from an OS backup. +- Server changes stop and destroy the old web context and erase website data. + Older Android engines that lack complete browsing-data deletion use an OS + app-data reset, which closes the app. A local wipe is not remote session revocation. +- No app logs contain passwords, tokens, cookie headers or raw network exceptions. + System/browser diagnostics are outside the app's complete control. + +## Limitations and release gates + +The configured server and any server-installed extension are trusted same-origin +code. An XSS or malicious administrator remains able to act as the signed-in user; +native origin checks cannot fix compromised application content. Structural metadata +probing does not authenticate the Yuvomi product or expose an anonymous version number. +Embedded SSO providers that reject web views need a browser session instead; no +secure native-session handoff exists upstream. A future handoff needs upstream +review and single-use, short-lived, session-bound exchange semantics. + +Downloaded files saved by the user remain outside app erasure. Android network +downloads are capped at 100 MB / 120 seconds; generated blob exports at 25 MB / +45 seconds. iOS checks declared size before downloads and actual size before +export (100 MB); an unknown/chunked size may consume disk before rejection. +This resource-limit gap requires review and device testing before release. + +Android WebView Safe Browsing remains enabled. The installed engine/OS may perform +its own security checks; this app does not implement or log those network services. +Keep the OS and WebView patched. OSV advisory checks are build-time, never runtime, +and do not prove the absence of vulnerabilities. See `docs/security-review.md`. diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index c49df12..5a30dde 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -31,3 +31,23 @@ SOFTWARE. Android build dependencies retain their own licenses (Android SDK/platform APIs, AndroidX: Apache-2.0; Kotlin: Apache-2.0; Gradle: Apache-2.0). Apple system frameworks are provided by the operating system, not vendored here. + +## Gradle wrapper notice + +The unmodified official Gradle wrapper JAR retains `META-INF/LICENSE` (Apache-2.0). +The corresponding Gradle distribution NOTICE is reproduced below: + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). + +It includes the following other software: + +Groovy (http://groovy-lang.org) +SLF4J (http://www.slf4j.org) +JUnit (http://www.junit.org) +JCIFS (http://jcifs.samba.org) +HttpClient (https://hc.apache.org/httpcomponents-client-4.5.x/) + +For licenses, see the LICENSE file supplied in the Gradle distribution. +If any software distributed with Gradle does not have an Apache 2 License, its +license is explicitly listed in that distribution's LICENSE file. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..8cccbe8 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,41 @@ +# Architecture + +Two independent native applications share a policy, not a cross-platform runtime: + +| Responsibility | Android | iOS | +| --- | --- | --- | +| Native entry/configuration | ComponentActivity and platform widgets | SwiftUI | +| Web application | Android WebView | WKWebView | +| Server URL policy | ServerAddress | ServerAddress | +| Reachability/metadata | HttpsURLConnection, no redirects/cookies | Ephemeral URLSession, no redirects/cookies | +| Authentication | Upstream web UI and OS cookie jar | Upstream web UI and WKWebsiteDataStore | +| OIDC | Separate restricted web view after consent | Separate restricted web view after consent | +| Downloads | Origin-bound streaming / bounded blob capture and pull | WKDownload to temporary protected file, system export | + +The client never reimplements a Yuvomi module or introduces a backend. The user +selects the origin. Bootstrap calls check the actual upstream unauthenticated +metadata contract before loading the server application. Configuration stores only +the origin and a query/fragment-free last path; auth/reset/invite routes are not +restored. No native password or API-token storage exists. + +The current web view remains alive across background/resume and ordinary rotation. +Android handles orientation changes in the existing activity; process recreation +loads the remembered path and retains OS cookies, not unsaved web form memory. +iOS retains a StateObject-owned view; cold launch restores path and persistent +cookies. No resume reload is imposed. Native recovery offers Retry, Keep viewing, +and server management without hiding the route back to configuration. + +Server erasure destroys the browsing context and clears all website storage before +another server is loaded. The local wipe does not invalidate the remote session; +logout is still a server-side operation. Web application history remains native +web history. External schemes, universal links and app links are not registered +because arbitrary self-hosted domains cannot be verified by this app in advance. + +The optional integration build has a different Android package ID and adds trust +for a fresh test CA generated outside the repository. It uses the same production +code and the unmodified pinned upstream server. Neither normal debug nor release +resources include that CA. Never distribute an integration APK. + +Read-only offline functionality belongs to upstream's service worker. The app +preserves it where the platform engine supports it, but does not promise offline +editing, synchronization, or the same PWA cache behavior on all OS versions. diff --git a/docs/build-android.md b/docs/build-android.md new file mode 100644 index 0000000..824076c --- /dev/null +++ b/docs/build-android.md @@ -0,0 +1,67 @@ +# Android development + +Requirements: JDK 17, Android SDK platform 37.0, build-tools 36.0.0, current +platform-tools, and accepted Android SDK licenses. Minimum Android 8 (API 26). +Use a maintained Android System WebView. Target API 37. On Android 17, choose +"Allow private-network servers" when using a LAN instance; public HTTPS servers +do not need this optional runtime permission. No discovery/scanning is performed. + +```sh +export ANDROID_HOME=/path/to/android-sdk +bash android/gradlew -p android testDebugUnitTest lintDebug lintRelease assembleDebug assembleRelease bundleRelease +bash android/gradlew -p android connectedDebugAndroidTest +``` + +Gradle 9.6.0 is checksum-verified by the wrapper. AGP 9.4.1 uses built-in Kotlin +with the build-cache fix in KGP 2.4.21. Maven versions are locked. No dynamic +application dependencies or private Maven repository is required. + +Ordinary outputs: + +- `android/app/build/outputs/apk/debug/app-debug.apk` (development-signed) +- `android/app/build/outputs/apk/release/app-release-unsigned.apk` +- `android/app/build/outputs/bundle/release/app-release.aab` (unsigned unless signed later) +- `android/app/build/reports/` (lint, JVM and emulator results) + +Immediately after building, collect and inspect the outputs: + +```sh +python3 scripts/collect-android-artifacts.py +``` + +This writes ignored `artifacts/android/` copies, `SHA256SUMS`, source identity and +manifest/network-policy/signature evidence. It requires `ANDROID_HOME` and respects +`YUVOMI_BUILD_DIR`. Source identity records the checkout at collection time; always +rebuild immediately beforehand and use a clean worktree for a release candidate. + +The unsigned release cannot be installed/published as-is. See release signing +instructions. `gradle-wrapper.jar` is the standard generated Gradle bootstrap +binary; it is intentionally versioned, unlike generated APKs or caches. + +On WSL/Windows mounts that reject POSIX metadata operations, put outputs on the +Linux filesystem: + +```sh +export YUVOMI_BUILD_DIR="$HOME/yuvomi-build" +bash android/gradlew -p android testDebugUnitTest assembleDebug +``` + +The application never permits HTTP, including debug builds. Use real HTTPS for +manual development. For a temporary local HTTPS integration environment: + +```sh +git clone --filter=blob:none https://github.com/ulsklyc/yuvomi.git /path/to/upstream +git -C /path/to/upstream checkout 10bfef7686ed7303b4c74c7fcc55a5eb16356c9d +npm ci --omit=dev --prefix /path/to/upstream +python3 scripts/test-integration.py /path/to/upstream --android +``` + +Requires Node 22.14+ and a running emulator. The harness creates and removes its +own CA/key/database, uses `adb reverse`, and builds `.integration` with explicit +test trust. It does not weaken production TLS. Test credentials are ephemeral. +Keep test reports private if you customize the harness with real data (not advised). + +For dependency updates run `:app:dependencies --write-locks`, the full pipeline, +and `python3 scripts/check-dependencies.py`. Review lockfile changes. The version +update lint recommendations are informational, not suppressed correctness errors; +OSV checks independently fail on known advisories. diff --git a/docs/build-ios.md b/docs/build-ios.md new file mode 100644 index 0000000..9e227d0 --- /dev/null +++ b/docs/build-ios.md @@ -0,0 +1,39 @@ +# iOS development + +Requires macOS, Xcode 16.4 or newer with an iOS simulator, and XcodeGen 2.44.1. +Minimum iOS/iPadOS 18.4: the auth window must be able to deny native file-panel +requests, which earlier WKWebView delegates cannot do. No CocoaPods or external +runtime package is required. For App Store submission use Apple's currently +required Xcode/iOS SDK, not merely the oldest compiler that can build the source. + +```sh +bash scripts/install-xcodegen.sh "$HOME/.local/yuvomi-xcodegen" +"$HOME/.local/yuvomi-xcodegen/xcodegen/bin/xcodegen" generate --spec ios/project.yml +device=$(python3 scripts/select-simulator.py) +xcodebuild -project ios/Yuvomi.xcodeproj -scheme Yuvomi \ + -destination "platform=iOS Simulator,id=$device" CODE_SIGNING_ALLOWED=NO test +xcodebuild -project ios/Yuvomi.xcodeproj -scheme Yuvomi \ + -destination 'generic/platform=iOS' -archivePath artifacts/Yuvomi-unsigned.xcarchive \ + CODE_SIGNING_ALLOWED=NO archive +``` + +`project.yml` is the source of truth. The Xcode project and generated Info.plist +are ignored. The XcodeGen download is version- and SHA256-pinned. The project +includes a privacy manifest, camera/photo/local-network usage strings, universal +app icon, orientation support, unit and UI test targets, and no ATS exception. + +On macOS or Linux with Swift 6 installed: + +```sh +swift test --package-path ios +swiftc -frontend -parse ios/Sources/*.swift ios/Tests/*.swift ios/UITests/*.swift +``` + +These portable tests compile the **production URL/metadata policies only**. +Parsing does not typecheck UIKit, SwiftUI or WebKit APIs. Neither command is +evidence that the iOS application builds. Actual Xcode testing is mandatory. + +For a device build select your authorized development team in Xcode, use your own +registered bundle identifier, and let Xcode manage development provisioning. +Never commit generated profiles or certificates. See `release-process.md` for +distribution. A Linux environment cannot produce a validated iOS archive. diff --git a/docs/continuation.md b/docs/continuation.md new file mode 100644 index 0000000..9eb0f9f --- /dev/null +++ b/docs/continuation.md @@ -0,0 +1,77 @@ +# Maintainer continuation + +This is a development delivery, not authorization to publish. Preserve the Git +history on `feat/yuvomi-mobile`; use Conventional Commits and normal pushes only. +The authorized community remote is `https://git.nesterovic.cc/nessi/Yuvomi-App`. +Do not push, submit issues or open pull requests against upstream on this task's +behalf. No production credentials or store accounts have been provided. + +## Start with the evidence + +Read [validation](validation.md), [security review](security-review.md), and +[release gates](release-process.md). Do not repeat completed implementation work +or equate portable Swift checks with an iOS app build. Inspect `git status` before +editing; preserve any newer maintainer changes. + +The upstream reference is Yuvomi 2.78.0 at +`10bfef7686ed7303b4c74c7fcc55a5eb16356c9d`. Keep it unmodified. Subpath hosting, +browser-to-native OIDC handoff and native remote push are not implemented. + +The extended API 35 HTTPS suite passes all seven tests, including the local-IdP +round trip, native transfers, recovery and back navigation. Portable Swift has +seven passing policy tests; the separate JUnit verifier has eight regressions. +Keep the fixture's scope separate from real-provider or Apple-platform validation. + +## Persistent local environment (Linux/WSL) + +- Repository: `/mnt/c/Users/neste/Documents/GIT/Yuvomi-App`. +- Upstream and installed dependencies: `/home/neste/yuvomi-tools/upstream`. +- SDK: `/home/neste/yuvomi-tools/android-toolchain/android-sdk`. +- Build outputs/logs: `/home/neste/yuvomi-build`. +- Swift 6.2.1: `/home/neste/yuvomi-tools/swift-6.2.1-RELEASE-ubuntu24.04/usr/bin`. +- Swift compatibility libraries: `/home/neste/yuvomi-tools/compat/usr/lib/x86_64-linux-gnu`. +- Swift scratch output: `/home/neste/yuvomi-swift-build`. +- ktlint and actionlint: `/home/neste/yuvomi-tools/ktlint.jar` and + `/home/neste/yuvomi-tools/actionlint`. +- Local collected artifacts/evidence: ignored `artifacts/android/`. + +`/tmp/opencode` is temporary and was cleared by server restarts. Background +processes may also disappear. Keep durable logs under `/home/neste`; never persist +the integration fixture's generated private CA, keys or real household data. + +```sh +export ANDROID_HOME=/home/neste/yuvomi-tools/android-toolchain/android-sdk +export YUVOMI_BUILD_DIR=/home/neste/yuvomi-build +"$ANDROID_HOME/platform-tools/adb" devices -l +"$ANDROID_HOME/platform-tools/adb" shell am get-started-user-state 0 +# Require RUNNING_UNLOCKED, then: +python3 scripts/test-integration.py /home/neste/yuvomi-tools/upstream --android +bash android/gradlew -p android testDebugUnitTest lintDebug lintRelease assembleDebug assembleRelease bundleRelease +python3 scripts/collect-android-artifacts.py +``` + +The API 35 AVD is `yuvomi-test`. Its stable attempt uses KVM, `-gpu host`, +`-no-window -no-audio -no-boot-anim -no-snapshot -memory 2560 -cores 2`. +Launch under the SDK/AVD owner with access to the `kvm` group. Other GPU modes +previously crashed the host emulator with SIGSEGV. API 37 had broken services and +locked credential-encrypted storage; no API 37 runtime success is claimed. + +For portable Swift checks add the compiler directory to `PATH` and set +`LD_LIBRARY_PATH` to the compatibility-library directory above, then use the +commands in [iOS development](build-ios.md). Apple application/XCTest/UI/archive +validation must happen on macOS with Xcode and real supported devices. + +## Highest-priority external work + +1. Typecheck/build the iOS app against Apple SDKs, run its actual XCTest/UI tests, + and produce an unsigned archive. Fix any failures; none of these ran locally. +2. Run the API 37 permission grant/denial/revocation scenarios on a working image + or device, plus the minimum-supported Android and current WebView matrix. +3. Review iOS unknown-length download disk-pressure handling before release. +4. Validate real supported IdPs, TOTP after SSO, linking, cancellation, native + file/camera pickers, process death, accessibility and offline account isolation. +5. Establish private vulnerability reporting, owned identifiers, authorized CI, + human security review and owner-controlled signing before any distribution. + +The provided GitHub Actions workflows do not automatically execute on the current +non-GitHub forge. Do not claim hosted CI or store readiness without actual runs. diff --git a/docs/release-process.md b/docs/release-process.md new file mode 100644 index 0000000..bba4ede --- /dev/null +++ b/docs/release-process.md @@ -0,0 +1,72 @@ +# Release process + +No release is authorized by the existence of these scripts. No workflow publishes +to either store. A debug APK or unsigned archive is not a production release. + +1. Complete every outstanding gate in `validation.md` and `security-review.md`. + Obtain independent human review of authentication, navigation, file handlers, + local erasure and privacy disclosures. Run actual supported device/OS tests. +2. Resolve bundle/application identifier ownership. `community.yuvomi.mobile` is + a provisional community identifier, not proof of registry/store ownership. + Confirm use of the Yuvomi name, required attribution and independent status. +3. Bump version/name/code in Android and the iOS project spec; update CHANGELOG. +4. Run JVM/emulator/real-upstream HTTPS tests, portable Swift and Xcode simulator + tests, static checks, OSV scan, release builds and artifact inspection. Record + upstream revision, app SHA, OS/WebView/Xcode versions, results and checksums. +5. Produce signed artifacts only using an authorized maintainer's credentials. +6. Review store privacy/Data Safety answers for the app AND selected-server model, + permission rationale, encryption/export compliance, screenshots, support URL, + vulnerability contact, and device demonstrations. A functional web companion + is not guaranteed to pass Apple's minimum-functionality review. +7. Create a release/tag and publish artifacts/store submissions manually only + after explicit maintainer authorization. Never force-push or rewrite history. + +## Android + +The manual `release.yml` workflow uses a protected GitHub environment named +`release`. Configure branch restrictions and required reviewers before adding +secrets. With `sign_android=false` it emits unsigned artifacts. Signing requires: + +- `ANDROID_KEYSTORE_BASE64` +- `ANDROID_STORE_PASSWORD` +- `ANDROID_KEY_PASSWORD` +- `ANDROID_KEY_ALIAS` + +The workflow uses `zipalign`, `apksigner`, and `jarsigner`; private material exists +only in a restrictive runner-temporary file removed on exit. Securely back up the +real upload key and use Play App Signing according to the owner's policy. No +production key is generated here. Manually verify APK/AAB signatures and inspect +the final manifest: no debuggable flag, HTTP/test CA or unintended exported component. +Never distribute an `.integration` package or include its generated test resources. +Run `python3 scripts/collect-android-artifacts.py` immediately after the clean-source +build to inspect unsigned outputs and record local hashes/source identity. This +collector intentionally rejects signed release outputs; collect before signing. + +## iOS + +The CI archive is unsigned and cannot be uploaded to App Store Connect. An owner +needs Apple Developer Program membership, a registered app ID, distribution +certificate/private key, provisioning profile and App Store Connect permissions. + +Generate/open the project, choose the authorized team, set the owned bundle ID, +select a physical/generic iOS destination, and use Product -> Archive. Validate +the archive in Organizer and export using the owner's distribution method. For +CLI export use a **locally supplied** ExportOptions.plist with the correct team, +method and provisioning mappings: + +```sh +xcodebuild -exportArchive -archivePath artifacts/Yuvomi.xcarchive \ + -exportPath artifacts/ios -exportOptionsPlist /secure/path/ExportOptions.plist +``` + +Do not add distribution certificates, profiles, App Store keys or passwords to the +repository. Device camera, Files, VoiceOver, memory pressure and app-switcher +privacy need physical-device validation beyond simulator tests. + +## CI hosting + +GitHub Actions files are provided, but the configured community remote is hosted +on a different forge. GitHub workflows will not automatically run there. Enable +an authorized GitHub mirror/repository (or port the jobs to the forge's runner) +and inspect real runs before claiming CI is operational. No destination is +created automatically. CI service availability is not an application dependency. diff --git a/docs/security-review.md b/docs/security-review.md new file mode 100644 index 0000000..151be0b --- /dev/null +++ b/docs/security-review.md @@ -0,0 +1,47 @@ +# Security review record + +This is an engineering review, not an independent penetration test or certification. + +Addressed during implementation: + +- Canonical, HTTPS-only origin/port comparison; credential, fragment, query, + subpath, scheme, lookalike-host and TLS-downgrade regression cases. +- A main-frame POST can bypass Android's usual navigation callback. The request + interception gate now rejects **all** cross-origin requests, not only subresources. + The emulator regression was observed failing when the main-frame guard was + deliberately removed, then rerun with the fix restored. +- TLS failures cancel by default. Native download redirects are refused before + cookies can be replayed to another origin. Bootstrap requests use neither + cookies nor automatic redirects and have bounded metadata reads/timeouts. +- Files use explicit system selection/content URIs; no filesystem or storage + permission is granted to web content. Blob exports have no native JS bridge. +- Complete Android browsing-data deletion uses WebStorageCompat, with OS app + reset for engines without that capability. WebStorage.deleteAllData alone was + insufficient for service-worker CacheStorage/IndexedDB and is not relied upon. +- iOS server erase replaces the WKWebView, not only its URL, eliminating old + history/back-forward contexts as well as persistent website data. +- iOS metadata uses typed decoding, rejecting numeric values masquerading as booleans. +- Native picker results are bound to the browsing generation/request. Android + rejects stale upload/download selections, revokes camera URI grants, and clears + capture cache on erasure. iOS ignores export-cancellation callbacks from an old + download. Apple-specific callback regressions have not run without Xcode. +- KGP was upgraded after OSV identified CVE-2026-53914 in the original build tool. + The final OSV scan found no listed advisories across 213 locked/direct Maven + coordinates and build plugins. Rescan after resolution/lock updates. +- The inspected release APK is not debuggable, rejects cleartext, disables backup + and trusts system CAs only. AndroidX's exported profile installer receiver is + protected by the system DUMP permission; app providers are not exported. + +Release gates still requiring evidence: + +- Actual Xcode typecheck, simulator, archive, physical-device and accessibility review. +- End-to-end IdP flows, especially providers that prohibit embedded agents; no + browser-to-native session transfer is supported by the current upstream protocol. +- iOS unknown-length download disk-pressure behavior; a post-download size check + is not a streaming quota. Verify file picker/camera cancellation on real devices. +- Android file-picker/camera/rotation while a picker is outstanding; cancellation + on process death intentionally loses the selection, never silently retries it. +- Offline sign-out/account switching, stale-worker updates and server erasure on + current WebView/WKWebView versions. Upstream tests are not native device proof. +- Reverify final signed release manifests, signing, store ownership, private vulnerability contact + and applicable privacy disclosures. No claim that all vulnerabilities are absent. diff --git a/docs/server-compatibility.md b/docs/server-compatibility.md new file mode 100644 index 0000000..596d1fe --- /dev/null +++ b/docs/server-compatibility.md @@ -0,0 +1,70 @@ +# Server compatibility and authentication + +Source reference: upstream 2.78.0 revision +`10bfef7686ed7303b4c74c7fcc55a5eb16356c9d`. No general version range has been +certified. Anonymous bootstrap metadata deliberately omits the exact version; +native probing verifies shape, not an invented minimum-version comparison. + +Use `https://family.example.com` or `https://family.example.com:8443`, backed by a +root-hosted Yuvomi installation and a valid system-trusted certificate. Operators +should set `SESSION_SECURE=true`, correct `BASE_URL`, and correct proxy trust. +Private servers are supported through reachable HTTPS/VPN, not TLS bypasses. +International hostnames should be entered in ASCII/punycode for both platforms. + +Root-relative assets, API endpoints, cookie paths, callback redirects and worker +registration mean `/yuvomi/` subpaths are not supported by the inspected source. +Use a dedicated hostname. Reverse proxies must pass `/api/v1/*`, cookies, HTML, +JavaScript and the service worker consistently. An external authentication proxy +that intercepts bootstrap calls is rejected with a connection error; it is not +silently identified as a Yuvomi server. + +## Authentication + +Password login, TOTP/recovery codes, password reset, invitations, server-side +session expiry/revocation and logout remain upstream web flows. No native code +stores the password, supplies a CSRF bypass, or extends an expired session. +Backgrounding does not clear cookies. Native server erasure does not revoke a +remote session; use Yuvomi logout first or revoke sessions server-side. + +### OIDC: local fixture verified; real-provider validation pending + +The initiating Yuvomi session contains OIDC state, nonce and PKCE verifier. When +the server redirects to an identity provider, native consent offers an isolated +web sign-in window sharing the OS website cookie store. HTTPS-only redirects +can return to the server callback; the final same-origin page returns to the main +view. No app-capability handlers or JS bridge are installed in that auth window. + +Some providers (including configurations that prohibit embedded user agents) +require a system browser. **Those cannot sign the native view in with upstream's +current protocol.** Use Server settings -> Open server in browser, and sign in +there for an independent browser session. Opening only the external authorization +link in a browser does not transfer the initiating cookie. Browser cookies are +never copied into the app, and custom-scheme callbacks are not fabricated. + +The API 35 integration suite completes a native isolated-window round trip with +a local test IdP, real RS256 ID tokens, nonce and S256 PKCE. No external +IdP/developer account was supplied. Validate the actual provider, including +cross-site cookies, cancellation, errors, TOTP and account linking, before relying +on that deployment. iOS authentication has not run against Apple SDKs. A native +browser handoff would require an independently reviewed upstream protocol; no +such upstream change is included or published. + +Android generated exports require a current WebView supporting document-start +scripts and are capped at 25 MB. A bounded Blob registry preserves a generated +file even when upstream immediately revokes its object URL; it does not fetch +blob URLs or alter the server's CSP. HTTPS file downloads are capped at 100 MB. +Update the system WebView if generated exports are unavailable on an old engine. + +## Notifications and offline + +Upstream implements Web Push and optional ntfy/Gotify/webhook/email channels. +Embedded web views do not supply a portable native push subscription. This app +has **no native remote-push claim**, no Firebase/APNs secrets, no background +polling service, and no fake notification-registration UI. Configure an existing +optional upstream ntfy/Gotify channel and its client if desired. No centralized +service is required by this application. + +Upstream service-worker caching is read-only, allow-listed, and versioned. +Mutations/authentication remain online. Platform-specific cache/resume behavior +and offline account switching still need device validation. Do not rely on offline +editing, synchronization, or closed-app push in this native development build. diff --git a/docs/validation.md b/docs/validation.md new file mode 100644 index 0000000..a7dc442 --- /dev/null +++ b/docs/validation.md @@ -0,0 +1,130 @@ +# Validation status + +**Partially verified development software, not production-ready.** +Local validation date: 2026-10-21. No unexecuted iOS application test, hosted CI +run, production signing, or store publication is represented as completed. + +## Executed evidence + +- Android debug APK and unsigned release APK/AAB built successfully; both + `lintDebug` and `lintRelease` passed. JVM security/picker-policy tests: **7 passed, + zero failures/skips**. +- Android API 35 regular emulator suite: **6 passed, zero failures/skips**. + This covers onboarding, invalid URLs, background/resume, hardened settings, + cross-origin POST/subresource isolation, opaque-page Blob rejection and activity + recreation. Its permission test checks that the API 37 permission UI is absent; + it is **not** evidence of API 37 permission grant/denial behavior. +- Unmodified pinned upstream ran behind a temporary HTTPS reverse proxy. + Bootstrap metadata, password login, Secure/HttpOnly/SameSite cookies, persistent + session, CSRF rejection, logout/revocation passed in the harness. +- Android's extended real-server scenario exercises login, HttpOnly cookies, + document upload via upstream fetch, native FileTransfer output, bounded Blob + export, background/resume, recreation, CSRF-protected logout, revocation, + recovery, isolated OIDC return and back navigation. It does not automate the OS + camera/document destination picker or prove every upstream module works. + Two consecutive API 35 runs have **7 passed, zero failures/skips each**, including the + six regular security/onboarding cases and this real-server scenario. +- The cross-origin POST regression was deliberately observed failing without its + guard. The production guard was restored and the API 35 regression passes. +- Portable Swift production-policy tests: 7 passed (URL and typed metadata). + All Swift sources passed format lint and parsing with Swift 6.2.1 on Linux. + The portable package excludes BrowserModelTests. This does not build iOS. +- Selected upstream suites ran successfully: cookie-secure-flag (4), + session-sliding (8), two-factor (22), password-reset (24), sw-api-cache (42). + Upstream's plain OIDC script also exited successfully. These are upstream tests, + not evidence of a provider round-trip or native push support. +- The HTTPS harness independently passed upstream OIDC discovery, RS256 ID-token + signature/nonce validation, S256 PKCE exchange and session creation with a local + test IdP. The fixture checks single-use codes, exact redirect URIs and OAuth + Basic client authentication. Loopback hosts/ports and automatic fixture consent + are not representative of every provider's cross-site/embedded-agent policies. +- OSV: no listed advisories for **213** locked/direct Maven coordinates and build + plugins at scan time. This is not a guarantee that no vulnerabilities exist. +- ktlint 1.7.1, actionlint 1.7.7, repository invariants, Python compilation, + Node syntax and shell syntax checks passed. JUnit-verifier regression suite: + **8 passed**, including rejection of absent, empty, malformed, insufficient, + failed, errored and skipped evidence. +- Release APK inspection confirms API 26 minimum / API 37 target, no debuggable + flag, backups and cleartext disabled, system-only certificate trust. Exported + entry points are the launcher and AndroidX ProfileInstallReceiver protected by + the system DUMP permission; file/startup providers are not exported. Debug APK + signature verifies; release APK/AAB are unsigned. Collected archives contain no + fixture CA/key or signing-key files. + +## Emulator limitations and retry evidence + +Earlier extended-suite attempts crashed the host emulator with SIGSEGV under +software/off GPU modes. Host-GPU mode remained running and produced actionable +JUnit failures: an OIDC-return synchronization timeout, followed by an outage +assertion that incorrectly assumed the upstream worker could not serve its cached +app shell, then a document-readiness race after recreation. Tests now verify the +loaded JavaScript origin, wait for the sign-in window to close, retry only a probe +lost to document replacement and exercise recovery through uncached metadata. +The completed retry passes all seven tests without disabling the worker or +weakening production TLS/CSP/origin policies. + +API 37 attempts encountered broken package/activity services and locked +credential-encrypted storage. **No API 37 runtime pass is claimed.** + +Local logs and reports live in `/home/neste/yuvomi-build/`; test XML is under +`app/outputs/androidTest-results/connected/`. Earlier failing JUnit snapshots are +preserved as `integration-host-gpu-oidc-race.xml` and +`integration-host-gpu-sw-cache.xml`, plus +`integration-host-gpu-document-ready.xml`. Passing evidence is preserved in +`integration-api35-first-pass.xml` and `integration-api35-repeat-pass.xml`; logs are +`upstream-integration-final-retry.log` and `upstream-integration-repeat.log`. +These files are local evidence, not published +artifacts or a hosted CI result. + +Test environment: JDK 17.0.20.1, Node 22.22.1, Python 3.14.4, Android Emulator +37.2.12, API 35 x86_64 Google APIs image, WebView 124.0.6367.219. The old bundled +WebView is useful compatibility evidence, not a recommendation to use an unpatched +engine; a current engine/device run remains mandatory. + +## Artifacts + +Ignored `artifacts/android/` contains the development-signed debug APK and unsigned +release APK/AAB, `SHA256SUMS`, `build-info.json` and manifest/policy/signature +inspection evidence. No integration APK is collected. No IPA or Apple archive +exists. See [Android build](build-android.md) for repeatable collection commands. + +## Commands + +```sh +bash android/gradlew -p android testDebugUnitTest lintDebug lintRelease assembleDebug assembleRelease bundleRelease connectedDebugAndroidTest +python3 scripts/test-integration.py /path/to/pinned-upstream --android +swift test --package-path ios +swiftc -frontend -parse ios/Sources/*.swift ios/Tests/*.swift ios/UITests/*.swift +python3 scripts/check-repository.py +python3 scripts/check-dependencies.py +python3 scripts/test-verifier.py +python3 scripts/collect-android-artifacts.py +git diff --check +``` + +This environment is Linux/WSL. Android SDK and a KVM emulator were installed for +real execution. Build output relocation was needed because the Windows mount +rejects some Gradle POSIX metadata operations. Swift's Linux toolchain was +installed for portable tests. No macOS, Xcode, Apple simulator or physical device +is available; no iOS build/archive/UI result is claimed. + +## Mandatory remaining evidence + +- Run Xcode build, XCTest/UI tests and unsigned archive on macOS; fix any compiler + or runtime issues. The app has **not** yet been typechecked against Apple SDKs. +- Validate real IdPs: cancellation, account linking, TOTP after OIDC, and embedded + provider policy. Browser-only providers have no native-session handoff upstream. +- Real-device camera/document picker cancellation, file MIME cases, rotation with + an outstanding picker, network loss/reconnect, process kill/memory pressure, + session expiry/revocation, OS backup, and offline account isolation. +- Android 17 private-network permission grant/denial/revocation on a matching OS. + Also run minimum-supported API 26 and a current OS/WebView device matrix. +- VoiceOver/TalkBack, large text, contrast, keyboard/safe areas, reduced motion, + light/dark appearance and responsive web modules on actual supported devices. +- Operational CI runs on an authorized GitHub repository/runner, private security + reporting contact, human security review, store ownership and production signing. + +No Firebase/APNs registration, closed-app push, offline editing, App Store approval, +signing, publication or physical-device validation is claimed. See `SECURITY.md` +and `docs/security-review.md` for residual limitations. +Resume work using [maintainer continuation](continuation.md).