From 967224c030b9cd721fb0217d0763e1ec1978c51e Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Sat, 5 Sep 2026 12:11:40 +0200 Subject: [PATCH] fix: remove the image-fragmentation surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1300. Fragmentation was configurable, stored per event, served to the gallery client, and consumed by nothing. It was not unbuilt scaffolding — both halves exist and are individually coherent — but they were never connected, and they disagree: the server cut a fixed 3x3 grid while the client reassembled a 4x4 one, so wiring them together as they stood would have produced scrambled images rather than protection. Removed rather than finished, because finishing it buys nothing. The client fetches the whole image and then redraws it in pieces on a canvas, so the full original has already crossed the wire before any "protection" is applied — that is obfuscation, not a control. The per-fragment canvas work also lands on mobile, which is the memory profile under investigation in #1287. Goes: secureImageService.fragmentImageBuffer and its branch, the ?fragment=N delivery path and handleFragmentedImage in secureImages, the fragmented-JSON response in protectedImages, fragmentation_level in the gallery payload, the default_fragmentation_level setting, the PUT validator, the ProtectedImage fragment renderer, and the operator control with its strings in all eight locales. No migration. `events.fragmentation_level` and the app_settings row stay — dropping a column is irreversible and the stored values are harmless once nothing reads them. If they should go, that is a deliberate data decision and its own migration. `fragmentGrid` on AuthenticatedImage and the layouts is deliberately untouched: #1299 already removes it as part of the inert prop surface, and doing it here would only collide. --- backend/src/routes/adminEvents/crud.js | 1 - backend/src/routes/adminImageSecurity.js | 2 - backend/src/routes/gallery.js | 1 - backend/src/routes/protectedImages.js | 18 +---- backend/src/routes/secureImages.js | 62 +----------------- backend/src/services/secureImageService.js | 59 +---------------- .../src/components/common/ProtectedImage.tsx | 65 ++----------------- .../common/__tests__/ProtectedImage.test.tsx | 38 ----------- .../settings/tabs/ImageSecurityTab.tsx | 17 ----- frontend/src/hooks/useImageProtection.ts | 1 - frontend/src/i18n/locales/de.json | 2 - frontend/src/i18n/locales/en.json | 2 - frontend/src/i18n/locales/es.json | 1 - frontend/src/i18n/locales/fr.json | 1 - frontend/src/i18n/locales/nl.json | 1 - frontend/src/i18n/locales/pt.json | 1 - frontend/src/i18n/locales/ru.json | 1 - frontend/src/i18n/locales/sl.json | 1 - frontend/src/types/index.ts | 1 - frontend/src/types/protection.ts | 15 ----- 20 files changed, 9 insertions(+), 281 deletions(-) diff --git a/backend/src/routes/adminEvents/crud.js b/backend/src/routes/adminEvents/crud.js index fc2dce8e..251a6a36 100644 --- a/backend/src/routes/adminEvents/crud.js +++ b/backend/src/routes/adminEvents/crud.js @@ -1569,7 +1569,6 @@ module.exports = (router) => { body('use_canvas_rendering').optional().isBoolean(), body('overlay_protection').optional().isBoolean(), body('image_quality').optional().isInt({ min: 1, max: 100 }), - body('fragmentation_level').optional().isInt({ min: 1, max: 10 }), body('password').optional().isString().custom((value) => { if (value === undefined || value === null || value === '') { return true; diff --git a/backend/src/routes/adminImageSecurity.js b/backend/src/routes/adminImageSecurity.js index 877a5421..2499a22a 100644 --- a/backend/src/routes/adminImageSecurity.js +++ b/backend/src/routes/adminImageSecurity.js @@ -22,7 +22,6 @@ router.get('/settings', adminAuth, requirePermission(['settings.view', 'image_se 'max_image_requests_per_hour', 'suspicious_activity_threshold', 'enable_canvas_rendering', - 'default_fragmentation_level', 'security_monitoring_enabled', 'block_suspicious_ips', 'log_security_events_to_db', @@ -61,7 +60,6 @@ router.put('/settings', adminAuth, requirePermission('image_security.manage'), a 'max_image_requests_per_hour', 'suspicious_activity_threshold', 'enable_canvas_rendering', - 'default_fragmentation_level', 'security_monitoring_enabled', 'block_suspicious_ips', 'log_security_events_to_db', diff --git a/backend/src/routes/gallery.js b/backend/src/routes/gallery.js index b87e1855..4a5a162e 100644 --- a/backend/src/routes/gallery.js +++ b/backend/src/routes/gallery.js @@ -1227,7 +1227,6 @@ router.get('/:slug/photos', verifyGalleryAccess, resolveGuest, noStoreCache, asy protection_level: req.event.protection_level || 'standard', image_quality: req.event.image_quality || 85, use_canvas_rendering: parseBooleanInput(req.event.use_canvas_rendering, false), - fragmentation_level: req.event.fragmentation_level || 3, overlay_protection: parseBooleanInput(req.event.overlay_protection, true) }; diff --git a/backend/src/routes/protectedImages.js b/backend/src/routes/protectedImages.js index 6f94c9ff..a018522c 100644 --- a/backend/src/routes/protectedImages.js +++ b/backend/src/routes/protectedImages.js @@ -117,8 +117,7 @@ router.get('/:slug/photo/:photoId/view', verifyGalleryAccess, blockHiddenGallery const protectionSettings = { protectionLevel: eventProtectionLevel, quality: req.event.image_quality || 85, - addFingerprint: req.event.add_fingerprint !== false, - fragmentImage: eventProtectionLevel === 'maximum' + addFingerprint: req.event.add_fingerprint !== false }; // Resolve photo location through the storage backend (managed) or local @@ -151,21 +150,6 @@ router.get('/:slug/photo/:photoId/view', verifyGalleryAccess, blockHiddenGallery ? await withLocalCopy(storageKey, runProcessing) : await runProcessing(resolvePhotoFilePath(req.event, photo)); - if (processedImage.type === 'fragmented') { - return res.json({ - type: 'fragmented', - fragments: processedImage.fragments.map(f => ({ - index: f.index, - row: f.row, - col: f.col, - data: f.buffer.toString('base64'), - position: f.position - })), - dimensions: processedImage.originalDimensions, - fragmentDimensions: processedImage.fragmentDimensions - }); - } - finalImage = processedImage; } diff --git a/backend/src/routes/secureImages.js b/backend/src/routes/secureImages.js index c0b229c6..bf0d9684 100644 --- a/backend/src/routes/secureImages.js +++ b/backend/src/routes/secureImages.js @@ -120,8 +120,6 @@ router.get('/:slug/secure/:photoId/:token', tokenLength: token?.length, hasAuthHeader: Boolean(req.headers.authorization), }); - const { fragment } = req.query; - // Verify secure token const tokenValidation = secureImageService.verifySecureToken( token, @@ -212,8 +210,7 @@ router.get('/:slug/secure/:photoId/:token', const protectionSettings = { protectionLevel: event.protection_level || 'standard', quality: event.image_quality || 85, - addFingerprint: event.add_fingerprint !== false, - fragmentImage: event.use_canvas_rendering === true && fragment !== undefined + addFingerprint: event.add_fingerprint !== false }; let processedImage; @@ -232,11 +229,6 @@ router.get('/:slug/secure/:photoId/:token', return res.status(404).json({ error: 'Photo file not found' }); } - // Handle fragmented images - if (processedImage.type === 'fragmented') { - return await handleFragmentedImage(req, res, processedImage, fragment); - } - // Log successful access await secureImageService.logImageAccess( photoId, @@ -267,58 +259,6 @@ router.get('/:slug/secure/:photoId/:token', } ); -/** - * Handle fragmented image delivery - */ -async function handleFragmentedImage(req, res, fragmentedImage, fragmentIndex) { - const { photoId } = req.params; - - try { - if (fragmentIndex === undefined) { - // Return fragment metadata - res.json({ - type: 'fragmented', - fragments: fragmentedImage.fragments.length, - dimensions: fragmentedImage.originalDimensions, - fragmentDimensions: fragmentedImage.fragmentDimensions - }); - return; - } - - const index = parseInt(fragmentIndex); - if (isNaN(index) || index < 0 || index >= fragmentedImage.fragments.length) { - return res.status(400).json({ error: 'Invalid fragment index' }); - } - - const fragment = fragmentedImage.fragments[index]; - - // Log fragment access - await secureImageService.logImageAccess( - photoId, - req.event.id, - req.clientInfo, - `fragment_${index}` - ); - - res.set({ - 'Content-Type': 'image/jpeg', - 'Content-Length': fragment.buffer.length, - 'X-Fragment-Index': index, - 'X-Fragment-Position': JSON.stringify(fragment.position) - }); - - res.send(fragment.buffer); - - } catch (error) { - logger.error('Error serving image fragment', { - error: error.message, - fragmentIndex, - photoId - }); - res.status(500).json({ error: 'Failed to serve image fragment' }); - } -} - /** * Download protected image with watermark */ diff --git a/backend/src/services/secureImageService.js b/backend/src/services/secureImageService.js index 7e006940..49a7c28b 100644 --- a/backend/src/services/secureImageService.js +++ b/backend/src/services/secureImageService.js @@ -175,8 +175,7 @@ class SecureImageService { quality = 85, maxWidth = 1920, maxHeight = 1080, - addFingerprint = true, - fragmentImage = false + addFingerprint = true } = options; try { @@ -187,7 +186,7 @@ class SecureImageService { // For standard protection without fingerprinting, return original file // This avoids unnecessary recompression when no protection features are needed - if (protectionLevel === 'standard' && !addFingerprint && !fragmentImage) { + if (protectionLevel === 'standard' && !addFingerprint) { return await fs.readFile(imagePath); } @@ -268,14 +267,7 @@ class SecureImageService { }); } - const buffer = await image.toBuffer(); - - // Fragment image if requested (for canvas reconstruction) - if (fragmentImage && protectionLevel === 'maximum') { - return await this.fragmentImageBuffer(buffer, metadata); - } - - return buffer; + return await image.toBuffer(); } catch (error) { logger.error('Error processing protected image:', error); // Return original on error @@ -283,51 +275,6 @@ class SecureImageService { } } - /** - * Fragment image into multiple pieces for canvas reconstruction - */ - async fragmentImageBuffer(buffer, metadata) { - const { width, height } = metadata; - const fragments = []; - - // Create 3x3 grid of fragments - const cols = 3; - const rows = 3; - const fragmentWidth = Math.floor(width / cols); - const fragmentHeight = Math.floor(height / rows); - - for (let row = 0; row < rows; row++) { - for (let col = 0; col < cols; col++) { - const left = col * fragmentWidth; - const top = row * fragmentHeight; - - const fragment = await sharp(buffer) - .extract({ - left, - top, - width: fragmentWidth, - height: fragmentHeight - }) - .toBuffer(); - - fragments.push({ - index: row * cols + col, - row, - col, - buffer: fragment, - position: { left, top, width: fragmentWidth, height: fragmentHeight } - }); - } - } - - return { - type: 'fragmented', - fragments, - originalDimensions: { width, height }, - fragmentDimensions: { width: fragmentWidth, height: fragmentHeight, cols, rows } - }; - } - /** * Log image access for security monitoring */ diff --git a/frontend/src/components/common/ProtectedImage.tsx b/frontend/src/components/common/ProtectedImage.tsx index 717fa29d..dbad8683 100644 --- a/frontend/src/components/common/ProtectedImage.tsx +++ b/frontend/src/components/common/ProtectedImage.tsx @@ -12,9 +12,6 @@ interface ProtectedImageProps extends React.CanvasHTMLAttributes void; fallbackSrc?: string; @@ -26,9 +23,6 @@ export const ProtectedImage: React.FC = ({ alt, protectionLevel = 'standard', watermarkText, - fragmentGrid = false, - gridSize = 4, - scrambleFragments = false, invisibleWatermark = false, onProtectionViolation, fallbackSrc, @@ -120,52 +114,6 @@ export const ProtectedImage: React.FC = ({ ctx.shadowOffsetY = 0; }, []); - // Fragment and scramble image for maximum protection - const renderFragmentedImage = useCallback(( - ctx: CanvasRenderingContext2D, - img: HTMLImageElement, - width: number, - height: number - ) => { - const fragmentWidth = width / gridSize; - const fragmentHeight = height / gridSize; - const fragments: Array<{ x: number; y: number; destX: number; destY: number }> = []; - - // Create fragment map - for (let row = 0; row < gridSize; row++) { - for (let col = 0; col < gridSize; col++) { - fragments.push({ - x: col * fragmentWidth, - y: row * fragmentHeight, - destX: col * fragmentWidth, - destY: row * fragmentHeight, - }); - } - } - - // Scramble fragments if requested - if (scrambleFragments) { - for (let i = fragments.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - const temp = fragments[i].destX; - const tempY = fragments[i].destY; - fragments[i].destX = fragments[j].destX; - fragments[i].destY = fragments[j].destY; - fragments[j].destX = temp; - fragments[j].destY = tempY; - } - } - - // Draw fragments - fragments.forEach(fragment => { - ctx.drawImage( - img, - fragment.x, fragment.y, fragmentWidth, fragmentHeight, - fragment.destX, fragment.destY, fragmentWidth, fragmentHeight - ); - }); - }, [gridSize, scrambleFragments]); - // Main canvas rendering function - wrapped in useCallback to prevent infinite re-renders const renderToCanvas = useCallback(() => { if (!canvasRef.current || !imageRef.current) { @@ -199,14 +147,9 @@ export const ProtectedImage: React.FC = ({ ctx.globalCompositeOperation = 'source-over'; // Reset composite operation try { - if (fragmentGrid && (protectionLevel === 'enhanced' || protectionLevel === 'maximum')) { - // Render fragmented image - renderFragmentedImage(ctx, img, canvas.width, canvas.height); - } else { - // Render normal image - ensure image is valid before drawing - if (img.naturalWidth > 0 && img.naturalHeight > 0) { - ctx.drawImage(img, 0, 0, canvas.width, canvas.height); - } + // Ensure image is valid before drawing + if (img.naturalWidth > 0 && img.naturalHeight > 0) { + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); } // Apply watermarks @@ -242,7 +185,7 @@ export const ProtectedImage: React.FC = ({ reportViolation('canvas_rendering_error'); setError(true); } - }, [fragmentGrid, protectionLevel, renderFragmentedImage, watermarkText, invisibleWatermark, applyInvisibleWatermark, applyVisibleWatermark, reportViolation]); + }, [protectionLevel, watermarkText, invisibleWatermark, applyInvisibleWatermark, applyVisibleWatermark, reportViolation]); // Set up protection event listeners useEffect(() => { diff --git a/frontend/src/components/common/__tests__/ProtectedImage.test.tsx b/frontend/src/components/common/__tests__/ProtectedImage.test.tsx index c06ceed3..8c87155a 100644 --- a/frontend/src/components/common/__tests__/ProtectedImage.test.tsx +++ b/frontend/src/components/common/__tests__/ProtectedImage.test.tsx @@ -128,25 +128,6 @@ describe('ProtectedImage', () => { expect(mockContext.fillText).toHaveBeenCalled(); }); - it('handles fragment grid rendering', async () => { - render( - - ); - - await waitFor(() => { - const canvas = screen.getByRole('img', { name: 'Test image' }); - expect(canvas).toHaveStyle({ opacity: '1' }); - }); - - // Verify multiple drawImage calls for fragments - expect(mockContext.drawImage).toHaveBeenCalled(); - }); - it('blocks interactions in maximum protection mode', async () => { const onViolation = vi.fn(); @@ -230,25 +211,6 @@ describe('ProtectedImage', () => { expect(mockContext.putImageData).toHaveBeenCalled(); }); - it('scrambles fragments when enabled', async () => { - render( - - ); - - await waitFor(() => { - const canvas = screen.getByRole('img', { name: 'Test image' }); - expect(canvas).toHaveStyle({ opacity: '1' }); - }); - - // Fragment scrambling should result in multiple drawImage calls - expect(mockContext.drawImage).toHaveBeenCalled(); - }); - it('adds random noise in maximum protection', async () => { render( { />

{t('settings.imageSecurity.imageQualityHelp', '1-100, higher = better quality')}

- -
- - handleChange('default_fragmentation_level', parseInt(e.target.value) || 3)} - className="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-primary-500" - /> -

{t('settings.imageSecurity.fragmentationLevelHelp', '1-10, higher = more protection')}

-
diff --git a/frontend/src/hooks/useImageProtection.ts b/frontend/src/hooks/useImageProtection.ts index 5dbe2d24..bb0b7866 100644 --- a/frontend/src/hooks/useImageProtection.ts +++ b/frontend/src/hooks/useImageProtection.ts @@ -20,7 +20,6 @@ interface UseImageProtectionOptions { blockKeyboardShortcuts?: boolean; detectPrintScreen?: boolean; watermarkText?: string; - fragmentGrid?: boolean; } export const useImageProtection = (options: UseImageProtectionOptions) => { diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 79e14b0c..72fb62c3 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -1852,7 +1852,6 @@ "defaultProtectionHelp": "Diese Einstellungen gelten für alle neuen Veranstaltungen. Einzelne Veranstaltungen können diese Standardwerte überschreiben.", "protectionLevel": "Standard-Schutzstufe", "imageQuality": "Standard-Bildqualität", - "fragmentationLevel": "Fragmentierungsstufe", "enableDevtools": "DevTools-Erkennung standardmäßig aktivieren", "enableCanvas": "Canvas-Rendering standardmäßig aktivieren (erweiterter Schutz)", "rateLimiting": "Ratenbegrenzung", @@ -1869,7 +1868,6 @@ "infoTitle": "Über Bildschutz", "infoText": "Diese Schutzfunktionen helfen, gelegentliches Herunterladen und Kopieren zu verhindern, können aber nicht alle Methoden blockieren. Entschlossene Benutzer finden möglicherweise trotzdem Wege, Bilder zu erfassen. Erwägen Sie die Verwendung von Wasserzeichen und rechtlichen Vereinbarungen für umfassenden Schutz.", "imageQualityHelp": "1–100, höher = bessere Qualität", - "fragmentationLevelHelp": "1–10, höher = mehr Schutz", "suspiciousActivityThresholdHelp": "Verstöße, bevor als verdächtig markiert wird", "autoBlockThresholdHelp": "Verstöße, bevor die IP automatisch gesperrt wird" }, diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 75957a58..f9c740d8 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -1415,7 +1415,6 @@ "defaultProtectionHelp": "These settings apply to all new events. Individual events can override these defaults.", "protectionLevel": "Default Protection Level", "imageQuality": "Default Image Quality", - "fragmentationLevel": "Fragmentation Level", "enableDevtools": "Enable DevTools detection by default", "enableCanvas": "Enable canvas rendering by default (advanced protection)", "rateLimiting": "Rate Limiting", @@ -1432,7 +1431,6 @@ "infoTitle": "About Image Protection", "infoText": "These protection features help prevent casual downloading and copying but cannot block all methods. Determined users may still find ways to capture images. Consider using watermarks and legal agreements for comprehensive protection.", "imageQualityHelp": "1-100, higher = better quality", - "fragmentationLevelHelp": "1-10, higher = more protection", "suspiciousActivityThresholdHelp": "Violations before flagging as suspicious", "autoBlockThresholdHelp": "Violations before auto-blocking IP" }, diff --git a/frontend/src/i18n/locales/es.json b/frontend/src/i18n/locales/es.json index d9e246c7..9c4dc381 100644 --- a/frontend/src/i18n/locales/es.json +++ b/frontend/src/i18n/locales/es.json @@ -941,7 +941,6 @@ "defaultProtectionHelp": "Estos ajustes se aplican a todos los nuevos eventos. Los eventos individuales pueden anular estos valores por defecto.", "protectionLevel": "Nivel de protección por defecto", "imageQuality": "Calidad de imagen por defecto", - "fragmentationLevel": "Nivel de fragmentación", "enableDevtools": "Habilitar detección de DevTools por defecto", "enableCanvas": "Habilitar renderizado con canvas por defecto (protección avanzada)", "rateLimiting": "Limitación de velocidad", diff --git a/frontend/src/i18n/locales/fr.json b/frontend/src/i18n/locales/fr.json index 40427398..f18625db 100644 --- a/frontend/src/i18n/locales/fr.json +++ b/frontend/src/i18n/locales/fr.json @@ -911,7 +911,6 @@ "defaultProtectionHelp": "Ces paramètres s'appliquent à tous les nouveaux événements. Les événements individuels peuvent remplacer ces valeurs par défaut.", "protectionLevel": "Niveau de protection par défaut", "imageQuality": "Qualité d'image par défaut", - "fragmentationLevel": "Niveau de fragmentation", "enableDevtools": "Activer la détection des outils DevTools par défaut", "enableCanvas": "Activer le rendu canvas par défaut (protection avancée)", "rateLimiting": "Limitation de débit", diff --git a/frontend/src/i18n/locales/nl.json b/frontend/src/i18n/locales/nl.json index 8379d768..755fb22a 100644 --- a/frontend/src/i18n/locales/nl.json +++ b/frontend/src/i18n/locales/nl.json @@ -907,7 +907,6 @@ "defaultProtectionHelp": "Deze instellingen zijn van toepassing op alle nieuwe evenementen. Individuele evenementen kunnen deze standaardwaarden overschrijven.", "protectionLevel": "Standaard beveiligingsniveau", "imageQuality": "Standaard beeldkwaliteit", - "fragmentationLevel": "Fragmentatieniveau", "enableDevtools": "Standaard DevTools-detectie inschakelen", "enableCanvas": "Standaard canvas-rendering inschakelen (geavanceerde beveiliging)", "rateLimiting": "Snelheidsbeperking", diff --git a/frontend/src/i18n/locales/pt.json b/frontend/src/i18n/locales/pt.json index bef63fc7..7fdf85e4 100644 --- a/frontend/src/i18n/locales/pt.json +++ b/frontend/src/i18n/locales/pt.json @@ -924,7 +924,6 @@ "defaultProtectionHelp": "Aplicado a novos eventos por padrão. Podem ser substituídas individualmente.", "protectionLevel": "Nível de Proteção Padrão", "imageQuality": "Qualidade de Imagem Padrão", - "fragmentationLevel": "Nível de Fragmentação", "enableDevtools": "Ativar detecção de DevTools por padrão", "enableCanvas": "Ativar renderização em Canvas por padrão", "rateLimiting": "Limite de Requisições", diff --git a/frontend/src/i18n/locales/ru.json b/frontend/src/i18n/locales/ru.json index f1423665..49f2356b 100644 --- a/frontend/src/i18n/locales/ru.json +++ b/frontend/src/i18n/locales/ru.json @@ -930,7 +930,6 @@ "defaultProtectionHelp": "Эти настройки применяются ко всем новым событиям. Отдельные события могут их переопределить.", "protectionLevel": "Уровень защиты по умолчанию", "imageQuality": "Качество изображений по умолчанию", - "fragmentationLevel": "Уровень фрагментации", "enableDevtools": "Включить обнаружение DevTools по умолчанию", "enableCanvas": "Включить рендеринг Canvas по умолчанию (расширенная защита)", "rateLimiting": "Ограничение скорости", diff --git a/frontend/src/i18n/locales/sl.json b/frontend/src/i18n/locales/sl.json index f66c1363..a02444bc 100644 --- a/frontend/src/i18n/locales/sl.json +++ b/frontend/src/i18n/locales/sl.json @@ -911,7 +911,6 @@ "defaultProtectionHelp": "Te nastavitve veljajo za vse nove dogodke. Posamezni dogodki lahko te privzete nastavitve prepišejo.", "protectionLevel": "Privzeta raven zaščite", "imageQuality": "Privzeta kakovost slike", - "fragmentationLevel": "Raven fragmentacije", "enableDevtools": "Privzeto omogoči zaznavanje DevTools", "enableCanvas": "Privzeto omogoči izris prek canvas (napredna zaščita)", "rateLimiting": "Omejevanje hitrosti", diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index fefc33c5..8a39245a 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -290,7 +290,6 @@ export interface GalleryData { image_quality?: number; use_canvas_rendering?: boolean; enable_devtools_protection?: boolean; - fragmentation_level?: number; overlay_protection?: boolean; // Hero logo customization fields hero_logo_visible?: boolean | null; diff --git a/frontend/src/types/protection.ts b/frontend/src/types/protection.ts index 26d3ada0..b8ad3b59 100644 --- a/frontend/src/types/protection.ts +++ b/frontend/src/types/protection.ts @@ -49,7 +49,6 @@ export interface ImageProtectionOptions { blockKeyboardShortcuts?: boolean; detectPrintScreen?: boolean; watermarkText?: string; - fragmentGrid?: boolean; } export interface ProtectedImageProps { @@ -57,9 +56,6 @@ export interface ProtectedImageProps { alt: string; protectionLevel?: ProtectionLevel; watermarkText?: string; - fragmentGrid?: boolean; - gridSize?: number; - scrambleFragments?: boolean; invisibleWatermark?: boolean; onProtectionViolation?: (violationType: ViolationType) => void; fallbackSrc?: string; @@ -83,13 +79,6 @@ export interface WatermarkConfig { rotation: number; } -export interface FragmentConfig { - enabled: boolean; - gridSize: number; - scramble: boolean; - randomSeed?: number; -} - export interface SteganographyConfig { enabled: boolean; message: string; @@ -121,7 +110,6 @@ export interface CanvasProtectionContext { originalImageData: ImageData; protectedImageData: ImageData; watermarkApplied: boolean; - fragmentsScrambled: boolean; } export interface PrintScreenDetectionState { @@ -181,7 +169,6 @@ export interface ProtectionConfig { rendering: { canvas: { enabled: boolean; - fragmentGrid: FragmentConfig; watermark: WatermarkConfig; steganography: SteganographyConfig; noiseInjection: boolean; @@ -231,9 +218,7 @@ export type ProtectionProps = { export type CanvasProtectionProps = ProtectionProps & { useCanvasRendering?: boolean; - fragmentGrid?: boolean; watermarkText?: string; - scrambleFragments?: boolean; invisibleWatermark?: boolean; };