1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-03-23 18:50:07 +00:00

fix: explicitly cache images to prevent unexpected behavior

This commit is contained in:
Elias Schneider
2025-06-16 15:59:14 +02:00
parent 4ed312251e
commit 2e5d268798
17 changed files with 142 additions and 58 deletions

View File

@@ -0,0 +1,89 @@
type SkipCacheUntil = {
[key: string]: number;
};
type CachableImage = {
getUrl: (...props: any[]) => string;
bustCache: (...props: any[]) => void;
};
export const cachedApplicationLogo: CachableImage = {
getUrl: (light = true) => {
let url = '/api/application-configuration/logo';
if (!light) {
url += '?light=false';
}
return getCachedImageUrl(url);
},
bustCache: (light = true) => {
let url = '/api/application-configuration/logo';
if (!light) {
url += '?light=false';
}
bustImageCache(url);
}
};
export const cachedBackgroundImage: CachableImage = {
getUrl: () => getCachedImageUrl('/api/application-configuration/background-image'),
bustCache: () => bustImageCache('/api/application-configuration/background-image')
};
export const cachedProfilePicture: CachableImage = {
getUrl: (userId: string) => {
const url = `/api/users/${userId}/profile-picture.png`;
return getCachedImageUrl(url);
},
bustCache: (userId: string) => {
const url = `/api/users/${userId}/profile-picture.png`;
bustImageCache(url);
}
};
export const cachedOidcClientLogo: CachableImage = {
getUrl: (clientId: string) => {
const url = `/api/oidc/clients/${clientId}/logo`;
return getCachedImageUrl(url);
},
bustCache: (clientId: string) => {
const url = `/api/oidc/clients/${clientId}/logo`;
bustImageCache(url);
}
};
function getCachedImageUrl(url: string) {
const skipCacheUntil = getSkipCacheUntil(url);
const skipCache = skipCacheUntil > Date.now();
if (skipCache) {
const skipCacheParam = new URLSearchParams();
skipCacheParam.append('skip-cache', skipCacheUntil.toString());
url += '?' + skipCacheParam.toString();
}
return url.toString();
}
function bustImageCache(url: string) {
const skipCacheUntil: SkipCacheUntil = JSON.parse(
localStorage.getItem('skip-cache-until') ?? '{}'
);
skipCacheUntil[hashKey(url)] = Date.now() + 1000 * 60 * 15; // 15 minutes
localStorage.setItem('skip-cache-until', JSON.stringify(skipCacheUntil));
}
function getSkipCacheUntil(url: string) {
const skipCacheUntil: SkipCacheUntil = JSON.parse(
localStorage.getItem('skip-cache-until') ?? '{}'
);
return skipCacheUntil[hashKey(url)] ?? 0;
}
function hashKey(key: string): string {
let hash = 0;
for (let i = 0; i < key.length; i++) {
const char = key.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return Math.abs(hash).toString(36);
}

View File

@@ -1,34 +0,0 @@
type SkipCacheUntil = {
[key: string]: number;
};
export function getProfilePictureUrl(userId?: string) {
if (!userId) return '';
let url = `/api/users/${userId}/profile-picture.png`;
const skipCacheUntil = getSkipCacheUntil(userId);
const skipCache = skipCacheUntil > Date.now();
if (skipCache) {
const skipCacheParam = new URLSearchParams();
skipCacheParam.append('skip-cache', skipCacheUntil.toString());
url += '?' + skipCacheParam.toString();
}
return url.toString();
}
function getSkipCacheUntil(userId: string) {
const skipCacheUntil: SkipCacheUntil = JSON.parse(
localStorage.getItem('skip-cache-until') ?? '{}'
);
return skipCacheUntil[userId] ?? 0;
}
export function bustProfilePictureCache(userId: string) {
const skipCacheUntil: SkipCacheUntil = JSON.parse(
localStorage.getItem('skip-cache-until') ?? '{}'
);
skipCacheUntil[userId] = Date.now() + 1000 * 60 * 15; // 15 minutes
localStorage.setItem('skip-cache-until', JSON.stringify(skipCacheUntil));
}