mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 15:06:32 +00:00
feat(settings): set the Google Maps key through PLACES_API_KEY
The server already put PLACES_API_KEY ahead of the key saved in the admin panel, but nothing said so: the variable was in no template and the admin field kept showing a stored value that no search used. GET /me/settings now answers env_keys, the variable behind each key the environment sets (Google, Unsplash, Amap), and null for that key's value. The admin field turns read-only and names the variable, Test still probes the key a search resolves to, and a save leaves those names out so the stored fallback survives. The variable is documented in .env.example, docker-compose.yml, the Helm chart (as a secret) and the wiki. Addresses discussion #1881.
This commit is contained in:
@@ -8,6 +8,7 @@ import { EMAIL_REGEX, mask_stored_api_key } from './auth.helpers';
|
||||
import { splitManagedKeys, MANAGED_LOCKED_PROFILE_KEYS } from '../common/managed';
|
||||
import {
|
||||
INSTANCE_API_KEY_NAMES,
|
||||
operatorKeyVariables,
|
||||
readInstanceApiKey,
|
||||
resolveApiKey,
|
||||
writeInstanceApiKey,
|
||||
@@ -270,12 +271,21 @@ export class UserProfileService {
|
||||
// first. Showing the admin their own column while every request used another
|
||||
// value is the confusion #1939 reported. Their column still answers while no
|
||||
// instance value exists — on that install it is what the resolver picks too.
|
||||
//
|
||||
// Ahead of both sits the operator's environment variable. A key set there
|
||||
// comes back as null plus the variable's name in `env_keys`: the stored
|
||||
// value is not what any search uses, and the variable's value is the
|
||||
// operator's, not the panel's to hand out (#1881).
|
||||
const envKeys = operatorKeyVariables();
|
||||
const shown = (name: InstanceApiKeyName, own: unknown) =>
|
||||
envKeys[name] ? null : (readInstanceApiKey(this.db, name) ?? decrypt_api_key(own));
|
||||
return {
|
||||
settings: {
|
||||
maps_api_key: readInstanceApiKey(this.db, 'maps_api_key') ?? decrypt_api_key(user.maps_api_key),
|
||||
maps_api_key: shown('maps_api_key', user.maps_api_key),
|
||||
openweather_api_key: decrypt_api_key(user.openweather_api_key),
|
||||
unsplash_api_key: readInstanceApiKey(this.db, 'unsplash_api_key') ?? decrypt_api_key(user.unsplash_api_key),
|
||||
amap_api_key: readInstanceApiKey(this.db, 'amap_api_key') ?? decrypt_api_key(user.amap_api_key),
|
||||
unsplash_api_key: shown('unsplash_api_key', user.unsplash_api_key),
|
||||
amap_api_key: shown('amap_api_key', user.amap_api_key),
|
||||
env_keys: envKeys,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { readEnv } from '../../app-config';
|
||||
import { DatabaseService } from '../database/database.service';
|
||||
import { decrypt_api_key, maybe_encrypt_api_key } from '../common/crypto/apiKeyCrypto';
|
||||
import type { ApiKeySource } from '@trek/shared';
|
||||
@@ -46,6 +47,26 @@ const USER_ROW_SQL: Record<InstanceApiKeyName, string> = {
|
||||
amap_api_key: 'SELECT amap_api_key FROM users WHERE id = ?',
|
||||
};
|
||||
|
||||
/**
|
||||
* The environment variable that overrides each instance key. Whatever it holds
|
||||
* is the operator key resolveApiKey puts first, so the admin panel names the
|
||||
* variable rather than showing a field that nothing reads (#1881).
|
||||
*/
|
||||
const OPERATOR_KEY_ENV: Record<InstanceApiKeyName, { variable: string; read: () => string | undefined }> = {
|
||||
maps_api_key: { variable: 'PLACES_API_KEY', read: () => readEnv().maps.placesApiKey },
|
||||
unsplash_api_key: { variable: 'UNSPLASH_ACCESS_KEY', read: () => readEnv().integrations.unsplashAccessKey },
|
||||
amap_api_key: { variable: 'AMAP_API_KEY', read: () => readEnv().maps.amapApiKey },
|
||||
};
|
||||
|
||||
/** The instance keys an environment variable sets, each with that variable's name. Never the value. */
|
||||
export function operatorKeyVariables(): Partial<Record<InstanceApiKeyName, string>> {
|
||||
const set: Partial<Record<InstanceApiKeyName, string>> = {};
|
||||
for (const name of INSTANCE_API_KEY_NAMES) {
|
||||
if (OPERATOR_KEY_ENV[name].read()) set[name] = OPERATOR_KEY_ENV[name].variable;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/** The instance-wide value in cleartext, or null when unset/cleared. */
|
||||
export function readInstanceApiKey(db: DatabaseService, name: InstanceApiKeyName): string | null {
|
||||
const row = db.get<{ value: string | null }>('SELECT value FROM app_settings WHERE key = ?', name);
|
||||
|
||||
Reference in New Issue
Block a user