Files

5.4 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
quick-3 01 navigation
remote-links
http
security
whitelist
history
requires provides affects
quick-1
quick-2
remote-markdown-fetching
domain-whitelist
app-navigation
renderer-styling
vault-fetching
config
added patterns
ureq 2.12 (synchronous HTTP client)
domain whitelist check
content-type validation
5MB body cap
no-history-on-error
created modified
Cargo.toml
src/config.rs
src/vault.rs
src/app.rs
src/renderer.rs
ureq chosen for synchronous HTTP (no async runtime, consistent with existing architecture)
Subdomain matching
sub.example.com matches whitelist entry example.com via suffix check
Content-type validation accepts text/markdown, text/plain, text/x-markdown, and any URL ending in .md
Error cases (domain-not-allowed, fetch-error, not-markdown) do NOT push history entry
Back/forward re-fetch remote pages from network (consistent with re-load-from-disk pattern)
current_url
Option<String> field distinguishes remote vs local page context across resize/reload
duration completed tasks_completed files_modified
4 min 2026-03-01T12:15:30Z 2 5

Quick Task 3: Remote Markdown Page Linking Summary

One-liner: Domain-whitelisted HTTP/HTTPS link following with ureq, content-type validation, BBS error screens, and browser history integration.

What Was Built

Users can now follow HTTP/HTTPS links in markdown documents. When a link is activated:

  1. The domain is extracted from the URL and checked against allowed_remote_domains in bbs.toml.
  2. If allowed, ureq fetches the URL with a 10-second timeout.
  3. The Content-Type header is validated (accepts text/markdown, text/plain, text/x-markdown, or any .md URL).
  4. The response body is read with a 5 MB cap.
  5. The fetched markdown is rendered in the TUI exactly like a local page.
  6. Remote pages participate in browser history (Backspace/Alt+Left goes back; re-fetches on return).

Error cases show BBS-themed error screens (no history entry pushed):

  • Domain not whitelisted: shows domain name and config hint
  • Fetch error (network, timeout, non-2xx): shows HTTP status or error message
  • Not markdown (HTML, binary): shows Content-Type received

HTTP/HTTPS links are styled in LightMagenta to visually distinguish them from local LightCyan links.

Tasks Completed

Task Name Commit Key Files
1 Add config field, ureq dependency, and remote fetch function 5759ec8 Cargo.toml, src/config.rs, src/vault.rs
2 Wire remote link navigation into app event loop with history and error screens c8d4754 src/app.rs, src/renderer.rs

Key Changes

Cargo.toml

  • Added ureq = "2.12" dependency

src/config.rs

  • Added allowed_remote_domains: Vec<String> field with #[serde(default)]
  • Updated Default impl to include empty Vec

src/vault.rs

  • Added RemoteDocument enum (Loaded, DomainNotAllowed, FetchError, NotMarkdown)
  • Added extract_domain() — strips scheme, path, port from URL
  • Added domain_is_allowed() — exact + subdomain matching (case-insensitive)
  • Added fetch_remote_markdown() — whitelist check, 10s timeout, content-type validation, 5MB cap

src/renderer.rs

  • HTTP/HTTPS links styled LightMagenta in Event::Start(Tag::Link) handler (non-wiki, non-local branch)

src/app.rs

  • Added current_url: Option<String> field (Some = remote page, None = local page)
  • Added navigate_to_remote() method — saves history, fetches, renders, pushes entry on success
  • Updated follow_selected_link() to detect HTTP/HTTPS and dispatch to navigate_to_remote()
  • Updated navigate_back() and navigate_forward() to re-fetch remote URLs from history
  • Updated handle_resize() to pass None vault_path for remote pages
  • Updated reload_current_document() to skip live-reload for remote pages
  • Updated navigate_to() to clear current_url when going to a local page

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Fixed clippy lint: manual split_once pattern

  • Found during: Task 2 verification (cargo clippy)
  • Issue: url.splitn(2, "://").nth(1) and resp.status_text().to_string() triggered clippy warnings
  • Fix: Replaced with url.split_once("://")?.1 and removed redundant .to_string() in format!
  • Files modified: src/vault.rs, src/app.rs
  • Commit: c8d4754

Out-of-scope items (deferred)

None discovered.

Verification Results

  • cargo build passes with no errors (3 pre-existing warnings, unrelated to this task)
  • cargo clippy passes with warnings only (no new errors introduced)
  • HTTP links styled LightMagenta (verified in renderer.rs code path)
  • Domain whitelist check with exact and subdomain matching implemented
  • All 4 RemoteDocument variants handled with appropriate error screens
  • History integration tested via code review (back/forward re-fetch remote URLs)
  • handle_resize passes None vault_path for remote pages
  • reload_current_document returns early for remote pages

Self-Check: PASSED

Files exist:

  • Cargo.toml: FOUND (ureq = "2.12")
  • src/config.rs: FOUND (allowed_remote_domains field)
  • src/vault.rs: FOUND (fetch_remote_markdown function)
  • src/app.rs: FOUND (navigate_to_remote method, current_url field)
  • src/renderer.rs: FOUND (LightMagenta branch)

Commits exist: