Store image filenames in DB, resolve paths for cleanup on replace/delete, and reuse product-thumb multer limits.
71 lines
2.4 KiB
TypeScript
71 lines
2.4 KiB
TypeScript
import { join, resolve, sep } from 'node:path';
|
|
|
|
const uploadsRoot = (): string => join(process.cwd(), 'uploads');
|
|
|
|
const validatePathTraversal = (baseDir: string, absolutePath: string): void => {
|
|
const resolvedBaseDir = resolve(baseDir);
|
|
|
|
if (!absolutePath.startsWith(`${resolvedBaseDir}${sep}`)) {
|
|
throw new Error('Invalid storage key');
|
|
}
|
|
};
|
|
|
|
const resolvePathWithinDir = (baseDir: string, storageKey: string): string => {
|
|
const resolvedBaseDir = resolve(baseDir);
|
|
const absolutePath = resolve(resolvedBaseDir, storageKey);
|
|
|
|
validatePathTraversal(resolvedBaseDir, absolutePath);
|
|
|
|
return absolutePath;
|
|
};
|
|
|
|
export const getPublicUploadsDir = (): string => join(uploadsRoot(), 'public');
|
|
|
|
export const publicUploadsUrlPrefix = '/uploads/public/';
|
|
|
|
export const getPrivateUploadsDir = (): string => join(uploadsRoot(), 'private');
|
|
|
|
export const getVariantImagesDir = (): string => join(getPublicUploadsDir(), 'variants', 'images');
|
|
|
|
export const variantImagesUrlPrefix = '/uploads/public/variants/images/';
|
|
|
|
export const getVariantImagePublicUrl = (filename: string): string => `${variantImagesUrlPrefix}${filename}`;
|
|
|
|
export const getBlogImagesDir = (): string => join(getPublicUploadsDir(), 'blog', 'images');
|
|
|
|
export const blogImagesUrlPrefix = '/uploads/public/blog/images/';
|
|
|
|
export const getBlogImagePublicUrl = (filename: string): string => `${blogImagesUrlPrefix}${filename}`;
|
|
|
|
export const resolveBlogImagePath = (storageKey: string): string => {
|
|
const baseDir = getBlogImagesDir();
|
|
|
|
const absolutePath = resolvePathWithinDir(baseDir, storageKey);
|
|
|
|
return absolutePath;
|
|
};
|
|
|
|
export const getShopBrandingDir = (): string => join(getPublicUploadsDir(), 'shop');
|
|
|
|
export const shopBrandingUrlPrefix = '/uploads/public/shop/';
|
|
|
|
export const getShopBrandingPublicUrl = (filename: string): string => `${shopBrandingUrlPrefix}${filename}`;
|
|
|
|
export const resolveShopBrandingPath = (storageKey: string): string => {
|
|
const baseDir = getShopBrandingDir();
|
|
|
|
const absolutePath = resolvePathWithinDir(baseDir, storageKey);
|
|
|
|
return absolutePath;
|
|
};
|
|
|
|
export const getDigitalStockAttachmentsDir = (): string => join(getPrivateUploadsDir(), 'digital-stock', 'attachments');
|
|
|
|
export const resolveDigitalStockAttachmentPath = (storageKey: string): string => {
|
|
const baseDir = getDigitalStockAttachmentsDir();
|
|
|
|
const absolutePath = resolvePathWithinDir(baseDir, storageKey);
|
|
|
|
return absolutePath;
|
|
};
|