mirror of
https://git.unlock-music.dev/um/um-react.git
synced 2024-11-23 19:32:15 +00:00
feat: pass options to downstream decryptor
This commit is contained in:
parent
0038322ae9
commit
865dcae931
@ -1,3 +1,5 @@
|
||||
import type { DecryptCommandOptions } from '~/decrypt-worker/types';
|
||||
|
||||
export interface CryptoBase {
|
||||
cryptoName: string;
|
||||
checkByDecryptHeader: boolean;
|
||||
@ -8,8 +10,8 @@ export interface CryptoBase {
|
||||
*/
|
||||
overrideExtension?: string;
|
||||
|
||||
checkBySignature?: (buffer: ArrayBuffer) => Promise<boolean>;
|
||||
decrypt(buffer: ArrayBuffer, blob: Blob): Promise<Blob | ArrayBuffer>;
|
||||
checkBySignature?: (buffer: ArrayBuffer, options: DecryptCommandOptions) => Promise<boolean>;
|
||||
decrypt(buffer: ArrayBuffer, options: DecryptCommandOptions): Promise<Blob | ArrayBuffer>;
|
||||
}
|
||||
|
||||
export type CryptoFactory = () => CryptoBase;
|
||||
|
9
src/decrypt-worker/types.ts
Normal file
9
src/decrypt-worker/types.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export interface DecryptCommandOptions {
|
||||
qmc2Key?: string;
|
||||
}
|
||||
|
||||
export interface DecryptCommandPayload {
|
||||
id: string;
|
||||
blobURI: string;
|
||||
options: DecryptCommandOptions;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { Parakeet, fetchParakeet } from '@jixun/libparakeet';
|
||||
import { timedLogger, withGroupedLogs as withTimeGroupedLogs } from '~/util/logUtils';
|
||||
import type { DecryptCommandOptions, DecryptCommandPayload } from '~/decrypt-worker/types';
|
||||
import { allCryptoFactories } from '../../crypto/CryptoFactory';
|
||||
import { toArrayBuffer, toBlob } from '~/decrypt-worker/util/buffer';
|
||||
import { CryptoBase, CryptoFactory } from '~/decrypt-worker/crypto/CryptoBase';
|
||||
@ -11,8 +12,13 @@ const TEST_FILE_HEADER_LEN = 4 * 1024 * 1024;
|
||||
class DecryptCommandHandler {
|
||||
private label: string;
|
||||
|
||||
constructor(label: string, private parakeet: Parakeet, private blob: Blob, private buffer: ArrayBuffer) {
|
||||
this.label = `DecryptCommandHandler( ${label} )`;
|
||||
constructor(
|
||||
label: string,
|
||||
private parakeet: Parakeet,
|
||||
private buffer: ArrayBuffer,
|
||||
private options: DecryptCommandOptions
|
||||
) {
|
||||
this.label = `DecryptCommandHandler(${label})`;
|
||||
}
|
||||
|
||||
log<R>(label: string, fn: () => R): R {
|
||||
@ -42,7 +48,7 @@ class DecryptCommandHandler {
|
||||
}
|
||||
|
||||
async decryptFile(crypto: CryptoBase) {
|
||||
if (crypto.checkBySignature && !(await crypto.checkBySignature(this.buffer))) {
|
||||
if (crypto.checkBySignature && !(await crypto.checkBySignature(this.buffer, this.options))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -50,7 +56,7 @@ class DecryptCommandHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
const decrypted = await this.log(`decrypt (${crypto.cryptoName})`, () => crypto.decrypt(this.buffer, this.blob));
|
||||
const decrypted = await this.log(`decrypt (${crypto.cryptoName})`, () => crypto.decrypt(this.buffer, this.options));
|
||||
|
||||
// Check if we had a successful decryption
|
||||
const audioExt = crypto.overrideExtension ?? (await this.detectAudioExtension(decrypted));
|
||||
@ -76,23 +82,21 @@ class DecryptCommandHandler {
|
||||
|
||||
// Check by decrypt max first 8MiB
|
||||
const decryptedBuffer = await this.log(`${crypto.cryptoName}/decrypt-header-test`, async () =>
|
||||
toArrayBuffer(
|
||||
await crypto.decrypt(this.buffer.slice(0, TEST_FILE_HEADER_LEN), this.blob.slice(0, TEST_FILE_HEADER_LEN))
|
||||
)
|
||||
toArrayBuffer(await crypto.decrypt(this.buffer.slice(0, TEST_FILE_HEADER_LEN), this.options))
|
||||
);
|
||||
|
||||
return this.parakeet.detectAudioExtension(decryptedBuffer) !== 'bin';
|
||||
}
|
||||
}
|
||||
|
||||
export const workerDecryptHandler = async ({ id, blobURI }: { id: string; blobURI: string }) => {
|
||||
const label = `decrypt( ${id} )`;
|
||||
export const workerDecryptHandler = async ({ id, blobURI, options }: DecryptCommandPayload) => {
|
||||
const label = `decrypt(${id})`;
|
||||
return withTimeGroupedLogs(label, async () => {
|
||||
const parakeet = await timedLogger(`${label}/init`, fetchParakeet);
|
||||
const blob = await timedLogger(`${label}/fetch-src`, async () => fetch(blobURI).then((r) => r.blob()));
|
||||
const buffer = await timedLogger(`${label}/read-src`, async () => blob.arrayBuffer());
|
||||
|
||||
const handler = new DecryptCommandHandler(id, parakeet, blob, buffer);
|
||||
const handler = new DecryptCommandHandler(id, parakeet, buffer, options);
|
||||
return handler.decrypt(allCryptoFactories);
|
||||
});
|
||||
};
|
||||
|
@ -5,6 +5,7 @@ import { decryptionQueue } from '~/decrypt-worker/client';
|
||||
|
||||
import type { DecryptionResult } from '~/decrypt-worker/constants';
|
||||
import { DecryptErrorType } from '~/decrypt-worker/util/DecryptError';
|
||||
import { selectDecryptOptionByFile } from '../settings/settingsSelector';
|
||||
|
||||
export enum ProcessState {
|
||||
QUEUED = 'QUEUED',
|
||||
@ -51,7 +52,8 @@ export const processFile = createAsyncThunk<
|
||||
{ fileId: string },
|
||||
{ rejectValue: { message: string; stack?: string } }
|
||||
>('fileListing/processFile', async ({ fileId }, thunkAPI) => {
|
||||
const file = selectFiles(thunkAPI.getState() as RootState)[fileId];
|
||||
const state = thunkAPI.getState() as RootState;
|
||||
const file = selectFiles(state)[fileId];
|
||||
if (!file) {
|
||||
const { message, stack } = new Error('ERROR: File not found');
|
||||
return thunkAPI.rejectWithValue({ message, stack });
|
||||
@ -61,7 +63,8 @@ export const processFile = createAsyncThunk<
|
||||
thunkAPI.dispatch(setFileAsProcessing({ id: fileId }));
|
||||
};
|
||||
|
||||
return decryptionQueue.add({ id: fileId, blobURI: file.raw }, onPreProcess);
|
||||
const options = selectDecryptOptionByFile(state, file.fileName);
|
||||
return decryptionQueue.add({ id: fileId, blobURI: file.raw, options }, onPreProcess);
|
||||
});
|
||||
|
||||
export const fileListingSlice = createSlice({
|
||||
|
11
src/features/settings/settingsSelector.ts
Normal file
11
src/features/settings/settingsSelector.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { DecryptCommandOptions } from '~/decrypt-worker/types';
|
||||
import type { RootState } from '~/store';
|
||||
import { hasOwn } from '~/util/objects';
|
||||
|
||||
export const selectDecryptOptionByFile = (state: RootState, name: string): DecryptCommandOptions => {
|
||||
const qmc2Keys = state.settings.qmc2.keys;
|
||||
|
||||
return {
|
||||
qmc2Key: hasOwn(qmc2Keys, name) ? qmc2Keys[name] : undefined,
|
||||
};
|
||||
};
|
@ -1,13 +1,15 @@
|
||||
import type { DecryptCommandPayload } from '~/decrypt-worker/types';
|
||||
import { DECRYPTION_WORKER_ACTION_NAME, DecryptionResult } from '~/decrypt-worker/constants';
|
||||
|
||||
import { ConcurrentQueue } from './ConcurrentQueue';
|
||||
import { WorkerClientBus } from './WorkerEventBus';
|
||||
|
||||
export class DecryptionQueue extends ConcurrentQueue<{ id: string; blobURI: string }, DecryptionResult> {
|
||||
export class DecryptionQueue extends ConcurrentQueue<DecryptCommandPayload, DecryptionResult> {
|
||||
constructor(private workerClientBus: WorkerClientBus<DECRYPTION_WORKER_ACTION_NAME>, maxQueue?: number) {
|
||||
super(maxQueue);
|
||||
}
|
||||
|
||||
async handler(item: { id: string; blobURI: string }): Promise<DecryptionResult> {
|
||||
async handler(item: DecryptCommandPayload): Promise<DecryptionResult> {
|
||||
return this.workerClientBus.request(DECRYPTION_WORKER_ACTION_NAME.DECRYPT, item);
|
||||
}
|
||||
}
|
||||
|
@ -5,3 +5,5 @@ export function* enumObject<T>(obj: Record<string, T> | null | void): Generator<
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const { hasOwn } = Object;
|
||||
|
Loading…
Reference in New Issue
Block a user