mirror of
				https://git.unlock-music.dev/um/web.git
				synced 2025-11-04 09:23:28 +08:00 
			
		
		
		
	fix: treat qmcflac/qmcogg as QMCv2 and fallback to QMCv1
(cherry picked from commit 41e588e9864801897fa13eb96a1764baaa5a4ab5)
This commit is contained in:
		
							parent
							
								
									d199647308
								
							
						
					
					
						commit
						fb33e80484
					
				@ -27,11 +27,14 @@ export const HandlerMap: { [key: string]: Handler } = {
 | 
				
			|||||||
    "mflac": {ext: "flac", version: 2},
 | 
					    "mflac": {ext: "flac", version: 2},
 | 
				
			||||||
    "mflac0": {ext: "flac", version: 2},
 | 
					    "mflac0": {ext: "flac", version: 2},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // qmcflac / qmcogg:
 | 
				
			||||||
 | 
					    // 有可能是 v2 加密但混用同一个后缀名。
 | 
				
			||||||
 | 
					    "qmcflac": {ext: "flac", version: 2},
 | 
				
			||||||
 | 
					    "qmcogg": {ext: "ogg", version: 2},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    "qmc0": {ext: "mp3", version: 1},
 | 
					    "qmc0": {ext: "mp3", version: 1},
 | 
				
			||||||
    "qmc2": {ext: "ogg", version: 1},
 | 
					    "qmc2": {ext: "ogg", version: 1},
 | 
				
			||||||
    "qmc3": {ext: "mp3", version: 1},
 | 
					    "qmc3": {ext: "mp3", version: 1},
 | 
				
			||||||
    "qmcogg": {ext: "ogg", version: 1},
 | 
					 | 
				
			||||||
    "qmcflac": {ext: "flac", version: 1},
 | 
					 | 
				
			||||||
    "bkcmp3": {ext: "mp3", version: 1},
 | 
					    "bkcmp3": {ext: "mp3", version: 1},
 | 
				
			||||||
    "bkcflac": {ext: "flac", version: 1},
 | 
					    "bkcflac": {ext: "flac", version: 1},
 | 
				
			||||||
    "tkm": {ext: "m4a", version: 1},
 | 
					    "tkm": {ext: "m4a", version: 1},
 | 
				
			||||||
@ -45,16 +48,26 @@ export const HandlerMap: { [key: string]: Handler } = {
 | 
				
			|||||||
export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise<DecryptResult> {
 | 
					export async function Decrypt(file: Blob, raw_filename: string, raw_ext: string): Promise<DecryptResult> {
 | 
				
			||||||
    if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`;
 | 
					    if (!(raw_ext in HandlerMap)) throw `Qmc cannot handle type: ${raw_ext}`;
 | 
				
			||||||
    const handler = HandlerMap[raw_ext];
 | 
					    const handler = HandlerMap[raw_ext];
 | 
				
			||||||
 | 
					    let { version } = handler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const fileBuffer = await GetArrayBuffer(file);
 | 
					    const fileBuffer = await GetArrayBuffer(file);
 | 
				
			||||||
    let musicDecoded: Uint8Array;
 | 
					    let musicDecoded: Uint8Array|undefined;
 | 
				
			||||||
    if (handler.version === 1) {
 | 
					
 | 
				
			||||||
 | 
					    if (version === 2) {
 | 
				
			||||||
 | 
					        const v2Decrypted = await DecryptQMCv2(fileBuffer);
 | 
				
			||||||
 | 
					        // 如果 v2 检测失败,降级到 v1 再尝试一次
 | 
				
			||||||
 | 
					        if (v2Decrypted) {
 | 
				
			||||||
 | 
					            musicDecoded = v2Decrypted;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            version = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (version === 1) {
 | 
				
			||||||
        const seed = QmcMaskGetDefault();
 | 
					        const seed = QmcMaskGetDefault();
 | 
				
			||||||
        musicDecoded = seed.Decrypt(new Uint8Array(fileBuffer));
 | 
					        musicDecoded = seed.Decrypt(new Uint8Array(fileBuffer));
 | 
				
			||||||
    } else if (handler.version === 2) {
 | 
					    } else if (!musicDecoded) {
 | 
				
			||||||
        musicDecoded = await DecryptQMCv2(fileBuffer);
 | 
					        throw new Error(`解密失败: ${raw_ext}`);
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        throw new Error(`不支持的加密版本: ${handler.version} (${raw_ext})`);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const ext = SniffAudioExt(musicDecoded, handler.ext);
 | 
					    const ext = SniffAudioExt(musicDecoded, handler.ext);
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,7 @@ function MergeUint8Array(array: Uint8Array[]): Uint8Array {
 | 
				
			|||||||
 * 如果检测并解密成功,返回解密后的 Uint8Array 数据。
 | 
					 * 如果检测并解密成功,返回解密后的 Uint8Array 数据。
 | 
				
			||||||
 * @param  {ArrayBuffer} mggBlob 读入的文件 Blob
 | 
					 * @param  {ArrayBuffer} mggBlob 读入的文件 Blob
 | 
				
			||||||
 * @param  {string}         name 文件名
 | 
					 * @param  {string}         name 文件名
 | 
				
			||||||
 * @return {Promise<Uint8Array|null>}
 | 
					 * @return {Promise<Uint8Array|false>}
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export async function DecryptQMCv2(mggBlob: ArrayBuffer) {
 | 
					export async function DecryptQMCv2(mggBlob: ArrayBuffer) {
 | 
				
			||||||
  // 初始化模组
 | 
					  // 初始化模组
 | 
				
			||||||
@ -53,14 +53,13 @@ export async function DecryptQMCv2(mggBlob: ArrayBuffer) {
 | 
				
			|||||||
  // (pos: i32; len: i32; error: char[??])
 | 
					  // (pos: i32; len: i32; error: char[??])
 | 
				
			||||||
  const position = QMCCrypto.getValue(pDetectionResult, "i32");
 | 
					  const position = QMCCrypto.getValue(pDetectionResult, "i32");
 | 
				
			||||||
  const len = QMCCrypto.getValue(pDetectionResult + 4, "i32");
 | 
					  const len = QMCCrypto.getValue(pDetectionResult + 4, "i32");
 | 
				
			||||||
  const detectionError = QMCCrypto.UTF8ToString(pDetectionResult + 8);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 释放内存
 | 
					  // 释放内存
 | 
				
			||||||
  QMCCrypto._free(pDetectionBuf);
 | 
					  QMCCrypto._free(pDetectionBuf);
 | 
				
			||||||
  QMCCrypto._free(pDetectionResult);
 | 
					  QMCCrypto._free(pDetectionResult);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!detectOK) {
 | 
					  if (!detectOK) {
 | 
				
			||||||
    throw new Error("解密失败: \n  " + detectionError);
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 计算解密后文件的大小。
 | 
					  // 计算解密后文件的大小。
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user