mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
Merge pull request #622 from JDProfresh/fix/attach-video-containers
fix(uploads): refuse an unsupported video before uploading it Conflict resolved against #621 in src/web/public/image-input.js (the _promptAttachKind doc comment only): #621's comment is kept with #622's clause that a video MIME counts only for the containers the server admits; #622's video MIME check and #621's document branch both stay. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
6e4181a2e6
2 files changed
+24
-5
No files matched your search
@@ -270,13 +270,17 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
* clips (the server streams those to disk under their own cap), 'document'
|
* clips (the server streams those to disk under their own cap), 'document'
|
||||||
* for the office and text files the server admits, else null. The one filter
|
* for the office and text files the server admits, else null. The one filter
|
||||||
* behind Attach, drop, the Compose and paste-dialog pickers and the clipboard
|
* behind Attach, drop, the Compose and paste-dialog pickers and the clipboard
|
||||||
* handlers. For media the MIME type decides; some Android file managers hand
|
* handlers. For media the MIME type decides, but a video MIME only for the
|
||||||
* over a File with none, so the name's extension is the fallback. A document
|
* containers the server admits; some Android file managers hand over a File
|
||||||
* is known by its extension alone, as on the server (the MIME a file manager
|
* with none, so the name's extension is the fallback. A document is known by
|
||||||
* gives a .md or .csv is anyone's guess). Mirrors the server's allowlists. */
|
* its extension alone, as on the server (the MIME a file manager gives a .md
|
||||||
|
* or .csv is anyone's guess). Mirrors the server's allowlists. */
|
||||||
_promptAttachKind(file) {
|
_promptAttachKind(file) {
|
||||||
if (file.type.startsWith('image/')) return 'image';
|
if (file.type.startsWith('image/')) return 'image';
|
||||||
if (file.type.startsWith('video/')) return 'video';
|
// A video MIME counts only for the five containers the server accepts on
|
||||||
|
// ?kind=video (its own set in session-routes.ts); a 3gp or mkv falls to the
|
||||||
|
// extension check below and is refused up front, not after a 1GB upload and a 400.
|
||||||
|
if (/^video\/(mp4|quicktime|x-m4v|webm|ogg)$/i.test(file.type)) return 'video';
|
||||||
const ext = (file.name || '').toLowerCase().match(/\.([a-z0-9]+)$/)?.[1] || '';
|
const ext = (file.name || '').toLowerCase().match(/\.([a-z0-9]+)$/)?.[1] || '';
|
||||||
if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'heic', 'heif'].includes(ext)) return 'image';
|
if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'heic', 'heif'].includes(ext)) return 'image';
|
||||||
if (['mp4', 'webm', 'mov', 'm4v', 'ogv'].includes(ext)) return 'video';
|
if (['mp4', 'webm', 'mov', 'm4v', 'ogv'].includes(ext)) return 'video';
|
||||||
|
|||||||
@@ -367,6 +367,21 @@ describe('phone toolbar Attach button', () => {
|
|||||||
expect(fetchMock.mock.calls[0][0]).toBe('/api/sessions/session-1/paste-image');
|
expect(fetchMock.mock.calls[0][0]).toBe('/api/sessions/session-1/paste-image');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('counts a video MIME only for the containers the server admits on ?kind=video', () => {
|
||||||
|
const { app, window } = loadToolbar();
|
||||||
|
const kind = (type: string, name = 'clip') => app._promptAttachKind(new window.File(['x'], name, { type }));
|
||||||
|
// The five the server's ?kind=video branch accepts (session-routes.ts).
|
||||||
|
for (const type of ['video/mp4', 'video/quicktime', 'video/x-m4v', 'video/webm', 'video/ogg']) {
|
||||||
|
expect(kind(type)).toBe('video');
|
||||||
|
}
|
||||||
|
// A video MIME outside that set is refused client-side (no full upload then a
|
||||||
|
// 400) when the name's extension is not one the server admits either.
|
||||||
|
expect(kind('video/3gpp', 'clip.3gp')).toBeNull();
|
||||||
|
expect(kind('video/x-matroska', 'clip.mkv')).toBeNull();
|
||||||
|
// An admitted extension still rescues an odd MIME, as the server's path does.
|
||||||
|
expect(kind('video/3gpp', 'clip.mp4')).toBe('video');
|
||||||
|
});
|
||||||
|
|
||||||
it('flags the upload as a video by name as well as by MIME type', async () => {
|
it('flags the upload as a video by name as well as by MIME type', async () => {
|
||||||
const { app, window, fetchMock } = loadToolbar();
|
const { app, window, fetchMock } = loadToolbar();
|
||||||
await app._uploadPasteImage('session-1', new window.File(['v'], 'clip.ogv', { type: '' }));
|
await app._uploadPasteImage('session-1', new window.File(['v'], 'clip.ogv', { type: '' }));
|
||||||
|
|||||||
Reference in new issue
Block a user