@@ -338,10 +338,15 @@ export async function _downloadFromUrl(url: string): Promise<string> {
338338 extract : false ,
339339 } ) ;
340340
341- logger . debug ( `Downloaded file to: ${ downloadPath } ` ) ;
341+ const downloadFilePath = downloadPath . endsWith ( '.zip' ) ? downloadPath : `${ downloadPath } .zip` ;
342+ logger . debug ( `Downloaded file to: ${ downloadFilePath } ` ) ;
342343
343- // 返回下载文件路径,由主流程决定是否需要压缩
344- return downloadPath ;
344+ const isDownloadedFileZip = await isZipFile ( downloadFilePath ) ;
345+ if ( ! isDownloadedFileZip ) {
346+ throw new Error ( `Downloaded file is not a valid zip file: ${ downloadFilePath } ` ) ;
347+ }
348+
349+ return downloadFilePath ;
345350 } catch ( error ) {
346351 // 如果下载失败,清理临时目录
347352 try {
@@ -356,3 +361,32 @@ export async function _downloadFromUrl(url: string): Promise<string> {
356361 throw new Error ( `Failed to download code from URL: ${ error . message } ` ) ;
357362 }
358363}
364+
365+ /**
366+ * 判断文件是否为ZIP文件 - 通过魔数检查
367+ */
368+ async function isZipFile ( filePath : string ) : Promise < boolean > {
369+ try {
370+ if ( ! fs . existsSync ( filePath ) ) {
371+ return false ;
372+ }
373+
374+ // 检查文件头部的魔数(而非扩展名)
375+ const buffer = Buffer . alloc ( 4 ) ;
376+ const fd = fs . openSync ( filePath , 'r' ) ;
377+ fs . readSync ( fd , buffer , 0 , 4 , 0 ) ;
378+ fs . closeSync ( fd ) ;
379+
380+ // ZIP文件的魔数是 50 4B 03 04 (十六进制)
381+ const isZipMagicNumber =
382+ buffer [ 0 ] === 0x50 &&
383+ buffer [ 1 ] === 0x4b &&
384+ ( buffer [ 2 ] === 0x03 || buffer [ 2 ] === 0x05 || buffer [ 2 ] === 0x07 ) &&
385+ ( buffer [ 3 ] === 0x04 || buffer [ 3 ] === 0x06 || buffer [ 3 ] === 0x08 ) ;
386+
387+ return isZipMagicNumber ;
388+ } catch ( error ) {
389+ logger . debug ( `Error checking if file is zip: ${ error . message } ` ) ;
390+ return false ;
391+ }
392+ }
0 commit comments