diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts index 4e4c31e02..2ffbf471b 100644 --- a/packages/hydrooj/src/handler/home.ts +++ b/packages/hydrooj/src/handler/home.ts @@ -422,7 +422,7 @@ class HomeAvatarHandler extends Handler { } else if (this.request.files.file) { const file = this.request.files.file; if (file.size > 8 * 1024 * 1024) throw new ValidationError('file'); - const ext = path.extname(file.originalFilename); + const ext = path.extname(file.originalFilename).toLowerCase(); if (!['.jpg', '.jpeg', '.png'].includes(ext)) throw new ValidationError('file'); await storage.put(`user/${this.user._id}/.avatar${ext}`, file.filepath, this.user._id); // TODO: cached avatar diff --git a/packages/hydrooj/src/lib/mime.ts b/packages/hydrooj/src/lib/mime.ts new file mode 100644 index 000000000..f5a12e9ff --- /dev/null +++ b/packages/hydrooj/src/lib/mime.ts @@ -0,0 +1,8 @@ +import { lookup } from 'mime-types'; + +export default function mime(file: string) { + const identifer = file.toLowerCase(); + return (['.in', '.out', '.ans'].some((i) => identifer.endsWith(i))) + ? 'text/plain' + : lookup(file) || 'application/octet-stream'; +} diff --git a/packages/hydrooj/src/model/storage.ts b/packages/hydrooj/src/model/storage.ts index f6ab19873..c9cd51f12 100644 --- a/packages/hydrooj/src/model/storage.ts +++ b/packages/hydrooj/src/model/storage.ts @@ -1,9 +1,9 @@ import { extname } from 'path'; import { escapeRegExp } from 'lodash'; -import { lookup } from 'mime-types'; import moment from 'moment-timezone'; import { nanoid } from 'nanoid'; import type { Readable } from 'stream'; +import mime from '../lib/mime'; import * as bus from '../service/bus'; import db from '../service/db'; import storage from '../service/storage'; @@ -20,9 +20,7 @@ export class StorageModel { static async put(path: string, file: string | Buffer | Readable, owner?: number) { const meta = {}; await StorageModel.del([path]); - meta['Content-Type'] = (path.endsWith('.ans') || path.endsWith('.out')) - ? 'text/plain' - : lookup(path) || 'application/octet-stream'; + meta['Content-Type'] = mime(path); let _id = StorageModel.generateId(extname(path)); // Make sure id is not used // eslint-disable-next-line no-await-in-loop @@ -103,9 +101,7 @@ export class StorageModel { ); const meta = {}; await StorageModel.del([dst]); - meta['Content-Type'] = (dst.endsWith('.ans') || dst.endsWith('.out')) - ? 'text/plain' - : lookup(dst) || 'application/octet-stream'; + meta['Content-Type'] = mime(dst); let _id = StorageModel.generateId(extname(dst)); // Make sure id is not used // eslint-disable-next-line no-await-in-loop diff --git a/packages/hydrooj/src/plugin-api.ts b/packages/hydrooj/src/plugin-api.ts index 06a8e0296..ed15c5bb8 100644 --- a/packages/hydrooj/src/plugin-api.ts +++ b/packages/hydrooj/src/plugin-api.ts @@ -37,6 +37,7 @@ export { postJudge } from './handler/judge'; export { Collections } from './service/db'; export { Service, Context } from './context'; export { buildContent } from './lib/content'; +export { default as mime } from './lib/mime'; export { default as rating } from './lib/rating'; export { default as avatar } from './lib/avatar'; export { default as rank } from './lib/rank'; diff --git a/packages/ui-default/components/preview/preview.page.ts b/packages/ui-default/components/preview/preview.page.ts index 912b13e0f..da7e195c7 100644 --- a/packages/ui-default/components/preview/preview.page.ts +++ b/packages/ui-default/components/preview/preview.page.ts @@ -121,7 +121,7 @@ export async function previewFile(ev?, type = '') { const link = $(ev.currentTarget).find('a').attr('href'); if (!link) return null; type ||= ev.currentTarget.getAttribute('data-preview'); - const ext = filename.split('.').pop(); + const ext = filename.split('.').pop().toLowerCase(); if (['zip', 'rar', '7z'].includes(ext) || filesize > 8 * 1024 * 1024) { const action = await new ActionDialog({ $body: tpl.typoMsg(i18n('Cannot preview this file. Download now?')),