From e695d3b574d311ce6a25dd649ec3405c0bf295a2 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Sun, 20 Aug 2023 10:38:08 -0400 Subject: [PATCH] Add custom proxy --- src/utils/proxy/handlers/credentialed.js | 2 - src/widgets/calibreweb/proxy.js | 74 ++++++++++++++++++++++++ src/widgets/calibreweb/widget.js | 12 +--- 3 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 src/widgets/calibreweb/proxy.js diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index ed6d7492..495dc0e4 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -54,8 +54,6 @@ export default async function credentialedProxyHandler(req, res, map) { } else { headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`; } - } else if (widget.type === "calibreweb") { - headers["X-Authenticated-User"] = widget.username; } else { headers["X-API-Key"] = `${widget.key}`; } diff --git a/src/widgets/calibreweb/proxy.js b/src/widgets/calibreweb/proxy.js new file mode 100644 index 00000000..cab5277d --- /dev/null +++ b/src/widgets/calibreweb/proxy.js @@ -0,0 +1,74 @@ +import cache from "memory-cache"; +import { xml2json } from "xml-js"; + +import { formatApiCall } from "utils/proxy/api-helpers"; +import { httpProxy } from "utils/proxy/http"; +import getServiceWidget from "utils/config/service-helpers"; +import createLogger from "utils/logger"; +import widgets from "widgets/widgets"; + +const proxyName = "calibreWebProxyHandler"; +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; + } + + return widget; +} + +async function apiCall(widget, endpoint) { + const apiUrl = new URL(formatApiCall(endpoint, { endpoint, ...widget })); + const headers = { + Authorization: `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}` + }; + + const [status, contentType, data] = await httpProxy(apiUrl, { + withCredentials: true, + credentials: "include", + headers, + }); + + if (status !== 200) { + logger.error("Error getting data from CalibreWeb: %s status %d. Data: %s", apiUrl, status, data); + return { status, contentType, data: null, responseHeaders }; + } + + try { + const dataDecoded = xml2json(data.toString(), { compact: true }); + return {status, data: JSON.parse(dataDecoded), contentType}; + } catch (e) { + logger.error("Error decoding CalibreWeb API data. Data: %s", data.toString()); + return {status, data: null, contentType}; + } +} + +export default async function calibreWebProxyHandler(req, res) { + const widget = await getWidget(req); + + const { service } = req.query; + + if (!widget) { + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + const endpoint = widgets[widget.type].mappings[service].endpoint; + const { status, contentType, data } = await apiCall(widget, endpoint); + + if (status !== 200) { + return res.status(status).json({error: {message: "HTTP error communicating with CalibreWeb API", data: Buffer.from(data).toString()}}); + } + + return res.status(status).json(data); +} diff --git a/src/widgets/calibreweb/widget.js b/src/widgets/calibreweb/widget.js index ba0dafc2..6b9b1efb 100644 --- a/src/widgets/calibreweb/widget.js +++ b/src/widgets/calibreweb/widget.js @@ -1,18 +1,12 @@ -import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; +import calibreWebProxyHandler from "./proxy"; const widget = { api: "{url}/{endpoint}", - proxyHandler: credentialedProxyHandler, + proxyHandler: calibreWebProxyHandler, mappings: { books: { - endpoint: "ajax/listbooks", - }, - authors: { - endpoint: "get_authors_json", - }, - series: { - endpoint: "get_series_json", + endpoint: "opds/books/letter/00", }, }, };