From ae102323f606f9f8ac57d95ab09239f2d977a4a2 Mon Sep 17 00:00:00 2001 From: Laan Tungir Date: Thu, 16 Jul 2026 11:17:13 -0400 Subject: [PATCH] v0.0.30 - Local file browsing: test site, storage/media tests, load-failed URL fix, title logging fix, README update --- .gitignore | 11 + README.md | 233 +++++++----- VERSION | 2 +- src/tab_manager.c | 67 +++- src/version.h | 4 +- tests/local-site/404.html | 20 + .../local-site/LOCAL-FILE-BROWSING-REPORT.md | 348 ++++++++++++++++++ tests/local-site/about.html | 34 ++ tests/local-site/assets/data.json | 13 + tests/local-site/assets/external.js | 5 + tests/local-site/assets/favicon.svg | 4 + tests/local-site/assets/home.js | 5 + tests/local-site/assets/logo.svg | 4 + tests/local-site/assets/pic.svg | 7 + tests/local-site/assets/site.css | 51 +++ tests/local-site/contact.html | 23 ++ tests/local-site/data.html | 86 +++++ tests/local-site/encoded name.html | 23 ++ tests/local-site/form-target.html | 26 ++ tests/local-site/form.html | 47 +++ tests/local-site/gallery.html | 42 +++ tests/local-site/hash.html | 35 ++ tests/local-site/history.html | 62 ++++ tests/local-site/iframe.html | 64 ++++ tests/local-site/index.html | 81 ++++ tests/local-site/media.html | 123 +++++++ tests/local-site/popup.html | 61 +++ tests/local-site/query.html | 32 ++ tests/local-site/scripts/external.html | 20 + tests/local-site/storage-test.html | 197 ++++++++++ tests/local-site/storage.html | 100 +++++ .../subdir/deep/deeper/deepest.html | 24 ++ tests/local-site/subdir/page.html | 34 ++ tests/local-site/subdir/sub.json | 5 + ~/Temp/flowers/index.html | 202 ---------- 35 files changed, 1800 insertions(+), 295 deletions(-) create mode 100644 tests/local-site/404.html create mode 100644 tests/local-site/LOCAL-FILE-BROWSING-REPORT.md create mode 100644 tests/local-site/about.html create mode 100644 tests/local-site/assets/data.json create mode 100644 tests/local-site/assets/external.js create mode 100644 tests/local-site/assets/favicon.svg create mode 100644 tests/local-site/assets/home.js create mode 100644 tests/local-site/assets/logo.svg create mode 100644 tests/local-site/assets/pic.svg create mode 100644 tests/local-site/assets/site.css create mode 100644 tests/local-site/contact.html create mode 100644 tests/local-site/data.html create mode 100644 tests/local-site/encoded name.html create mode 100644 tests/local-site/form-target.html create mode 100644 tests/local-site/form.html create mode 100644 tests/local-site/gallery.html create mode 100644 tests/local-site/hash.html create mode 100644 tests/local-site/history.html create mode 100644 tests/local-site/iframe.html create mode 100644 tests/local-site/index.html create mode 100644 tests/local-site/media.html create mode 100644 tests/local-site/popup.html create mode 100644 tests/local-site/query.html create mode 100644 tests/local-site/scripts/external.html create mode 100644 tests/local-site/storage-test.html create mode 100644 tests/local-site/storage.html create mode 100644 tests/local-site/subdir/deep/deeper/deepest.html create mode 100644 tests/local-site/subdir/page.html create mode 100644 tests/local-site/subdir/sub.json delete mode 100644 ~/Temp/flowers/index.html diff --git a/.gitignore b/.gitignore index 67be676..02111f9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,14 @@ nostr_core_lib/ # auto-generated embedded web content (built by embed_web_files.sh) src/embedded_web_content.c src/embedded_web_content.h + +# binary media files for local-site test (too large for git) +tests/local-site/assets/*.mp3 +tests/local-site/assets/*.m4a +tests/local-site/assets/*.mp4 +tests/local-site/assets/*.webm +tests/local-site/assets/*.ogg +tests/local-site/assets/*.ogv +tests/local-site/assets/*.wav +tests/local-site/assets/*.avi +tests/local-site/assets/*.mkv diff --git a/README.md b/README.md index c8f88cb..32827cf 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,13 @@ because trust moves to the layer where it belongs: your keys. 4. **Deprecated web security, deliberately.** Same-origin policy, CORS, and certificate enforcement are stripped so pages (and the agent runtime to come) can freely call any endpoint — including FIPS mesh services — without - the workarounds traditional browsers force on automators. + the workarounds traditional browsers force on automators. Security moves + up to the **Qube level** (isolation per VM), so the browser doesn't need + the traditional in-browser security model. +5. **Local file browsing.** Open and operate multipage websites directly from + `file://` with no web server — cross-origin access between local files, + `fetch()`/XHR, iframes, storage, media playback, all work. See + [Local file browsing](#local-file-browsing) below. ## Nostr interaction policy @@ -67,25 +73,28 @@ Conversations and skills are still stored as the same Nostr event kinds (30078 for conversations, 31123 for skills) with the same tags, so they're **compatible** across projects — just not live-synced. -## Non-goals (for now) - -- Agent integration, multi-window agent hosts, didactyl hosting, and the - broader "browser as agent runtime" vision are documented in - [`docs/architecture.md`](docs/architecture.md) and the linked plans, but - **not in scope for the first build**. First: a usable browser with basic - Nostr signing. Then the rest. - ## Current status -Working browser: a C99 + WebKitGTK window with multi-tab support, a URL bar -per tab, Nostr login, and `window.nostr` injection. Verified loading -`https://laantungir.net` cleanly. See -[`docs/webkit-poc-findings.md`](docs/webkit-poc-findings.md) for the friction -report from the POC phase (and the Servo fallback exploration). +Working browser with a broad feature set: -``` -[loaded] https://laantungir.net/ -- title: Laan Tungir -``` +- **Multi-tab browsing** with session restore, tab drag/reorder, context menus +- **Nostr login** (GTK dialog or CLI flags) with multiple methods: generate, + local (nsec), seed (BIP-39), readonly (npub), NIP-46, n_signer hardware +- **`window.nostr` injection** (NIP-07) into every page +- **Agent MCP server** — 100 tools for browser automation via Streamable HTTP + at `http://localhost:17777/mcp` +- **Local file browsing** — open and operate multipage websites directly from + `file://` with no web server (see below) +- **Bookmarks, history, search** — built-in bookmark manager, browsing history, + and search engine integration +- **Keyboard shortcuts** — standard browser shortcuts (Ctrl+T, Ctrl+W, Ctrl+L, + Ctrl+Tab, etc.) +- **Per-user profiles** — separate identities and settings per profile +- **Embedded web content** — `sovereign://` pages for settings, bookmarks, + profile, and agent chat/config + +See [`docs/webkit-poc-findings.md`](docs/webkit-poc-findings.md) for the +friction report from the POC phase. ## Build @@ -94,9 +103,14 @@ Requires Debian 13 (trixie) or similar with WebKitGTK 4.1 dev headers: ```bash sudo apt install libwebkit2gtk-4.1-dev make -./sovereign_browser [url] +./browser.sh start [url] # build + launch (detached, won't hang terminal) ``` +> **Note:** Always use `./browser.sh` to start/stop the browser. Running +> `./sovereign_browser` directly will hang the terminal because the GUI +> process keeps stdout/stderr open. See `./browser.sh --help` or +> [`.roo/agents.md`](.roo/agents.md) for details. + ## Command-line flags Run `./sovereign_browser --help` for the full list. Flags are parsed before @@ -158,21 +172,22 @@ credentials. ### Examples ```bash -# Existing behavior — still works -./sovereign_browser https://example.com +# Basic usage (via browser.sh — recommended) +./browser.sh start https://example.com # Generate a fresh key, skip the login dialog, open a page -./sovereign_browser --login-method generate --url https://example.com +./browser.sh start --login-method generate --url https://example.com # Local key from env, custom agent port -./sovereign_browser --login-method local --nsec "$NSEC" --port 18888 +./browser.sh start --login-method local --nsec "$NSEC" --port 18888 # Read-only (npub), no agent server, two tabs -./sovereign_browser --login-method readonly --npub npub1... \ +./browser.sh start --login-method readonly --npub npub1... \ --no-agent --url https://a.com --url https://b.com -# Via browser.sh (forwards extra args) -./browser.sh start --login-method generate --url https://example.com +# Open a local website (no web server needed) +./browser.sh start --login-method generate \ + --url "file:///path/to/website/index.html" ``` ## Architecture (summary) @@ -195,7 +210,7 @@ credentials. ▼ ┌─────────────────────────────────────────────────────┐ │ WebKitGTK (system lib, ~35 MB) │ -│ Blink-grade renderer + V8 + libsoup network stack │ +│ WebCore renderer + JavaScriptCore + libsoup net │ └─────────────────────────────────────────────────────┘ ``` @@ -211,8 +226,9 @@ infrastructure, multiple uses: | Scheme | Purpose | Status | |--------|---------|--------| -| `sovereign://nostr/*` | `window.nostr` bridge — web pages call `fetch('sovereign://nostr/signEvent')` to sign via the C-side `nostr_signer_t` | Planned | -| `sovereign://settings` | Browser-internal pages (like `chrome://settings`) | Planned | +| `sovereign://nostr/*` | `window.nostr` bridge — web pages call `fetch('sovereign://nostr/signEvent')` to sign via the C-side `nostr_signer_t` | ✅ Working | +| `sovereign://settings`, `sovereign://bookmarks`, `sovereign://profile` | Browser-internal pages (like `chrome://settings`) | ✅ Working | +| `sovereign://agents/chat`, `sovereign://agents/config` | Agent chat and configuration pages | ✅ Working | | `fips://` / `*.fips` | Route to FIPS mesh nodes via TUN interface | Planned | | `nostr://` | Fetch Nostr events from relays, render as HTML | Planned | @@ -277,79 +293,130 @@ is saved to `~/.sovereign_browser/session.txt`. See [`plans/browser-tabs.md`](plans/browser-tabs.md) for the full implementation plan. -### Agent tools +### Local file browsing -The browser embeds a WebSocket server (using libsoup) that allows external -AI agents to control the browser programmatically. Connect to -`ws://localhost:17777/agent` and send JSON tool commands. +sovereign_browser is designed to run websites directly from local files — +open an `index.html` from its directory and navigate as if it were served +over HTTP. No web server required. This is a deliberate design choice: +security is moved up to the Qube level, so the browser doesn't need the +traditional security restrictions (same-origin policy, CORS) that would +block local-file web apps. -The server starts before the login dialog and remains available throughout -the browser's lifecycle. The browser starts normally with the GTK login -dialog — no blocking wait. An agent can log in at any time: while the dialog -is showing, or after the browser is already running. If an agent logs in -while the dialog is open, the agent's login takes priority. +**What works on `file://` pages:** -**Login tools** (available before login): +- **Relative links** between pages — `index.html` → `about.html`, + `subdir/page.html`, `../index.html`, `../../../deep/page.html` +- **Cross-origin access** — all `file://` URLs are treated as same-origin. + Iframes can access their parent's DOM, `window.open()` popups are + accessible, and `fetch()`/XHR work across directories. +- **`fetch()` and `XMLHttpRequest`** — load local JSON, text, and other + files via relative paths (returns `status=0`, the `file://` convention) +- **External resources** — CSS stylesheets, JavaScript files, SVG images, + favicons, ``/`srcset`, ``/`` +- **Video and audio playback** — MP4 video and M4A audio play correctly + with full duration/dimension metadata +- **All browser storage** — `localStorage`, `sessionStorage`, `cookies`, + and `IndexedDB` all work fully (open, upgrade, put, get, count) +- **`history.pushState`/`replaceState`** — SPA-style routing works on + `file://` URLs +- **Query strings and hash fragments** — preserved in `location.href`, + accessible via `location.search`/`location.hash` +- **URL-encoded filenames** — `encoded%20name.html` (file on disk: + `encoded name.html`) loads correctly +- **Form submissions** — GET forms append query strings to the target + page; POST forms navigate (body silently dropped, no server) +- **`window.open()`** — opens local pages in new tabs -- `login_status` — check if logged in -- `login` — authenticate with method: `local` (nsec), `seed` (BIP-39 - mnemonic), `readonly` (npub), `nip46` (bunker:// URL), or `nsigner` - (hardware signer via serial/unix/tcp/qrexec transport) -- `logout` — clear signer and reset state -- `switch_identity` — change identity (same params as login) +**Known limitations (WebKit engine quirks, not bugs):** -**Browser tools** (available after login): +- `fetch()` for missing files throws `Load failed` instead of returning an + error Response (no HTTP status codes on `file://`) +- `