Skip to content

Quick Add + Update Cryptography for API Key Generation#1099

Closed
seanmorley15 wants to merge 31 commits intomainfrom
development
Closed

Quick Add + Update Cryptography for API Key Generation#1099
seanmorley15 wants to merge 31 commits intomainfrom
development

Conversation

@seanmorley15
Copy link
Copy Markdown
Owner

@seanmorley15 seanmorley15 commented Apr 5, 2026

This pull request introduces significant enhancements to image importing and location creation in the backend, particularly focusing on robust remote image handling and a new "quick add" endpoint for locations. The changes improve usability, safety, and efficiency for both image import and location creation workflows.

Fixes #687

Remote image import improvements:

  • Added download_remote_image and import_remote_images_for_object utility functions to safely download and attach remote images, with SSRF protection, redirect handling, file type/size validation, and parallel downloads using ThreadPoolExecutor.
  • Refactored the fetch_from_url endpoint in ContentImageViewSet to use the new download_remote_image utility, improving error handling and code clarity.
  • Introduced a new import_from_urls endpoint to bulk import images from remote URLs for a content object, with validation, error reporting, and response serialization.

Location creation enhancements:

  • Added a quick_add endpoint to LocationViewSet, allowing streamlined creation of locations from minimal input, including optional reverse geocoding, place details lookup, tag/category normalization, and photo import via the new image utilities.
  • Implemented a suite of helper methods in LocationViewSet for input coercion, URL/tag sanitization, category normalization, and applying reverse geocode metadata to the new location.

Other improvements and refactoring:

  • Updated import statements and dependencies in location_image_view.py and location_view.py to support new utilities and models. [1] [2] [3] [4] [5]
  • Updated documentation reference in CONTRIBUTING.md from /documentation to /docs for consistency.

These changes collectively make the system more robust, user-friendly, and maintainable, especially for workflows involving remote images and rapid location creation.

