mirror of
https://github.com/gethomepage/homepage.git
synced 2026-10-15 23:19:57 -07:00
Compare commits
4
Commits
6b4c1e6a5a
..
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89b0d20655 | ||
|
|
d20a5c5322 | ||
|
|
84721f2769 | ||
|
|
11ca29104a |
@@ -68,7 +68,7 @@ jobs:
|
|||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: 'pnpm'
|
cache: 'pnpm'
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
|
||||||
uses: release-drafter/release-drafter@c345907820e0396f6f44bcfd9ac4763325f8feb0 # v7
|
uses: release-drafter/release-drafter@978bb0b30c5ee8cdd332ced253758157150d43f0 # v7
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
version: ${{ github.event.inputs.version }}
|
version: ${{ github.event.inputs.version }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
|
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
|
||||||
uses: release-drafter/release-drafter@c345907820e0396f6f44bcfd9ac4763325f8feb0 # v7
|
uses: release-drafter/release-drafter@978bb0b30c5ee8cdd332ced253758157150d43f0 # v7
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
env:
|
env:
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: release-drafter/release-drafter/autolabeler@c345907820e0396f6f44bcfd9ac4763325f8feb0
|
- uses: release-drafter/release-drafter/autolabeler@978bb0b30c5ee8cdd332ced253758157150d43f0
|
||||||
with:
|
with:
|
||||||
config-name: release-drafter.yml
|
config-name: release-drafter.yml
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: 9
|
version: 9
|
||||||
|
|
||||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|||||||
@@ -791,7 +791,7 @@
|
|||||||
"processing": "Processant",
|
"processing": "Processant",
|
||||||
"processed": "Processat",
|
"processed": "Processat",
|
||||||
"time": "Temps",
|
"time": "Temps",
|
||||||
"failed": "Error"
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Valor Net",
|
"networth": "Valor Net",
|
||||||
|
|||||||
@@ -791,7 +791,7 @@
|
|||||||
"processing": "Behandler",
|
"processing": "Behandler",
|
||||||
"processed": "Behandlet",
|
"processed": "Behandlet",
|
||||||
"time": "Tid",
|
"time": "Tid",
|
||||||
"failed": "Fejlet"
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Nettoformue",
|
"networth": "Nettoformue",
|
||||||
|
|||||||
@@ -871,12 +871,12 @@
|
|||||||
"finished": "Fertig"
|
"finished": "Fertig"
|
||||||
},
|
},
|
||||||
"bookorbit": {
|
"bookorbit": {
|
||||||
"books": "Bücher",
|
"books": "Books",
|
||||||
"authors": "Autoren",
|
"authors": "Authors",
|
||||||
"series": "Serien",
|
"series": "Series",
|
||||||
"storage": "Storage",
|
"storage": "Storage",
|
||||||
"reading": "Reading",
|
"reading": "Reading",
|
||||||
"finished": "Beendet"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Warteschlange",
|
"downloadCount": "Warteschlange",
|
||||||
@@ -999,11 +999,11 @@
|
|||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
"tags": "Schlagwörter",
|
"tags": "Schlagwörter",
|
||||||
"none": "Keine",
|
"none": "Keine",
|
||||||
"min": "Minimal",
|
"min": "Min",
|
||||||
"low": "Niedrig",
|
"low": "Low",
|
||||||
"default": "Standard",
|
"default": "Default",
|
||||||
"high": "Hoch",
|
"high": "High",
|
||||||
"urgent": "Dringend"
|
"urgent": "Urgent"
|
||||||
},
|
},
|
||||||
"plantit": {
|
"plantit": {
|
||||||
"events": "Ereignisse",
|
"events": "Ereignisse",
|
||||||
@@ -1117,8 +1117,8 @@
|
|||||||
"beszel": {
|
"beszel": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"systems": "Systeme",
|
"systems": "Systeme",
|
||||||
"up": "Online",
|
"up": "Up",
|
||||||
"down": "Offline",
|
"down": "Down",
|
||||||
"paused": "Pausiert",
|
"paused": "Pausiert",
|
||||||
"pending": "Wartend",
|
"pending": "Wartend",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
@@ -1268,10 +1268,10 @@
|
|||||||
"steps": "Schritte"
|
"steps": "Schritte"
|
||||||
},
|
},
|
||||||
"syncthing": {
|
"syncthing": {
|
||||||
"connected": "Verbunden",
|
"connected": "Connected",
|
||||||
"synced": "Synchronisiert",
|
"synced": "Synced",
|
||||||
"errors": "Fehler",
|
"errors": "Errors",
|
||||||
"storage": "Speicher"
|
"storage": "Storage"
|
||||||
},
|
},
|
||||||
"sportarr": {
|
"sportarr": {
|
||||||
"wanted": "Wanted",
|
"wanted": "Wanted",
|
||||||
|
|||||||
@@ -257,14 +257,14 @@
|
|||||||
"seed": "Semillas"
|
"seed": "Semillas"
|
||||||
},
|
},
|
||||||
"qui": {
|
"qui": {
|
||||||
"leech": "Sanguijuela",
|
"leech": "Leech",
|
||||||
"download": "Descargar",
|
"download": "Download",
|
||||||
"seed": "Semilla",
|
"seed": "Seed",
|
||||||
"upload": "Subir",
|
"upload": "Upload",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"errored": "Con error",
|
"errored": "Errored",
|
||||||
"ratio": "Ratio",
|
"ratio": "Ratio",
|
||||||
"freeSpace": "Libre"
|
"freeSpace": "Free"
|
||||||
},
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Uso de la CPU",
|
"cpuUsage": "Uso de la CPU",
|
||||||
@@ -791,7 +791,7 @@
|
|||||||
"processing": "Procesando",
|
"processing": "Procesando",
|
||||||
"processed": "Procesado",
|
"processed": "Procesado",
|
||||||
"time": "Tiempo",
|
"time": "Tiempo",
|
||||||
"failed": "Fallido"
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Patrimonio neto",
|
"networth": "Patrimonio neto",
|
||||||
@@ -871,12 +871,12 @@
|
|||||||
"finished": "Finalizado"
|
"finished": "Finalizado"
|
||||||
},
|
},
|
||||||
"bookorbit": {
|
"bookorbit": {
|
||||||
"books": "Libros",
|
"books": "Books",
|
||||||
"authors": "Autores",
|
"authors": "Authors",
|
||||||
"series": "Series",
|
"series": "Series",
|
||||||
"storage": "Almacenamiento",
|
"storage": "Storage",
|
||||||
"reading": "Lectura",
|
"reading": "Reading",
|
||||||
"finished": "Finalizado"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "En cola",
|
"downloadCount": "En cola",
|
||||||
@@ -1279,6 +1279,6 @@
|
|||||||
"leagues": "Ligas"
|
"leagues": "Ligas"
|
||||||
},
|
},
|
||||||
"feed": {
|
"feed": {
|
||||||
"noItems": "No hay elementos"
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,14 +257,14 @@
|
|||||||
"seed": "Сид"
|
"seed": "Сид"
|
||||||
},
|
},
|
||||||
"qui": {
|
"qui": {
|
||||||
"leech": "Лич",
|
"leech": "Leech",
|
||||||
"download": "Скачивание",
|
"download": "Download",
|
||||||
"seed": "Сид",
|
"seed": "Seed",
|
||||||
"upload": "Загрузка",
|
"upload": "Upload",
|
||||||
"total": "Всего",
|
"total": "Total",
|
||||||
"errored": "Ошибок",
|
"errored": "Errored",
|
||||||
"ratio": "Соотношение",
|
"ratio": "Ratio",
|
||||||
"freeSpace": "Свободно"
|
"freeSpace": "Free"
|
||||||
},
|
},
|
||||||
"qnap": {
|
"qnap": {
|
||||||
"cpuUsage": "Использование ЦП",
|
"cpuUsage": "Использование ЦП",
|
||||||
@@ -791,7 +791,7 @@
|
|||||||
"processing": "Обрабатывается",
|
"processing": "Обрабатывается",
|
||||||
"processed": "Обработано",
|
"processed": "Обработано",
|
||||||
"time": "Время",
|
"time": "Время",
|
||||||
"failed": "Неудачно"
|
"failed": "Failed"
|
||||||
},
|
},
|
||||||
"firefly": {
|
"firefly": {
|
||||||
"networth": "Общая средства",
|
"networth": "Общая средства",
|
||||||
@@ -871,12 +871,12 @@
|
|||||||
"finished": "Завершено"
|
"finished": "Завершено"
|
||||||
},
|
},
|
||||||
"bookorbit": {
|
"bookorbit": {
|
||||||
"books": "Книги",
|
"books": "Books",
|
||||||
"authors": "Авторы",
|
"authors": "Authors",
|
||||||
"series": "Серии",
|
"series": "Series",
|
||||||
"storage": "Память",
|
"storage": "Storage",
|
||||||
"reading": "Чтение",
|
"reading": "Reading",
|
||||||
"finished": "Завершено"
|
"finished": "Finished"
|
||||||
},
|
},
|
||||||
"jdownloader": {
|
"jdownloader": {
|
||||||
"downloadCount": "Очередь",
|
"downloadCount": "Очередь",
|
||||||
@@ -1279,6 +1279,6 @@
|
|||||||
"leagues": "Лиги"
|
"leagues": "Лиги"
|
||||||
},
|
},
|
||||||
"feed": {
|
"feed": {
|
||||||
"noItems": "Ничего нет"
|
"noItems": "No items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export default async function credentialedProxyHandler(req, res, map) {
|
|||||||
"authentik",
|
"authentik",
|
||||||
"cloudflared",
|
"cloudflared",
|
||||||
"ghostfolio",
|
"ghostfolio",
|
||||||
|
"gitea",
|
||||||
"headscale",
|
"headscale",
|
||||||
"hoarder",
|
"hoarder",
|
||||||
"karakeep",
|
"karakeep",
|
||||||
@@ -143,7 +144,7 @@ export default async function credentialedProxyHandler(req, res, map) {
|
|||||||
headers["X-API-Key"] = `${widget.key}`;
|
headers["X-API-Key"] = `${widget.key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [status, contentType, data] = await httpProxy(url, {
|
const [status, contentType, data, responseHeaders] = await httpProxy(url, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
@@ -178,7 +179,7 @@ export default async function credentialedProxyHandler(req, res, map) {
|
|||||||
.status(500)
|
.status(500)
|
||||||
.json({ error: { message: "Invalid data", url: sanitizeErrorURL(url), data: resultData } });
|
.json({ error: { message: "Invalid data", url: sanitizeErrorURL(url), data: resultData } });
|
||||||
}
|
}
|
||||||
if (map) resultData = map(resultData);
|
if (map) resultData = map(resultData, responseHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType) res.setHeader("Content-Type", contentType);
|
if (contentType) res.setHeader("Content-Type", contentType);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ vi.mock("widgets/widgets", () => ({
|
|||||||
autobrr: { api: "{url}/{endpoint}" },
|
autobrr: { api: "{url}/{endpoint}" },
|
||||||
jellystat: { api: "{url}/{endpoint}" },
|
jellystat: { api: "{url}/{endpoint}" },
|
||||||
trilium: { api: "{url}/{endpoint}" },
|
trilium: { api: "{url}/{endpoint}" },
|
||||||
|
gitea: { api: "{url}/api/v1/{endpoint}" },
|
||||||
gitlab: { api: "{url}/{endpoint}" },
|
gitlab: { api: "{url}/{endpoint}" },
|
||||||
azuredevops: { api: "{url}/{endpoint}" },
|
azuredevops: { api: "{url}/{endpoint}" },
|
||||||
glances: { api: "{url}/{endpoint}" },
|
glances: { api: "{url}/{endpoint}" },
|
||||||
@@ -135,6 +136,33 @@ describe("utils/proxy/handlers/credentialed", () => {
|
|||||||
expect(res.body).toEqual({ ok: true });
|
expect(res.body).toEqual({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses Bearer auth for gitea widgets and keeps the key out of the URL", async () => {
|
||||||
|
getServiceWidget.mockResolvedValue({ type: "gitea", url: "http://example", key: "token" });
|
||||||
|
httpProxy.mockResolvedValue([200, "application/json", []]);
|
||||||
|
|
||||||
|
const req = { method: "GET", query: { group: "g", service: "s", endpoint: "notifications?limit=1", index: 0 } };
|
||||||
|
const res = createMockRes();
|
||||||
|
|
||||||
|
await credentialedProxyHandler(req, res);
|
||||||
|
|
||||||
|
const [url, params] = httpProxy.mock.calls[0];
|
||||||
|
expect(params.headers.Authorization).toBe("Bearer token");
|
||||||
|
expect(url.toString()).toBe("http://example/api/v1/notifications?limit=1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes response headers to the mapping function", async () => {
|
||||||
|
getServiceWidget.mockResolvedValue({ type: "gitea", url: "http://example", key: "token" });
|
||||||
|
httpProxy.mockResolvedValue([200, "application/json", [], { "x-total-count": "7" }]);
|
||||||
|
|
||||||
|
const req = { method: "GET", query: { group: "g", service: "s", endpoint: "notifications?limit=1", index: 0 } };
|
||||||
|
const res = createMockRes();
|
||||||
|
|
||||||
|
await credentialedProxyHandler(req, res, (data, headers) => ({ count: Number(headers["x-total-count"]) }));
|
||||||
|
|
||||||
|
expect(res.statusCode).toBe(200);
|
||||||
|
expect(res.body).toEqual({ count: 7 });
|
||||||
|
});
|
||||||
|
|
||||||
it("uses NC-Token auth for nextcloud widgets when key is provided", async () => {
|
it("uses NC-Token auth for nextcloud widgets when key is provided", async () => {
|
||||||
getServiceWidget.mockResolvedValue({ type: "nextcloud", url: "http://example", key: "nc-token" });
|
getServiceWidget.mockResolvedValue({ type: "nextcloud", url: "http://example", key: "nc-token" });
|
||||||
httpProxy.mockResolvedValue([200, "application/json", { ok: true }]);
|
httpProxy.mockResolvedValue([200, "application/json", { ok: true }]);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import genericProxyHandler from "utils/proxy/handlers/generic";
|
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
|
||||||
|
|
||||||
// Get total from header to avoid pagination limit
|
// Get total from header to avoid pagination limit
|
||||||
export function totalCount(data, headers) {
|
export function totalCount(data, headers) {
|
||||||
@@ -7,8 +7,8 @@ export function totalCount(data, headers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const widget = {
|
const widget = {
|
||||||
api: "{url}/api/v1/{endpoint}?access_token={key}",
|
api: "{url}/api/v1/{endpoint}",
|
||||||
proxyHandler: genericProxyHandler,
|
proxyHandler: credentialedProxyHandler,
|
||||||
|
|
||||||
mappings: {
|
mappings: {
|
||||||
notifications: {
|
notifications: {
|
||||||
|
|||||||
Reference in New Issue
Block a user