da2b58ef96
feat(capture): mark stalled running jobs failed on server startup
2026-06-26 12:57:59 +02:00
cfd51778b1
feat(capture): async capture_handler (spawn_blocking) + job poll endpoint
2026-06-26 12:57:44 +02:00
27b37c3b6d
feat(capture): CaptureJobSummary type and archive::get_capture_job
2026-06-26 12:56:38 +02:00
d86a4d92a8
feat(capture): capture_jobs schema and DB helpers
2026-06-26 12:56:10 +02:00
9ac28459ed
feat(capture): async polling in CaptureDialog + pollCaptureJob api helper
2026-06-26 12:54:31 +02:00
f76f5438f2
feat(auth): Track 4 auth foundation — sessions, roles, login, setup wizard
...
Implements the full auth foundation layer across 13 atomic task commits:
Core DB (archivr-core/database.rs):
- initialize_auth_schema: roles, user_roles, sessions, api_tokens, instance_settings
- open_auth_db: dedicated server-level auth SQLite (separate from archive DBs)
- create_owner, compute_role_bits: cumulative role assignment (guest=1 user=2 admin=4 owner=8)
- create_session, get_session, delete_session, touch_session, delete_expired_sessions
- create_api_token, get_user_for_token, list_user_tokens, delete_api_token
Server (archivr-server):
- auth.rs: AuthUser Axum extractor (cookie→session or Bearer→token), Argon2id
password hashing, random token generation, role bit constants
- AppState gains auth_db_path; ServerRegistry gains optional auth_db_path field
- main.rs: auth DB path computed from config dir, session cleanup background task (24h)
- setup_guard middleware: 503 SERVICE_UNAVAILABLE for all non-/api/auth/ routes until
first owner account is created via POST /api/auth/setup
- Auth endpoints: GET|POST /api/auth/setup, POST /api/auth/login, POST /api/auth/logout,
GET /api/auth/me, GET|POST|DELETE /api/auth/tokens
- WRITE routes guarded with ROLE_USER: captures, tag create/assign/remove
Frontend:
- LoginPage.jsx, SetupPage.jsx (new)
- App.jsx: AuthContext, auth state machine (loading→setup→login→authenticated),
setup check on mount, auth:expired event listener
- api.js: checkSetup, doSetup, login, logout, fetchMe, 401 interceptor
- Topbar.jsx: user menu with username and logout button
Docs:
- NEXT.md: Track 4 marked done, Tracks 5-8 stubs added, old tracks renumbered
159 tests green. Frontend builds cleanly.
2026-06-26 12:04:08 +02:00
7cebf06124
chore: update Cargo.lock after frontend build
2026-06-26 12:03:30 +02:00
37fd057c1f
fix(auth): use rfc3339 for session expires_at; update tag tests for auth guards
2026-06-26 12:03:13 +02:00
7671049f55
Merge branch 'task/auth-docs'
2026-06-26 11:59:31 +02:00
8edd17d694
Merge branch 'task/auth-topbar'
2026-06-26 11:59:31 +02:00
a983b6090a
Merge branch 'task/auth-frontend'
2026-06-26 11:59:31 +02:00
59a37a2ce3
Merge branch 'task/auth-session-cleanup'
2026-06-26 11:59:24 +02:00
059196252b
Merge branch 'task/auth-route-protection'
2026-06-26 11:59:24 +02:00
64706cb976
Merge branch 'task/auth-tokens'
2026-06-26 11:59:24 +02:00
6fd5e8881e
Merge branch 'task/auth-endpoints'
2026-06-26 11:59:24 +02:00
c806b0bbaf
Merge branch 'task/auth-extractor'
2026-06-26 11:59:24 +02:00
0a3cde9005
Merge branch 'task/auth-appstate'
2026-06-26 11:59:24 +02:00
98bb5f03b0
Merge branch 'task/auth-session-helpers'
2026-06-26 11:59:18 +02:00
2e2ce4b6ac
Merge branch 'task/auth-user-helpers'
2026-06-26 11:59:18 +02:00
8ed79192eb
Merge branch 'task/auth-schema'
2026-06-26 11:59:18 +02:00
1bbc0a108c
Merge branch 'task/auth-deps'
2026-06-26 11:59:18 +02:00
f9d2ac80e7
feat(auth): session cleanup background task (24h interval)
2026-06-26 11:57:14 +02:00
cb376aa986
feat(auth): apply ROLE_USER guard to WRITE routes (captures, tags)
2026-06-26 11:56:38 +02:00
36c7d575e2
feat(auth): API token endpoints (create, list, delete)
2026-06-26 11:55:05 +02:00
affb8aadc0
feat(auth): login, logout, /me, setup endpoints + setup_guard middleware
2026-06-26 11:53:58 +02:00
db28d038d9
feat(auth): AuthUser extractor, password helpers, token generation
2026-06-26 11:50:29 +02:00
a4239ba5fc
feat(auth): add auth_db_path to AppState, registry, and main.rs
2026-06-26 11:46:23 +02:00
86e8049f1b
feat(auth): session and token DB helpers
2026-06-26 11:32:32 +02:00
f482707b75
feat(auth): user and role DB helpers (create_owner, compute_role_bits)
2026-06-26 11:31:20 +02:00
696a5e1ac7
feat(auth): add initialize_auth_schema, open_auth_db, and auth record types
2026-06-26 11:30:02 +02:00
7fcc207de7
feat(auth): user menu and logout button in Topbar
2026-06-26 11:29:13 +02:00
0a5c899c5e
feat(auth): frontend login/setup pages + auth state in App.jsx
2026-06-26 11:28:58 +02:00
57fc48d73c
feat(auth): add argon2, rand, axum-extra dependencies
2026-06-26 11:28:51 +02:00
decaef389b
docs: mark Track 4 auth foundation done, add Tracks 5-8 stubs, renumber roadmap
2026-06-26 11:28:21 +02:00
7584e309de
chore: remove docs/superpowers from gitignore (not for VCS)
2026-06-26 11:19:40 +02:00
d81b8fd793
docs: add Track 4 auth foundation implementation plan
2026-06-25 17:38:30 +02:00
151835258b
docs: fix 8 reviewer findings in auth foundation spec
...
- Role hierarchy: cumulative assignment + ROLE_GUEST floor; owner gets role_bits=15
- ALTER TABLE: move default_entry_visibility into CREATE TABLE DDL (idempotent)
- Session cookie: add Secure flag conditionally on HTTPS (X-Forwarded-Proto)
- API token role_bits: live query user_roles per request (vs snapshot)
- POST /api/auth/setup after complete: returns 409 already_configured
- users.role placeholder: use 'admin' in ensure_owner_exists INSERT
- Disabled users: extractor JOINs users and checks status='active'
- last_seen_at throttle: conditional update if >60s elapsed
2026-06-25 17:27:33 +02:00
10aeebd878
docs: add Track 4 auth foundation design spec + whitelist docs/superpowers in gitignore
2026-06-25 17:20:17 +02:00
5fba6987a3
fix(capture): remove debug println! from hash_exists
2026-06-25 16:19:33 +02:00
351e74df09
feat(fonts): wire font extraction into capture pipeline + blob serving route
...
- capture.rs: add archive_id: Option<&str> to perform_capture; when Some,
call font_extractor::extract_and_rewrite before hashing HTML, register
each font as a deduplicated blob + 'font' artifact
- main.rs: pass None as archive_id (CLI keeps fonts embedded)
- routes.rs: add GET /api/archives/:id/blobs/:sha256 (serve_blob handler),
pass Some(&archive_id) to perform_capture in capture_handler,
add ApiError::internal constructor
2026-06-25 16:07:50 +02:00
22b0a55730
feat(fonts): hash_bytes, get_blob_by_sha256, font_extractor module
...
- fix(hash): hash raw bytes instead of lossy UTF-8; add hash_bytes
- feat(database): add get_blob_by_sha256 lookup
- feat(font_extractor): extract embedded font data-URIs from archived HTML
2026-06-25 16:02:57 +02:00
f6d636fce2
feat(singlefile): add UA, disable-web-security, and user-data-dir
...
- --user-agent: realistic Chrome UA so servers don't block headless string
- --browser-args=[--disable-web-security, --user-data-dir]: lets single-file
inline fonts from any cross-origin CDN (e.g. fonts.gstatic.com) regardless
of ACAO headers; user-data-dir required for --disable-web-security to take
effect in newer Chromium builds (otherwise silently ignored)
2026-06-25 11:39:24 +02:00
ab353f9209
fix(singlefile): improve font capture and eliminate ES module viewer errors
...
Font fidelity:
- --browser-wait-delay=2000: Cloudflare Fonts injects @font-face CSS after
HTML parse; the font hook needs extra time to see it after networkidle2
- --remove-unused-fonts=false: preserve @font-face rules even when fonts
haven't rendered yet (font-display:swap, off-screen text)
- --remove-alternative-fonts=false: preserve unicode-range subsets instead
of stripping them as 'alternatives'
ES module viewer error fix:
- Write a user script (sf-strip-scripts.js) that listens for
single-file-on-before-capture-start and removes all <script> elements
(except application/ld+json) from the live DOM before serialization.
Scripts still execute during capture for CSS fidelity; none end up in
the saved file, so no data:-URL base ES module resolution errors.
2026-06-24 21:30:14 +02:00
852cc45956
fix(singlefile): disable CSS stripping and script blocking for full render fidelity
...
Defaults that were destroying CSS fidelity:
- --remove-unused-styles=true: strips CSS nesting rules (site uses & selector)
and any rule targeting JS-applied classes
- --remove-alternative-medias=true: deletes @media blocks that don't match
the capture viewport, breaking responsive layout
- --block-scripts=true: prevents JS from applying classes before CSS snapshot
All three now set to false.
2026-06-24 21:15:36 +02:00
fbb96fbd05
build(frontend): update bundled assets after favicon+rendering changes
2026-06-24 21:05:35 +02:00
1239ad9f34
feat(ui): show website favicon in entry list for webpage entries
2026-06-24 19:16:21 +02:00
1206d7103d
feat(server): add GET /entries/:uid/favicon endpoint
2026-06-24 19:16:21 +02:00
cc2dbf4ac2
feat(archive): add has_favicon to EntrySummary
2026-06-24 19:16:21 +02:00
653efa9705
feat(capture): store favicon artifact for WebPage entries
2026-06-24 19:16:21 +02:00
ee697625fb
feat(singlefile): add SaveResult, favicon extraction, wait for networkidle2
2026-06-24 19:16:21 +02:00