mirror of
https://git.um-react.app/um/um-react.git
synced 2025-11-28 11:33:02 +00:00
Dependency upgrade + lib_um_crypto_rust (#78)
Co-authored-by: 鲁树人 <lu.shuren@um-react.app> Co-committed-by: 鲁树人 <lu.shuren@um-react.app>
This commit is contained in:
91
src/decrypt-worker/worker/decrypt.ts
Normal file
91
src/decrypt-worker/worker/decrypt.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { timedLogger, withGroupedLogs as withTimeGroupedLogs } from '~/util/logUtils.ts';
|
||||
import type { DecryptCommandOptions, DecryptCommandPayload } from '~/decrypt-worker/types.ts';
|
||||
import { allCryptoFactories } from '../Deciphers.ts';
|
||||
import { toBlob } from '~/decrypt-worker/util/buffer.ts';
|
||||
import { DecipherFactory, DecipherInstance, Status } from '~/decrypt-worker/Deciphers.ts';
|
||||
import { UnsupportedSourceFile } from '~/decrypt-worker/util/DecryptError.ts';
|
||||
import { ready as umCryptoReady } from '@unlock-music/crypto';
|
||||
import { go } from '~/util/go.ts';
|
||||
import { detectAudioExtension } from '~/decrypt-worker/util/audioType.ts';
|
||||
|
||||
class DecryptCommandHandler {
|
||||
private readonly label: string;
|
||||
|
||||
constructor(
|
||||
label: string,
|
||||
private buffer: Uint8Array,
|
||||
private options: DecryptCommandOptions,
|
||||
) {
|
||||
this.label = `DecryptCommandHandler(${label})`;
|
||||
}
|
||||
|
||||
log<R>(label: string, fn: () => Promise<R>): Promise<R> {
|
||||
return timedLogger(`${this.label}: ${label}`, fn);
|
||||
}
|
||||
|
||||
async decrypt(decipherFactories: DecipherFactory[]) {
|
||||
const errors: string[] = [];
|
||||
for (const factory of decipherFactories) {
|
||||
const decipher = factory();
|
||||
|
||||
const [result, error] = await go(this.tryDecryptWith(decipher));
|
||||
if (!error) {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
errors.push(`${decipher.cipherName}: no response`);
|
||||
continue; // not supported
|
||||
}
|
||||
|
||||
const errMsg = error.message;
|
||||
if (errMsg) {
|
||||
errors.push(`${decipher.cipherName}: ${errMsg}`);
|
||||
}
|
||||
if (error instanceof UnsupportedSourceFile) {
|
||||
console.debug('[%s] Not this decipher:', decipher.cipherName, error);
|
||||
} else {
|
||||
console.error('decrypt failed with unknown error: ', error);
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnsupportedSourceFile(errors.join('\n'));
|
||||
}
|
||||
|
||||
async tryDecryptWith(decipher: DecipherInstance) {
|
||||
const result = await this.log(`try decrypt with ${decipher.cipherName}`, async () =>
|
||||
decipher.decrypt(this.buffer, this.options),
|
||||
);
|
||||
switch (result.status) {
|
||||
case Status.NOT_THIS_CIPHER:
|
||||
return null;
|
||||
case Status.FAILED:
|
||||
throw new Error(`failed: ${result.message}`);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if we had a successful decryption
|
||||
let audioExt = result.overrideExtension || detectAudioExtension(result.data);
|
||||
if (!result.overrideExtension && audioExt === 'bin') {
|
||||
throw new UnsupportedSourceFile('unable to produce valid audio file');
|
||||
}
|
||||
|
||||
// Convert mp4 to m4a
|
||||
if (audioExt.toLowerCase() === 'mp4') {
|
||||
audioExt = 'm4a';
|
||||
}
|
||||
|
||||
return { decrypted: URL.createObjectURL(toBlob(result.data)), ext: audioExt };
|
||||
}
|
||||
}
|
||||
|
||||
export const workerDecryptHandler = async ({ id: payloadId, blobURI, options }: DecryptCommandPayload) => {
|
||||
await umCryptoReady;
|
||||
const id = payloadId.replace('://', ':');
|
||||
const label = `decrypt(${id})`;
|
||||
return withTimeGroupedLogs(label, async () => {
|
||||
const buffer = await fetch(blobURI).then((r) => r.arrayBuffer());
|
||||
const handler = new DecryptCommandHandler(id, new Uint8Array(buffer), options);
|
||||
return handler.decrypt(allCryptoFactories);
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user