Commit Graph
207 Commits
Author SHA1 Message Date
SnapOtter d705c863e3 Merge feat/transparency-fixer: add PNG Transparency Fixer tool
New AI-powered tool that fixes fake transparent PNGs in one click.
Uses BiRefNet HR-matting (2048x2048) with Sharp defringe post-processing.
2026-05-06 21:57:46 +08:00
SnapOtter 8f9ba701be fix: QR code logo causes preview to vanish and become unrecoverable
The QR code generator's logo feature was broken in production (Docker)
due to three interacting issues:

1. The CSP connect-src directive did not include data:, so the
   qr-code-styling library's internal XHR to convert logo data URLs to
   blobs was silently blocked. The library has no onerror handler, so the
   render promise hung forever after the container was already cleared.

2. crossOrigin: "anonymous" was unnecessarily set on imageOptions for
   data URLs, which can cause canvas taint issues.

3. The logo options used a conditional spread that omitted the image key
   when no logo was set. The library's update() deep-merges options, so
   removing the logo preserved the stale data URL and the QR stayed
   broken even after logo removal.

Closes #121
2026-05-06 21:38:12 +08:00
SnapOtter 84e62e6132 refactor: rename tool display name to "PNG Transparency Fixer" 2026-05-06 18:53:37 +08:00
SnapOtter 75e48f2738 test: add transparency-fixer to GUI AI tools and tools-all E2E tests 2026-05-06 10:39:15 +08:00
SnapOtter eb3d0828cb docs: add transparency-fixer endpoint documentation 2026-05-05 23:24:22 +08:00
SnapOtter 4745e435a4 test: add Playwright E2E tests for transparency-fixer tool 2026-05-05 23:17:24 +08:00
SnapOtter c263834037 test: add integration tests for transparency-fixer tool 2026-05-05 23:14:42 +08:00
SnapOtter 5e45cb292b test: increase QR max-size test timeout to 180s for CI
The 10000x10000 QR generation exceeds 120s on GitHub-hosted runners.
2026-05-05 22:31:53 +08:00
SnapOtter 83fa0a39dc test: add fake transparency PNG fixture for transparency-fixer tool 2026-05-05 21:50:43 +08:00
SnapOtter d46510138f fix: custom logo not showing in sidebar and silent upload failures
The desktop sidebar never rendered the custom logo because only mobile
views used the customLogo state. Added a logo section at the top of
the desktop sidebar that displays the custom logo (or the default
OtterLogo when none is set).

The upload handler used raw fetch() without checking response.ok, so
HTTP 4xx errors (e.g. file too large) were silently ignored and the UI
falsely reported success. Now checks response status and surfaces the
server error message.

Closes #125
2026-05-05 21:45:51 +08:00
SnapOtter f856c26fcb fix: upscale tool times out on CPU-only systems (NAS/low-power hardware)
The upscale function called runPythonWithProgress without a timeout parameter,
defaulting to the bridge's 10-minute hard limit. On CPU-only systems like
Synology NAS devices, Real-ESRGAN 4x upscaling easily exceeds this for modest
images. Additionally, when the timeout fired on the dispatcher path, the Python
process was left running and blocked all subsequent AI operations.

This fix adds an adaptive timeout based on input megapixels, scale factor, and
GPU availability (180s/effective-MP on CPU, 30s/effective-MP on GPU, floor of
10 minutes). It also kills the dispatcher on timeout so subsequent requests can
proceed via a fresh restart.

Closes #119
2026-05-05 21:14:56 +08:00
SnapOtter 7ff100c4f9 docs: update tagline to "Your images never leave your home" 2026-05-05 21:12:44 +08:00
SnapOtter a85f4db97c test: add portrait fixture images and extreme-height regression test
Add test-portrait-tall.png (200x4000) and test-portrait-extreme.png
(100x6000) fixtures. Update crop overflow tests to use fixture files
instead of generating images at runtime, and add a second test case
for extremely tall images.
2026-05-05 20:53:02 +08:00
SnapOtter 1807a43f2d fix: crop tool overflows viewport with tall portrait images
The crop area flex container lacked min-h-0, preventing it from shrinking
below its content's intrinsic height. For tall images, react-image-crop's
CSS (max-height: inherit at specificity 0-1-1) overrides the Tailwind
max-h constraint, and without min-h-0 the flex item refuses to shrink,
causing viewport overflow.

Closes #122
2026-05-05 17:51:01 +08:00
SnapOtter e358634f8b fix: production CSP blocking PostHog/Sentry/Scalar and silent failure hardening
The production CSP had connect-src/script-src/font-src set to 'self' only,
silently blocking all analytics and error reporting in production while
working fine in dev (where CSP is not applied).

