Commit Graph

36 Commits

Author SHA1 Message Date
Morten V. Christiansen 139698cab5 Fix Android Playwright tests: connectOverCDP + card reconnect
launchBrowser() hangs indefinitely on Chrome 145 in the Android
emulator. Replaced with chrome-command-line proxy flag + force-stop/
restart + connectOverCDP. A polling retry loop (max 15 s) handles
CDP startup variance.

proxy_service.dart: added _ensureCardOpen() which calls isCardAttached()
and re-runs _tryOpenCard() if the emulator socket was closed (e.g. after
a bridge restart). Called before makeCredential and getAssertion in all
three handler paths so the app reconnects automatically without restart.

playwright.config.js: global timeout 180 s → 60 s.

All 4 tests in k_phone_android.spec.js now pass (16 s total).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:41:36 +02:00
Morten V. Christiansen c6294a46c7 Add Playwright acceptance tests for k_phone proxy routing
Three new specs in tests/:
- k_phone_portal.spec.js: portal UI flow (enroll/login/status/logout/delete)
- k_phone_proxy.spec.js: 4 serial proxy-routing tests via Node http module;
  requires adb forward for emulator use
- k_phone_android.spec.js: same 4 tests with Chrome running inside the
  Android emulator via playwright.android; no port-forward needed,
  auto-skips if no ADB device found

All tests use card_emulator_bridge.py for instant FIDO2 auto-approval —
no physical card or fingerprint interaction required in emulator mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:43:40 +02:00
Morten V. Christiansen 6f08c7eed4 Add k_server assertion verification tests + clarify session login comment
tests/test_k_server.py:
  - TestVerifyAssertionToken (12 tests): unit tests using raw P-256 keys —
    valid accept, wrong path/method, tampered nonce/signature/key, cross-
    resource replay, malformed/empty token, wrong cdj type, missing field.
  - TestVerifyAssertionTokenRoundTrip (5 tests): end-to-end via CardEmulator
    — register, getAssertion with bound challenge, build bundle as k_phone
    does, verify on server.  Tests include wrong path/method and cross-user
    key swap.  Skipped automatically if fido2 is not installed.
  All 17 pass.

proxy_service.dart: add comment to _handleSessionLogin explaining why
  random challenge is correct there (user-presence proof for portal session,
  not per-request resource binding).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:16:08 +02:00
Morten V. Christiansen 3bc47deb27 Extend filter_proxy tests: verify /auth/get-token binding fields
- _mockTokenServer now reads and captures the request body instead of
  draining it — Completer type updated to ({HttpRequest, String rawBody})
- Two new tests: assert that url, method, nonce are present in the
  /auth/get-token request body; verify POST requests carry method=POST

48/48 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:05:46 +02:00
Morten V. Christiansen 3fc40fc395 Implement per-request FIDO2 token binding across all components
Each request to a gated endpoint now triggers a fresh FIDO2 assertion.
Challenge = SHA256(url|method|nonce) — bound to the specific resource.
The self-contained assertion bundle lets the server verify independently
without calling back to the phone.

- fido2_ops.dart: GetAssertionResult gains clientDataJson; getAssertion
  accepts optional challenge override
- proxy_service.dart: _handleAuthGetToken accepts {url,method,nonce},
  derives challenge, runs card assertion, returns b64url bundle
- filter_proxy.dart: _getAuthToken(uri, method) generates nonce and
  passes binding fields to Component 2
- component3/phone.go: stateless GetTokenForRequest(url, method) —
  no session caching, no expiry, one card touch per request
- component3/proxy.go: use GetTokenForRequest
- component3/main.go: remove --user flag (Component 2 picks enrolled user)
- k_server_app.py: _verify_assertion_token() — verifies path+method
  match, challenge claim, and ECDSA-P256 signature; accepts both
  legacy X-Proxy-Token and new Bearer assertion tokens

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 12:01:23 +02:00
Morten V. Christiansen ffa5bea1c7 Remove MITM from Component 3; record per-request token binding decision
- Delete mitm.go: CA generation and HTTPS interception removed entirely
- proxy.go: remove handleGatedConnect, forwardToUpstream, MITM struct field;
  gated CONNECT now returns 407 with explanation
- main.go: remove --ca-dir flag and MITM initialisation
- Workplan.md: record per-request auth decision (challenge bound to
  URL + method + nonce; no session opened; may revisit)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 10:47:34 +02:00
Morten V. Christiansen 920d702dea Refactor k_phone (v2) and add component3 Go binary
k_phone:
- filter_proxy.dart: extract _writeProxyHeaders/_forwardHttpRequest helpers,
  removing ~30 lines of duplication; simplify _handleDirectHttp signature
