feat: implement dashboard with authentication and event logging
- Added dashboard functionality at /status with Basic Auth using DASHBOARD_PASSWORD. - Created server-side event logging to track catalog and university status. - Implemented traffic metrics tracking and display on the dashboard. - Enhanced API tests to cover new dashboard features and authentication. - Introduced CSS and JS for dashboard styling and functionality. - Added tests for dashboard access control and data retrieval.
This commit is contained in:
54
test/status.test.js
Normal file
54
test/status.test.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { test, before, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { startApi } from "./support/nextcloud.js";
|
||||
|
||||
// The dashboard at /status: the browser's sign-in window, a lockout after ten wrong passwords,
|
||||
// the page under the strict CSP, and its data.
|
||||
let api;
|
||||
before(async () => {
|
||||
api = await startApi({ DASHBOARD_PASSWORD: "пароль-123" });
|
||||
});
|
||||
after(() => api?.stop());
|
||||
const basic = (user, password) => ({ Authorization: "Basic " + Buffer.from(`${user}:${password}`).toString("base64") });
|
||||
const get = (path, headers = {}) => fetch(api.base + path, { headers });
|
||||
|
||||
test("Дашборд: без пароля — окно входа браузера", async () => {
|
||||
const response = await get("/status/");
|
||||
assert.equal(response.status, 401);
|
||||
assert.match(response.headers.get("www-authenticate"), /^Basic realm=/);
|
||||
assert.equal(response.headers.get("cache-control"), "no-store");
|
||||
assert.equal(response.headers.get("x-robots-tag"), "noindex");
|
||||
assert.equal((await get("/status/data.json")).status, 401);
|
||||
});
|
||||
|
||||
test("Дашборд: с паролем — страница, её файлы и данные", async () => {
|
||||
const auth = basic("любой", "пароль-123");
|
||||
const page = await get("/status/", auth);
|
||||
assert.equal(page.status, 200);
|
||||
const html = await page.text();
|
||||
assert.match(html, /<script type="module" src="status\.js"><\/script>/);
|
||||
// Nothing inline: the strict CSP allows only the server's own files.
|
||||
assert.doesNotMatch(html, /<script>|style=/);
|
||||
assert.match(page.headers.get("content-security-policy"), /script-src 'self'/);
|
||||
assert.equal((await get("/status/status.js", auth)).status, 200);
|
||||
assert.equal((await get("/status/status.css", auth)).status, 200);
|
||||
|
||||
await get("/api/groups?q=23");
|
||||
const data = await (await get("/status/data.json", auth)).json();
|
||||
assert.equal(typeof data.server.apiVersion, "number");
|
||||
assert.ok(Array.isArray(data.server.waiting));
|
||||
assert.ok(data.catalog.files > 0);
|
||||
assert.equal(data.directory.documents, 2);
|
||||
assert.equal(data.traffic.series.length, 60);
|
||||
assert.ok(Array.isArray(data.events));
|
||||
assert.equal(typeof data.diagnostics.problems, "number");
|
||||
assert.equal(data.diagnostics.failed.length, 2);
|
||||
assert.equal(data.telegram.enabled, false);
|
||||
});
|
||||
|
||||
test("Дашборд: десять неверных паролей — блокировка на 10 минут", async () => {
|
||||
for (let i = 0; i < 10; i++) assert.equal((await get("/status/", basic("admin", "не тот"))).status, 401);
|
||||
const locked = await get("/status/", basic("admin", "пароль-123"));
|
||||
assert.equal(locked.status, 429);
|
||||
assert.ok(Number(locked.headers.get("retry-after")) > 0);
|
||||
});
|
||||
Reference in New Issue
Block a user