From 4a3f836020b8461c4baaa39d5e0fc24d3e08144f Mon Sep 17 00:00:00 2001 From: Michael Shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 21 Dec 2022 12:20:17 -0800 Subject: [PATCH] Refactor Omada proxy for v4/v5 --- src/widgets/omada/proxy.js | 287 ++++++++++++++++++------------------- 1 file changed, 137 insertions(+), 150 deletions(-) diff --git a/src/widgets/omada/proxy.js b/src/widgets/omada/proxy.js index 582630526..d5f4d9ba2 100644 --- a/src/widgets/omada/proxy.js +++ b/src/widgets/omada/proxy.js @@ -9,40 +9,26 @@ const proxyName = "omadaProxyHandler"; const logger = createLogger(proxyName); -async function login(loginUrl, username, password, cversion) { - let params; - if (cversion < "4.0.0") { - // change the parameters of the query string - params = JSON.stringify({ - "method": "login", - "params": { - "name": username, - "password": password - } - }); - } else { - params = JSON.stringify({ - "username": username, - "password": password - }); +async function login(loginUrl, username, password, controllerVersionMajor) { + const params = { + username: username, + password: password } - const authResponse = await httpProxy(loginUrl, { - method: "POST", - body: params, - headers: { - "Content-Type": "application/json", - }, - }); - const data = JSON.parse(authResponse[2]); - const status = authResponse[0]; - let token; - if (data.errorCode === 0) { - token = data.result.token; - } else { - token = null; + if (controllerVersionMajor < 4) { + params.method = "login"; + params.name = username; } - return [status, token ?? data]; + + const [status, contentType, data] = await httpProxy(loginUrl, { + method: "POST", + body: JSON.stringify(params), + headers: { + "Content-Type": "application/json", + }, + }); + + return [status, JSON.parse(data.toString())]; } @@ -57,108 +43,121 @@ export default async function omadaProxyHandler(req, res) { } if (widget) { - let cid; - let cversion; - let connectedAp; - let activeuser; - let connectedSwitches; - let connectedGateways; - - let alerts; - let loginUrl; - let siteName; - let requestresponse; const {url} = widget; - const controllerInfoUrl = `${widget.url}/api/info`; + const controllerInfoURL = `${widget.url}/api/info`; - const cInfoResponse = await httpProxy(controllerInfoUrl, { - method: "GET", + let [status, contentType, data] = await httpProxy(controllerInfoURL, { headers: { "Content-Type": "application/json", }, }); - - if (cInfoResponse[0] === 500) { - logger.debug("Getting controller version ends with Error 500"); - return res.status(cInfoResponse[0]).json({error: {message: "HTTP Error", controllerInfoUrl, data: cInfoResponse[2]}}); - + if (status !== 200) { + logger.error("Unable to retrieve Omada controller info"); + return res.status(status).json({error: {message: `HTTP Error ${status}`, url: controllerInfoURL, data: data}}); } - const cidresult = cInfoResponse[2]; + + const cId = JSON.parse(data).result.omadacId; + let controllerVersion; try { - cid = JSON.parse(cidresult).result.omadacId; - cversion = JSON.parse(cidresult).result.controllerVer; + controllerVersion = JSON.parse(data).result.controllerVer; } catch (e) { - cversion = "3.2.17" + // fallback to this random version? + controllerVersion = "3.2.17" } - if (cversion < "4.0.0") { - loginUrl = `${widget.url}/api/user/login?ajax`; - } else if (cversion < "5.0.0") { - loginUrl = `${widget.url}/api/v2/login`; - } else { - loginUrl = `${widget.url}/${cid}/api/v2/login`; + + const controllerVersionMajor = parseInt(controllerVersion.split('.')[0], 10) + + if (![3,4,5].includes(controllerVersionMajor)) { + return res.status(500).json({error: {message: "Error determining controller version", data}}); + } + + let loginUrl; + + switch (controllerVersionMajor) { + case 3: + loginUrl = `${widget.url}/api/user/login?ajax`; + break; + case 4: + loginUrl = `${widget.url}/api/v2/login`; + break; + case 5: + loginUrl = `${widget.url}/${cId}/api/v2/login`; + break; + default: + break; } - requestresponse = await login(loginUrl, widget.username, widget.password, cversion); + + const [loginStatus, loginResponseData] = await login(loginUrl, widget.username, widget.password, controllerVersionMajor); - if (requestresponse[1].errorCode) { - return res.status(requestresponse[0]).json({error: {message: "Error logging in", url, data: requestresponse[1]}}); + if (loginStatus !== 200 || loginResponseData.errorCode > 0) { + return res.status(requestresponse[0]).json({error: {message: "Error logging in to Oamda controller", url: loginUrl, data: loginResponseData}}); } - const token = requestresponse[1]; - // Switching to the site we want to gather stats from - // First, we get the list of sites + const token = loginResponseData.result.token; + + // List sites let sitesUrl; - let body; - let params; - let headers; - let method; - let sitetoswitch; - if (cversion < "4.0.0") { - sitesUrl = `${widget.url}/web/v1/controller?ajax=&token=${token}`; - body = JSON.stringify({ - "method": "getUserSites", - "params": { - "userName": widget.username - }}); - params = { "token": token }; - headers = { }; - method = "POST"; - } else if (cversion < "5.0.0") { - sitesUrl = `${widget.url}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; - body = {}; - params = {"token": token}; - headers = {"Csrf-Token": token }; - method = "GET"; - - } else { - sitesUrl = `${widget.url}/${cid}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; - body = {}; - headers = { "Csrf-Token": token }; - method = "GET"; - params = { }; + let body = {}; + let params = { token }; + let headers = { "Csrf-Token": token }; + let method = "GET"; + + switch (controllerVersionMajor) { + case 3: + sitesUrl = `${widget.url}/web/v1/controller?ajax=&token=${token}`; + body = { + "method": "getUserSites", + "params": { + "userName": widget.username + } + }; + method = "POST"; + break; + case 4: + sitesUrl = `${widget.url}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; + break; + case 5: + sitesUrl = `${widget.url}/${cId}/api/v2/sites?token=${token}¤tPage=1¤tPageSize=1000`; + break; } - requestresponse = await httpProxy(sitesUrl, { + + [status, contentType, data] = await httpProxy(sitesUrl, { method, params, - body: body.toString(), + body: JSON.stringify(body), headers, }); - const listresult = JSON.parse(requestresponse[2]); - if (listresult.errorCode !== 0) { - logger.debug(`HTTTP ${requestresponse[0]} getting sites list: ${requestresponse[2].msg}`); - return res.status(requestresponse[0]).json({error: {message: "Error getting sites list", url, data: requestresponse[2]}}); + + const sitesResponseData = JSON.parse(data); + + let site; + + let connectedAp; + let activeUser; + let connectedSwitches; + let connectedGateways; + let alerts; + + if (sitesResponseData.errorCode > 0) { + logger.debug(`HTTTP ${status} getting sites list: ${requestresponse[2].msg}`); + return res.status(status).json({error: {message: "Error getting sites list", url, data: requestresponse[2]}}); } - // Switching site is really needed only for Omada 3.x.x controllers + // on modern controller, we need to call two different endpoints + // on older controller, we can call one endpoint - let switchUrl; + if (controllerVersionMajor === 3) { - if (cversion < "4.0.0") { - sitetoswitch = listresult.result.siteList.filter(site => site.name === widget.site); - siteName = sitetoswitch[0].siteName; + // Switching site is really needed only for Omada 3.x.x controllers + + let switchUrl; + + site = listresult.result.siteList.filter(site => site.name === widget.site); + siteName = site[0].siteName; switchUrl = `${widget.url}/web/v1/controller?ajax=&token=${token}`; method = "POST"; body = JSON.stringify({ @@ -181,12 +180,7 @@ export default async function omadaProxyHandler(req, res) { logger.debug(`HTTTP ${requestresponse[0]} getting sites list: ${requestresponse[2]}`); return res.status(requestresponse[0]).json({error: {message: "Error switching site", url, data: requestresponse[2]}}); } - } - - // OK now we are on the correct site. Let's get the stats - // on modern controller, we need to call two different endpoints - // on older controller, we can call one endpoint - if (cversion < "4.0.0") { + const statsUrl = `${widget.url}/web/v1/controller?getGlobalStat=&token=${token}`; const statResponse = await httpProxy(statsUrl, { method: "POST", @@ -205,68 +199,61 @@ export default async function omadaProxyHandler(req, res) { return res.status(statResponse[0]).json({error: {message: "Error getting stats", url, data: statResponse[2]}}); } connectedAp = data.result.connectedAp; - activeuser = data.result.activeUser; + activeUser = data.result.activeUser; alerts = data.result.alerts; - } else { - let siteStatsUrl; - let response; - sitetoswitch = listresult.result.data.filter(site => site.name === widget.site); + } else if (controllerVersionMajor === 4 || controllerVersionMajor === 5) { + site = sitesResponseData.result.data.find(site => site.name === widget.site); - if (sitetoswitch.length === 0) { - return res.status(requestresponse[0]).json({error: {message: `Site ${widget.site} is not found`, url, data: requestresponse[2]}}); + if (site.length === 0) { + return res.status(requestresponse[0]).json({error: {message: `Site ${widget.site} is not found`, url, data}}); } - // On 5.0.0, the field we need is id, on 4.x.x, it's key ... - siteName = sitetoswitch[0].id ?? sitetoswitch[0].key; - if (cversion < "5.0.0") { - siteStatsUrl = `${url}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000`; - } else { - siteStatsUrl = `${url}/${cid}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000`; - } - response = await httpProxy(siteStatsUrl, { - method: "GET", + const siteName = (controllerVersionMajor === 5) ? site.id : site.key; + const siteStatsUrl = (controllerVersionMajor === 4) ? + `${url}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000` : + `${url}/${cId}/api/v2/sites/${siteName}/dashboard/overviewDiagram?token=${token}¤tPage=1¤tPageSize=1000`; + + [status, contentType, data] = await httpProxy(siteStatsUrl, { headers: { "Csrf-Token": token, }, }); - const clientresult = JSON.parse(response[2]); - if (clientresult.errorCode !== 0) { - logger.debug(`HTTTP ${listresult.errorCode} getting clients stats for site ${widget.site} with message ${listresult.msg}`); - return res.status(500).send(response[2]); + const siteResponseData = JSON.parse(data); + + if (status !== 200 || siteResponseData.errorCode > 0) { + logger.debug(`HTTP ${status} getting stats for site ${widget.site} with message ${listresult.msg}`); + return res.status(500).send(data); } - activeuser = clientresult.result.totalClientNum; - connectedAp = clientresult.result.connectedApNum; - connectedGateways = clientresult.result.connectedGatewayNum; - connectedSwitches = clientresult.result.connectedSwitchNum; + activeUser = siteResponseData.result.totalClientNum; + connectedAp = siteResponseData.result.connectedApNum; + connectedGateways = siteResponseData.result.connectedGatewayNum; + connectedSwitches = siteResponseData.result.connectedSwitchNum; + const alertUrl = (controllerVersionMajor === 4) ? + `${url}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000` : + `${url}/${cId}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000`; - let alertUrl; - if (cversion >= "5.0.0") { - alertUrl = `${url}/${cid}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000`; - } else { - alertUrl = `${url}/api/v2/sites/${siteName}/alerts/num?token=${token}¤tPage=1¤tPageSize=1000`; - } - response = await httpProxy(alertUrl, { - method: "GET", + [status, contentType, data] = await httpProxy(alertUrl, { headers: { "Csrf-Token": token, }, }); - const alertresult = JSON.parse(response[2]); - alerts = alertresult.result.alertNum; + const alertResponseData = JSON.parse(data); + alerts = alertResponseData.result.alertNum; } return res.send(JSON.stringify({ - "connectedAp": connectedAp, - "activeUser": activeuser, - "alerts": alerts, - "connectedGateways": connectedGateways, - "connectedSwitches": connectedSwitches, + connectedAp, + activeUser, + alerts, + connectedGateways, + connectedSwitches, })); } } + return res.status(400).json({ error: "Invalid proxy service type" }); }