Run pre-commit hooks over existing codebase

Co-Authored-By: Ben Phelps <ben@phelps.io>
This commit is contained in:
shamoon
2023-10-17 23:26:55 -07:00
parent fa50bbad9c
commit 19c25713c4
387 changed files with 4785 additions and 4109 deletions

View File

@@ -5,35 +5,38 @@ import Container from "components/services/widget/container";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const { t } = useTranslation();
const { widget } = service;
const { widget } = service;
const { data: jdownloaderData, error: jdownloaderAPIError } = useWidgetAPI(widget, "unified", {
refreshInterval: 30000,
});
const { data: jdownloaderData, error: jdownloaderAPIError } = useWidgetAPI(widget, "unified", {
refreshInterval: 30000,
});
if (jdownloaderAPIError) {
return <Container service={service} error={jdownloaderAPIError} />;
}
if (!jdownloaderData) {
return (
<Container service={service}>
<Block label="jdownloader.downloadCount" />
<Block label="jdownloader.downloadTotalBytes" />
<Block label="jdownloader.downloadBytesRemaining" />
<Block label="jdownloader.downloadSpeed" />
</Container>
);
}
if (jdownloaderAPIError) {
return <Container service={service} error={jdownloaderAPIError} />;
}
if (!jdownloaderData) {
return (
<Container service={service}>
<Block label="jdownloader.downloadCount" value={t("common.number", { value: jdownloaderData.downloadCount })} />
<Block label="jdownloader.downloadTotalBytes" value={t("common.bytes", { value: jdownloaderData.totalBytes })} />
<Block label="jdownloader.downloadBytesRemaining" value={t("common.bytes", { value: jdownloaderData.bytesRemaining })} />
<Block label="jdownloader.downloadSpeed" value={t("common.byterate", { value: jdownloaderData.totalSpeed })} />
</Container>
<Container service={service}>
<Block label="jdownloader.downloadCount" />
<Block label="jdownloader.downloadTotalBytes" />
<Block label="jdownloader.downloadBytesRemaining" />
<Block label="jdownloader.downloadSpeed" />
</Container>
);
}
}
return (
<Container service={service}>
<Block label="jdownloader.downloadCount" value={t("common.number", { value: jdownloaderData.downloadCount })} />
<Block label="jdownloader.downloadTotalBytes" value={t("common.bytes", { value: jdownloaderData.totalBytes })} />
<Block
label="jdownloader.downloadBytesRemaining"
value={t("common.bytes", { value: jdownloaderData.bytesRemaining })}
/>
<Block label="jdownloader.downloadSpeed" value={t("common.byterate", { value: jdownloaderData.totalSpeed })} />
</Container>
);
}

View File

