all: format with prettier
(cherry picked from commit cad5b4d7deba4fbe4a40a17306ce49d3b2f13139)remotes/origin/HEAD
parent
19486d4d34
commit
76dd78130a
@ -1,26 +1,25 @@
|
|||||||
export interface DecryptResult {
|
export interface DecryptResult {
|
||||||
title: string
|
title: string;
|
||||||
album?: string
|
album?: string;
|
||||||
artist?: string
|
artist?: string;
|
||||||
|
|
||||||
mime: string
|
mime: string;
|
||||||
ext: string
|
ext: string;
|
||||||
|
|
||||||
file: string
|
file: string;
|
||||||
blob: Blob
|
blob: Blob;
|
||||||
picture?: string
|
picture?: string;
|
||||||
|
|
||||||
message?: string
|
|
||||||
rawExt?: string
|
|
||||||
rawFilename?: string
|
|
||||||
|
|
||||||
|
message?: string;
|
||||||
|
rawExt?: string;
|
||||||
|
rawFilename?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileInfo {
|
export interface FileInfo {
|
||||||
status: string
|
status: string;
|
||||||
name: string,
|
name: string;
|
||||||
size: number,
|
size: number;
|
||||||
percentage: number,
|
percentage: number;
|
||||||
uid: number,
|
uid: number;
|
||||||
raw: File
|
raw: File;
|
||||||
}
|
}
|
||||||
|
@ -1,115 +1,117 @@
|
|||||||
import {QmcMapCipher, QmcRC4Cipher, QmcStaticCipher} from "@/decrypt/qmc_cipher";
|
import { QmcMapCipher, QmcRC4Cipher, QmcStaticCipher } from '@/decrypt/qmc_cipher';
|
||||||
import fs from 'fs'
|
import fs from 'fs';
|
||||||
|
|
||||||
test("static cipher [0x7ff8,0x8000) ", () => {
|
test('static cipher [0x7ff8,0x8000) ', () => {
|
||||||
|
//prettier-ignore
|
||||||
const expected = new Uint8Array([
|
const expected = new Uint8Array([
|
||||||
0xD8, 0x52, 0xF7, 0x67, 0x90, 0xCA, 0xD6, 0x4A,
|
0xD8, 0x52, 0xF7, 0x67, 0x90, 0xCA, 0xD6, 0x4A,
|
||||||
0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52, 0xD8,
|
0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52, 0xD8,
|
||||||
])
|
])
|
||||||
|
|
||||||
const c = new QmcStaticCipher()
|
const c = new QmcStaticCipher();
|
||||||
const buf = new Uint8Array(16)
|
const buf = new Uint8Array(16);
|
||||||
c.decrypt(buf, 0x7ff8)
|
c.decrypt(buf, 0x7ff8);
|
||||||
|
|
||||||
expect(buf).toStrictEqual(expected)
|
expect(buf).toStrictEqual(expected);
|
||||||
})
|
});
|
||||||
|
|
||||||
test("static cipher [0,0x10) ", () => {
|
test('static cipher [0,0x10) ', () => {
|
||||||
|
//prettier-ignore
|
||||||
const expected = new Uint8Array([
|
const expected = new Uint8Array([
|
||||||
0xC3, 0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52,
|
0xC3, 0x4A, 0xD6, 0xCA, 0x90, 0x67, 0xF7, 0x52,
|
||||||
0xD8, 0xA1, 0x66, 0x62, 0x9F, 0x5B, 0x09, 0x00,
|
0xD8, 0xA1, 0x66, 0x62, 0x9F, 0x5B, 0x09, 0x00,
|
||||||
])
|
])
|
||||||
|
|
||||||
const c = new QmcStaticCipher()
|
const c = new QmcStaticCipher();
|
||||||
const buf = new Uint8Array(16)
|
const buf = new Uint8Array(16);
|
||||||
c.decrypt(buf, 0)
|
c.decrypt(buf, 0);
|
||||||
|
|
||||||
expect(buf).toStrictEqual(expected)
|
expect(buf).toStrictEqual(expected);
|
||||||
})
|
});
|
||||||
|
|
||||||
|
test('map cipher: get mask', () => {
|
||||||
test("map cipher: get mask", () => {
|
//prettier-ignore
|
||||||
const expected = new Uint8Array([
|
const expected = new Uint8Array([
|
||||||
0xBB, 0x7D, 0x80, 0xBE, 0xFF, 0x38, 0x81, 0xFB,
|
0xBB, 0x7D, 0x80, 0xBE, 0xFF, 0x38, 0x81, 0xFB,
|
||||||
0xBB, 0xFF, 0x82, 0x3C, 0xFF, 0xBA, 0x83, 0x79,
|
0xBB, 0xFF, 0x82, 0x3C, 0xFF, 0xBA, 0x83, 0x79,
|
||||||
])
|
])
|
||||||
const key = new Uint8Array(256)
|
const key = new Uint8Array(256);
|
||||||
for (let i = 0; i < 256; i++) key[i] = i
|
for (let i = 0; i < 256; i++) key[i] = i;
|
||||||
const buf = new Uint8Array(16)
|
const buf = new Uint8Array(16);
|
||||||
|
|
||||||
const c = new QmcMapCipher(key)
|
const c = new QmcMapCipher(key);
|
||||||
c.decrypt(buf, 0)
|
c.decrypt(buf, 0);
|
||||||
expect(buf).toStrictEqual(expected)
|
expect(buf).toStrictEqual(expected);
|
||||||
})
|
});
|
||||||
|
|
||||||
function loadTestDataCipher(name: string): {
|
function loadTestDataCipher(name: string): {
|
||||||
key: Uint8Array,
|
key: Uint8Array;
|
||||||
cipherText: Uint8Array,
|
cipherText: Uint8Array;
|
||||||
clearText: Uint8Array
|
clearText: Uint8Array;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
key: fs.readFileSync(`testdata/${name}_key.bin`),
|
key: fs.readFileSync(`testdata/${name}_key.bin`),
|
||||||
cipherText: fs.readFileSync(`testdata/${name}_raw.bin`),
|
cipherText: fs.readFileSync(`testdata/${name}_raw.bin`),
|
||||||
clearText: fs.readFileSync(`testdata/${name}_target.bin`)
|
clearText: fs.readFileSync(`testdata/${name}_target.bin`),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test("map cipher: real file", async () => {
|
test('map cipher: real file', async () => {
|
||||||
const cases = ["mflac_map", "mgg_map"]
|
const cases = ['mflac_map', 'mgg_map'];
|
||||||
for (const name of cases) {
|
for (const name of cases) {
|
||||||
const {key, clearText, cipherText} = loadTestDataCipher(name)
|
const { key, clearText, cipherText } = loadTestDataCipher(name);
|
||||||
const c = new QmcMapCipher(key)
|
const c = new QmcMapCipher(key);
|
||||||
|
|
||||||
c.decrypt(cipherText, 0)
|
c.decrypt(cipherText, 0);
|
||||||
|
|
||||||
expect(cipherText).toStrictEqual(clearText)
|
expect(cipherText).toStrictEqual(clearText);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
test("rc4 cipher: real file", async () => {
|
test('rc4 cipher: real file', async () => {
|
||||||
const cases = ["mflac0_rc4"]
|
const cases = ['mflac0_rc4'];
|
||||||
for (const name of cases) {
|
for (const name of cases) {
|
||||||
const {key, clearText, cipherText} = loadTestDataCipher(name)
|
const { key, clearText, cipherText } = loadTestDataCipher(name);
|
||||||
const c = new QmcRC4Cipher(key)
|
const c = new QmcRC4Cipher(key);
|
||||||
|
|
||||||
c.decrypt(cipherText, 0)
|
c.decrypt(cipherText, 0);
|
||||||
|
|
||||||
expect(cipherText).toStrictEqual(clearText)
|
expect(cipherText).toStrictEqual(clearText);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
test("rc4 cipher: first segment", async () => {
|
test('rc4 cipher: first segment', async () => {
|
||||||
const cases = ["mflac0_rc4"]
|
const cases = ['mflac0_rc4'];
|
||||||
for (const name of cases) {
|
for (const name of cases) {
|
||||||
const {key, clearText, cipherText} = loadTestDataCipher(name)
|
const { key, clearText, cipherText } = loadTestDataCipher(name);
|
||||||
const c = new QmcRC4Cipher(key)
|
const c = new QmcRC4Cipher(key);
|
||||||
|
|
||||||
const buf = cipherText.slice(0, 128)
|
const buf = cipherText.slice(0, 128);
|
||||||
c.decrypt(buf, 0)
|
c.decrypt(buf, 0);
|
||||||
expect(buf).toStrictEqual(clearText.slice(0, 128))
|
expect(buf).toStrictEqual(clearText.slice(0, 128));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
test("rc4 cipher: align block (128~5120)", async () => {
|
test('rc4 cipher: align block (128~5120)', async () => {
|
||||||
const cases = ["mflac0_rc4"]
|
const cases = ['mflac0_rc4'];
|
||||||
for (const name of cases) {
|
for (const name of cases) {
|
||||||
const {key, clearText, cipherText} = loadTestDataCipher(name)
|
const { key, clearText, cipherText } = loadTestDataCipher(name);
|
||||||
const c = new QmcRC4Cipher(key)
|
const c = new QmcRC4Cipher(key);
|
||||||
|
|
||||||
const buf = cipherText.slice(128, 5120)
|
const buf = cipherText.slice(128, 5120);
|
||||||
c.decrypt(buf, 128)
|
c.decrypt(buf, 128);
|
||||||
expect(buf).toStrictEqual(clearText.slice(128, 5120))
|
expect(buf).toStrictEqual(clearText.slice(128, 5120));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
test("rc4 cipher: simple block (5120~10240)", async () => {
|
test('rc4 cipher: simple block (5120~10240)', async () => {
|
||||||
const cases = ["mflac0_rc4"]
|
const cases = ['mflac0_rc4'];
|
||||||
for (const name of cases) {
|
for (const name of cases) {
|
||||||
const {key, clearText, cipherText} = loadTestDataCipher(name)
|
const { key, clearText, cipherText } = loadTestDataCipher(name);
|
||||||
const c = new QmcRC4Cipher(key)
|
const c = new QmcRC4Cipher(key);
|
||||||
|
|
||||||
const buf = cipherText.slice(5120, 10240)
|
const buf = cipherText.slice(5120, 10240);
|
||||||
c.decrypt(buf, 5120)
|
c.decrypt(buf, 5120);
|
||||||
expect(buf).toStrictEqual(clearText.slice(5120, 10240))
|
expect(buf).toStrictEqual(clearText.slice(5120, 10240));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
@ -1,30 +1,26 @@
|
|||||||
import {QmcDeriveKey, simpleMakeKey} from "@/decrypt/qmc_key";
|
import { QmcDeriveKey, simpleMakeKey } from '@/decrypt/qmc_key';
|
||||||
import fs from "fs";
|
import fs from 'fs';
|
||||||
|
|
||||||
test("key dec: make simple key", () => {
|
test('key dec: make simple key', () => {
|
||||||
expect(
|
expect(simpleMakeKey(106, 8)).toStrictEqual([0x69, 0x56, 0x46, 0x38, 0x2b, 0x20, 0x15, 0x0b]);
|
||||||
simpleMakeKey(106, 8)
|
});
|
||||||
).toStrictEqual(
|
|
||||||
[0x69, 0x56, 0x46, 0x38, 0x2b, 0x20, 0x15, 0x0b]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
function loadTestDataKeyDecrypt(name: string): {
|
function loadTestDataKeyDecrypt(name: string): {
|
||||||
cipherText: Uint8Array,
|
cipherText: Uint8Array;
|
||||||
clearText: Uint8Array
|
clearText: Uint8Array;
|
||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
cipherText: fs.readFileSync(`testdata/${name}_key_raw.bin`),
|
cipherText: fs.readFileSync(`testdata/${name}_key_raw.bin`),
|
||||||
clearText: fs.readFileSync(`testdata/${name}_key.bin`)
|
clearText: fs.readFileSync(`testdata/${name}_key.bin`),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
test("key dec: real file", async () => {
|
test('key dec: real file', async () => {
|
||||||
const cases = ["mflac_map", "mgg_map", "mflac0_rc4"]
|
const cases = ['mflac_map', 'mgg_map', 'mflac0_rc4'];
|
||||||
for (const name of cases) {
|
for (const name of cases) {
|
||||||
const {clearText, cipherText} = loadTestDataKeyDecrypt(name)
|
const { clearText, cipherText } = loadTestDataKeyDecrypt(name);
|
||||||
const buf = QmcDeriveKey(cipherText)
|
const buf = QmcDeriveKey(cipherText);
|
||||||
|
|
||||||
expect(buf).toStrictEqual(clearText)
|
expect(buf).toStrictEqual(clearText);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
@ -1,5 +1,2 @@
|
|||||||
const bs = chrome || browser
|
const bs = chrome || browser;
|
||||||
bs.tabs.create({
|
bs.tabs.create({ url: bs.runtime.getURL('./index.html') }, (tab) => console.log(tab));
|
||||||
url: bs.runtime.getURL('./index.html')
|
|
||||||
}, tab => console.log(tab))
|
|
||||||
|
|
||||||
|
@ -1,31 +1,30 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
import {register} from 'register-service-worker'
|
import { register } from 'register-service-worker';
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production' && window.location.protocol === "https:") {
|
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production' && window.location.protocol === 'https:') {
|
||||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||||
ready() {
|
ready() {
|
||||||
console.log('App is being served from cache by a service worker.')
|
console.log('App is being served from cache by a service worker.');
|
||||||
},
|
},
|
||||||
registered() {
|
registered() {
|
||||||
console.log('Service worker has been registered.')
|
console.log('Service worker has been registered.');
|
||||||
},
|
},
|
||||||
cached() {
|
cached() {
|
||||||
console.log('Content has been cached for offline use.')
|
console.log('Content has been cached for offline use.');
|
||||||
},
|
},
|
||||||
updatefound() {
|
updatefound() {
|
||||||
console.log('New content is downloading.')
|
console.log('New content is downloading.');
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
console.log('New content is available.');
|
console.log('New content is available.');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
},
|
},
|
||||||
offline() {
|
offline() {
|
||||||
console.log('No internet connection found. App is running in offline mode.')
|
console.log('No internet connection found. App is running in offline mode.');
|
||||||
},
|
},
|
||||||
error(error) {
|
error(error) {
|
||||||
console.error('Error during service worker registration:', error)
|
console.error('Error during service worker registration:', error);
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
import Vue, {VNode} from 'vue'
|
import Vue, { VNode } from 'vue';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace JSX {
|
namespace JSX {
|
||||||
// tslint:disable no-empty-interface
|
// tslint:disable no-empty-interface
|
||||||
interface Element extends VNode {
|
interface Element extends VNode {}
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable no-empty-interface
|
// tslint:disable no-empty-interface
|
||||||
interface ElementClass extends Vue {
|
interface ElementClass extends Vue {}
|
||||||
}
|
|
||||||
|
|
||||||
interface IntrinsicElements {
|
interface IntrinsicElements {
|
||||||
[elem: string]: any
|
[elem: string]: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import Vue from 'vue'
|
import Vue from 'vue';
|
||||||
export default Vue
|
export default Vue;
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,73 @@
|
|||||||
import {fromByteArray as Base64Encode} from "base64-js";
|
import { fromByteArray as Base64Encode } from 'base64-js';
|
||||||
|
|
||||||
export const IXAREA_API_ENDPOINT = "https://um-api.ixarea.com"
|
export const IXAREA_API_ENDPOINT = 'https://um-api.ixarea.com';
|
||||||
|
|
||||||
export interface UpdateInfo {
|
export interface UpdateInfo {
|
||||||
Found: boolean
|
Found: boolean;
|
||||||
HttpsFound: boolean
|
HttpsFound: boolean;
|
||||||
Version: string
|
Version: string;
|
||||||
URL: string
|
URL: string;
|
||||||
Detail: string
|
Detail: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkUpdate(version: string): Promise<UpdateInfo> {
|
export async function checkUpdate(version: string): Promise<UpdateInfo> {
|
||||||
const resp = await fetch(IXAREA_API_ENDPOINT + "/music/app-version", {
|
const resp = await fetch(IXAREA_API_ENDPOINT + '/music/app-version', {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({"Version": version})
|
body: JSON.stringify({ Version: version }),
|
||||||
});
|
});
|
||||||
return await resp.json();
|
return await resp.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reportKeyUsage(keyData: Uint8Array, maskData: number[], filename: string, format: string, title: string, artist?: string, album?: string) {
|
export function reportKeyUsage(
|
||||||
return fetch(IXAREA_API_ENDPOINT + "/qmcmask/usage", {
|
keyData: Uint8Array,
|
||||||
method: "POST",
|
maskData: number[],
|
||||||
headers: {"Content-Type": "application/json"},
|
filename: string,
|
||||||
|
format: string,
|
||||||
|
title: string,
|
||||||
|
artist?: string,
|
||||||
|
album?: string,
|
||||||
|
) {
|
||||||
|
return fetch(IXAREA_API_ENDPOINT + '/qmcmask/usage', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
Mask: Base64Encode(new Uint8Array(maskData)), Key: Base64Encode(keyData),
|
Mask: Base64Encode(new Uint8Array(maskData)),
|
||||||
Artist: artist, Title: title, Album: album, Filename: filename, Format: format
|
Key: Base64Encode(keyData),
|
||||||
|
Artist: artist,
|
||||||
|
Title: title,
|
||||||
|
Album: album,
|
||||||
|
Filename: filename,
|
||||||
|
Format: format,
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KeyInfo {
|
interface KeyInfo {
|
||||||
Matrix44: string
|
Matrix44: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryKeyInfo(keyData: Uint8Array, filename: string, format: string): Promise<KeyInfo> {
|
export async function queryKeyInfo(keyData: Uint8Array, filename: string, format: string): Promise<KeyInfo> {
|
||||||
const resp = await fetch(IXAREA_API_ENDPOINT + "/qmcmask/query", {
|
const resp = await fetch(IXAREA_API_ENDPOINT + '/qmcmask/query', {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ Format: format, Key: Base64Encode(keyData), Filename: filename, Type: 44 }),
|
body: JSON.stringify({ Format: format, Key: Base64Encode(keyData), Filename: filename, Type: 44 }),
|
||||||
});
|
});
|
||||||
return await resp.json();
|
return await resp.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoverInfo {
|
export interface CoverInfo {
|
||||||
Id: string
|
Id: string;
|
||||||
Type: number
|
Type: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryAlbumCover(title: string, artist?: string, album?: string): Promise<CoverInfo> {
|
export async function queryAlbumCover(title: string, artist?: string, album?: string): Promise<CoverInfo> {
|
||||||
const endpoint = IXAREA_API_ENDPOINT + "/music/qq-cover"
|
const endpoint = IXAREA_API_ENDPOINT + '/music/qq-cover';
|
||||||
const params = new URLSearchParams([["Title", title], ["Artist", artist ?? ""], ["Album", album ?? ""]])
|
const params = new URLSearchParams([
|
||||||
const resp = await fetch(`${endpoint}?${params.toString()}`)
|
['Title', title],
|
||||||
return await resp.json()
|
['Artist', artist ?? ''],
|
||||||
|
['Album', album ?? ''],
|
||||||
|
]);
|
||||||
|
const resp = await fetch(`${endpoint}?${params.toString()}`);
|
||||||
|
return await resp.json();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {expose} from "threads/worker";
|
import { expose } from 'threads/worker';
|
||||||
import {CommonDecrypt} from "@/decrypt/common";
|
import { CommonDecrypt } from '@/decrypt/common';
|
||||||
|
|
||||||
expose(CommonDecrypt)
|
expose(CommonDecrypt);
|
||||||
|
Loading…
Reference in New Issue