Commit Graph

159 Commits

Author SHA1 Message Date
Ralksta
fb32a8cabc Merge PR #164
🛡️ Sentinel: [HIGH] Fix scrypt lockout and timing fallback
2026-05-06 11:59:48 +02:00
Ralksta
3a4c65276d Merge PR #165
⚡ Bolt: [performance improvement] Optimize map bucketing memory and deduplicate getMapData promises
2026-05-06 11:59:45 +02:00
Ralksta
08207e2f16 Merge PR #163
🎨 Palette: Improve PhotoGrid screen reader accessibility
2026-05-06 11:59:42 +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
google-labs-jules[bot]
ebf60b12c3 Improve PhotoGrid screen reader accessibility
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-05-05 10:24:39 +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
93ac1c20e8 Add [role="button"]:focus-visible to app/tokens.css for proper keyboard focus indication on custom button elements. (#130)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:52:08 +02:00
dependabot[bot]
a61c577a94 chore(deps-dev): bump @types/node from 20.19.37 to 20.19.39 (#84)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.19.37 to 20.19.39.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.39
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-21 22:51:55 +02:00
Ralksta
431e7c0553 🛡️ Sentinel: [improvement] Add Content Security Policy Report-Only header (#86)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:50 +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
bb7c1aa1bd Improve rate-limit headers in auth API (#102)
Destructures `remaining` and `resetAt` from `checkRateLimit` and adds standard rate-limiting headers (`Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`) to the 429 Too Many Requests response.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:42 +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
16e1c7647b 🎨 Palette: [UX improvement] Auto-focus Close button in Lightbox (#104)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:31 +02:00
dependabot[bot]
b803daf8f9 chore(deps): bump the react group with 2 updates (#107)
Bumps the react group with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react)

Updates `react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.5/packages/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-21 22:51:29 +02:00
Ralksta
e8709b9ae9 feat(a11y): consolidate ARIA announcements on interactive cards (#133)
- Added comprehensive `aria-label` to the parent `<Link>` in `SubpageGridView`.
- Hid redundant textual child elements using `aria-hidden="true"`.
- Removed redundant `alt` text from decorative thumbnail `Image`.
- Removed unused `albumMap` prop in `AlbumGrid`.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-21 22:51:26 +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
dependabot[bot]
972ace5833 chore(deps-dev): bump prettier from 3.8.1 to 3.8.2 (#108)
Bumps [prettier](https://github.com/prettier/prettier) from 3.8.1 to 3.8.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.8.1...3.8.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-21 22:51:17 +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
e739fdb518 🎨 Palette: [UX improvement] Add aria-hidden to decorative SVGs (#70)
* Added aria-hidden="true" to decorative SVG icons within interactive elements (buttons, links) in Lightbox, ThemeToggle, Footer, BackLink, and MapView.
* Added role="alert" and aria-live="polite" to the MapView loading indicator.
* Documented learning in .Jules/palette.md

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-04-01 12:46:20 +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
af7e2e9206 feat: add aria-label to BackLink component (#10)
Adds an `aria-label` to the `BackLink` component to improve screen reader accessibility. By default, it was an icon next to text that functioned as a single link, but providing an explicit `aria-label` makes its target clearer.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-27 10:52:39 +01:00
dependabot[bot]
59153c9f48 chore(deps): bump the nextjs group with 2 updates (#43)
Bumps the nextjs group with 2 updates: [next](https://github.com/vercel/next.js) and [eslint-config-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-config-next).


Updates `next` from 16.1.6 to 16.2.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v16.1.6...v16.2.1)

Updates `eslint-config-next` from 16.1.6 to 16.2.1
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-config-next)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nextjs
- dependency-name: eslint-config-next
  dependency-version: 16.2.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: nextjs
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ralksta <16941050+ralksta@users.noreply.github.com>
2026-03-27 10:51:26 +01:00
dependabot[bot]
741dba3576 chore(deps): bump actions/checkout from 4 to 6 (#13)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ralksta <16941050+ralksta@users.noreply.github.com>
2026-03-27 10:51: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
dependabot[bot]
f4778d09f6 chore(deps-dev): bump @types/node from 20.19.33 to 20.19.37 (#17)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.19.33 to 20.19.37.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 20.19.37
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 10:37:56 +01:00
dependabot[bot]
88dc8dcbeb chore(deps): bump actions/checkout from 4 to 6 (#13)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 10:37:13 +01:00
dependabot[bot]
457d92e657 chore(deps): bump the react group with 2 updates (#15)
Bumps the react group with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom).


Updates `react` from 19.2.3 to 19.2.4
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.4/packages/react)

Updates `react-dom` from 19.2.3 to 19.2.4
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.4/packages/react-dom)

---
updated-dependencies:
- dependency-name: react
  dependency-version: 19.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
- dependency-name: react-dom
  dependency-version: 19.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 10:36:28 +01:00
Ralksta
43d5b4d15d 🛡️ Sentinel: Add rate limiting to /api/og endpoint (#47)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-27 10:36:25 +01:00
Ralksta
c8f75e4615 feat(a11y): enhance accessibility of password gate form (#46)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-27 10:36:22 +01:00
Ralksta
5ebc900851 feat(ux): Add proper ARIA attributes to Lightbox modal and EXIF toggle (#45)
Adds `role="dialog"`, `aria-modal="true"`, and `aria-label` to the `.overlay` container to improve screen reader accessibility. Also adds `aria-expanded` and `aria-controls` to the EXIF info toggle button, linking it to the newly ID'd `#exif-panel`.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-27 10:36:19 +01:00
ralksta
228771decc Merge PR 36 and resolve ci.yml conflict 2026-03-22 10:03:02 +01:00
Ralksta
6a45dc3657 Add aria-label to input fields for better accessibility (#39)
Added aria-labels to the password input in `components/PasswordGate.tsx` and the grid columns/gap inputs in `components/DevToolbar.tsx` to provide clear semantic meaning for screen readers.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-03-22 09:57:29 +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
dependabot[bot]
db19504c91 chore(deps-dev): bump eslint from 9.39.2 to 9.39.4 (#16)
Bumps [eslint](https://github.com/eslint/eslint) from 9.39.2 to 9.39.4.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v9.39.2...v9.39.4)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.39.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 09:51:19 +01:00
dependabot[bot]
1f83bad3a7 chore(deps): bump actions/setup-node from 4 to 6 (#14)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-22 09:51:11 +01:00
google-labs-jules[bot]
8cd96d4dac Fix CI failures due to AUTH_SECRET and missing Playwright types
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-03-20 11:38:33 +00:00
google-labs-jules[bot]
cdc26c00ac 🛡️ Sentinel: [HIGH] Cache health check endpoint to prevent upstream DoS
Co-authored-by: ralksta <16941050+ralksta@users.noreply.github.com>
2026-03-20 11:33:38 +00: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
3fa47f7031 chore: add GitHub community files and CI pipeline
- .github/workflows/ci.yml: TypeScript check + Vitest + build on every PR
- .github/dependabot.yml: weekly npm + Actions updates (minor/patch grouped)
- .github/ISSUE_TEMPLATE/: bug_report, feature_request, config (→ Discussions)
- .github/PULL_REQUEST_TEMPLATE.md: checklist for contributors
- SECURITY.md: responsible disclosure policy via GitHub Advisories
- CONTRIBUTING.md: dev setup, code style, commit conventions
2026-03-13 13:00:19 +01:00
ralksta
a97b261c14 fix: raise map rate limit 30→120/min, allow 5min private browser cache
Prevents spurious 429s during normal browsing/refreshing.
Browser now caches personalised map data for 5 minutes (private,
so CDNs/proxies won't share it between users).
2026-03-13 12:55:07 +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