Fix cypress tests following user wizard changes

This commit is contained in:
Jamie Curnow
2025-09-10 19:11:35 +10:00
parent ca84e3a146
commit cde7460b5e
27 changed files with 939 additions and 655 deletions

View File

@@ -9,7 +9,7 @@ import internalAuditLog from "./audit-log.js";
import internalToken from "./token.js"; import internalToken from "./token.js";
const omissions = () => { const omissions = () => {
return ["is_deleted"]; return ["is_deleted", "permissions.id", "permissions.user_id", "permissions.created_on", "permissions.modified_on"];
}; };
const DEFAULT_AVATAR = gravatar.url("admin@example.com", { default: "mm" }); const DEFAULT_AVATAR = gravatar.url("admin@example.com", { default: "mm" });
@@ -250,6 +250,14 @@ const internalUser = {
}); });
}, },
deleteAll: async () => {
await userModel
.query()
.patch({
is_deleted: 1,
});
},
/** /**
* This will only count the users * This will only count the users
* *

View File

@@ -199,6 +199,13 @@ const isPostgres = () => {
*/ */
const isDebugMode = () => !!process.env.DEBUG; const isDebugMode = () => !!process.env.DEBUG;
/**
* Are we running in CI?
*
* @returns {boolean}
*/
const isCI = () => process.env.CI === 'true' && process.env.DEBUG === 'true';
/** /**
* Returns a public key * Returns a public key
* *
@@ -234,4 +241,4 @@ const useLetsencryptServer = () => {
return null; return null;
}; };
export { configHas, configGet, isSqlite, isMysql, isPostgres, isDebugMode, getPrivateKey, getPublicKey, useLetsencryptStaging, useLetsencryptServer }; export { isCI, configHas, configGet, isSqlite, isMysql, isPostgres, isDebugMode, getPrivateKey, getPublicKey, useLetsencryptStaging, useLetsencryptServer };

View File

@@ -14,7 +14,10 @@ const errs = {
Error.captureStackTrace(this, this.constructor); Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name; this.name = this.constructor.name;
this.previous = previous; this.previous = previous;
this.message = `Item Not Found - ${id}`; this.message = "Not Found";
if (id) {
this.message = `Not Found - ${id}`;
}
this.public = true; this.public = true;
this.status = 404; this.status = 404;
}, },

View File

@@ -2,6 +2,7 @@ import express from "express";
import internalAuditLog from "../internal/audit-log.js"; import internalAuditLog from "../internal/audit-log.js";
import jwtdecode from "../lib/express/jwt-decode.js"; import jwtdecode from "../lib/express/jwt-decode.js";
import validator from "../lib/validator/index.js"; import validator from "../lib/validator/index.js";
import { express as logger } from "../logger.js";
const router = express.Router({ const router = express.Router({
caseSensitive: true, caseSensitive: true,
@@ -24,31 +25,31 @@ router
* *
* Retrieve all logs * Retrieve all logs
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalAuditLog.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalAuditLog.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}); });
export default router; export default router;

View File

@@ -3,6 +3,7 @@ import internalAccessList from "../../internal/access-list.js";
import jwtdecode from "../../lib/express/jwt-decode.js"; import jwtdecode from "../../lib/express/jwt-decode.js";
import apiValidator from "../../lib/validator/api.js"; import apiValidator from "../../lib/validator/api.js";
import validator from "../../lib/validator/index.js"; import validator from "../../lib/validator/index.js";
import { express as logger } from "../../logger.js";
import { getValidationSchema } from "../../schema/index.js"; import { getValidationSchema } from "../../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -26,31 +27,31 @@ router
* *
* Retrieve all access-lists * Retrieve all access-lists
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalAccessList.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalAccessList.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}) })
/** /**
@@ -58,15 +59,15 @@ router
* *
* Create a new access-list * Create a new access-list
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/access-lists", "post"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/access-lists", "post"), req.body);
return internalAccessList.create(res.locals.access, payload); const result = await internalAccessList.create(res.locals.access, payload);
}) res.status(201).send(result);
.then((result) => { } catch (err) {
res.status(201).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
/** /**
@@ -86,35 +87,35 @@ router
* *
* Retrieve a specific access-list * Retrieve a specific access-list
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["list_id"], {
additionalProperties: false, required: ["list_id"],
properties: { additionalProperties: false,
list_id: { properties: {
$ref: "common#/properties/id", list_id: {
}, $ref: "common#/properties/id",
expand: { },
$ref: "common#/properties/expand", expand: {
$ref: "common#/properties/expand",
},
}, },
}, },
}, {
{ list_id: req.params.list_id,
list_id: req.params.list_id, expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, },
}, );
) const row = await internalAccessList.get(res.locals.access, {
.then((data) => { id: Number.parseInt(data.list_id, 10),
return internalAccessList.get(res.locals.access, { expand: data.expand,
id: Number.parseInt(data.list_id, 10), });
expand: data.expand, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -122,16 +123,16 @@ router
* *
* Update and existing access-list * Update and existing access-list
*/ */
.put((req, res, next) => { .put(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/access-lists/{listID}", "put"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/access-lists/{listID}", "put"), req.body);
payload.id = Number.parseInt(req.params.list_id, 10); payload.id = Number.parseInt(req.params.list_id, 10);
return internalAccessList.update(res.locals.access, payload); const result = await internalAccessList.update(res.locals.access, payload);
}) res.status(200).send(result);
.then((result) => { } catch (err) {
res.status(200).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}) })
/** /**
@@ -139,13 +140,16 @@ router
* *
* Delete and existing access-list * Delete and existing access-list
*/ */
.delete((req, res, next) => { .delete(async (req, res, next) => {
internalAccessList try {
.delete(res.locals.access, { id: Number.parseInt(req.params.list_id, 10) }) const result = await internalAccessList.delete(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.list_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
export default router; export default router;

View File

@@ -4,6 +4,7 @@ import errs from "../../lib/error.js";
import jwtdecode from "../../lib/express/jwt-decode.js"; import jwtdecode from "../../lib/express/jwt-decode.js";
import apiValidator from "../../lib/validator/api.js"; import apiValidator from "../../lib/validator/api.js";
import validator from "../../lib/validator/index.js"; import validator from "../../lib/validator/index.js";
import { express as logger } from "../../logger.js";
import { getValidationSchema } from "../../schema/index.js"; import { getValidationSchema } from "../../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -27,31 +28,31 @@ router
* *
* Retrieve all certificates * Retrieve all certificates
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalCertificate.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalCertificate.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}) })
/** /**
@@ -59,16 +60,16 @@ router
* *
* Create a new certificate * Create a new certificate
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/certificates", "post"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/certificates", "post"), req.body);
req.setTimeout(900000); // 15 minutes timeout req.setTimeout(900000); // 15 minutes timeout
return internalCertificate.create(res.locals.access, payload); const result = await internalCertificate.create(res.locals.access, payload);
}) res.status(201).send(result);
.then((result) => { } catch (err) {
res.status(201).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
/** /**
@@ -88,18 +89,22 @@ router
* *
* Test HTTP challenge for domains * Test HTTP challenge for domains
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
if (req.query.domains === undefined) { if (req.query.domains === undefined) {
next(new errs.ValidationError("Domains are required as query parameters")); next(new errs.ValidationError("Domains are required as query parameters"));
return; return;
} }
internalCertificate try {
.testHttpsChallenge(res.locals.access, JSON.parse(req.query.domains)) const result = await internalCertificate.testHttpsChallenge(
.then((result) => { res.locals.access,
res.status(200).send(result); JSON.parse(req.query.domains),
}) );
.catch(next); res.status(200).send(result);
} catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -119,35 +124,35 @@ router
* *
* Retrieve a specific certificate * Retrieve a specific certificate
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["certificate_id"], {
additionalProperties: false, required: ["certificate_id"],
properties: { additionalProperties: false,
certificate_id: { properties: {
$ref: "common#/properties/id", certificate_id: {
}, $ref: "common#/properties/id",
expand: { },
$ref: "common#/properties/expand", expand: {
$ref: "common#/properties/expand",
},
}, },
}, },
}, {
{ certificate_id: req.params.certificate_id,
certificate_id: req.params.certificate_id, expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, },
}, );
) const row = await internalCertificate.get(res.locals.access, {
.then((data) => { id: Number.parseInt(data.certificate_id, 10),
return internalCertificate.get(res.locals.access, { expand: data.expand,
id: Number.parseInt(data.certificate_id, 10), });
expand: data.expand, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -155,13 +160,16 @@ router
* *
* Update and existing certificate * Update and existing certificate
*/ */
.delete((req, res, next) => { .delete(async (req, res, next) => {
internalCertificate try {
.delete(res.locals.access, { id: Number.parseInt(req.params.certificate_id, 10) }) const result = await internalCertificate.delete(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.certificate_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -181,19 +189,21 @@ router
* *
* Upload certificates * Upload certificates
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
if (!req.files) { if (!req.files) {
res.status(400).send({ error: "No files were uploaded" }); res.status(400).send({ error: "No files were uploaded" });
} else { return;
internalCertificate }
.upload(res.locals.access, {
id: Number.parseInt(req.params.certificate_id, 10), try {
files: req.files, const result = await internalCertificate.upload(res.locals.access, {
}) id: Number.parseInt(req.params.certificate_id, 10),
.then((result) => { files: req.files,
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
} }
}); });
@@ -214,16 +224,17 @@ router
* *
* Renew certificate * Renew certificate
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
req.setTimeout(900000); // 15 minutes timeout req.setTimeout(900000); // 15 minutes timeout
internalCertificate try {
.renew(res.locals.access, { const result = await internalCertificate.renew(res.locals.access, {
id: Number.parseInt(req.params.certificate_id, 10), id: Number.parseInt(req.params.certificate_id, 10),
}) });
.then((result) => { res.status(200).send(result);
res.status(200).send(result); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.catch(next); next(err);
}
}); });
/** /**
@@ -243,15 +254,16 @@ router
* *
* Renew certificate * Renew certificate
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
internalCertificate try {
.download(res.locals.access, { const result = await internalCertificate.download(res.locals.access, {
id: Number.parseInt(req.params.certificate_id, 10), id: Number.parseInt(req.params.certificate_id, 10),
}) });
.then((result) => { res.status(200).download(result.fileName);
res.status(200).download(result.fileName); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.catch(next); next(err);
}
}); });
/** /**
@@ -271,18 +283,20 @@ router
* *
* Validate certificates * Validate certificates
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
if (!req.files) { if (!req.files) {
res.status(400).send({ error: "No files were uploaded" }); res.status(400).send({ error: "No files were uploaded" });
} else { return;
internalCertificate }
.validate({
files: req.files, try {
}) const result = await internalCertificate.validate({
.then((result) => { files: req.files,
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
} }
}); });

View File

@@ -3,6 +3,7 @@ import internalDeadHost from "../../internal/dead-host.js";
import jwtdecode from "../../lib/express/jwt-decode.js"; import jwtdecode from "../../lib/express/jwt-decode.js";
import apiValidator from "../../lib/validator/api.js"; import apiValidator from "../../lib/validator/api.js";
import validator from "../../lib/validator/index.js"; import validator from "../../lib/validator/index.js";
import { express as logger } from "../../logger.js";
import { getValidationSchema } from "../../schema/index.js"; import { getValidationSchema } from "../../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -26,31 +27,31 @@ router
* *
* Retrieve all dead-hosts * Retrieve all dead-hosts
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalDeadHost.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalDeadHost.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}) })
/** /**
@@ -58,15 +59,15 @@ router
* *
* Create a new dead-host * Create a new dead-host
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/dead-hosts", "post"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/dead-hosts", "post"), req.body);
return internalDeadHost.create(res.locals.access, payload); const result = await internalDeadHost.create(res.locals.access, payload);
}) res.status(201).send(result);
.then((result) => { } catch (err) {
res.status(201).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
/** /**
@@ -86,35 +87,35 @@ router
* *
* Retrieve a specific dead-host * Retrieve a specific dead-host
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["host_id"], {
additionalProperties: false, required: ["host_id"],
properties: { additionalProperties: false,
host_id: { properties: {
$ref: "common#/properties/id", host_id: {
}, $ref: "common#/properties/id",
expand: { },
$ref: "common#/properties/expand", expand: {
$ref: "common#/properties/expand",
},
}, },
}, },
}, {
{ host_id: req.params.host_id,
host_id: req.params.host_id, expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, },
}, );
) const row = await internalDeadHost.get(res.locals.access, {
.then((data) => { id: Number.parseInt(data.host_id, 10),
return internalDeadHost.get(res.locals.access, { expand: data.expand,
id: Number.parseInt(data.host_id, 10), });
expand: data.expand, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -122,16 +123,16 @@ router
* *
* Update and existing dead-host * Update and existing dead-host
*/ */
.put((req, res, next) => { .put(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/dead-hosts/{hostID}", "put"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/dead-hosts/{hostID}", "put"), req.body);
payload.id = Number.parseInt(req.params.host_id, 10); payload.id = Number.parseInt(req.params.host_id, 10);
return internalDeadHost.update(res.locals.access, payload); const result = await internalDeadHost.update(res.locals.access, payload);
}) res.status(200).send(result);
.then((result) => { } catch (err) {
res.status(200).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}) })
/** /**
@@ -139,13 +140,16 @@ router
* *
* Update and existing dead-host * Update and existing dead-host
*/ */
.delete((req, res, next) => { .delete(async (req, res, next) => {
internalDeadHost try {
.delete(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalDeadHost.delete(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -163,13 +167,16 @@ router
/** /**
* POST /api/nginx/dead-hosts/123/enable * POST /api/nginx/dead-hosts/123/enable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalDeadHost try {
.enable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalDeadHost.enable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -188,12 +195,13 @@ router
* POST /api/nginx/dead-hosts/123/disable * POST /api/nginx/dead-hosts/123/disable
*/ */
.post((req, res, next) => { .post((req, res, next) => {
internalDeadHost try {
.disable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = internalDeadHost.disable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) });
.then((result) => { res.status(200).send(result);
res.status(200).send(result); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.catch(next); next(err);
}
}); });
export default router; export default router;

View File

@@ -3,6 +3,7 @@ import internalProxyHost from "../../internal/proxy-host.js";
import jwtdecode from "../../lib/express/jwt-decode.js"; import jwtdecode from "../../lib/express/jwt-decode.js";
import apiValidator from "../../lib/validator/api.js"; import apiValidator from "../../lib/validator/api.js";
import validator from "../../lib/validator/index.js"; import validator from "../../lib/validator/index.js";
import { express as logger } from "../../logger.js";
import { getValidationSchema } from "../../schema/index.js"; import { getValidationSchema } from "../../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -26,31 +27,31 @@ router
* *
* Retrieve all proxy-hosts * Retrieve all proxy-hosts
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalProxyHost.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalProxyHost.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}) })
/** /**
@@ -58,15 +59,15 @@ router
* *
* Create a new proxy-host * Create a new proxy-host
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/proxy-hosts", "post"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/proxy-hosts", "post"), req.body);
return internalProxyHost.create(res.locals.access, payload); const result = await internalProxyHost.create(res.locals.access, payload);
}) res.status(201).send(result);
.then((result) => { } catch (err) {
res.status(201).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
/** /**
@@ -86,35 +87,35 @@ router
* *
* Retrieve a specific proxy-host * Retrieve a specific proxy-host
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["host_id"], {
additionalProperties: false, required: ["host_id"],
properties: { additionalProperties: false,
host_id: { properties: {
$ref: "common#/properties/id", host_id: {
}, $ref: "common#/properties/id",
expand: { },
$ref: "common#/properties/expand", expand: {
$ref: "common#/properties/expand",
},
}, },
}, },
}, {
{ host_id: req.params.host_id,
host_id: req.params.host_id, expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, },
}, );
) const row = await internalProxyHost.get(res.locals.access, {
.then((data) => { id: Number.parseInt(data.host_id, 10),
return internalProxyHost.get(res.locals.access, { expand: data.expand,
id: Number.parseInt(data.host_id, 10), });
expand: data.expand, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -122,16 +123,16 @@ router
* *
* Update and existing proxy-host * Update and existing proxy-host
*/ */
.put((req, res, next) => { .put(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/proxy-hosts/{hostID}", "put"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/proxy-hosts/{hostID}", "put"), req.body);
payload.id = Number.parseInt(req.params.host_id, 10); payload.id = Number.parseInt(req.params.host_id, 10);
return internalProxyHost.update(res.locals.access, payload); const result = await internalProxyHost.update(res.locals.access, payload);
}) res.status(200).send(result);
.then((result) => { } catch (err) {
res.status(200).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}) })
/** /**
@@ -139,13 +140,16 @@ router
* *
* Update and existing proxy-host * Update and existing proxy-host
*/ */
.delete((req, res, next) => { .delete(async (req, res, next) => {
internalProxyHost try {
.delete(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalProxyHost.delete(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -163,13 +167,16 @@ router
/** /**
* POST /api/nginx/proxy-hosts/123/enable * POST /api/nginx/proxy-hosts/123/enable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalProxyHost try {
.enable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalProxyHost.enable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -187,13 +194,16 @@ router
/** /**
* POST /api/nginx/proxy-hosts/123/disable * POST /api/nginx/proxy-hosts/123/disable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalProxyHost try {
.disable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalProxyHost.disable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
export default router; export default router;

View File

@@ -3,6 +3,7 @@ import internalRedirectionHost from "../../internal/redirection-host.js";
import jwtdecode from "../../lib/express/jwt-decode.js"; import jwtdecode from "../../lib/express/jwt-decode.js";
import apiValidator from "../../lib/validator/api.js"; import apiValidator from "../../lib/validator/api.js";
import validator from "../../lib/validator/index.js"; import validator from "../../lib/validator/index.js";
import { express as logger } from "../../logger.js";
import { getValidationSchema } from "../../schema/index.js"; import { getValidationSchema } from "../../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -26,31 +27,31 @@ router
* *
* Retrieve all redirection-hosts * Retrieve all redirection-hosts
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalRedirectionHost.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalRedirectionHost.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}) })
/** /**
@@ -58,15 +59,15 @@ router
* *
* Create a new redirection-host * Create a new redirection-host
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/redirection-hosts", "post"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/redirection-hosts", "post"), req.body);
return internalRedirectionHost.create(res.locals.access, payload); const result = await internalRedirectionHost.create(res.locals.access, payload);
}) res.status(201).send(result);
.then((result) => { } catch (err) {
res.status(201).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
/** /**
@@ -86,35 +87,35 @@ router
* *
* Retrieve a specific redirection-host * Retrieve a specific redirection-host
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["host_id"], {
additionalProperties: false, required: ["host_id"],
properties: { additionalProperties: false,
host_id: { properties: {
$ref: "common#/properties/id", host_id: {
}, $ref: "common#/properties/id",
expand: { },
$ref: "common#/properties/expand", expand: {
$ref: "common#/properties/expand",
},
}, },
}, },
}, {
{ host_id: req.params.host_id,
host_id: req.params.host_id, expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, },
}, );
) const row = await internalRedirectionHost.get(res.locals.access, {
.then((data) => { id: Number.parseInt(data.host_id, 10),
return internalRedirectionHost.get(res.locals.access, { expand: data.expand,
id: Number.parseInt(data.host_id, 10), });
expand: data.expand, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -122,16 +123,19 @@ router
* *
* Update and existing redirection-host * Update and existing redirection-host
*/ */
.put((req, res, next) => { .put(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/redirection-hosts/{hostID}", "put"), req.body) try {
.then((payload) => { const payload = await apiValidator(
payload.id = Number.parseInt(req.params.host_id, 10); getValidationSchema("/nginx/redirection-hosts/{hostID}", "put"),
return internalRedirectionHost.update(res.locals.access, payload); req.body,
}) );
.then((result) => { payload.id = Number.parseInt(req.params.host_id, 10);
res.status(200).send(result); const result = await internalRedirectionHost.update(res.locals.access, payload);
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}) })
/** /**
@@ -139,13 +143,16 @@ router
* *
* Update and existing redirection-host * Update and existing redirection-host
*/ */
.delete((req, res, next) => { .delete(async (req, res, next) => {
internalRedirectionHost try {
.delete(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalRedirectionHost.delete(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -163,13 +170,16 @@ router
/** /**
* POST /api/nginx/redirection-hosts/123/enable * POST /api/nginx/redirection-hosts/123/enable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalRedirectionHost try {
.enable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalRedirectionHost.enable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -187,13 +197,16 @@ router
/** /**
* POST /api/nginx/redirection-hosts/123/disable * POST /api/nginx/redirection-hosts/123/disable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalRedirectionHost try {
.disable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalRedirectionHost.disable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
export default router; export default router;

View File

@@ -3,6 +3,7 @@ import internalStream from "../../internal/stream.js";
import jwtdecode from "../../lib/express/jwt-decode.js"; import jwtdecode from "../../lib/express/jwt-decode.js";
import apiValidator from "../../lib/validator/api.js"; import apiValidator from "../../lib/validator/api.js";
import validator from "../../lib/validator/index.js"; import validator from "../../lib/validator/index.js";
import { express as logger } from "../../logger.js";
import { getValidationSchema } from "../../schema/index.js"; import { getValidationSchema } from "../../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -26,31 +27,31 @@ router
* *
* Retrieve all streams * Retrieve all streams
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
additionalProperties: false, {
properties: { additionalProperties: false,
expand: { properties: {
$ref: "common#/properties/expand", expand: {
}, $ref: "common#/properties/expand",
query: { },
$ref: "common#/properties/query", query: {
$ref: "common#/properties/query",
},
}, },
}, },
}, {
{ expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, query: typeof req.query.query === "string" ? req.query.query : null,
query: typeof req.query.query === "string" ? req.query.query : null, },
}, );
) const rows = await internalStream.getAll(res.locals.access, data.expand, data.query);
.then((data) => { res.status(200).send(rows);
return internalStream.getAll(res.locals.access, data.expand, data.query); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((rows) => { next(err);
res.status(200).send(rows); }
})
.catch(next);
}) })
/** /**
@@ -58,15 +59,15 @@ router
* *
* Create a new stream * Create a new stream
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/streams", "post"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/streams", "post"), req.body);
return internalStream.create(res.locals.access, payload); const result = await internalStream.create(res.locals.access, payload);
}) res.status(201).send(result);
.then((result) => { } catch (err) {
res.status(201).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
/** /**
@@ -86,35 +87,35 @@ router
* *
* Retrieve a specific stream * Retrieve a specific stream
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["stream_id"], {
additionalProperties: false, required: ["stream_id"],
properties: { additionalProperties: false,
stream_id: { properties: {
$ref: "common#/properties/id", stream_id: {
}, $ref: "common#/properties/id",
expand: { },
$ref: "common#/properties/expand", expand: {
$ref: "common#/properties/expand",
},
}, },
}, },
}, {
{ stream_id: req.params.stream_id,
stream_id: req.params.stream_id, expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, },
}, );
) const row = await internalStream.get(res.locals.access, {
.then((data) => { id: Number.parseInt(data.stream_id, 10),
return internalStream.get(res.locals.access, { expand: data.expand,
id: Number.parseInt(data.stream_id, 10), });
expand: data.expand, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -122,16 +123,16 @@ router
* *
* Update and existing stream * Update and existing stream
*/ */
.put((req, res, next) => { .put(async (req, res, next) => {
apiValidator(getValidationSchema("/nginx/streams/{streamID}", "put"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/nginx/streams/{streamID}", "put"), req.body);
payload.id = Number.parseInt(req.params.stream_id, 10); payload.id = Number.parseInt(req.params.stream_id, 10);
return internalStream.update(res.locals.access, payload); const result = await internalStream.update(res.locals.access, payload);
}) res.status(200).send(result);
.then((result) => { } catch (err) {
res.status(200).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}) })
/** /**
@@ -139,13 +140,16 @@ router
* *
* Update and existing stream * Update and existing stream
*/ */
.delete((req, res, next) => { .delete(async (req, res, next) => {
internalStream try {
.delete(res.locals.access, { id: Number.parseInt(req.params.stream_id, 10) }) const result = await internalStream.delete(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.stream_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -163,13 +167,16 @@ router
/** /**
* POST /api/nginx/streams/123/enable * POST /api/nginx/streams/123/enable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalStream try {
.enable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalStream.enable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
/** /**
@@ -187,13 +194,16 @@ router
/** /**
* POST /api/nginx/streams/123/disable * POST /api/nginx/streams/123/disable
*/ */
.post((req, res, next) => { .post(async (req, res, next) => {
internalStream try {
.disable(res.locals.access, { id: Number.parseInt(req.params.host_id, 10) }) const result = await internalStream.disable(res.locals.access, {
.then((result) => { id: Number.parseInt(req.params.host_id, 10),
res.status(200).send(result); });
}) res.status(200).send(result);
.catch(next); } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
}); });
export default router; export default router;

View File

@@ -1,6 +1,7 @@
import express from "express"; import express from "express";
import internalReport from "../internal/report.js"; import internalReport from "../internal/report.js";
import jwtdecode from "../lib/express/jwt-decode.js"; import jwtdecode from "../lib/express/jwt-decode.js";
import { express as logger } from "../logger.js";
const router = express.Router({ const router = express.Router({
caseSensitive: true, caseSensitive: true,
@@ -17,13 +18,14 @@ router
/** /**
* GET /reports/hosts * GET /reports/hosts
*/ */
.get(jwtdecode(), (_, res, next) => { .get(jwtdecode(), async (req, res, next) => {
internalReport try {
.getHostsReport(res.locals.access) const data = await internalReport.getHostsReport(res.locals.access);
.then((data) => { res.status(200).send(data);
res.status(200).send(data); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.catch(next); next(err);
}
}); });
export default router; export default router;

View File

@@ -1,4 +1,5 @@
import express from "express"; import express from "express";
import { express as logger } from "../logger.js";
import PACKAGE from "../package.json" with { type: "json" }; import PACKAGE from "../package.json" with { type: "json" };
import { getCompiledSchema } from "../schema/index.js"; import { getCompiledSchema } from "../schema/index.js";
@@ -18,21 +19,26 @@ router
* GET /schema * GET /schema
*/ */
.get(async (req, res) => { .get(async (req, res) => {
const swaggerJSON = await getCompiledSchema(); try {
const swaggerJSON = await getCompiledSchema();
let proto = req.protocol; let proto = req.protocol;
if (typeof req.headers["x-forwarded-proto"] !== "undefined" && req.headers["x-forwarded-proto"]) { if (typeof req.headers["x-forwarded-proto"] !== "undefined" && req.headers["x-forwarded-proto"]) {
proto = req.headers["x-forwarded-proto"]; proto = req.headers["x-forwarded-proto"];
}
let origin = `${proto}://${req.hostname}`;
if (typeof req.headers.origin !== "undefined" && req.headers.origin) {
origin = req.headers.origin;
}
swaggerJSON.info.version = PACKAGE.version;
swaggerJSON.servers[0].url = `${origin}/api`;
res.status(200).send(swaggerJSON);
} catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
} }
let origin = `${proto}://${req.hostname}`;
if (typeof req.headers.origin !== "undefined" && req.headers.origin) {
origin = req.headers.origin;
}
swaggerJSON.info.version = PACKAGE.version;
swaggerJSON.servers[0].url = `${origin}/api`;
res.status(200).send(swaggerJSON);
}); });
export default router; export default router;

View File

@@ -3,6 +3,7 @@ import internalSetting from "../internal/setting.js";
import jwtdecode from "../lib/express/jwt-decode.js"; import jwtdecode from "../lib/express/jwt-decode.js";
import apiValidator from "../lib/validator/api.js"; import apiValidator from "../lib/validator/api.js";
import validator from "../lib/validator/index.js"; import validator from "../lib/validator/index.js";
import { express as logger } from "../logger.js";
import { getValidationSchema } from "../schema/index.js"; import { getValidationSchema } from "../schema/index.js";
const router = express.Router({ const router = express.Router({
@@ -26,13 +27,14 @@ router
* *
* Retrieve all settings * Retrieve all settings
*/ */
.get((_, res, next) => { .get(async (req, res, next) => {
internalSetting try {
.getAll(res.locals.access) const rows = await internalSetting.getAll(res.locals.access);
.then((rows) => { res.status(200).send(rows);
res.status(200).send(rows); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.catch(next); next(err);
}
}); });
/** /**
@@ -52,31 +54,31 @@ router
* *
* Retrieve a specific setting * Retrieve a specific setting
*/ */
.get((req, res, next) => { .get(async (req, res, next) => {
validator( try {
{ const data = await validator(
required: ["setting_id"], {
additionalProperties: false, required: ["setting_id"],
properties: { additionalProperties: false,
setting_id: { properties: {
type: "string", setting_id: {
minLength: 1, type: "string",
minLength: 1,
},
}, },
}, },
}, {
{ setting_id: req.params.setting_id,
setting_id: req.params.setting_id, },
}, );
) const row = await internalSetting.get(res.locals.access, {
.then((data) => { id: data.setting_id,
return internalSetting.get(res.locals.access, { });
id: data.setting_id, res.status(200).send(row);
}); } catch (err) {
}) logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
.then((row) => { next(err);
res.status(200).send(row); }
})
.catch(next);
}) })
/** /**
@@ -84,16 +86,16 @@ router
* *
* Update and existing setting * Update and existing setting
*/ */
.put((req, res, next) => { .put(async (req, res, next) => {
apiValidator(getValidationSchema("/settings/{settingID}", "put"), req.body) try {
.then((payload) => { const payload = await apiValidator(getValidationSchema("/settings/{settingID}", "put"), req.body);
payload.id = req.params.setting_id; payload.id = req.params.setting_id;
return internalSetting.update(res.locals.access, payload); const result = await internalSetting.update(res.locals.access, payload);
}) res.status(200).send(result);
.then((result) => { } catch (err) {
res.status(200).send(result); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
}) next(err);
.catch(next); }
}); });
export default router; export default router;

View File

@@ -1,6 +1,8 @@
import express from "express"; import express from "express";
import internalUser from "../internal/user.js"; import internalUser from "../internal/user.js";
import Access from "../lib/access.js"; import Access from "../lib/access.js";
import { isCI } from "../lib/config.js";
import errs from "../lib/error.js";
import jwtdecode from "../lib/express/jwt-decode.js"; import jwtdecode from "../lib/express/jwt-decode.js";
import userIdFromMe from "../lib/express/user-id-from-me.js"; import userIdFromMe from "../lib/express/user-id-from-me.js";
import apiValidator from "../lib/validator/api.js"; import apiValidator from "../lib/validator/api.js";
@@ -45,11 +47,18 @@ router
}, },
}, },
{ {
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, expand:
typeof req.query.expand === "string"
? req.query.expand.split(",")
: null,
query: typeof req.query.query === "string" ? req.query.query : null, query: typeof req.query.query === "string" ? req.query.query : null,
}, },
); );
const users = await internalUser.getAll(res.locals.access, data.expand, data.query); const users = await internalUser.getAll(
res.locals.access,
data.expand,
data.query,
);
res.status(200).send(users); res.status(200).send(users);
} catch (err) { } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
@@ -85,13 +94,43 @@ router
} }
} }
const payload = await apiValidator(getValidationSchema("/users", "post"), body); const payload = await apiValidator(
getValidationSchema("/users", "post"),
body,
);
const user = await internalUser.create(res.locals.access, payload); const user = await internalUser.create(res.locals.access, payload);
res.status(201).send(user); res.status(201).send(user);
} catch (err) { } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err); next(err);
} }
})
/**
* DELETE /api/users
*
* Deletes ALL users. This is NOT GENERALLY AVAILABLE!
* (!) It is NOT an authenticated endpoint.
* (!) Only CI should be able to call this endpoint. As a result,
*
* it will only work when the env vars DEBUG=true and CI=true
*
* Do NOT set those env vars in a production environment!
*/
.delete(async (_, res, next) => {
if (isCI()) {
try {
logger.warn("Deleting all users - CI environment detected, allowing this operation");
await internalUser.deleteAll();
res.status(200).send(true);
} catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
next(err);
}
return;
}
next(new errs.ItemNotFoundError());
}); });
/** /**
@@ -129,14 +168,20 @@ router
}, },
{ {
user_id: req.params.user_id, user_id: req.params.user_id,
expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null, expand:
typeof req.query.expand === "string"
? req.query.expand.split(",")
: null,
}, },
); );
const user = await internalUser.get(res.locals.access, { const user = await internalUser.get(res.locals.access, {
id: data.user_id, id: data.user_id,
expand: data.expand, expand: data.expand,
omit: internalUser.getUserOmisionsByAccess(res.locals.access, data.user_id), omit: internalUser.getUserOmisionsByAccess(
res.locals.access,
data.user_id,
),
}); });
res.status(200).send(user); res.status(200).send(user);
} catch (err) { } catch (err) {
@@ -152,7 +197,10 @@ router
*/ */
.put(async (req, res, next) => { .put(async (req, res, next) => {
try { try {
const payload = await apiValidator(getValidationSchema("/users/{userID}", "put"), req.body); const payload = await apiValidator(
getValidationSchema("/users/{userID}", "put"),
req.body,
);
payload.id = req.params.user_id; payload.id = req.params.user_id;
const result = await internalUser.update(res.locals.access, payload); const result = await internalUser.update(res.locals.access, payload);
res.status(200).send(result); res.status(200).send(result);
@@ -169,7 +217,9 @@ router
*/ */
.delete(async (req, res, next) => { .delete(async (req, res, next) => {
try { try {
const result = await internalUser.delete(res.locals.access, { id: req.params.user_id }); const result = await internalUser.delete(res.locals.access, {
id: req.params.user_id,
});
res.status(200).send(result); res.status(200).send(result);
} catch (err) { } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
@@ -197,7 +247,10 @@ router
*/ */
.put(async (req, res, next) => { .put(async (req, res, next) => {
try { try {
const payload = await apiValidator(getValidationSchema("/users/{userID}/auth", "put"), req.body); const payload = await apiValidator(
getValidationSchema("/users/{userID}/auth", "put"),
req.body,
);
payload.id = req.params.user_id; payload.id = req.params.user_id;
const result = await internalUser.setPassword(res.locals.access, payload); const result = await internalUser.setPassword(res.locals.access, payload);
res.status(200).send(result); res.status(200).send(result);
@@ -227,9 +280,15 @@ router
*/ */
.put(async (req, res, next) => { .put(async (req, res, next) => {
try { try {
const payload = await apiValidator(getValidationSchema("/users/{userID}/permissions", "put"), req.body); const payload = await apiValidator(
getValidationSchema("/users/{userID}/permissions", "put"),
req.body,
);
payload.id = req.params.user_id; payload.id = req.params.user_id;
const result = await internalUser.setPermissions(res.locals.access, payload); const result = await internalUser.setPermissions(
res.locals.access,
payload,
);
res.status(200).send(result); res.status(200).send(result);
} catch (err) { } catch (err) {
logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`); logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);

View File

@@ -9,6 +9,11 @@
"description": "Healthy", "description": "Healthy",
"example": "OK" "example": "OK"
}, },
"setup": {
"type": "boolean",
"description": "Whether the initial setup has been completed",
"example": true
},
"version": { "version": {
"type": "object", "type": "object",
"description": "The version object", "description": "The version object",

View File

@@ -54,6 +54,63 @@
"items": { "items": {
"type": "string" "type": "string"
} }
},
"permissions": {
"type": "object",
"description": "Permissions if expanded in request",
"required": [
"visibility",
"proxy_hosts",
"redirection_hosts",
"dead_hosts",
"streams",
"access_lists",
"certificates"
],
"properties": {
"visibility": {
"type": "string",
"description": "Visibility level",
"example": "all",
"pattern": "^(all|user)$"
},
"proxy_hosts": {
"type": "string",
"description": "Proxy Hosts access level",
"example": "all",
"pattern": "^(manage|view|hidden)$"
},
"redirection_hosts": {
"type": "string",
"description": "Redirection Hosts access level",
"example": "all",
"pattern": "^(manage|view|hidden)$"
},
"dead_hosts": {
"type": "string",
"description": "Dead Hosts access level",
"example": "all",
"pattern": "^(manage|view|hidden)$"
},
"streams": {
"type": "string",
"description": "Streams access level",
"example": "all",
"pattern": "^(manage|view|hidden)$"
},
"access_lists": {
"type": "string",
"description": "Access Lists access level",
"example": "all",
"pattern": "^(manage|view|hidden)$"
},
"certificates": {
"type": "string",
"description": "Certificates access level",
"example": "all",
"pattern": "^(manage|view|hidden)$"
}
}
} }
} }
} }

View File

@@ -11,6 +11,7 @@
"default": { "default": {
"value": { "value": {
"status": "OK", "status": "OK",
"setup": true,
"version": { "version": {
"major": 2, "major": 2,
"minor": 1, "minor": 1,

View File

@@ -9,6 +9,7 @@ services:
environment: environment:
TZ: "${TZ:-Australia/Brisbane}" TZ: "${TZ:-Australia/Brisbane}"
DEBUG: 'true' DEBUG: 'true'
CI: 'true'
FORCE_COLOR: 1 FORCE_COLOR: 1
# Required for DNS Certificate provisioning in CI # Required for DNS Certificate provisioning in CI
LE_SERVER: 'https://ca.internal/acme/acme/directory' LE_SERVER: 'https://ca.internal/acme/acme/directory'

View File

@@ -5,6 +5,7 @@ describe('Certificates endpoints', () => {
let certID; let certID;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
}); });

View File

@@ -4,6 +4,7 @@ describe('Dashboard endpoints', () => {
let token; let token;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
}); });

View File

@@ -4,6 +4,7 @@ describe('Full Certificate Provisions', () => {
let token; let token;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
}); });

View File

@@ -5,6 +5,7 @@ describe('LDAP with Authentik', () => {
if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') { if (Cypress.env('skipStackCheck') === 'true' || Cypress.env('stack') === 'postgres') {
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
_token = tok; _token = tok;

View File

@@ -4,6 +4,7 @@ describe('Proxy Hosts endpoints', () => {
let token; let token;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
}); });

View File

@@ -4,6 +4,7 @@ describe('Settings endpoints', () => {
let token; let token;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
}); });

View File

@@ -4,6 +4,7 @@ describe('Streams', () => {
let token; let token;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
// Set default site content // Set default site content

View File

@@ -4,6 +4,7 @@ describe('Users endpoints', () => {
let token; let token;
before(() => { before(() => {
cy.resetUsers();
cy.getToken().then((tok) => { cy.getToken().then((tok) => {
token = tok; token = tok;
}); });

View File

@@ -12,10 +12,10 @@
import 'cypress-wait-until'; import 'cypress-wait-until';
Cypress.Commands.add('randomString', (length) => { Cypress.Commands.add('randomString', (length) => {
var result = ''; let result = '';
var characters = 'ABCDEFGHIJK LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const characters = 'ABCDEFGHIJK LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length; const charactersLength = characters.length;
for (var i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength)); result += characters.charAt(Math.floor(Math.random() * charactersLength));
} }
return result; return result;
@@ -40,16 +40,81 @@ Cypress.Commands.add('validateSwaggerSchema', (method, code, path, data) => {
}).should('equal', null); }).should('equal', null);
}); });
Cypress.Commands.add('getToken', () => { Cypress.Commands.add('createInitialUser', (defaultUser) => {
// login with existing user let user = {
cy.task('backendApiPost', { name: 'Cypress McGee',
path: '/api/tokens', nickname: 'Cypress',
data: { email: 'cypress@example.com',
identity: 'admin@example.com', auth: {
secret: 'changeme' type: 'password',
secret: 'changeme'
},
};
if (typeof defaultUser === 'object' && defaultUser) {
user = Object.assign({}, user, defaultUser);
}
return cy.task('backendApiPost', {
path: '/api/users',
data: user,
}).then((data) => {
// Check the swagger schema:
cy.validateSwaggerSchema('post', 201, '/users', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
cy.wrap(data);
});
});
Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
if (typeof defaultAuth === 'object' && defaultAuth) {
if (!defaultUser) {
defaultUser = {};
} }
}).then(res => { defaultUser.auth = defaultAuth;
cy.wrap(res.token); }
cy.task('backendApiGet', {
path: '/api/',
}).then((data) => {
// Check the swagger schema:
cy.validateSwaggerSchema('get', 200, '/', data);
if (!data.setup) {
cy.log('Setup = false');
// create a new user
cy.createInitialUser(defaultUser).then(() => {
return cy.getToken(defaultUser);
});
} else {
let auth = {
identity: 'cypress@example.com',
secret: 'changeme',
};
if (typeof defaultUser === 'object' && defaultUser && typeof defaultUser.auth === 'object' && defaultUser.auth) {
auth = Object.assign({}, auth, defaultUser.auth);
}
cy.log('Setup = true');
// login with existing user
cy.task('backendApiPost', {
path: '/api/tokens',
data: auth,
}).then((res) => {
cy.wrap(res.token);
});
}
});
});
Cypress.Commands.add('resetUsers', () => {
cy.task('backendApiDelete', {
path: '/api/users'
}).then((data) => {
expect(data).to.be.equal(true);
cy.wrap(data);
}); });
}); });