- proxy_service.dart: import portal_html, merge _serveHtml/_serveEnrollHtml →
  _serveHtmlBytes, extract _parseUsername/_parseUsernameAndDisplay helpers,
  remove dead _loadTlsContext stub, use SessionManager.ttlSeconds (872→455 lines)
- portal_html.dart (new): kPortalHtml/kEnrollHtml/kPortalHtmlBytes/kEnrollHtmlBytes
- session_manager.dart: expose ttlSeconds as public constant
- filter_proxy_test.dart: rewritten for v2 — gated HTTP tests now verify Bearer
  token injection to endpoint directly; 24/24 pass
- k_server_client.dart: deleted (dead code)

component3 (Go proxy — first commit of entire directory):
- gated.go: fix IsGated(host,port) — was silently missing host:port entries
- proxy.go: pass port to IsGated in both handleHTTP and handleConnect
- phone.go: add getToken() calling /auth/get-token to avoid unnecessary FIDO2
  card interactions; fix login() JSON field expires_in→ttl_seconds

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 21:04:19 +02:00
Morten V. Christiansen ddeed9b71e Merge remote history: unify diverged repos from machine switch
Local branch was started fresh on new Mac (2026-04-29) as a workspace
snapshot of the full project state, then extended with Phase 9 k_phone
work. Remote has the complete git history up to 2026-04-27.

This merge grafts the two histories together. Local content is preserved
in full (it is a strict superset of the remote state).
2026-05-04 09:00:52 +02:00
Morten V. Christiansen 328c7d7cae Add Component 2 CONNECT handler; fix CONNECT routing tests
proxy_service.dart: _handleConnect gates on hasAnyActiveSession() (407 if
no active session), then connects directly to the upstream external target
(host:port from Host header), detaches the socket, and pipes bytes
bidirectionally. k_server is not involved in CONNECT tunnels.

filter_proxy_test.dart: replace _mockTcp() with _mockComp2Tcp() in the
CONNECT routing group so the mock speaks the full CONNECT handshake
(reads request headers, sends 200 Connection Established, pauses sub).
All 21 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 20:22:24 +02:00
Morten V. Christiansen 1124a7f5a9 Phase 9: add Component 1 (filter_proxy), tests, session gate, doc update
- k_phone/lib/filter_proxy.dart: Component 1 — raw-socket HTTP proxy with
  gating filter; gated hosts relay to Component 2, others go direct
- k_phone/lib/session_manager.dart: add hasAnyActiveSession() for the
  personal-device gated-proxy authorization model
- k_phone/test/filter_proxy_test.dart: full test suite for Component 1
- k_phone/test/enrollment_test.dart: full test suite for EnrollmentDb
- k_phone/integration_test/registration_login_test.dart: emulator integration test
- Misc k_phone lib fixes (ctaphid_channel, fido2_ops, proxy_service, main,
  enrollment_db, k_server_client) and pubspec/Gradle updates
- CLAUDE.md + Workplan.md: document Component 1, k_phone module map,
  gated terminology (replacing "allowlist"), pending CONNECT handler in
  Component 2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 20:10:54 +02:00
Morten V. Christiansen 83a6382270 Initial commit: chromecard workspace snapshot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 22:06:14 +02:00
Morten V. Christiansen 35c40985dd Update Setup.md and Workplan.md for 2026-04-27 emulator session
Records CardEmulator addition, the two fido2-direct id=/raw_id= bug fixes,
and the expanded test count (100 → 122). Marks project status unchanged:
Phases 7 and 9 remain externally gated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:32:09 +02:00
Morten V. Christiansen 56132528fe Add CardEmulator and fix fido2-direct id= constructor bugs
tests/card_emulator.py: software emulator of the ChromeCard FIDO2
authenticator. Implements make_credential and get_assertion with real P-256
cryptography and an in-memory credential store. Both methods accept
user_confirms=True/False to simulate the card's Yes/No confirmation dialog;
False raises CtapError(OPERATION_DENIED). refusing() returns a wrapper that
forces user_confirms=False for integration tests that route through
_with_direct_ctap2. forget_user() simulates card-side credential removal.
Module docstring serves as the usage guide.

tests/test_k_proxy.py: 22 new tests across TestCardEmulatorUnit (direct
emulator calls) and TestCardEmulatorIntegration (full ProxyState flows
covering register, authenticate, user-says-no, forget, two-user isolation,
and sign-count monotonicity).

