Commit Graph

12 Commits

Author SHA1 Message Date
Huang Xin 353d381427 fix(deps): bump undici and dompurify overrides for security advisories (#4684)
Raise the pnpm-workspace transitive overrides to the patched versions:

- undici >=7.24.0 -> >=7.28.0 <8 (resolves to 7.28.0). Fixes 7 advisories:
  WebSocket DoS, SOCKS5 cross-origin routing, SOCKS5 TLS bypass,
  Set-Cookie header injection, shared-cache info disclosure, response
  queue poisoning, and SameSite downgrade (GHSA undici < 7.28.0).
  Bounded below 8 to stay on the patched 7.x line and avoid an
  unvetted major bump (an open-ended range pulled undici 8.5.0).
- dompurify >=3.4.9 -> >=3.4.11 (resolves to 3.4.11). Fixes permanent
  ALLOWED_ATTR pollution via setConfig() (<= 3.4.10).

Verified: pnpm test, pnpm lint, pnpm build-web all pass; lockfile sweep
confirms no vulnerable undici/dompurify versions remain.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:30:20 +02:00
Huang Xin f6fbbf59f2 chore(deps): bump transitive deps for security advisories (batch) (#4620)
Resolve a batch of transitive Dependabot alerts on the web lockfile via
pnpm-workspace overrides.

Bumped existing overrides:
- vite >=7.3.5 (#244 high, #245 med; GHSA path within 7.3.x) <- was 7.3.2
- dompurify >=3.4.9 (#249-#255; clears #252 <=3.4.6 by leaving the range)
- protobufjs >=7.6.3 <8 (#233, #247, #248); bounded <8 to stay on the
  patched 7.x line (a bare floor let pnpm jump to the 8.x major)
- ws >=8.21.0 (#241 high) <- was pinned 8.20.1

Added overrides:
- form-data >=4.0.6 (#246 high)
- js-yaml >=4.2.0 (#243 med)
- '@babel/core' >=7.29.6 (#242 low)
- '@opentelemetry/core' >=2.8.0 (#256 med)

Not auto-fixable here: #236 @ai-sdk/provider-utils (<=3.0.97, no recorded
fix; the installed 3.0.25 is pinned via a local patchedDependencies patch).

Verified: pnpm test (5685 passed), pnpm lint, pnpm build-web (exit 0).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 21:19:36 +02:00
Huang Xin d6e59cedd7 chore(deps): bump esbuild to 0.28.1 and vitest to 4.1.x for security advisories (#4618)
Resolve transitive Dependabot alerts on the web lockfile.

esbuild >= 0.28.1 (GHSA-gv7w-rqvm-qjhr #239, GHSA-g7r4-m6w7-qqqr #238):
Deno-module RCE via NPM_CONFIG_REGISTRY and Windows dev-server arbitrary
file read. Forced via a pnpm-workspace override (esbuild is a regular dep
of vite, so the override applies cleanly); bounded to <0.29 to stay on the
verified line. vite 7.3.3 declares ^0.27.0, but the 0.28 JS API is
unchanged for vite's usage -- verified by the full test run and web build.

@vitest/browser >= 4.1.8 (GHSA-g8mr-85jm-7xhm #240): Browser Mode CDP
bridge bypasses allowWrite/allowExec, enabling config overwrite -> RCE.
Bumped the vitest devDep family (vitest, @vitest/browser-*, coverage-v8)
from ^4.0.18 to ^4.1.8; resolves to 4.1.9.

Verified: pnpm test (5685 passed), pnpm lint, pnpm build-web (exit 0).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 21:01:17 +02:00
Huang Xin 607e646bc6 chore(deps): bump shell-quote to 1.8.4 and qs to 6.15.2 for security (#4523)
Raise the pnpm overrides so the patched transitive versions are pulled:

- shell-quote >=1.8.4 fixes GHSA-w7jw-789q-3m8p / CVE-2026-9277 (critical):
  quote() failed to escape newlines in object .op values, allowing shell
  command injection. Pulled in via cpx2.
- qs >=6.15.2 fixes GHSA-q8mj-m7cp-5q26 / CVE-2026-8723 (medium):
  qs.stringify DoS on null/undefined entries in comma-format arrays with
  encodeValuesOnly. The prior >=6.14.2 pin still allowed vulnerable 6.15.1.
  Pulled in via express, body-parser, googleapis-common.

Resolves Dependabot alerts:
- https://github.com/readest/readest/security/dependabot/237 (shell-quote)
- https://github.com/readest/readest/security/dependabot/235 (qs)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:19:25 +02:00
Huang Xin f6dfd09d82 feat(send): browser extension that clips pages into Readest as EPUBs (#4266)
Replaces the URL-only placeholder extension with a full MV3 page-clipper
that builds a self-contained EPUB on the user's machine and uploads it
to the inbox.

- Captures the rendered DOM in a content script, then runs Readability,
  asset bundling, and EPUB build through the shared
  `convertToEpub({kind: 'page'})` pipeline inside a Chrome offscreen
  document (the SW lacks DOMParser).
- Uploads the resulting EPUB directly from the offscreen page to the
  new `POST /api/send/inbox/file` endpoint — keeps the bytes in one
  realm because `runtime.sendMessage` JSON-serialises ArrayBuffer to
  `{}` between extension contexts.
- Adds a long-lived Port + ping handshake between SW, offscreen, and
  the on-demand capture content script so neither idle-eviction nor
  load-order races can hang the popup.
- Localised popup, badge feedback, key-as-content i18n (`_('English source')`)
  with an extract script that seeds locale stubs from i18n-langs.json
  and writes a static-imports map for the runtime. All 33 locales
  fully translated.
- Server: `pages/api/send/inbox/file.ts` accepts a raw EPUB body
  (Content-Type: application/epub+zip), enforces the inbox pending cap,
  stores to the existing send-inbox R2 bucket as `kind='file'`.
  `assetBundler` now sets `credentials: 'include'` in the non-Tauri
  branch so the extension SW carries paywalled-CDN cookies.
- 47 vitest cases for the extension shell (upload, badge, auth, lazy,
  popup state machine, auth-bridge token sync) + 8 cases for the new
  server endpoint. CI's `test_web_app` invokes both via the extended
  `test:pr:web` plus a `build-browser-ext` step that catches webpack
  alias / Tauri-stub regressions.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:45:29 +02:00
Huang Xin 0b18de0581 feat(send): Send to Readest — multi-channel capture into your library (#4230)
* feat(send): Send to Readest — multi-channel capture into your library

A Send-to-Kindle equivalent: email, web-upload, share, or one-click
capture books and articles into the cloud library; they sync to every
device.

Architecture (client-side processing): out-of-app channels drop a raw
payload into a per-user send_inbox; Readest clients drain it through one
shared ingestService.ingestFile(). The server never parses or converts.

- ingestService.ingestFile() — channel-agnostic import orchestration
  extracted from library/page.tsx (DI-based, forceUpload support).
- send_addresses / send_allowed_senders / send_inbox tables + RLS + 4
  SECURITY DEFINER claim/lease RPCs (migration 012_send_to_readest.sql).
- Conversion subsystem (DOCX/RTF/HTML/article/TXT -> EPUB) in a Web Worker.
- send-email Cloudflare Email Worker; inbox-drainer controller +
  useInboxDrainer hook; /api/send/* routes.
- Send to Readest settings panel: inbound address, approved-sender
  allowlist, recent activity, per-device drain toggle.
- /send web page (file drop + article URL) + SSRF-guarded fetch-url proxy.
- OS-shared files routed through ingestFile; Manifest V3 browser extension.

Security: inbox state changes only via SECURITY DEFINER RPCs (clients get
SELECT-only on send_inbox); approved-sender allowlist gates email;
SSRF guard on the one server-side URL fetch; inbox payload signed URLs
authorize against send_inbox.user_id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: run format:check in the pre-push hook

Biome format checking is fast (~0.4s), so gate pushes on it too — catches
mis-formatted files that bypassed the staged-only pre-commit hook before
they reach CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(send): address CodeQL security findings

- ReDoS (senders.ts): the email regex had ambiguous quantifiers around
  the literal dot. Rewrote it linear-time (domain labels exclude '.')
  and cap the input at 254 chars.
- XSS (convertToEpub.ts): run untrusted HTML through DOMPurify
  (sanitizeForParsing — keeps document structure) before DOMParser, so
  title extraction and Readability never parse executable markup.
- SSRF (fetch-url.ts): harden the host guard — block bare single-label
  hostnames, IPv4-mapped IPv6, CGNAT/benchmark/multicast ranges, and the
  unspecified address. DNS rebinding stays a documented residual risk.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 20:06:52 +02:00
Huang Xin d25c41ee89 chore(security): address code scanning findings (#4224) 2026-05-19 09:01:07 +02:00
Huang Xin e8df651d5a chore(deps): bump Next.js to version 16.2.6 (#4143) 2026-05-13 10:57:06 +02:00
Huang Xin c86af457e7 chore: bump Next.js to 16.0.3 (#2496) 2025-11-21 12:49:36 +01:00
chrox 01ad5dbb14 Add books parsing function using foliate-js 2024-10-12 21:29:54 +02:00
chrox 63107506b7 Add module nativeAppService 2024-10-12 20:59:44 +02:00
chrox 866964cb12 Initialize project workspace using tauri-app and create-next-app 2024-10-12 19:42:06 +02:00