fix(admin-service): 改用 yauzl.fromBuffer 解析 APK,支持 V2/V3 签名格式
yauzl.open() 在 APK V2/V3 签名包上报 'end of central directory record signature not found',因为签名块会挤移 EOCD 位置。改为直接调用 yauzl.fromBuffer() + adbkit-apkreader 内部 BinaryXmlParser/ManifestParser 直接从内存解析 AndroidManifest.xml,兼容所有签名格式,且无需临时文件。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e00cbb71c5
commit
276eda2a84
|
|
@ -1,6 +1,3 @@
|
|||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { Injectable, Logger, BadRequestException } from '@nestjs/common';
|
||||
import { IPackageParser, ParsedPackageInfo } from '../../domain/ports/package-parser.interface';
|
||||
|
||||
|
|
@ -16,14 +13,47 @@ export class PackageParserService implements IPackageParser {
|
|||
}
|
||||
|
||||
private async parseApk(buffer: Buffer): Promise<ParsedPackageInfo> {
|
||||
// adbkit-apkreader v3 底层用 yauzl.open(),只接受文件路径而非 Buffer
|
||||
// 先写入临时文件,解析后删除
|
||||
const tmpFile = path.join(os.tmpdir(), `apk-parse-${Date.now()}.apk`);
|
||||
// yauzl.open() 不支持 APK V2/V3 签名格式(EOCD 被签名块挤移),
|
||||
// 改用 yauzl.fromBuffer() + adbkit-apkreader 内部 ManifestParser 直接解析
|
||||
try {
|
||||
fs.writeFileSync(tmpFile, buffer);
|
||||
const ApkReader = await import('adbkit-apkreader').then(m => m.default || m);
|
||||
const reader = await ApkReader.open(tmpFile);
|
||||
const manifest = await reader.readManifest();
|
||||
const yauzl = await import('yauzl');
|
||||
const { ManifestParser } = await import('adbkit-apkreader/lib/apkreader/parser/manifest' as any).then(
|
||||
(m: any) => ({ ManifestParser: m.default || m }),
|
||||
);
|
||||
const { BinaryXmlParser } = await import('adbkit-apkreader/lib/apkreader/parser/binaryxml' as any).then(
|
||||
(m: any) => ({ BinaryXmlParser: m.default || m }),
|
||||
);
|
||||
|
||||
const zipfile = await new Promise<any>((resolve, reject) =>
|
||||
yauzl.fromBuffer(buffer, { lazyEntries: true }, (err: any, zf: any) =>
|
||||
err ? reject(err) : resolve(zf),
|
||||
),
|
||||
);
|
||||
|
||||
const manifestBuffer = await new Promise<Buffer>((resolve, reject) => {
|
||||
zipfile.readEntry();
|
||||
zipfile.on('entry', (entry: any) => {
|
||||
if (entry.fileName === 'AndroidManifest.xml') {
|
||||
zipfile.openReadStream(entry, (err: any, stream: any) => {
|
||||
if (err) return reject(err);
|
||||
const chunks: Buffer[] = [];
|
||||
stream.on('data', (c: Buffer) => chunks.push(c));
|
||||
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
||||
stream.on('error', reject);
|
||||
});
|
||||
} else {
|
||||
zipfile.readEntry();
|
||||
}
|
||||
});
|
||||
zipfile.on('end', () => reject(new Error('AndroidManifest.xml not found')));
|
||||
zipfile.on('error', reject);
|
||||
});
|
||||
|
||||
const binaryXml = new BinaryXmlParser(manifestBuffer);
|
||||
const parsed = binaryXml.parse();
|
||||
const manifestParser = new ManifestParser(parsed);
|
||||
const manifest = manifestParser.parse();
|
||||
|
||||
return {
|
||||
packageName: manifest.package || 'unknown',
|
||||
versionCode: manifest.versionCode || 0,
|
||||
|
|
@ -39,8 +69,6 @@ export class PackageParserService implements IPackageParser {
|
|||
versionName: '0.0.0',
|
||||
platform: 'ANDROID',
|
||||
};
|
||||
} finally {
|
||||
try { fs.unlinkSync(tmpFile); } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue