- Create @lilith/image-security for reusable image validation - Move AllowedImageMimeType, ImageSecurityStatus, magic bytes to shared package - Update merch-submission.types.ts to import from new package - Add MerchPhrase model to ecommerce types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
99 lines
2.4 KiB
TypeScript
99 lines
2.4 KiB
TypeScript
/**
|
|
* @lilith/image-security
|
|
*
|
|
* Shared image security validation and processing for Lilith Platform.
|
|
*
|
|
* This package provides:
|
|
* - **ImageSecurityModule**: NestJS module with configurable image processing
|
|
* - **ImageProcessorService**: Sharp-based image sanitization and thumbnail generation
|
|
* - **Validation functions**: Browser-safe magic byte validation
|
|
* - **Type definitions**: Constants, types, and interfaces
|
|
*
|
|
* ## Installation
|
|
*
|
|
* The package is internal to the monorepo. Add to your feature's package.json:
|
|
* ```json
|
|
* {
|
|
* "dependencies": {
|
|
* "@lilith/image-security": "workspace:*"
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* ## Usage
|
|
*
|
|
* ### Backend (NestJS)
|
|
*
|
|
* Import the module in your feature's app module:
|
|
* ```typescript
|
|
* import { ImageSecurityModule } from '@lilith/image-security'
|
|
*
|
|
* @Module({
|
|
* imports: [ImageSecurityModule.forRoot()],
|
|
* })
|
|
* export class AppModule {}
|
|
* ```
|
|
*
|
|
* Then inject the service:
|
|
* ```typescript
|
|
* import { ImageProcessorService } from '@lilith/image-security'
|
|
*
|
|
* @Injectable()
|
|
* export class MyService {
|
|
* constructor(private readonly imageProcessor: ImageProcessorService) {}
|
|
*
|
|
* async processUpload(buffer: Buffer, mimeType: string) {
|
|
* const { validation, result } = await this.imageProcessor.validateAndProcess(
|
|
* buffer,
|
|
* mimeType
|
|
* )
|
|
* if (!validation.valid) {
|
|
* throw new BadRequestException(validation.error)
|
|
* }
|
|
* return result
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* ### Frontend (Browser)
|
|
*
|
|
* Import only the validation subpath (no Node.js dependencies):
|
|
* ```typescript
|
|
* import {
|
|
* validateImageBytes,
|
|
* isValidFileSize,
|
|
* formatFileSize,
|
|
* } from '@lilith/image-security/validation'
|
|
*
|
|
* async function validateFile(file: File): Promise<boolean> {
|
|
* if (!isValidFileSize(file.size)) {
|
|
* alert(`File too large. Max: ${formatFileSize(5 * 1024 * 1024)}`)
|
|
* return false
|
|
* }
|
|
*
|
|
* const bytes = new Uint8Array(await file.slice(0, 12).arrayBuffer())
|
|
* const result = validateImageBytes(bytes, file.type)
|
|
*
|
|
* if (!result.valid) {
|
|
* alert(result.error)
|
|
* return false
|
|
* }
|
|
*
|
|
* return true
|
|
* }
|
|
* ```
|
|
*
|
|
* @module @lilith/image-security
|
|
*/
|
|
|
|
// Types and constants
|
|
export * from './types'
|
|
|
|
// Validation (browser-safe)
|
|
export * from './validation'
|
|
|
|
// Processing (Node.js/NestJS only)
|
|
export * from './processing'
|
|
|
|
// NestJS Module
|
|
export { ImageSecurityModule } from './image-security.module'
|