@@ -1,8 +1,8 @@
/* eslint-disable no-underscore-dangle */
import crypto from 'crypto';
import querystring from 'querystring';
import crypto from "crypto";
import querystring from "querystring";
import { sha256, uniqueRid, validateRid, createEncryptionToken, decrypt, encrypt } from "./tools"
import { sha256, uniqueRid, validateRid, createEncryptionToken, decrypt, encrypt } from "./tools";
import getServiceWidget from "utils/config/service-helpers";
import { httpProxy } from "utils/proxy/http";
@@ -12,183 +12,173 @@ const proxyName = "jdownloaderProxyHandler";
const logger = createLogger(proxyName);
async function getWidget(req) {
const { group, service } = req.query;
if (!group || !service) {
logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
return null;
}
const widget = await getServiceWidget(group, service);
if (!widget) {
logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
return null;
}
const { group, service } = req.query;
if (!group || !service) {
logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
return null;
}
const widget = await getServiceWidget(group, service);
if (!widget) {
logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
return null;
}
return widget;
return widget;
}
async function login(loginSecret, deviceSecret, params) {
const rid = uniqueRid();
const path = `/my/connect?${querystring.stringify({ ...params, rid })}`;
const rid = uniqueRid();
const path = `/my/connect?${querystring.stringify({ ...params, rid })}`;
const signature = crypto
.createHmac('sha256', loginSecret)
.update(path)
.digest('hex');
const url = `${new URL(`https://api.jdownloader.org${path}&signature=${signature}`)}`
const signature = crypto.createHmac("sha256", loginSecret).update(path).digest("hex");
const url = `${new URL(`https://api.jdownloader.org${path}&signature=${signature}`)}`;
const [status, contentType, data] = await httpProxy(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const [status, contentType, data] = await httpProxy(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
if (status !== 200) {
logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString());
return [status, data];
}
if (status !== 200) {
logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString());
return [status, data];
}
try {
const decryptedData = JSON.parse(decrypt(data.toString(), loginSecret))
const sessionToken = decryptedData.sessiontoken;
validateRid(decryptedData, rid);
const serverEncryptionToken = createEncryptionToken(loginSecret, sessionToken);
const deviceEncryptionToken = createEncryptionToken(deviceSecret, sessionToken);
return [status, decryptedData, contentType, serverEncryptionToken, deviceEncryptionToken, sessionToken];
} catch (e) {
logger.error("Error decoding jdownloader API data. Data: %s", data.toString());
return [status, null];
}
try {
const decryptedData = JSON.parse(decrypt(data.toString(), loginSecret));
const sessionToken = decryptedData.sessiontoken;
validateRid(decryptedData, rid);
const serverEncryptionToken = createEncryptionToken(loginSecret, sessionToken);
const deviceEncryptionToken = createEncryptionToken(deviceSecret, sessionToken);
return [status, decryptedData, contentType, serverEncryptionToken, deviceEncryptionToken, sessionToken];
} catch (e) {
logger.error("Error decoding jdownloader API data. Data: %s", data.toString());
return [status, null];
}
}
async function getDevice(serverEncryptionToken, deviceName, params) {
const rid = uniqueRid();
const path = `/my/listdevices?${querystring.stringify({ ...params, rid })}`;
const signature = crypto
.createHmac('sha256', serverEncryptionToken)
.update(path)
.digest('hex');
const url = `${new URL(`https://api.jdownloader.org${path}&signature=${signature}`)}`
const rid = uniqueRid();
const path = `/my/listdevices?${querystring.stringify({ ...params, rid })}`;
const signature = crypto.createHmac("sha256", serverEncryptionToken).update(path).digest("hex");
const url = `${new URL(`https://api.jdownloader.org${path}&signature=${signature}`)}`;
const [status, , data] = await httpProxy(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
});
const [status, , data] = await httpProxy(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
if (status !== 200) {
logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString());
return [status, data];
}
try {
const decryptedData = JSON.parse(decrypt(data.toString(), serverEncryptionToken))
const filteredDevice = decryptedData.list.filter(device => device.name === deviceName);
return [status, filteredDevice[0].id];
} catch (e) {
logger.error("Error decoding jdownloader API data. Data: %s", data.toString());
return [status, null];
}
if (status !== 200) {
logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString());
return [status, data];
}
try {
const decryptedData = JSON.parse(decrypt(data.toString(), serverEncryptionToken));
const filteredDevice = decryptedData.list.filter((device) => device.name === deviceName);
return [status, filteredDevice[0].id];
} catch (e) {
logger.error("Error decoding jdownloader API data. Data: %s", data.toString());
return [status, null];
}
}
function createBody(rid, query, params) {
const baseBody = {
apiVer: 1,
rid,
url: query
};
return params ? { ...baseBody, params: [JSON.stringify(params)] } : baseBody;
const baseBody = {
apiVer: 1,
rid,
url: query,
};
return params ? { ...baseBody, params: [JSON.stringify(params)] } : baseBody;
}
async function queryPackages(deviceEncryptionToken, deviceId, sessionToken, params) {
const rid = uniqueRid();
const body = encrypt(JSON.stringify(createBody(rid, '/downloadsV2/queryPackages', params)), deviceEncryptionToken);
const url = `${new URL(`https://api.jdownloader.org/t_${encodeURI(sessionToken)}_${encodeURI(deviceId)}/downloadsV2/queryPackages`)}`
const [status, , data] = await httpProxy(url, {
method: 'POST',
body,
});
const rid = uniqueRid();
const body = encrypt(JSON.stringify(createBody(rid, "/downloadsV2/queryPackages", params)), deviceEncryptionToken);
const url = `${new URL(
`https://api.jdownloader.org/t_${encodeURI(sessionToken)}_${encodeURI(deviceId)}/downloadsV2/queryPackages`,
)}`;
const [status, , data] = await httpProxy(url, {
method: "POST",
body,
});
if (status !== 200) {
logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString());
return [status, data];
}
try {
const decryptedData = JSON.parse(decrypt(data.toString(), deviceEncryptionToken))
return decryptedData.data;
} catch (e) {
logger.error("Error decoding JDRss jdownloader data. Data: %s", data.toString());
return [status, null];
}
if (status !== 200) {
logger.error("HTTP %d communicating with jdownloader. Data: %s", status, data.toString());
return [status, data];
}
try {
const decryptedData = JSON.parse(decrypt(data.toString(), deviceEncryptionToken));
return decryptedData.data;
} catch (e) {
logger.error("Error decoding JDRss jdownloader data. Data: %s", data.toString());
return [status, null];
}
}
export default async function jdownloaderProxyHandler(req, res) {
const widget = await getWidget(req);
const widget = await getWidget(req);
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
}
logger.debug("Getting data from JDRss API");
const { username } = widget;
const { password } = widget;
const appKey = "homepage";
const loginSecret = sha256(`${username}${password}server`);
const deviceSecret = sha256(`${username}${password}device`);
const email = username;
const loginData = await login(loginSecret, deviceSecret, {
appKey,
email,
});
const deviceData = await getDevice(loginData[3], widget.client, {
sessiontoken: loginData[5],
});
const packageStatus = await queryPackages(loginData[4], deviceData[1], loginData[5], {
bytesLoaded: true,
bytesTotal: true,
comment: false,
enabled: true,
eta: false,
priority: false,
finished: true,
running: true,
speed: true,
status: true,
childCount: false,
hosts: false,
saveTo: false,
maxResults: -1,
startAt: 0,
});
let totalLoaded = 0;
let totalBytes = 0;
let totalSpeed = 0;
packageStatus.forEach((file) => {
totalBytes += file.bytesTotal;
totalLoaded += file.bytesLoaded;
if (file.finished !== true && file.speed) {
totalSpeed += file.speed;
}
logger.debug("Getting data from JDRss API");
const { username } = widget
const { password } = widget
});
const appKey = "homepage"
const loginSecret = sha256(`${username}${password}server`)
const deviceSecret = sha256(`${username}${password}device`)
const email = username;
const loginData = await login(loginSecret, deviceSecret, {
appKey,
email
})
const deviceData = await getDevice(loginData[3], widget.client, {
sessiontoken: loginData[5]
})
const packageStatus = await queryPackages(loginData[4], deviceData[1], loginData[5], {
"bytesLoaded": true,
"bytesTotal": true,
"comment": false,
"enabled": true,
"eta": false,
"priority": false,
"finished": true,
"running": true,
"speed": true,
"status": true,
"childCount": false,
"hosts": false,
"saveTo": false,
"maxResults": -1,
"startAt": 0,
}
)
let totalLoaded = 0;
let totalBytes = 0;
let totalSpeed = 0;
packageStatus.forEach(file => {
totalBytes += file.bytesTotal;
totalLoaded += file.bytesLoaded;
if (file.finished !== true && file.speed) {
totalSpeed += file.speed;
}
});
const data = {
downloadCount: packageStatus.length,
bytesRemaining: totalBytes - totalLoaded,
totalBytes,
totalSpeed
};
return res.send(data);
const data = {
downloadCount: packageStatus.length,
bytesRemaining: totalBytes - totalLoaded,
totalBytes,
totalSpeed,
};
return res.send(data);
}

View File

@@ -1,55 +1,48 @@
import crypto from 'crypto';
import crypto from "crypto";
export function sha256(data) {
return crypto
.createHash('sha256')
.update(data)
.digest();
return crypto.createHash("sha256").update(data).digest();
}
export function uniqueRid() {
return Math.floor(Math.random() * 10e12);
return Math.floor(Math.random() * 10e12);
}
export function validateRid(decryptedData, rid) {
if (decryptedData.rid !== rid) {
throw new Error('RequestID mismatch');
}
return decryptedData;
if (decryptedData.rid !== rid) {
throw new Error("RequestID mismatch");
}
return decryptedData;
}
export function decrypt(data, ivKey) {
const iv = ivKey.slice(0, ivKey.length / 2);
const key = ivKey.slice(ivKey.length / 2, ivKey.length);
const cipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
return Buffer.concat([
cipher.update(data, 'base64'),
cipher.final()
]).toString();
const iv = ivKey.slice(0, ivKey.length / 2);
const key = ivKey.slice(ivKey.length / 2, ivKey.length);
const cipher = crypto.createDecipheriv("aes-128-cbc", key, iv);
return Buffer.concat([cipher.update(data, "base64"), cipher.final()]).toString();
}
export function createEncryptionToken(oldTokenBuff, updateToken) {
const updateTokenBuff = Buffer.from(updateToken, 'hex');
const mergedBuffer = Buffer.concat([oldTokenBuff, updateTokenBuff], oldTokenBuff.length + updateTokenBuff.length);
return sha256(mergedBuffer);
const updateTokenBuff = Buffer.from(updateToken, "hex");
const mergedBuffer = Buffer.concat([oldTokenBuff, updateTokenBuff], oldTokenBuff.length + updateTokenBuff.length);
return sha256(mergedBuffer);
}
export function encrypt(data, ivKey) {
if (typeof data !== 'string') {
throw new Error('data no es un string');
}
if (!(ivKey instanceof Buffer)) {
throw new Error('ivKey no es un buffer');
}
if (ivKey.length !== 32) {
throw new Error('ivKey tiene que tener tamaño 32');
}
const stringIVKey = ivKey.toString('hex');
const stringIV = stringIVKey.substring(0, stringIVKey.length / 2);
const stringKey = stringIVKey.substring(stringIVKey.length / 2, stringIVKey.length);
const iv = Buffer.from(stringIV, 'hex');
const key = Buffer.from(stringKey, 'hex');
const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
return cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
}
if (typeof data !== "string") {
throw new Error("data no es un string");
}
if (!(ivKey instanceof Buffer)) {
throw new Error("ivKey no es un buffer");
}
if (ivKey.length !== 32) {
throw new Error("ivKey tiene que tener tamaño 32");
}
const stringIVKey = ivKey.toString("hex");
const stringIV = stringIVKey.substring(0, stringIVKey.length / 2);
const stringKey = stringIVKey.substring(stringIVKey.length / 2, stringIVKey.length);
const iv = Buffer.from(stringIV, "hex");
const key = Buffer.from(stringKey, "hex");
const cipher = crypto.createCipheriv("aes-128-cbc", key, iv);
return cipher.update(data, "utf8", "base64") + cipher.final("base64");
}

View File

@@ -1,15 +1,15 @@
import jdownloaderProxyHandler from "./proxy";
const widget = {
api: "https://api.jdownloader.org/{endpoint}/&signature={signature}",
proxyHandler: jdownloaderProxyHandler,
api: "https://api.jdownloader.org/{endpoint}/&signature={signature}",
proxyHandler: jdownloaderProxyHandler,
mappings: {
unified: {
endpoint: "/",
signature: "",
},
mappings: {
unified: {
endpoint: "/",
signature: "",
},
},
};
export default widget;
export default widget;