Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84c61af74d | ||
|
|
e6f2ff970b | ||
|
|
af1695687a | ||
|
|
f0d7cf3ce6 | ||
|
|
36e77e1fe3 | ||
|
|
35dd7ec230 | ||
|
|
15cc1d98c5 | ||
|
|
9803ef70c6 | ||
|
|
ccc27142ef | ||
|
|
9a20982406 | ||
|
|
67a69a5878 |
No files matched your search
@@ -66,6 +66,10 @@ Homepage is highly customizable, with support for custom themes, custom CSS & JS
|
|||||||
|
|
||||||
For configuration options, examples and more, [please check out the homepage documentation](http://gethomepage.dev).
|
For configuration options, examples and more, [please check out the homepage documentation](http://gethomepage.dev).
|
||||||
|
|
||||||
|
## Security Notice 🔒
|
||||||
|
|
||||||
|
Please note that when using features such as widgets, Homepage can access personal information (for example from your home automation system) and Homepage currently does not (and is not planned to) include any authentication layer itself. Thus, we recommend homepage be deployed behind a reverse proxy including authentication, SSL etc, and / or behind a VPN.
|
||||||
|
|
||||||
## With Docker
|
## With Docker
|
||||||
|
|
||||||
Using docker compose:
|
Using docker compose:
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ When the Kubernetes cluster connection has been properly configured, this servic
|
|||||||
|
|
||||||
If you are using multiple instances of homepage, an `instance` annotation can be specified to limit services to a specific instance. If no instance is provided, the service will be visible on all instances.
|
If you are using multiple instances of homepage, an `instance` annotation can be specified to limit services to a specific instance. If no instance is provided, the service will be visible on all instances.
|
||||||
|
|
||||||
|
If you have a single service that needs to be shown on multiple specific instances of homepage (but not on all of them), the service can be annotated by multiple `instance.name` annotations, where `name` can be the names of your specific multiple homepage instances. For example, a service that is annotated with `gethomepage.dev/instance.public: ""` and `gethomepage.dev/instance.internal: ""` will be shown on `public` and `internal` homepage instances.
|
||||||
|
|
||||||
### Traefik IngressRoute support
|
### Traefik IngressRoute support
|
||||||
|
|
||||||
Homepage can also read ingresses defined using the Traefik IngressRoute custom resource definition. Due to the complex nature of Traefik routing rules, it is required for the `gethomepage.dev/href` annotation to be set:
|
Homepage can also read ingresses defined using the Traefik IngressRoute custom resource definition. Due to the complex nature of Traefik routing rules, it is required for the `gethomepage.dev/href` annotation to be set:
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ quicklaunch:
|
|||||||
suggestionUrl: https://ac.ecosia.org/autocomplete?type=list&q=
|
suggestionUrl: https://ac.ecosia.org/autocomplete?type=list&q=
|
||||||
```
|
```
|
||||||
|
|
||||||
## Homepage Version
|
## Homepage Version & Update Checking
|
||||||
|
|
||||||
By default the release version is displayed at the bottom of the page. To hide this, use the `hideVersion` setting, like so:
|
By default the release version is displayed at the bottom of the page. To hide this, use the `hideVersion` setting, like so:
|
||||||
|
|
||||||
@@ -410,6 +410,12 @@ By default the release version is displayed at the bottom of the page. To hide t
|
|||||||
hideVersion: true
|
hideVersion: true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can disable checking for new versions from GitHub (enabled by default) with:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
disableUpdateCheck: true
|
||||||
|
```
|
||||||
|
|
||||||
## Log Path
|
## Log Path
|
||||||
|
|
||||||
By default the homepage logfile is written to the a `logs` subdirectory of the `config` folder. In order to customize this path, you can set the `logpath` setting. A `logs` folder will be created in that location where the logfile will be written.
|
By default the homepage logfile is written to the a `logs` subdirectory of the `config` folder. In order to customize this path, you can set the `logpath` setting. A `logs` folder will be created in that location where the logfile will be written.
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ description: Docs intro
|
|||||||
You have a few options for deploying homepage, depending on your needs. We offer docker images for a majority of platforms. You can also install and run homepage from source if Docker is not your thing. It can even be installed on Kubernetes with Helm.
|
You have a few options for deploying homepage, depending on your needs. We offer docker images for a majority of platforms. You can also install and run homepage from source if Docker is not your thing. It can even be installed on Kubernetes with Helm.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
!!! danger
|
||||||
|
|
||||||
|
Please note that when using features such as widgets, Homepage can access personal information (for example from your home automation system) and Homepage currently does not (and is not planned to) include any authentication layer itself. Thus, we recommend homepage be deployed behind a reverse proxy including authentication, SSL etc, and / or behind a VPN.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div class="grid cards" style="margin: 0 auto;" markdown>
|
<div class="grid cards" style="margin: 0 auto;" markdown>
|
||||||
|
|||||||
@@ -140,7 +140,7 @@
|
|||||||
"connectionStatusPendingDisconnect": "Desconexión pendiente",
|
"connectionStatusPendingDisconnect": "Desconexión pendiente",
|
||||||
"connectionStatusDisconnecting": "Desconectando",
|
"connectionStatusDisconnecting": "Desconectando",
|
||||||
"connectionStatusDisconnected": "Desconectado",
|
"connectionStatusDisconnected": "Desconectado",
|
||||||
"connectionStatusConnected": "Connected",
|
"connectionStatusConnected": "Conectado",
|
||||||
"uptime": "Tiempo activo",
|
"uptime": "Tiempo activo",
|
||||||
"maxDown": "Descarga máxima",
|
"maxDown": "Descarga máxima",
|
||||||
"maxUp": "Subida máxima",
|
"maxUp": "Subida máxima",
|
||||||
@@ -279,9 +279,9 @@
|
|||||||
},
|
},
|
||||||
"netalertx": {
|
"netalertx": {
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"connected": "Connected",
|
"connected": "Conectado",
|
||||||
"new_devices": "New Devices",
|
"new_devices": "Nuevos dispositivos",
|
||||||
"down_alerts": "Down Alerts"
|
"down_alerts": "Alertas de caída"
|
||||||
},
|
},
|
||||||
"pihole": {
|
"pihole": {
|
||||||
"queries": "Consultas",
|
"queries": "Consultas",
|
||||||
@@ -544,7 +544,7 @@
|
|||||||
"hdhomerun": {
|
"hdhomerun": {
|
||||||
"channels": "Canales",
|
"channels": "Canales",
|
||||||
"hd": "Alta definición",
|
"hd": "Alta definición",
|
||||||
"tunerCount": "Tuners",
|
"tunerCount": "Sintonizadores",
|
||||||
"channelNumber": "Canal",
|
"channelNumber": "Canal",
|
||||||
"channelNetwork": "Red",
|
"channelNetwork": "Red",
|
||||||
"signalStrength": "Intensidad",
|
"signalStrength": "Intensidad",
|
||||||
@@ -827,7 +827,7 @@
|
|||||||
},
|
},
|
||||||
"romm": {
|
"romm": {
|
||||||
"platforms": "Plataformas",
|
"platforms": "Plataformas",
|
||||||
"totalRoms": "Total ROMs"
|
"totalRoms": "ROMs totales"
|
||||||
},
|
},
|
||||||
"netdata": {
|
"netdata": {
|
||||||
"warnings": "Advertencias",
|
"warnings": "Advertencias",
|
||||||
@@ -835,38 +835,38 @@
|
|||||||
},
|
},
|
||||||
"plantit": {
|
"plantit": {
|
||||||
"events": "Eventos",
|
"events": "Eventos",
|
||||||
"plants": "Plants",
|
"plants": "Plantas",
|
||||||
"photos": "Fotos",
|
"photos": "Fotos",
|
||||||
"species": "Species"
|
"species": "Especies"
|
||||||
},
|
},
|
||||||
"gitea": {
|
"gitea": {
|
||||||
"notifications": "Notificaciones",
|
"notifications": "Notificaciones",
|
||||||
"issues": "Números",
|
"issues": "Números",
|
||||||
"pulls": "Pull Requests"
|
"pulls": "Solicitudes de cambios"
|
||||||
},
|
},
|
||||||
"stash": {
|
"stash": {
|
||||||
"scenes": "Scenes",
|
"scenes": "Escenas",
|
||||||
"scenesPlayed": "Scenes Played",
|
"scenesPlayed": "Escenas reproducidas",
|
||||||
"playCount": "Total Plays",
|
"playCount": "Reproducciones totales",
|
||||||
"playDuration": "Time Watched",
|
"playDuration": "Tiempo visto",
|
||||||
"sceneSize": "Scenes Size",
|
"sceneSize": "Tamaño de las escenas",
|
||||||
"sceneDuration": "Scenes Duration",
|
"sceneDuration": "Duración de las escenas",
|
||||||
"images": "Imágenes",
|
"images": "Imágenes",
|
||||||
"imageSize": "Tamaño de imagen",
|
"imageSize": "Tamaño de imagen",
|
||||||
"galleries": "Galerías",
|
"galleries": "Galerías",
|
||||||
"performers": "Performers",
|
"performers": "Intérpretes",
|
||||||
"studios": "Studios",
|
"studios": "Estudios",
|
||||||
"movies": "Películas",
|
"movies": "Películas",
|
||||||
"tags": "Etiquetas",
|
"tags": "Etiquetas",
|
||||||
"oCount": "O Count"
|
"oCount": "O cuenta"
|
||||||
},
|
},
|
||||||
"tandoor": {
|
"tandoor": {
|
||||||
"users": "Usuarios",
|
"users": "Usuarios",
|
||||||
"recipes": "Recetas",
|
"recipes": "Recetas",
|
||||||
"keywords": "Keywords"
|
"keywords": "Palabras clave"
|
||||||
},
|
},
|
||||||
"homebox": {
|
"homebox": {
|
||||||
"items": "Items",
|
"items": "Objetos",
|
||||||
"totalWithWarranty": "Con Garantía",
|
"totalWithWarranty": "Con Garantía",
|
||||||
"locations": "Ubicaciones",
|
"locations": "Ubicaciones",
|
||||||
"labels": "Etiquetas",
|
"labels": "Etiquetas",
|
||||||
@@ -875,10 +875,10 @@
|
|||||||
},
|
},
|
||||||
"crowdsec": {
|
"crowdsec": {
|
||||||
"alerts": "Alertas",
|
"alerts": "Alertas",
|
||||||
"bans": "Bans"
|
"bans": "Baneos"
|
||||||
},
|
},
|
||||||
"wgeasy": {
|
"wgeasy": {
|
||||||
"connected": "Connected",
|
"connected": "Conectado",
|
||||||
"enabled": "Activado",
|
"enabled": "Activado",
|
||||||
"disabled": "Desactivado",
|
"disabled": "Desactivado",
|
||||||
"total": "Total"
|
"total": "Total"
|
||||||
|
|||||||
@@ -884,9 +884,9 @@
|
|||||||
"total": "Total"
|
"total": "Total"
|
||||||
},
|
},
|
||||||
"swagdashboard": {
|
"swagdashboard": {
|
||||||
"proxied": "Proxied",
|
"proxied": "Par proxy",
|
||||||
"auth": "With Auth",
|
"auth": "Avec authentification",
|
||||||
"outdated": "Outdated",
|
"outdated": "Obsolète",
|
||||||
"banned": "Banned"
|
"banned": "Banni"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ import useSWR from "swr";
|
|||||||
import { compareVersions } from "compare-versions";
|
import { compareVersions } from "compare-versions";
|
||||||
import { MdNewReleases } from "react-icons/md";
|
import { MdNewReleases } from "react-icons/md";
|
||||||
|
|
||||||
export default function Version() {
|
export default function Version({ disableUpdateCheck = false }) {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
const buildTime = process.env.NEXT_PUBLIC_BUILDTIME?.length
|
const buildTime = process.env.NEXT_PUBLIC_BUILDTIME?.length
|
||||||
@@ -12,7 +12,7 @@ export default function Version() {
|
|||||||
const revision = process.env.NEXT_PUBLIC_REVISION?.length ? process.env.NEXT_PUBLIC_REVISION : "dev";
|
const revision = process.env.NEXT_PUBLIC_REVISION?.length ? process.env.NEXT_PUBLIC_REVISION : "dev";
|
||||||
const version = process.env.NEXT_PUBLIC_VERSION?.length ? process.env.NEXT_PUBLIC_VERSION : "dev";
|
const version = process.env.NEXT_PUBLIC_VERSION?.length ? process.env.NEXT_PUBLIC_VERSION : "dev";
|
||||||
|
|
||||||
const { data: releaseData } = useSWR("/api/releases");
|
const { data: releaseData } = useSWR(disableUpdateCheck ? null : "/api/releases");
|
||||||
|
|
||||||
// use Intl.DateTimeFormat to format the date
|
// use Intl.DateTimeFormat to format the date
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import cachedFetch from "utils/proxy/cached-fetch";
|
import cachedFetch from "utils/proxy/cached-fetch";
|
||||||
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
|
const logger = createLogger("releases");
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const releasesURL = "https://api.github.com/repos/gethomepage/homepage/releases";
|
const releasesURL = "https://api.github.com/repos/gethomepage/homepage/releases";
|
||||||
return res.send(await cachedFetch(releasesURL, 5));
|
try {
|
||||||
|
return res.send(await cachedFetch(releasesURL, 5));
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Error checking GitHub releases: ${e}`);
|
||||||
|
return res.send([]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import cachedFetch from "utils/proxy/cached-fetch";
|
import cachedFetch from "utils/proxy/cached-fetch";
|
||||||
import { getSettings } from "utils/config/config";
|
import { getSettings } from "utils/config/config";
|
||||||
|
import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { latitude, longitude, units, provider, cache, lang } = req.query;
|
const { latitude, longitude, units, provider, cache, lang, index } = req.query;
|
||||||
let { apiKey } = req.query;
|
const privateWidgetOptions = await getPrivateWidgetOptions("openweathermap", index);
|
||||||
|
let { apiKey } = privateWidgetOptions;
|
||||||
|
|
||||||
if (!apiKey && !provider) {
|
if (!apiKey && !provider) {
|
||||||
return res.status(400).json({ error: "Missing API key or provider" });
|
return res.status(400).json({ error: "Missing API key or provider" });
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import cachedFetch from "utils/proxy/cached-fetch";
|
import cachedFetch from "utils/proxy/cached-fetch";
|
||||||
import { getSettings } from "utils/config/config";
|
import { getSettings } from "utils/config/config";
|
||||||
|
import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
|
||||||
|
|
||||||
export default async function handler(req, res) {
|
export default async function handler(req, res) {
|
||||||
const { latitude, longitude, provider, cache, lang } = req.query;
|
const { latitude, longitude, provider, cache, lang, index } = req.query;
|
||||||
let { apiKey } = req.query;
|
const privateWidgetOptions = await getPrivateWidgetOptions("weatherapi", index);
|
||||||
|
let { apiKey } = privateWidgetOptions;
|
||||||
|
|
||||||
if (!apiKey && !provider) {
|
if (!apiKey && !provider) {
|
||||||
return res.status(400).json({ error: "Missing API key or provider" });
|
return res.status(400).json({ error: "Missing API key or provider" });
|
||||||
|
|||||||
+1
-1
@@ -445,7 +445,7 @@ function Home({ initialSettings }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="version" className="flex mt-4 w-full justify-end">
|
<div id="version" className="flex mt-4 w-full justify-end">
|
||||||
{!settings.hideVersion && <Version />}
|
{!settings.hideVersion && <Version disableUpdateCheck={settings.disableUpdateCheck} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -254,7 +254,8 @@ export async function servicesFromKubernetes() {
|
|||||||
ingress.metadata.annotations &&
|
ingress.metadata.annotations &&
|
||||||
ingress.metadata.annotations[`${ANNOTATION_BASE}/enabled`] === "true" &&
|
ingress.metadata.annotations[`${ANNOTATION_BASE}/enabled`] === "true" &&
|
||||||
(!ingress.metadata.annotations[`${ANNOTATION_BASE}/instance`] ||
|
(!ingress.metadata.annotations[`${ANNOTATION_BASE}/instance`] ||
|
||||||
ingress.metadata.annotations[`${ANNOTATION_BASE}/instance`] === instanceName),
|
ingress.metadata.annotations[`${ANNOTATION_BASE}/instance`] === instanceName ||
|
||||||
|
`${ANNOTATION_BASE}/instance.${instanceName}` in ingress.metadata.annotations),
|
||||||
)
|
)
|
||||||
.map((ingress) => {
|
.map((ingress) => {
|
||||||
let constructedService = {
|
let constructedService = {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export async function cleanWidgetGroups(widgets) {
|
|||||||
const optionKeys = Object.keys(sanitizedOptions);
|
const optionKeys = Object.keys(sanitizedOptions);
|
||||||
|
|
||||||
// delete private options from the sanitized options
|
// delete private options from the sanitized options
|
||||||
["username", "password", "key"].forEach((pO) => {
|
["username", "password", "key", "apiKey"].forEach((pO) => {
|
||||||
if (optionKeys.includes(pO)) {
|
if (optionKeys.includes(pO)) {
|
||||||
delete sanitizedOptions[pO];
|
delete sanitizedOptions[pO];
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ export async function getPrivateWidgetOptions(type, widgetIndex) {
|
|||||||
const widgets = await widgetsFromConfig();
|
const widgets = await widgetsFromConfig();
|
||||||
|
|
||||||
const privateOptions = widgets.map((widget) => {
|
const privateOptions = widgets.map((widget) => {
|
||||||
const { index, url, username, password, key } = widget.options;
|
const { index, url, username, password, key, apiKey } = widget.options;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: widget.type,
|
type: widget.type,
|
||||||
@@ -67,6 +67,7 @@ export async function getPrivateWidgetOptions(type, widgetIndex) {
|
|||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
key,
|
key,
|
||||||
|
apiKey,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ export async function sendJsonRpcRequest(url, method, params, username, password
|
|||||||
if (status === 200) {
|
if (status === 200) {
|
||||||
const json = JSON.parse(data.toString());
|
const json = JSON.parse(data.toString());
|
||||||
|
|
||||||
|
if (json.id === null) {
|
||||||
|
json.id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// in order to get access to the underlying error object in the JSON response
|
// in order to get access to the underlying error object in the JSON response
|
||||||
// you must set `result` equal to undefined
|
// you must set `result` equal to undefined
|
||||||
if (json.error && json.result === null) {
|
if (json.error && json.result === null) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default function Component({ service }) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
const { data: resultData, error: resultError } = useWidgetAPI(widget, "result");
|
const { data: resultData, error: resultError } = useWidgetAPI(widget, "upstreams");
|
||||||
|
|
||||||
if (resultError) {
|
if (resultError) {
|
||||||
return <Container service={service} error={resultError} />;
|
return <Container service={service} error={resultError} />;
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import genericProxyHandler from "utils/proxy/handlers/generic";
|
import genericProxyHandler from "utils/proxy/handlers/generic";
|
||||||
|
|
||||||
const widget = {
|
const widget = {
|
||||||
api: "{url}/reverse_proxy/upstreams",
|
api: "{url}/{endpoint}",
|
||||||
proxyHandler: genericProxyHandler,
|
proxyHandler: genericProxyHandler,
|
||||||
|
|
||||||
|
mappings: {
|
||||||
|
upstreams: {
|
||||||
|
endpoint: "reverse_proxy/upstreams",
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default widget;
|
export default widget;
|
||||||
@@ -65,7 +65,7 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container service={service}>
|
<Container service={service}>
|
||||||
<div className={classNames(service.description ? "-top-10" : "-top-8", "absolute right-1")}>
|
<div className={classNames(service.description ? "-top-10" : "-top-8", "absolute right-1 z-20")}>
|
||||||
<Dropdown options={dateRangeOptions} value={dateRange} setValue={setDateRange} />
|
<Dropdown options={dateRangeOptions} value={dateRange} setValue={setDateRange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
|
|
||||||
const { data: omadaData, error: omadaAPIError } = useWidgetAPI(widget, {
|
const { data: omadaData, error: omadaAPIError } = useWidgetAPI(widget, "info", {
|
||||||
refreshInterval: 5000,
|
refreshInterval: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ import omadaProxyHandler from "./proxy";
|
|||||||
|
|
||||||
const widget = {
|
const widget = {
|
||||||
proxyHandler: omadaProxyHandler,
|
proxyHandler: omadaProxyHandler,
|
||||||
|
|
||||||
|
mappings: {
|
||||||
|
info: {
|
||||||
|
endpoint: "api/info",
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default widget;
|
export default widget;
|
||||||
@@ -77,7 +77,7 @@ async function fetchSystem(url) {
|
|||||||
const systemResponse = JSON.parse(data.toString())[1];
|
const systemResponse = JSON.parse(data.toString())[1];
|
||||||
const response = {
|
const response = {
|
||||||
uptime: systemResponse.uptime,
|
uptime: systemResponse.uptime,
|
||||||
cpuLoad: systemResponse.load[1],
|
cpuLoad: (systemResponse.load[1] / 65536.0).toFixed(2),
|
||||||
};
|
};
|
||||||
return [200, contentType, response];
|
return [200, contentType, response];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function Component({ service }) {
|
|||||||
|
|
||||||
const enabled = infoData.filter((item) => item.enabled).length;
|
const enabled = infoData.filter((item) => item.enabled).length;
|
||||||
const disabled = infoData.length - enabled;
|
const disabled = infoData.length - enabled;
|
||||||
const connectionThreshold = widget.threshold ?? 2 * 60 * 1000;
|
const connectionThreshold = (widget.threshold ?? 2) * 60 * 1000;
|
||||||
const currentTime = new Date();
|
const currentTime = new Date();
|
||||||
const connected = infoData.filter(
|
const connected = infoData.filter(
|
||||||
(item) => currentTime - new Date(item.latestHandshakeAt) < connectionThreshold,
|
(item) => currentTime - new Date(item.latestHandshakeAt) < connectionThreshold,
|
||||||
|
|||||||
@@ -21,14 +21,21 @@ async function login(widget, service) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const connectSidCookie = responseHeaders["set-cookie"]
|
let connectSidCookie = responseHeaders["set-cookie"];
|
||||||
|
if (!connectSidCookie) {
|
||||||
|
const sid = cache.get(`${sessionSIDCacheKey}.${service}`);
|
||||||
|
if (sid) {
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connectSidCookie = connectSidCookie
|
||||||
.find((cookie) => cookie.startsWith("connect.sid="))
|
.find((cookie) => cookie.startsWith("connect.sid="))
|
||||||
.split(";")[0]
|
.split(";")[0]
|
||||||
.replace("connect.sid=", "");
|
.replace("connect.sid=", "");
|
||||||
cache.put(`${sessionSIDCacheKey}.${service}`, connectSidCookie);
|
cache.put(`${sessionSIDCacheKey}.${service}`, connectSidCookie);
|
||||||
return connectSidCookie;
|
return connectSidCookie;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`Error logging into wg-easy`);
|
logger.error(`Error logging into wg-easy, error: ${e}`);
|
||||||
cache.del(`${sessionSIDCacheKey}.${service}`);
|
cache.del(`${sessionSIDCacheKey}.${service}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user