CSP fixes:
- Add PostHog ingest + assets origins to connect-src and script-src
- Add Sentry ingest origin to connect-src
- Add Scalar fonts origin to font-src for API docs pages
- Extract CSP construction into testable buildCsp() function

Silent failure hardening:
- Settings/features stores now set loadError flag and allow retry on
  subsequent fetch() calls instead of permanently caching failed state
- Analytics init no longer sets initialized=true before the try block,
  allowing retry on failure
- Settings dialog Tools section disables save button when settings
  failed to load, preventing accidental config wipe
- Branding logo storage moved from process.cwd() to FILES_STORAGE_PATH
  so logos persist across Docker container recreation

Test coverage:
- 16 CSP directive tests covering all external service domains
- Store retry-on-error behavior tests for settings and features stores
- Analytics init retry-after-failure test
2026-05-05 17:16:19 +08:00
SnapOtter 69deeb075f fix: increase vectorize HEIF test timeout to 180s for CI
Vectorize + HEIF decoding is particularly slow on CI runners.
120s was not enough; bump to 180s.
2026-05-01 20:25:12 +08:00
SnapOtter d1f2f63453 fix: add 120s timeout to all HEIF/HEIC integration tests for CI
Comprehensively adds { timeout: 120_000 } to every HEIF/HEIC
integration test across 40 test files. HEIF decoding on CI runners
is significantly slower than local, causing sporadic timeouts at
the default 5s or previous 60s limits.
2026-05-01 19:51:47 +08:00
SnapOtter 332c79f4ce fix: increase all HEIF/HEIC integration test timeouts to 120s for CI
The sharpening HEIF test was timing out at 60s in GitHub Actions.
Bumps all remaining HEIF/HEIC test timeouts from 60s to 120s across
14 integration test files for consistency with vectorize.
2026-05-01 19:05:51 +08:00
SnapOtter 66211ed6a7 fix: resolve 20 Sentry issues and fix navbar test flakiness
Sentry fixes:
- Only send 5xx errors to Sentry (was sending 4xx rate-limit, media type errors)
- Encode non-ASCII chars in X-Output-Filename header (encodeURIComponent)
- Handle FK constraint failures gracefully in file upload, pipeline save, API keys
- Harden getDirSize against ENOENT race on readdirSync

Test fixes:
- Wrap navbar test renders in act() to flush async useEffect state updates
- Add useEffect cleanup to navbar to prevent state updates on unmounted component
- Fixes timeout when running in full test suite
2026-05-01 19:01:05 +08:00
SnapOtter b50e1e0fb3 fix: increase vectorize HEIF test timeout to 120s for CI
Vectorize + HEIF decoding exceeds 60s on CI runners because potrace
(CPU-intensive bitmap tracing) runs on top of slow HEIF decoding.
2026-05-01 15:24:19 +08:00
SnapOtter e466c06cad fix: add 60s timeout to all HEIF integration tests for CI
HEIF decoding via heif-convert is slow on CI runners (~15-30s per
image) and exceeds the default 30s Vitest timeout. Add explicit
60s timeouts to all 16 HEIF input tests across integration suite.
2026-05-01 14:50:03 +08:00
SnapOtter fa479dcee4 fix: resolve 3 pre-existing issues found during test coverage expansion
1. passport-photo 404 vs 501: add base route at /api/v1/tools/passport-photo
   that returns 501 FEATURE_NOT_INSTALLED when the AI bundle is missing,
   matching other AI tools. The /generate sub-route is Sharp-only (no
   sidecar) so it correctly skips the isToolInstalled guard.

2. AuthGuard analytics consent race: don't evaluate shouldShowConsent()
   until analyticsConfig has been fetched (guard on analyticsConfig !== null).
   Prevents redirect to /analytics-consent before config is loaded.

3. Fragile sidebar Settings selector: add openSettings(page) helper to
   E2E helpers that checks sidebar visibility with fallback to button role.
   Replace all 134 occurrences of page.locator("aside").getByText("Settings")
   across 18 test files.
