36 Commits

Author SHA1 Message Date
neon f79874317d perf(koreader): check md5 before bcrypt when authenticating plugin requests
The KOReader plugin sends md5(password) as x-auth-key, which can never match the bcrypt hash of the
plaintext password. The auth guard ran a cost-12 bcrypt compare first, so every authenticated
request spent about 250 ms of CPU and stalled other traffic before the md5 fallback accepted it.

Check md5 first and keep bcrypt as the fallback for clients that send the plaintext password, so the
accepted credentials are unchanged. A plugin auth call drops from about 285 ms to 8 ms.

Bump the KOReader plugin to 2.2.0. The plugin changed after the 2.1.0 release shipped in v3.6.0
(series sorting, series selection, file browser exit, paged Shelves list) without a version bump.

Also fix three metadata-fetch tests that were failing on main since cfcd4ca52 kept single-digit
tokens in tokenizeTitleText. A volume digit in the query diluted the word overlap in scoreTitleMatch,
so an ebook candidate fell under the relevance floor and a manga outranked it. scoreTitleMatch now
drops lone digits again; symmetricTitleSimilarity keeps them to tell volumes apart.

Also align the pnpm version installed in both Dockerfiles with the packageManager field. Since
f2a7a1118 the images installed pnpm 11.22.0 while package.json pinned 11.28.9, so pnpm tried to
switch itself and failed the arm64 image build with a missing @pnpm/exe lockfile entry.

Closes #1983
Ref #2037
2026-11-02 04:54:35 +00:00
neon 199ba687c3 feat(achievements): answer in the language the client asks for
Achievement names, descriptions and category labels, the secret placeholder and the monthly
challenge are text the server writes and every client shows as is, so they stayed English in a
translated web page and will in the localized iOS app. The routes that return them now read
Accept-Language and answer in that language, with Vary: Accept-Language.

The translations live in the web's catalogs under serverText, so Crowdin, its checks and its
translators handle them through the existing pipeline; the server reads that subtree, and the image
copies the catalogs beside dist. English is never looked up: a request without the header, and
every client that predates it, gets the bytes it got before. A test keeps serverText in en.json
equal to the seed and the constants it mirrors. The web now sends its chosen language on every API
request, and the Accept-Language matcher moved into @bookorbit/types so the client and the server
negotiate the same way.

The iOS app is a consumer the web client does not show: it will send its own interface language.
App Store builds that predate that still send the device language, so on a non-English device they
will start getting translated achievement names inside English screens. That was accepted; the
response shape does not change.

Ref bookorbit/bookorbit-ios-support#79
2026-10-30 02:21:07 +00:00
neon 569cc8c84b security(docker): move both images to node 26.12.1
Rebuild the app and read-aloud worker images on Node 26.12.1, which fixes
CVE-2026-111497 in the bundled Brotli decoder and the other October 2026
Node security issues. The app image stays on Alpine 3.23, pinned by digest.
Closes #1912
2026-10-24 22:48:29 +00:00
neon cecbdc44ce security(docker): require patched libexpat version
Prevent cached image layers from retaining the vulnerable Alpine package.
2026-10-20 22:33:08 +00:00
neon 97cd03325f feat(reader): open DjVu documents in the web reader
Scanned books are commonly distributed as DjVu, which the scanner only stored as a supplement.
Decode pages on the server with DjVuLibre so DjVu imports with a cover and page count, opens in
the image reader with its embedded OCR text, and can be the preferred format of an ordinary email
recipient. Migration 0113 widens the recipient format check to allow it.

