diff --git a/apps/server/src/services/import/samples/utf8-filename.zip b/apps/server/src/services/import/samples/utf8-filename.zip new file mode 100644 index 0000000000..959afe86d5 Binary files /dev/null and b/apps/server/src/services/import/samples/utf8-filename.zip differ diff --git a/apps/server/src/services/import/zip.spec.ts b/apps/server/src/services/import/zip.spec.ts index ecc070c6a9..21e4b19e14 100644 --- a/apps/server/src/services/import/zip.spec.ts +++ b/apps/server/src/services/import/zip.spec.ts @@ -71,6 +71,11 @@ describe("processNoteContent", () => { expect(content).toContain(` { + const { importedNote } = await testImport("utf8-filename.zip"); + expect(importedNote.title).toBe("测试"); + }); + it("can import old geomap notes", async () => { const { importedNote } = await testImport("geomap.zip"); expect(importedNote.type).toBe("book"); diff --git a/apps/server/src/services/import/zip.ts b/apps/server/src/services/import/zip.ts index 9c7cd8aefc..5d9e00d8ab 100644 --- a/apps/server/src/services/import/zip.ts +++ b/apps/server/src/services/import/zip.ts @@ -659,13 +659,20 @@ export function readContent(zipfile: yauzl.ZipFile, entry: yauzl.Entry): Promise export function readZipFile(buffer: Buffer, processEntryCallback: (zipfile: yauzl.ZipFile, entry: yauzl.Entry) => Promise) { return new Promise((res, rej) => { - yauzl.fromBuffer(buffer, { lazyEntries: true, validateEntrySizes: false }, (err, zipfile) => { + yauzl.fromBuffer(buffer, { lazyEntries: true, validateEntrySizes: false, decodeStrings: false }, (err, zipfile) => { if (err) rej(err); if (!zipfile) throw new Error("Unable to read zip file."); zipfile.readEntry(); zipfile.on("entry", async (entry) => { try { + // yauzl with decodeStrings: false returns fileName as a Buffer. + // We decode as UTF-8 to handle ZIP files that use UTF-8 filenames + // without setting the general purpose bit flag 11 (language encoding flag). + if (Buffer.isBuffer(entry.fileName)) { + entry.fileName = (entry.fileName as Buffer).toString("utf-8"); + } + await processEntryCallback(zipfile, entry); } catch (e) { rej(e);