feat: extend file type classification and implement computeHash
- Add sticker (webp) and video_note to classification mapping and file limits - Handle unknown mime or caption fallback to document - Implement computeHash utility using Bun.CryptoHasher for sha256 checksums - Update and add comprehensive tests in file.test.ts Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
22c2133b24
commit
4e805689c1
+11
-1
@@ -5,12 +5,16 @@ const FILE_TYPES: Record<string, number> = {
|
|||||||
audio: 200 * 1024 * 1024, // 200MB
|
audio: 200 * 1024 * 1024, // 200MB
|
||||||
voice: 200 * 1024 * 1024, // 200MB
|
voice: 200 * 1024 * 1024, // 200MB
|
||||||
animation: 2 * 1024 * 1024 * 1024, // 2GB
|
animation: 2 * 1024 * 1024 * 1024, // 2GB
|
||||||
|
sticker: 10 * 1024 * 1024, // 10MB
|
||||||
|
video_note: 2 * 1024 * 1024 * 1024, // 2GB
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getFileType = (mime: string | null, caption?: string): string => {
|
export const getFileType = (mime: string | null, caption?: string): string => {
|
||||||
const mimeUpper = mime?.split('/')[0]?.toLowerCase();
|
const mimeUpper = mime?.split('/')[0]?.toLowerCase();
|
||||||
const captionLower = caption?.toLowerCase();
|
const captionLower = caption?.toLowerCase();
|
||||||
|
|
||||||
|
if (mime?.toLowerCase() === 'image/webp' || captionLower?.includes('sticker')) return 'sticker';
|
||||||
|
if (captionLower?.includes('video_note')) return 'video_note';
|
||||||
if (mimeUpper === 'video') return 'video';
|
if (mimeUpper === 'video') return 'video';
|
||||||
if (mimeUpper === 'audio') return 'audio';
|
if (mimeUpper === 'audio') return 'audio';
|
||||||
if (mimeUpper === 'document') return 'document';
|
if (mimeUpper === 'document') return 'document';
|
||||||
@@ -18,7 +22,7 @@ export const getFileType = (mime: string | null, caption?: string): string => {
|
|||||||
if (captionLower?.includes('voice')) return 'voice';
|
if (captionLower?.includes('voice')) return 'voice';
|
||||||
if (captionLower?.includes('animation')) return 'animation';
|
if (captionLower?.includes('animation')) return 'animation';
|
||||||
|
|
||||||
return mimeUpper || 'document';
|
return mimeUpper === 'application' ? 'application' : 'document';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const checkFileSize = (sizeBytes: number, fileType: string): boolean => {
|
export const checkFileSize = (sizeBytes: number, fileType: string): boolean => {
|
||||||
@@ -95,3 +99,9 @@ export const extractMimeType = (msg: any, request: any): string => {
|
|||||||
'application/octet-stream'
|
'application/octet-stream'
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const computeHash = (buffer: Buffer): string => {
|
||||||
|
const hasher = new Bun.CryptoHasher('sha256');
|
||||||
|
hasher.update(buffer);
|
||||||
|
return hasher.digest('hex');
|
||||||
|
};
|
||||||
|
|||||||
+20
-1
@@ -1,6 +1,6 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { describe, expect, it } from 'bun:test';
|
import { describe, expect, it } from 'bun:test';
|
||||||
import { checkFileSize, extractFileName, extractMimeType, getFileType } from '../src/utils/file';
|
import { checkFileSize, computeHash, extractFileName, extractMimeType, getFileType } from '../src/utils/file';
|
||||||
|
|
||||||
describe('File Utilities', () => {
|
describe('File Utilities', () => {
|
||||||
describe('getFileType', () => {
|
describe('getFileType', () => {
|
||||||
@@ -26,9 +26,17 @@ describe('File Utilities', () => {
|
|||||||
expect(getFileType('application/octet-stream', 'cool animation')).toBe('animation');
|
expect(getFileType('application/octet-stream', 'cool animation')).toBe('animation');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should classify sticker and video_note', () => {
|
||||||
|
expect(getFileType('image/webp', '')).toBe('sticker');
|
||||||
|
expect(getFileType('image/webp', 'some caption')).toBe('sticker');
|
||||||
|
expect(getFileType('video/mp4', 'this is a video_note')).toBe('video_note');
|
||||||
|
expect(getFileType('application/octet-stream', 'video_note file')).toBe('video_note');
|
||||||
|
});
|
||||||
|
|
||||||
it('should default to mime first segment or document', () => {
|
it('should default to mime first segment or document', () => {
|
||||||
expect(getFileType('application/pdf', '')).toBe('application');
|
expect(getFileType('application/pdf', '')).toBe('application');
|
||||||
expect(getFileType(null, '')).toBe('document');
|
expect(getFileType(null, '')).toBe('document');
|
||||||
|
expect(getFileType('unknown/type', '')).toBe('document');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -36,11 +44,13 @@ describe('File Utilities', () => {
|
|||||||
it('should allow files under the size limit', () => {
|
it('should allow files under the size limit', () => {
|
||||||
expect(checkFileSize(5 * 1024 * 1024, 'photo')).toBe(true); // Photo limit is 10MB
|
expect(checkFileSize(5 * 1024 * 1024, 'photo')).toBe(true); // Photo limit is 10MB
|
||||||
expect(checkFileSize(1 * 1024 * 1024 * 1024, 'video')).toBe(true); // Video limit is 2GB
|
expect(checkFileSize(1 * 1024 * 1024 * 1024, 'video')).toBe(true); // Video limit is 2GB
|
||||||
|
expect(checkFileSize(2 * 1024 * 1024 * 1024, 'document')).toBe(true); // Document limit is 2GB
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should block files exceeding the size limit', () => {
|
it('should block files exceeding the size limit', () => {
|
||||||
expect(checkFileSize(15 * 1024 * 1024, 'photo')).toBe(false); // Photo limit is 10MB
|
expect(checkFileSize(15 * 1024 * 1024, 'photo')).toBe(false); // Photo limit is 10MB
|
||||||
expect(checkFileSize(3 * 1024 * 1024 * 1024, 'video')).toBe(false); // Video limit is 2GB
|
expect(checkFileSize(3 * 1024 * 1024 * 1024, 'video')).toBe(false); // Video limit is 2GB
|
||||||
|
expect(checkFileSize(3 * 1024 * 1024 * 1024, 'document')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fall back to document limit if fileType is unknown', () => {
|
it('should fall back to document limit if fileType is unknown', () => {
|
||||||
@@ -92,4 +102,13 @@ describe('File Utilities', () => {
|
|||||||
expect(extractMimeType({}, null)).toBe('application/octet-stream');
|
expect(extractMimeType({}, null)).toBe('application/octet-stream');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('computeHash', () => {
|
||||||
|
it('should compute SHA-256 hash of a buffer', () => {
|
||||||
|
const buffer = Buffer.from('hello world');
|
||||||
|
const hash = computeHash(buffer);
|
||||||
|
// sha256 of 'hello world' is b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||||
|
expect(hash).toBe('b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user