seanmorley15 and others added 29 commits March 16, 2026 11:40
- Implemented API key creation, deletion, and display functionality.
- Updated the settings page to fetch and show existing API keys.
- Added UI elements for creating new API keys and copying them to clipboard.
- Enhanced request handling to ensure proper trailing slashes for API endpoints.
- dompurify: upgraded from 3.3.1 to 3.3.3
- emoji-picker-element: upgraded from 1.29.0 to 1.29.1
- @sveltejs/adapter-node: updated to use @sveltejs/kit@2.55.0
- @sveltejs/adapter-vercel: updated to use @sveltejs/kit@2.55.0
- @sveltejs/kit: upgraded from 2.53.3 to 2.55.0
- @types/node: upgraded from 22.19.13 to 22.19.15
- autoprefixer: updated postcss version from 8.5.6 to 8.5.8
- baseline-browser-mapping: upgraded from 2.10.0 to 2.10.8
- daisyui: updated postcss version from 8.5.6 to 8.5.8
- prettier-plugin-svelte: upgraded from 3.5.0 to 3.5.1
- svelte-check: updated postcss version from 8.5.6 to 8.5.8
- devalue: upgraded from 5.6.3 to 5.6.4
- electron-to-chromium: upgraded from 1.5.302 to 1.5.313
- caniuse-lite: upgraded from 1.0.30001774 to 1.0.30001780
- mlly: upgraded from 1.8.0 to 1.8.1
- node-releases: upgraded from 2.0.27 to 2.0.36
- tar: upgraded from 7.5.9 to 7.5.11
- tinyexec: upgraded from 1.0.2 to 1.0.4
Currently translated at 99.9% (1091 of 1092 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/fr/
Currently translated at 100.0% (1092 of 1092 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ko/
Currently translated at 100.0% (1092 of 1092 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/
Currently translated at 100.0% (1092 of 1092 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sv/
Currently translated at 1.2% (14 of 1092 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/ca/
* Refactor AdventureLog Bot workflow to improve issue validation handling and encapsulate comment and close logic (#1068)

* Reorder immich API permissions to natural order

---------

Co-authored-by: Sean Morley <git@seanmorley.com>
Currently translated at 100.0% (1093 of 1093 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/tr/
Currently translated at 100.0% (1093 of 1093 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/sv/
Currently translated at 100.0% (1093 of 1093 strings)

Translation: AdventureLog/Web App
Translate-URL: https://hosted.weblate.org/projects/adventurelog/web-app/de/
…ty and location enrichment

- Added quick add feature for locations with category selection.
- Implemented location description enrichment using Google Maps API.
- Improved search functionality and result handling.
- Introduced new utility functions for location saving and validation.
- Updated UI to reflect changes in location selection and quick add status.
- Added toast notifications for user feedback on actions.
- Refactored existing code for better readability and maintainability.

fix: Ensure finite coordinates in LocationSearchMap component

- Added validation for initial selection coordinates to prevent errors.

chore: Update app version to v0.12.0-main-033126

- Updated versioning in config file.

feat: Create location-save module for handling location data saving

- Implemented saveLocation function to handle both new and existing location data.
- Added utility functions for coordinate formatting and link sanitization.
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
adventurelog Ready Ready Preview, Comment Apr 5, 2026 2:26am

@seanmorley15 seanmorley15 requested a review from Copilot April 5, 2026 02:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a streamlined “quick add” location flow and substantially expands backend geocoding + remote image import capabilities, while also updating API key hashing and some frontend location-editing behavior.

Changes:

  • Added backend endpoints/utilities for quick-adding locations, enriching place details, and bulk importing remote images with SSRF/redirect validation and parallel downloads.
  • Enhanced geocoding to support richer Google Place results (types/ratings/photos) and added a place-details enrichment path (Google + Wikipedia).
  • Refactored frontend location creation/editing flow to support quick-start selection, quick add, and improved save payload normalization.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 25 comments.

Show a summary per file
File Description
frontend/src/locales/pl.json Updates Polish translations (currently removes several keys).
frontend/src/locales/no.json Updates Norwegian translations (currently removes several keys).
frontend/src/locales/nl.json Updates Dutch translations (currently removes several keys).
frontend/src/locales/ko.json Updates Korean translations (currently removes several keys / tweaks wording).
frontend/src/locales/ja.json Updates Japanese translations (currently removes several keys).
frontend/src/lib/location-save.ts Adds a shared location save helper (payload cleanup/normalization + error parsing).
frontend/src/lib/components/shared/LocationSearchMap.svelte Improves initial selection validation and name/display-name resolution behavior.
frontend/src/lib/components/locations/LocationQuickStart.svelte Adds richer place selection + “Quick Add” UX with enrichment hooks.
frontend/src/lib/components/locations/LocationModal.svelte Integrates quick-start/quick-add flow and optional background import of Google photos.
frontend/src/lib/components/locations/LocationDetails.svelte Refactors save logic to use the shared save helper and improves lat/lng coercion.
CONTRIBUTING.md Updates docs path reference in contributing guide.
backend/server/users/models.py Changes API key hashing from SHA-256 to PBKDF2-HMAC-SHA256.
backend/server/templates/base.html Fixes a JS function name typo in the template.
backend/server/adventures/views/reverse_geocode_view.py Adds a place_details endpoint to return enriched place details.
backend/server/adventures/views/location_view.py Adds quick-add endpoint and helper coercion/normalization methods.
backend/server/adventures/views/location_image_view.py Adds remote image download/import utilities and a bulk import endpoint.
backend/server/adventures/geocoding.py Expands Google search payload/results + adds place-details enrichment (Google + Wikipedia) and improved reverse-geocode naming.
.github/workflows/adventurelog-bot.yml Expands PR-actor skip logic (maintainer + dependabot).

@@ -28,8 +28,7 @@
"calendar": "Kalendarz",
"admin_panel": "Panel administracyjny",
"navigation": "Nawigacja",
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navbar.mobile_login translation key was removed, but it’s still referenced in the UI (e.g., frontend/src/lib/components/Avatar.svelte). This will cause the Polish locale to show a raw key/fallback instead of a proper label—please restore the key or update the code to stop using it.

Suggested change
"navigation": "Nawigacja",
"navigation": "Nawigacja",
"mobile_login": "Zaloguj się",

Copilot uses AI. Check for mistakes.
"locations": "Lokalizacje",
"my_locations": "Moje lokalizacje",
"best_happened_at": "Najlepsze wydarzyło się o godz"
"my_locations": "Moje lokalizacje"
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The locations.best_happened_at translation key was removed, but it’s still used in the frontend (e.g., frontend/src/routes/profile/[uuid]/+page.svelte). Please re-add this key (or remove the usage) to avoid missing-string fallbacks in Polish.

Suggested change
"my_locations": "Moje lokalizacje"
"my_locations": "Moje lokalizacje",
"best_happened_at": "Najlepiej wspominane w"

Copilot uses AI. Check for mistakes.
Comment on lines 1139 to 1142
"trip_context_info": "Elementy kontekstu podróży dotyczą całej podróży — na przykład lokalizacje będące samym celem podróży, uwagi ogólne lub listy rzeczy do spakowania ważne dla całej podróży.",
"unscheduled_items": "Niezaplanowane pozycje",
"unscheduled_items_desc": "Te elementy są powiązane z tą podróżą, ale nie zostały jeszcze dodane do konkretnego dnia."
},
"api_keys": {
"copied": "Skopiowano!",
"copy": "Skopiuj klucz",
"create": "Utwórz klucz",
"create_error": "Nie udało się utworzyć klucza API.",
"created": "Stworzony",
"description": "Twórz osobiste klucze API w celu uzyskania dostępu programowego. \nKlucze są wyświetlane tylko raz w momencie tworzenia.",
"dismiss": "Odrzucać",
"key_created": "Klucz API został utworzony pomyślnie.",
"key_name_placeholder": "Nazwa klucza (np. Asystent domowy)",
"key_revoked": "Klucz API unieważniony.",
"last_used": "Ostatnio używany",
"never_used": "Nigdy nie używany",
"new_key_title": "Zapisz swój nowy klucz API",
"new_key_warning": "Ten klucz nie będzie już więcej wyświetlany. \nSkopiuj go i przechowuj w bezpiecznym miejscu.",
"no_keys": "Nie ma jeszcze kluczy API.",
"revoke": "Unieważnić",
"revoke_error": "Nie udało się unieważnić klucza API.",
"title": "Klucze API",
"copy_error": "Błąd podczas kopiowania klucza.",
"usage_middle": "nagłówek lub jako",
"usage_prefix": "Użyj tego klawisza w",
"delete_confirm": "Czy na pewno chcesz usunąć ten klucz mobilnego API?"
}
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire api_keys translation section was removed, but API key UI still references these keys without defaults (e.g., frontend/src/routes/settings/+page.svelte). This will break Polish localization for the API keys settings page; please restore these strings or remove the references.

Copilot uses AI. Check for mistakes.
@@ -28,8 +28,7 @@
"northernLights": "Nordlys"
},
"navigation": "Navigasjon",
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navbar.mobile_login translation key was removed, but it’s still referenced in the UI (e.g., frontend/src/lib/components/Avatar.svelte). Please restore it for Norwegian, or update the UI to not reference the removed key.

Suggested change
"navigation": "Navigasjon",
"navigation": "Navigasjon",
"mobile_login": "Logg inn",

Copilot uses AI. Check for mistakes.
"locations": "Lokasjoner",
"my_locations": "Mine lokasjoner",
"best_happened_at": "Best skjedde kl"
"my_locations": "Mine lokasjoner"
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The locations.best_happened_at translation key was removed, but it’s still used in the frontend (see frontend/src/routes/profile/[uuid]/+page.svelte). Please re-add this Norwegian translation or remove the key usage.

Suggested change
"my_locations": "Mine lokasjoner"
"my_locations": "Mine lokasjoner",
"best_happened_at": "Beste opplevelse på"

Copilot uses AI. Check for mistakes.
Comment on lines 78 to 99
@@ -80,7 +95,7 @@ def generate(cls, user, name: str) -> tuple['APIKey', str]:
user once and must never be stored anywhere after that.
"""
raw_key = f"al_{secrets.token_urlsafe(32)}"
key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
key_hash = cls._hash_raw_key(raw_key)
key_prefix = raw_key[:12]
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching from SHA-256 to PBKDF2 changes the stored key_hash format, but existing API keys can’t be re-derived (the raw token isn’t stored). As written, all existing API keys will stop authenticating after this change. Please add a backward-compatible verification path (e.g., accept both legacy SHA-256 and new hash formats) or provide a migration/rotation plan that explicitly revokes and forces recreation of keys.

Copilot uses AI. Check for mistakes.
Comment on lines 59 to +87
@@ -71,6 +75,17 @@ class Meta:
def __str__(self):
return f"{self.user.username} – {self.name} ({self.key_prefix}…)"

@classmethod
def _hash_raw_key(cls, raw_key: str) -> str:
"""Derive a computationally expensive hash for API key persistence."""
salt = f"{cls._KEY_HASH_SALT_NAMESPACE}:{settings.SECRET_KEY}".encode("utf-8")
return hashlib.pbkdf2_hmac(
"sha256",
raw_key.encode("utf-8"),
salt,
cls._KEY_HASH_ITERATIONS,
).hex()
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using PBKDF2 with 600k iterations in APIKey.authenticate() puts an expensive CPU operation on every API request authenticated via API keys (unlike password login, which is infrequent). Given these tokens are already high-entropy, this is likely to be a significant performance/DoS risk. Consider using a fast keyed hash (HMAC/salted_hmac) with a server-side secret (pepper) instead, or substantially lower the cost/introduce caching/rate-limiting.

Copilot uses AI. Check for mistakes.
Comment on lines +80 to +87
"""Derive a computationally expensive hash for API key persistence."""
salt = f"{cls._KEY_HASH_SALT_NAMESPACE}:{settings.SECRET_KEY}".encode("utf-8")
return hashlib.pbkdf2_hmac(
"sha256",
raw_key.encode("utf-8"),
salt,
cls._KEY_HASH_ITERATIONS,
).hex()
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PBKDF2 salt includes settings.SECRET_KEY, which effectively peppers the hash (good), but it also means rotating SECRET_KEY will immediately invalidate all existing API keys. If that’s not intended, consider using a dedicated, versioned pepper (e.g., API_KEY_PEPPER) or storing per-key salt/algorithm metadata so rotation can be managed without a hard cutover.

Copilot uses AI. Check for mistakes.

```
/documentation
/docs
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change updates the contribution guide to reference /docs, but the repository currently contains a /documentation directory and no /docs directory. Either create/move docs to /docs or keep the existing /documentation path to avoid misleading contributors.

Suggested change
/docs
/documentation

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +65
// Ignore PRs created by the maintainer to avoid blocking their work, as well as dependabot
if (context.actor === "seanmorley15" || context.actor === "dependabot") {
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub’s context.actor for Dependabot PRs is typically dependabot[bot], not dependabot. With the current check, Dependabot PRs may still be processed. Consider checking for dependabot[bot] (and/or using endsWith('[bot]') or github.actor comparisons that match actual values).

Suggested change
// Ignore PRs created by the maintainer to avoid blocking their work, as well as dependabot
if (context.actor === "seanmorley15" || context.actor === "dependabot") {
// Ignore PRs created by the maintainer to avoid blocking their work, as well as Dependabot
if (context.actor === "seanmorley15" || context.actor === "dependabot[bot]") {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REQUEST] Scrap information from Google Map for the descriptions

10 participants