You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
homepage/src/widgets/fritzbox/proxy.js

85 lines
3.2 KiB

import { xml2json } from "xml-js";
import { httpProxy } from "utils/proxy/http";
import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
const logger = createLogger("fritzboxProxyHandler");
async function requestEndpoint(apiBaseUrl, service, action) {
const servicePath = service === "WANIPConnection" ? "WANIPConn1" : "WANCommonIFC1";
const params = {
method: "POST",
headers: {
"Content-Type": "text/xml; charset='utf-8'",
SoapAction: `urn:schemas-upnp-org:service:${service}:1#${action}`,
},
body:
"<?xml version='1.0' encoding='utf-8'?>" +
"<s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>" +
"<s:Body>" +
`<u:${action} xmlns:u='urn:schemas-upnp-org:service:${service}:1' />` +
"</s:Body>" +
"</s:Envelope>",
};
const apiUrl = `${apiBaseUrl}/igdupnp/control/${servicePath}`;
const [status, , data] = await httpProxy(apiUrl, params);
if (status !== 200) {
logger.debug(`HTTP ${status} performing SoapRequest for ${service}->${action}`, data);
throw new Error(`Failed fetching '${action}'`);
}
const response = {};
try {
const jsonData = JSON.parse(xml2json(data));
const responseElements = jsonData?.elements[0]?.elements[0]?.elements[0]?.elements || [];
responseElements.forEach((element) => {
response[element.name] = element.elements[0]?.text || "";
});
} catch (e) {
logger.debug(`Failed parsing ${service}->${action} response:`, data);
throw new Error(`Failed parsing '${action}' response`);
}
return response;
}
export default async function fritzboxProxyHandler(req, res) {
const { group, service } = req.query;
const serviceWidget = await getServiceWidget(group, service);
if (!serviceWidget) {
res.status(500).json({ error: "Service widget not found" });
return;
}
if (!serviceWidget.url) {
res.status(500).json({ error: "Service widget url not configured" });
return;
}
const serviceWidgetUrl = new URL(serviceWidget.url);
const port = serviceWidgetUrl.protocol === "https:" ? 49443 : 49000;
const apiBaseUrl = `${serviceWidgetUrl.protocol}//${serviceWidgetUrl.hostname}:${port}`;
await Promise.all([
requestEndpoint(apiBaseUrl, "WANIPConnection", "GetStatusInfo"),
requestEndpoint(apiBaseUrl, "WANIPConnection", "GetExternalIPAddress"),
requestEndpoint(apiBaseUrl, "WANCommonInterfaceConfig", "GetCommonLinkProperties"),
requestEndpoint(apiBaseUrl, "WANCommonInterfaceConfig", "GetAddonInfos"),
])
.then(([statusInfo, externalIPAddress, linkProperties, addonInfos]) => {
res.status(200).json({
connectionStatus: statusInfo.NewConnectionStatus,
uptime: statusInfo.NewUptime,
maxDown: linkProperties.NewLayer1DownstreamMaxBitRate,
maxUp: linkProperties.NewLayer1UpstreamMaxBitRate,
down: addonInfos.NewByteReceiveRate,
up: addonInfos.NewByteSendRate,
received: addonInfos.NewX_AVM_DE_TotalBytesReceived64,
sent: addonInfos.NewX_AVM_DE_TotalBytesSent64,
externalIPAddress: externalIPAddress.NewExternalIPAddress,
});
})
.catch((error) => {
res.status(500).json({ error: error.message });
});
}