Commit Graph

618 Commits

Author SHA1 Message Date
Julien G.
cc613771fa Merge pull request #437 from mauriceboe/feat/migrate-node-fetch-to-native
refactor(server): replace node-fetch with native fetch + undici, fix photo integrations
2026-04-05 21:15:03 +02:00
jubnl
5cc81ae4b0 refactor(server): replace node-fetch with native fetch + undici, fix photo integrations
Replace node-fetch v2 with Node 22's built-in fetch API across the entire server.
Add undici as an explicit dependency to provide the dispatcher API needed for
DNS pinning (SSRF rebinding prevention) in ssrfGuard.ts. All seven service files
that used a plain `import fetch from 'node-fetch'` are updated to use the global.
The ssrfGuard safeFetch/createPinnedAgent is rewritten as createPinnedDispatcher
using an undici Agent, with correct handling of the `all: true` lookup callback
required by Node 18+. The collabService dynamic require() and notifications agent
option are updated to use the dispatcher pattern. Test mocks are migrated from
vi.mock('node-fetch') to vi.stubGlobal('fetch'), and streaming test fixtures are
updated to use Web ReadableStream instead of Node Readable.

Fix several bugs in the Synology and Immich photo integrations:
- pipeAsset: guard against setting headers after stream has already started
- _getSynologySession: clear stale SID and re-login when decrypt_api_key returns null
  instead of propagating success(null) downstream
- _requestSynologyApi: return retrySession error (not stale session) on retry failure;
  also retry on error codes 106 (timeout) and 107 (duplicate login), not only 119
- searchSynologyPhotos: fix incorrect total field type (Synology list_item returns no
  total); hasMore correctly uses allItems.length === limit
- _splitPackedSynologyId: validate cache_key format before use; callers return 400
- getImmichCredentials / _getSynologyCredentials: treat null from decrypt_api_key as
  a missing-credentials condition rather than casting null to string
- Synology size param: enforce allowlist ['sm', 'm', 'xl'] per API documentation
2026-04-05 21:12:51 +02:00
Maurice
94b74f96a3 fix(ical): pad datetime to 15 chars for valid iCal DTSTART/DTEND format
Times like 09:00 were exported as YYYYMMDDTHHMM (13 chars) instead of
YYYYMMDDTHHMMSS (15 chars). Google Calendar couldn't parse the short
format and defaulted all events to 12:00 AM. Closes #432
2026-04-05 20:17:22 +02:00
Maurice
48bf149d01 feat(packing): item quantity, bag rename, multi-user bags, save as template
- Add quantity field to packing items (persisted, visible per item)
- Bags are now renamable (click to edit in sidebar)
- Bags support multiple user assignments with avatar display
- New packing_bag_members table for multi-user bag ownership
- Save current packing list as reusable template
- Add bag members API endpoint (PUT /bags/:bagId/members)
- Migration 74: quantity on packing_items, user_id on packing_bags, packing_bag_members table
2026-04-05 19:28:33 +02:00
Maurice
f3679739d8 fix(reservations): format check-in/out times with user's time format setting
Respects 12h/24h preference for hotel check-in and check-out display.
2026-04-05 18:19:46 +02:00
Maurice
38206883ff feat(budget): bidirectional sync between reservations and budget items
- Link budget items to reservations via reservation_id column
- Update budget entry when reservation price changes (not create duplicate)
- Delete budget entry when reservation price is cleared
- Sync price back to reservation when edited in budget panel
- Lock budget item name when linked to a reservation
- Add migration 73 for reservation_id on budget_items
2026-04-05 18:16:02 +02:00
Maurice
cd5a6c7491 ui(settings): add about text, community links and bug/feature/wiki cards
- Add TREK description and "Made with heart" text to About tab (all 13 languages)
- Add Report Bug, Feature Request and Wiki cards to About tab and Admin GitHub panel
- Version shown as inline badge
2026-04-05 17:53:15 +02:00
Maurice
6e6e0a370e ui(settings): add Ko-fi, Buy Me a Coffee and Discord cards to About tab 2026-04-05 17:33:16 +02:00
Maurice
83bac11173 ui(trip): replace plane loading animation with TREK logo GIF
- Use animated TREK logo instead of plane SVG on trip loading screen
- Dark/light mode aware (switches GIF based on theme)
2026-04-05 17:28:04 +02:00
Julien G.
ecf69225e1 Merge pull request #433 from mauriceboe/fix/mfa-qr-svg
fix(mfa): generate SVG QR code
2026-04-05 17:16:50 +02:00
jubnl
c6148ba4f2 fix(mfa): generate SVG QR code
Replace the rasterized 180px PNG QR code with a crisp 250px SVG
2026-04-05 17:15:19 +02:00
Maurice
9ee5d21c3a test(trips): update TRIP-002 for dateless trips and add day_count test
- TRIP-002 now expects null dates and 7 placeholder days instead of forced date window
- Add TRIP-002b to verify custom day_count creates correct number of days
2026-04-05 16:29:29 +02:00
Maurice
d5cc2432c4 fix(i18n): escape apostrophes in French dayCountHint translation 2026-04-05 16:25:32 +02:00
Maurice
7f077d949d feat(trips): add configurable day count for trips without dates
- Show day count input in trip form when no start/end date is set
- Backend accepts day_count param for create and update
- Remove forced date assignment for dateless trips (was always setting tomorrow + 7)
- Fix off-by-one: single-date fallback now creates 7 days instead of 8
- Add dayCount/dayCountHint translations for all 13 languages
2026-04-05 16:25:09 +02:00
Julien G.
312bc715bf Merge pull request #430 from mauriceboe/fix/gpx-import-tracks-and-xml-parser
fix(gpx): replace regex parsing with fast-xml-parser and import tracks alongside waypoints
2026-04-05 15:56:22 +02:00
jubnl
6ba08352ed fix(gpx): replace regex parsing with fast-xml-parser and import tracks alongside waypoints
GPX files containing both <wpt> and <trk> elements would only import
waypoints, silently discarding track geometry. The fallback chain only
parsed <trkpt> when no waypoints were found.

