mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 13:36:48 +00:00
1f66ef1d32
CARTO stamps an "API KEY REQUIRED" watermark onto every basemap tile fetched without a key since 26.08.2026, and both CartoDB presets plus the built-in fallback are CARTO. The key is free and needs no account, so add it as a setting rather than dropping the provider. carto_api_key sits next to mapbox_access_token: per user in Settings/Map, instance-wide under Admin/User Defaults, encrypted at rest, injected from CARTO_API_KEY on managed instances. Unlike Mapbox it never switches the map provider, since a raster key says nothing about the renderer. The key is appended as ?key= at render time instead of being stored in the template, so a saved URL stays portable and survives a rotation. That is also what reaches the four maps that pinned CARTO and ignored the user's tile setting: atlas, collections, the public trip share and the public journey. The two share pages read it from their token-gated payload, the same way baseCurrency already travels. Also lifts the release notice above page chrome. Its overlay sat at z-index 50, under the Vacay mode toolbar at 61, so the dialog was neither on top nor modal. Adds a six-step layer scale to index.css and moves the three notice shells onto it. Closes #2054 Closes #2052
90 lines
3.4 KiB
TypeScript
90 lines
3.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { redact, SENSITIVE_KEYS } from '../../../src/middleware/globalMiddleware';
|
|
|
|
describe('globalMiddleware request-log redaction', () => {
|
|
it('redacts secretAccessKey (any casing) — storage admin PUT bodies land in the same debug log line', () => {
|
|
expect(redact({ secretAccessKey: 'sk-super-secret' })).toEqual({ secretAccessKey: '[REDACTED]' });
|
|
expect(redact({ SecretAccessKey: 'sk-super-secret' })).toEqual({ SecretAccessKey: '[REDACTED]' });
|
|
expect(redact({ secretaccesskey: 'sk-super-secret' })).toEqual({ secretaccesskey: '[REDACTED]' });
|
|
});
|
|
|
|
it('lists secretaccesskey in the lowercase lookup set (lookup lowercases the key first)', () => {
|
|
expect(SENSITIVE_KEYS.has('secretaccesskey')).toBe(true);
|
|
});
|
|
|
|
it('still redacts every pre-existing sensitive key (no regression)', () => {
|
|
const input = {
|
|
password: 'p',
|
|
new_password: 'p',
|
|
current_password: 'p',
|
|
token: 't',
|
|
jwt: 'j',
|
|
authorization: 'a',
|
|
cookie: 'c',
|
|
client_secret: 's',
|
|
mfa_token: 'm',
|
|
code: '123456',
|
|
smtp_pass: 's',
|
|
};
|
|
const out = redact(input) as Record<string, unknown>;
|
|
for (const key of Object.keys(input)) {
|
|
expect(out[key]).toBe('[REDACTED]');
|
|
}
|
|
});
|
|
|
|
it('redacts nested objects and arrays, leaving non-sensitive fields untouched', () => {
|
|
const out = redact({
|
|
name: 'off-box',
|
|
options: { secretAccessKey: 'sk-1', accessKeyId: 'ak-1' },
|
|
backends: [{ secretAccessKey: 'sk-2' }, { accessKeyId: 'ak-2' }],
|
|
});
|
|
expect(out).toEqual({
|
|
name: 'off-box',
|
|
options: { secretAccessKey: '[REDACTED]', accessKeyId: 'ak-1' },
|
|
backends: [{ secretAccessKey: '[REDACTED]' }, { accessKeyId: 'ak-2' }],
|
|
});
|
|
});
|
|
|
|
it('redacts secret-shaped keys by suffix — the OAuth token body and the settings API keys', () => {
|
|
const out = redact({
|
|
refresh_token: 'rt-1',
|
|
code_verifier: 'cv-1',
|
|
llm_api_key: 'sk-1',
|
|
mapbox_access_token: 'pk-1',
|
|
grant_type: 'refresh_token',
|
|
}) as Record<string, unknown>;
|
|
expect(out.refresh_token).toBe('[REDACTED]');
|
|
expect(out.code_verifier).toBe('[REDACTED]');
|
|
expect(out.llm_api_key).toBe('[REDACTED]');
|
|
expect(out.mapbox_access_token).toBe('[REDACTED]');
|
|
expect(out.grant_type).toBe('refresh_token');
|
|
});
|
|
|
|
it('redacts the value of a {key, value} settings body when the key names a secret', () => {
|
|
expect(redact({ key: 'carto_api_key', value: 'carto-secret' })).toEqual({
|
|
key: 'carto_api_key',
|
|
value: '[REDACTED]',
|
|
});
|
|
expect(redact({ key: 'mapbox_access_token', value: 'pk-1' })).toEqual({
|
|
key: 'mapbox_access_token',
|
|
value: '[REDACTED]',
|
|
});
|
|
// A harmless setting keeps its value: the name is what decides.
|
|
expect(redact({ key: 'map_tile_url', value: 'https://tiles.example/{z}/{x}/{y}.png' })).toEqual({
|
|
key: 'map_tile_url',
|
|
value: 'https://tiles.example/{z}/{x}/{y}.png',
|
|
});
|
|
});
|
|
|
|
it('matches the suffix on the end of the key only, so identifiers stay readable', () => {
|
|
expect(redact({ accessKeyId: 'ak-1', tokenCount: 5 })).toEqual({ accessKeyId: 'ak-1', tokenCount: 5 });
|
|
});
|
|
|
|
it('passes non-object values through untouched', () => {
|
|
expect(redact('plain string')).toBe('plain string');
|
|
expect(redact(42)).toBe(42);
|
|
expect(redact(null)).toBe(null);
|
|
expect(redact(undefined)).toBe(undefined);
|
|
});
|
|
});
|