- Add comprehensive naming convention (provider-region-resource-env-purpose) - Implement Terraform locals for centralized naming - Update all Terraform resources to use new naming convention - Create deployment automation framework (18 phase scripts) - Add Azure setup scripts (provider registration, quota checks) - Update deployment scripts config with naming functions - Create complete deployment documentation (guide, steps, quick reference) - Add frontend portal implementations (public and internal) - Add UI component library (18 components) - Enhance Entra VerifiedID integration with file utilities - Add API client package for all services - Create comprehensive documentation (naming, deployment, next steps) Infrastructure: - Resource groups, storage accounts with new naming - Terraform configuration updates - Outputs with naming convention examples Deployment: - Automated deployment scripts for all 15 phases - State management and logging - Error handling and validation Documentation: - Naming convention guide and implementation summary - Complete deployment guide (296 steps) - Next steps and quick start guides - Azure prerequisites and setup completion docs Note: ESLint warnings present - will be addressed in follow-up commit
174 lines
5.6 KiB
TypeScript
174 lines
5.6 KiB
TypeScript
/**
|
|
* Tests for file utilities
|
|
* Run with: pnpm test file-utils
|
|
*/
|
|
|
|
import {
|
|
encodeFileToBase64,
|
|
decodeBase64ToBuffer,
|
|
isBase64,
|
|
detectMimeType,
|
|
validateBase64File,
|
|
encodeFileWithMetadata,
|
|
sanitizeFilename,
|
|
calculateFileHash,
|
|
FILE_SIZE_LIMITS,
|
|
SUPPORTED_MIME_TYPES,
|
|
} from './file-utils';
|
|
|
|
describe('File Utilities', () => {
|
|
describe('encodeFileToBase64', () => {
|
|
it('should encode buffer to base64', () => {
|
|
const buffer = Buffer.from('test content');
|
|
const result = encodeFileToBase64(buffer);
|
|
expect(result).toBe('dGVzdCBjb250ZW50');
|
|
});
|
|
|
|
it('should encode string to base64', () => {
|
|
const result = encodeFileToBase64('test content');
|
|
expect(result).toBe('dGVzdCBjb250ZW50');
|
|
});
|
|
|
|
it('should return base64 string as-is if already encoded', () => {
|
|
const base64 = 'dGVzdCBjb250ZW50';
|
|
const result = encodeFileToBase64(base64);
|
|
expect(result).toBe(base64);
|
|
});
|
|
|
|
it('should include MIME type in data URL format', () => {
|
|
const buffer = Buffer.from('test');
|
|
const result = encodeFileToBase64(buffer, 'application/json');
|
|
expect(result).toContain('data:application/json;base64,');
|
|
});
|
|
});
|
|
|
|
describe('decodeBase64ToBuffer', () => {
|
|
it('should decode base64 to buffer', () => {
|
|
const base64 = 'dGVzdCBjb250ZW50';
|
|
const buffer = decodeBase64ToBuffer(base64);
|
|
expect(buffer.toString()).toBe('test content');
|
|
});
|
|
|
|
it('should handle data URL format', () => {
|
|
const dataUrl = 'data:application/json;base64,dGVzdCBjb250ZW50';
|
|
const buffer = decodeBase64ToBuffer(dataUrl);
|
|
expect(buffer.toString()).toBe('test content');
|
|
});
|
|
});
|
|
|
|
describe('isBase64', () => {
|
|
it('should return true for valid base64', () => {
|
|
expect(isBase64('dGVzdCBjb250ZW50')).toBe(true);
|
|
expect(isBase64('SGVsbG8gV29ybGQ=')).toBe(true);
|
|
});
|
|
|
|
it('should return false for invalid base64', () => {
|
|
expect(isBase64('not base64!@#')).toBe(false);
|
|
expect(isBase64('')).toBe(false);
|
|
});
|
|
|
|
it('should handle data URL format', () => {
|
|
expect(isBase64('data:application/json;base64,dGVzdA==')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('detectMimeType', () => {
|
|
it('should detect PDF from buffer', () => {
|
|
const pdfBuffer = Buffer.from('%PDF-1.4\n');
|
|
const mimeType = detectMimeType(pdfBuffer);
|
|
expect(mimeType).toBe(SUPPORTED_MIME_TYPES.PDF);
|
|
});
|
|
|
|
it('should detect PNG from buffer', () => {
|
|
const pngBuffer = Buffer.from([0x89, 0x50, 0x4E, 0x47]);
|
|
const mimeType = detectMimeType(pngBuffer);
|
|
expect(mimeType).toBe(SUPPORTED_MIME_TYPES.PNG);
|
|
});
|
|
|
|
it('should detect MIME type from filename', () => {
|
|
const mimeType = detectMimeType(Buffer.from('test'), 'document.pdf');
|
|
expect(mimeType).toBe(SUPPORTED_MIME_TYPES.PDF);
|
|
});
|
|
});
|
|
|
|
describe('validateBase64File', () => {
|
|
it('should validate valid base64 file', () => {
|
|
const base64 = encodeFileToBase64(Buffer.from('test content'));
|
|
const result = validateBase64File(base64);
|
|
expect(result.valid).toBe(true);
|
|
expect(result.errors).toHaveLength(0);
|
|
});
|
|
|
|
it('should reject invalid base64', () => {
|
|
const result = validateBase64File('invalid base64!@#');
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should enforce size limits', () => {
|
|
const largeBuffer = Buffer.alloc(FILE_SIZE_LIMITS.MEDIUM + 1);
|
|
const base64 = encodeFileToBase64(largeBuffer);
|
|
const result = validateBase64File(base64, {
|
|
maxSize: FILE_SIZE_LIMITS.MEDIUM,
|
|
});
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors.some(e => e.includes('exceeds maximum'))).toBe(true);
|
|
});
|
|
|
|
it('should validate MIME types', () => {
|
|
const pdfBuffer = Buffer.from('%PDF-1.4\n');
|
|
const base64 = encodeFileToBase64(pdfBuffer);
|
|
const result = validateBase64File(base64, {
|
|
allowedMimeTypes: [SUPPORTED_MIME_TYPES.PDF],
|
|
});
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should reject disallowed MIME types', () => {
|
|
const pdfBuffer = Buffer.from('%PDF-1.4\n');
|
|
const base64 = encodeFileToBase64(pdfBuffer);
|
|
const result = validateBase64File(base64, {
|
|
allowedMimeTypes: [SUPPORTED_MIME_TYPES.PNG],
|
|
});
|
|
expect(result.valid).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('sanitizeFilename', () => {
|
|
it('should sanitize unsafe characters', () => {
|
|
const filename = '../../etc/passwd';
|
|
const sanitized = sanitizeFilename(filename);
|
|
expect(sanitized).not.toContain('/');
|
|
expect(sanitized).not.toContain('..');
|
|
});
|
|
|
|
it('should preserve safe characters', () => {
|
|
const filename = 'document_123.pdf';
|
|
const sanitized = sanitizeFilename(filename);
|
|
expect(sanitized).toBe('document_123.pdf');
|
|
});
|
|
|
|
it('should limit filename length', () => {
|
|
const longFilename = 'a'.repeat(300) + '.pdf';
|
|
const sanitized = sanitizeFilename(longFilename);
|
|
expect(sanitized.length).toBeLessThanOrEqual(255);
|
|
});
|
|
});
|
|
|
|
describe('calculateFileHash', () => {
|
|
it('should calculate SHA256 hash', () => {
|
|
const data = Buffer.from('test content');
|
|
const hash = calculateFileHash(data);
|
|
expect(hash).toHaveLength(64); // SHA256 produces 64 hex characters
|
|
expect(typeof hash).toBe('string');
|
|
});
|
|
|
|
it('should calculate SHA512 hash', () => {
|
|
const data = Buffer.from('test content');
|
|
const hash = calculateFileHash(data, 'sha512');
|
|
expect(hash).toHaveLength(128); // SHA512 produces 128 hex characters
|
|
});
|
|
});
|
|
});
|
|
|