Decoding runs on validated private snapshots behind a bounded, reader-first queue, and
revalidation and cached pages are answered without a decoder. Released iOS builds cannot open
DjVu, so series continuation offers it only to callers sending includeDjvu=true, and the
dashboard and notebook read file never name it. The first full scan after upgrading promotes
stored .djvu supplements to content.
2026-10-14 21:37:41 +00:00
neon c37821782a security(deps): update dependencies and rebuild kepubify with go 1.27.2
Bump every direct dependency to its newest same-major release and move the
node base image to 26.11.1, which invalidates the cached apk layer and picks
up tiff 4.7.2 for CVE-2026-4775. Rebuild all six kepubify binaries from the
pinned upstream commit with Go 1.27.2 for CVE-2026-78667, CVE-2026-78669 and
CVE-2026-97031, keeping v4-dev so rendition hashes stay stable.
2026-10-11 05:19:04 +00:00
neon 2ced82794f feat(docker): support file-backed secrets
Load mounted secrets before database migrations while preserving direct environment values for existing deployments.

Closes #373
2026-09-14 17:02:03 +00:00
neon d9ea13ba45 feat: add BookOrbit attribution requirements
Define AGPLv3 additional terms and expose attribution, source, and license details through unobtrusive About surfaces.
2026-09-10 18:03:11 +00:00
neon c2f9eea839 chore: add AGPL attribution notice
Preserve project credit in conveyed source distributions and include the legal files in runtime images.
2026-09-10 13:32:29 +00:00
neon 04a0f21c8b feat(server): allow configuring the listen address
Allow native and host-network deployments to select an IPv4 or IPv6 bind
address through HOST while preserving the existing wildcard default.
Keep Docker health checks aligned with the configured listener and document
how to restrict host port publishing independently of the container address.
Cover validation, real bootstrap sockets, and health-check commands with tests.

Closes #1315
2026-09-09 10:26:12 +00:00
neon e3241eea3d security(deps): patch container vulnerabilities
Use the supported Alpine 3.23 Node image to avoid vulnerable util-linux packages in Alpine 3.24. Force fast-uri 3.1.6 to resolve the SSRF advisories reported by the image scan.
2026-09-05 10:06:56 +00:00
neon 45a2ae93c8 perf(docker): use lightweight health probe
Avoid launching a full Node runtime every 30 seconds so idle containers do not create unnecessary CPU, memory, and disk pressure. Let Compose inherit the image probe to keep one source of truth.

Closes #1129
2026-08-24 23:21:43 +00:00
neon 5f465156ac fix(stats): resolve day boundaries in the reader's timezone
Day keys are written per reader but read back using UTC, the database server's CURRENT_DATE, or
the server process's local year, so streaks and day-based achievements were evaluated against the
wrong day. Route every lookup through one resolved timezone on the evaluation context.

Install tzdata so the container honours TZ for date and subprocesses. Node already resolved TZ
through ICU, so no reading data was affected by the missing package.

Closes #1084
2026-08-24 04:16:37 +00:00
neon 197f6b6b30 fix(docker): stop the image build re-installing into a partial workspace
pnpm 11 changed the default of verifyDepsBeforeRun to "install", so `pnpm run` now
resolves and installs before executing a script. Each builder stage already installs its
own filtered subset with a frozen lockfile two steps earlier, so that install is redundant
work at best.

At worst it is fatal. No builder stage carries the whole workspace: the server stage never
copies client/, so the re-install resolves against a workspace with no client, finds
nothing depending on @embedpdf, and rejects the workspace-level patches for it with
ERR_PNPM_UNUSED_PATCH. The image has not built since the pnpm 11 upgrade.

Turn the check off for both build steps rather than widen the patch allowance, because the
dependencies genuinely are already installed and correct at that point; verifying them
against a workspace that was deliberately narrowed can only produce a wrong answer.
2026-08-16 20:51:21 +00:00
neon 30cfcd8ba3 fix(docker): drop pip from the runtime image to clear the image scan
pip is only needed to install the Kobo cloudscraper requirements. Leaving it
in the final image also leaves pip/_vendor/vendor.txt, which Trivy reads as
installed msgpack 1.1.2 and setuptools 70.3.0 and fails the CRITICAL,HIGH
gate. Neither is an application dependency, and setuptools is not present in
the image as code at all.

