um-react/src/decrypt-worker/worker.ts

56 lines
1.7 KiB
TypeScript
Raw Normal View History

2023-05-09 00:22:00 +00:00
import { WorkerServerBus } from '~/util/WorkerEventBus';
import { DECRYPTION_WORKER_ACTION_NAME } from './constants';
import type { CryptoFactory } from './crypto/CryptoBase';
2023-05-14 22:15:59 +00:00
import { fetchParakeet } from '@jixun/libparakeet';
import { XiamiCrypto } from './crypto/xiami/xiami';
import { QMC1Crypto } from './crypto/qmc/qmc_v1';
2023-05-14 22:15:59 +00:00
import { QMC2Crypto } from './crypto/qmc/qmc_v2';
const bus = new WorkerServerBus();
onmessage = bus.onmessage;
const decryptorFactories: CryptoFactory[] = [
// Xiami (*.xm)
() => new XiamiCrypto(),
2023-05-13 19:04:55 +00:00
// QMCv1 (*.qmcflac)
() => new QMC1Crypto(),
2023-05-14 22:15:59 +00:00
// QMCv2 (*.mflac)
() => new QMC2Crypto(),
];
2023-05-14 20:57:18 +00:00
// Use first 4MiB of the file to perform check.
const TEST_FILE_HEADER_LEN = 1024 * 1024 * 4;
bus.addEventHandler(DECRYPTION_WORKER_ACTION_NAME.DECRYPT, async (blobURI) => {
const blob = await fetch(blobURI).then((r) => r.blob());
2023-05-14 20:57:18 +00:00
const parakeet = await fetchParakeet();
for (const factory of decryptorFactories) {
const decryptor = factory();
if (await decryptor.isSupported(blob)) {
2023-05-14 22:15:59 +00:00
try {
const decryptedBlob = await decryptor.decrypt(blob);
// Check if we had a successful decryption
const header = await decryptedBlob.slice(0, TEST_FILE_HEADER_LEN).arrayBuffer();
const audioExt = parakeet.detectAudioExtension(header);
if (!decryptor.hasSignature() && audioExt === 'bin') {
// skip this decryptor result
continue;
}
return { decrypted: URL.createObjectURL(decryptedBlob), ext: audioExt };
} catch (error) {
console.error('decrypt failed: ', error);
2023-05-14 20:57:18 +00:00
continue;
}
}
}
throw new Error('could not decrypt file: no working decryptor found');
});