Enhancement: support new unifi network api and api key (#4860)

This commit is contained in:
shamoon 2025-03-01 11:25:34 -08:00 committed by GitHub
parent 7f910814f8
commit a8961c3345
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 23 additions and 17 deletions

View File

@ -22,9 +22,8 @@ An optional 'site' parameter can be supplied, if it is not the widget will use t
```yaml
- unifi_console:
url: https://unifi.host.or.ip:port
site: Site Name # optional
username: user
password: pass
site: Site Name # optional
key: unifiapikey # required if using API key instead of username/password
```
_Added in v0.4.18, updated in 0.6.7_

View File

@ -25,9 +25,8 @@ Allowed fields: `["uptime", "wan", "lan", "lan_users", "lan_devices", "wlan", "w
widget:
type: unifi
url: https://unifi.host.or.ip:port
username: username
password: password
site: Site Name # optional
username: user
password: pass
key: unifiapikey # required if using API key instead of username/password
```
_Added in v0.4.18, updated in 0.6.7_

View File

@ -38,7 +38,7 @@ export async function cleanWidgetGroups(widgets) {
}
});
// delete url from the sanitized options if the widget is not a search or glances widgeth
// delete url from the sanitized options if the widget is not a search or glances widget
if (widget.type !== "search" && widget.type !== "glances" && optionKeys.includes("url")) {
delete sanitizedOptions.url;
}

View File

@ -47,7 +47,7 @@ async function login(widget, csrfToken) {
const endpoint = widget.prefix === udmpPrefix ? "auth/login" : "login";
const api = widgets?.[widget.type]?.api?.replace("{prefix}", ""); // no prefix for login url
const loginUrl = new URL(formatApiCall(api, { endpoint, ...widget }));
const loginBody = { username: widget.username, password: widget.password, remember: true };
const loginBody = { username: widget.username, password: widget.password, remember: true, rememberMe: true };
const headers = { "Content-Type": "application/json" };
if (csrfToken) {
headers["X-CSRF-TOKEN"] = csrfToken;
@ -75,31 +75,39 @@ export default async function unifiProxyHandler(req, res) {
let [status, contentType, data, responseHeaders] = [];
let prefix = cache.get(`${prefixCacheKey}.${service}`);
let csrfToken;
if (prefix === null) {
// auto detect if we're talking to a UDM Pro, and cache the result so that we
// don't make two requests each time data from Unifi is required
const headers = {};
if (widget.key) {
prefix = udmpPrefix;
headers["X-API-KEY"] = widget.key;
headers["Accept"] = "application/json";
} else if (prefix === null) {
// auto detect if we're talking to a UDM Pro or Network API device, and cache the result
// so that we don't make two requests each time data from Unifi is required
[status, contentType, data, responseHeaders] = await httpProxy(widget.url);
prefix = "";
if (responseHeaders?.["x-csrf-token"]) {
// Unifi OS < 3.2.5 passes & requires csrf-token
prefix = udmpPrefix;
csrfToken = responseHeaders["x-csrf-token"];
} else if (responseHeaders?.["access-control-expose-headers"]) {
// Unifi OS ≥ 3.2.5 doesnt pass csrf token but still uses different endpoint
} else if (
responseHeaders?.["access-control-expose-headers"] ||
responseHeaders?.["Access-Control-Expose-Headers"]
) {
// Unifi OS ≥ 3.2.5 doesnt pass csrf token but still uses different endpoint, same with Network API
prefix = udmpPrefix;
}
cache.put(`${prefixCacheKey}.${service}`, prefix);
}
cache.put(`${prefixCacheKey}.${service}`, prefix);
widget.prefix = prefix;
const { endpoint } = req.query;
const url = new URL(formatApiCall(api, { endpoint, ...widget }));
const params = { method: "GET", headers: {} };
const params = { method: "GET", headers };
setCookieHeader(url, params);
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
if (status === 401) {
if (status === 401 && !widget.key) {
logger.debug("Unifi isn't logged in or rejected the reqeust, attempting login.");
if (responseHeaders?.["x-csrf-token"]) {
csrfToken = responseHeaders["x-csrf-token"];