Replaced all regex-based XML parsing helpers with fast-xml-parser for
correctness (namespaces, CDATA, attribute ordering). Tracks are now
always parsed independently of waypoints, with each <trk> element
becoming its own place with route geometry. Fixes #427.
2026-04-05 15:54:42 +02:00
Julien G.
58874a1ccb Merge pull request #429 from mauriceboe/fix/mcp-search-place-google-maps
fix(mcp): route search_place through mapsService to support Google Maps
2026-04-05 15:39:23 +02:00
jubnl
82f08360d7 fix(mcp): route search_place through mapsService to support Google Maps
The search_place MCP tool was hardcoding a direct Nominatim call, ignoring
any configured Google Maps API key and never returning google_place_id despite
the tool description advertising it. Replace the inline fetch with the existing
searchPlaces() service which already switches between Google and Nominatim.

Update unit tests to mock mapsService instead of global fetch, and add a
dedicated test case for the Google path returning google_place_id.

Closes #424
2026-04-05 15:38:19 +02:00
Julien G.
978d26f36c Merge pull request #428 from mauriceboe/fix/avatar-url-documents-tab
fix(files): prepend /uploads/avatars/ to avatar URL in documents tab
2026-04-05 15:25:26 +02:00
jubnl
18eee16d2d fix(files): prepend /uploads/avatars/ to avatar URL in documents tab
Raw avatar filename was passed through formatFile without being
transformed into a full URL path, causing the browser to resolve
it relative to the current /trips/... page. Closes #417.
2026-04-05 15:23:45 +02:00
Maurice
c274846275 fix(memories): fix deprecated immich route regressions from PR #336
- Fix createAlbumLink using old column name (immich_album_id → album_id)
- Fix deleteAlbumLink not removing associated photos (with owner check)
- Update integration tests for new schema (asset_id, album_id, provider)
2026-04-05 15:19:13 +02:00
Maurice
7821993450 fix(memories): patch critical bugs from PR #336 Synology Photos merge
- Fix missing response on successful addTripPhotos in deprecated immich route
- Fix undefined tripId in asset proxy routes (use query param instead)
- Fix unquoted SQL string in migration 68 (id = memories → id = 'memories')
- Add missing return after error response in synology asset streaming
2026-04-05 15:11:07 +02:00
Maurice
a9d6ce87c1 Merge pull request #336 from tiquis0290/test
Adding support for SynologyPhoto (immich like) and adding support to use more photo proiders not just immich
2026-04-05 15:08:50 +02:00
Maurice
67b21d5fe3 i18n(admin): rename tabs and merge notification panels
- Configuration → Personalization (all 13 languages)
- Merge Notification Channels + Admin Notifications into single Notifications tab
- Audit Log → Audit (all 13 languages)
2026-04-05 14:46:36 +02:00
Marek Maslowski
8b488efc8e fixing migrations to change to correct label name 2026-04-05 14:32:41 +02:00
Marek Maslowski
070b75b6be fixing loging in to synology 2026-04-05 14:26:28 +02:00
Marek Maslowski
51c4afd5f7 fixing error on test connection without params 2026-04-05 14:26:14 +02:00
Marek Maslowski
74b3b0f9ae removing race conteset on delting album link 2026-04-05 12:21:00 +02:00
Marek Maslowski
1236f3281d adding old routes 2026-04-05 12:17:43 +02:00
Marek Maslowski
4a0d586768 fix for not calling api route on fetch 2026-04-05 11:54:51 +02:00
Marek Maslowski
079964bec8 making helper functions for building urls 2026-04-05 11:50:34 +02:00
Marek Maslowski
b0b85fff3a fix for settings page 2026-04-05 11:08:58 +02:00
Marek Maslowski
0d3a10120a post merge 2026-04-05 10:26:23 +02:00
Marek Maslowski
b8c3d5b3d1 Merge branch 'dev' into test 2026-04-05 10:26:09 +02:00
jubnl
959015928f feat(security): mask saved webhook URLs instead of returning encrypted values
Encrypted webhook URLs are no longer returned to the frontend. Both user
and admin webhook fields now show '••••••••' as a placeholder when a URL
is already saved, and the sentinel value is skipped on save/test so the
stored secret is never exposed or accidentally overwritten.
2026-04-05 06:08:44 +02:00
jubnl
d8ee545002 fix(ssrf): handle Node 20+ Happy Eyeballs dns lookup signature in pinned agent
Node 20+ enables autoSelectFamily by default, causing internal dns lookups
to be called with `all: true`. This expects the callback to receive an array
of address objects instead of a flat (address, family) pair, causing webhook
requests to fail with "Invalid IP address: undefined".
2026-04-05 05:59:25 +02:00
Julien G.
78b9536de9 Merge pull request #423 from mauriceboe/feat/settings-tabbed-layout
feat(settings): remake settings page with admin-style tabbed layout
2026-04-05 05:33:30 +02:00
jubnl
4e4afe2545 feat(settings): remake settings page with admin-style tabbed layout
Replaces the 2-column masonry layout with a horizontal pill tab bar
matching the admin page pattern. Extracts all sections into self-contained
components under components/Settings/ and reduces SettingsPage.tsx from
1554 lines to 93. Adds i18n tab label keys across all 13 language files.
2026-04-05 05:32:21 +02:00
jubnl
38afba0820 fix(csp): add https://router.project-osrm.org/route/v1 to CSP Connect-Src 2026-04-05 05:23:33 +02:00
Julien G.
81742dbb85 Merge pull request #419 from mauriceboe/feat/notification-system
feat(notifications): add unified multi-channel notification system
2026-04-05 04:37:06 +02:00
jubnl
3898e5f7e2 chore(CRLF): normalize index.html line endings to LF 2026-04-05 04:35:17 +02:00
jubnl
6a36efbf1a feat(i18n): translate missing keys across all 12 language files 2026-04-05 04:34:58 +02:00
Julien G.
991b4065e3 Merge branch 'dev' into feat/notification-system 2026-04-05 04:06:49 +02:00
jubnl
c158df1bc5 chore(CRLF) Normalize all files to LF 2026-04-05 04:01:08 +02:00
jubnl
f03705848d fix(translation): syntax error 2026-04-05 03:54:42 +02:00
jubnl
0c99eb1d07 chore: merge dev branch, resolve conflicts for migrations and translations
- migrations.ts: keep dev's migrations 69 (place_regions) + 70 (visited_regions), renumber our notification_channel_preferences migration to 71 and drop-old-table to 72
- translations: use dev values for existing keys, add notification system keys unique to this branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 03:46:53 +02:00
jubnl
7b37d337c1 fix(security): address notification system security audit findings
- SSRF: guard sendWebhook() with checkSsrf() + createPinnedAgent() to block
  requests to loopback, link-local, private network, and cloud metadata endpoints
