From ec0e8a980c817d620de8b5bbdae60abe49de6333 Mon Sep 17 00:00:00 2001 From: hdbg Date: Sun, 15 Mar 2026 14:51:39 +0100 Subject: [PATCH] feat(useragent): added connection info setup screen --- AGENTS.md | 128 ++ useragent/.dart_tool/package_config.json | 904 ---------- useragent/.dart_tool/package_graph.json | 1465 ----------------- useragent/.dart_tool/version | 1 - useragent/lib/features/arbiter_url.dart | 56 + .../lib/features/connection/connection.dart | 3 + useragent/lib/features/pk_manager.dart | 5 +- .../lib/features/server_info_storage.dart | 67 + useragent/lib/main.dart | 35 +- useragent/lib/providers/server_info.dart | 51 + useragent/lib/providers/server_info.g.dart | 102 ++ useragent/lib/router.dart | 5 +- useragent/lib/router.gr.dart | 45 +- useragent/lib/screens/bootstrap.dart | 4 +- useragent/lib/screens/dashboard/about.dart | 3 +- useragent/lib/screens/server_info_setup.dart | 284 ++++ .../ephemeral/Flutter-Generated.xcconfig | 13 - .../ephemeral/flutter_export_environment.sh | 14 - useragent/macos/Podfile | 2 +- useragent/macos/Podfile.lock | 2 +- .../macos/Runner.xcodeproj/project.pbxproj | 34 +- .../macos/Runner/DebugProfile.entitlements | 8 +- useragent/macos/Runner/Release.entitlements | 2 + useragent/pubspec.lock | 4 +- useragent/pubspec.yaml | 4 +- 25 files changed, 800 insertions(+), 2441 deletions(-) create mode 100644 AGENTS.md delete mode 100644 useragent/.dart_tool/package_config.json delete mode 100644 useragent/.dart_tool/package_graph.json delete mode 100644 useragent/.dart_tool/version create mode 100644 useragent/lib/features/arbiter_url.dart create mode 100644 useragent/lib/features/connection/connection.dart create mode 100644 useragent/lib/features/server_info_storage.dart create mode 100644 useragent/lib/providers/server_info.dart create mode 100644 useragent/lib/providers/server_info.g.dart create mode 100644 useragent/lib/screens/server_info_setup.dart delete mode 100644 useragent/macos/Flutter/ephemeral/Flutter-Generated.xcconfig delete mode 100755 useragent/macos/Flutter/ephemeral/flutter_export_environment.sh diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..bc166c4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,128 @@ +# AGENTS.md + +This file provides guidance to Codex (Codex.ai/code) when working with code in this repository. + +## Project Overview + +Arbiter is a **permissioned signing service** for cryptocurrency wallets. It consists of: +- **`server/`** — Rust gRPC daemon that holds encrypted keys and enforces policies +- **`useragent/`** — Flutter desktop app (macOS/Windows) with a Rust backend via Rinf +- **`protobufs/`** — Protocol Buffer definitions shared between server and client + +The vault never exposes key material; it only produces signatures when requests satisfy configured policies. + +## Toolchain Setup + +Tools are managed via [mise](https://mise.jdx.dev/). Install all required tools: +```sh +mise install +``` + +Key versions: Rust 1.93.0 (with clippy), Flutter 3.38.9-stable, protoc 29.6, diesel_cli 2.3.6 (sqlite). + +## Server (Rust workspace at `server/`) + +### Crates + +| Crate | Purpose | +|---|---| +| `arbiter-proto` | Generated gRPC stubs + protobuf types; compiled from `protobufs/*.proto` via `tonic-prost-build` | +| `arbiter-server` | Main daemon — actors, DB, EVM policy engine, gRPC service implementation | +| `arbiter-useragent` | Rust client library for the user agent side of the gRPC protocol | +| `arbiter-client` | Rust client library for SDK clients | + +### Common Commands + +```sh +cd server + +# Build +cargo build + +# Run the server daemon +cargo run -p arbiter-server + +# Run all tests (preferred over cargo test) +cargo nextest run + +# Run a single test +cargo nextest run + +# Lint +cargo clippy + +# Security audit +cargo audit + +# Check unused dependencies +cargo shear + +# Run snapshot tests and update snapshots +cargo insta review +``` + +### Architecture + +The server is actor-based using the **kameo** crate. All long-lived state lives in `GlobalActors`: + +- **`Bootstrapper`** — Manages the one-time bootstrap token written to `~/.arbiter/bootstrap_token` on first run. +- **`KeyHolder`** — Holds the encrypted root key and manages the Sealed/Unsealed vault state machine. On unseal, decrypts the root key into a `memsafe` hardened memory cell. +- **`MessageRouter`** — Coordinates streaming messages between user agents and SDK clients. +- **`EvmActor`** — Handles EVM transaction policy enforcement and signing. + +Per-connection actors live under `actors/user_agent/` and `actors/client/`, each with `auth` (challenge-response authentication) and `session` (post-auth operations) sub-modules. + +**Database:** SQLite via `diesel-async` + `bb8` connection pool. Schema managed by embedded Diesel migrations in `crates/arbiter-server/migrations/`. DB file lives at `~/.arbiter/arbiter.sqlite`. Tests use a temp-file DB via `db::create_test_pool()`. + +**Cryptography:** +- Authentication: ed25519 (challenge-response, nonce-tracked per peer) +- Encryption at rest: XChaCha20-Poly1305 (versioned via `scheme` field for transparent migration on unseal) +- Password KDF: Argon2 +- Unseal transport: X25519 ephemeral key exchange +- TLS: self-signed certificate (aws-lc-rs backend), fingerprint distributed via `ArbiterUrl` + +**Protocol:** gRPC with Protocol Buffers. The `ArbiterUrl` type encodes host, port, CA cert, and bootstrap token into a single shareable string (printed to console on first run). + +### Proto Regeneration + +When `.proto` files in `protobufs/` change, rebuild to regenerate: +```sh +cd server && cargo build -p arbiter-proto +``` + +### Database Migrations + +```sh +# Create a new migration +diesel migration generate --migration-dir crates/arbiter-server/migrations + +# Run migrations manually (server also runs them on startup) +diesel migration run --migration-dir crates/arbiter-server/migrations +``` + +## User Agent (Flutter + Rinf at `useragent/`) + +The Flutter app uses [Rinf](https://rinf.cunarist.org) to call Rust code. The Rust logic lives in `useragent/native/hub/` as a separate crate that uses `arbiter-useragent` for the gRPC client. + +Communication between Dart and Rust uses typed **signals** defined in `useragent/native/hub/src/signals/`. After modifying signal structs, regenerate Dart bindings: + +```sh +cd useragent && rinf gen +``` + +### Common Commands + +```sh +cd useragent + +# Run the app (macOS or Windows) +flutter run + +# Regenerate Rust↔Dart signal bindings +rinf gen + +# Analyze Dart code +flutter analyze +``` + +The Rinf Rust entry point is `useragent/native/hub/src/lib.rs`. It spawns actors defined in `useragent/native/hub/src/actors/` which handle Dart↔server communication via signals. diff --git a/useragent/.dart_tool/package_config.json b/useragent/.dart_tool/package_config.json deleted file mode 100644 index 9c93efa..0000000 --- a/useragent/.dart_tool/package_config.json +++ /dev/null @@ -1,904 +0,0 @@ -{ - "configVersion": 2, - "packages": [ - { - "name": "_fe_analyzer_shared", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/_fe_analyzer_shared-91.0.0", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "analyzer", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/analyzer-8.4.1", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "analyzer_buffer", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/analyzer_buffer-0.1.11", - "packageUri": "lib/", - "languageVersion": "3.6" - }, - { - "name": "ansicolor", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/ansicolor-2.0.3", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "args", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/args-2.7.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "async", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/async-2.13.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "auto_route", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/auto_route-11.1.0", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "auto_route_generator", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/auto_route_generator-10.4.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "biometric_signature", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/biometric_signature-10.2.0", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "bloc", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/bloc-9.2.0", - "packageUri": "lib/", - "languageVersion": "2.14" - }, - { - "name": "boolean_selector", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "build", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/build-4.0.4", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "build_config", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/build_config-1.3.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "build_daemon", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/build_daemon-4.1.1", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "build_runner", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/build_runner-2.12.2", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "built_collection", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/built_collection-5.1.1", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "built_value", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/built_value-8.12.4", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "characters", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/characters-1.4.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "checked_yaml", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/checked_yaml-2.0.4", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "cli_config", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/cli_config-0.2.0", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "clock", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/clock-1.1.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "code_assets", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/code_assets-1.0.0", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "code_builder", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/code_builder-4.11.1", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "collection", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/collection-1.19.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "convert", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/convert-3.1.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "coverage", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/coverage-1.15.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "cross_file", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/cross_file-0.3.5+2", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "crypto", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/crypto-3.0.7", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "cryptography", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/cryptography-2.9.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "cryptography_flutter", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/cryptography_flutter-2.3.4", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "cupertino_icons", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "dart_style", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/dart_style-3.1.3", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "fake_async", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/fake_async-1.3.3", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "ffi", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/ffi-2.2.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "file", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/file-7.0.1", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "fixnum", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/fixnum-1.1.1", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "flutter", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/packages/flutter", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "flutter_adaptive_scaffold", - "rootUri": "file:///Users/kaska/.pub-cache/git/flutter_adaptive_scaffold-b2e3615901a7ab837cb7fc35efbfcf8b55f27638/", - "packageUri": "lib/", - "languageVersion": "3.10" - }, - { - "name": "flutter_bloc", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_bloc-9.1.1", - "packageUri": "lib/", - "languageVersion": "2.14" - }, - { - "name": "flutter_hooks", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_hooks-0.21.3+1", - "packageUri": "lib/", - "languageVersion": "2.17" - }, - { - "name": "flutter_lints", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_lints-6.0.0", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "flutter_riverpod", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_riverpod-3.1.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "flutter_secure_storage", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_secure_storage-10.0.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter_secure_storage_darwin", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_secure_storage_darwin-0.2.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter_secure_storage_linux", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_secure_storage_linux-3.0.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter_secure_storage_platform_interface", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_secure_storage_platform_interface-2.0.1", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter_secure_storage_web", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_secure_storage_web-2.1.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter_secure_storage_windows", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_secure_storage_windows-4.1.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "flutter_spinkit", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/flutter_spinkit-5.2.2", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "flutter_test", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/packages/flutter_test", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "flutter_web_plugins", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/packages/flutter_web_plugins", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "freezed_annotation", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/freezed_annotation-3.1.0", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "frontend_server_client", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/frontend_server_client-4.0.0", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "glob", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/glob-2.1.3", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "google_identity_services_web", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/google_identity_services_web-0.3.3+1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "googleapis_auth", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/googleapis_auth-2.0.0", - "packageUri": "lib/", - "languageVersion": "3.6" - }, - { - "name": "graphs", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/graphs-2.3.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "group_button", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/group_button-5.3.4", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "grpc", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/grpc-5.1.0", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "hooks", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/hooks-1.0.2", - "packageUri": "lib/", - "languageVersion": "3.10" - }, - { - "name": "hooks_riverpod", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/hooks_riverpod-3.1.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "hotreloader", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/hotreloader-4.3.0", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "http", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/http-1.6.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "http2", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/http2-2.3.1", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "http_multi_server", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/http_multi_server-3.2.2", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "http_parser", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/http_parser-4.1.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "io", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/io-1.0.5", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "js", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/js-0.7.2", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "json_annotation", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/json_annotation-4.11.0", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "leak_tracker", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "leak_tracker_flutter_testing", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "leak_tracker_testing", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "lean_builder", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/lean_builder-0.1.6", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "lints", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/lints-6.1.0", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "logging", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/logging-1.3.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "matcher", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/matcher-0.12.17", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "material_color_utilities", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1", - "packageUri": "lib/", - "languageVersion": "2.17" - }, - { - "name": "meta", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/meta-1.17.0", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "mime", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/mime-2.0.0", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "mockito", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/mockito-5.6.3", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "mtcore", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/git.markettakers.org%2547api%2547packages%2547MarketTakers%2547pub%2547/mtcore-1.0.6", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "native_toolchain_c", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/native_toolchain_c-0.17.5", - "packageUri": "lib/", - "languageVersion": "3.10" - }, - { - "name": "nested", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/nested-1.0.0", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "node_preamble", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/node_preamble-2.0.2", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "objective_c", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/objective_c-9.3.0", - "packageUri": "lib/", - "languageVersion": "3.10" - }, - { - "name": "package_config", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/package_config-2.2.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "path", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path-1.9.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "path_provider", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path_provider-2.1.5", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "path_provider_android", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path_provider_android-2.2.22", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "path_provider_foundation", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path_provider_foundation-2.6.0", - "packageUri": "lib/", - "languageVersion": "3.10" - }, - { - "name": "path_provider_linux", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1", - "packageUri": "lib/", - "languageVersion": "2.19" - }, - { - "name": "path_provider_platform_interface", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path_provider_platform_interface-2.1.2", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "path_provider_windows", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "percent_indicator", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/percent_indicator-4.2.5", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "platform", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/platform-3.1.6", - "packageUri": "lib/", - "languageVersion": "3.2" - }, - { - "name": "plugin_platform_interface", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "pool", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/pool-1.5.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "protobuf", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/protobuf-6.0.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "provider", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/provider-6.1.5+1", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "pub_semver", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/pub_semver-2.2.0", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "pubspec_parse", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/pubspec_parse-1.5.0", - "packageUri": "lib/", - "languageVersion": "3.6" - }, - { - "name": "rive", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/rive-0.14.4", - "packageUri": "lib/", - "languageVersion": "3.6" - }, - { - "name": "rive_native", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/rive_native-0.1.4", - "packageUri": "lib/", - "languageVersion": "3.6" - }, - { - "name": "riverpod", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/riverpod-3.1.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "riverpod_analyzer_utils", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/riverpod_analyzer_utils-1.0.0-dev.8", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "riverpod_annotation", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/riverpod_annotation-4.0.0", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "riverpod_generator", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/riverpod_generator-4.0.0+1", - "packageUri": "lib/", - "languageVersion": "3.7" - }, - { - "name": "share_plus", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/share_plus-12.0.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "share_plus_platform_interface", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/share_plus_platform_interface-6.1.0", - "packageUri": "lib/", - "languageVersion": "2.18" - }, - { - "name": "shelf", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/shelf-1.4.2", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "shelf_packages_handler", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/shelf_packages_handler-3.0.2", - "packageUri": "lib/", - "languageVersion": "2.17" - }, - { - "name": "shelf_static", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/shelf_static-1.1.3", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "shelf_web_socket", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/shelf_web_socket-3.0.0", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "sizer", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/sizer-3.1.3", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "sky_engine", - "rootUri": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable/bin/cache/pkg/sky_engine", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "source_gen", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/source_gen-4.2.1", - "packageUri": "lib/", - "languageVersion": "3.9" - }, - { - "name": "source_map_stack_trace", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/source_map_stack_trace-2.1.2", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "source_maps", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/source_maps-0.10.13", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "source_span", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/source_span-1.10.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "stack_trace", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/stack_trace-1.12.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "state_notifier", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/state_notifier-1.0.0", - "packageUri": "lib/", - "languageVersion": "2.12" - }, - { - "name": "stream_channel", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/stream_channel-2.1.4", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "stream_transform", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/stream_transform-2.1.1", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "string_scanner", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/string_scanner-1.4.1", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "talker", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/talker-5.1.15", - "packageUri": "lib/", - "languageVersion": "2.17" - }, - { - "name": "talker_flutter", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/talker_flutter-5.1.15", - "packageUri": "lib/", - "languageVersion": "3.6" - }, - { - "name": "talker_logger", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/talker_logger-5.1.15", - "packageUri": "lib/", - "languageVersion": "2.15" - }, - { - "name": "term_glyph", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/term_glyph-1.2.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "test", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/test-1.26.3", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "test_api", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/test_api-0.7.7", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "test_core", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/test_core-0.6.12", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "typed_data", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/typed_data-1.4.0", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "url_launcher_linux", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "url_launcher_platform_interface", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/url_launcher_platform_interface-2.3.2", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "url_launcher_web", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/url_launcher_web-2.4.2", - "packageUri": "lib/", - "languageVersion": "3.10" - }, - { - "name": "url_launcher_windows", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "uuid", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/uuid-4.5.3", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "vector_math", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/vector_math-2.2.0", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "vm_service", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/vm_service-15.0.2", - "packageUri": "lib/", - "languageVersion": "3.5" - }, - { - "name": "watcher", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/watcher-1.1.4", - "packageUri": "lib/", - "languageVersion": "3.1" - }, - { - "name": "web", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/web-1.1.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "web_socket", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/web_socket-1.0.1", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "web_socket_channel", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/web_socket_channel-3.0.3", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "webkit_inspection_protocol", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/webkit_inspection_protocol-1.2.1", - "packageUri": "lib/", - "languageVersion": "3.0" - }, - { - "name": "win32", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/win32-5.15.0", - "packageUri": "lib/", - "languageVersion": "3.8" - }, - { - "name": "xdg_directories", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0", - "packageUri": "lib/", - "languageVersion": "3.3" - }, - { - "name": "xxh3", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/xxh3-1.2.0", - "packageUri": "lib/", - "languageVersion": "2.16" - }, - { - "name": "yaml", - "rootUri": "file:///Users/kaska/.pub-cache/hosted/pub.dev/yaml-3.1.3", - "packageUri": "lib/", - "languageVersion": "3.4" - }, - { - "name": "arbiter", - "rootUri": "../", - "packageUri": "lib/", - "languageVersion": "3.10" - } - ], - "generator": "pub", - "generatorVersion": "3.10.8", - "flutterRoot": "file:///Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable", - "flutterVersion": "3.38.9", - "pubCache": "file:///Users/kaska/.pub-cache" -} diff --git a/useragent/.dart_tool/package_graph.json b/useragent/.dart_tool/package_graph.json deleted file mode 100644 index 2588cea..0000000 --- a/useragent/.dart_tool/package_graph.json +++ /dev/null @@ -1,1465 +0,0 @@ -{ - "roots": [ - "arbiter" - ], - "packages": [ - { - "name": "arbiter", - "version": "1.0.0+1", - "dependencies": [ - "auto_route", - "biometric_signature", - "cryptography", - "cryptography_flutter", - "cupertino_icons", - "flutter", - "flutter_adaptive_scaffold", - "flutter_hooks", - "flutter_secure_storage", - "grpc", - "hooks_riverpod", - "mtcore", - "riverpod", - "riverpod_annotation", - "sizer", - "talker" - ], - "devDependencies": [ - "auto_route_generator", - "build_runner", - "flutter_lints", - "flutter_test", - "riverpod_generator" - ] - }, - { - "name": "auto_route_generator", - "version": "10.4.0", - "dependencies": [ - "analyzer", - "auto_route", - "build", - "code_builder", - "dart_style", - "glob", - "lean_builder", - "path", - "source_gen" - ] - }, - { - "name": "build_runner", - "version": "2.12.2", - "dependencies": [ - "analyzer", - "args", - "async", - "build", - "build_config", - "build_daemon", - "built_collection", - "built_value", - "code_builder", - "collection", - "convert", - "crypto", - "dart_style", - "glob", - "graphs", - "http_multi_server", - "io", - "json_annotation", - "logging", - "meta", - "mime", - "package_config", - "path", - "pool", - "pub_semver", - "shelf", - "shelf_web_socket", - "stream_transform", - "watcher", - "web_socket_channel", - "yaml" - ] - }, - { - "name": "riverpod_generator", - "version": "4.0.0+1", - "dependencies": [ - "analyzer", - "analyzer_buffer", - "build", - "build_config", - "collection", - "crypto", - "meta", - "mockito", - "path", - "riverpod_analyzer_utils", - "riverpod_annotation", - "source_gen" - ] - }, - { - "name": "flutter_lints", - "version": "6.0.0", - "dependencies": [ - "lints" - ] - }, - { - "name": "flutter_test", - "version": "0.0.0", - "dependencies": [ - "clock", - "collection", - "fake_async", - "flutter", - "leak_tracker_flutter_testing", - "matcher", - "meta", - "path", - "stack_trace", - "stream_channel", - "test_api", - "vector_math" - ] - }, - { - "name": "auto_route", - "version": "11.1.0", - "dependencies": [ - "collection", - "flutter", - "meta", - "path", - "web" - ] - }, - { - "name": "flutter_hooks", - "version": "0.21.3+1", - "dependencies": [ - "flutter" - ] - }, - { - "name": "grpc", - "version": "5.1.0", - "dependencies": [ - "async", - "clock", - "crypto", - "fixnum", - "googleapis_auth", - "http", - "http2", - "meta", - "protobuf", - "web" - ] - }, - { - "name": "riverpod_annotation", - "version": "4.0.0", - "dependencies": [ - "meta", - "riverpod" - ] - }, - { - "name": "cryptography_flutter", - "version": "2.3.4", - "dependencies": [ - "cryptography", - "flutter" - ] - }, - { - "name": "flutter_secure_storage", - "version": "10.0.0", - "dependencies": [ - "flutter", - "flutter_secure_storage_darwin", - "flutter_secure_storage_linux", - "flutter_secure_storage_platform_interface", - "flutter_secure_storage_web", - "flutter_secure_storage_windows", - "meta" - ] - }, - { - "name": "cryptography", - "version": "2.9.0", - "dependencies": [ - "collection", - "crypto", - "ffi", - "meta", - "typed_data" - ] - }, - { - "name": "mtcore", - "version": "1.0.6", - "dependencies": [ - "bloc", - "flutter", - "flutter_bloc", - "flutter_hooks", - "flutter_riverpod", - "flutter_spinkit", - "freezed_annotation", - "hooks_riverpod", - "percent_indicator", - "rive", - "riverpod_annotation", - "talker_flutter" - ] - }, - { - "name": "biometric_signature", - "version": "10.2.0", - "dependencies": [ - "flutter", - "plugin_platform_interface" - ] - }, - { - "name": "sizer", - "version": "3.1.3", - "dependencies": [ - "flutter" - ] - }, - { - "name": "riverpod", - "version": "3.1.0", - "dependencies": [ - "async", - "clock", - "collection", - "meta", - "state_notifier", - "test" - ] - }, - { - "name": "talker", - "version": "5.1.15", - "dependencies": [ - "talker_logger" - ] - }, - { - "name": "flutter_adaptive_scaffold", - "version": "1.0.0+1", - "dependencies": [ - "flutter" - ] - }, - { - "name": "cupertino_icons", - "version": "1.0.8", - "dependencies": [] - }, - { - "name": "flutter", - "version": "0.0.0", - "dependencies": [ - "characters", - "collection", - "material_color_utilities", - "meta", - "sky_engine", - "vector_math" - ] - }, - { - "name": "yaml", - "version": "3.1.3", - "dependencies": [ - "collection", - "source_span", - "string_scanner" - ] - }, - { - "name": "path", - "version": "1.9.1", - "dependencies": [] - }, - { - "name": "meta", - "version": "1.17.0", - "dependencies": [] - }, - { - "name": "glob", - "version": "2.1.3", - "dependencies": [ - "async", - "collection", - "file", - "path", - "string_scanner" - ] - }, - { - "name": "collection", - "version": "1.19.1", - "dependencies": [] - }, - { - "name": "dart_style", - "version": "3.1.3", - "dependencies": [ - "analyzer", - "args", - "collection", - "package_config", - "path", - "pub_semver", - "source_span", - "yaml" - ] - }, - { - "name": "async", - "version": "2.13.0", - "dependencies": [ - "collection", - "meta" - ] - }, - { - "name": "xxh3", - "version": "1.2.0", - "dependencies": [] - }, - { - "name": "stack_trace", - "version": "1.12.1", - "dependencies": [ - "path" - ] - }, - { - "name": "hotreloader", - "version": "4.3.0", - "dependencies": [ - "collection", - "logging", - "path", - "stream_transform", - "vm_service", - "watcher" - ] - }, - { - "name": "frontend_server_client", - "version": "4.0.0", - "dependencies": [ - "async", - "path" - ] - }, - { - "name": "args", - "version": "2.7.0", - "dependencies": [] - }, - { - "name": "ansicolor", - "version": "2.0.3", - "dependencies": [] - }, - { - "name": "matcher", - "version": "0.12.17", - "dependencies": [ - "async", - "meta", - "stack_trace", - "term_glyph", - "test_api" - ] - }, - { - "name": "built_collection", - "version": "5.1.1", - "dependencies": [] - }, - { - "name": "test_api", - "version": "0.7.7", - "dependencies": [ - "async", - "boolean_selector", - "collection", - "meta", - "source_span", - "stack_trace", - "stream_channel", - "string_scanner", - "term_glyph" - ] - }, - { - "name": "stream_channel", - "version": "2.1.4", - "dependencies": [ - "async" - ] - }, - { - "name": "build_config", - "version": "1.3.0", - "dependencies": [ - "checked_yaml", - "json_annotation", - "path", - "pubspec_parse" - ] - }, - { - "name": "test", - "version": "1.26.3", - "dependencies": [ - "analyzer", - "async", - "boolean_selector", - "collection", - "coverage", - "http_multi_server", - "io", - "js", - "matcher", - "node_preamble", - "package_config", - "path", - "pool", - "shelf", - "shelf_packages_handler", - "shelf_static", - "shelf_web_socket", - "source_span", - "stack_trace", - "stream_channel", - "test_api", - "test_core", - "typed_data", - "web_socket_channel", - "webkit_inspection_protocol", - "yaml" - ] - }, - { - "name": "riverpod_analyzer_utils", - "version": "1.0.0-dev.8", - "dependencies": [ - "analyzer", - "analyzer_buffer", - "collection", - "crypto", - "freezed_annotation", - "meta", - "path", - "source_span" - ] - }, - { - "name": "test_core", - "version": "0.6.12", - "dependencies": [ - "analyzer", - "args", - "async", - "boolean_selector", - "collection", - "coverage", - "frontend_server_client", - "glob", - "io", - "meta", - "package_config", - "path", - "pool", - "source_map_stack_trace", - "source_maps", - "source_span", - "stack_trace", - "stream_channel", - "test_api", - "vm_service", - "yaml" - ] - }, - { - "name": "freezed_annotation", - "version": "3.1.0", - "dependencies": [ - "collection", - "json_annotation", - "meta" - ] - }, - { - "name": "vector_math", - "version": "2.2.0", - "dependencies": [] - }, - { - "name": "leak_tracker_flutter_testing", - "version": "3.0.10", - "dependencies": [ - "flutter", - "leak_tracker", - "leak_tracker_testing", - "matcher", - "meta" - ] - }, - { - "name": "fake_async", - "version": "1.3.3", - "dependencies": [ - "clock", - "collection" - ] - }, - { - "name": "clock", - "version": "1.1.2", - "dependencies": [] - }, - { - "name": "web", - "version": "1.1.1", - "dependencies": [] - }, - { - "name": "protobuf", - "version": "6.0.0", - "dependencies": [ - "collection", - "fixnum", - "meta" - ] - }, - { - "name": "http2", - "version": "2.3.1", - "dependencies": [] - }, - { - "name": "fixnum", - "version": "1.1.1", - "dependencies": [] - }, - { - "name": "flutter_secure_storage_windows", - "version": "4.1.0", - "dependencies": [ - "ffi", - "flutter", - "flutter_secure_storage_platform_interface", - "path", - "path_provider", - "win32" - ] - }, - { - "name": "flutter_secure_storage_web", - "version": "2.1.0", - "dependencies": [ - "flutter", - "flutter_secure_storage_platform_interface", - "flutter_web_plugins", - "web" - ] - }, - { - "name": "flutter_secure_storage_platform_interface", - "version": "2.0.1", - "dependencies": [ - "flutter", - "plugin_platform_interface" - ] - }, - { - "name": "flutter_secure_storage_linux", - "version": "3.0.0", - "dependencies": [ - "flutter", - "flutter_secure_storage_platform_interface" - ] - }, - { - "name": "flutter_secure_storage_darwin", - "version": "0.2.0", - "dependencies": [ - "flutter", - "plugin_platform_interface" - ] - }, - { - "name": "flutter_web_plugins", - "version": "0.0.0", - "dependencies": [ - "flutter" - ] - }, - { - "name": "percent_indicator", - "version": "4.2.5", - "dependencies": [ - "flutter" - ] - }, - { - "name": "flutter_spinkit", - "version": "5.2.2", - "dependencies": [ - "flutter" - ] - }, - { - "name": "flutter_bloc", - "version": "9.1.1", - "dependencies": [ - "bloc", - "flutter", - "provider" - ] - }, - { - "name": "group_button", - "version": "5.3.4", - "dependencies": [ - "flutter" - ] - }, - { - "name": "nested", - "version": "1.0.0", - "dependencies": [ - "flutter" - ] - }, - { - "name": "talker_logger", - "version": "5.1.15", - "dependencies": [ - "ansicolor", - "web" - ] - }, - { - "name": "sky_engine", - "version": "0.0.0", - "dependencies": [] - }, - { - "name": "material_color_utilities", - "version": "0.11.1", - "dependencies": [ - "collection" - ] - }, - { - "name": "characters", - "version": "1.4.0", - "dependencies": [] - }, - { - "name": "hooks_riverpod", - "version": "3.1.0", - "dependencies": [ - "collection", - "flutter", - "flutter_hooks", - "flutter_riverpod", - "flutter_test", - "riverpod", - "state_notifier" - ] - }, - { - "name": "flutter_riverpod", - "version": "3.1.0", - "dependencies": [ - "collection", - "flutter", - "flutter_test", - "meta", - "riverpod", - "state_notifier" - ] - }, - { - "name": "source_span", - "version": "1.10.2", - "dependencies": [ - "collection", - "path", - "term_glyph" - ] - }, - { - "name": "crypto", - "version": "3.0.7", - "dependencies": [ - "typed_data" - ] - }, - { - "name": "googleapis_auth", - "version": "2.0.0", - "dependencies": [ - "args", - "crypto", - "google_identity_services_web", - "http", - "http_parser" - ] - }, - { - "name": "google_identity_services_web", - "version": "0.3.3+1", - "dependencies": [ - "meta", - "web" - ] - }, - { - "name": "code_builder", - "version": "4.11.1", - "dependencies": [ - "built_collection", - "built_value", - "collection", - "matcher", - "meta" - ] - }, - { - "name": "lints", - "version": "6.1.0", - "dependencies": [] - }, - { - "name": "leak_tracker_testing", - "version": "3.0.2", - "dependencies": [ - "leak_tracker", - "matcher", - "meta" - ] - }, - { - "name": "leak_tracker", - "version": "11.0.2", - "dependencies": [ - "clock", - "collection", - "meta", - "path", - "vm_service" - ] - }, - { - "name": "state_notifier", - "version": "1.0.0", - "dependencies": [ - "meta" - ] - }, - { - "name": "path_provider", - "version": "2.1.5", - "dependencies": [ - "flutter", - "path_provider_android", - "path_provider_foundation", - "path_provider_linux", - "path_provider_platform_interface", - "path_provider_windows" - ] - }, - { - "name": "path_provider_linux", - "version": "2.2.1", - "dependencies": [ - "ffi", - "flutter", - "path", - "path_provider_platform_interface", - "xdg_directories" - ] - }, - { - "name": "pub_semver", - "version": "2.2.0", - "dependencies": [ - "collection" - ] - }, - { - "name": "package_config", - "version": "2.2.0", - "dependencies": [ - "path" - ] - }, - { - "name": "term_glyph", - "version": "1.2.2", - "dependencies": [] - }, - { - "name": "lean_builder", - "version": "0.1.6", - "dependencies": [ - "_fe_analyzer_shared", - "analyzer", - "ansicolor", - "args", - "collection", - "dart_style", - "frontend_server_client", - "glob", - "hotreloader", - "meta", - "path", - "source_span", - "stack_trace", - "watcher", - "xxh3", - "yaml" - ] - }, - { - "name": "watcher", - "version": "1.1.4", - "dependencies": [ - "async", - "path" - ] - }, - { - "name": "boolean_selector", - "version": "2.1.2", - "dependencies": [ - "source_span", - "string_scanner" - ] - }, - { - "name": "pool", - "version": "1.5.2", - "dependencies": [ - "async", - "stack_trace" - ] - }, - { - "name": "analyzer_buffer", - "version": "0.1.11", - "dependencies": [ - "analyzer", - "collection", - "meta", - "path", - "source_gen" - ] - }, - { - "name": "shelf_packages_handler", - "version": "3.0.2", - "dependencies": [ - "path", - "shelf", - "shelf_static" - ] - }, - { - "name": "node_preamble", - "version": "2.0.2", - "dependencies": [] - }, - { - "name": "bloc", - "version": "9.2.0", - "dependencies": [ - "meta" - ] - }, - { - "name": "path_provider_windows", - "version": "2.3.0", - "dependencies": [ - "ffi", - "flutter", - "path", - "path_provider_platform_interface" - ] - }, - { - "name": "path_provider_platform_interface", - "version": "2.1.2", - "dependencies": [ - "flutter", - "platform", - "plugin_platform_interface" - ] - }, - { - "name": "plugin_platform_interface", - "version": "2.1.8", - "dependencies": [ - "meta" - ] - }, - { - "name": "source_map_stack_trace", - "version": "2.1.2", - "dependencies": [ - "path", - "source_maps", - "stack_trace" - ] - }, - { - "name": "string_scanner", - "version": "1.4.1", - "dependencies": [ - "source_span" - ] - }, - { - "name": "typed_data", - "version": "1.4.0", - "dependencies": [ - "collection" - ] - }, - { - "name": "file", - "version": "7.0.1", - "dependencies": [ - "meta", - "path" - ] - }, - { - "name": "stream_transform", - "version": "2.1.1", - "dependencies": [] - }, - { - "name": "json_annotation", - "version": "4.11.0", - "dependencies": [ - "meta" - ] - }, - { - "name": "graphs", - "version": "2.3.2", - "dependencies": [ - "collection" - ] - }, - { - "name": "analyzer", - "version": "8.4.1", - "dependencies": [ - "_fe_analyzer_shared", - "collection", - "convert", - "crypto", - "glob", - "meta", - "package_config", - "path", - "pub_semver", - "source_span", - "watcher", - "yaml" - ] - }, - { - "name": "_fe_analyzer_shared", - "version": "91.0.0", - "dependencies": [ - "meta" - ] - }, - { - "name": "source_maps", - "version": "0.10.13", - "dependencies": [ - "source_span" - ] - }, - { - "name": "rive", - "version": "0.14.4", - "dependencies": [ - "flutter", - "flutter_web_plugins", - "meta", - "rive_native" - ] - }, - { - "name": "rive_native", - "version": "0.1.4", - "dependencies": [ - "args", - "ffi", - "flutter", - "flutter_web_plugins", - "graphs", - "http", - "meta", - "path", - "plugin_platform_interface", - "vector_math", - "web" - ] - }, - { - "name": "build", - "version": "4.0.4", - "dependencies": [ - "analyzer", - "crypto", - "glob", - "logging", - "package_config", - "path" - ] - }, - { - "name": "io", - "version": "1.0.5", - "dependencies": [ - "meta", - "path", - "string_scanner" - ] - }, - { - "name": "http_multi_server", - "version": "3.2.2", - "dependencies": [ - "async" - ] - }, - { - "name": "checked_yaml", - "version": "2.0.4", - "dependencies": [ - "json_annotation", - "source_span", - "yaml" - ] - }, - { - "name": "web_socket_channel", - "version": "3.0.3", - "dependencies": [ - "async", - "crypto", - "stream_channel", - "web", - "web_socket" - ] - }, - { - "name": "shelf_web_socket", - "version": "3.0.0", - "dependencies": [ - "shelf", - "stream_channel", - "web_socket_channel" - ] - }, - { - "name": "web_socket", - "version": "1.0.1", - "dependencies": [ - "web" - ] - }, - { - "name": "webkit_inspection_protocol", - "version": "1.2.1", - "dependencies": [ - "logging" - ] - }, - { - "name": "shelf_static", - "version": "1.1.3", - "dependencies": [ - "convert", - "http_parser", - "mime", - "path", - "shelf" - ] - }, - { - "name": "http", - "version": "1.6.0", - "dependencies": [ - "async", - "http_parser", - "meta", - "web" - ] - }, - { - "name": "ffi", - "version": "2.2.0", - "dependencies": [] - }, - { - "name": "convert", - "version": "3.1.2", - "dependencies": [ - "typed_data" - ] - }, - { - "name": "http_parser", - "version": "4.1.2", - "dependencies": [ - "collection", - "source_span", - "string_scanner", - "typed_data" - ] - }, - { - "name": "logging", - "version": "1.3.0", - "dependencies": [] - }, - { - "name": "build_daemon", - "version": "4.1.1", - "dependencies": [ - "built_collection", - "built_value", - "crypto", - "http_multi_server", - "logging", - "path", - "pool", - "shelf", - "shelf_web_socket", - "stream_transform", - "watcher", - "web_socket_channel" - ] - }, - { - "name": "js", - "version": "0.7.2", - "dependencies": [] - }, - { - "name": "mime", - "version": "2.0.0", - "dependencies": [] - }, - { - "name": "source_gen", - "version": "4.2.1", - "dependencies": [ - "analyzer", - "async", - "build", - "dart_style", - "glob", - "path", - "pub_semver", - "source_span", - "yaml" - ] - }, - { - "name": "mockito", - "version": "5.6.3", - "dependencies": [ - "analyzer", - "build", - "code_builder", - "collection", - "dart_style", - "matcher", - "meta", - "path", - "source_gen", - "test_api" - ] - }, - { - "name": "path_provider_foundation", - "version": "2.6.0", - "dependencies": [ - "ffi", - "flutter", - "objective_c", - "path_provider_platform_interface" - ] - }, - { - "name": "objective_c", - "version": "9.3.0", - "dependencies": [ - "code_assets", - "collection", - "ffi", - "hooks", - "logging", - "native_toolchain_c", - "pub_semver" - ] - }, - { - "name": "code_assets", - "version": "1.0.0", - "dependencies": [ - "collection", - "hooks" - ] - }, - { - "name": "native_toolchain_c", - "version": "0.17.5", - "dependencies": [ - "code_assets", - "glob", - "hooks", - "logging", - "meta", - "pub_semver" - ] - }, - { - "name": "hooks", - "version": "1.0.2", - "dependencies": [ - "collection", - "crypto", - "logging", - "meta", - "pub_semver", - "yaml" - ] - }, - { - "name": "pubspec_parse", - "version": "1.5.0", - "dependencies": [ - "checked_yaml", - "collection", - "json_annotation", - "pub_semver", - "yaml" - ] - }, - { - "name": "platform", - "version": "3.1.6", - "dependencies": [] - }, - { - "name": "built_value", - "version": "8.12.4", - "dependencies": [ - "built_collection", - "collection", - "fixnum", - "meta" - ] - }, - { - "name": "shelf", - "version": "1.4.2", - "dependencies": [ - "async", - "collection", - "http_parser", - "path", - "stack_trace", - "stream_channel" - ] - }, - { - "name": "xdg_directories", - "version": "1.1.0", - "dependencies": [ - "meta", - "path" - ] - }, - { - "name": "provider", - "version": "6.1.5+1", - "dependencies": [ - "collection", - "flutter", - "nested" - ] - }, - { - "name": "vm_service", - "version": "15.0.2", - "dependencies": [] - }, - { - "name": "win32", - "version": "5.15.0", - "dependencies": [ - "ffi" - ] - }, - { - "name": "talker_flutter", - "version": "5.1.15", - "dependencies": [ - "flutter", - "group_button", - "path_provider", - "share_plus", - "talker", - "web" - ] - }, - { - "name": "share_plus", - "version": "12.0.1", - "dependencies": [ - "cross_file", - "ffi", - "file", - "flutter", - "flutter_web_plugins", - "meta", - "mime", - "share_plus_platform_interface", - "url_launcher_linux", - "url_launcher_platform_interface", - "url_launcher_web", - "url_launcher_windows", - "web", - "win32" - ] - }, - { - "name": "url_launcher_platform_interface", - "version": "2.3.2", - "dependencies": [ - "flutter", - "plugin_platform_interface" - ] - }, - { - "name": "share_plus_platform_interface", - "version": "6.1.0", - "dependencies": [ - "cross_file", - "flutter", - "meta", - "mime", - "path_provider", - "plugin_platform_interface", - "uuid" - ] - }, - { - "name": "url_launcher_windows", - "version": "3.1.5", - "dependencies": [ - "flutter", - "url_launcher_platform_interface" - ] - }, - { - "name": "url_launcher_linux", - "version": "3.2.2", - "dependencies": [ - "flutter", - "url_launcher_platform_interface" - ] - }, - { - "name": "cross_file", - "version": "0.3.5+2", - "dependencies": [ - "meta", - "web" - ] - }, - { - "name": "url_launcher_web", - "version": "2.4.2", - "dependencies": [ - "flutter", - "flutter_web_plugins", - "url_launcher_platform_interface", - "web" - ] - }, - { - "name": "path_provider_android", - "version": "2.2.22", - "dependencies": [ - "flutter", - "path_provider_platform_interface" - ] - }, - { - "name": "uuid", - "version": "4.5.3", - "dependencies": [ - "crypto", - "fixnum" - ] - }, - { - "name": "coverage", - "version": "1.15.0", - "dependencies": [ - "args", - "cli_config", - "glob", - "logging", - "meta", - "package_config", - "path", - "source_maps", - "stack_trace", - "vm_service", - "yaml" - ] - }, - { - "name": "cli_config", - "version": "0.2.0", - "dependencies": [ - "args", - "yaml" - ] - } - ], - "configVersion": 1 -} \ No newline at end of file diff --git a/useragent/.dart_tool/version b/useragent/.dart_tool/version deleted file mode 100644 index 75fffa6..0000000 --- a/useragent/.dart_tool/version +++ /dev/null @@ -1 +0,0 @@ -3.38.9 \ No newline at end of file diff --git a/useragent/lib/features/arbiter_url.dart b/useragent/lib/features/arbiter_url.dart new file mode 100644 index 0000000..d71d236 --- /dev/null +++ b/useragent/lib/features/arbiter_url.dart @@ -0,0 +1,56 @@ +import 'dart:convert'; + +class ArbiterUrl { + const ArbiterUrl({ + required this.host, + required this.port, + required this.caCert, + this.bootstrapToken, + }); + + final String host; + final int port; + final List caCert; + final String? bootstrapToken; + + static const _scheme = 'arbiter'; + static const _certQueryKey = 'cert'; + static const _bootstrapTokenQueryKey = 'bootstrap_token'; + + static ArbiterUrl parse(String value) { + final uri = Uri.tryParse(value); + if (uri == null || uri.scheme != _scheme) { + throw const FormatException("Invalid URL scheme, expected 'arbiter://'"); + } + + if (uri.host.isEmpty) { + throw const FormatException('Missing host in URL'); + } + + if (!uri.hasPort) { + throw const FormatException('Missing port in URL'); + } + + final cert = uri.queryParameters[_certQueryKey]; + if (cert == null || cert.isEmpty) { + throw const FormatException("Missing 'cert' query parameter in URL"); + } + + final decodedCert = _decodeCert(cert); + + return ArbiterUrl( + host: uri.host, + port: uri.port, + caCert: decodedCert, + bootstrapToken: uri.queryParameters[_bootstrapTokenQueryKey], + ); + } + + static List _decodeCert(String cert) { + try { + return base64Url.decode(base64Url.normalize(cert)); + } on FormatException catch (error) { + throw FormatException("Invalid base64 in 'cert' query parameter: ${error.message}"); + } + } +} diff --git a/useragent/lib/features/connection/connection.dart b/useragent/lib/features/connection/connection.dart new file mode 100644 index 0000000..944711a --- /dev/null +++ b/useragent/lib/features/connection/connection.dart @@ -0,0 +1,3 @@ + + +class Connection {} \ No newline at end of file diff --git a/useragent/lib/features/pk_manager.dart b/useragent/lib/features/pk_manager.dart index a9bfb62..ff6db23 100644 --- a/useragent/lib/features/pk_manager.dart +++ b/useragent/lib/features/pk_manager.dart @@ -1,6 +1,3 @@ - -import 'package:flutter/services.dart'; - enum KeyAlgorithm { rsa, ecdsa, ed25519 } @@ -16,4 +13,4 @@ abstract class KeyHandle { abstract class KeyManager { Future get(); Future create(); -} \ No newline at end of file +} diff --git a/useragent/lib/features/server_info_storage.dart b/useragent/lib/features/server_info_storage.dart new file mode 100644 index 0000000..704939e --- /dev/null +++ b/useragent/lib/features/server_info_storage.dart @@ -0,0 +1,67 @@ +import 'dart:convert'; + +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class StoredServerInfo { + const StoredServerInfo({ + required this.address, + required this.port, + required this.caCertFingerprint, + }); + + final String address; + final int port; + final String caCertFingerprint; + + Map toJson() => { + 'address': address, + 'port': port, + 'caCertFingerprint': caCertFingerprint, + }; + + factory StoredServerInfo.fromJson(Map json) { + return StoredServerInfo( + address: json['address'] as String, + port: json['port'] as int, + caCertFingerprint: json['caCertFingerprint'] as String, + ); + } +} + +abstract class ServerInfoStorage { + Future load(); + Future save(StoredServerInfo serverInfo); + Future clear(); +} + +class SecureServerInfoStorage implements ServerInfoStorage { + static const _storageKey = 'server_info'; + + const SecureServerInfoStorage(); + + static const _storage = FlutterSecureStorage(); + + @override + Future load() async { + final rawValue = await _storage.read(key: _storageKey); + if (rawValue == null) { + return null; + } + + final decoded = jsonDecode(rawValue) as Map; + return StoredServerInfo.fromJson(decoded); + } + + @override + Future save(StoredServerInfo serverInfo) { + return _storage.write( + key: _storageKey, + value: jsonEncode(serverInfo.toJson()), + ); + } + + @override + Future clear() { + return _storage.delete(key: _storageKey); + } +} diff --git a/useragent/lib/main.dart b/useragent/lib/main.dart index 89df0e1..5fac968 100644 --- a/useragent/lib/main.dart +++ b/useragent/lib/main.dart @@ -1,14 +1,35 @@ import 'package:arbiter/router.dart'; import 'package:flutter/material.dart' hide Router; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:sizer/sizer.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); - runApp( - ProviderScope( - child: MaterialApp.router( - routerConfig: Router().config(), - ), - ), - ); + runApp(const ProviderScope(child: App())); +} + +class App extends StatefulWidget { + const App({super.key}); + + @override + State createState() => _AppState(); +} + +class _AppState extends State { + late final Router _router; + + @override + void initState() { + super.initState(); + _router = Router(); + } + + @override + Widget build(BuildContext context) { + return Sizer( + builder: (context, orientation, deviceType) { + return MaterialApp.router(routerConfig: _router.config()); + }, + ); + } } diff --git a/useragent/lib/providers/server_info.dart b/useragent/lib/providers/server_info.dart new file mode 100644 index 0000000..651143e --- /dev/null +++ b/useragent/lib/providers/server_info.dart @@ -0,0 +1,51 @@ +import 'package:arbiter/features/server_info_storage.dart'; +import 'package:cryptography/cryptography.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'server_info.g.dart'; + +@riverpod +ServerInfoStorage serverInfoStorage(Ref ref) { + return const SecureServerInfoStorage(); +} + +@Riverpod(keepAlive: true) +class ServerInfo extends _$ServerInfo { + @override + Future build() { + final storage = ref.watch(serverInfoStorageProvider); + return storage.load(); + } + + Future save({ + required String address, + required int port, + required List caCert, + }) async { + final storage = ref.read(serverInfoStorageProvider); + final fingerprint = await _fingerprint(caCert); + final serverInfo = StoredServerInfo( + address: address, + port: port, + caCertFingerprint: fingerprint, + ); + + state = await AsyncValue.guard(() async { + await storage.save(serverInfo); + return serverInfo; + }); + } + + Future clear() async { + final storage = ref.read(serverInfoStorageProvider); + state = await AsyncValue.guard(() async { + await storage.clear(); + return null; + }); + } + + Future _fingerprint(List caCert) async { + final digest = await Sha256().hash(caCert); + return digest.bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(); + } +} diff --git a/useragent/lib/providers/server_info.g.dart b/useragent/lib/providers/server_info.g.dart new file mode 100644 index 0000000..ec0afbc --- /dev/null +++ b/useragent/lib/providers/server_info.g.dart @@ -0,0 +1,102 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'server_info.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint, type=warning + +@ProviderFor(serverInfoStorage) +final serverInfoStorageProvider = ServerInfoStorageProvider._(); + +final class ServerInfoStorageProvider + extends + $FunctionalProvider< + ServerInfoStorage, + ServerInfoStorage, + ServerInfoStorage + > + with $Provider { + ServerInfoStorageProvider._() + : super( + from: null, + argument: null, + retry: null, + name: r'serverInfoStorageProvider', + isAutoDispose: true, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$serverInfoStorageHash(); + + @$internal + @override + $ProviderElement $createElement( + $ProviderPointer pointer, + ) => $ProviderElement(pointer); + + @override + ServerInfoStorage create(Ref ref) { + return serverInfoStorage(ref); + } + + /// {@macro riverpod.override_with_value} + Override overrideWithValue(ServerInfoStorage value) { + return $ProviderOverride( + origin: this, + providerOverride: $SyncValueProvider(value), + ); + } +} + +String _$serverInfoStorageHash() => r'fc06865e7314b1a2493c5de1a9347923a3d21c5c'; + +@ProviderFor(ServerInfo) +final serverInfoProvider = ServerInfoProvider._(); + +final class ServerInfoProvider + extends $AsyncNotifierProvider { + ServerInfoProvider._() + : super( + from: null, + argument: null, + retry: null, + name: r'serverInfoProvider', + isAutoDispose: false, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$serverInfoHash(); + + @$internal + @override + ServerInfo create() => ServerInfo(); +} + +String _$serverInfoHash() => r'6e94f52de03259695a2166b766004eec60ff45fa'; + +abstract class _$ServerInfo extends $AsyncNotifier { + FutureOr build(); + @$mustCallSuper + @override + void runBuild() { + final ref = + this.ref as $Ref, StoredServerInfo?>; + final element = + ref.element + as $ClassProviderElement< + AnyNotifier, StoredServerInfo?>, + AsyncValue, + Object?, + Object? + >; + element.handleCreate(ref, build); + } +} diff --git a/useragent/lib/router.dart b/useragent/lib/router.dart index bcbc314..5462fbd 100644 --- a/useragent/lib/router.dart +++ b/useragent/lib/router.dart @@ -1,8 +1,4 @@ -import 'package:arbiter/screens/dashboard/about.dart'; -import 'package:arbiter/screens/dashboard/calc.dart'; import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart'; import 'router.gr.dart'; @@ -11,6 +7,7 @@ class Router extends RootStackRouter { @override List get routes => [ AutoRoute(page: Bootstrap.page, path: '/bootstrap', initial: true), + AutoRoute(page: ServerInfoSetupRoute.page, path: '/server-info'), AutoRoute( page: DashboardRouter.page, diff --git a/useragent/lib/router.gr.dart b/useragent/lib/router.gr.dart index 824cf97..704418e 100644 --- a/useragent/lib/router.gr.dart +++ b/useragent/lib/router.gr.dart @@ -13,33 +13,34 @@ import 'package:arbiter/screens/bootstrap.dart' as _i2; import 'package:arbiter/screens/dashboard.dart' as _i4; import 'package:arbiter/screens/dashboard/about.dart' as _i1; import 'package:arbiter/screens/dashboard/calc.dart' as _i3; -import 'package:auto_route/auto_route.dart' as _i5; +import 'package:arbiter/screens/server_info_setup.dart' as _i5; +import 'package:auto_route/auto_route.dart' as _i6; /// generated route for /// [_i1.AboutScreen] -class AboutRoute extends _i5.PageRouteInfo { - const AboutRoute({List<_i5.PageRouteInfo>? children}) +class AboutRoute extends _i6.PageRouteInfo { + const AboutRoute({List<_i6.PageRouteInfo>? children}) : super(AboutRoute.name, initialChildren: children); static const String name = 'AboutRoute'; - static _i5.PageInfo page = _i5.PageInfo( + static _i6.PageInfo page = _i6.PageInfo( name, builder: (data) { - return _i1.AboutScreen(); + return const _i1.AboutScreen(); }, ); } /// generated route for /// [_i2.Bootstrap] -class Bootstrap extends _i5.PageRouteInfo { - const Bootstrap({List<_i5.PageRouteInfo>? children}) +class Bootstrap extends _i6.PageRouteInfo { + const Bootstrap({List<_i6.PageRouteInfo>? children}) : super(Bootstrap.name, initialChildren: children); static const String name = 'Bootstrap'; - static _i5.PageInfo page = _i5.PageInfo( + static _i6.PageInfo page = _i6.PageInfo( name, builder: (data) { return const _i2.Bootstrap(); @@ -49,13 +50,13 @@ class Bootstrap extends _i5.PageRouteInfo { /// generated route for /// [_i3.CalcScreen] -class CalcRoute extends _i5.PageRouteInfo { - const CalcRoute({List<_i5.PageRouteInfo>? children}) +class CalcRoute extends _i6.PageRouteInfo { + const CalcRoute({List<_i6.PageRouteInfo>? children}) : super(CalcRoute.name, initialChildren: children); static const String name = 'CalcRoute'; - static _i5.PageInfo page = _i5.PageInfo( + static _i6.PageInfo page = _i6.PageInfo( name, builder: (data) { return const _i3.CalcScreen(); @@ -65,16 +66,32 @@ class CalcRoute extends _i5.PageRouteInfo { /// generated route for /// [_i4.DashboardRouter] -class DashboardRouter extends _i5.PageRouteInfo { - const DashboardRouter({List<_i5.PageRouteInfo>? children}) +class DashboardRouter extends _i6.PageRouteInfo { + const DashboardRouter({List<_i6.PageRouteInfo>? children}) : super(DashboardRouter.name, initialChildren: children); static const String name = 'DashboardRouter'; - static _i5.PageInfo page = _i5.PageInfo( + static _i6.PageInfo page = _i6.PageInfo( name, builder: (data) { return const _i4.DashboardRouter(); }, ); } + +/// generated route for +/// [_i5.ServerInfoSetupScreen] +class ServerInfoSetupRoute extends _i6.PageRouteInfo { + const ServerInfoSetupRoute({List<_i6.PageRouteInfo>? children}) + : super(ServerInfoSetupRoute.name, initialChildren: children); + + static const String name = 'ServerInfoSetupRoute'; + + static _i6.PageInfo page = _i6.PageInfo( + name, + builder: (data) { + return const _i5.ServerInfoSetupScreen(); + }, + ); +} diff --git a/useragent/lib/screens/bootstrap.dart b/useragent/lib/screens/bootstrap.dart index da215f4..d2e2172 100644 --- a/useragent/lib/screens/bootstrap.dart +++ b/useragent/lib/screens/bootstrap.dart @@ -14,13 +14,13 @@ class Bootstrap extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final container = ProviderScope.containerOf( context); + final container = ProviderScope.containerOf(context); final completer = useMemoized(() { final completer = Completer(); completer.future.then((_) async { if (context.mounted) { final router = AutoRouter.of(context); - router.replace(const DashboardRouter()); + router.replace(const ServerInfoSetupRoute()); } }); diff --git a/useragent/lib/screens/dashboard/about.dart b/useragent/lib/screens/dashboard/about.dart index 29e853d..3745aec 100644 --- a/useragent/lib/screens/dashboard/about.dart +++ b/useragent/lib/screens/dashboard/about.dart @@ -2,9 +2,10 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:mtcore/markettakers.dart' as mt; - @RoutePage() class AboutScreen extends StatelessWidget { + const AboutScreen({super.key}); + @override Widget build(BuildContext context) { return mt.AboutScreen(decription: "Arbiter is bla bla bla"); diff --git a/useragent/lib/screens/server_info_setup.dart b/useragent/lib/screens/server_info_setup.dart new file mode 100644 index 0000000..82873cf --- /dev/null +++ b/useragent/lib/screens/server_info_setup.dart @@ -0,0 +1,284 @@ +import 'package:arbiter/features/arbiter_url.dart'; +import 'package:arbiter/features/server_info_storage.dart'; +import 'package:arbiter/providers/server_info.dart'; +import 'package:arbiter/router.gr.dart'; +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:sizer/sizer.dart'; + +@RoutePage() +class ServerInfoSetupScreen extends HookConsumerWidget { + const ServerInfoSetupScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final storedServerInfo = ref.watch(serverInfoProvider); + final resolvedServerInfo = storedServerInfo.asData?.value; + final controller = useTextEditingController(); + final errorText = useState(null); + final isSaving = useState(false); + + useEffect(() { + final serverInfo = resolvedServerInfo; + if (serverInfo != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (context.mounted) { + context.router.replace(const DashboardRouter()); + } + }); + } + return null; + }, [context, resolvedServerInfo]); + + Future saveRemoteServerInfo() async { + errorText.value = null; + isSaving.value = true; + + try { + final arbiterUrl = ArbiterUrl.parse(controller.text.trim()); + await ref + .read(serverInfoProvider.notifier) + .save( + address: arbiterUrl.host, + port: arbiterUrl.port, + caCert: arbiterUrl.caCert, + ); + + if (context.mounted) { + context.router.replace(const DashboardRouter()); + } + } on FormatException catch (error) { + errorText.value = error.message; + } catch (_) { + errorText.value = 'Failed to store connection settings.'; + } finally { + isSaving.value = false; + } + } + + if (storedServerInfo.isLoading) { + return const Scaffold(body: Center(child: CircularProgressIndicator())); + } + + if (storedServerInfo.hasError) { + return Scaffold( + appBar: AppBar(title: const Text('Server Info Setup')), + body: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 6.w), + child: Text( + 'Failed to load stored server info.', + style: Theme.of(context).textTheme.bodyLarge, + textAlign: TextAlign.center, + ), + ), + ), + ); + } + + final serverInfo = resolvedServerInfo; + if (serverInfo != null) { + return _RedirectingView(serverInfo: serverInfo); + } + + return Scaffold( + appBar: AppBar(title: const Text('Server Info Setup')), + body: LayoutBuilder( + builder: (context, constraints) { + final useRowLayout = constraints.maxWidth > constraints.maxHeight; + final gap = 2.h; + final horizontalPadding = 6.w; + final verticalPadding = 3.h; + final options = [ + const _OptionCard( + title: 'Local', + subtitle: 'Will start and connect to a local service in a future update.', + enabled: false, + child: SizedBox.shrink(), + ), + _OptionCard( + title: 'Remote', + subtitle: 'Paste an Arbiter URL to store the server address, port, and CA fingerprint.', + child: _RemoteConnectionForm( + controller: controller, + errorText: errorText.value, + isSaving: isSaving.value, + onSave: saveRemoteServerInfo, + ), + ), + ]; + + return ListView( + padding: EdgeInsets.symmetric( + horizontal: horizontalPadding, + vertical: verticalPadding, + ), + children: [ + _SetupHeader(gap: gap), + SizedBox(height: gap), + useRowLayout + ? Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded(child: options[0]), + SizedBox(width: 3.w), + Expanded(child: options[1]), + ], + ) + : Column( + children: [ + options[0], + SizedBox(height: gap), + options[1], + ], + ), + ], + ); + }, + ), + ); + } +} + +class _SetupHeader extends StatelessWidget { + const _SetupHeader({required this.gap}); + + final double gap; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Choose how this user agent should reach Arbiter.', + style: Theme.of(context).textTheme.headlineSmall, + ), + SizedBox(height: gap * 0.5), + Text( + 'Remote accepts the shareable Arbiter URL emitted by the server.', + style: Theme.of(context).textTheme.bodyMedium, + ), + ], + ); + } +} + +class _RedirectingView extends StatelessWidget { + const _RedirectingView({required this.serverInfo}); + + final StoredServerInfo serverInfo; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const CircularProgressIndicator(), + SizedBox(height: 2.h), + Text('Using saved server ${serverInfo.address}:${serverInfo.port}'), + ], + ), + ), + ); + } +} + +class _RemoteConnectionForm extends StatelessWidget { + const _RemoteConnectionForm({ + required this.controller, + required this.errorText, + required this.isSaving, + required this.onSave, + }); + + final TextEditingController controller; + final String? errorText; + final bool isSaving; + final VoidCallback onSave; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextField( + controller: controller, + decoration: const InputDecoration( + border: OutlineInputBorder(), + labelText: 'Arbiter URL', + hintText: 'arbiter://host:port?cert=...', + ), + minLines: 2, + maxLines: 4, + ), + if (errorText != null) ...[ + SizedBox(height: 1.5.h), + Text( + errorText!, + style: TextStyle(color: Theme.of(context).colorScheme.error), + ), + ], + SizedBox(height: 2.h), + Align( + alignment: Alignment.centerLeft, + child: FilledButton( + onPressed: isSaving ? null : onSave, + child: Text(isSaving ? 'Saving...' : 'Save connection'), + ), + ), + ], + ); + } +} + +class _OptionCard extends StatelessWidget { + const _OptionCard({ + required this.title, + required this.subtitle, + required this.child, + this.enabled = true, + }); + + final String title; + final String subtitle; + final Widget child; + final bool enabled; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Card( + child: Padding( + padding: EdgeInsets.all(2.h), + child: Opacity( + opacity: enabled ? 1 : 0.55, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text(title, style: theme.textTheme.titleLarge), + if (!enabled) ...[ + SizedBox(width: 2.w), + const Chip(label: Text('Coming soon')), + ], + ], + ), + SizedBox(height: 1.h), + Text(subtitle, style: theme.textTheme.bodyMedium), + if (enabled) ...[ + SizedBox(height: 2.h), + child, + ], + ], + ), + ), + ), + ); + } +} diff --git a/useragent/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/useragent/macos/Flutter/ephemeral/Flutter-Generated.xcconfig deleted file mode 100644 index 1e123d0..0000000 --- a/useragent/macos/Flutter/ephemeral/Flutter-Generated.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -// This is a generated file; do not edit or check into version control. -FLUTTER_ROOT=/Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable -FLUTTER_APPLICATION_PATH=/Users/kaska/Documents/Projects/Major/arbiter/useragent -COCOAPODS_PARALLEL_CODE_SIGN=true -FLUTTER_TARGET=/Users/kaska/Documents/Projects/Major/arbiter/useragent/lib/main.dart -FLUTTER_BUILD_DIR=build -FLUTTER_BUILD_NAME=1.0.0 -FLUTTER_BUILD_NUMBER=1 -DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzguOQ==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049NjczMjNkZTI4NQ==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049NTg3YzE4Zjg3Mw==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My4xMC44 -DART_OBFUSCATION=false -TRACK_WIDGET_CREATION=true -TREE_SHAKE_ICONS=false -PACKAGE_CONFIG=/Users/kaska/Documents/Projects/Major/arbiter/useragent/.dart_tool/package_config.json diff --git a/useragent/macos/Flutter/ephemeral/flutter_export_environment.sh b/useragent/macos/Flutter/ephemeral/flutter_export_environment.sh deleted file mode 100755 index 301f1f6..0000000 --- a/useragent/macos/Flutter/ephemeral/flutter_export_environment.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# This is a generated file; do not edit or check into version control. -export "FLUTTER_ROOT=/Users/kaska/.local/share/mise/installs/flutter/3.38.9-stable" -export "FLUTTER_APPLICATION_PATH=/Users/kaska/Documents/Projects/Major/arbiter/useragent" -export "COCOAPODS_PARALLEL_CODE_SIGN=true" -export "FLUTTER_TARGET=/Users/kaska/Documents/Projects/Major/arbiter/useragent/lib/main.dart" -export "FLUTTER_BUILD_DIR=build" -export "FLUTTER_BUILD_NAME=1.0.0" -export "FLUTTER_BUILD_NUMBER=1" -export "DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzguOQ==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049NjczMjNkZTI4NQ==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049NTg3YzE4Zjg3Mw==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My4xMC44" -export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=true" -export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=/Users/kaska/Documents/Projects/Major/arbiter/useragent/.dart_tool/package_config.json" diff --git a/useragent/macos/Podfile b/useragent/macos/Podfile index ff5ddb3..25eb537 100644 --- a/useragent/macos/Podfile +++ b/useragent/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.15' +platform :osx, '26.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/useragent/macos/Podfile.lock b/useragent/macos/Podfile.lock index 32a275d..c054fb2 100644 --- a/useragent/macos/Podfile.lock +++ b/useragent/macos/Podfile.lock @@ -42,6 +42,6 @@ SPEC CHECKSUMS: rive_native: 1c53d33e44c2b54424810effea4590671dd220c7 share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc -PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 +PODFILE CHECKSUM: 224cb1c0d6f5312abfc2477bcb5c7f1fca2574fb COCOAPODS: 1.16.2 diff --git a/useragent/macos/Runner.xcodeproj/project.pbxproj b/useragent/macos/Runner.xcodeproj/project.pbxproj index 28b98d2..12c3f47 100644 --- a/useragent/macos/Runner.xcodeproj/project.pbxproj +++ b/useragent/macos/Runner.xcodeproj/project.pbxproj @@ -195,7 +195,6 @@ 5385F9987FF8E7FD3BA4E87E /* Pods-RunnerTests.release.xcconfig */, ADF8B0EB51CA38AE67931C44 /* Pods-RunnerTests.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -478,6 +477,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.useragent.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -493,6 +493,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.useragent.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -508,6 +509,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.example.useragent.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -560,6 +562,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; @@ -572,14 +575,22 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 8L884L537J; + ENABLE_APP_SANDBOX = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 26.0; + PRODUCT_BUNDLE_IDENTIFIER = org.markettakers.arbiter; PROVISIONING_PROFILE_SPECIFIER = ""; + RUNTIME_EXCEPTION_ALLOW_JIT = YES; SWIFT_VERSION = 5.0; }; name = Profile; @@ -588,6 +599,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; @@ -643,6 +655,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -692,6 +705,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; @@ -704,14 +718,22 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 8L884L537J; + ENABLE_APP_SANDBOX = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 26.0; + PRODUCT_BUNDLE_IDENTIFIER = org.markettakers.arbiter; PROVISIONING_PROFILE_SPECIFIER = ""; + RUNTIME_EXCEPTION_ALLOW_JIT = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; @@ -724,14 +746,22 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 8L884L537J; + ENABLE_APP_SANDBOX = YES; + ENABLE_INCOMING_NETWORK_CONNECTIONS = YES; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 26.0; + PRODUCT_BUNDLE_IDENTIFIER = org.markettakers.arbiter; PROVISIONING_PROFILE_SPECIFIER = ""; + RUNTIME_EXCEPTION_ALLOW_JIT = YES; SWIFT_VERSION = 5.0; }; name = Release; @@ -740,6 +770,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -748,6 +779,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; + MACOSX_DEPLOYMENT_TARGET = 11.0; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/useragent/macos/Runner/DebugProfile.entitlements b/useragent/macos/Runner/DebugProfile.entitlements index dddb8a3..fbad023 100644 --- a/useragent/macos/Runner/DebugProfile.entitlements +++ b/useragent/macos/Runner/DebugProfile.entitlements @@ -2,11 +2,7 @@ - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - + keychain-access-groups + diff --git a/useragent/macos/Runner/Release.entitlements b/useragent/macos/Runner/Release.entitlements index 852fa1a..0833c1b 100644 --- a/useragent/macos/Runner/Release.entitlements +++ b/useragent/macos/Runner/Release.entitlements @@ -4,5 +4,7 @@ com.apple.security.app-sandbox + keychain-access-groups + diff --git a/useragent/pubspec.lock b/useragent/pubspec.lock index d7f4657..e6982a5 100644 --- a/useragent/pubspec.lock +++ b/useragent/pubspec.lock @@ -282,7 +282,7 @@ packages: source: hosted version: "7.0.1" fixnum: - dependency: transitive + dependency: "direct main" description: name: fixnum sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be @@ -770,7 +770,7 @@ packages: source: hosted version: "1.5.2" protobuf: - dependency: transitive + dependency: "direct main" description: name: protobuf sha256: "75ec242d22e950bdcc79ee38dd520ce4ee0bc491d7fadc4ea47694604d22bf06" diff --git a/useragent/pubspec.yaml b/useragent/pubspec.yaml index 683baef..cc653e5 100644 --- a/useragent/pubspec.yaml +++ b/useragent/pubspec.yaml @@ -26,8 +26,10 @@ dependencies: cryptography_flutter: ^2.3.4 riverpod_annotation: ^4.0.0 grpc: ^5.1.0 + fixnum: ^1.1.1 flutter_hooks: ^0.21.3+1 auto_route: ^11.1.0 + protobuf: ^6.0.0 dev_dependencies: flutter_test: @@ -39,4 +41,4 @@ dev_dependencies: auto_route_generator: ^10.4.0 flutter: - uses-material-design: true \ No newline at end of file + uses-material-design: true