mirror of
https://git.um-react.app/um/um-react.git
synced 2025-11-28 03:23: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:
@@ -1,4 +1,4 @@
|
||||
import { chakra, Box, Button, Collapse, Text, useDisclosure } from '@chakra-ui/react';
|
||||
import { Box, Button, chakra, Collapse, Text, useDisclosure } from '@chakra-ui/react';
|
||||
import { DecryptErrorType } from '~/decrypt-worker/util/DecryptError';
|
||||
|
||||
export interface FileErrorProps {
|
||||
@@ -18,11 +18,12 @@ export function FileError({ error, code }: FileErrorProps) {
|
||||
<Box>
|
||||
<Text>
|
||||
<chakra.span>
|
||||
解密错误:<chakra.span color="red.700">{errorSummary}</chakra.span>
|
||||
解密错误:
|
||||
<chakra.span color="red.700">{errorSummary}</chakra.span>
|
||||
</chakra.span>
|
||||
{error && (
|
||||
<Button ml="2" onClick={onToggle} type="button">
|
||||
详细
|
||||
诊断信息
|
||||
</Button>
|
||||
)}
|
||||
</Text>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
|
||||
import type { RootState } from '~/store';
|
||||
|
||||
import { DECRYPTION_WORKER_ACTION_NAME, type DecryptionResult } from '~/decrypt-worker/constants';
|
||||
import type { DecryptCommandOptions, FetchMusicExNamePayload } from '~/decrypt-worker/types';
|
||||
import type {
|
||||
DecryptCommandOptions,
|
||||
FetchMusicExNamePayload,
|
||||
ParseKuwoHeaderPayload,
|
||||
ParseKuwoHeaderResponse,
|
||||
} from '~/decrypt-worker/types';
|
||||
import { decryptionQueue, workerClientBus } from '~/decrypt-worker/client';
|
||||
import { DecryptErrorType } from '~/decrypt-worker/util/DecryptError';
|
||||
import { selectQMCv2KeyByFileName, selectKWMv2Key, selectQtfmAndroidKey } from '../settings/settingsSelector';
|
||||
import { selectKWMv2Key, selectQMCv2KeyByFileName, selectQtfmAndroidKey } from '../settings/settingsSelector';
|
||||
|
||||
export enum ProcessState {
|
||||
QUEUED = 'QUEUED',
|
||||
@@ -43,6 +48,7 @@ export interface FileListingState {
|
||||
files: Record<string, DecryptedAudioFile>;
|
||||
displayMode: ListingMode;
|
||||
}
|
||||
|
||||
const initialState: FileListingState = {
|
||||
files: {},
|
||||
displayMode: ListingMode.LIST,
|
||||
@@ -64,28 +70,20 @@ export const processFile = createAsyncThunk<
|
||||
thunkAPI.dispatch(setFileAsProcessing({ id: fileId }));
|
||||
};
|
||||
|
||||
const fileHeader = await fetch(file.raw, { headers: { Range: 'bytes=0-1023' } })
|
||||
.then((r) => r.blob())
|
||||
.then((r) => r.arrayBuffer())
|
||||
.then((r) => {
|
||||
if (r.byteLength > 1024) {
|
||||
return r.slice(0, 1024);
|
||||
}
|
||||
return r;
|
||||
});
|
||||
|
||||
const qmcv2MusicExMediaFile = await workerClientBus.request<string, FetchMusicExNamePayload>(
|
||||
DECRYPTION_WORKER_ACTION_NAME.FIND_QMC_MUSICEX_NAME,
|
||||
{
|
||||
id: fileId,
|
||||
const [qmcv2MusicExMediaFile, kuwoHdr] = await Promise.all([
|
||||
workerClientBus.request<string, FetchMusicExNamePayload>(DECRYPTION_WORKER_ACTION_NAME.FIND_QMC_MUSICEX_NAME, {
|
||||
blobURI: file.raw,
|
||||
},
|
||||
);
|
||||
}),
|
||||
workerClientBus.request<ParseKuwoHeaderResponse, ParseKuwoHeaderPayload>(
|
||||
DECRYPTION_WORKER_ACTION_NAME.KUWO_PARSE_HEADER,
|
||||
{ blobURI: file.raw },
|
||||
),
|
||||
]);
|
||||
|
||||
const options: DecryptCommandOptions = {
|
||||
fileName: file.fileName,
|
||||
qmc2Key: selectQMCv2KeyByFileName(state, qmcv2MusicExMediaFile || file.fileName),
|
||||
kwm2key: selectKWMv2Key(state, new DataView(fileHeader)),
|
||||
kwm2key: selectKWMv2Key(state, kuwoHdr),
|
||||
qingTingAndroidKey: selectQtfmAndroidKey(state),
|
||||
};
|
||||
return decryptionQueue.add({ id: fileId, blobURI: file.raw, options }, onPreProcess);
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
ButtonGroup,
|
||||
Checkbox,
|
||||
Flex,
|
||||
HStack,
|
||||
Heading,
|
||||
HStack,
|
||||
Icon,
|
||||
IconButton,
|
||||
List,
|
||||
@@ -61,7 +61,7 @@ export function PanelQMCv2Key() {
|
||||
alert(`不是支持的 SQLite 数据库文件。`);
|
||||
return;
|
||||
}
|
||||
} else if (/MMKVStreamEncryptId|filenameEkeyMap|qmpc-mmkv-v1/i.test(file.name)) {
|
||||
} else if (/MMKVStreamEncryptId|filenameEkeyMap|qmpc-mmkv-v1|(\.mmkv$)/i.test(file.name)) {
|
||||
const fileBuffer = await file.arrayBuffer();
|
||||
const map = parseAndroidQmEKey(new DataView(fileBuffer));
|
||||
qmc2Keys = Array.from(map.entries(), ([name, ekey]) => ({ name: getFileName(name), ekey }));
|
||||
|
||||
@@ -13,12 +13,14 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '~/hooks';
|
||||
import { fetchParakeet } from '@um/libparakeet';
|
||||
import { ExtLink } from '~/components/ExtLink';
|
||||
import { ChangeEvent, ClipboardEvent } from 'react';
|
||||
import { VQuote } from '~/components/HelpText/VQuote';
|
||||
import { selectStagingQtfmAndroidKey } from '../settingsSelector';
|
||||
import { qtfmAndroidUpdateKey } from '../settingsSlice';
|
||||
import { workerClientBus } from '~/decrypt-worker/client.ts';
|
||||
import { GetQingTingFMDeviceKeyPayload } from '~/decrypt-worker/types.ts';
|
||||
import { DECRYPTION_WORKER_ACTION_NAME } from '~/decrypt-worker/constants.ts';
|
||||
|
||||
const QTFM_DEVICE_ID_URL = 'https://github.com/parakeet-rs/qtfm-device-id/releases/latest';
|
||||
|
||||
@@ -38,31 +40,23 @@ export function PanelQingTing() {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataMap = new Map();
|
||||
for (const [_unused, key, value] of plainText.matchAll(
|
||||
/^(PRODUCT|DEVICE|MANUFACTURER|BRAND|BOARD|MODEL): (.+)/gim,
|
||||
)) {
|
||||
dataMap.set(key.toLowerCase(), value);
|
||||
const dataMap = Object.create(null);
|
||||
for (const [, key, value] of plainText.matchAll(/^(PRODUCT|DEVICE|MANUFACTURER|BRAND|BOARD|MODEL): (.+)/gim)) {
|
||||
dataMap[key.toLowerCase()] = value;
|
||||
}
|
||||
const { product, device, manufacturer, brand, board, model } = dataMap;
|
||||
|
||||
const product = dataMap.get('product') ?? null;
|
||||
const device = dataMap.get('device') ?? null;
|
||||
const manufacturer = dataMap.get('manufacturer') ?? null;
|
||||
const brand = dataMap.get('brand') ?? null;
|
||||
const board = dataMap.get('board') ?? null;
|
||||
const model = dataMap.get('model') ?? null;
|
||||
if (
|
||||
product !== null &&
|
||||
device !== null &&
|
||||
manufacturer !== null &&
|
||||
brand !== null &&
|
||||
board !== null &&
|
||||
model !== null
|
||||
) {
|
||||
if (product && device && manufacturer && brand && board && model) {
|
||||
e.preventDefault();
|
||||
fetchParakeet().then((parakeet) => {
|
||||
setSecretKey(parakeet.qtfm.createDeviceKey(product, device, manufacturer, brand, board, model));
|
||||
});
|
||||
workerClientBus
|
||||
.request<string, GetQingTingFMDeviceKeyPayload>(
|
||||
DECRYPTION_WORKER_ACTION_NAME.QINGTING_FM_GET_DEVICE_KEY,
|
||||
dataMap,
|
||||
)
|
||||
.then(setSecretKey)
|
||||
.catch((err) => {
|
||||
alert(`生成设备密钥时发生错误: ${err}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { parseKuwoHeader } from '~/crypto/parseKuwo';
|
||||
import type { RootState } from '~/store';
|
||||
import { closestByLevenshtein } from '~/util/levenshtein';
|
||||
import { hasOwn } from '~/util/objects';
|
||||
import { kwm2StagingToProductionKey } from './keyFormats';
|
||||
import type { ParseKuwoHeaderResponse } from '~/decrypt-worker/types.ts';
|
||||
|
||||
export const selectIsSettingsNotSaved = (state: RootState) => state.settings.dirty;
|
||||
|
||||
@@ -31,14 +31,16 @@ export const selectQMCv2KeyByFileName = (state: RootState, name: string): string
|
||||
return ekey;
|
||||
};
|
||||
|
||||
export const selectKWMv2Key = (state: RootState, headerView: DataView): string | undefined => {
|
||||
const hdr = parseKuwoHeader(headerView);
|
||||
export const selectKWMv2Key = (state: RootState, hdr: ParseKuwoHeaderResponse): string | undefined => {
|
||||
if (!hdr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const quality = String(hdr.qualityId);
|
||||
const rid = String(hdr.resourceId);
|
||||
|
||||
const keys = selectFinalKWMv2Keys(state);
|
||||
const lookupKey = kwm2StagingToProductionKey({ id: '', ekey: '', quality: hdr.quality, rid: hdr.rid });
|
||||
const lookupKey = kwm2StagingToProductionKey({ id: '', ekey: '', quality, rid });
|
||||
|
||||
let ekey: string | undefined;
|
||||
if (hasOwn(keys, lookupKey)) {
|
||||
|
||||
Reference in New Issue
Block a user