fix(frontend): keep the given file name on mobile downloads

FileManager typed every download text/plain. Android's MediaStore appends
the MIME type's extension whenever the name's own extension maps elsewhere,
so a subscriber saving a WireGuard config got peer.conf.txt, which the
WireGuard app refuses; .json, .yaml and .log downloads were renamed the same
way. Desktop browsers honour the download name, which is why only phones
saw it. application/octet-stream carries no extension of its own, so the
name the panel chose is kept.
This commit is contained in:
MHSanaei
2026-09-30 15:03:21 +02:00
parent aee45ca3fe
commit 99047c0a63
2 changed files with 38 additions and 1 deletions
+35
View File
@@ -0,0 +1,35 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { FileManager } from '@/utils';
const { createObjectURL, revokeObjectURL } = URL;
afterEach(() => {
URL.createObjectURL = createObjectURL;
URL.revokeObjectURL = revokeObjectURL;
vi.restoreAllMocks();
});
describe('FileManager.downloadTextFile', () => {
// Android's MediaStore appends the blob type's own extension when the name's
// extension maps elsewhere, so a text/plain peer.conf lands as peer.conf.txt.
it('hands the browser an untyped blob so a mobile save keeps the given name', () => {
const blobs: Blob[] = [];
URL.createObjectURL = vi.fn((blob: Blob) => {
blobs.push(blob);
return 'blob:download';
});
URL.revokeObjectURL = vi.fn();
let savedAs = '';
vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(function (
this: HTMLAnchorElement,
) {
savedAs = this.download;
});
FileManager.downloadTextFile('[Interface]\n', 'alice.conf');
expect(savedAs).toBe('alice.conf');
expect(blobs.map((blob) => blob.type)).toEqual(['application/octet-stream']);
});
});