Verify by building both variants for linux/amd64 and scanning with Trivy
0.70.0 at the workflow's settings: the current layer exits 1 with exactly
those two findings, the stripped layer exits 0. cloudscraper still imports
and creates a scraper, and removing py3-pip orphans no runtime tooling.

The setup:kobo-cloudscraper script still shells out to pip, but it needs tsx
and only ever runs in local development, never in the image.
2026-08-16 04:18:43 +00:00
neon d7556011df build(deps): upgrade Node.js to 26 and pnpm to 11
Update package manager configuration to pnpm 11.22.0 and Node.js requirement to Node 26 across Dockerfile, GitHub Actions workflows, root package.json, and workspace configurations.

Upgrade dependencies, update GitHub Action versions, and remove deprecated scorecard workflow.
2026-08-16 00:41:56 +00:00
Jadehawk ec84703cef feat(koreader): enhance settings and plugin behavior (#669)
* feat(koreader): add device file naming and improve plugin downloads (BO-658)

* fix(koreader): secure download paths and test collisions

* fix(koreader): preserve bulk collision identities

* fix(koreader): improve device file naming validation and path generation

* fix(koreader): remove duplicate settings lookup and audit file naming changes

* fix(koreader): resolve remaining CodeRabbit review issues

* fix(koreader): validate book detail query and finalize file naming release

validate book detail deviceId via DTO and ValidationPipe

localize new KOReader file naming settings (de, nl, sl)

bump KOReader plugin version to 1.3.0

* chore: rerun CI

* chore: normalized Closes #658 to not have embedded URL to issue. This is failing PR Conventions test

* test(koreader): align source and device removal assertions

* test(koreader): cover file naming settings flows

* test(koreader): cover file naming sync requests

* test(koreader): close remaining patch coverage gaps

* test(koreader): cover file naming server paths

* docs: add fixed2 modifier to file naming reference

* feat(koreader): support custom file naming patterns for KOReader sync

Add support for configurable KOReader file naming patterns, allowing users to define dynamic path templates for sync targets. Include UI draft settings, preview updates, and server path resolution.

Closes #658

---------

Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
Co-authored-by: jadehawk <jadehawk@hotmail.com>
2026-07-14 11:26:27 -06:00
neon d8a7bd10f4 build(docker): include dependency patches in image builds
Copy workspace patch files before frozen installs so pnpm can validate patched dependencies. Permit unused client patches only while deploying the server production bundle.
2026-07-11 19:43:45 +00:00
neon c28ea29671 feat(sync): three way (kobo, koreader and bookorbit) progress and annotation sync (#338)
Introduces a custom KOReader plugin to synchronize reading progress, stats, and annotations. Adds backend controllers, services, and database schema updates to ingest plugin data. Updates the frontend to display KOReader annotations alongside built-in reader highlights.

Closes #337
2026-06-25 20:13:04 -06:00
neon 2143b00cc5 fix(scanner): handle watched moves across docker libraries
Emit transfer events when watcher reconciliation moves a book between libraries. Keep file-as-book and folder-as-book watcher paths consistent across Docker, direct runs, and delayed copy-delete moves.

Closes #386
2026-06-21 19:15:39 +00:00
neon 329d1b6643 feat(metadata): add Kobo metadata provider
Add Kobo as a first-class metadata source so books can keep Kobo IDs across fetch, edit, import, scoring, and file-write flows. Provide the Python cloudscraper setup needed for production fetches while keeping local setup explicit.

Closes #247
2026-06-06 18:16:47 +00:00
neon 3138cf3a4d fix(security): complete sanitizeLogValue sweep, DOMParser stripHtml, least-privilege CI permissions, pin Dockerfile image 2026-05-15 00:15:23 +00:00
neon f9c1e29911 feat: implement version UI and short-sha CI versioning 2026-05-13 22:24:46 +00:00
neon 6b650981da fix(docker): rebuild kepubify with Go 1.26.3, fix read-only fs chmod
Replaced pre-compiled kepubify binaries (built with Go 1.17.8, 53
HIGH/CRITICAL CVEs) with binaries rebuilt from source using Go 1.26.3
and golang.org/x/text upgraded to v0.3.8, resolving all fixable CVEs.

Also fixed KepubifyBinaryService incorrectly falling back to downloading
the binary on every startup in read-only containers. chmod() was throwing
EROFS, and the single catch block treated it as a missing file. Split
stat and chmod into separate try/catch so only a missing-file error
triggers the download fallback.
2026-05-11 18:42:18 +00:00
neon 4a53a9250e fix(audio): replace npm ffprobe/ffmpeg installers with system binaries to fix Alpine/musl incompatibility in Docker 2026-05-11 00:43:44 +00:00
neon 94af42cbbf revert: undo kepubify Docker build-time install 2026-04-14 07:42:29 -06:00
neon ad46061db7 chore: install kepubify into Docker image at build time
- download correct arch binary from projectx-tools during image build
- use system binary at /usr/local/bin/kepubify when available, fall back to runtime download for local dev
2026-04-13 23:13:01 -06:00
neon 26d1e6ebc8 feat: improve header UI and optimize docker storage configuration 2026-04-08 20:34:38 -06:00
neon a8b203ef4a chore: optimize docker image and scanner performance 2026-04-08 20:31:38 -06:00
neon ef82cb5d00 fix: patch Trivy CRITICAL/HIGH findings in container image
- apk upgrade in runtime stage to fix OpenSSL CVEs (CVE-2025-15467 CRITICAL, CVE-2025-69419 HIGH)
- remove npm from runtime image to eliminate npm-bundled CVEs
- update fastify to 5.8.5 and force via pnpm override (CVE-2026-33806 HIGH)
- switch vitest pool to threads to fix flaky audio extractor tests
- simplify unit test setup with direct instantiation
2026-04-07 07:30:07 -06:00
neon 0a58a87239 refactor(scanner): rename staging module to book bucket 2026-04-03 20:50:11 -06:00
neon 1418957b6f chore: cleanup project structure and resolve client type errors
- resolve all 69 client type-checking errors for stricter TS compliance
- remove obsolete type-check baseline scripts and files
- overhaul project root with updated README.md and new DEVELOPMENT.md
- migrate to unified baseline migration strategy and cleanup docker configs
- remove redundant production and dev-specific shell scripts
2026-03-25 07:14:51 -06:00
neon 8abfb82214 chore: speed up Docker builds
- drop arm64/QEMU — build amd64 only
- add pnpm store cache mounts to client and server install steps
2026-03-11 14:07:42 -06:00
neon a3579ac57f ci: overhaul CI workflows for reliability and maintainability
- add CODEOWNERS assigning .github/ to @neonsolstice
- configure automated updates for npm, docker, and github-actions ecosystems
- replace custom change-detection bash script with dorny/paths-filter@v4
- consolidate lint, typecheck, and test into a single checks matrix job
- gate per-package change detection via has-changes step (matrix unavailable in job-level if)
- fix duplicate actions/setup-node call in setup-node-pnpm composite action
- scope pnpm store cache key by pnpm version to prevent stale cross-version cache hits
- pin all action references to commit SHAs
- fix container-image concurrency group to use commit SHA across all trigger types
- add timeout-minutes to all jobs
- document fail-fast: false rationale and checks: write trade-off
2026-03-07 18:14:36 -06:00
neon 8dea90d966 feat(docker): add monorepo Docker build with auto-migrate and pdf-lib 2026-01-13 14:28:36 -06:00
neon b4ee0cb90c feat(metadata): add cover extraction for epub, mobi, cbz, and pdf 2025-12-22 14:37:28 -06:00