refactor: move decrypt command to its own file; added version command
This commit is contained in:
parent
b99590908e
commit
cf3324e833
@ -9,7 +9,7 @@ export const workerClient = new Worker(new URL('./worker', import.meta.url), { t
|
|||||||
workerClient.onerror = (err) => console.error(err);
|
workerClient.onerror = (err) => console.error(err);
|
||||||
|
|
||||||
class DecryptionQueue extends ConcurrentQueue<{ id: string; blobURI: string }> {
|
class DecryptionQueue extends ConcurrentQueue<{ id: string; blobURI: string }> {
|
||||||
constructor(private workerClientBus: WorkerClientBus, maxQueue?: number) {
|
constructor(private workerClientBus: WorkerClientBus<DECRYPTION_WORKER_ACTION_NAME>, maxQueue?: number) {
|
||||||
super(maxQueue);
|
super(maxQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,4 +18,5 @@ class DecryptionQueue extends ConcurrentQueue<{ id: string; blobURI: string }> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const decryptionQueue = new DecryptionQueue(new WorkerClientBus(workerClient));
|
export const workerClientBus = new WorkerClientBus<DECRYPTION_WORKER_ACTION_NAME>(workerClient);
|
||||||
|
export const decryptionQueue = new DecryptionQueue(workerClientBus);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export enum DECRYPTION_WORKER_ACTION_NAME {
|
export enum DECRYPTION_WORKER_ACTION_NAME {
|
||||||
DECRYPT = 'DECRYPT',
|
DECRYPT = 'DECRYPT',
|
||||||
|
VERSION = 'VERSION',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DecryptionResult {
|
export interface DecryptionResult {
|
||||||
|
49
src/decrypt-worker/worker-handler/decrypt.ts
Normal file
49
src/decrypt-worker/worker-handler/decrypt.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { fetchParakeet } from '@jixun/libparakeet';
|
||||||
|
import { CryptoFactory } from '../crypto/CryptoBase';
|
||||||
|
|
||||||
|
import { XiamiCrypto } from '../crypto/xiami/xiami';
|
||||||
|
import { QMC1Crypto } from '../crypto/qmc/qmc_v1';
|
||||||
|
import { QMC2Crypto } from '../crypto/qmc/qmc_v2';
|
||||||
|
|
||||||
|
// Use first 4MiB of the file to perform check.
|
||||||
|
const TEST_FILE_HEADER_LEN = 1024 * 1024 * 4;
|
||||||
|
|
||||||
|
const decryptorFactories: CryptoFactory[] = [
|
||||||
|
// Xiami (*.xm)
|
||||||
|
() => new XiamiCrypto(),
|
||||||
|
|
||||||
|
// QMCv1 (*.qmcflac)
|
||||||
|
() => new QMC1Crypto(),
|
||||||
|
|
||||||
|
// QMCv2 (*.mflac)
|
||||||
|
() => new QMC2Crypto(),
|
||||||
|
];
|
||||||
|
|
||||||
|
export const workerDecryptHandler = async (blobURI: string) => {
|
||||||
|
const blob = await fetch(blobURI).then((r) => r.blob());
|
||||||
|
const parakeet = await fetchParakeet();
|
||||||
|
|
||||||
|
for (const factory of decryptorFactories) {
|
||||||
|
const decryptor = factory();
|
||||||
|
if (await decryptor.isSupported(blob)) {
|
||||||
|
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);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('could not decrypt file: no working decryptor found');
|
||||||
|
};
|
@ -1,55 +1,15 @@
|
|||||||
import { WorkerServerBus } from '~/util/WorkerEventBus';
|
import { WorkerServerBus } from '~/util/WorkerEventBus';
|
||||||
import { DECRYPTION_WORKER_ACTION_NAME } from './constants';
|
import { DECRYPTION_WORKER_ACTION_NAME } from './constants';
|
||||||
|
|
||||||
import type { CryptoFactory } from './crypto/CryptoBase';
|
import { getSDKVersion } from '@jixun/libparakeet';
|
||||||
import { fetchParakeet } from '@jixun/libparakeet';
|
|
||||||
|
|
||||||
import { XiamiCrypto } from './crypto/xiami/xiami';
|
import { workerDecryptHandler } from './worker-handler/decrypt';
|
||||||
import { QMC1Crypto } from './crypto/qmc/qmc_v1';
|
|
||||||
import { QMC2Crypto } from './crypto/qmc/qmc_v2';
|
|
||||||
|
|
||||||
const bus = new WorkerServerBus();
|
const bus = new WorkerServerBus();
|
||||||
onmessage = bus.onmessage;
|
onmessage = bus.onmessage;
|
||||||
|
|
||||||
const decryptorFactories: CryptoFactory[] = [
|
bus.addEventHandler(DECRYPTION_WORKER_ACTION_NAME.DECRYPT, workerDecryptHandler);
|
||||||
// Xiami (*.xm)
|
|
||||||
() => new XiamiCrypto(),
|
|
||||||
|
|
||||||
// QMCv1 (*.qmcflac)
|
bus.addEventHandler(DECRYPTION_WORKER_ACTION_NAME.VERSION, async () => {
|
||||||
() => new QMC1Crypto(),
|
return getSDKVersion();
|
||||||
|
|
||||||
// QMCv2 (*.mflac)
|
|
||||||
() => new QMC2Crypto(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// 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());
|
|
||||||
const parakeet = await fetchParakeet();
|
|
||||||
|
|
||||||
for (const factory of decryptorFactories) {
|
|
||||||
const decryptor = factory();
|
|
||||||
if (await decryptor.isSupported(blob)) {
|
|
||||||
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);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('could not decrypt file: no working decryptor found');
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user