1
0
forked from um/web

test(joox): Added basic sanity test for joox encryption.

(cherry picked from commit 48b8194363264a0276006deaa3c956970a543627)
This commit is contained in:
鲁树人 2021-12-23 23:23:32 +00:00
parent 18a8dbfaa4
commit 62cd276c5d
8 changed files with 70 additions and 8 deletions

View File

@ -1,4 +1,7 @@
module.exports = { module.exports = {
setupFilesAfterEnv: [
'./src/__test__/setup_jest.js'
],
moduleNameMapper: { moduleNameMapper: {
'@/(.*)': '<rootDir>/src/$1' '@/(.*)': '<rootDir>/src/$1'
} }

14
package-lock.json generated
View File

@ -12,7 +12,7 @@
"dependencies": { "dependencies": {
"@babel/preset-typescript": "^7.16.5", "@babel/preset-typescript": "^7.16.5",
"@jixun/qmc2-crypto": "^0.0.5-R4", "@jixun/qmc2-crypto": "^0.0.5-R4",
"@unlock-music/joox-crypto": "^0.0.1-R4", "@unlock-music/joox-crypto": "^0.0.1-R5",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"browser-id3-writer": "^4.4.0", "browser-id3-writer": "^4.4.0",
"core-js": "^3.16.0", "core-js": "^3.16.0",
@ -3487,9 +3487,9 @@
"dev": true "dev": true
}, },
"node_modules/@unlock-music/joox-crypto": { "node_modules/@unlock-music/joox-crypto": {
"version": "0.0.1-R4", "version": "0.0.1-R5",
"resolved": "https://registry.npmjs.org/@unlock-music/joox-crypto/-/joox-crypto-0.0.1-R4.tgz", "resolved": "https://registry.npmjs.org/@unlock-music/joox-crypto/-/joox-crypto-0.0.1-R5.tgz",
"integrity": "sha512-5UScjXtH9J3mAy9sRBjNn5kkEuT7dHvH3YQYKRyOfF3EKxLkWsJP0Fuw/tZtylLPL5beI3qDBzyHf5mVrpdH4A==", "integrity": "sha512-+FhGT4bjzfb1Q7dAwHps/XqbqXrRA6Qg7pkDPzyXfeRmQocAySQ/dekojxkaFBf7ZX5ToIAopwxkKZ5NFt5bFw==",
"dependencies": { "dependencies": {
"crypto-js": "^4.1.1" "crypto-js": "^4.1.1"
}, },
@ -23635,9 +23635,9 @@
"dev": true "dev": true
}, },
"@unlock-music/joox-crypto": { "@unlock-music/joox-crypto": {
"version": "0.0.1-R4", "version": "0.0.1-R5",
"resolved": "https://registry.npmjs.org/@unlock-music/joox-crypto/-/joox-crypto-0.0.1-R4.tgz", "resolved": "https://registry.npmjs.org/@unlock-music/joox-crypto/-/joox-crypto-0.0.1-R5.tgz",
"integrity": "sha512-5UScjXtH9J3mAy9sRBjNn5kkEuT7dHvH3YQYKRyOfF3EKxLkWsJP0Fuw/tZtylLPL5beI3qDBzyHf5mVrpdH4A==", "integrity": "sha512-+FhGT4bjzfb1Q7dAwHps/XqbqXrRA6Qg7pkDPzyXfeRmQocAySQ/dekojxkaFBf7ZX5ToIAopwxkKZ5NFt5bFw==",
"requires": { "requires": {
"crypto-js": "^4.1.1" "crypto-js": "^4.1.1"
} }

View File

@ -22,7 +22,7 @@
"dependencies": { "dependencies": {
"@babel/preset-typescript": "^7.16.5", "@babel/preset-typescript": "^7.16.5",
"@jixun/qmc2-crypto": "^0.0.5-R4", "@jixun/qmc2-crypto": "^0.0.5-R4",
"@unlock-music/joox-crypto": "^0.0.1-R4", "@unlock-music/joox-crypto": "^0.0.1-R5",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"browser-id3-writer": "^4.4.0", "browser-id3-writer": "^4.4.0",
"core-js": "^3.16.0", "core-js": "^3.16.0",

View File

@ -0,0 +1,2 @@
// Polyfill for node.
global.Blob = global.Blob || require("node:buffer").Blob;

Binary file not shown.

View File

@ -0,0 +1,52 @@
import fs from 'fs';
import { storage } from '@/utils/storage';
import { Decrypt as decryptJoox } from '../joox';
import { extractQQMusicMeta as extractQQMusicMetaOrig } from '@/utils/qm_meta';
jest.mock('@/utils/storage');
jest.mock('@/utils/qm_meta');
const loadJooxUUID = storage.loadJooxUUID as jest.MockedFunction<typeof storage.loadJooxUUID>;
const extractQQMusicMeta = extractQQMusicMetaOrig as jest.MockedFunction<typeof extractQQMusicMetaOrig>;
const TEST_UUID_ZEROS = ''.padStart(32, '0');
const encryptedFile1 = fs.readFileSync(__dirname + '/fixture/joox_1.bin');
describe('decrypt/joox', () => {
it('should be able to decrypt sample file (v4)', async () => {
loadJooxUUID.mockResolvedValue(TEST_UUID_ZEROS);
extractQQMusicMeta.mockImplementationOnce(async (blob: Blob) => {
return {
title: 'unused',
album: 'unused',
blob: blob,
artist: 'unused',
imgUrl: 'https://github.com/unlock-music',
};
});
const result = await decryptJoox(new Blob([encryptedFile1]), 'test.bin', 'bin');
const resultBuf = await result.blob.arrayBuffer();
expect(resultBuf).toEqual(Buffer.from('Hello World', 'utf-8').buffer);
});
it('should reject E!99 files', async () => {
loadJooxUUID.mockResolvedValue(TEST_UUID_ZEROS);
const input = new Blob([Buffer.from('E!99....')]);
await expect(decryptJoox(input, 'test.bin', 'bin')).rejects.toThrow('不支持的 joox 加密格式');
});
it('should reject empty uuid', async () => {
loadJooxUUID.mockResolvedValue('');
const input = new Blob([encryptedFile1]);
await expect(decryptJoox(input, 'test.bin', 'bin')).rejects.toThrow('UUID');
});
it('should reject invalid uuid', async () => {
loadJooxUUID.mockResolvedValue('hello!');
const input = new Blob([encryptedFile1]);
await expect(decryptJoox(input, 'test.bin', 'bin')).rejects.toThrow('UUID');
});
});

View File

@ -0,0 +1 @@
export const extractQQMusicMeta = jest.fn();

View File

@ -0,0 +1,4 @@
export const storage = {
loadJooxUUID: jest.fn(),
saveJooxUUID: jest.fn(),
};