Commit Graph

56 Commits

Author SHA1 Message Date
ralksta
5887706775 fix: restore @ts-expect-error for request.ip in getClientIp
The property was removed from NextRequest types in Next.js 15+ but is
still populated by hosting platforms (Vercel, Netlify, etc.).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 12:15:33 +02:00
ralksta
771cee517a security: implement secure IP retrieval with TRUSTED_PROXIES support (closes #139) 2026-05-06 12:10:20 +02:00
Ralksta
fb32a8cabc Merge PR #164
🛡️ Sentinel: [HIGH] Fix scrypt lockout and timing fallback
2026-05-06 11:59:48 +02:00
google-labs-jules[bot]
59321d88ca ⚡ Bolt: [performance improvement] Optimize map bucketing memory and deduplicate getMapData promises
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-05 10:44:12 +00:00
google-labs-jules[bot]
8ab1a3d5ea Fix scrypt hash generation in plaintext fallback
- Adjusted `generateScryptHash` parameter in plaintext fallback logic in `lib/auth.ts` to use `storedPassword` instead of the intermediate hashed value. This prevents users from getting locked out when they adopt the recommended hash.
- Enhanced plaintext fallback verification to hash `password` and `storedPassword` via keyed HMAC before executing `crypto.timingSafeEqual` to avoid potential timing attacks more securely.

Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-05 10:34:52 +00:00
Ralksta
56f0305763 perf(map): chunk album fetching to prevent OOM errors (#138)
Replaced the unbounded `Promise.all` in `getMapData` with a chunked
fetching approach. This prevents Out of Memory crashes by limiting
the concurrent fetching of large arrays of assets to chunks of 10.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-24 22:12:45 +02:00
Ralksta
f18d9ae3d9 🛡️ Sentinel: [CRITICAL] Fix rate limit DoS vulnerability (#136)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-24 22:12:42 +02:00
Ralksta
006ba539ab fix(rate-limit): mitigate cache flooding vulnerability (#94)
Update in-memory rate limiter to fail secure (reject new requests) when maximum capacity is reached, rather than evicting the oldest tracking entry. This prevents an attacker from bypassing their rate limit by flooding the store with spoofed `x-forwarded-for` IPs to intentionally trigger cache eviction. Also cleaned up temporary files and updated tests to verify the behavior.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:46 +02:00
Ralksta
3bbec5a4ac 🛡️ Sentinel: [CRITICAL/HIGH] Upgrade token encryption to AES-GCM (#117)
Upgraded `encodeAssetId` and `decodeAssetId` to use `aes-256-gcm` (Authenticated Encryption) instead of `aes-256-cbc`.
AES-CBC lacks authentication, leaving it potentially susceptible to padding oracle attacks or ciphertext manipulation.
The new token adds a `v2:` prefix which strictly enforces AES-GCM while supporting legacy fallback for cached urls.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:39 +02:00
Ralksta
13fcfe8436 Fix IP spoofing vulnerability in rate limiter by prioritizing request.ip (#132)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:35 +02:00
Ralksta
fef4c73e86 ⚡ Bolt: Cache parsed YAML to prevent repetitive synchronous file I/O (#91)
- Implement an in-memory `Map` to cache parsed YAML objects.
- Use `structuredClone` to prevent caller mutations from corrupting the cached object state.
- Implement negative caching for missing files.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:22 +02:00
Ralksta
264e48b3cc perf: return Buffer directly instead of wrapping in Uint8Array (#131)
Avoids unnecessary O(N) memory allocation and copy by returning `Buffer.from(...)` directly since Buffer inherits from Uint8Array in Node.js.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:19 +02:00
Ralksta
bb751c32ef perf: add promise deduplication for getAssetInfo (#134)
Add Promise deduplication (request coalescing) to the `getAssetInfo`
method in `ImmichClient` (`lib/immich.ts`) to prevent concurrent
identical requests from firing multiple times to the Immich server.
This is particularly helpful when calling `Promise.all` on multiple
assets concurrently (e.g. hero images on the homepage or multiple
album cover placeholder hashes).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:15 +02:00
ralksta
17398dea39 feat: implement album-level password protection 2026-04-07 23:04:03 +02:00
Ralksta
dbc525e8d8 feat(performance): Add promise deduplication for ImmichClient.getAlbum (#69)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-01 12:46:12 +02:00
Ralksta
258c36899c fix(auth): secure plaintext password comparison against timing attacks (#68)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-01 12:46:04 +02:00
Ralksta
b8833b4e60 🛡️ Fix global DoS vulnerability in rate limiter (FIFO eviction)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-01 12:45:46 +02:00
ralksta
bf72a88d6c perf: implement proper LRU Cache and ETag optimizations 2026-03-27 11:11:23 +01:00
Ralksta
1704cd87fc ⚡ Bolt: [Deduplicate concurrent album fetches] (#50)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-27 10:50:00 +01:00
Ralksta
e3e5972b32 ⚡ Bolt: Optimize base64 decoding for ThumbHash (#40)
* ⚡ Bolt: Optimize base64 decoding for ThumbHash

Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>

* ⚡ Bolt: Fix CI by adding AUTH_SECRET env var to build step

Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-22 09:51:25 +01:00
ralksta
e9154cedb8 fix(security): resolve rate-limiting IP spoofing and eviction bypass 2026-03-15 07:41:49 +01:00
ralksta
922302ce5c chore: implement audit action items and translate hardcoded German text 2026-03-15 07:32:42 +01:00
ralksta
6c20218369 security: fix XSS in map popups, refactor HeroTextContent, add evict test
- escapeHtml() in MapView.tsx sanitises city/country/url/name before HTML injection
- HeroTextContent extracted to top-level component with explicit props (was nested inside async Server Component)
- rate-limit.test.ts: add evictIfFull stress test (6/6 pass)
2026-03-13 12:52:09 +01:00
ralksta
33fd31e926 refactor: deslop — remove dead botanica preset, extract shared helpers
- Remove dead  theme preset (no CSS, not in DevToolbar)
- Extract  from closure → module-level export in lib/config/index.ts
- Extract  helper in app/[...path]/page.tsx to deduplicate password gate check
- Extract  inner component in app/page.tsx (was 4× inline in minimal/fullbleed/mosaic/split)
- Add 8 unit tests for buildSubpageGrid covering undefined, subset fields, layout fallback, and all fields
2026-03-13 11:56:40 +01:00
ralksta
d64a7239d1 refactor: audit improvements - rate limit ceiling, map route protection, lazy DevToolbar, lang=de
- lib/rate-limit.ts: add MAX_STORE_ENTRIES=10k ceiling + evictIfFull() to prevent DDoS memory exhaustion
- app/api/map/route.ts: add IP-based rate limiting (30 req/min) with proper Retry-After headers
- app/layout.tsx: lang='en' → 'de', DevToolbar loaded via dynamic import (reduces main bundle)
- app/layout.tsx: lazy DevToolbar keeps ~17KB out of production bundle via next/dynamic
2026-03-13 11:41:56 +01:00
ralksta
43c59f4bc9 chore: clean up repo root and improve .gitignore
- Remove debug scripts: check_albums.js, check_albums.ts
- Remove git-filter-repo binary from root
- Untrack server.log (was accidentally committed)
- Delete .DS_Store files
- Rewrite .gitignore with clear sections: deps, next.js,
  TypeScript, testing, logs, env, OS/editor, agent tools,
  one-off scripts, deployment, user content
- Add .Jules/ and *.log glob to .gitignore
2026-03-13 11:34:28 +01:00
google-labs-jules[bot]
63e6a2f784 🛡️ Sentinel: [HIGH] Fix missing rate limiting on /api/exif/[id]
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-03-12 11:30:45 +00:00
ralksta
8926fc27b7 perf: add bounded in-memory LRU cache for thumbhash decoding
- Cache up to 1000 entries for thumbHashToBlurDataUrl and thumbHashToDominantHex
- Evicts oldest entry when limit is reached (FIFO on Map insertion order)
- ~100x speedup for repeated decoding of same thumbhash

Closes #7
2026-03-11 23:34:04 +01:00
ralksta
134eae94e4 feat(subpages): add optional sections with typographic TOC
- Add SubpageSectionConfig type to schema.ts
- Update config parser to handle sections with album overrides
- Refactor SubpageGridView to render TOC + section headers
- Add base CSS for subpage-toc and subpage-section in globals.css
- Add theme-specific overrides for all 5 themes (minimal, editorial,
  classic, noir, monograph)
- Update gallery.yaml.example and docs/gallery-config.md
2026-03-08 23:52:23 +01:00
ralksta
32bb6cb2ca feat: allow subpages to override title and add subtitle in gallery.yaml 2026-03-08 22:46:27 +01:00
ralksta
b9993bd29e fix: gracefully handle Next.js static component fetch rendering when setup configs are completely empty 2026-03-08 21:38:44 +01:00
ralksta
7a1dfdc519 chore: remove unused 3P dependencies (zod, gray-matter, bcryptjs) and switch to native implementations 2026-03-08 21:12:52 +01:00
ralksta
25aefa5b70 feat: implement graceful setup fallback screen when yaml files are missing 2026-03-08 21:04:41 +01:00
ralksta
23d8bf0425 refactor: apply Clean Architecture principles
- Extract EXIF and Swipe logic into custom hooks for Lightbox
- Extract Map layout data formatting into mapService
- Extract AlbumDetailView and SubpageGridView components from page router
- Restructure monolithic config.ts into clean config/ directory
2026-03-08 18:55:45 +01:00
ralksta
ea72d720df chore: production-readiness audit fixes and linting cleanup 2026-03-08 16:26:05 +01:00
ralksta
270768d330 feat: add SEO fields to settings configuration 2026-03-08 16:19:41 +01:00
ralksta
01da5e1baa feat: improve lightbox rendering, hero styles, and config loading 2026-03-08 16:16:15 +01:00
ralksta
faab17f9cd fix: increase rate limit and add detailed logging to diagnose broken thumbnails 2026-03-07 09:42:33 +01:00
ralksta
68e442fff5 fix: revert experimental ImmichClient refactoring and restore absolute baseline for image loading 2026-03-07 09:37:48 +01:00
ralksta
277aab54e1 fix: remove minimum length requirement for AUTH_SECRET for maximum compatibility 2026-03-07 09:35:40 +01:00
ralksta
f790aa3268 fix: restore AUTH_SECRET fallback and fix asset caching to resolve fullscreen loading issues 2026-03-07 09:32:20 +01:00
ralksta
280c5430ca chore: full implementation of code review recommendations (security, quality, tests) 2026-03-07 09:27:47 +01:00
ralksta
fd965c5a75 style: restore CSS-only transitions and update config examples 2026-03-07 09:13:36 +01:00
ralksta
59ffe37cce docs: remove transitions from settings yaml example and lib/config 2026-03-07 09:12:24 +01:00
ralksta
0fed8e6c78 feat: separate settings and gallery config, add impressum page 2026-03-07 08:34:05 +01:00
ralksta
1e079760d8 feat: add configurable page transitions with framer-motion 2026-03-07 08:30:12 +01:00
ralksta
e394fe84a0 security: implement AUTH_SECRET and secure map/exif API routes 2026-03-07 08:18:23 +01:00
ralksta
2a16a9386f feat: simplify gallery.yaml and add support for album name overrides 2026-03-05 16:52:01 +01:00
ralksta
62a7b178d6 feat: add smart map view with location-level clustering
- /map page with Leaflet (CartoDB dark tiles)
- Photos clustered by city/country (not per-photo)
- /api/map endpoint with encrypted cover asset IDs
- Configurable via gallery.yaml (map: true/false)
- Conditional nav link in header
- CSP updated for Leaflet CDN and tile servers
- Theme-aware popups with cover thumbnails and album links
2026-02-15 23:07:04 +01:00
ralksta
4b80af1c29 feat: add noir, monograph, botanica presets + stacked/typographic/mosaic hero styles + showcase/filmstrip/editorial-flow gallery layouts
- 3 new theme presets: noir (darkroom analog), monograph (typographic book), botanica (organic nature)
- 3 new hero styles: stacked (fullbleed + thumbnail strip), typographic (text-only), mosaic (multi-image grid)
- 3 new gallery layouts: showcase (featured + grid), filmstrip (horizontal scroll), editorial-flow (alternating pairs)
- Extended config types, validation, and CSS tokens for all new options
- Updated theming docs with new presets table, descriptions, and example configs
2026-02-15 21:58:31 +01:00