2026-05-01 13:44:04 +08:00
SnapOtter 7ce0f7b431 Merge branch 'worktree-agent-a5c6c830' 2026-05-01 05:28:37 +08:00
SnapOtter 8e3e212146 Merge branch 'worktree-agent-ab98adb0' 2026-05-01 05:28:37 +08:00
SnapOtter d05337ad49 Merge branch 'worktree-agent-a8a8fe4d' 2026-05-01 05:28:37 +08:00
SnapOtter 1889f00554 test: comprehensive GUI settings E2E including API Keys tab and full RBAC coverage 2026-05-01 05:28:00 +08:00
SnapOtter ae241cec19 test: deepen GUI resilience, accessibility, and performance tests 2026-05-01 04:47:55 +08:00
SnapOtter 7342d9d8fd test: add tablet visual regression baselines and cross-browser tests 2026-05-01 04:17:19 +08:00
SnapOtter 43cac02331 Merge branch 'worktree-agent-a3a33bf5' 2026-05-01 04:13:56 +08:00
SnapOtter b5b66248f1 Merge branch 'worktree-agent-a062c389' 2026-05-01 04:13:56 +08:00
SnapOtter d40adb9789 Merge branch 'worktree-agent-a63c6a97' 2026-05-01 04:13:56 +08:00
SnapOtter e071c2868b test: comprehensive GUI E2E for all 47 tools including 13 AI tools 2026-05-01 04:12:57 +08:00
SnapOtter 241dedc31f test: deepen GUI navigation with mobile viewport, footer, responsive, and keyboard tests 2026-05-01 03:35:07 +08:00
SnapOtter b6ee96ed04 test: deepen GUI batch, pipeline, and file-carry E2E tests 2026-05-01 03:33:52 +08:00
SnapOtter 27a144e4d7 Merge branch 'worktree-agent-ae5b9f86' 2026-05-01 03:05:31 +08:00
SnapOtter 6762a4b367 Merge branch 'worktree-agent-aedfd941' 2026-05-01 03:05:31 +08:00
SnapOtter 548d2a30fe Merge branch 'worktree-agent-ac2de4e3' 2026-05-01 03:05:31 +08:00
SnapOtter b193a8321f Merge branch 'worktree-agent-a19378fc' 2026-05-01 03:05:31 +08:00
SnapOtter c9ed48b30e test: deepen integration tests for 8 complex tools (HEIC, large file, batch, edge cases) 2026-05-01 03:05:08 +08:00
SnapOtter e3c5279b92 test: expand E2E-Docker coverage to all 47 tools with auth-failure tests 2026-05-01 02:51:42 +08:00
SnapOtter b663a1fbab test: deepen integration tests for 11 medium tools (HEIC, large file, batch, edge cases) 2026-05-01 02:48:35 +08:00
SnapOtter 270f54950d test: deepen integration tests for 6 simpler tools (HEIC, large file, batch, edge cases) 2026-05-01 02:46:04 +08:00
SnapOtter b622245a35 Merge branch 'worktree-agent-a5f4fa03' 2026-05-01 02:30:04 +08:00
SnapOtter ea665915b4 Merge branch 'worktree-agent-a02ae816' 2026-05-01 02:30:01 +08:00
SnapOtter 3213d05e5c Merge branch 'worktree-agent-aa6874c3' 2026-05-01 02:29:58 +08:00
SnapOtter 41455f98bd test: add path traversal, null-byte, unicode, and concurrent request tests
New adversarial-security.test.ts covering 28 security-focused test cases:
- Path traversal attacks (7): Unix, Windows-style, URL-encoded, double-encoded, embedded
- Null byte injection (4): before extension, embedded, null-only, combined with traversal
- Extreme filename lengths (5): 1000-char, 5000-char, special-char-only, spaces, repeated dots
- Unicode filenames (8): Arabic RTL, Korean, Devanagari, complex emoji, RTLO char, ZWJ, tabs
- Concurrent request racing (4): 10 simultaneous with integrity check, batch+single isolation,
  10 across 5 tools, adversarial+valid mixed
- Server stability (1): post-barrage health verification

No real vulnerabilities found -- sanitizeFilename() in lib/filename.ts properly
handles all tested attack vectors via basename(), dot-dot stripping, and null
byte removal.
2026-05-01 02:29:20 +08:00
SnapOtter 88e6355642 test: add AI tool format matrix covering 13 tools x 17 formats 2026-05-01 02:26:52 +08:00
SnapOtter 7d915f7439 test: deepen AI bridge unit tests with dispatcher protocol and concurrency coverage 2026-05-01 02:25:57 +08:00
SnapOtter 0a0512a153 test: fill image-engine unit test branch coverage gaps 2026-05-01 02:19:56 +08:00
SnapOtter d12b1c0fc6 fix: harden all AI tools against proxy timeouts and filename attacks
Convert all 9 AI tool routes (colorize, restore-photo, remove-background,
enhance-faces, blur-faces, red-eye-removal, erase-object, noise-removal,
upscale) to async 202 processing so none are vulnerable to proxy
connection timeouts.

Also fixes:
- Replace basename() with sanitizeFilename() in all AI tool routes
  (prevents double-extension attacks and adds length truncation)
- Add UUID format validation for clientJobId field
- Fix missing filename sanitization in noise-removal (was using raw
  user-supplied filename with zero sanitization)
- Remove em dash from error message in use-tool-processor
2026-05-01 00:11:03 +08:00