k_proxy_app.py: fix two bugs where RegistrationResponse and
AuthenticationResponse were constructed with id= instead of raw_id=. Both
calls raised TypeError at runtime, silently caught by the surrounding except
block, making all fido2-direct register and authenticate calls fail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:31:07 +02:00
Morten V. Christiansen 23c37f4590 Merge docs-maintenance: Phase 6 complete, project in holding pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 13:18:01 +02:00
Morten V. Christiansen 9d6da53b8f Update Workplan current status: phases 6.5/7/9 all externally gated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 13:17:58 +02:00
Morten V. Christiansen 855b4175bc Update Setup.md and Workplan.md for 2026-04-27 session
- fido2-direct confirmed as deployed default after full browser flow with real card
- Document enroll-clears-session bug fix
- Document k_proxy unit test suite (100 tests)
- Record current deployed service state and port map

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 11:29:26 +02:00
Morten V. Christiansen 2cf44e97df Refactor all three service files and fix enroll-clears-session bug
- Update module docstrings to concise service descriptions
- Add _require_json() helper to Handler in k_proxy and k_client_portal,
  eliminating repetitive try/except JSON-parse blocks in handler methods
- Cache SSL context once in ClientState.__init__ instead of per-request
- Fix: ClientState.enroll() now calls /session/logout on k_proxy before
  re-enrolling, so the old server-side session is invalidated rather than
  left to expire (discovered via live test where re-register after login
  caused subsequent logout to fail with missing bearer token)
- Add targeted comments explaining non-obvious invariants: _gc_locked lock
  ownership, _with_direct_ctap2 retry-on-reopen, _require_session None
  convention, will_close connection reuse, HTTP/1.1 body-drain requirement,
  90 s interactive timeout margin, and enroll session-clearing rationale

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 11:27:57 +02:00
Morten V. Christiansen e7212b49a0 Add k_proxy unit tests with mocked card and upstream
100 tests covering session management, enrollment CRUD, probe and direct
FIDO2 auth routing, UpstreamPool connection handling, and all HTTP
endpoints via a live in-process server. Card (FIDO2/CTAP) and k_server
are fully mocked so the suite runs locally without hardware or VMs.

Also hardens the fido2.features.webauthn_json_mapping import guard to
tolerate older python-fido2 versions that lack the attribute.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 10:44:43 +02:00
Morten V. Christiansen 86189793b7 inconsistancies resolved 2026-04-26 07:14:19 +02:00
Morten V. Christiansen bd839ea42d Add Playwright portal regression and harden direct auth 2026-04-25 21:06:08 +02:00
Morten V. Christiansen e57f8a446f Improve portal enrollment controls and direct hidraw selection 2026-04-25 19:29:28 +02:00
Morten V. Christiansen 1d85c21d7f Add k_client browser flow demo 2026-04-25 15:56:50 +02:00
Morten V. Christiansen 689587629a Harden direct auth path and regression helper 2026-04-25 15:49:52 +02:00
Morten V. Christiansen 2448956946 Add CTAP probe and update phase docs 2026-04-25 10:25:40 +02:00
Morten V. Christiansen d0d27a0896 Move browser portal to k_proxy 2026-04-25 01:47:26 +02:00
Morten V. Christiansen 4893eb8312 Add Phase 6 client portal and enrollment flow 2026-04-25 01:42:03 +02:00
Morten V. Christiansen 46fb878f8d Document Phase 2.5 ownership and concurrency 2026-04-25 01:33:16 +02:00
Morten V. Christiansen 4b0b126bf9 Add Phase 2 HTTPS prototype and runbook updates 2026-04-25 01:29:37 +02:00
Morten V. Christiansen 6db7a7e217 Update Qubes chain status docs 2026-04-25 01:12:47 +02:00
Morten V. Christiansen 37600548ac Start Phase 5 proxy/server session reuse prototype 2026-04-24 10:30:40 +02:00
Morten V. Christiansen 3dcac21dd0 Record successful WebAuthn register/login in k_proxy 2026-04-24 06:48:52 +02:00
Morten V. Christiansen b6dbbc4839 Record AppVM startup success after memory tuning 2026-04-24 06:08:43 +02:00
Morten V. Christiansen 4f58b83842 Log Qubes libxenlight VM start blocker 2026-04-24 06:02:47 +02:00
Morten V. Christiansen 8888601f69 Record AppVM template and UI baseline 2026-04-24 05:52:44 +02:00
Morten V. Christiansen d9e9e95b5f Ignore local .codex marker 2026-04-24 05:38:21 +02:00
Morten V. Christiansen 9abf41fcd5 Initialize workspace tracking repo 2026-04-24 05:38:00 +02:00