changing handling of rights for accesing assets

This commit is contained in:
Marek Maslowski
2026-04-04 00:52:01 +02:00
parent fc28996420
commit 860739b28b
6 changed files with 75 additions and 87 deletions
+18 -24
View File
@@ -15,11 +15,11 @@ import {
proxyThumbnail,
proxyOriginal,
isValidAssetId,
canAccessUserPhoto,
listAlbums,
syncAlbumAssets,
getAssetInfo,
} from '../services/immichService';
import { canAccessUserPhoto } from '../services/memoriesService';
const router = express.Router();
@@ -83,48 +83,42 @@ router.post('/search', authenticate, async (req: Request, res: Response) => {
// ── Asset Details ──────────────────────────────────────────────────────────
router.get('/assets/:assetId/info', authenticate, async (req: Request, res: Response) => {
router.get('/assets/:tripId/:assetId/:ownerId/info', authenticate, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
const { assetId } = req.params;
if (!isValidAssetId(assetId)) return res.status(400).json({ error: 'Invalid asset ID' });
const queryUserId = req.query.userId ? Number(req.query.userId) : undefined;
const ownerUserId = queryUserId && queryUserId !== authReq.user.id ? queryUserId : undefined;
if (ownerUserId && !canAccessUserPhoto(authReq.user.id, ownerUserId, assetId)) {
const { tripId, assetId, ownerId } = req.params;
if (!canAccessUserPhoto(authReq.user.id, Number(ownerId), tripId, assetId, 'immich')) {
return res.status(403).json({ error: 'Forbidden' });
}
const result = await getAssetInfo(authReq.user.id, assetId, ownerUserId);
const result = await getAssetInfo(authReq.user.id, assetId, Number(ownerId));
if (result.error) return res.status(result.status!).json({ error: result.error });
res.json(result.data);
});
// ── Proxy Immich Assets ────────────────────────────────────────────────────
router.get('/assets/:assetId/thumbnail', authFromQuery, async (req: Request, res: Response) => {
router.get('/assets/:tripId/:assetId/:ownerId/thumbnail', authFromQuery, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
const { assetId } = req.params;
if (!isValidAssetId(assetId)) return res.status(400).send('Invalid asset ID');
const queryUserId = req.query.userId ? Number(req.query.userId) : undefined;
const ownerUserId = queryUserId && queryUserId !== authReq.user.id ? queryUserId : undefined;
if (ownerUserId && !canAccessUserPhoto(authReq.user.id, ownerUserId, assetId)) {
return res.status(403).send('Forbidden');
const { tripId, assetId, ownerId } = req.params;
if (!canAccessUserPhoto(authReq.user.id, Number(ownerId), tripId, assetId, 'immich')) {
return res.status(403).json({ error: 'Forbidden' });
}
const result = await proxyThumbnail(authReq.user.id, assetId, ownerUserId);
const result = await proxyThumbnail(authReq.user.id, assetId, Number(ownerId));
if (result.error) return res.status(result.status!).send(result.error);
res.set('Content-Type', result.contentType!);
res.set('Cache-Control', 'public, max-age=86400');
res.send(result.buffer);
});
router.get('/assets/:assetId/original', authFromQuery, async (req: Request, res: Response) => {
router.get('/assets/:tripId/:assetId/:ownerId/original', authFromQuery, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
const { assetId } = req.params;
if (!isValidAssetId(assetId)) return res.status(400).send('Invalid asset ID');
const queryUserId = req.query.userId ? Number(req.query.userId) : undefined;
const ownerUserId = queryUserId && queryUserId !== authReq.user.id ? queryUserId : undefined;
if (ownerUserId && !canAccessUserPhoto(authReq.user.id, ownerUserId, assetId)) {
return res.status(403).send('Forbidden');
const { tripId, assetId, ownerId } = req.params;
if (!canAccessUserPhoto(authReq.user.id, Number(ownerId), tripId, assetId, 'immich')) {
return res.status(403).json({ error: 'Forbidden' });
}
const result = await proxyOriginal(authReq.user.id, assetId, ownerUserId);
const result = await proxyOriginal(authReq.user.id, assetId, Number(ownerId));
if (result.error) return res.status(result.status!).send(result.error);
res.set('Content-Type', result.contentType!);
res.set('Cache-Control', 'public, max-age=86400');
+22 -10
View File
@@ -12,11 +12,11 @@ import {
searchSynologyPhotos,
getSynologyAssetInfo,
pipeSynologyProxy,
getSynologyTargetUserId,
streamSynologyAsset,
handleSynologyError,
SynologyServiceError,
} from '../services/synologyService';
import { canAccessUserPhoto } from '../services/memoriesService';
const router = express.Router();
@@ -121,24 +121,32 @@ router.post('/search', authenticate, async (req: Request, res: Response) => {
}
});
router.get('/assets/:photoId/info', authenticate, async (req: Request, res: Response) => {
router.get('/assets/:tripId/:photoId/:ownerId/info', authenticate, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
const { photoId } = req.params;
const { tripId, photoId, ownerId } = req.params;
if (!canAccessUserPhoto(authReq.user.id, Number(ownerId), tripId, photoId, 'synologyphotos')) {
return handleSynologyError(res, new SynologyServiceError(403, 'You don\'t have access to this photo'), 'Access denied');
}
try {
res.json(await getSynologyAssetInfo(authReq.user.id, photoId, getSynologyTargetUserId(req)));
res.json(await getSynologyAssetInfo(authReq.user.id, photoId, Number(ownerId)));
} catch (err: unknown) {
handleSynologyError(res, err, 'Could not reach Synology');
}
});
router.get('/assets/:photoId/thumbnail', authenticate, async (req: Request, res: Response) => {
router.get('/assets/:tripId/:photoId/:ownerId/thumbnail', authenticate, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
const { photoId } = req.params;
const { tripId, photoId, ownerId } = req.params;
const { size = 'sm' } = req.query;
if (!canAccessUserPhoto(authReq.user.id, Number(ownerId), tripId, photoId, 'synologyphotos')) {
return handleSynologyError(res, new SynologyServiceError(403, 'You don\'t have access to this photo'), 'Access denied');
}
try {
const proxy = await streamSynologyAsset(authReq.user.id, getSynologyTargetUserId(req), photoId, 'thumbnail', String(size));
const proxy = await streamSynologyAsset(authReq.user.id, Number(ownerId), photoId, 'thumbnail', String(size));
await pipeSynologyProxy(res, proxy);
} catch (err: unknown) {
if (res.headersSent) {
@@ -148,12 +156,16 @@ router.get('/assets/:photoId/thumbnail', authenticate, async (req: Request, res:
}
});
router.get('/assets/:photoId/original', authenticate, async (req: Request, res: Response) => {
router.get('/assets/:tripId/:photoId/:ownerId/original', authenticate, async (req: Request, res: Response) => {
const authReq = req as AuthRequest;
const { photoId } = req.params;
const { tripId, photoId, ownerId } = req.params;
if (!canAccessUserPhoto(authReq.user.id, Number(ownerId), tripId, photoId, 'synologyphotos')) {
return handleSynologyError(res, new SynologyServiceError(403, 'You don\'t have access to this photo'), 'Access denied');
}
try {
const proxy = await streamSynologyAsset(authReq.user.id, getSynologyTargetUserId(req), photoId, 'original');
const proxy = await streamSynologyAsset(authReq.user.id, Number(ownerId), photoId, 'original');
await pipeSynologyProxy(res, proxy);
} catch (err: unknown) {
if (res.headersSent) {