- XSS: escape subject, body, and ctaHref in buildEmailHtml() via escapeHtml()
  to prevent HTML injection through user-controlled params (actor, preview, etc.)
- Encrypt webhook URLs at rest: apply maybe_encrypt_api_key on save
  (settingsService for user URLs, authService for admin URL) and decrypt_api_key
  on read in getUserWebhookUrl() / getAdminWebhookUrl()
- Log failed channel dispatches: inspect Promise.allSettled() results and log
  rejections via logError instead of silently dropping them
- Log admin webhook failures: replace fire-and-forget .catch(() => {}) with
  .catch(err => logError(...)) and await the call
- Migration 69: guard against missing notification_preferences table on fresh installs
- Migration 70: drop the now-unused notification_preferences table
- Refactor: extract applyUserChannelPrefs() helper to deduplicate
  setPreferences / setAdminPreferences logic
- Tests: add SEC-016 (XSS, 5 cases) and SEC-017 (SSRF, 6 cases) test suites;
  mock ssrfGuard in notificationService tests
2026-04-05 03:36:50 +02:00
Julien G.
69ae6f93db Merge pull request #420 from mauriceboe/feat/atlas
feat(atlas): sub-national region view when zooming in
2026-04-05 03:19:48 +02:00
jubnl
71c1683bb3 feat(atlas): mark sub-national regions as visited with cascade behavior
- Add visited_regions table migration
- Mark/unmark region endpoints with auto-mark parent country
- Unmark country cascades to its regions; unmark last region cascades to country
- Region modal with mark/unmark flow and bucket list shortcut
- Viewport-based lazy loading of region GeoJSON at zoom >= 6
- i18n: add atlas.markRegionVisitedHint and atlas.confirmUnmarkRegion across all 13 locales
2026-04-05 03:17:59 +02:00
mauriceboe
6df8b2555d chore: resolve merge conflicts with dev branch
Merge dev into feat/notification-system, keeping all i18n keys from both
branches (notification system keys + reservation price/budget keys).
2026-04-05 01:43:43 +02:00