59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
const ROOM_NAME_SANITIZER = /[^\w.-]+/g;
|
|
const STORED_FILENAME_SANITIZER = /[^\w.-]+/g;
|
|
|
|
export function sanitizeAttachmentRoomName(roomName: string): string {
|
|
const sanitizedRoomName = roomName.trim().replace(ROOM_NAME_SANITIZER, '_');
|
|
|
|
return sanitizedRoomName || 'room';
|
|
}
|
|
|
|
export function resolveAttachmentStoredFilename(attachmentId: string, filename: string): string {
|
|
const sanitizedAttachmentId = attachmentId.trim().replace(STORED_FILENAME_SANITIZER, '_') || 'attachment';
|
|
const basename = filename.trim().split(/[\\/]/)
|
|
.pop() ?? '';
|
|
const extensionIndex = basename.lastIndexOf('.');
|
|
|
|
if (extensionIndex <= 0 || extensionIndex === basename.length - 1) {
|
|
return sanitizedAttachmentId;
|
|
}
|
|
|
|
const sanitizedExtension = basename.slice(extensionIndex)
|
|
.replace(STORED_FILENAME_SANITIZER, '_')
|
|
.toLowerCase();
|
|
|
|
return sanitizedExtension === '.'
|
|
? sanitizedAttachmentId
|
|
: `${sanitizedAttachmentId}${sanitizedExtension}`;
|
|
}
|
|
|
|
export function isAllowedAttachmentStoredPath(candidatePath: string, appDataPath: string): boolean {
|
|
const normalizedCandidate = candidatePath.trim().replace(/\\/g, '/');
|
|
const normalizedRoot = appDataPath.trim().replace(/\\/g, '/')
|
|
.replace(/\/+$/, '');
|
|
|
|
if (!normalizedCandidate.startsWith(`${normalizedRoot}/`)) {
|
|
return false;
|
|
}
|
|
|
|
const relativePath = normalizedCandidate.slice(normalizedRoot.length + 1);
|
|
|
|
return relativePath.startsWith('server/')
|
|
|| relativePath.startsWith('direct-messages/');
|
|
}
|
|
|
|
export function resolveAttachmentStorageBucket(mime: string): 'video' | 'audio' | 'image' | 'files' {
|
|
if (mime.startsWith('video/')) {
|
|
return 'video';
|
|
}
|
|
|
|
if (mime.startsWith('audio/')) {
|
|
return 'audio';
|
|
}
|
|
|
|
if (mime.startsWith('image/')) {
|
|
return 'image';
|
|
}
|
|
|
|
return 'files';
|
|
}
|