Skip to content

Commit

Permalink
VScode: Fix first key extraction + Allow unsecure
Browse files Browse the repository at this point in the history
- To prevent undefined value of extracted cbc key at first run the conf() object is refreshed at every access
- To allow playback behind corporate proxies the 'secure' flag was added
  • Loading branch information
yne committed Jul 4, 2024
1 parent ae929b2 commit f78e15a
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 12 deletions.
22 changes: 11 additions & 11 deletions extension/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
const vscode = require("vscode");
const crypto = require('crypto');
const https = require('https');
const conf = vscode.workspace.getConfiguration("dzr");
const conf = () => vscode.workspace.getConfiguration("dzr");
const location = vscode.ProgressLocation.Notification;
const hhmmss = (s) => (new Date(s * 1000)).toISOString().slice(11, 19).replace(/^00:/, '');
const wait = (ms = 1000) => new Promise(resolve => setTimeout(resolve, ms));
// still no fetch() in 2023 ?
const fetch = (url, opt, data) => new Promise((resolve, reject) => {
const chunks = [], req = https.request(url, opt, res => {
const chunks = [], req = https.request(url, { rejectUnauthorized: conf().get('secure'), ...opt }, res => {
res.on('data', chunk => chunks.push(chunk));
res.on('end', () => resolve(Buffer.concat(chunks)));
}).on('error', reject);
Expand All @@ -27,7 +27,7 @@ async function browse(url_or_event_or_ids, label) {
const ignoreFocusOut = true;
const url = typeof (url_or_event_or_ids) == "string" ? url_or_event_or_ids : '/';
const id = url.replace(/\d+/g, '0').replace(/[^\w]/g, '_');
const menus = conf.get('menus');
const menus = conf().get('menus');
const title = (label || '').replace(/\$\(.+?\)/g, '');
if (url.endsWith('=') || url.endsWith('/0')) { // query step
const input = await vscode.window.showInputBox({ title, ignoreFocusOut });
Expand All @@ -39,11 +39,11 @@ async function browse(url_or_event_or_ids, label) {
return await browse(url + pick.path, pick.label);
} else { // fetch step
const json = JSON.parse(await fetch("https://api.deezer.com" + url)); // todo: json.next?
console.debug(json);
//console.debug(json);
const data = json.data?.tracks || json.data || json.tracks?.data;
const picked = url.match(/\/(playlist|album)\//);
const canPickMany = data.find(item => item.type == "track");
const type2icon = conf.get('type2icon');
const type2icon = conf().get('type2icon');
const choices = data.map(entry => ({
...entry, picked,
label: (type2icon[entry.type] || '') + (entry.title_short || entry.name || entry.title),
Expand Down Expand Up @@ -101,7 +101,7 @@ class DzrWebView { // can't Audio() in VSCode, we need a webview
set: (target, key, value) => {
target[key] = value;
if (['queue', 'looping'].includes(key)) { // persist those values across reboot
conf.update(key, value, vscode.ConfigurationTarget.Global);
conf().update(key, value, vscode.ConfigurationTarget.Global);
}
if (key == 'queue') this._onDidChangeTreeData.fire();
vscode.commands.executeCommand('setContext', `dzr.${key}`, value);
Expand All @@ -113,8 +113,8 @@ class DzrWebView { // can't Audio() in VSCode, we need a webview

constructor() {
this.initAckSemaphore();
this.state.queue = conf.get('queue'); // first is best
this.state.looping = conf.get('looping');
this.state.queue = conf().get('queue'); // first is best
this.state.looping = conf().get('looping');
}
renderStatus() {
const index = this.state.queue?.indexOf(this.state.current);
Expand Down Expand Up @@ -183,7 +183,7 @@ class DzrWebView { // can't Audio() in VSCode, we need a webview
}
exports.activate = async function (/**@type {import('vscode').ExtensionContext}*/ context) {
// deezer didn't DMCA'd dzr so let's follow the same path here
conf.get('cbc') || vscode.window.withProgress({ title: 'Extracting CBC key...', location }, async () => {
conf().get('cbc') || vscode.window.withProgress({ title: 'Extracting CBC key...', location }, async () => {
const html_url = 'https://www.deezer.com/en/channels/explore';
const html = (await fetch(html_url)).toString('utf-8');
const js_url = html.match(/src="(http[^"]+app-web\.[^"]+\.js)"/)?.[1];
Expand All @@ -193,7 +193,7 @@ exports.activate = async function (/**@type {import('vscode').ExtensionContext}*
const cbc = a.map((a, i) => `${a}${b[i]}`).join('');// zip a+b
const sha = crypto.createHash('sha1').update(cbc).digest('hex').slice(0, 8);
if (sha != '3ad58d92') return await vscode.window.showErrorMessage('Bad extracted key');
conf.update('cbc', cbc, vscode.ConfigurationTarget.Global);
conf().update('cbc', cbc, vscode.ConfigurationTarget.Global);
});
const dzr = new DzrWebView();
const htmlUri = vscode.Uri.joinPath(context.extensionUri, 'webview.html');
Expand Down Expand Up @@ -242,7 +242,7 @@ exports.activate = async function (/**@type {import('vscode').ExtensionContext}*
}
const hex = (str) => str.split('').map(c => c.charCodeAt(0))
const md5 = hex(crypto.createHash('md5').update(`${dzr.state.current.id}`).digest('hex'));
const key = Buffer.from(hex(conf.get('cbc')).map((c, i) => c ^ md5[i] ^ md5[i + 16]));
const key = Buffer.from(hex(conf().get('cbc')).map((c, i) => c ^ md5[i] ^ md5[i + 16]));
const iv = Buffer.from([0, 1, 2, 3, 4, 5, 6, 7]);
const stripe = 2048;//TODO:use .pipe() API https://codereview.stackexchange.com/questions/57492/
dzr.post('open', dzr.state.current);
Expand Down
7 changes: 6 additions & 1 deletion extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "dzr",
"displayName": "DZR player",
"description": "deezer.com player",
"version": "0.1.0",
"version": "0.2.0",
"publisher": "yne",
"engines": {
"vscode": "^1.73.0"
Expand Down Expand Up @@ -191,6 +191,11 @@
"default": "",
"description": "track decryption key"
},
"dzr.secure": {
"type": "boolean",
"default": true,
"description": "Disable if you are behind a corporate proxy"
},
"dzr.queue": {
"type": "array",
"default": [],
Expand Down

0 comments on commit f78e15a

Please sign in to comment.